diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libauth/newns.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libauth/newns.c')
-rwxr-xr-x | sys/src/libauth/newns.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/sys/src/libauth/newns.c b/sys/src/libauth/newns.c new file mode 100755 index 000000000..3486a93ab --- /dev/null +++ b/sys/src/libauth/newns.c @@ -0,0 +1,382 @@ +#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(char*, Biobuf *, AuthRpc *); +static int nsop(char*, int, char*[], AuthRpc*); +static int callexport(char*, char*); +static int catch(void*, char*); + +int newnsdebug; + +static int +freecloserpc(AuthRpc *rpc) +{ + if(rpc){ + close(rpc->afd); + auth_freerpc(rpc); + } + return -1; +} + +static int +buildns(int newns, char *user, char *file) +{ + Biobuf *b; + char home[4*ANAMELEN]; + int afd, cdroot; + char *path; + AuthRpc *rpc; + + rpc = nil; + /* try for factotum now because later is impossible */ + afd = open("/mnt/factotum/rpc", ORDWR); + if(afd < 0 && newnsdebug) + fprint(2, "open /mnt/factotum/rpc: %r\n"); + if(afd >= 0){ + rpc = auth_allocrpc(afd); + if(rpc == nil) + close(afd); + } + /* rpc != nil iff afd >= 0 */ + + if(file == nil){ + if(!newns){ + werrstr("no namespace file specified"); + return freecloserpc(rpc); + } + file = "/lib/namespace"; + } + b = Bopen(file, OREAD); + if(b == 0){ + werrstr("can't open %s: %r", file); + return freecloserpc(rpc); + } + if(newns){ + rfork(RFENVG|RFCNAMEG); + setenv("user", user); + snprint(home, sizeof home, "/usr/%s", user); + setenv("home", home); + } + + cdroot = nsfile(newns ? "newns" : "addns", b, rpc); + Bterm(b); + freecloserpc(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(char *fn, Biobuf *b, AuthRpc *rpc) +{ + int argc; + char *cmd, *argv[NARG+1], argbuf[MAXARG*NARG]; + int cdroot; + + 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(fn, 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; + int ret; + + afd = fauth(fd, aname); + if(afd >= 0){ + ai = fauth_proxy(afd, rpc, amount_getkey, "proto=p9any role=client"); + if(ai != nil) + auth_freeAI(ai); + } + ret = mount(fd, afd, mntpt, flags, aname); + if(afd >= 0) + close(afd); + return ret; +} + +static int +nsop(char *fn, int argc, char *argv[], AuthRpc *rpc) +{ + char *argv0; + ulong flags; + int fd, i; + Biobuf *b; + int cdroot; + + cdroot = 0; + flags = 0; + argv0 = 0; + if (newnsdebug){ + for (i = 0; i < argc; i++) + fprint(2, "%s ", argv[i]); + fprint(2, "\n"); + } + 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(fn, b, rpc); + Bterm(b); + }else if(strcmp(argv0, "clear") == 0 && argc == 0) + rfork(RFCNAMEG); + else if(strcmp(argv0, "bind") == 0 && argc == 2){ + if(bind(argv[0], argv[1], flags) < 0 && newnsdebug) + fprint(2, "%s: bind: %s %s: %r\n", fn, argv[0], argv[1]); + }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){ + if(famount(fd, rpc, argv[1], flags, "") < 0 && newnsdebug) + fprint(2, "%s: mount: %s %s: %r\n", fn, argv[0], argv[1]); + }else if(argc == 3){ + if(famount(fd, rpc, argv[1], flags, argv[2]) < 0 && newnsdebug) + fprint(2, "%s: mount: %s %s %s: %r\n", fn, argv[0], argv[1], 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 char* +unquote(char *s) +{ + char *r, *w; + int inquote; + + inquote = 0; + for(r=w=s; *r; r++){ + if(*r != '\''){ + *w++ = *r; + continue; + } + if(inquote){ + if(*(r+1) == '\''){ + *w++ = '\''; + r++; + }else + inquote = 0; + }else + inquote = 1; + } + *w = 0; + return s; +} + +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 == nil) + return 0; + unquote(argv[i]); + } + return n; +} + +static char* +nextdollar(char *arg) +{ + char *p; + int inquote; + + inquote = 0; + for(p=arg; *p; p++){ + if(*p == '\'') + inquote = !inquote; + if(*p == '$' && !inquote) + return p; + } + return nil; +} + +/* + * 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, *x; + int fd, n, len; + + n = 0; + while(p = nextdollar(arg)){ + len = p - arg; + if(n + len + ANAMELEN >= MAXARG-1) + return 0; + memmove(&buf[n], arg, len); + n += len; + p++; + arg = strpbrk(p, "/.!'$"); + if(arg == nil) + arg = p+strlen(p); + len = arg - p; + if(len == 0 || 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; +} |