diff options
Diffstat (limited to 'usr/src/tools/pmodes/pmodes.c')
-rw-r--r-- | usr/src/tools/pmodes/pmodes.c | 690 |
1 files changed, 0 insertions, 690 deletions
diff --git a/usr/src/tools/pmodes/pmodes.c b/usr/src/tools/pmodes/pmodes.c deleted file mode 100644 index 6a83865f40..0000000000 --- a/usr/src/tools/pmodes/pmodes.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * $Id: pmodes.c,v 1.23 1999/03/22 14:51:16 casper Exp $ - * - * - * Program to list files from packages with modes that are to - * permissive. Usage: - * - * pmodes [options] pkgdir ... - * - * Pmodes currently has 4 types of modes that are changed: - * - * m remove group/other write permissions of all files, - * except those in the exceptions list. - * w remove user write permission for executables that - * are not root owned. - * s remove g/o read permission for set-uid/set-gid executables - * o change the owner of files/directories that can be safely - * chowned to root. - * - * Any combination of changes can be switched of by specifying -X - * - * The -n option will create a "FILE.new" file for all changed - * pkgmap/prototype files. - * The -D option will limit changes to directories only. - * - * output: - * - * d m oldmode -> newmode pathname - * | ^ whether the file/dir is group writable or even world writable - * > type of file. - * d o owner -> newowner pathname [mode] - * - * - * Casper Dik (Casper.Dik@Holland.Sun.COM) - */ - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <dirent.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/param.h> -#include <sys/stat.h> -#include "binsearch.h" - -static char *exceptions[] = { - "/etc/lp", - "/var/cache/cups", -}; - -static char *exempt_pkgs[] = { - "SUNWSMSdf", /* "data files" package for SMS */ - "SUNWSMSr", /* "root" package for SMS */ - "SUNWSMSsu", /* "user" package for SMS */ - "SUNWnethackr", /* "root" package for nethack */ -}; - -#define NEXEMPT (sizeof (exempt_pkgs) / sizeof (char *)) - -#define PROTO "prototype_" - -#define DEFAULT_SU 0 -#define DEFAULT_OWNER 1 -#define DEFAULT_MODES 1 -#define DEFAULT_USERWRITE 1 -#define DEFAULT_DIRSONLY 0 -#define DEFAULT_EDITABLE 1 - -static int nexceptions = sizeof (exceptions)/sizeof (char *); -static int dosu = DEFAULT_SU; -static int doowner = DEFAULT_OWNER; -static int domodes = DEFAULT_MODES; -static int douserwrite = DEFAULT_USERWRITE; -static int dirsonly = DEFAULT_DIRSONLY; -static int editable = DEFAULT_EDITABLE; -static int makenew = 0; -static int installnew = 0; -static int diffout = 0; -static int proto = 0; -static int verbose = 0; -static int quiet = 0; -static int errors = 0; - -static void update_map(char *, char *, int); - -static char *program; - -itemlist restrictto = NULL; - -static void -usage(void) { - (void) fprintf(stderr, - "Usage: %s [-DowsnNmdePvq] [-r file] pkgdir ...\n", program); - exit(1); -} - -int -main(int argc, char **argv) -{ - char buf[8192]; - int c; - extern int optind, opterr; - - opterr = 0; - - program = argv[0]; - - while ((c = getopt(argc, argv, "eDowsnNmdPvqr:")) != EOF) { - switch (c) { - case 's': dosu = !DEFAULT_SU; break; - case 'o': doowner = !DEFAULT_OWNER; break; - case 'm': domodes = !DEFAULT_MODES; break; - case 'w': douserwrite = !DEFAULT_USERWRITE; break; - case 'D': dirsonly = !DEFAULT_DIRSONLY; break; - case 'e': editable = !DEFAULT_EDITABLE; break; - case 'N': installnew = 1; /* FALLTHROUGH */ - case 'n': makenew = 1; break; - case 'd': diffout = 1; break; - case 'P': proto = 1; break; - case 'v': verbose = 1; break; - case 'q': quiet = 1; break; - case 'r': - if (restrictto == NULL) - restrictto = new_itemlist(); - if (item_addfile(restrictto, optarg) != 0) { - perror(optarg); - exit(1); - } - break; - default: - case '?': usage(); break; - } - } - argc -= optind; - argv += optind; - - if (argc < 1) - usage(); - - for (; *argv; argv++) { - FILE *info; - char name[MAXPATHLEN]; - char basedir[MAXPATHLEN] = "/"; - int basedir_len; - struct stat stb; - int isfile = 0; - boolean_t exempt = B_FALSE; - - /* - * If a plain file is passed on the command line, we assume - * it's a prototype or pkgmap file and try to find the matching - * pkginfo file - */ - if (lstat(*argv, &stb) == 0 && S_ISREG(stb.st_mode)) { - char *lastslash = strrchr(*argv, '/'); - - if (lastslash != NULL) - *lastslash = '\0'; - (void) sprintf(name, "%s/pkginfo", *argv); - if (lastslash != NULL) - *lastslash = '/'; - isfile = 1; - } else - (void) sprintf(name, "%s/pkginfo", *argv); - - /* if there's no pkginfo file, it could be a prototype area */ - - if (access(name, R_OK) != 0) - (void) strcat(name, ".tmpl"); - - info = fopen(name, "r"); - if (info == 0) { - if (!quiet) - (void) fprintf(stderr, - "Can't open pkginfo file %s\n", name); - continue; - } - - while (fgets(buf, sizeof (buf), info) != NULL && !exempt) { - if (strncmp(buf, "BASEDIR=", 8) == 0) { - (void) strcpy(basedir, buf+8); - basedir[strlen(basedir)-1] = '\0'; - } else if (strncmp(buf, "PKG=", 4) == 0) { - int i; - char *str; - - str = buf + sizeof ("PKG=") - 1; - str[strlen(str)-1] = '\0'; - if (str[0] == '"') - str++; - if (str[strlen(str)-1] == '"') - str[strlen(str)-1] = '\0'; - for (i = 0; i < NEXEMPT; i++) { - if (strcmp(exempt_pkgs[i], str) == 0) { - exempt = B_TRUE; - break; - } - } - } - } - - (void) fclose(info); - - /* exempt package */ - if (exempt) - continue; - - basedir_len = strlen(basedir); - if (basedir_len != 1) - basedir[basedir_len++] = '/'; - - (void) sprintf(name, "%s/pkgmap", *argv); - if (isfile) - update_map(*argv, basedir, basedir_len); - else if (!proto && access(name, R_OK) == 0) - update_map(name, basedir, basedir_len); - else { - DIR *d = opendir(*argv); - struct dirent *de; - - if (d == NULL) { - (void) fprintf(stderr, - "Can't read directory \"%s\"\n", *argv); - continue; - } - while (de = readdir(d)) { - /* Skip files with .old or .new suffix */ - if (strstr(de->d_name, PROTO) != NULL && - strncmp(de->d_name, ".del-", 5) != 0 && - strstr(de->d_name, ".old") == NULL && - strstr(de->d_name, ".new") == NULL) { - (void) sprintf(name, "%s/%s", *argv, - de->d_name); - update_map(name, basedir, basedir_len); - } - } - (void) closedir(d); - } - } - return (errors != 0); -} - -#define NEXTWORD(tmp, end, warnme) \ - do { \ - tmp = strpbrk(tmp, "\t ");\ - if (!tmp) {\ - if (warnme)\ - warn(name, lineno);\ - return (LINE_IGNORE);\ - }\ - end = tmp++;\ - while (*tmp && isspace(*tmp)) tmp++;\ - } while (0) - -static void -warn(const char *file, int line) -{ - (void) fprintf(stderr, "pmodes: %s, line %d: unexpected format\n", - file, line); -} - -struct parsed_line { - char *start; /* buffer start */ - char *rest; /* buffer after owner */ - char *owner; /* same size as ut_user */ - char *old_owner; /* same size as ut_user */ - char group[16]; /* whatever */ - int modelen; /* number of mode bytes (3 or 4); */ - int mode; /* the complete file mode */ - char path[MAXPATHLEN]; /* NUL terminated pathname */ - char type; /* */ - char realtype; /* */ -}; - -#define LINE_OK 0 -#define LINE_IGNORE 1 -#define LINE_ERROR 2 - -static void -put_line(FILE *f, struct parsed_line *line) -{ - if (f != NULL) - if (line->rest) - (void) fprintf(f, "%s%.*o %s %s", line->start, - line->modelen, line->mode, line->owner, line->rest); - else - (void) fputs(line->start, f); -} - -/* - * the first field is the path, the second the type, the - * third the class, the fourth the mode, when appropriate. - * We're interested in - * f (file) - * e (edited file) - * v (volatile file) - * d (directory) - * c (character devices) - * b (block devices) - */ - -static int -parse_line(struct parsed_line *parse, char *buf, const char *name, int lineno) -{ - char *tmp; - char *p = buf; - char *end, *q; - - parse->start = buf; - parse->rest = 0; /* makes put_line work */ - - /* Trim trailing spaces */ - end = buf + strlen(buf); - while (end > buf+1 && isspace(end[-2])) { - end -= 1; - end[-1] = end[0]; - end[0] = '\0'; - } - - while (*p && isspace(*p)) - p++; - - if (*p == '#' || *p == ':' || *p == '\0') - return (LINE_IGNORE); - - /* - * Special directives; we really should follow the include - * directives but we certainly need to look at default - */ - if (*p == '!') { - p++; - while (*p && isspace(*p)) - p++; - - if (!*p || *p == '\n') - return (LINE_IGNORE); - - if (strncmp(p, "default", 7) == 0) { - NEXTWORD(p, end, 1); - parse->type = 'f'; - parse->realtype = 'D'; - strcpy(parse->path, "(default)"); - tmp = p; - NEXTWORD(p, end, 1); - goto domode; - } else if (strncmp(p, "include", 7) == 0) { - NEXTWORD(p, end, 1); - if (strstr(p, PROTO) == NULL) - fprintf(stderr, "including file %s", p); - } - return (LINE_IGNORE); - } - - /* - * Parse the pkgmap line: - * [<number>] <type> <class> <path> [<major> <minor>] - * [ <mode> <owner> <group> .... ] - */ - - /* Skip first column for non-prototype (i.e., pkgmap) files */ - if (isdigit(*p)) - NEXTWORD(p, end, 1); - - parse->realtype = parse->type = *p; - - switch (parse->type) { - case 'i': case 's': case 'l': - return (LINE_IGNORE); - } - - NEXTWORD(p, end, 1); - - /* skip class */ - NEXTWORD(p, end, 1); - - /* - * p now points to pathname - * At this point, we could have no mode because we are - * using a default. - */ - tmp = p; - NEXTWORD(p, end, 0); - - /* end points to space after name */ - (void) strncpy(parse->path, tmp, end - tmp); - parse->path[end - tmp] = '\0'; - - switch (parse->type) { - case 'e': - case 'v': - /* type 'e' and 'v' are files, just like 'f', use 'f' in out */ - parse->type = 'f'; - /* FALLTHROUGH */ - case 'f': - case 'd': - case 'p': /* FIFO - assume mode is sensible, don't treat as file */ - break; - - case 'x': /* Exclusive directory */ - parse->type = 'd'; - break; - - /* device files have class major minor, skip */ - case 'c': - case 'b': - NEXTWORD(p, end, 1); NEXTWORD(p, end, 1); - break; - - default: - (void) fprintf(stderr, "Unknown type '%c', %s:%d\n", - parse->type, name, lineno); - return (LINE_ERROR); - } - tmp = p; - NEXTWORD(p, end, 1); - -domode: - /* - * the mode is either a 4 digit number (file is sticky/set-uid or - * set-gid or the mode has a leading 0) or a three digit number - * mode has all the mode bits, mode points to the three least - * significant bit so fthe mode - */ - parse->mode = 0; - for (q = tmp; q < end; q++) { - if (!isdigit(*q) || *q > '7') { - (void) fprintf(stderr, - "Warning: Unparseble mode \"%.*s\" at %s:%d\n", - end-tmp, tmp, name, lineno); - return (LINE_IGNORE); - } - parse->mode <<= 3; - parse->mode += *q - '0'; - } - parse->modelen = end - tmp; - tmp[0] = '\0'; - - parse->old_owner = parse->owner = p; - - NEXTWORD(p, end, 1); - - parse->rest = end+1; - *end = '\0'; - - (void) memset(parse->group, 0, sizeof (parse->group)); - (void) strncpy(parse->group, end+1, strcspn(end+1, " \t\n")); - - return (LINE_OK); -} - -static void -update_map(char *name, char *basedir, int basedir_len) -{ - char buf[8192]; - int i; - FILE *map, *newmap; - char newname[MAXPATHLEN]; - int nchanges = 0; - unsigned int lineno = 0; - struct parsed_line line; - char *fname; - - map = fopen(name, "r"); - if (map == 0) { - (void) fprintf(stderr, "Can't open \"%s\"\n", name); - return; - } - (void) strcpy(newname, name); - (void) strcat(newname, ".new"); - if (makenew) { - newmap = fopen(newname, "w"); - if (newmap == 0) - (void) fprintf(stderr, "Can't open %s for writing\n", - name); - } else - newmap = 0; - - /* Get last one or two components non-trivial of pathname */ - if (verbose) { - char *tmp = name + strlen(name); - int cnt = 0, first = 0; - - while (--tmp > name && cnt < 2) { - if (*tmp == '/') { - if (++cnt == 1) - first = tmp - name; - else { - fname = tmp + 1; - /* Triviality check */ - if (tmp - name > first - 4) - cnt--; - } - } - } - if (cnt < 2) - fname = name; - } - - nchanges = 0; - - for (; fgets(buf, sizeof (buf), map) != 0; put_line(newmap, &line)) { - - int root_owner, mode_diff = 0; - int changed = 0; - - lineno ++; - - switch (parse_line(&line, buf, name, lineno)) { - case LINE_IGNORE: - continue; - case LINE_ERROR: - errors++; - continue; - } - - if (restrictto) { - char nbuf[MAXPATHLEN]; - snprintf(nbuf, sizeof (nbuf), "%.*s%s", basedir_len, - basedir, line.path); - - if (item_search(restrictto, nbuf) == -1) - continue; - } - - if (dirsonly && line.type != 'd') - continue; - - root_owner = strcmp(line.owner, "root") == 0; - if (dosu && line.type == 'f' && (line.mode & (S_ISUID|S_ISGID))) - mode_diff = line.mode & (S_IRGRP|S_IROTH); - - /* - * The following heuristics are used to determine whether a file - * can be safely chown'ed to root: - * - it's not set-uid. - * and one of the following applies: - * - it's not writable by the current owner and is - * group/world readable - * - it's world executable and a file - * - owner, group and world permissions are identical - * - it's a bin owned directory or a "non-volatile" - * file (any owner) for which group and other r-x - * permissions are identical, or it's a bin owned - * executable or it's a /etc/security/dev/ device - */ - - if (doowner && !(line.mode & S_ISUID) && - !root_owner && - ((!(line.mode & S_IWUSR) && - (line.mode&(S_IRGRP|S_IROTH)) == (S_IRGRP|S_IROTH)) || - (line.type == 'f' && (line.mode & S_IXOTH)) || - ((line.mode & 07) == ((line.mode>>3) & 07) && - (line.mode & 07) == ((line.mode>>6) & 07) && - strcmp(line.owner, "uucp") != 0) || - ((line.type == 'd' && strcmp(line.owner, "bin") == 0 || - (editable && strcmp(line.owner, "bin") == 0 ? - line.type : line.realtype) == 'f') && - ((line.mode & 05) == ((line.mode>>3) & 05) || - (line.mode & 0100) && - strcmp(line.owner, "bin") == 0) && - ((line.mode & 0105) != 0 || - basedir_len < 18 && - strncmp(basedir, "/etc/security/dev/", - basedir_len) == 0 && - strncmp(line.path, "/etc/security/dev/" - + basedir_len, 18 - basedir_len) == 0)))) { - if (!diffout) { - if (!changed && verbose && !nchanges) - (void) printf("%s:\n", fname); - (void) printf("%c o %s -> root %s%s [%.*o]\n", - line.realtype, line.owner, basedir, - line.path, line.modelen, line.mode); - } - line.owner = "root"; - root_owner = 1; - changed = 1; - } - /* - * Strip user write bit if owner != root and executable by user. - * root can write even if no write bits set - * Could prevent executables from being overwritten. - */ - if (douserwrite && line.type == 'f' && !root_owner && - (line.mode & (S_IWUSR|S_IXUSR)) == (S_IWUSR|S_IXUSR)) - mode_diff |= S_IWUSR; - - - if (domodes && (line.mode & (S_IWGRP|S_IWOTH)) != 0 && - (line.mode & S_ISVTX) == 0) { - if (basedir_len <= 1) { /* root dir */ - for (i = 0; i < nexceptions; i++) { - if (strcmp(line.path, - exceptions[i]+basedir_len) == 0) - break; - } - } else { - for (i = 0; i < nexceptions; i++) { - if (strncmp(basedir, exceptions[i], - basedir_len) == 0 && - strcmp(line.path, - exceptions[i]+basedir_len) == 0) - break; - } - } - if (i == nexceptions) - mode_diff |= line.mode & (S_IWGRP|S_IWOTH); - } - - if (mode_diff) { - int oldmode = line.mode; - - line.mode &= ~mode_diff; - - if (line.mode != oldmode) { - if (!diffout) { - if (!changed && verbose && !nchanges) - (void) printf("%s:\n", fname); - printf("%c %c %04o -> %04o %s%s\n", - line.realtype, - (mode_diff & (S_IRGRP|S_IROTH)) ? - 's' : 'm', - oldmode, line.mode, basedir, - line.path); - } - changed = 1; - } - } - nchanges += changed; - if (diffout && changed) { - if (nchanges == 1 && verbose) - (void) printf("%s:\n", fname); - - (void) printf("< %c %04o %s %s %s%s\n", line.realtype, - line.mode | mode_diff, line.old_owner, line.group, - basedir, line.path); - (void) printf("> %c %04o %s %s %s%s\n", line.realtype, - line.mode, line.owner, line.group, basedir, - line.path); - } - } - (void) fclose(map); - - if (newmap != NULL) { - (void) fflush(newmap); - if (ferror(newmap)) { - (void) fprintf(stderr, "Error writing %s\n", name); - return; - } - (void) fclose(newmap); - if (nchanges == 0) - (void) unlink(newname); - else if (installnew) { - char oldname[MAXPATHLEN]; - - (void) strcpy(oldname, name); - (void) strcat(oldname, ".old"); - if (rename(name, oldname) == -1 || - rename(newname, name) == -1) - (void) fprintf(stderr, - "Couldn't install %s: %s\n", - newname, strerror(errno)); - } - } -} |