int cap_set_file(const char *filename, cap_t cap_d) { struct vfs_cap_data rawvfscap; int sizeofcaps; struct stat buf; if (lstat(filename, &buf) != 0) { _cap_debug("unable to stat file [%s]", filename); return -1; } if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) { _cap_debug("file [%s] is not a regular file", filename); errno = EINVAL; return -1; } if (cap_d == NULL) { _cap_debug("removing filename capabilities"); return removexattr(filename, XATTR_NAME_CAPS); } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) { return -1; } _cap_debug("setting filename capabilities"); return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0); }
int cap_set_fd(int fildes, cap_t cap_d) { struct vfs_cap_data rawvfscap; int sizeofcaps; struct stat buf; if (fstat(fildes, &buf) != 0) { _cap_debug("unable to stat file descriptor %d", fildes); return -1; } if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) { _cap_debug("file descriptor %d for non-regular file", fildes); errno = EINVAL; return -1; } if (cap_d == NULL) { _cap_debug("deleting fildes capabilities"); return fremovexattr(fildes, XATTR_NAME_CAPS); } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) { return -1; } _cap_debug("setting fildes capabilities"); return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0); }
cap_t cap_get_file(const char *filename) { cap_t result; /* allocate a new capability set */ result = cap_init(); if (result) { struct vfs_cap_data rawvfscap; int sizeofcaps; _cap_debug("getting filename capabilities"); /* fill the capability sets via a system call */ sizeofcaps = getxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeof(rawvfscap)); if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) { cap_free(result); result = NULL; } else { result = _fcaps_load(&rawvfscap, result, sizeofcaps); } } return result; }
cap_t cap_dup(cap_t cap_d) { cap_t result; if (!good_cap_t(cap_d)) { _cap_debug("bad argument"); errno = EINVAL; return NULL; } result = cap_init(); if (result == NULL) { _cap_debug("out of memory"); return NULL; } memcpy(result, cap_d, sizeof(*cap_d)); return result; }
int cap_set_file(const char *filename, cap_t cap_d) { if (!good_cap_t(cap_d)) { errno = EINVAL; return -1; } _cap_debug("setting filename capabilities"); return _setfilecap(filename, sizeof(struct __cap_s), &cap_d->set[CAP_INHERITABLE], &cap_d->set[CAP_PERMITTED], &cap_d->set[CAP_EFFECTIVE] ); }
int cap_set_proc(cap_t cap_d) { int retval; if (!good_cap_t(cap_d)) { errno = EINVAL; return -1; } _cap_debug("setting process capabilities"); retval = capset(&cap_d->head, &cap_d->set); cap_d->head.version = _LINUX_CAPABILITY_VERSION; return retval; }
int capsetp(pid_t pid, cap_t cap_d) { int error; if (!good_cap_t(cap_d)) { errno = EINVAL; return -1; } _cap_debug("setting process capabilities for proc %d", pid); cap_d->head.pid = pid; error = capset(&cap_d->head, &cap_d->set); cap_d->head.version = _LINUX_CAPABILITY_VERSION; cap_d->head.pid = 0; return error; }
cap_t cap_get_proc(void) { cap_t result; /* allocate a new capability set */ result = cap_init(); if (result) { _cap_debug("getting current process' capabilities"); /* fill the capability sets via a system call */ if (capget(&result->head, &result->set)) { cap_free(&result); } } return result; }
cap_t cap_get_file(const char *filename) { cap_t result; /* allocate a new capability set */ result = cap_init(); if (result) { _cap_debug("getting named file capabilities"); /* fill the capability sets via a system call */ if (_getfilecap(filename, sizeof(struct __cap_s), &result->set[CAP_INHERITABLE], &result->set[CAP_PERMITTED], &result->set[CAP_EFFECTIVE] )) cap_free(&result); } return result; }
cap_t cap_get_fd(int fildes) { cap_t result; /* allocate a new capability set */ result = cap_init(); if (result) { _cap_debug("getting fildes capabilities"); /* fill the capability sets via a system call */ if (_fgetfilecap(fildes, sizeof(struct __cap_s), &result->set[CAP_INHERITABLE], &result->set[CAP_PERMITTED], &result->set[CAP_EFFECTIVE] )) { cap_free(&result); } } return result; }
cap_t cap_init(void) { __u32 *raw_data; cap_t result; raw_data = malloc( sizeof(__u32) + sizeof(*result) ); if (raw_data == NULL) { _cap_debug("out of memory"); errno = ENOMEM; return NULL; } *raw_data = CAP_T_MAGIC; result = (cap_t) (raw_data + 1); memset(result, 0, sizeof(*result)); result->head.version = _LINUX_CAPABILITY_VERSION_1; return result; }
int cap_free(void *data_p) { if ( good_cap_t(data_p) ) { data_p = -1 + (__u32 *) data_p; memset(data_p, 0, sizeof(__u32) + sizeof(struct _cap_struct)); free(data_p); data_p = NULL; return 0; } if ( good_cap_string(data_p) ) { int length = strlen(data_p) + sizeof(__u32); data_p = -1 + (__u32 *) data_p; memset(data_p, 0, length); free(data_p); data_p = NULL; return 0; } _cap_debug("don't recognize what we're supposed to liberate"); errno = EINVAL; return -1; }
static int _fcaps_save(struct vfs_cap_data *rawvfscap, cap_t cap_d, int *bytes_p) { __u32 eff_not_zero, magic; unsigned tocopy, i; if (!good_cap_t(cap_d)) { errno = EINVAL; return -1; } switch (cap_d->head.version) { #ifdef _LINUX_CAPABILITY_VERSION_1 case _LINUX_CAPABILITY_VERSION_1: magic = VFS_CAP_REVISION_1; tocopy = VFS_CAP_U32_1; *bytes_p = XATTR_CAPS_SZ_1; break; #endif #ifdef _LINUX_CAPABILITY_VERSION_2 case _LINUX_CAPABILITY_VERSION_2: magic = VFS_CAP_REVISION_2; tocopy = VFS_CAP_U32_2; *bytes_p = XATTR_CAPS_SZ_2; break; #endif #ifdef _LINUX_CAPABILITY_VERSION_3 case _LINUX_CAPABILITY_VERSION_3: magic = VFS_CAP_REVISION_2; tocopy = VFS_CAP_U32_2; *bytes_p = XATTR_CAPS_SZ_2; break; #endif default: errno = EINVAL; return -1; } _cap_debug("setting named file capabilities"); for (eff_not_zero = 0, i = 0; i < tocopy; i++) { eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE]; } while (i < __CAP_BLKS) { if ((cap_d->u[i].flat[CAP_EFFECTIVE] || cap_d->u[i].flat[CAP_INHERITABLE] || cap_d->u[i].flat[CAP_PERMITTED])) { /* * System does not support these capabilities */ errno = EINVAL; return -1; } i++; } for (i=0; i < tocopy; i++) { rawvfscap->data[i].permitted = FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]); rawvfscap->data[i].inheritable = FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]); if (eff_not_zero && ((~(cap_d->u[i].flat[CAP_EFFECTIVE])) & (cap_d->u[i].flat[CAP_PERMITTED] | cap_d->u[i].flat[CAP_INHERITABLE]))) { errno = EINVAL; return -1; } } if (eff_not_zero == 0) { rawvfscap->magic_etc = FIXUP_32BITS(magic); } else { rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE); } return 0; /* success */ }
cap_t cap_from_text(const char *str) { cap_t res; __cap_s allones; int n; if (str == NULL) { _cap_debug("bad argument"); errno = EINVAL; return NULL; } if (!(res = cap_init())) return NULL; for (n = __CAP_BLKS; n--; ) allones._blk[n] = -1; _cap_debug("%s", str); for (;;) { char op; int flags = 0, listed=0; __cap_s list = {{0}}; /* skip leading spaces */ while (isspace((unsigned char)*str)) str++; if (!*str) { _cap_debugcap("e = ", &res->set.effective); _cap_debugcap("i = ", &res->set.inheritable); _cap_debugcap("p = ", &res->set.permitted); return res; } /* identify caps specified by this clause */ if (isalnum((unsigned char)*str) || *str == '_') { for (;;) { if (namcmp(str, "all")) { str += 3; list = allones; } else { n = lookupname(&str); if (n == -1) goto bad; list.raise_cap(n); } if (*str != ',') break; if (!isalnum((unsigned char)*++str) && *str != '_') goto bad; } listed = 1; } else if (*str == '+' || *str == '-') goto bad; /* require a list of capabilities */ else list = allones; /* identify first operation on list of capabilities */ op = *str++; if (op == '=' && (*str == '+' || *str == '-')) { if (!listed) goto bad; op = (*str++ == '+' ? 'P':'M'); /* skip '=' and take next op */ } else if (op != '+' && op != '-' && op != '=') goto bad; /* cycle through list of actions */ do { _cap_debug("next char = `%c'", *str); if (*str && !isspace(*str)) { switch (*str++) { /* Effective, Inheritable, Permitted */ case 'e': flags |= LIBCAP_EFF; break; case 'i': flags |= LIBCAP_INH; break; case 'p': flags |= LIBCAP_PER; break; default: goto bad; } } else if (op != '=') { _cap_debug("only '=' can be followed by space"); goto bad; } _cap_debug("how to read?"); switch (op) { /* how do we interpret the caps? */ case '=': case 'P': /* =+ */ case 'M': /* =- */ clrbits(&res->set.effective, &list); clrbits(&res->set.inheritable, &list); clrbits(&res->set.permitted, &list); /* fall through */ if (op == 'M') goto minus; case '+': if (flags & LIBCAP_EFF) setbits(&res->set.effective, &list); if (flags & LIBCAP_INH) setbits(&res->set.inheritable, &list); if (flags & LIBCAP_PER) setbits(&res->set.permitted, &list); break; case '-': minus: if (flags & LIBCAP_EFF) clrbits(&res->set.effective, &list); if (flags & LIBCAP_INH) clrbits(&res->set.inheritable, &list); if (flags & LIBCAP_PER) clrbits(&res->set.permitted, &list); break; } /* new directive? */ if (*str == '+' || *str == '-') { if (!listed) { _cap_debug("for + & - must list capabilities"); goto bad; } flags = 0; /* reset the flags */ op = *str++; if (!isalpha(*str)) goto bad; } } while (*str && !isspace(*str)); _cap_debug("next clause"); } bad: cap_free(&res); errno = EINVAL; return NULL; }
char *cap_to_text(cap_t caps, ssize_t *length_p) { static char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE]; char *p; int histo[8] = {0}; int m, n, t; /* Check arguments */ if (!good_cap_t(caps)) { errno = EINVAL; return NULL; } _cap_debugcap("e = ", &caps->set.effective); _cap_debugcap("i = ", &caps->set.inheritable); _cap_debugcap("p = ", &caps->set.permitted); for (n = __CAP_BITS; n--; ) histo[getstateflags(caps, n)]++; for (m=t=7; t--; ) if (histo[t] > histo[m]) m = t; /* blank is not a valid capability set */ p = sprintf(buf, "=%s%s%s", (m & LIBCAP_EFF) ? "e" : "", (m & LIBCAP_INH) ? "i" : "", (m & LIBCAP_PER) ? "p" : "" ) + buf; for (t = 8; t--; ) if (t != m && histo[t]) { *p++ = ' '; for (n = 0; n != __CAP_BITS; n++) if (getstateflags(caps, n) == t) { if (_cap_names[n]) p += sprintf(p, "%s,", _cap_names[n]); else p += sprintf(p, "%d,", n); if (p - buf > CAP_TEXT_SIZE) { errno = ERANGE; return NULL; } } p--; n = t & ~m; if (n) p += sprintf(p, "+%s%s%s", (n & LIBCAP_EFF) ? "e" : "", (n & LIBCAP_INH) ? "i" : "", (n & LIBCAP_PER) ? "p" : ""); n = ~t & m; if (n) p += sprintf(p, "-%s%s%s", (n & LIBCAP_EFF) ? "e" : "", (n & LIBCAP_INH) ? "i" : "", (n & LIBCAP_PER) ? "p" : ""); if (p - buf > CAP_TEXT_SIZE) { errno = ERANGE; return NULL; } } _cap_debug("%s", buf); if (length_p) { *length_p = p - buf; } return (_libcap_strdup(buf)); }