(root)/
glibc-2.38/
posix/
tst-chmod.c
       1  /* Test for chmod functions.
       2     Copyright (C) 2000-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <dirent.h>
      20  #include <errno.h>
      21  #include <error.h>
      22  #include <fcntl.h>
      23  #include <mcheck.h>
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <string.h>
      27  #include <unistd.h>
      28  #include <sys/stat.h>
      29  
      30  #include <support/xunistd.h>
      31  
      32  
      33  #define OUT_OF_MEMORY \
      34    do {									      \
      35      puts ("cannot allocate memory");					      \
      36      result = 1;								      \
      37      goto fail;								      \
      38    } while (0)
      39  
      40  static int
      41  do_test (int argc, char *argv[])
      42  {
      43    const char *builddir;
      44    struct stat64 st1;
      45    struct stat64 st2;
      46    char *buf;
      47    char *testdir;
      48    char *testfile = NULL;
      49    char *startdir;
      50    size_t buflen;
      51    int fd;
      52    int result = 0;
      53    DIR *dir;
      54  
      55    mtrace ();
      56  
      57    if (argc <= 1)
      58      error (EXIT_FAILURE, 0, "no parameters");
      59  
      60    /* This is where we will create the test files.  */
      61    builddir = argv[1];
      62    buflen = strlen (builddir) + 50;
      63  
      64    startdir = getcwd (NULL, 0);
      65    if (startdir == NULL)
      66      {
      67        printf ("cannot get current directory: %m\n");
      68        exit (EXIT_FAILURE);
      69      }
      70  
      71    /* A buffer large enough for everything we need.  */
      72    buf = (char *) alloca (buflen);
      73  
      74    /* Create the directory name.  */
      75    snprintf (buf, buflen, "%s/chmoddirXXXXXX", builddir);
      76  
      77    if (mkdtemp (buf) == NULL)
      78      {
      79        printf ("cannot create test directory: %m\n");
      80        exit (EXIT_FAILURE);
      81      }
      82  
      83    if (chmod ("", 0600) == 0)
      84      {
      85        puts ("chmod(\"\", 0600 didn't fail");
      86        result = 1;
      87      }
      88    else if (errno != ENOENT)
      89      {
      90        puts ("chmod(\"\",0600) does not set errno to ENOENT");
      91        result = 1;
      92      }
      93  
      94    /* Create a duplicate.  */
      95    testdir = strdup (buf);
      96    if (testdir == NULL)
      97      OUT_OF_MEMORY;
      98  
      99    if (stat64 (testdir, &st1) != 0)
     100      {
     101        printf ("cannot stat test directory: %m\n");
     102        exit (1);
     103      }
     104    if (!S_ISDIR (st1.st_mode))
     105      {
     106        printf ("file not created as directory: %m\n");
     107        exit (1);
     108      }
     109  
     110    /* We have to wait for a second to make sure the ctime changes.  */
     111    sleep (1);
     112  
     113    /* Remove all access rights from the directory.  */
     114    if (chmod (testdir, 0) != 0)
     115      {
     116        printf ("cannot change mode of test directory: %m\n");
     117        result = 1;
     118        goto fail;
     119      }
     120  
     121    if (stat64 (testdir, &st2) != 0)
     122      {
     123        printf ("cannot stat test directory: %m\n");
     124        result = 1;
     125        goto fail;
     126      }
     127  
     128    /* Compare result.  */
     129    if ((st2.st_mode & ALLPERMS) != 0)
     130      {
     131        printf ("chmod(...,0) on directory left bits nonzero: %o\n",
     132  	      st2.st_mode & ALLPERMS);
     133        result = 1;
     134      }
     135    if (st1.st_ctime >= st2.st_ctime)
     136      {
     137        puts ("chmod(...,0) did not set ctime correctly");
     138        result = 1;
     139      }
     140  
     141    /* Name of a file in the directory.  */
     142    snprintf (buf, buflen, "%s/file", testdir);
     143    testfile = strdup (buf);
     144    if (testfile == NULL)
     145      OUT_OF_MEMORY;
     146  
     147    fd = creat (testfile, 0);
     148    if (fd != -1)
     149      {
     150        if (getuid () != 0)
     151  	{
     152  	  puts ("managed to create test file in protected directory");
     153  	  result = 1;
     154  	}
     155        close (fd);
     156      }
     157    else if (errno != EACCES)
     158      {
     159        puts ("creat didn't generate correct errno value");
     160        result = 1;
     161      }
     162  
     163    /* With this mode it still shouldn't be possible to create a file.  */
     164    if (chmod (testdir, 0600) != 0)
     165      {
     166        printf ("cannot change mode of test directory to 0600: %m\n");
     167        result = 1;
     168        goto fail;
     169      }
     170  
     171    fd = creat (testfile, 0);
     172    if (fd != -1)
     173      {
     174        if (getuid () != 0)
     175  	{
     176  	  puts ("managed to create test file in no-x protected directory");
     177  	  result = 1;
     178  	}
     179        close (fd);
     180      }
     181    else if (errno != EACCES)
     182      {
     183        puts ("creat didn't generate correct errno value");
     184        result = 1;
     185      }
     186  
     187    /* Change the directory mode back to allow creating a file.  This
     188       time with fchmod.  */
     189    dir = opendir (testdir);
     190    if (dir != NULL)
     191      {
     192        if (fchmod (dirfd (dir), 0700) != 0)
     193  	{
     194  	  printf ("cannot change mode of test directory to 0700: %m\n");
     195  	  result = 1;
     196  	  closedir (dir);
     197  	  goto fail;
     198  	}
     199  
     200        closedir (dir);
     201      }
     202    else
     203      {
     204        printf ("cannot open directory: %m\n");
     205        result = 1;
     206  
     207        if (chmod (testdir, 0700) != 0)
     208  	{
     209  	  printf ("cannot change mode of test directory to 0700: %m\n");
     210  	  goto fail;
     211  	}
     212      }
     213  
     214    fd = creat (testfile, 0);
     215    if (fd == -1)
     216      {
     217        puts ("still didn't manage to create test file in protected directory");
     218        result = 1;
     219        goto fail;
     220      }
     221    if (fstat64 (fd, &st1) != 0)
     222      {
     223        printf ("cannot stat new file: %m\n");
     224        result = 1;
     225      }
     226    else if ((st1.st_mode & ALLPERMS) != 0)
     227      {
     228        puts ("file not created with access mode 0");
     229        result = 1;
     230      }
     231    close (fd);
     232  
     233    snprintf (buf, buflen, "%s/..", testdir);
     234    xchdir (buf);
     235  
     236    /* We are now in the directory above the one we create the test
     237       directory in.  */
     238  
     239    sleep (1);
     240    snprintf (buf, buflen, "./%s/../%s/file",
     241  	    basename (testdir), basename (testdir));
     242    if (chmod (buf, 0600) != 0)
     243      {
     244        printf ("cannot change mode of file to 0600: %m\n");
     245        result = 1;
     246        goto fail;
     247      }
     248    snprintf (buf, buflen, "./%s//file", basename (testdir));
     249    if (stat64 (buf, &st2) != 0)
     250      {
     251        printf ("cannot stat new file: %m\n");
     252        result = 1;
     253      }
     254    else if ((st2.st_mode & ALLPERMS) != 0600)
     255      {
     256        puts ("file mode not changed to 0600");
     257        result = 1;
     258      }
     259    else if (st1.st_ctime >= st2.st_ctime)
     260      {
     261        puts ("chmod(\".../file\",0600) did not set ctime correctly");
     262        result = 1;
     263      }
     264  
     265    if (chmod (buf, 0777 | S_ISUID | S_ISGID) != 0)
     266      {
     267        printf ("cannot change mode of file to %o: %m\n",
     268  	      0777 | S_ISUID | S_ISGID);
     269        result = 1;
     270      }
     271    if (stat64 (buf, &st2) != 0)
     272      {
     273        printf ("cannot stat test file: %m\n");
     274        result = 1;
     275      }
     276    else if ((st2.st_mode & ALLPERMS) != (0777 | S_ISUID | S_ISGID))
     277      {
     278        puts ("file mode not changed to 0777 | S_ISUID | S_ISGID");
     279        result = 1;
     280      }
     281  
     282    if (chmod (basename (testdir), 0777 | S_ISUID | S_ISGID | S_ISVTX) != 0)
     283      {
     284        printf ("cannot change mode of test directory to %o: %m\n",
     285  	      0777 | S_ISUID | S_ISGID | S_ISVTX);
     286        result = 1;
     287      }
     288    if (stat64 (basename (testdir), &st2) != 0)
     289      {
     290        printf ("cannot stat test directory: %m\n");
     291        result = 1;
     292      }
     293    else if ((st2.st_mode & ALLPERMS) != (0777 | S_ISUID | S_ISGID | S_ISVTX))
     294      {
     295        puts ("directory mode not changed to 0777 | S_ISUID | S_ISGID | S_ISGID");
     296        result = 1;
     297      }
     298  
     299    snprintf (buf, buflen, "./%s/no-such-file", basename (testdir));
     300    if (chmod (buf, 0600) != -1)
     301      {
     302        puts ("chmod(\".../no-such-file\",0600) did not fail");
     303        result = 1;
     304      }
     305    else if (errno != ENOENT)
     306      {
     307        puts ("chmod(\".../no-such-file\",0600) does not set errno to ENOENT");
     308        result = 1;
     309      }
     310  
     311    snprintf (buf, buflen, "%s/", basename (testdir));
     312    if (chmod (basename (testdir), 0677) != 0)
     313      {
     314        printf ("cannot change mode of test directory to 0677: %m\n");
     315        result = 1;
     316      }
     317    else
     318      {
     319        snprintf (buf, buflen, "./%s/file", basename (testdir));
     320        if (chmod (buf, 0600) == 0)
     321  	{
     322  	  if (getuid () != 0)
     323  	    {
     324  	      puts ("chmod(\".../file\") with no-exec directory succeeded");
     325  	      result = 1;
     326  	    }
     327  	}
     328        else if (errno != EACCES)
     329  	{
     330  	  puts ("chmod(\".../file\") with no-exec directory didn't set EACCES");
     331  	  result = 1;
     332  	}
     333      }
     334  
     335    if (chmod (basename (testdir), 0777) != 0)
     336      {
     337        printf ("cannot change mode of test directory to 0777: %m\n");
     338        result = 1;
     339        goto fail;
     340      }
     341  
     342    snprintf (buf, buflen, "%s/file/cannot-be", basename (testdir));
     343    if (chmod (buf, 0600) == 0)
     344      {
     345        puts ("chmod(\".../file/cannot-be\",0600) did not fail");
     346        result = 1;
     347      }
     348    else if (errno != ENOTDIR)
     349      {
     350        puts ("chmod(\".../file/cannot-be\",0600) does not set errno to ENOTDIR");
     351        result = 1;
     352      }
     353  
     354   fail:
     355    xchdir (startdir);
     356  
     357    /* Remove all the files.  */
     358    chmod (testdir, 0700);
     359    if (testfile != NULL)
     360      {
     361        chmod (testfile, 0700);
     362        unlink (testfile);
     363      }
     364    rmdir (testdir);
     365  
     366    /* Free the resources.  */
     367    free (testfile);
     368    free (testdir);
     369    free (startdir);
     370  
     371    return result;
     372  }
     373  
     374  #include "../test-skeleton.c"