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