1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <auth.h> 5 #include <authsrv.h> 6 #include "authlocal.h" 7 8 enum 9 { 10 NARG = 15, /* max number of arguments */ 11 MAXARG = 10*ANAMELEN, /* max length of an argument */ 12 }; 13 14 static int setenv(char*, char*); 15 static char *expandarg(char*, char*); 16 static int splitargs(char*, char*[], char*, int); 17 static int nsfile(char*, Biobuf *, AuthRpc *); 18 static int nsop(char*, int, char*[], AuthRpc*); 19 static int callexport(char*, char*); 20 static int catch(void*, char*); 21 22 int newnsdebug; 23 24 static int 25 freecloserpc(AuthRpc *rpc) 26 { 27 if(rpc){ 28 close(rpc->afd); 29 auth_freerpc(rpc); 30 } 31 return -1; 32 } 33 34 static int 35 buildns(int newns, char *user, char *file) 36 { 37 Biobuf *b; 38 char home[4*ANAMELEN]; 39 int afd, cdroot; 40 char *path; 41 AuthRpc *rpc; 42 43 rpc = nil; 44 /* try for factotum now because later is impossible */ 45 afd = open("/mnt/factotum/rpc", ORDWR); 46 if(afd < 0 && newnsdebug) 47 fprint(2, "open /mnt/factotum/rpc: %r\n"); 48 if(afd >= 0){ 49 rpc = auth_allocrpc(afd); 50 if(rpc == nil) 51 close(afd); 52 } 53 /* rpc != nil iff afd >= 0 */ 54 55 if(file == nil){ 56 if(!newns){ 57 werrstr("no namespace file specified"); 58 return freecloserpc(rpc); 59 } 60 file = "/lib/namespace"; 61 } 62 b = Bopen(file, OREAD); 63 if(b == 0){ 64 werrstr("can't open %s: %r", file); 65 return freecloserpc(rpc); 66 } 67 if(newns){ 68 rfork(RFENVG|RFCNAMEG); 69 setenv("user", user); 70 snprint(home, sizeof home, "/usr/%s", user); 71 setenv("home", home); 72 } 73 74 cdroot = nsfile(newns ? "newns" : "addns", b, rpc); 75 Bterm(b); 76 freecloserpc(rpc); 77 78 /* make sure we managed to cd into the new name space */ 79 if(newns && !cdroot){ 80 path = malloc(1024); 81 if(path == nil || getwd(path, 1024) == 0 || chdir(path) < 0) 82 chdir("/"); 83 if(path != nil) 84 free(path); 85 } 86 87 return 0; 88 } 89 90 static int 91 nsfile(char *fn, Biobuf *b, AuthRpc *rpc) 92 { 93 int argc; 94 char *cmd, *argv[NARG+1], argbuf[MAXARG*NARG]; 95 int cdroot; 96 97 cdroot = 0; 98 atnotify(catch, 1); 99 while(cmd = Brdline(b, '\n')){ 100 cmd[Blinelen(b)-1] = '\0'; 101 while(*cmd==' ' || *cmd=='\t') 102 cmd++; 103 if(*cmd == '#') 104 continue; 105 argc = splitargs(cmd, argv, argbuf, NARG); 106 if(argc) 107 cdroot |= nsop(fn, argc, argv, rpc); 108 } 109 atnotify(catch, 0); 110 return cdroot; 111 } 112 113 int 114 newns(char *user, char *file) 115 { 116 return buildns(1, user, file); 117 } 118 119 int 120 addns(char *user, char *file) 121 { 122 return buildns(0, user, file); 123 } 124 125 static int 126 famount(int fd, AuthRpc *rpc, char *mntpt, int flags, char *aname) 127 { 128 int afd; 129 AuthInfo *ai; 130 int ret; 131 132 afd = fauth(fd, aname); 133 if(afd >= 0){ 134 ai = fauth_proxy(afd, rpc, amount_getkey, "proto=p9any role=client"); 135 if(ai != nil) 136 auth_freeAI(ai); 137 } 138 ret = mount(fd, afd, mntpt, flags, aname); 139 if(afd >= 0) 140 close(afd); 141 return ret; 142 } 143 144 static int 145 nsop(char *fn, int argc, char *argv[], AuthRpc *rpc) 146 { 147 char *argv0; 148 ulong flags; 149 int fd, i; 150 Biobuf *b; 151 int cdroot; 152 153 cdroot = 0; 154 flags = 0; 155 argv0 = 0; 156 if (newnsdebug){ 157 for (i = 0; i < argc; i++) 158 fprint(2, "%s ", argv[i]); 159 fprint(2, "\n"); 160 } 161 ARGBEGIN{ 162 case 'a': 163 flags |= MAFTER; 164 break; 165 case 'b': 166 flags |= MBEFORE; 167 break; 168 case 'c': 169 flags |= MCREATE; 170 break; 171 case 'C': 172 flags |= MCACHE; 173 break; 174 }ARGEND 175 176 if(!(flags & (MAFTER|MBEFORE))) 177 flags |= MREPL; 178 179 if(strcmp(argv0, ".") == 0 && argc == 1){ 180 b = Bopen(argv[0], OREAD); 181 if(b == nil) 182 return 0; 183 cdroot |= nsfile(fn, b, rpc); 184 Bterm(b); 185 }else if(strcmp(argv0, "clear") == 0 && argc == 0) 186 rfork(RFCNAMEG); 187 else if(strcmp(argv0, "bind") == 0 && argc == 2){ 188 if(bind(argv[0], argv[1], flags) < 0 && newnsdebug) 189 fprint(2, "%s: bind: %s %s: %r\n", fn, argv[0], argv[1]); 190 }else if(strcmp(argv0, "unmount") == 0){ 191 if(argc == 1) 192 unmount(nil, argv[0]); 193 else if(argc == 2) 194 unmount(argv[0], argv[1]); 195 }else if(strcmp(argv0, "mount") == 0){ 196 fd = open(argv[0], ORDWR); 197 if(argc == 2){ 198 if(famount(fd, rpc, argv[1], flags, "") < 0 && newnsdebug) 199 fprint(2, "%s: mount: %s %s: %r\n", fn, argv[0], argv[1]); 200 }else if(argc == 3){ 201 if(famount(fd, rpc, argv[1], flags, argv[2]) < 0 && newnsdebug) 202 fprint(2, "%s: mount: %s %s %s: %r\n", fn, argv[0], argv[1], argv[2]); 203 } 204 close(fd); 205 }else if(strcmp(argv0, "import") == 0){ 206 fd = callexport(argv[0], argv[1]); 207 if(argc == 2) 208 famount(fd, rpc, argv[1], flags, ""); 209 else if(argc == 3) 210 famount(fd, rpc, argv[2], flags, ""); 211 close(fd); 212 }else if(strcmp(argv0, "cd") == 0 && argc == 1){ 213 if(chdir(argv[0]) == 0 && *argv[0] == '/') 214 cdroot = 1; 215 } 216 return cdroot; 217 } 218 219 static char *wocp = "sys: write on closed pipe"; 220 221 static int 222 catch(void *x, char *m) 223 { 224 USED(x); 225 return strncmp(m, wocp, strlen(wocp)) == 0; 226 } 227 228 static int 229 callexport(char *sys, char *tree) 230 { 231 char *na, buf[3]; 232 int fd; 233 AuthInfo *ai; 234 235 na = netmkaddr(sys, 0, "exportfs"); 236 if((fd = dial(na, 0, 0, 0)) < 0) 237 return -1; 238 if((ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client")) == nil 239 || write(fd, tree, strlen(tree)) < 0 240 || read(fd, buf, 3) != 2 || buf[0]!='O' || buf[1]!= 'K'){ 241 close(fd); 242 auth_freeAI(ai); 243 return -1; 244 } 245 auth_freeAI(ai); 246 return fd; 247 } 248 249 static char* 250 unquote(char *s) 251 { 252 char *r, *w; 253 int inquote; 254 255 inquote = 0; 256 for(r=w=s; *r; r++){ 257 if(*r != '\''){ 258 *w++ = *r; 259 continue; 260 } 261 if(inquote){ 262 if(*(r+1) == '\''){ 263 *w++ = '\''; 264 r++; 265 }else 266 inquote = 0; 267 }else 268 inquote = 1; 269 } 270 *w = 0; 271 return s; 272 } 273 274 static int 275 splitargs(char *p, char *argv[], char *argbuf, int nargv) 276 { 277 char *q; 278 int i, n; 279 280 n = gettokens(p, argv, nargv, " \t\r"); 281 if(n == nargv) 282 return 0; 283 for(i = 0; i < n; i++){ 284 q = argv[i]; 285 argv[i] = argbuf; 286 argbuf = expandarg(q, argbuf); 287 if(argbuf == nil) 288 return 0; 289 unquote(argv[i]); 290 } 291 return n; 292 } 293 294 static char* 295 nextdollar(char *arg) 296 { 297 char *p; 298 int inquote; 299 300 inquote = 0; 301 for(p=arg; *p; p++){ 302 if(*p == '\'') 303 inquote = !inquote; 304 if(*p == '$' && !inquote) 305 return p; 306 } 307 return nil; 308 } 309 310 /* 311 * copy the arg into the buffer, 312 * expanding any environment variables. 313 * environment variables are assumed to be 314 * names (ie. < ANAMELEN long) 315 * the entire argument is expanded to be at 316 * most MAXARG long and null terminated 317 * the address of the byte after the terminating null is returned 318 * any problems cause a 0 return; 319 */ 320 static char * 321 expandarg(char *arg, char *buf) 322 { 323 char env[3+ANAMELEN], *p, *x; 324 int fd, n, len; 325 326 n = 0; 327 while(p = nextdollar(arg)){ 328 len = p - arg; 329 if(n + len + ANAMELEN >= MAXARG-1) 330 return 0; 331 memmove(&buf[n], arg, len); 332 n += len; 333 p++; 334 arg = strpbrk(p, "/.!'$"); 335 if(arg == nil) 336 arg = p+strlen(p); 337 len = arg - p; 338 if(len == 0 || len >= ANAMELEN) 339 continue; 340 strcpy(env, "#e/"); 341 strncpy(env+3, p, len); 342 env[3+len] = '\0'; 343 fd = open(env, OREAD); 344 if(fd >= 0){ 345 len = read(fd, &buf[n], ANAMELEN - 1); 346 /* some singleton environment variables have trailing NULs */ 347 /* lists separate entries with NULs; we arbitrarily take the first element */ 348 if(len > 0){ 349 x = memchr(&buf[n], 0, len); 350 if(x != nil) 351 len = x - &buf[n]; 352 n += len; 353 } 354 close(fd); 355 } 356 } 357 len = strlen(arg); 358 if(n + len >= MAXARG - 1) 359 return 0; 360 strcpy(&buf[n], arg); 361 return &buf[n+len+1]; 362 } 363 364 static int 365 setenv(char *name, char *val) 366 { 367 int f; 368 char ename[ANAMELEN+6]; 369 long s; 370 371 sprint(ename, "#e/%s", name); 372 f = create(ename, OWRITE, 0664); 373 if(f < 0) 374 return -1; 375 s = strlen(val); 376 if(write(f, val, s) != s){ 377 close(f); 378 return -1; 379 } 380 close(f); 381 return 0; 382 } 383