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