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