int main(int argc, char *argv[]) { int lc; char *msg; uid_t user_id; gid_t group_id; int i; if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); /* set the expected errnos... */ TEST_EXP_ENOS(exp_enos); user_id = geteuid(); UID16_CHECK(user_id, lchown, cleanup); group_id = getegid(); GID16_CHECK(group_id, lchown, cleanup); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; test_cases[i].desc != NULL; i++) { char *file_name = test_cases[i].pathname; char *test_desc = test_cases[i].desc; /* * Call lchown(2) to test different test conditions. * verify that it fails with -1 return value and * sets appropriate errno. */ TEST(LCHOWN(cleanup, file_name, user_id, group_id)); /* Check return code from lchown(2) */ if (TEST_RETURN == -1) { TEST_ERROR_LOG(TEST_ERRNO); if (TEST_ERRNO == test_cases[i].exp_errno) { tst_resm(TPASS, "lchown(2) fails, %s, errno:%d", test_desc, TEST_ERRNO); } else { tst_resm(TFAIL, "lchown(2) fails, %s, " "errno:%d, expected errno:%d", test_desc, TEST_ERRNO, test_cases[i].exp_errno); } } else { tst_resm(TFAIL, "lchown(2) returned %ld, " "expected -1, errno:%d", TEST_RETURN, test_cases[i].exp_errno); } } } cleanup(); tst_exit(); }
int main(int argc, char *argv[]) { struct stat stat_buf; int lc; const char *msg; int i; if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; test_cases[i].desc != NULL; i++) { uid_t user_id = test_cases[i].user_id; gid_t group_id = test_cases[i].group_id; char *test_desc = test_cases[i].desc; /* * Call lchown(2) with different user id and * group id (numeric values) to set it on * symlink of testfile. */ TEST(LCHOWN(cleanup, SFILE, user_id, group_id)); if (TEST_RETURN == -1) { tst_resm(TFAIL, "lchown() Fails to %s, errno %d", test_desc, TEST_ERRNO); continue; } if (lstat(SFILE, &stat_buf) < 0) { tst_brkm(TFAIL, cleanup, "lstat(2) " "%s failed, errno %d", SFILE, TEST_ERRNO); } if (user_id == -1) { if (i > 0) user_id = test_cases[i - 1].user_id; else user_id = geteuid(); } if (group_id == -1) { if (i > 0) group_id = test_cases[i - 1].group_id; else group_id = getegid(); } /* * Check for expected Ownership ids * set on testfile. */ if ((stat_buf.st_uid != user_id) || (stat_buf.st_gid != group_id)) { tst_resm(TFAIL, "%s: incorrect ownership set, " "Expected %d %d", SFILE, user_id, group_id); } else { tst_resm(TPASS, "lchown() succeeds to " "%s of %s", test_desc, SFILE); } } } cleanup(); tst_exit(); }
/* * chgrpr() - recursive chown() * * Recursively chowns the input directory then its contents. rflag must * have been set if chgrpr() is called. The input directory should not * be a sym link (this is handled in the calling routine). In * addition, the calling routine should have already added the input * directory to the search tree so we do not get into endless loops. * Note: chgrpr() doesn't need a return value as errors are reported * through the global "status" variable. */ static void chgrpr(char *dir, gid_t gid) { struct dirent *dp; DIR *dirp; struct stat st, st2; char savedir[1024]; if (getcwd(savedir, 1024) == 0) { (void) fprintf(stderr, "chgrp: "); (void) fprintf(stderr, gettext("%s\n"), savedir); exit(255); } /* * Attempt to chown the directory, however don't return if we * can't as we still may be able to chown the contents of the * directory. Note: the calling routine resets the SUID bits * on this directory so we don't have to perform an extra 'stat'. */ CHOWN(dir, -1, gid); if (chdir(dir) < 0) { status += Perror(dir); return; } if ((dirp = opendir(".")) == NULL) { status += Perror(dir); return; } for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) { continue; /* skip "." and ".." */ } if (lstat(dp->d_name, &st) < 0) { status += Perror(dp->d_name); continue; } if ((st.st_mode & S_IFMT) == S_IFLNK) { if (hflag || Pflag) { /* * Change the group id of the symbolic link * encountered while traversing the * directory. Don't follow the symbolic * link to any other part of the file * hierarchy. */ LCHOWN(dp->d_name, -1, gid); } else { if (stat(dp->d_name, &st2) < 0) { status += Perror(dp->d_name); continue; } /* * We know that we are to change the * group of the file referenced by the * symlink encountered while traversing * the directory. Now check to see if we * are to follow the symlink to any other * part of the file hierarchy. */ if (FOLLOW_D_LINKS) { if ((st2.st_mode & S_IFMT) == S_IFDIR) { /* * We are following symlinks so * traverse into the directory. * Add this node to the search * tree so we don't get into an * endless loop. */ int rc; if ((rc = add_tnode(&tree, st2.st_dev, st2.st_ino)) == 1) { chgrpr(dp->d_name, gid); /* * Restore SET[UG]ID * bits. */ SETUGID_PRESERVE( dp->d_name, st2.st_mode & ~S_IFMT); } else if (rc == 0) { /* already visited */ continue; } else { /* * An error occurred * while trying to add * the node to the tree. */ status += Perror( dp->d_name); continue; } } else { /* * Change the group id of the * file referenced by the * symbolic link. */ CHOWN(dp->d_name, -1, gid); } } else { /* * Change the group id of the file * referenced by the symbolic link. */ CHOWN(dp->d_name, -1, gid); if ((st2.st_mode & S_IFMT) == S_IFDIR) { /* Restore SET[UG]ID bits. */ SETUGID_PRESERVE(dp->d_name, st2.st_mode & ~S_IFMT); } } } } else if ((st.st_mode & S_IFMT) == S_IFDIR) { /* * Add this node to the search tree so we don't * get into a endless loop. */ int rc; if ((rc = add_tnode(&tree, st.st_dev, st.st_ino)) == 1) { chgrpr(dp->d_name, gid); /* Restore the SET[UG]ID bits. */ SETUGID_PRESERVE(dp->d_name, st.st_mode & ~S_IFMT); } else if (rc == 0) { /* already visited */ continue; } else { /* * An error occurred while trying * to add the node to the search tree. */ status += Perror(dp->d_name); continue; } } else { CHOWN(dp->d_name, -1, gid); } } (void) closedir(dirp); if (chdir(savedir) < 0) { (void) fprintf(stderr, "chgrp: "); (void) fprintf(stderr, gettext("can't change back to %s\n"), savedir); exit(255); } }
int main(int argc, char *argv[]) { int c; /* set the locale for only the messages system (all else is clean) */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); while ((c = getopt(argc, argv, "RhfHLPs")) != EOF) switch (c) { case 'R': rflag++; break; case 'h': hflag++; break; case 'f': fflag++; break; case 'H': /* * If more than one of -H, -L, and -P * are specified, only the last option * specified determines the behavior of * chgrp. In addition, make [-H|-L] * mutually exclusive of -h. */ Lflag = Pflag = 0; Hflag++; break; case 'L': Hflag = Pflag = 0; Lflag++; break; case 'P': Hflag = Lflag = 0; Pflag++; break; case 's': sflag++; break; default: usage(); } /* * Set Pflag by default for recursive operations * if no other options were specified. */ if (rflag && !(Lflag || Hflag || Pflag || hflag)) { Pflag = 1; } /* * Check for sufficient arguments * or a usage error. */ argc -= optind; argv = &argv[optind]; if ((argc < 2) || ((Hflag || Lflag || Pflag) && !rflag) || ((Hflag || Lflag || Pflag) && hflag)) { usage(); } if (sflag) { if (sid_to_id(argv[0], B_FALSE, &gid)) { (void) fprintf(stderr, gettext( "chgrp: invalid group sid %s\n"), argv[0]); exit(2); } } else if ((gr = getgrnam(argv[0])) != NULL) { gid = gr->gr_gid; } else { if (isnumber(argv[0])) { errno = 0; /* gid is an int */ gid = (gid_t)strtoul(argv[0], NULL, 10); if (errno != 0) { if (errno == ERANGE) { (void) fprintf(stderr, gettext( "chgrp: group id is too large\n")); exit(2); } else { (void) fprintf(stderr, gettext( "chgrp: invalid group id\n")); exit(2); } } } else { (void) fprintf(stderr, "chgrp: "); (void) fprintf(stderr, gettext("unknown group: %s\n"), argv[0]); exit(2); } } for (c = 1; c < argc; c++) { tree = NULL; if (lstat(argv[c], &stbuf) < 0) { status += Perror(argv[c]); continue; } if (rflag && ((stbuf.st_mode & S_IFMT) == S_IFLNK)) { if (hflag || Pflag) { /* * Change the group id of the symbolic link * specified on the command line. * Don't follow the symbolic link to * any other part of the file hierarchy. */ LCHOWN(argv[c], -1, gid); } else { if (stat(argv[c], &stbuf2) < 0) { status += Perror(argv[c]); continue; } /* * We know that we are to change the * group of the file referenced by the * symlink specified on the command line. * Now check to see if we are to follow * the symlink to any other part of the * file hierarchy. */ if (FOLLOW_CL_LINKS) { if ((stbuf2.st_mode & S_IFMT) == S_IFDIR) { /* * We are following symlinks so * traverse into the directory. * Add this node to the search * tree so we don't get into an * endless loop. */ if (add_tnode(&tree, stbuf2.st_dev, stbuf2.st_ino) == 1) { chgrpr(argv[c], gid); /* * Try to restore the * SET[UG]ID bits. */ SETUGID_PRESERVE( argv[c], stbuf2.st_mode & ~S_IFMT); } else { /* * Error occurred. * rc can't be 0 * as this is the first * node to be added to * the search tree. */ status += Perror( argv[c]); } } else { /* * Change the group id of the * file referenced by the * symbolic link. */ CHOWN(argv[c], -1, gid); } } else { /* * Change the group id of the file * referenced by the symbolic link. */ CHOWN(argv[c], -1, gid); if ((stbuf2.st_mode & S_IFMT) == S_IFDIR) { /* Reset the SET[UG]ID bits. */ SETUGID_PRESERVE(argv[c], stbuf2.st_mode & ~S_IFMT); } } } } else if (rflag && ((stbuf.st_mode & S_IFMT) == S_IFDIR)) { /* * Add this node to the search tree so we don't * get into a endless loop. */ if (add_tnode(&tree, stbuf.st_dev, stbuf.st_ino) == 1) { chgrpr(argv[c], gid); /* Restore the SET[UG]ID bits. */ SETUGID_PRESERVE(argv[c], stbuf.st_mode & ~S_IFMT); } else { /* * An error occurred while trying * to add the node to the tree. * Continue on with next file * specified. Note: rc shouldn't * be 0 as this was the first node * being added to the search tree. */ status += Perror(argv[c]); } } else { if (hflag || Pflag) { LCHOWN(argv[c], -1, gid); } else { CHOWN(argv[c], -1, gid); } /* If a directory, reset the SET[UG]ID bits. */ if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { SETUGID_PRESERVE(argv[c], stbuf.st_mode & ~S_IFMT); } } } return (status); }
/* * chown_tree - change ownership of files in a directory tree * * chown_dir() walks a directory tree and changes the ownership * of all files owned by the provided user ID. */ int chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid) { char new_name[1024]; int rc = 0; struct DIRECT *ent; struct stat sb; DIR *dir; /* * Make certain the directory exists. This routine is called * directory by the invoker, or recursively. */ if (access (root, F_OK) != 0) return -1; /* * Open the directory and read each entry. Every entry is tested * to see if it is a directory, and if so this routine is called * recursively. If not, it is checked to see if it is owned by * old user ID. */ if (!(dir = opendir (root))) return -1; while ((ent = readdir (dir))) { /* * Skip the "." and ".." entries */ if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) continue; /* * Make the filename for both the source and the * destination files. */ if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) break; snprintf (new_name, sizeof new_name, "%s/%s", root, ent->d_name); /* Don't follow symbolic links! */ if (LSTAT (new_name, &sb) == -1) continue; if (S_ISDIR (sb.st_mode) && !S_ISLNK (sb.st_mode)) { /* * Do the entire subdirectory. */ rc = chown_tree (new_name, old_uid, new_uid, old_gid, new_gid); if (0 != rc) { break; } } #ifndef HAVE_LCHOWN /* don't use chown (follows symbolic links!) */ if (S_ISLNK (sb.st_mode)) continue; #endif if (sb.st_uid == old_uid) LCHOWN (new_name, new_uid, sb.st_gid == old_gid ? new_gid : sb.st_gid); } (void) closedir (dir); /* * Now do the root of the tree */ if (stat (root, &sb) == 0) { if (sb.st_uid == old_uid) { LCHOWN (root, new_uid, sb.st_gid == old_gid ? new_gid : sb.st_gid); } } return rc; }