]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libauth/newns.c
libauth: open internal file-descriptors with OCEXEC flag
[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|OCEXEC);
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|OCEXEC);
62         if(b == nil){
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(ret == -1)
139                 close(fd);
140         if(afd >= 0)
141                 close(afd);
142         return ret;
143 }
144
145 static int
146 nsop(char *fn, int argc, char *argv[], AuthRpc *rpc)
147 {
148         char *argv0;
149         ulong flags;
150         int fd, i;
151         Biobuf *b;
152         int cdroot;
153
154         cdroot = 0;
155         flags = 0;
156         argv0 = nil;
157         if(newnsdebug){
158                 for (i = 0; i < argc; i++)
159                         fprint(2, "%s ", argv[i]);
160                 fprint(2, "\n");
161         }
162         ARGBEGIN{
163         case 'a':
164                 flags |= MAFTER;
165                 break;
166         case 'b':
167                 flags |= MBEFORE;
168                 break;
169         case 'c':
170                 flags |= MCREATE;
171                 break;
172         case 'C':
173                 flags |= MCACHE;
174                 break;
175         }ARGEND
176
177         if(!(flags & (MAFTER|MBEFORE)))
178                 flags |= MREPL;
179
180         if(strcmp(argv0, ".") == 0 && argc == 1){
181                 b = Bopen(argv[0], OREAD|OCEXEC);
182                 if(b == nil)
183                         return 0;
184                 cdroot |= nsfile(fn, b, rpc);
185                 Bterm(b);
186         }else if(strcmp(argv0, "clear") == 0 && argc == 0){
187                 rfork(RFCNAMEG);
188         }else if(strcmp(argv0, "bind") == 0 && argc == 2){
189                 if(bind(argv[0], argv[1], flags) == -1 && newnsdebug)
190                         fprint(2, "%s: bind: %s %s: %r\n", fn, argv[0], argv[1]);
191         }else if(strcmp(argv0, "unmount") == 0){
192                 if(argc == 1)
193                         unmount(nil, argv[0]);
194                 else if(argc == 2)
195                         unmount(argv[0], argv[1]);
196         }else if(strcmp(argv0, "mount") == 0){
197                 fd = open(argv[0], ORDWR|OCEXEC);
198                 if(fd < 0){
199                         if(newnsdebug)
200                                 fprint(2, "%s: mount: %s: %r\n", fn, argv[0]);
201                         return 0;
202                 }
203                 if(argc == 2){
204                         if(famount(fd, rpc, argv[1], flags, "") == -1 && newnsdebug)
205                                 fprint(2, "%s: mount: %s %s: %r\n", fn, argv[0], argv[1]);
206                 }else if(argc == 3){
207                         if(famount(fd, rpc, argv[1], flags, argv[2]) == -1 && newnsdebug)
208                                 fprint(2, "%s: mount: %s %s %s: %r\n", fn, argv[0], argv[1], argv[2]);
209                 } else {
210                         close(fd);
211                 }
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
222 catch(void *x, char *m)
223 {
224         USED(x);
225         return strncmp(m, wocp, strlen(wocp)) == 0;
226 }
227
228 static char*
229 unquote(char *s)
230 {
231         char *r, *w;
232         int inquote;
233         
234         inquote = 0;
235         for(r=w=s; *r; r++){
236                 if(*r != '\''){
237                         *w++ = *r;
238                         continue;
239                 }
240                 if(inquote){
241                         if(*(r+1) == '\''){
242                                 *w++ = '\'';
243                                 r++;
244                         }else
245                                 inquote = 0;
246                 }else
247                         inquote = 1;
248         }
249         *w = 0;
250         return s;
251 }
252
253 static int
254 splitargs(char *p, char *argv[], char *argbuf, int nargv)
255 {
256         char *q;
257         int i, n;
258
259         n = gettokens(p, argv, nargv, " \t\r");
260         if(n == nargv)
261                 return 0;
262         for(i = 0; i < n; i++){
263                 q = argv[i];
264                 argv[i] = argbuf;
265                 argbuf = expandarg(q, argbuf);
266                 if(argbuf == nil)
267                         return 0;
268                 unquote(argv[i]);
269         }
270         return n;
271 }
272
273 static char*
274 nextdollar(char *arg)
275 {
276         char *p;
277         int inquote;
278         
279         inquote = 0;
280         for(p=arg; *p; p++){
281                 if(*p == '\'')
282                         inquote = !inquote;
283                 if(*p == '$' && !inquote)
284                         return p;
285         }
286         return nil;
287 }
288
289 /*
290  * copy the arg into the buffer,
291  * expanding any environment variables.
292  * environment variables are assumed to be
293  * names (ie. < ANAMELEN long)
294  * the entire argument is expanded to be at
295  * most MAXARG long and null terminated
296  * the address of the byte after the terminating null is returned
297  * any problems cause a 0 return;
298  */
299 static char *
300 expandarg(char *arg, char *buf)
301 {
302         char env[3+ANAMELEN], *p, *x;
303         int fd, n, len;
304
305         n = 0;
306         while(p = nextdollar(arg)){
307                 len = p - arg;
308                 if(n + len + ANAMELEN >= MAXARG-1)
309                         return 0;
310                 memmove(&buf[n], arg, len);
311                 n += len;
312                 p++;
313                 arg = strpbrk(p, "/.!'$");
314                 if(arg == nil)
315                         arg = p+strlen(p);
316                 len = arg - p;
317                 if(len == 0 || len >= ANAMELEN)
318                         continue;
319                 strcpy(env, "#e/");
320                 strncpy(env+3, p, len);
321                 env[3+len] = '\0';
322                 fd = open(env, OREAD|OCEXEC);
323                 if(fd >= 0){
324                         len = read(fd, &buf[n], ANAMELEN - 1);
325                         /* some singleton environment variables have trailing NULs */
326                         /* lists separate entries with NULs; we arbitrarily take the first element */
327                         if(len > 0){
328                                 x = memchr(&buf[n], 0, len);
329                                 if(x != nil)
330                                         len = x - &buf[n];
331                                 n += len;
332                         }
333                         close(fd);
334                 }
335         }
336         len = strlen(arg);
337         if(n + len >= MAXARG - 1)
338                 return 0;
339         strcpy(&buf[n], arg);
340         return &buf[n+len+1];
341 }
342
343 static int
344 setenv(char *name, char *val)
345 {
346         int f;
347         char ename[ANAMELEN+6];
348         long s;
349
350         sprint(ename, "#e/%s", name);
351         f = create(ename, OWRITE|OCEXEC, 0664);
352         if(f < 0)
353                 return -1;
354         s = strlen(val);
355         if(write(f, val, s) != s){
356                 close(f);
357                 return -1;
358         }
359         close(f);
360         return 0;
361 }