summaryrefslogtreecommitdiff
path: root/sys/src/libauth/newns.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libauth/newns.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libauth/newns.c')
-rwxr-xr-xsys/src/libauth/newns.c382
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;
+}