xref: /plan9/sys/src/libauth/newns.c (revision f366f900ff2cf070570ce4f3ef512f925d4caaac)
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