diff options
Diffstat (limited to 'src/rc/checkpath.c')
-rw-r--r-- | src/rc/checkpath.c | 452 |
1 files changed, 0 insertions, 452 deletions
diff --git a/src/rc/checkpath.c b/src/rc/checkpath.c deleted file mode 100644 index 550e7cea..00000000 --- a/src/rc/checkpath.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * checkpath.c - * Checks for the existance of a file or directory and creates it - * if necessary. It can also correct its ownership. - */ - -/* - * Copyright (c) 2007-2015 The OpenRC Authors. - * See the Authors file at the top-level directory of this distribution and - * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS - * - * This file is part of OpenRC. It is subject to the license terms in - * the LICENSE file found in the top-level directory of this - * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE - * This file may not be copied, modified, propagated, or distributed - * except according to the terms contained in the LICENSE file. - */ - -#define _GNU_SOURCE -#include <sys/types.h> -#include <sys/stat.h> - -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <grp.h> -#include <libgen.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "einfo.h" -#include "rc.h" -#include "rc-misc.h" -#include "rc-selinux.h" -#include "_usage.h" - -typedef enum { - inode_unknown = 0, - inode_file = 1, - inode_dir = 2, - inode_fifo = 3, -} inode_t; - -const char *applet = NULL; -const char *extraopts ="path1 [path2] [...]"; -const char getoptstring[] = "dDfFpm:o:sW" getoptstring_COMMON; -const struct option longopts[] = { - { "directory", 0, NULL, 'd'}, - { "directory-truncate", 0, NULL, 'D'}, - { "file", 0, NULL, 'f'}, - { "file-truncate", 0, NULL, 'F'}, - { "pipe", 0, NULL, 'p'}, - { "mode", 1, NULL, 'm'}, - { "owner", 1, NULL, 'o'}, - { "symlinks", 0, NULL, 's'}, - { "writable", 0, NULL, 'W'}, - longopts_COMMON -}; -const char * const longopts_help[] = { - "Create a directory if not exists", - "Create/empty directory", - "Create a file if not exists", - "Truncate file", - "Create a named pipe (FIFO) if not exists", - "Mode to check", - "Owner to check (user:group)", - "follow symbolic links (irrelivent on linux)", - "Check whether the path is writable or not", - longopts_help_COMMON -}; -const char *usagestring = NULL; - -static int get_dirfd(char *path, bool symlinks) -{ - char *ch; - char *item; - char *linkpath = NULL; - char *path_dupe; - char *str; - int components = 0; - int dirfd; - int flags = 0; - int new_dirfd; - struct stat st; - ssize_t linksize; - - if (!path || *path != '/') - eerrorx("%s: empty or relative path", applet); - dirfd = openat(dirfd, "/", O_RDONLY); - if (dirfd == -1) - eerrorx("%s: unable to open the root directory: %s", - applet, strerror(errno)); - ch = path; - while (*ch) { - if (*ch == '/') - components++; - ch++; - } - path_dupe = xstrdup(path); - item = strtok(path_dupe, "/"); -#ifdef O_PATH - flags |= O_PATH; -#endif - if (!symlinks) - flags |= O_NOFOLLOW; - flags |= O_RDONLY; - while (dirfd > 0 && item && components > 1) { - str = xstrdup(linkpath ? linkpath : item); - new_dirfd = openat(dirfd, str, flags); - if (new_dirfd == -1) - eerrorx("%s: %s: could not open %s: %s", applet, path, str, - strerror(errno)); - if (fstat(new_dirfd, &st) == -1) - eerrorx("%s: %s: unable to stat %s: %s", applet, path, item, - strerror(errno)); - if (S_ISLNK(st.st_mode) ) { - if (st.st_uid != 0) - eerrorx("%s: %s: symbolic link %s not owned by root", - applet, path, str); - linksize = st.st_size+1; - if (linkpath) - free(linkpath); - linkpath = xmalloc(linksize); - memset(linkpath, 0, linksize); - if (readlinkat(new_dirfd, "", linkpath, linksize) != st.st_size) - eerrorx("%s: symbolic link destination changed", applet); - /* - * now follow the symlink. - */ - close(new_dirfd); - } else { - /* now walk down the directory path */ - close(dirfd); - dirfd = new_dirfd; - free(linkpath); - linkpath = NULL; - item = strtok(NULL, "/"); - components--; - } - } - free(path_dupe); - free(linkpath); - return dirfd; -} - -static char *clean_path(char *path) -{ - char *ch; - char *ch2; - char *str; - str = xmalloc(strlen(path) + 1); - ch = path; - ch2 = str; - while (true) { - *ch2 = *ch; - ch++; - ch2++; - if (!*(ch-1)) - break; - while (*(ch - 1) == '/' && *ch == '/') - ch++; - } - /* get rid of trailing / characters */ - while ((ch = strrchr(str, '/'))) { - if (ch == str) - break; - if (!*(ch+1)) - *ch = 0; - else - break; - } - return str; -} - -static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, - inode_t type, bool trunc, bool chowner, bool symlinks, bool selinux_on) -{ - struct stat st; - char *name = NULL; - int dirfd; - int fd; - int flags; - int r; - int readfd; - int readflags; - int u; - - memset(&st, 0, sizeof(st)); - flags = O_CREAT|O_NDELAY|O_WRONLY|O_NOCTTY; - readflags = O_NDELAY|O_NOCTTY|O_RDONLY; -#ifdef O_CLOEXEC - flags |= O_CLOEXEC; - readflags |= O_CLOEXEC; -#endif -#ifdef O_NOFOLLOW - flags |= O_NOFOLLOW; - readflags |= O_NOFOLLOW; -#endif - if (trunc) - flags |= O_TRUNC; - xasprintf(&name, "%s", basename_c(path)); - dirfd = get_dirfd(path, symlinks); - readfd = openat(dirfd, name, readflags); - if (readfd == -1 || (type == inode_file && trunc)) { - if (type == inode_file) { - einfo("%s: creating file", path); - if (!mode) /* 664 */ - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; - u = umask(0); - fd = openat(dirfd, name, flags, mode); - umask(u); - if (fd == -1) { - eerror("%s: open: %s", applet, strerror(errno)); - return -1; - } - if (readfd != -1 && trunc) - close(readfd); - readfd = fd; - } else if (type == inode_dir) { - einfo("%s: creating directory", path); - if (!mode) /* 775 */ - mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; - u = umask(0); - /* We do not recursively create parents */ - r = mkdirat(dirfd, name, mode); - umask(u); - if (r == -1 && errno != EEXIST) { - eerror("%s: mkdirat: %s", applet, - strerror (errno)); - return -1; - } - readfd = openat(dirfd, name, readflags); - if (readfd == -1) { - eerror("%s: unable to open directory: %s", applet, - strerror(errno)); - return -1; - } - } else if (type == inode_fifo) { - einfo("%s: creating fifo", path); - if (!mode) /* 600 */ - mode = S_IRUSR | S_IWUSR; - u = umask(0); - r = mkfifo(path, mode); - umask(u); - if (r == -1 && errno != EEXIST) { - eerror("%s: mkfifo: %s", applet, - strerror (errno)); - return -1; - } - readfd = openat(dirfd, name, readflags); - if (readfd == -1) { - eerror("%s: unable to open fifo: %s", applet, - strerror(errno)); - return -1; - } - } - } - if (fstat(readfd, &st) != -1) { - if (type != inode_dir && S_ISDIR(st.st_mode)) { - eerror("%s: is a directory", path); - close(readfd); - return 1; - } - if (type != inode_file && S_ISREG(st.st_mode)) { - eerror("%s: is a file", path); - close(readfd); - return 1; - } - if (type != inode_fifo && S_ISFIFO(st.st_mode)) { - eerror("%s: is a fifo", path); - close(readfd); - return -1; - } - - if (mode && (st.st_mode & 0777) != mode) { - if ((type != inode_dir) && (st.st_nlink > 1)) { - eerror("%s: chmod: Too many hard links to %s", applet, path); - close(readfd); - return -1; - } - if (S_ISLNK(st.st_mode)) { - eerror("%s: chmod: %s %s", applet, path, " is a symbolic link"); - close(readfd); - return -1; - } - einfo("%s: correcting mode", path); - if (fchmod(readfd, mode)) { - eerror("%s: chmod: %s", applet, strerror(errno)); - close(readfd); - return -1; - } - } - - if (chowner && (st.st_uid != uid || st.st_gid != gid)) { - if ((type != inode_dir) && (st.st_nlink > 1)) { - eerror("%s: chown: %s %s", applet, "Too many hard links to", path); - close(readfd); - return -1; - } - if (S_ISLNK(st.st_mode)) { - eerror("%s: chown: %s %s", applet, path, " is a symbolic link"); - close(readfd); - return -1; - } - einfo("%s: correcting owner", path); - if (fchown(readfd, uid, gid)) { - eerror("%s: chown: %s", applet, strerror(errno)); - close(readfd); - return -1; - } - } - if (selinux_on) - selinux_util_label(path); - } else { - eerror("fstat: %s: %s", path, strerror(errno)); - close(readfd); - return -1; - } - close(readfd); - - return 0; -} - -static int parse_owner(struct passwd **user, struct group **group, - const char *owner) -{ - char *u = xstrdup (owner); - char *g = strchr (u, ':'); - int id = 0; - int retval = 0; - - if (g) - *g++ = '\0'; - - if (user && *u) { - if (sscanf(u, "%d", &id) == 1) - *user = getpwuid((uid_t) id); - else - *user = getpwnam(u); - if (*user == NULL) - retval = -1; - } - - if (group && g && *g) { - if (sscanf(g, "%d", &id) == 1) - *group = getgrgid((gid_t) id); - else - *group = getgrnam(g); - if (*group == NULL) - retval = -1; - } - - free(u); - return retval; -} - -int main(int argc, char **argv) -{ - int opt; - uid_t uid = geteuid(); - gid_t gid = getgid(); - mode_t mode = 0; - struct passwd *pw = NULL; - struct group *gr = NULL; - inode_t type = inode_unknown; - int retval = EXIT_SUCCESS; - bool trunc = false; - bool chowner = false; - bool symlinks = false; - bool writable = false; - bool selinux_on = false; - char *path = NULL; - - applet = basename_c(argv[0]); - while ((opt = getopt_long(argc, argv, getoptstring, - longopts, (int *) 0)) != -1) - { - switch (opt) { - case 'D': - trunc = true; - /* falls through */ - case 'd': - type = inode_dir; - break; - case 'F': - trunc = true; - /* falls through */ - case 'f': - type = inode_file; - break; - case 'p': - type = inode_fifo; - break; - case 'm': - if (parse_mode(&mode, optarg) != 0) - eerrorx("%s: invalid mode `%s'", - applet, optarg); - break; - case 'o': - chowner = true; - if (parse_owner(&pw, &gr, optarg) != 0) - eerrorx("%s: owner `%s' not found", - applet, optarg); - break; - case 's': -#ifndef O_PATH - symlinks = true; -#endif - break; - case 'W': - writable = true; - break; - - case_RC_COMMON_GETOPT - } - } - - if (optind >= argc) - usage(EXIT_FAILURE); - - if (writable && type != inode_unknown) - eerrorx("%s: -W cannot be specified along with -d, -f or -p", applet); - - if (pw) { - uid = pw->pw_uid; - gid = pw->pw_gid; - } - if (gr) - gid = gr->gr_gid; - - if (selinux_util_open() == 1) - selinux_on = true; - - while (optind < argc) { - path = clean_path(argv[optind]); - if (writable) - exit(!is_writable(path)); - if (do_check(path, uid, gid, mode, type, trunc, chowner, - symlinks, selinux_on)) - retval = EXIT_FAILURE; - optind++; - free(path); - } - - if (selinux_on) - selinux_util_close(); - - return retval; -} |