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