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