1 /* 2 * as user cmd [arg...] - run cmd with args as user on this cpu server. 3 * must be hostowner for this to work. 4 * needs #¤/caphash and #¤/capuse. 5 */ 6 #include <u.h> 7 #include <libc.h> 8 #include <bio.h> 9 #include <libsec.h> 10 #include <auth.h> 11 #include "authcmdlib.h" 12 13 int debug; 14 15 int becomeuser(char*); 16 void createuser(void); 17 void *emalloc(ulong); 18 void *erealloc(void*, ulong); 19 void initcap(void); 20 int mkcmd(char*, char*, int); 21 int myauth(int, char*); 22 int qidcmp(Qid, Qid); 23 void runas(char *, char *); 24 void usage(void); 25 26 #pragma varargck argpos clog 1 27 #pragma varargck argpos fatal 1 28 29 static void 30 fatal(char *fmt, ...) 31 { 32 char msg[256]; 33 va_list arg; 34 35 va_start(arg, fmt); 36 vseprint(msg, msg + sizeof msg, fmt, arg); 37 va_end(arg); 38 error("%s", msg); 39 } 40 41 void 42 main(int argc, char *argv[]) 43 { 44 debug = 0; 45 ARGBEGIN{ 46 case 'd': 47 debug = 1; 48 break; 49 default: 50 usage(); 51 }ARGEND 52 53 initcap(); 54 srand(getpid()*time(0)); 55 runas(argv[0], argv[1]); 56 } 57 58 void 59 runas(char *user, char *cmd) 60 { 61 if(becomeuser(user) < 0) 62 sysfatal("can't change uid for %s: %r", user); 63 putenv("service", "rx"); 64 execl("/bin/rc", "rc", "-lc", cmd, nil); 65 sysfatal("exec /bin/rc: %r"); 66 } 67 68 void * 69 emalloc(ulong n) 70 { 71 void *p; 72 73 if(p = mallocz(n, 1)) 74 return p; 75 fatal("out of memory"); 76 return 0; 77 } 78 79 void * 80 erealloc(void *p, ulong n) 81 { 82 if(p = realloc(p, n)) 83 return p; 84 fatal("out of memory"); 85 return 0; 86 } 87 88 void 89 usage(void) 90 { 91 fprint(2, "usage: %s [-c]\n", argv0); 92 exits("usage"); 93 } 94 95 void 96 memrandom(void *p, int n) 97 { 98 uchar *cp; 99 100 for(cp = (uchar*)p; n > 0; n--) 101 *cp++ = fastrand(); 102 } 103 104 /* 105 * keep caphash fd open since opens of it could be disabled 106 */ 107 static int caphashfd; 108 109 void 110 initcap(void) 111 { 112 caphashfd = open("#¤/caphash", OCEXEC|OWRITE); 113 if(caphashfd < 0) 114 fprint(2, "%s: opening #¤/caphash: %r\n", argv0); 115 } 116 117 /* 118 * create a change uid capability 119 */ 120 char* 121 mkcap(char *from, char *to) 122 { 123 uchar rand[20]; 124 char *cap; 125 char *key; 126 int nfrom, nto, ncap; 127 uchar hash[SHA1dlen]; 128 129 if(caphashfd < 0) 130 return nil; 131 132 /* create the capability */ 133 nto = strlen(to); 134 nfrom = strlen(from); 135 ncap = nfrom + 1 + nto + 1 + sizeof(rand)*3 + 1; 136 cap = emalloc(ncap); 137 snprint(cap, ncap, "%s@%s", from, to); 138 memrandom(rand, sizeof(rand)); 139 key = cap+nfrom+1+nto+1; 140 enc64(key, sizeof(rand)*3, rand, sizeof(rand)); 141 142 /* hash the capability */ 143 hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil); 144 145 /* give the kernel the hash */ 146 key[-1] = '@'; 147 if(write(caphashfd, hash, SHA1dlen) < 0){ 148 free(cap); 149 return nil; 150 } 151 152 return cap; 153 } 154 155 int 156 usecap(char *cap) 157 { 158 int fd, rv; 159 160 fd = open("#¤/capuse", OWRITE); 161 if(fd < 0) 162 return -1; 163 rv = write(fd, cap, strlen(cap)); 164 close(fd); 165 return rv; 166 } 167 168 int 169 becomeuser(char *new) 170 { 171 char *cap; 172 int rv; 173 174 cap = mkcap(getuser(), new); 175 if(cap == nil) 176 return -1; 177 rv = usecap(cap); 178 free(cap); 179 180 newns(new, nil); 181 return rv; 182 } 183