From 9c49729624b1a9c2c48d43929a4cbb2ce3c8db06 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Mon, 23 Nov 2009 00:43:10 -0800 Subject: New features (setting user and groups) Signed-off-by: Andrew G. Morgan --- doc/capsh.1 | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- progs/capsh.c | 51 ++++++++++++++++++++++++-- 2 files changed, 149 insertions(+), 18 deletions(-) diff --git a/doc/capsh.1 b/doc/capsh.1 index 20973b5..4f9273d 100644 --- a/doc/capsh.1 +++ b/doc/capsh.1 @@ -1,7 +1,7 @@ .\" -.\" capsh.1 Man page added 2009-11-22 Andrew G. Morgan +.\" capsh.1 Man page added 2009-12-23 Andrew G. Morgan .\" -.TH CAPSH 1 "2009-11-22" "libcap 2" "User Commands" +.TH CAPSH 1 "2009-12-24" "libcap 2" "User Commands" .SH NAME capsh \- capability shell wrapper .SH SYNOPSIS @@ -24,7 +24,7 @@ Execute .B /bin/bash with trailing arguments. Note, you can use .B -c 'command to execute' -for commands. +for specific commands. .TP .B == Execute @@ -41,29 +41,115 @@ Where is a text-representation of capability state as per .BR cap_from_text (3). .TP -.BI --drop= +.BI --drop= cap-list +Remove the listed capabilities from the prevailing bounding set. The +capabilites are a comma separated list of capabilities as recognized +by the +.BR cap_from_name (3) +function. Use of this feature requires that the capsh program is +operating with +.B CAP_SETPCAP +in its effective set. .TP -.BI --inh= +.BI --inh= cap-list +Set the inheritable set of capabilities for the current process to +equal those provided in the comma separated list. For this action to +succeed, the prevailing process should already have each of these +capabilities in the union of the current inheritable and permitted +capability sets, or the capsh program is operating with +.B CAP_SETPCAP +in its effective set. .TP -.BI --keep= <0|1> +.BI --user= username +Assume the identity of the named user. That is, look up the user's +.IR uid " and " gid +with +.BR getpwuid (3) +and their group memberships with +.BR getgrouplist (3) +and set them all. .TP -.BI --chroot= +.BI --uid= id +Force all +.B uid +values to equal +.I id +using the +.BR setuid (2) +system call. .TP -.BI --secbits= +.BI --gid= +Force all +.B gid +values to equal +.I id +using the +.BR setgid (2) +system call. .TP -.BI --forkfor= +.BI --groups= +Set the supplementary groups to the numerical list provided. The +groups are set with the +.BR setgroups (2) +system call. .TP -.BI --killit= +.BI --keep= <0|1> +In a non-pure capability mode, the kernel provides liberal privilege +to the super-user. However, it is normally the case that when the +super-user changes +.I uid +to some lesser user, then capabilities are dropped. For these +situations, the kernel can permit the process to retain its +capabilities after a +.BR setuid (2) +system call. This feature is known as +.I keep-caps +support. The way to activate it using this script is with this +argument. Setting the value to 1 will cause +.I keep-caps +to be active. Setting it to 0 will cause keep-caps to deactivate for +the current process. In all cases, +.I keep-caps +is deactivated when an +.BR exec () +is performed. See +.B --secbits +for ways to disable this feature. .TP -.BI --uid= +.BI --secbits= N +XXX - need to document this feature. .TP -.BI --gid= +.BI --chroot= path +Execute the +.BR chroot (2) +system call with the new root-directory (/) equal to +.IR path . +This operation requires +.B CAP_SYS_CHROOT +to be in effect. .TP -.BI --groups= +.BI --forkfor= sec .TP -.BI --user= +.BI --killit= sig .TP -.BI --decode= +.BI --decode= N +This is a convenience feature. If you look at +.B /proc/1/status +there are some capability related fields of the following form: + + CapInh: 0000000000000000 + CapPrm: ffffffffffffffff + CapEff: fffffffffffffeff + CapBnd: ffffffffffffffff + +This option provides a quick way to decode a capability vector +represented in this form. For example, the missing capability from +this effective set is 0x0100. By running: + + capsh --decode=0x0100 + +we observe that the missing capability is: +.BR cap_setpcap . .SH "EXIT STATUS" Following successful execution the tool exits with status 0. Following an error, the tool immediately exits with status 1. diff --git a/progs/capsh.c b/progs/capsh.c index 4cc3549..10aecf4 100644 --- a/progs/capsh.c +++ b/progs/capsh.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -328,7 +329,50 @@ int main(int argc, char *argv[], char *envp[]) exit(1); } } else if (!memcmp("--groups=", argv[i], 9)) { - exit(1); + char *ptr, *buf; + long length, max_groups; + gid_t *group_list; + int g_count; + + length = sysconf(_SC_GETGR_R_SIZE_MAX); + buf = calloc(1, length); + if (NULL == buf) { + fprintf(stderr, "No memory for [%s] operation\n", argv[i]); + exit(1); + } + + max_groups = sysconf(_SC_NGROUPS_MAX); + group_list = calloc(max_groups, sizeof(gid_t)); + if (NULL == group_list) { + fprintf(stderr, "No memory for gid list\n"); + exit(1); + } + + g_count = 0; + for (ptr = argv[i] + 9; (ptr = strtok(ptr, ",")); + ptr = NULL, g_count++) { + if (max_groups <= g_count) { + fprintf(stderr, "Too many groups specified (%d)\n", g_count); + exit(1); + } + if (!isdigit(*ptr)) { + struct group *g, grp; + getgrnam_r(ptr, &grp, buf, length, &g); + if (NULL == g) { + fprintf(stderr, "Failed to identify gid for group [%s]\n", ptr); + exit(1); + } + group_list[g_count] = g->gr_gid; + } else { + group_list[g_count] = strtoul(ptr, NULL, 0); + } + } + free(buf); + if (setgroups(g_count, group_list) != 0) { + fprintf(stderr, "Failed to setgroups.\n"); + exit(1); + } + free(group_list); } else if (!memcmp("--user=", argv[i], 7)) { struct passwd *pwd; const char *user; @@ -374,7 +418,7 @@ int main(int argc, char *argv[], char *envp[]) value = strtoull(argv[i]+9, NULL, 16); printf("0x%016llx=", value); - for (cap=0; value >> cap; ++cap) { + for (cap=0; (cap < 64) && (value >> cap); ++cap) { if (value & (1ULL << cap)) { const char *ptr; @@ -470,8 +514,9 @@ int main(int argc, char *argv[], char *envp[]) " --keep= set keep-capabability bit to \n" " --uid= set uid to (hint: id )\n" " --gid= set gid to (hint: id )\n" + " --groups=g,... set the supplemental groups\n" " --user= set uid,gid and groups to that of user\n" - " --chroot=path chroot(2) to this path to invoke bash\n" + " --chroot=path chroot(2) to this path\n" " --killit= send signal(n) to child\n" " --forkfor= fork and make child sleep for sec\n" " == re-exec(capsh) with args as for --\n" -- cgit v1.2.1