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