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