|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <bio.h> | 
|  | #include <auth.h> | 
|  | #include <authsrv.h> | 
|  | #include "authlocal.h" | 
|  |  | 
|  | enum | 
|  | { | 
|  | NARG	= 15,		/* max number of arguments */ | 
|  | MAXARG	= 10*ANAMELEN,	/* max length of an argument */ | 
|  | }; | 
|  |  | 
|  | static int	setenv(char*, char*); | 
|  | static char	*expandarg(char*, char*); | 
|  | static int	splitargs(char*, char*[], char*, int); | 
|  | static int	nsfile(Biobuf *, AuthRpc *); | 
|  | static int	nsop(int, char*[], AuthRpc*); | 
|  | static int	callexport(char*, char*); | 
|  | static int	catch(void*, char*); | 
|  |  | 
|  | static int | 
|  | buildns(int newns, char *user, char *file) | 
|  | { | 
|  | Biobuf *b; | 
|  | char home[4*ANAMELEN]; | 
|  | int afd; | 
|  | AuthRpc *rpc; | 
|  | int cdroot; | 
|  | char *path; | 
|  |  | 
|  | rpc = nil; | 
|  | /* try for factotum now because later is impossible */ | 
|  | afd = open("/mnt/factotum/rpc", ORDWR); | 
|  | if(afd >= 0){ | 
|  | rpc = auth_allocrpc(afd); | 
|  | if(rpc == nil){ | 
|  | close(afd); | 
|  | afd = -1; | 
|  | } | 
|  | } | 
|  | if(file == nil){ | 
|  | if(!newns){ | 
|  | werrstr("no namespace file specified"); | 
|  | return -1; | 
|  | } | 
|  | file = "/lib/namespace"; | 
|  | } | 
|  | b = Bopen(file, OREAD); | 
|  | if(b == 0){ | 
|  | werrstr("can't open %s: %r", file); | 
|  | close(afd); | 
|  | auth_freerpc(rpc); | 
|  | return -1; | 
|  | } | 
|  | if(newns){ | 
|  | rfork(RFENVG|RFCNAMEG); | 
|  | setenv("user", user); | 
|  | snprint(home, 2*ANAMELEN, "/usr/%s", user); | 
|  | setenv("home", home); | 
|  | } | 
|  | cdroot = nsfile(b, rpc); | 
|  | Bterm(b); | 
|  | if(rpc){ | 
|  | close(rpc->afd); | 
|  | auth_freerpc(rpc); | 
|  | } | 
|  |  | 
|  | /* make sure we managed to cd into the new name space */ | 
|  | if(newns && !cdroot){ | 
|  | path = malloc(1024); | 
|  | if(path == nil || getwd(path, 1024) == 0 || chdir(path) < 0) | 
|  | chdir("/"); | 
|  | if(path != nil) | 
|  | free(path); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | nsfile(Biobuf *b, AuthRpc *rpc) | 
|  | { | 
|  | int argc; | 
|  | char *cmd, *argv[NARG+1], argbuf[MAXARG*NARG]; | 
|  | int cdroot = 0; | 
|  |  | 
|  | atnotify(catch, 1); | 
|  | while(cmd = Brdline(b, '\n')){ | 
|  | cmd[Blinelen(b)-1] = '\0'; | 
|  | while(*cmd==' ' || *cmd=='\t') | 
|  | cmd++; | 
|  | if(*cmd == '#') | 
|  | continue; | 
|  | argc = splitargs(cmd, argv, argbuf, NARG); | 
|  | if(argc) | 
|  | cdroot |= nsop(argc, argv, rpc); | 
|  | } | 
|  | atnotify(catch, 0); | 
|  | return cdroot; | 
|  | } | 
|  |  | 
|  | int | 
|  | newns(char *user, char *file) | 
|  | { | 
|  | return buildns(1, user, file); | 
|  | } | 
|  |  | 
|  | int | 
|  | addns(char *user, char *file) | 
|  | { | 
|  | return buildns(0, user, file); | 
|  | } | 
|  |  | 
|  | static int | 
|  | famount(int fd, AuthRpc *rpc, char *mntpt, int flags, char *aname) | 
|  | { | 
|  | int afd; | 
|  | AuthInfo *ai; | 
|  |  | 
|  | afd = fauth(fd, aname); | 
|  | if(afd >= 0){ | 
|  | ai = fauth_proxy(afd, rpc, amount_getkey, "proto=p9any role=client"); | 
|  | if(ai != nil) | 
|  | auth_freeAI(ai); | 
|  | } | 
|  | return mount(fd, afd, mntpt, flags, aname); | 
|  | } | 
|  |  | 
|  | static int | 
|  | nsop(int argc, char *argv[], AuthRpc *rpc) | 
|  | { | 
|  | char *argv0; | 
|  | ulong flags; | 
|  | int fd; | 
|  | Biobuf *b; | 
|  | int cdroot = 0; | 
|  |  | 
|  | flags = 0; | 
|  | argv0 = 0; | 
|  | ARGBEGIN{ | 
|  | case 'a': | 
|  | flags |= MAFTER; | 
|  | break; | 
|  | case 'b': | 
|  | flags |= MBEFORE; | 
|  | break; | 
|  | case 'c': | 
|  | flags |= MCREATE; | 
|  | break; | 
|  | case 'C': | 
|  | flags |= MCACHE; | 
|  | break; | 
|  | }ARGEND | 
|  |  | 
|  | if(!(flags & (MAFTER|MBEFORE))) | 
|  | flags |= MREPL; | 
|  |  | 
|  | if(strcmp(argv0, ".") == 0 && argc == 1){ | 
|  | b = Bopen(argv[0], OREAD); | 
|  | if(b == nil) | 
|  | return 0; | 
|  | cdroot |= nsfile(b, rpc); | 
|  | Bterm(b); | 
|  | } else if(strcmp(argv0, "clear") == 0 && argc == 0) | 
|  | rfork(RFCNAMEG); | 
|  | else if(strcmp(argv0, "bind") == 0 && argc == 2) | 
|  | bind(argv[0], argv[1], flags); | 
|  | else if(strcmp(argv0, "unmount") == 0){ | 
|  | if(argc == 1) | 
|  | unmount(nil, argv[0]); | 
|  | else if(argc == 2) | 
|  | unmount(argv[0], argv[1]); | 
|  | } else if(strcmp(argv0, "mount") == 0){ | 
|  | fd = open(argv[0], ORDWR); | 
|  | if(argc == 2) | 
|  | famount(fd, rpc, argv[1], flags, ""); | 
|  | else if(argc == 3) | 
|  | famount(fd, rpc, argv[1], flags, argv[2]); | 
|  | close(fd); | 
|  | } else if(strcmp(argv0, "import") == 0){ | 
|  | fd = callexport(argv[0], argv[1]); | 
|  | if(argc == 2) | 
|  | famount(fd, rpc, argv[1], flags, ""); | 
|  | else if(argc == 3) | 
|  | famount(fd, rpc, argv[2], flags, ""); | 
|  | close(fd); | 
|  | } else if(strcmp(argv0, "cd") == 0 && argc == 1) | 
|  | if(chdir(argv[0]) == 0 && *argv[0] == '/') | 
|  | cdroot = 1; | 
|  | return cdroot; | 
|  | } | 
|  |  | 
|  | static char *wocp = "sys: write on closed pipe"; | 
|  |  | 
|  | static int | 
|  | catch(void *x, char *m) | 
|  | { | 
|  | USED(x); | 
|  | return strncmp(m, wocp, strlen(wocp)) == 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | callexport(char *sys, char *tree) | 
|  | { | 
|  | char *na, buf[3]; | 
|  | int fd; | 
|  | AuthInfo *ai; | 
|  |  | 
|  | na = netmkaddr(sys, 0, "exportfs"); | 
|  | if((fd = dial(na, 0, 0, 0)) < 0) | 
|  | return -1; | 
|  | if((ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client")) == nil | 
|  | || write(fd, tree, strlen(tree)) < 0 | 
|  | || read(fd, buf, 3) != 2 || buf[0]!='O' || buf[1]!= 'K'){ | 
|  | close(fd); | 
|  | auth_freeAI(ai); | 
|  | return -1; | 
|  | } | 
|  | auth_freeAI(ai); | 
|  | return fd; | 
|  | } | 
|  |  | 
|  | static int | 
|  | splitargs(char *p, char *argv[], char *argbuf, int nargv) | 
|  | { | 
|  | char *q; | 
|  | int i, n; | 
|  |  | 
|  | n = gettokens(p, argv, nargv, " \t'\r"); | 
|  | if(n == nargv) | 
|  | return 0; | 
|  | for(i = 0; i < n; i++){ | 
|  | q = argv[i]; | 
|  | argv[i] = argbuf; | 
|  | argbuf = expandarg(q, argbuf); | 
|  | if(!argbuf) | 
|  | return 0; | 
|  | } | 
|  | return n; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * copy the arg into the buffer, | 
|  | * expanding any environment variables. | 
|  | * environment variables are assumed to be | 
|  | * names (ie. < ANAMELEN long) | 
|  | * the entire argument is expanded to be at | 
|  | * most MAXARG long and null terminated | 
|  | * the address of the byte after the terminating null is returned | 
|  | * any problems cause a 0 return; | 
|  | */ | 
|  | static char * | 
|  | expandarg(char *arg, char *buf) | 
|  | { | 
|  | char env[3+ANAMELEN], *p, *q, *x; | 
|  | int fd, n, len; | 
|  |  | 
|  | n = 0; | 
|  | while(p = utfrune(arg, L'$')){ | 
|  | len = p - arg; | 
|  | if(n + len + ANAMELEN >= MAXARG-1) | 
|  | return 0; | 
|  | memmove(&buf[n], arg, len); | 
|  | n += len; | 
|  | p++; | 
|  | arg = utfrune(p, L'\0'); | 
|  | q = utfrune(p, L'/'); | 
|  | if(q && q < arg) | 
|  | arg = q; | 
|  | q = utfrune(p, L'.'); | 
|  | if(q && q < arg) | 
|  | arg = q; | 
|  | q = utfrune(p, L'$'); | 
|  | if(q && q < arg) | 
|  | arg = q; | 
|  | len = arg - p; | 
|  | if(len >= ANAMELEN) | 
|  | continue; | 
|  | strcpy(env, "#e/"); | 
|  | strncpy(env+3, p, len); | 
|  | env[3+len] = '\0'; | 
|  | fd = open(env, OREAD); | 
|  | if(fd >= 0){ | 
|  | len = read(fd, &buf[n], ANAMELEN - 1); | 
|  | /* some singleton environment variables have trailing NULs */ | 
|  | /* lists separate entries with NULs; we arbitrarily take the first element */ | 
|  | if(len > 0){ | 
|  | x = memchr(&buf[n], 0, len); | 
|  | if(x != nil) | 
|  | len = x - &buf[n]; | 
|  | n += len; | 
|  | } | 
|  | close(fd); | 
|  | } | 
|  | } | 
|  | len = strlen(arg); | 
|  | if(n + len >= MAXARG - 1) | 
|  | return 0; | 
|  | strcpy(&buf[n], arg); | 
|  | return &buf[n+len+1]; | 
|  | } | 
|  |  | 
|  | static int | 
|  | setenv(char *name, char *val) | 
|  | { | 
|  | int f; | 
|  | char ename[ANAMELEN+6]; | 
|  | long s; | 
|  |  | 
|  | sprint(ename, "#e/%s", name); | 
|  | f = create(ename, OWRITE, 0664); | 
|  | if(f < 0) | 
|  | return -1; | 
|  | s = strlen(val); | 
|  | if(write(f, val, s) != s){ | 
|  | close(f); | 
|  | return -1; | 
|  | } | 
|  | close(f); | 
|  | return 0; | 
|  | } |