rtems_task Init( rtems_task_argument argument ) { int status = 0; void *alloc_ptr = (void *)0; char linkname_n[20] = {0}; char linkname_p[20] = {0}; int i; struct stat stat_buf; puts( "\n\n*** TEST IMFS 02 ***" ); puts( "Creating directory /dir00" ); status = mkdir( "/dir00", S_IRWXU ); rtems_test_assert( status == 0 ); puts( "Creating directory /dir00/dir01" ); status = mkdir( "/dir00/dir01", S_IRWXU ); rtems_test_assert( status == 0 ); puts( "Changing directory to /dir00" ); status = chdir( "/dir00" ); rtems_test_assert( status == 0 ); puts( "Creating link dir01-link0 for dir01" ); status = link( "dir01", "dir01-link0" ); rtems_test_assert( status == 0 ); for( i = 1 ; ; ++i ) { sprintf( linkname_p, "dir01-link%d", i-1 ); sprintf( linkname_n, "dir01-link%d", i ); printf( "\nCreating link %s for %s\n", linkname_n, linkname_p ); status = link( linkname_p, linkname_n ); if( status != 0 ) { puts("Link creation failed" ); break; } } puts( "Creating a regular node /node, RDONLY" ); status = mknod( "/node", S_IFREG | S_IRUSR, 0LL ); rtems_test_assert( status == 0 ); puts( "Creating link /node-link for /node" ); status = link( "/node" , "/node-link" ); rtems_test_assert( status == 0 ); puts( "Opening /node-link in WRONLY mode -- expect EACCES" ); status = open( "/node-link", O_WRONLY ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == EACCES ); puts( "Creating a symlink /node-slink for /node" ); status = symlink( "/node" , "/node-slink" ); rtems_test_assert( status == 0 ); puts( "Opening /node-slink in WRONLY mode -- expect EACCES" ); status = open( "/node-slink", O_WRONLY ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == EACCES ); puts( "Allocate most of heap" ); alloc_ptr = malloc( malloc_free_space() - 150 ); puts( "Attempt to mount a fs at /dir01 -- expect ENOMEM" ); status = mount( NULL, "dir01", "imfs", RTEMS_FILESYSTEM_READ_WRITE, NULL ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == ENOMEM ); puts( "Freeing allocated memory" ); free( alloc_ptr ); puts( "Allocate most of heap" ); alloc_ptr = malloc( malloc_free_space() - 4 ); puts( "Changing directory to /" ); status = chdir( "/" ); rtems_test_assert( status == 0 ); puts( "Attempt to create /node-link-2 for /node -- expect ENOMEM" ); status = link( "/node", "/node-link-2" ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == ENOMEM ); puts( "Attempt to create /node-slink-2 for /node -- expect ENOMEM" ); status = symlink( "/node", "node-slink-2" ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == ENOMEM ); puts( "Freeing allocated memory" ); free( alloc_ptr ); puts( "Allocate most of heap" ); alloc_ptr = malloc( malloc_free_space() - 40 ); puts( "Attempt to create /node-slink-2 for /node -- expect ENOMEM" ); status = symlink( "/node", "node-slink-2" ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == ENOMEM ); puts( "Freeing allocated memory" ); free( alloc_ptr ); puts( "Attempt to stat a hardlink -- expect ENOTSUP" ); status = lstat( "/node-link", &stat_buf ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == ENOTSUP ); puts( "Changing euid to 10" ); status = seteuid( 10 ); rtems_test_assert( status == 0 ); #if defined(RTEMS_POSIX_API) puts( "Attempt chmod on /node -- expect EPERM" ); status = chmod( "/node", S_IRUSR ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == EPERM ); puts( "Attempt chown on /node -- expect EPERM" ); status = chown( "/node", 10, 10 ); rtems_test_assert( status == -1 ); rtems_test_assert( errno == EPERM ); #else puts( "Attempt chmod on /node -- EPERM only when POSIX enabled" ); puts( "Attempt chown on /node -- EPERM only when POSIX enabled" ); #endif puts( "Changing euid back to 0 [root]" ); status = seteuid( 0 ); rtems_test_assert( status == 0 ); puts( "Creating a fifo -- OK" ); status = mkfifo( "/fifo", S_IRWXU ); rtems_test_assert( status == 0 ); IMFS_dump(); puts( "chown /fifo to 10 -- OK" ); status = chown( "/fifo", 10, 10 ); rtems_test_assert( status == 0 ); puts( "Changing euid to 10" ); status = seteuid( 10 ); rtems_test_assert( status == 0 ); puts( "chmod /fifo -- OK" ); status = chmod( "/fifo", S_IRWXU ); rtems_test_assert( status == 0 ); printk( "chown /fifo to %o -- OK", 0 ); status = chown( "/fifo", 0, 0 ); rtems_test_assert( status == 0 ); puts( "*** END OF TEST IMFS 02 ***" ); rtems_test_exit(0); }
int main(int argc, char **argv) { struct dialup *dial; struct dialup dent; struct stat sb; FILE *fp; char *sh = 0; char *cp; char pass[BUFSIZ]; int fd; int found = 0; int opt; Prog = Basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); while ((opt = getopt (argc, argv, "a:d:")) != EOF) { switch (opt) { case 'a': aflg++; sh = optarg; break; case 'd': dflg++; sh = optarg; break; default: usage (); } } if (! aflg && ! dflg) aflg++; if (! sh) { if (optind >= argc) usage (); else sh = argv[optind]; } if (aflg + dflg != 1) usage (); /* * Add a new shell to the password file, or update an existing * entry. Begin by getting an encrypted password for this * shell. */ if (aflg) { int tries = 3; dent.du_shell = sh; dent.du_passwd = ""; /* XXX warning: const */ again: if (! (cp = getpass(_("Shell password: "******"re-enter Shell password: "******"%s: Passwords do not match, try again.\n"), Prog); if (--tries) goto again; exit(1); } strzero(cp); dent.du_passwd = pw_encrypt(pass, crypt_make_salt()); strzero(pass); } /* * Create the temporary file for the updated dialup password * information to be placed into. Turn it into a (FILE *) * for use by putduent(). */ if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) { snprintf(pass, sizeof pass, _("%s: can't create %s"), Prog, DTMP); perror (pass); exit (1); } if (! (fp = fdopen (fd, "r+"))) { snprintf(pass, sizeof pass, _("%s: can't open %s"), Prog, DTMP); perror (pass); unlink (DTMP); exit (1); } /* * Scan the dialup password file for the named entry, * copying out other entries along the way. Copying * stops when a match is found or the file runs out. */ while ((dial = getduent ())) { if (strcmp (dial->du_shell, sh) == 0) { found = 1; break; } if (putduent (dial, fp)) goto failure; } /* * To delete the entry, just don't copy it. To update * the entry, output the modified version - works with * new entries as well. */ if (dflg && ! found) { fprintf(stderr, _("%s: Shell %s not found.\n"), Prog, sh); goto failure; } if (aflg) if (putduent (&dent, fp)) goto failure; /* * Now copy out the remaining entries. Flush and close the * new file before doing anything nasty to the existing * file. */ while ((dial = getduent ())) if (putduent (dial, fp)) goto failure; if (fflush (fp)) goto failure; fclose (fp); /* * If the original file did not exist, we must create a new * file with owner "root" and mode 400. Otherwise we copy * the modes from the existing file to the new file. * * After this is done the new file will replace the old file. */ pwd_init(); if (! stat (DIALPWD, &sb)) { chown (DTMP, sb.st_uid, sb.st_gid); chmod (DTMP, sb.st_mode); unlink (DIALPWD); } else { chown (DTMP, 0, 0); chmod (DTMP, 0400); } if (! link (DTMP, DIALPWD)) unlink (DTMP); if (aflg && ! found) SYSLOG((LOG_INFO, DIALADD, sh)); else if (aflg && found) SYSLOG((LOG_INFO, DIALCHG, sh)); else if (dflg) SYSLOG((LOG_INFO, DIALREM, sh)); closelog(); sync (); exit (0); failure: unlink (DTMP); closelog(); exit (1); }
static int node_permissions_apply(struct udev_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid, struct udev_list *seclabel_list) { const char *devnode = udev_device_get_devnode(dev); dev_t devnum = udev_device_get_devnum(dev); struct stat stats; struct udev_list_entry *entry; int err = 0; if (streq(udev_device_get_subsystem(dev), "block")) mode |= S_IFBLK; else mode |= S_IFCHR; if (lstat(devnode, &stats) != 0) { err = -errno; log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); goto out; } if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) { err = -EEXIST; log_debug("found node '%s' with non-matching devnum %s, skip handling", udev_device_get_devnode(dev), udev_device_get_id_filename(dev)); goto out; } if (apply) { bool selinux = false; bool smack = false; if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); err = chmod(devnode, mode); if (err < 0) log_warning_errno(errno, "setting mode of %s to %#o failed: %m", devnode, mode); err = chown(devnode, uid, gid); if (err < 0) log_warning_errno(errno, "setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid); } else { log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); } /* apply SECLABEL{$module}=$label */ udev_list_entry_foreach(entry, udev_list_get_entry(seclabel_list)) { const char *name, *label; int r; name = udev_list_entry_get_name(entry); label = udev_list_entry_get_value(entry); if (streq(name, "selinux")) { selinux = true; r = mac_selinux_apply(devnode, label); if (r < 0) log_error_errno(r, "SECLABEL: failed to set SELinux label '%s': %m", label); else log_debug("SECLABEL: set SELinux label '%s'", label); } else if (streq(name, "smack")) { smack = true; r = mac_smack_apply(devnode, label); if (r < 0) log_error_errno(r, "SECLABEL: failed to set SMACK label '%s': %m", label); else log_debug("SECLABEL: set SMACK label '%s'", label); } else log_error("SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label); } /* set the defaults */ if (!selinux) mac_selinux_fix(devnode, true, false); if (!smack) mac_smack_apply(devnode, NULL); } /* always update timestamp when we re-use the node, like on media change events */ utimensat(AT_FDCWD, devnode, NULL, 0); out: return err; }
int copy_file(const char *source, const char *dest, int flags) { struct stat source_stat; struct stat dest_stat; int status = 0; signed char dest_exists = 0; signed char ovr; #define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE) if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { // This may be a dangling symlink. // Making [sym]links to dangling symlinks works, so... if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) goto make_links; bb_perror_msg("cannot stat '%s'", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { bb_perror_msg("cannot stat '%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino ) { bb_error_msg("'%s' and '%s' are the same file", source, dest); return -1; } dest_exists = 1; } if (S_ISDIR(source_stat.st_mode)) { DIR *dp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { bb_error_msg("omitting directory '%s'", source); return -1; } /* Create DEST. */ if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); return -1; } } else { mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); bb_perror_msg("cannot create directory '%s'", dest); return -1; } umask(saved_umask); } /* Recursively copy files in SOURCE. */ dp = opendir(source); if (dp == NULL) { status = -1; goto preserve_status; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; new_source = concat_subpath_file(source, d->d_name); if (new_source == NULL) continue; new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags) < 0) status = -1; free(new_source); free(new_dest); } closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 ) { bb_perror_msg("cannot change permissions of '%s'", dest); status = -1; } } else if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { int (*lf)(const char *oldpath, const char *newpath); make_links: // Hmm... maybe // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ? // (but realpath returns NULL on dangling symlinks...) lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; if (lf(source, dest) < 0) { ovr = retry_overwrite(dest, flags); if (ovr <= 0) return ovr; if (lf(source, dest) < 0) { bb_perror_msg("cannot create link '%s'", dest); return -1; } } return 0; } else if (S_ISREG(source_stat.st_mode) // Huh? DEREF uses stat, which never returns links IIRC... || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) ) { int src_fd; int dst_fd; if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { char *link_name; if (!FLAGS_DEREF && is_in_ino_dev_hashtable(&source_stat, &link_name) ) { if (link(link_name, dest) < 0) { ovr = retry_overwrite(dest, flags); if (ovr <= 0) return ovr; if (link(link_name, dest) < 0) { bb_perror_msg("cannot create link '%s'", dest); return -1; } } return 0; } // TODO: probably is_in_.. and add_to_... // can be combined: find_or_add_... add_to_ino_dev_hashtable(&source_stat, dest); } src_fd = open(source, O_RDONLY); if (src_fd == -1) { bb_perror_msg("cannot open '%s'", source); return -1; } // POSIX: if exists and -i, ask (w/o -i assume yes). // Then open w/o EXCL. // If open still fails and -f, try unlink, then try open again. // Result: a mess: // If dest is a softlink, we overwrite softlink's destination! // (or fail, if it points to dir/nonexistent location/etc). // This is strange, but POSIX-correct. // coreutils cp has --remove-destination to override this... dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE) ? O_WRONLY|O_CREAT|O_TRUNC|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); if (dst_fd == -1) { // We would not do POSIX insanity. -i asks, // then _unlinks_ the offender. Presto. // Or else we will end up having 3 open()s! ovr = retry_overwrite(dest, flags); if (ovr <= 0) { close(src_fd); return ovr; } dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); if (dst_fd == -1) { bb_perror_msg("cannot open '%s'", dest); close(src_fd); return -1; } } if (bb_copyfd_eof(src_fd, dst_fd) == -1) status = -1; if (close(dst_fd) < 0) { bb_perror_msg("cannot close '%s'", dest); status = -1; } if (close(src_fd) < 0) { bb_perror_msg("cannot close '%s'", source); status = -1; } } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) || S_ISLNK(source_stat.st_mode) ) { // We are lazy here, a bit lax with races... if (dest_exists) { ovr = retry_overwrite(dest, flags); if (ovr <= 0) return ovr; } if (S_ISFIFO(source_stat.st_mode)) { if (mkfifo(dest, source_stat.st_mode) < 0) { bb_perror_msg("cannot create fifo '%s'", dest); return -1; } } else if (S_ISLNK(source_stat.st_mode)) { char *lpath; lpath = xreadlink(source); if (symlink(lpath, dest) < 0) { bb_perror_msg("cannot create symlink '%s'", dest); free(lpath); return -1; } free(lpath); if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest); return 0; } else { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { bb_perror_msg("cannot create '%s'", dest); return -1; } } } else { bb_error_msg("internal error: unrecognized file type"); return -1; } preserve_status: if (flags & FILEUTILS_PRESERVE_STATUS /* Cannot happen: */ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */ ) { struct utimbuf times; times.actime = source_stat.st_atime; times.modtime = source_stat.st_mtime; if (utime(dest, ×) < 0) bb_perror_msg("cannot preserve %s of '%s'", "times", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest); } if (chmod(dest, source_stat.st_mode) < 0) bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest); } return status; }
void test30a() { /* Test normal operation. */ #define BUF_SIZE 1024 int fd1, fd2; char buf[BUF_SIZE]; struct stat st, dirst; time_t time1, time2; int stat_loc, cnt; subtest = 1; System("rm -rf ../DIR_30/*"); /* Check if processes have independent new fds */ switch (fork()) { case -1: printf("Can't fork\n"); break; case 0: alarm(20); if ((fd1 = creat("myfile", 0644)) != 3) e(1); if (close(fd1) != 0) e(2); exit(0); default: if ((fd1 = creat("myfile", 0644)) != 3) e(3); if (close(fd1) != 0) e(4); if (wait(&stat_loc) == -1) e(5); if (stat_loc != 0) e(6); } /* Save the dir status. */ Stat(".", &dirst); time(&time1); while (time1 == time((time_t *)0)) ; /* Check if the file status information is updated correctly */ cnt = 0; System("rm -rf myfile"); do { time(&time1); if ((fd1 = creat("myfile", 0644)) != 3) e(7); Stat("myfile", &st); time(&time2); } while (time1 != time2 && cnt++ < 100); if (cnt >= 100) e(8); if (st.st_uid != geteuid()) e(9); /* Uid should be set. */ #if defined(NGROUPS_MAX) && NGROUPS_MAX == 0 if (st.st_gid != getegid()) e(10); #endif /* defined(NGROUPS_MAX) && NGROUPS_MAX == 0 */ if (!S_ISREG(st.st_mode)) e(11); if ((st.st_mode & 0777) != 0644) e(12); if (st.st_nlink != 1) e(13); if (st.st_ctime != time1) e(14); /* All time fields should be updated */ if (st.st_atime != time1) e(15); if (st.st_mtime != time1) e(16); if (st.st_size != 0) e(17); /* File should be trunked. */ /* Check if c and mtime for "." is updated. */ Stat(".", &st); if (st.st_ctime <= dirst.st_ctime) e(18); if (st.st_mtime <= dirst.st_mtime) e(19); /* Let's see if cread fds are write only. */ if (read(fd1, buf, 7) != -1) e(20); /* we can't read */ if (errno != EBADF) e(21); /* a write only fd */ if (write(fd1, "HELLO", 6) != 6) e(22); /* but we can write */ /* No O_APPEND flag should have been used. */ if (lseek(fd1, (off_t) 1, SEEK_SET) != 1) e(23); if (write(fd1, "ello", 5) != 5) e(24); Stat("myfile", &st); if (st.st_size != 6) e(25); if (st.st_size == 11) e(26); /* O_APPEND should make it 11. */ if (close(fd1) != 0) e(27); /* A creat should set the file offset to 0. */ if ((fd1 = creat("myfile", 0644)) != 3) e(28); if (lseek(fd1, (off_t) 0, SEEK_CUR) != 0) e(29); if (close(fd1) != 0) e(30); /* Test if file permission bits and the file ownership are unchanged. */ /* So we will see if creat() is just an open() if the file exists. */ if (superuser) { System("echo > bar; chmod 073 bar"); /* Make bar 073 */ if (chown("bar", 1, 1) != 0) e(1137); fd1 = creat("bar", 0777); /* knock knock */ if (fd1 == -1) e(31); Stat("bar", &st); if (st.st_size != (size_t) 0) e(32); /* empty file. */ if (write(fd1, "foo", 3) != 3) e(33); /* rewrite bar */ if (close(fd1) != 0) e(34); Stat("bar", &st); if (st.st_uid != 1) e(35); if (st.st_gid != 1) e(36); if ((st.st_mode & 0777) != 073) e(37); /* mode still is 077 */ if (st.st_size != (size_t) 3) e(38); } /* Fifo's should be openable with creat(). */ if (mkfifo("fifo", 0644) != 0) e(39); /* Creat() should have no effect on FIFO files. */ switch (fork()) { case -1: printf("Can't fork\n"); break; case 0: alarm(20); /* Give child 20 seconds to live. */ if ((fd1 = open("fifo", O_WRONLY)) != 3) e(40); if (write(fd1, "I did see Elvis.\n", 18) != 18) e(41); if ((fd2 = creat("fifo", 0644)) != 4) e(42); if (write(fd2, "I DID.\n", 8) != 8) e(43); if (close(fd2) != 0) e(44); if (close(fd1) != 0) e(45); exit(0); default: if ((fd1 = open("fifo", O_RDONLY)) != 3) e(46); if (read(fd1, buf, 18) != 18) e(47); if (strcmp(buf, "I did see Elvis.\n") != 0) e(48); if (strcmp(buf, "I DID.\n") == 0) e(49); if (read(fd1, buf, BUF_SIZE) != 8) e(50); if (strcmp(buf, "I DID.\n") != 0) e(51); if (close(fd1) != 0) e(52); if (wait(&stat_loc) == -1) e(53); if (stat_loc != 0) e(54); /* The alarm went off? */ } /* Creat() should have no effect on directroys. */ System("mkdir dir; touch dir/f1 dir/f2 dir/f3"); if ((fd1 = creat("dir", 0644)) != -1) e(55); if (errno != EISDIR) e(56); close(fd1); /* The path should contain only dirs in the prefix. */ if ((fd1 = creat("dir/f1/nono", 0644)) != -1) e(57); if (errno != ENOTDIR) e(58); close(fd1); /* The path should contain only dirs in the prefix. */ if ((fd1 = creat("", 0644)) != -1) e(59); if (errno != ENOENT) e(60); close(fd1); if ((fd1 = creat("dir/noso/nono", 0644)) != -1) e(61); if (errno != ENOENT) e(62); close(fd1); }
/* __CFWriteBytesToFileWithAtomicity is a "safe save" facility. Write the bytes using the specified mode on the file to the provided URL. If the atomic flag is true, try to do it in a fashion that will enable a safe save. */ static Boolean __CFWriteBytesToFileWithAtomicity(CFURLRef url, const void *bytes, int length, SInt32 mode, Boolean atomic) { int fd = -1; char auxPath[CFMaxPathSize + 16]; char cpath[CFMaxPathSize]; uid_t owner = getuid(); gid_t group = getgid(); Boolean writingFileAsRoot = ((getuid() != geteuid()) && (geteuid() == 0)); if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)cpath, CFMaxPathSize)) { return false; } if (-1 == mode || writingFileAsRoot) { struct stat statBuf; if (0 == stat(cpath, &statBuf)) { mode = statBuf.st_mode; owner = statBuf.st_uid; group = statBuf.st_gid; } else { mode = 0664; if (writingFileAsRoot && (0 == strncmp(cpath, "/Library/Preferences", 20))) { owner = geteuid(); group = 80; } } } if (atomic) { CFURLRef dir = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url); CFURLRef tempFile = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, dir, CFSTR("cf#XXXXX"), false); CFRelease(dir); if (!CFURLGetFileSystemRepresentation(tempFile, true, (uint8_t *)auxPath, CFMaxPathSize)) { CFRelease(tempFile); return false; } CFRelease(tempFile); fd = mkstemp(auxPath); } else { fd = open(cpath, O_WRONLY|O_CREAT|O_TRUNC, mode); } if (fd < 0) return false; if (length && (write(fd, bytes, length) != length || fsync(fd) < 0)) { int saveerr = thread_errno(); close(fd); if (atomic) unlink(auxPath); thread_set_errno(saveerr); return false; } close(fd); if (atomic) { // preserve the mode as passed in originally chmod(auxPath, mode); if (0 != rename(auxPath, cpath)) { unlink(auxPath); return false; } // If the file was renamed successfully and we wrote it as root we need to reset the owner & group as they were. if (writingFileAsRoot) { chown(cpath, owner, group); } } return true; }
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { char *slash = strrchr(file_header->name, '/'); if (slash) { *slash = '\0'; bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); *slash = '/'; } } if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { /* Remove the entry if it exists */ if ((!S_ISDIR(file_header->mode)) && (unlink(file_header->name) == -1) && (errno != ENOENT) ) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat existing_sb; if (lstat(file_header->name, &existing_sb) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("can't stat old file"); } } else if (existing_sb.st_mtime >= file_header->mtime) { if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { bb_error_msg("%s not created: newer or " "same age file exists", file_header->name); } data_skip(archive_handle); return; } else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } /* Handle hard links separately * We identified hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 ) { /* hard link */ res = link(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("can't create %slink " "from %s to %s", "hard", file_header->name, file_header->link_target); } } else { /* Create the filesystem entry */ switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; dst_fd = xopen3(file_header->name, flags, file_header->mode ); bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((res == -1) && (errno != EISDIR) /* btw, Linux doesn't return this */ && (errno != EEXIST) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't make dir %s", file_header->name); } break; case S_IFLNK: /* Symlink */ res = symlink(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create %slink " "from %s to %s", "sym", file_header->name, file_header->link_target); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create node %s", file_header->name); } break; default: bb_error_msg_and_die("unrecognized file type"); } } if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { #if ENABLE_FEATURE_TAR_UNAME_GNAME if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { uid_t uid = file_header->uid; gid_t gid = file_header->gid; if (file_header->tar__uname) { //TODO: cache last name/id pair? struct passwd *pwd = getpwnam(file_header->tar__uname); if (pwd) uid = pwd->pw_uid; } if (file_header->tar__gname) { struct group *grp = getgrnam(file_header->tar__gname); if (grp) gid = grp->gr_gid; } /* GNU tar 1.15.1 uses chown, not lchown */ chown(file_header->name, uid, gid); } else #endif chown(file_header->name, file_header->uid, file_header->gid); } if (!S_ISLNK(file_header->mode)) { /* uclibc has no lchmod, glibc is even stranger - * it has lchmod which seems to do nothing! * so we use chmod... */ if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { chmod(file_header->name, file_header->mode); } /* same for utime */ if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { struct timeval t[2]; t[1].tv_sec = t[0].tv_sec = file_header->mtime; t[1].tv_usec = t[0].tv_usec = 0; utimes(file_header->name, t); } } }
void copylink(char *source, char *dest, int mode, int owner, int group) { struct stat sst, dst; int sfd, dfd, n; int r, same= 0, change= 0, docopy= 1; char buf[4096]; # define hdr ((struct exec *) buf) pid_t pid; int status; /* Source must exist as a plain file, dest may exist as a plain file. */ if (stat(source, &sst) < 0) { report(source); return; } if (mode == -1) { mode= sst.st_mode & 07777; if (!lflag || cflag) { mode|= 0444; if (mode & 0111) mode|= 0111; } } if (owner == -1) owner= sst.st_uid; if (group == -1) group= sst.st_gid; if (!S_ISREG(sst.st_mode)) { fprintf(stderr, "install: %s is not a regular file\n", source); excode= 1; return; } r= stat(dest, &dst); if (r < 0) { if (errno != ENOENT) { report(dest); return; } } else { if (!S_ISREG(dst.st_mode)) { fprintf(stderr, "install: %s is not a regular file\n", dest); excode= 1; return; } /* Are the files the same? */ if (sst.st_dev == dst.st_dev && sst.st_ino == dst.st_ino) { if (!lflag && cflag) { fprintf(stderr, "install: %s and %s are the same, can't copy\n", source, dest); excode= 1; return; } same= 1; } } if (lflag && !same) { /* Try to link the files. */ if (r >= 0 && unlink(dest) < 0) { report(dest); return; } if (link(source, dest) >= 0) { docopy= 0; } else { if (!cflag || errno != EXDEV) { fprintf(stderr, "install: can't link %s to %s: %s\n", source, dest, strerror(errno)); excode= 1; return; } } } if (docopy && !same) { /* Copy the files, stripping if necessary. */ long count= LONG_MAX; int first= 1; if ((sfd= open(source, O_RDONLY)) < 0) { report(source); return; } /* Open for write is less simple, its mode may be 444. */ dfd= open(dest, O_WRONLY|O_CREAT|O_TRUNC, mode | 0600); if (dfd < 0 && errno == EACCES) { (void) chmod(dest, mode | 0600); dfd= open(dest, O_WRONLY|O_TRUNC); } if (dfd < 0) { report(dest); close(sfd); return; } pid= 0; while (count > 0 && (n= read(sfd, buf, sizeof(buf))) > 0) { if (first && n >= A_MINHDR && !BADMAG(*hdr)) { if (strip) { count= hdr->a_hdrlen + hdr->a_text + hdr->a_data; #ifdef A_NSYM hdr->a_flags &= ~A_NSYM; #endif hdr->a_syms= 0; } if (stack != -1 && setstack(hdr)) change= 1; if (compress != nil) { /* Write first #! line. */ (void) write(dfd, zcat, strlen(zcat)); /* Put a compressor in between. */ if ((pid= filter(dfd, compress)) < 0) { close(sfd); close(dfd); return; } change= 1; } } if (count < n) n= count; if (write(dfd, buf, n) < 0) { report(dest); close(sfd); close(dfd); if (pid != 0) (void) waitpid(pid, nil, 0); return; } count-= n; first= 0; } if (n < 0) report(source); close(sfd); close(dfd); if (pid != 0 && waitpid(pid, &status, 0) < 0 || status != 0) { excode= 1; return; } if (n < 0) return; } else { if (stack != -1) { /* The file has been linked into place. Set the * stack size. */ if ((dfd= open(dest, O_RDWR)) < 0) { report(dest); return; } if ((n= read(dfd, buf, sizeof(*hdr))) < 0) { report(dest); return; } if (n >= A_MINHDR && !BADMAG(*hdr) && setstack(hdr)) { if (lseek(dfd, (off_t) 0, SEEK_SET) == -1 || write(dfd, buf, n) < 0 ) { report(dest); close(dfd); return; } change= 1; } close(dfd); } } if (stat(dest, &dst) < 0) { report(dest); return; } if ((dst.st_mode & 07777) != mode) { if (chmod(dest, mode) < 0) { report(dest); return; } } if (dst.st_uid != owner || dst.st_gid != group) { if (chown(dest, owner, group) < 0 && errno != EPERM) { report(dest); return; } /* Set the mode again, chown may have wrecked it. */ (void) chmod(dest, mode); } if (!change) { struct utimbuf ubuf; ubuf.actime= dst.st_atime; ubuf.modtime= sst.st_mtime; if (utime(dest, &ubuf) < 0 && errno != EPERM) { report(dest); return; } } }
int main(int argc, char *argv[]) { struct passwd *pw; struct group *gptr; const char *arg, *cp, *printer; char *p; char buf[BUFSIZ]; int c, i, f, errs; int ret, didlink; struct stat stb; struct stat statb1, statb2; struct printer myprinter, *pp = &myprinter; printer = NULL; euid = geteuid(); uid = getuid(); PRIV_END if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, cleanup); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, cleanup); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, cleanup); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, cleanup); progname = argv[0]; gethostname(local_host, sizeof(local_host)); openlog("lpd", 0, LOG_LPR); errs = 0; while ((c = getopt(argc, argv, ":#:1:2:3:4:C:J:L:P:T:U:Z:cdfghi:lnmprstvw:")) != -1) switch (c) { case '#': /* n copies */ i = strtol(optarg, &p, 10); if (*p) errx(1, "Bad argument to -#, number expected"); if (i > 0) ncopies = i; break; case '1': /* troff fonts */ case '2': case '3': case '4': fonts[optopt - '1'] = optarg; break; case 'C': /* classification spec */ hdr++; class = optarg; break; case 'J': /* job name */ hdr++; jobname = optarg; break; case 'P': /* specifiy printer name */ printer = optarg; break; case 'L': /* pr's locale */ locale = optarg; break; case 'T': /* pr's title line */ title = optarg; break; case 'U': /* user name */ hdr++; Uflag = optarg; break; case 'Z': Zflag = optarg; break; case 'c': /* print cifplot output */ case 'd': /* print tex output (dvi files) */ case 'g': /* print graph(1G) output */ case 'l': /* literal output */ case 'n': /* print ditroff output */ case 't': /* print troff output (cat files) */ case 'p': /* print using ``pr'' */ case 'v': /* print vplot output */ format = optopt; break; case 'f': /* print fortran output */ format = 'r'; break; case 'h': /* nulifiy header page */ hdr = 0; break; case 'i': /* indent output */ iflag++; indent = strtol(optarg, &p, 10); if (*p) errx(1, "Bad argument to -i, number expected"); break; case 'm': /* send mail when done */ mailflg++; break; case 'q': /* just queue job */ qflag++; break; case 'r': /* remove file when done */ rflag++; break; case 's': /* try to link files */ sflag++; break; case 'w': /* versatec page width */ width = optarg; break; case ':': /* catch "missing argument" error */ if (optopt == 'i') { iflag++; /* -i without args is valid */ indent = 8; } else errs++; break; default: errs++; } argc -= optind; argv += optind; if (errs) usage(); if (printer == NULL && (printer = getenv("PRINTER")) == NULL) printer = DEFLP; chkprinter(printer, pp); if (pp->no_copies && ncopies > 1) errx(1, "multiple copies are not allowed"); if (pp->max_copies > 0 && ncopies > pp->max_copies) errx(1, "only %ld copies are allowed", pp->max_copies); /* * Get the identity of the person doing the lpr using the same * algorithm as lprm. Actually, not quite -- lprm will override * the login name with "root" if the user is running as root; * the daemon actually checks for the string "root" in its * permission checking. Sigh. */ userid = getuid(); if (Uflag) { if (userid != 0 && userid != pp->daemon_user) errx(1, "only privileged users may use the `-U' flag"); lpr_username = Uflag; /* -U person doing 'lpr' */ } else { lpr_username = getlogin(); /* person doing 'lpr' */ if (userid != pp->daemon_user || lpr_username == 0) { if ((pw = getpwuid(userid)) == NULL) errx(1, "Who are you?"); lpr_username = pw->pw_name; } } /* * Check for restricted group access. */ if (pp->restrict_grp != NULL && userid != pp->daemon_user) { if ((gptr = getgrnam(pp->restrict_grp)) == NULL) errx(1, "Restricted group specified incorrectly"); if (gptr->gr_gid != getgid()) { while (*gptr->gr_mem != NULL) { if ((strcmp(lpr_username, *gptr->gr_mem)) == 0) break; gptr->gr_mem++; } if (*gptr->gr_mem == NULL) errx(1, "Not a member of the restricted group"); } } /* * Check to make sure queuing is enabled if userid is not root. */ lock_file_name(pp, buf, sizeof buf); if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS)) errx(1, "Printer queue is disabled"); /* * Initialize the control file. */ mktemps(pp); tfd = nfile(tfname); PRIV_START (void) fchown(tfd, pp->daemon_user, -1); /* owned by daemon for protection */ PRIV_END card('H', local_host); card('P', lpr_username); card('C', class); if (hdr && !pp->no_header) { if (jobname == NULL) { if (argc == 0) jobname = "stdin"; else jobname = ((arg = strrchr(argv[0], '/')) ? arg + 1 : argv[0]); } card('J', jobname); card('L', lpr_username); } if (format != 'p' && Zflag != 0) card('Z', Zflag); if (iflag) card('I', itoa(indent)); if (mailflg) card('M', lpr_username); if (format == 't' || format == 'n' || format == 'd') for (i = 0; i < 4; i++) if (fonts[i] != NULL) card('1'+i, fonts[i]); if (width != NULL) card('W', width); /* * XXX * Our use of `Z' here is incompatible with LPRng's * use. We assume that the only use of our existing * `Z' card is as shown for `p' format (pr) files. */ if (format == 'p') { char *s; if (locale) card('Z', locale); else if ((s = setlocale(LC_TIME, "")) != NULL) card('Z', s); } /* * Read the files and spool them. */ if (argc == 0) copy(pp, 0, " "); else while (argc--) { if (argv[0][0] == '-' && argv[0][1] == '\0') { /* use stdin */ copy(pp, 0, " "); argv++; continue; } if ((f = test(arg = *argv++)) < 0) continue; /* file unreasonable */ if (sflag && (cp = linked(arg)) != NULL) { (void)snprintf(buf, sizeof(buf), "%ju %ju", (uintmax_t)statb.st_dev, (uintmax_t)statb.st_ino); card('S', buf); if (format == 'p') card('T', title ? title : arg); for (i = 0; i < ncopies; i++) card(format, &dfname[inchar-2]); card('U', &dfname[inchar-2]); if (f) card('U', cp); card('N', arg); dfname[inchar]++; nact++; continue; } if (sflag) printf("%s: %s: not linked, copying instead\n", progname, arg); if (f) { /* * The user wants the file removed after it is copied * to the spool area, so see if the file can be moved * instead of copy/unlink'ed. This is much faster and * uses less spool space than copying the file. This * can be very significant when running services like * samba, pcnfs, CAP, et al. */ PRIV_START didlink = 0; /* * There are several things to check to avoid any * security issues. Some of these are redundant * under BSD's, but are necessary when lpr is built * under some other OS's (which I do do...) */ if (lstat(arg, &statb1) < 0) goto nohardlink; if (S_ISLNK(statb1.st_mode)) goto nohardlink; if (link(arg, dfname) != 0) goto nohardlink; didlink = 1; /* * Make sure the user hasn't tried to trick us via * any race conditions */ if (lstat(dfname, &statb2) < 0) goto nohardlink; if (statb1.st_dev != statb2.st_dev) goto nohardlink; if (statb1.st_ino != statb2.st_ino) goto nohardlink; /* * Skip if the file already had multiple hard links, * because changing the owner and access-bits would * change ALL versions of the file */ if (statb2.st_nlink > 2) goto nohardlink; /* * If we can access and remove the original file * without special setuid-ness then this method is * safe. Otherwise, abandon the move and fall back * to the (usual) copy method. */ PRIV_END ret = access(dfname, R_OK); if (ret == 0) ret = unlink(arg); PRIV_START if (ret != 0) goto nohardlink; /* * Unlink of user file was successful. Change the * owner and permissions, add entries to the control * file, and skip the file copying step. */ chown(dfname, pp->daemon_user, getegid()); chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); PRIV_END if (format == 'p') card('T', title ? title : arg); for (i = 0; i < ncopies; i++) card(format, &dfname[inchar-2]); card('U', &dfname[inchar-2]); card('N', arg); nact++; continue; nohardlink: if (didlink) unlink(dfname); PRIV_END /* restore old uid */ } /* end: if (f) */ if ((i = open(arg, O_RDONLY)) < 0) { printf("%s: cannot open %s\n", progname, arg); } else { copy(pp, i, arg); (void) close(i); if (f && unlink(arg) < 0) printf("%s: %s: not removed\n", progname, arg); } } if (nact) { (void) close(tfd); tfname[inchar]--; /* * Touch the control file to fix position in the queue. */ PRIV_START if ((tfd = open(tfname, O_RDWR)) >= 0) { char touch_c; if (read(tfd, &touch_c, 1) == 1 && lseek(tfd, (off_t)0, 0) == 0 && write(tfd, &touch_c, 1) != 1) { printf("%s: cannot touch %s\n", progname, tfname); tfname[inchar]++; cleanup(0); } (void) close(tfd); } if (link(tfname, cfname) < 0) { printf("%s: cannot rename %s\n", progname, cfname); tfname[inchar]++; cleanup(0); } unlink(tfname); PRIV_END if (qflag) /* just q things up */ exit(0); if (!startdaemon(pp)) printf("jobs queued, but cannot start daemon.\n"); exit(0); } cleanup(0); return (1); /* NOTREACHED */ }
int virNetSocketNewListenUNIX(const char *path, mode_t mask, uid_t user, gid_t grp, virNetSocketPtr *retsock) { virSocketAddr addr; mode_t oldmask; int fd; *retsock = NULL; memset(&addr, 0, sizeof(addr)); addr.len = sizeof(addr.data.un); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { virReportSystemError(errno, "%s", _("Failed to create socket")); goto error; } addr.data.un.sun_family = AF_UNIX; if (virStrcpyStatic(addr.data.un.sun_path, path) == NULL) { virReportSystemError(ENAMETOOLONG, _("Path %s too long for unix socket"), path); goto error; } if (addr.data.un.sun_path[0] == '@') addr.data.un.sun_path[0] = '\0'; else unlink(addr.data.un.sun_path); oldmask = umask(~mask); if (bind(fd, &addr.data.sa, addr.len) < 0) { umask(oldmask); virReportSystemError(errno, _("Failed to bind socket to '%s'"), path); goto error; } umask(oldmask); /* chown() doesn't work for abstract sockets but we use them only * if libvirtd runs unprivileged */ if (grp != 0 && chown(path, user, grp)) { virReportSystemError(errno, _("Failed to change ownership of '%s' to %d:%d"), path, (int) user, (int) grp); goto error; } if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0))) goto error; return 0; error: if (path[0] != '@') unlink(path); VIR_FORCE_CLOSE(fd); return -1; }