static PyObject * strcaps_set_file(PyObject *self, PyObject *args) { // (str) caps, (int) fd / (str) path / (file) file char *strcaps; PyObject *file; if (!PyArg_ParseTuple(args, "etO", Py_FileSystemDefaultEncoding, &strcaps, &file)) return NULL; cap_t caps; if ((caps = cap_from_text(strcaps)) == NULL) { PyErr_SetString(PyExc_ValueError, "Invalid capability specification"); PyMem_Free(strcaps); return NULL; } PyMem_Free(strcaps); int err; if (PyFile_Check(file)) err = cap_set_fd(PyObject_AsFileDescriptor(file), caps); else if (PyInt_Check(file)) err = cap_set_fd(PyInt_AsLong(file), caps); else if (PyString_Check(file)) err = cap_set_file(PyString_AsString(file), caps); else if (PyUnicode_Check(file)) { PyObject *file_dec = PyUnicode_AsEncodedString( file, Py_FileSystemDefaultEncoding, "strict" ); if (file_dec == NULL) return NULL; err = cap_set_file(PyString_AsString(file_dec), caps); Py_DECREF(file_dec); } else { PyErr_SetString( PyExc_TypeError, "Expecting file object, descriptor int or path string" ); cap_free(caps); return NULL; } cap_free(caps); if (err) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; };
int do_cap_set_file (const char *path, const char *capstr) { cap_t cap; int r; cap = cap_from_text (capstr); if (cap == NULL) { reply_with_perror ("could not parse cap string: %s: cap_from_text", capstr); return -1; } CHROOT_IN; r = cap_set_file (path, cap); CHROOT_OUT; if (r == -1) { reply_with_perror ("%s", path); cap_free (cap); return -1; } cap_free (cap); return 0; }
static void removeSBITS(const char *path) { struct stat stb; if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) { if ((stb.st_mode & 06000) != 0) { (void) chmod(path, stb.st_mode & 0777); } #if WITH_CAP if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) { (void) cap_set_file(path, NULL); } #endif } }
static int fsmSetFCaps(const char *path, const char *captxt) { int rc = 0; #if WITH_CAP if (captxt && *captxt != '\0') { cap_t fcaps = cap_from_text(captxt); if (fcaps == NULL || cap_set_file(path, fcaps) != 0) { rc = RPMERR_SETCAP_FAILED; } cap_free(fcaps); } #endif return rc; }
static int bin_setcap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) { cap_t caps; int ret = 0; unmetafy(*argv, NULL); caps = cap_from_text(*argv++); if(!caps) { zwarnnam(nam, "invalid capability string"); return 1; } do { if(cap_set_file(unmetafy(dupstring(*argv), NULL), caps)) { zwarnnam(nam, "%s: %e", *argv, errno); ret = 1; } } while(*++argv); cap_free(caps); return ret; }
int perms_test(void) { int ret; cap_t cap; drop_root(DROP_PERMS); cap = cap_from_text("all=eip"); if (!cap) { tst_resm(TFAIL, "could not get cap from text for perms test\n"); return 1; } ret = cap_set_file(TSTPATH, cap); if (ret) { tst_resm(TPASS, "could not set capabilities as non-root\n"); ret = 0; } else { tst_resm(TFAIL, "could set capabilities as non-root\n"); ret = 1; } cap_free(cap); return ret; }
int caps_actually_set_test(void) { int whichcap, finalret = 0, ret; cap_t fcap, pcap, cap_fullpi; cap_value_t capvalue[1]; int i; fcap = cap_init(); pcap = cap_init(); if (!fcap || !pcap) { perror("cap_init"); exit(2); } create_fifo(); int num_caps; for (num_caps = 0;; num_caps++) { ret = prctl(PR_CAPBSET_READ, num_caps); /* * Break from the loop in this manner to avoid incrementing, * then having to decrement value. */ if (ret == -1) break; } /* first, try each bit in fP (forced) with fE on and off. */ for (whichcap = 0; whichcap < num_caps; whichcap++) { /* * fP=whichcap, fE=fI=0 * pP'=whichcap, pI'=pE'=0 */ capvalue[0] = whichcap; cap_clear(fcap); cap_set_flag(fcap, CAP_PERMITTED, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, fcap); if (ret) { tst_resm(TINFO, "%d\n", whichcap); continue; } ret = fork_drop_and_exec(DROP_PERMS, fcap); if (ret) { tst_resm(TINFO, "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=0\n", whichcap); if (!finalret) finalret = ret; } /* SERGE here */ /* * fP = fE = whichcap, fI = 0 * pP = pE = whichcap, pI = 0 */ cap_clear(fcap); cap_set_flag(fcap, CAP_PERMITTED, 1, capvalue, CAP_SET); cap_set_flag(fcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, fcap); if (ret) { tst_resm(TINFO, "%d\n", whichcap); continue; } ret = fork_drop_and_exec(DROP_PERMS, fcap); if (ret) { tst_resm(TINFO, "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=1\n", whichcap); if (!finalret) finalret = ret; } } cap_free(pcap); cap_free(fcap); cap_fullpi = cap_init(); for (i = 0; i < num_caps; i++) { capvalue[0] = i; cap_set_flag(cap_fullpi, CAP_INHERITABLE, 1, capvalue, CAP_SET); } /* * For the inheritable tests, we want to make sure pI starts * filled. */ ret = cap_set_proc(cap_fullpi); if (ret) tst_resm(TINFO, "Could not fill pI. pI tests will fail.\n"); /* * next try each bit in fI * The first two attemps have the bit which is in fI in pI. * This should result in the bit being in pP'. * If fE was set then it should also be in pE'. * The last attempt starts with an empty pI. * This should result in empty capability, as there were * no bits to be inherited from the original process. */ for (whichcap = 0; whichcap < num_caps; whichcap++) { cap_t cmpcap; capvalue[0] = whichcap; /* * fI=whichcap, fP=fE=0 * pI=full * pI'=full, pP'=whichcap, pE'=0 */ /* fill pI' */ pcap = cap_dup(cap_fullpi); /* pP' = whichcap */ cap_set_flag(pcap, CAP_PERMITTED, 1, capvalue, CAP_SET); /* fI = whichcap */ fcap = cap_init(); cap_set_flag(fcap, CAP_INHERITABLE, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, fcap); if (ret) { tst_resm(TINFO, "%d\n", whichcap); continue; } ret = fork_drop_and_exec(KEEP_PERMS, pcap); if (ret) { tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d " "CAP_EFFECTIVE=0\n", whichcap); if (!finalret) finalret = ret; } /* * fI=fE=whichcap, fP=0 * pI=full * pI'=full, pP'=whichcap, pE'=whichcap * * Note that only fE and pE' change, so keep prior * fcap and pcap and set those bits. */ cap_set_flag(fcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); cap_set_flag(pcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, fcap); if (ret) { tst_resm(TINFO, "%d\n", whichcap); continue; } /* The actual result will be a full pI, with * pE and pP containing just whichcap. */ cmpcap = cap_dup(cap_fullpi); cap_set_flag(cmpcap, CAP_PERMITTED, 1, capvalue, CAP_SET); cap_set_flag(cmpcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); ret = fork_drop_and_exec(KEEP_PERMS, cmpcap); cap_free(cmpcap); if (ret) { tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d " "CAP_EFFECTIVE=1\n", whichcap); if (!finalret) finalret = ret; } /* * fI=fE=whichcap, fP=0 (so fcap is same as before) * pI=0 (achieved using DROP_PERMS) * pI'=pP'=pE'=0 */ cap_clear(pcap); ret = fork_drop_and_exec(DROP_PERMS, pcap); if (ret) { tst_resm(TINFO, "Failed without_perms CAP_INHERITABLE=%d", whichcap); if (!finalret) finalret = ret; } cap_free(fcap); cap_free(pcap); } cap_free(cap_fullpi); return finalret; }
int main(int argc, char **argv) { char *opt, *p, *str; int told = 0; int use_checklist = 0; int systemmode = 0; int suseconfig = 0; FILE *fp; char line[512]; char *part[4]; int i, pcnt, lcnt; int inpart; mode_t mode; struct perm *e; struct stat stb, stb2; struct passwd *pwd = 0; struct group *grp = 0; uid_t uid; gid_t gid; int fd, r; int errors = 0; cap_t caps = NULL; while (argc > 1) { opt = argv[1]; if (!strcmp(opt, "--")) break; if (*opt == '-' && opt[1] == '-') opt++; if (!strcmp(opt, "-system")) { argc--; argv++; systemmode = 1; continue; } // hidden option for use by suseconfig only if (!strcmp(opt, "-suseconfig")) { argc--; argv++; suseconfig = 1; systemmode = 1; continue; } if (!strcmp(opt, "-fscaps")) { argc--; argv++; have_fscaps = 1; continue; } if (!strcmp(opt, "-no-fscaps")) { argc--; argv++; have_fscaps = 0; continue; } if (!strcmp(opt, "-s") || !strcmp(opt, "-set")) { do_set=1; argc--; argv++; continue; } if (!strcmp(opt, "-warn")) { do_set=0; argc--; argv++; continue; } if (!strcmp(opt, "-n") || !strcmp(opt, "-noheader")) { told = 1; argc--; argv++; continue; } if (!strcmp(opt, "-e") || !strcmp(opt, "-examine")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "examine: argument required\n"); exit(1); } add_checklist(argv[1]); use_checklist = 1; argc--; argv++; continue; } if (!strcmp(opt, "-level")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "level: argument required\n"); exit(1); } force_level = argv[1]; argc--; argv++; continue; } if (!strcmp(opt, "-f") || !strcmp(opt, "-files")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "files: argument required\n"); exit(1); } if ((fp = fopen(argv[1], "r")) == 0) { fprintf(stderr, "files: %s: %s\n", argv[1], strerror(errno)); exit(1); } while (readline(fp, line, sizeof(line))) { if (!*line) continue; add_checklist(line); } fclose(fp); use_checklist = 1; argc--; argv++; continue; } if (!strcmp(opt, "-r") || !strcmp(opt, "-root")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "root: argument required\n"); exit(1); } root = argv[1]; rootl = strlen(root); if (*root != '/') { fprintf(stderr, "root: must begin with '/'\n"); exit(1); } argc--; argv++; continue; } if (*opt == '-') usage(!strcmp(opt, "-h") || !strcmp(opt, "-help") ? 0 : 1); break; } if (systemmode) { const char file[] = "/etc/sysconfig/security"; parse_sysconf(file); if(do_set == -1) { if (default_set < 0) { fprintf(stderr, "permissions handling disabled in %s\n", file); exit(0); } if (suseconfig && default_set) { char* module = getenv("ONLY_MODULE"); if (!module || strcmp(module, "permissions")) { puts("no permissions will be changed if not called explicitly"); default_set = 0; } } do_set = default_set; } if (force_level) { char *p = strtok(force_level, " "); do { add_level(p); } while ((p = strtok(NULL, " "))); } if (!nlevel) add_level("secure"); add_level("local"); // always add local for (i = 1; i < argc; i++) { add_checklist(argv[i]); use_checklist = 1; continue; } collect_permfiles(); } else if (argc <= 1) usage(1); else { npermfiles = argc-1; permfiles = &argv[1]; } if (have_fscaps == 1 && !check_fscaps_enabled()) { fprintf(stderr, "Warning: running kernel does not support fscaps\n"); } if (do_set == -1) do_set = 0; // add fake list entries for all files to check for (i = 0; i < nchecklist; i++) add_permlist(checklist[i], "unknown", "unknown", 0); for (i = 0; i < npermfiles; i++) { if ((fp = fopen(permfiles[i], "r")) == 0) { perror(argv[i]); exit(1); } lcnt = 0; struct perm* last = NULL; int extline; while (readline(fp, line, sizeof(line))) { extline = 0; lcnt++; if (*line == 0 || *line == '#' || *line == '$') continue; inpart = 0; pcnt = 0; for (p = line; *p; p++) { if (*p == ' ' || *p == '\t') { *p = 0; if (inpart) { pcnt++; inpart = 0; } continue; } if (pcnt == 0 && !inpart && *p == '+') { extline = 1; break; } if (!inpart) { inpart = 1; if (pcnt == 3) break; part[pcnt] = p; } } if (extline) { if (!last) { BAD_LINE(); continue; } if (!strncmp(p, "+capabilities ", 14)) { if (have_fscaps != 1) continue; p += 14; caps = cap_from_text(p); if (caps) { cap_free(last->caps); last->caps = caps; } continue; } BAD_LINE(); continue; } if (inpart) pcnt++; if (pcnt != 3) { BAD_LINE(); continue; } part[3] = part[2]; part[2] = strchr(part[1], ':'); if (!part[2]) part[2] = strchr(part[1], '.'); if (!part[2]) { BAD_LINE(); continue; } *part[2]++ = 0; mode = strtoul(part[3], part + 3, 8); if (mode > 07777 || part[3][0]) { BAD_LINE(); continue; } last = add_permlist(part[0], part[1], part[2], mode); } fclose(fp); } euid = geteuid(); for (e = permlist; e; e = e->next) { if (use_checklist && !in_checklist(e->file+rootl)) continue; if (lstat(e->file, &stb)) continue; if (S_ISLNK(stb.st_mode)) continue; if (!e->mode && !strcmp(e->owner, "unknown")) { char uids[16], gids[16]; pwd = getpwuid(stb.st_uid); grp = getgrgid(stb.st_gid); if (!pwd) sprintf(uids, "%d", stb.st_uid); if (!grp) sprintf(gids, "%d", stb.st_gid); fprintf(stderr, "%s: cannot verify %s:%s %04o - not listed in /etc/permissions\n", e->file+rootl, pwd?pwd->pw_name:uids, grp?grp->gr_name:gids, (int)(stb.st_mode&07777)); pwd = 0; grp = 0; continue; } if ((!pwd || strcmp(pwd->pw_name, e->owner)) && (pwd = getpwnam(e->owner)) == 0) { fprintf(stderr, "%s: unknown user %s\n", e->file+rootl, e->owner); continue; } if ((!grp || strcmp(grp->gr_name, e->group)) && (grp = getgrnam(e->group)) == 0) { fprintf(stderr, "%s: unknown group %s\n", e->file+rootl, e->group); continue; } uid = pwd->pw_uid; gid = grp->gr_gid; caps = cap_get_file(e->file); if (!caps) { cap_free(caps); caps = NULL; if (errno == EOPNOTSUPP) { //fprintf(stderr, "%s: fscaps not supported\n", e->file+rootl); cap_free(e->caps); e->caps = NULL; } } if (e->caps) { e->mode &= 0777; } int perm_ok = (stb.st_mode & 07777) == e->mode; int owner_ok = stb.st_uid == uid && stb.st_gid == gid; int caps_ok = 0; if (!caps && !e->caps) caps_ok = 1; else if (caps && e->caps && !cap_compare(e->caps, caps)) caps_ok = 1; if (perm_ok && owner_ok && caps_ok) continue; if (!told) { told = 1; printf("Checking permissions and ownerships - using the permissions files\n"); for (i = 0; i < npermfiles; i++) printf("\t%s\n", permfiles[i]); if (rootl) { printf("Using root %s\n", root); } } if (!do_set) printf("%s should be %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode); else printf("setting %s to %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode); if (!caps_ok && e->caps) { str = cap_to_text(e->caps, NULL); printf(" \"%s\"", str); cap_free(str); } printf(". (wrong"); if (!owner_ok) { pwd = getpwuid(stb.st_uid); grp = getgrgid(stb.st_gid); if (pwd) printf(" owner/group %s", pwd->pw_name); else printf(" owner/group %d", stb.st_uid); if (grp) printf(":%s", grp->gr_name); else printf(":%d", stb.st_gid); pwd = 0; grp = 0; } if (!perm_ok) printf(" permissions %04o", (int)(stb.st_mode & 07777)); if (!caps_ok) { if (!perm_ok || !owner_ok) { fputc(',', stdout); } if (caps) { str = cap_to_text(caps, NULL); printf(" capabilities \"%s\"", str); cap_free(str); } else fputs(" missing capabilities", stdout); } putchar(')'); putchar('\n'); if (!do_set) continue; fd = -1; if (S_ISDIR(stb.st_mode)) { fd = open(e->file, O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_NOFOLLOW); if (fd == -1) { perror(e->file); errors++; continue; } } else if (S_ISREG(stb.st_mode)) { fd = open(e->file, O_RDONLY|O_NONBLOCK|O_NOFOLLOW); if (fd == -1) { perror(e->file); errors++; continue; } if (fstat(fd, &stb2)) continue; if (stb.st_mode != stb2.st_mode || stb.st_nlink != stb2.st_nlink || stb.st_dev != stb2.st_dev || stb.st_ino != stb2.st_ino) { fprintf(stderr, "%s: too fluctuating\n", e->file+rootl); errors++; continue; } if (stb.st_nlink > 1 && !safepath(e->file, 0, 0)) { fprintf(stderr, "%s: on an insecure path\n", e->file+rootl); errors++; continue; } else if (e->mode & 06000) { /* extra checks for s-bits */ if (!safepath(e->file, (e->mode & 02000) == 0 ? uid : 0, (e->mode & 04000) == 0 ? gid : 0)) { fprintf(stderr, "%s: will not give away s-bits on an insecure path\n", e->file+rootl); errors++; continue; } } } else if (strncmp(e->file, "/dev/", 5) != 0) // handle special files only in /dev { fprintf(stderr, "%s: don't know what to do with that type of file\n", e->file+rootl); errors++; continue; } if (euid == 0 && !owner_ok) { /* if we change owner or group of a setuid file the bit gets reset so also set perms again */ if (e->mode & 06000) perm_ok = 0; if (fd >= 0) r = fchown(fd, uid, gid); else r = chown(e->file, uid, gid); if (r) { fprintf(stderr, "%s: chown: %s\n", e->file+rootl, strerror(errno)); errors++; } if (fd >= 0) r = fstat(fd, &stb); else r = lstat(e->file, &stb); if (r) { fprintf(stderr, "%s: too fluctuating\n", e->file+rootl); errors++; continue; } } if (!perm_ok) { if (fd >= 0) r = fchmod(fd, e->mode); else r = chmod(e->file, e->mode); if (r) { fprintf(stderr, "%s: chmod: %s\n", e->file+rootl, strerror(errno)); errors++; } } if (!caps_ok) { if (fd >= 0) r = cap_set_fd(fd, e->caps); else r = cap_set_file(e->file, e->caps); if (r) { fprintf(stderr, "%s: cap_set_file: %s\n", e->file+rootl, strerror(errno)); errors++; } } if (fd >= 0) close(fd); } if (errors) { fprintf(stderr, "ERROR: not all operations were successful.\n"); exit(1); } exit(0); }
int main(int argc, char **argv) { int tried_to_cap_setfcap = 0; char buffer[MAXCAP+1]; int retval, quiet=0, verify=0; cap_t mycaps; cap_value_t capflag; if (argc < 3) { usage(); } mycaps = cap_get_proc(); if (mycaps == NULL) { fprintf(stderr, "warning - unable to get process capabilities" " (old libcap?)\n"); } while (--argc > 0) { const char *text; cap_t cap_d; if (!strcmp(*++argv, "-q")) { quiet = 1; continue; } if (!strcmp(*argv, "-v")) { verify = 1; continue; } if (!strcmp(*argv, "-r")) { cap_d = NULL; } else { if (!strcmp(*argv,"-")) { retval = read_caps(quiet, *argv, buffer); if (retval) usage(); text = buffer; } else { text = *argv; } cap_d = cap_from_text(text); if (cap_d == NULL) { perror("fatal error"); usage(); } #ifdef DEBUG { ssize_t length; const char *result; result = cap_to_text(cap_d, &length); fprintf(stderr, "caps set to: [%s]\n", result); } #endif } if (--argc <= 0) usage(); /* * Set the filesystem capability for this file. */ if (verify) { cap_t cap_on_file; int cmp; if (cap_d == NULL) { cap_d = cap_from_text("="); } cap_on_file = cap_get_file(*++argv); if (cap_on_file == NULL) { cap_on_file = cap_from_text("="); } cmp = cap_compare(cap_on_file, cap_d); cap_free(cap_on_file); if (cmp != 0) { if (!quiet) { printf("%s differs in [%s%s%s]\n", *argv, CAP_DIFFERS(cmp, CAP_PERMITTED) ? "p" : "", CAP_DIFFERS(cmp, CAP_INHERITABLE) ? "i" : "", CAP_DIFFERS(cmp, CAP_EFFECTIVE) ? "e" : ""); } exit(1); } if (!quiet) { printf("%s: OK\n", *argv); } } else { if (!tried_to_cap_setfcap) { capflag = CAP_SETFCAP; /* * Raise the effective CAP_SETFCAP. */ if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET) != 0) { perror("unable to manipulate CAP_SETFCAP - " "try a newer libcap?"); exit(1); } if (cap_set_proc(mycaps) != 0) { perror("unable to set CAP_SETFCAP effective capability"); exit(1); } tried_to_cap_setfcap = 1; } retval = cap_set_file(*++argv, cap_d); if (retval != 0) { fprintf(stderr, "Failed to set capabilities on file `%s' (%s)\n", argv[0], strerror(errno)); usage(); } } if (cap_d) { cap_free(cap_d); } } exit(0); }
/* * Set the capabilities for self from the caps hash stored in @caps. */ VALUE cap2_file_setcaps(VALUE self) { int i; cap_t cap_d; char *filename; VALUE caps, cap_array, cap_sym; cap_value_t cap_values[__CAP_COUNT]; cap_d = cap_init(); caps = rb_iv_get(self, "@caps"); // permitted cap_array = rb_funcall( rb_hash_aref(caps, ID2SYM(rb_intern("permitted"))), rb_intern("to_a"), 0 ); for(i = 0; i < RARRAY_LEN(cap_array); i++) { cap_sym = RARRAY_PTR(cap_array)[i]; cap_values[i] = cap2_sym_to_cap(cap_sym); } cap_set_flag(cap_d, CAP_PERMITTED, i, cap_values, CAP_SET); // effective cap_array = rb_funcall( rb_hash_aref(caps, ID2SYM(rb_intern("effective"))), rb_intern("to_a"), 0 ); for(i = 0; i < RARRAY_LEN(cap_array); i++) { cap_sym = RARRAY_PTR(cap_array)[i]; cap_values[i] = cap2_sym_to_cap(cap_sym); } cap_set_flag(cap_d, CAP_EFFECTIVE, i, cap_values, CAP_SET); // inheritable cap_array = rb_funcall( rb_hash_aref(caps, ID2SYM(rb_intern("inheritable"))), rb_intern("to_a"), 0 ); for(i = 0; i < RARRAY_LEN(cap_array); i++) { cap_sym = RARRAY_PTR(cap_array)[i]; cap_values[i] = cap2_sym_to_cap(cap_sym); } cap_set_flag(cap_d, CAP_INHERITABLE, i, cap_values, CAP_SET); filename = cap2_file_filename(self); if(cap_set_file(filename, cap_d) == -1) { rb_raise( rb_eRuntimeError, "Failed to set capabilities for file %s: (%s)\n", filename, strerror(errno) ); } else { cap_free(cap_d); return Qtrue; } }