applyuidgid-caps.c (3140B)
1 /* ISC license. */ 2 3 #include <unistd.h> 4 #include <grp.h> 5 #include <limits.h> 6 #include <stdlib.h> 7 #include <sys/prctl.h> 8 #include <sys/capability.h> 9 #include <linux/securebits.h> 10 11 #include <skalibs/types.h> 12 #include <skalibs/setgroups.h> 13 #include <skalibs/strerr2.h> 14 #include <skalibs/sgetopt.h> 15 #include <skalibs/djbunix.h> 16 #include <skalibs/exec.h> 17 18 #define USAGE "applyuidgid-caps [ -z ] [ -u uid ] [ -g gid ] [ -G gidlist ] [ -U ] iab_caps prog..." 19 #define dieusage() strerr_dieusage(100, USAGE) 20 21 int main (int argc, char const *const *argv) 22 { 23 uid_t uid = 0 ; 24 gid_t gid = 0 ; 25 gid_t gids[NGROUPS_MAX+1] ; 26 size_t gidn = (size_t)-1 ; 27 int unexport = 0 ; 28 PROG = "s6-applyuidgid" ; 29 { 30 subgetopt l = SUBGETOPT_ZERO ; 31 for (;;) 32 { 33 int opt = subgetopt_r(argc, argv, "zUu:g:G:", &l) ; 34 if (opt == -1) break ; 35 switch (opt) 36 { 37 case 'z' : unexport = 1 ; break ; 38 case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; 39 case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; 40 case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; 41 case 'U' : 42 { 43 char const *x = getenv("UID") ; 44 if (!x) strerr_dienotset(100, "UID") ; 45 if (!uid0_scan(x, &uid)) strerr_dieinvalid(100, "UID") ; 46 x = getenv("GID") ; 47 if (!x) strerr_dienotset(100, "GID") ; 48 if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, "GID") ; 49 x = getenv("GIDLIST") ; 50 if (!x) strerr_dienotset(100, "GIDLIST") ; 51 if (!gid_scanlist(gids, NGROUPS_MAX+1, x, &gidn) && *x) 52 strerr_dieinvalid(100, "GIDLIST") ; 53 break ; 54 } 55 default : dieusage() ; 56 } 57 } 58 argc -= l.ind ; argv += l.ind ; 59 } 60 if (argc < 2) dieusage() ; 61 62 /* 63 The IAB 3-tuple of capability vectors (Inh, Amb and Bound), 64 captured in type cap_iab_t combine to pass capabilities 65 from one process to another through execve(2) system calls. 66 */ 67 68 /* parse the first argument to obtain a set of capabilities */ 69 cap_iab_t new_iab; 70 new_iab = cap_iab_from_text(argv[0]); 71 if (new_iab == NULL) { 72 strerr_dieinvalid(100, "caps") ; 73 // strerr_dief1sys(100, "requested capabilities were not recognized"); 74 } 75 76 if (prctl(PR_SET_SECUREBITS, 77 SECBIT_KEEP_CAPS | /* unneeded as NO_SETUID_FIXUP is superset */ 78 SECBIT_NO_SETUID_FIXUP | 79 SECBIT_NOROOT | /* disables suid and filecap privilege gain */ 80 SECBIT_NOROOT_LOCKED) < 0) { 81 strerr_dief1sys(111, "Failed to set securebits via prctl()"); 82 } 83 /* set these capabilities for the current process */ 84 if (cap_iab_set_proc(new_iab) != 0) { 85 strerr_dief1sys(111, "Failed to set capabilities via cap_set_proc()"); 86 } 87 88 if (gidn != (size_t)-1 && setgroups_and_gid(gid ? gid : getegid(), gidn, gids) < 0) 89 strerr_diefu1sys(111, "set supplementary group list") ; 90 if (gid && setgid(gid) < 0) 91 strerr_diefu1sys(111, "setgid") ; 92 if (uid && setuid(uid) < 0) 93 strerr_diefu1sys(111, "setuid") ; 94 95 if (unexport) xmexec_n(argv, "UID\0GID\0GIDLIST", 16, 3) ; 96 else xexec(&argv[1]) ; 97 }