Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
7 int debug;
8 char *aname = "";
9 char *keypattern = "";
10 int fd;
11 int msize;
12 int doauth;
13 u32int afid = NOFID;
14 extern char *post9parg; /* clumsy hack */
15 void xauth(void);
16 AuthInfo* xauth_proxy(AuthGetkey *getkey, char *fmt, ...);
18 void
19 usage(void)
20 {
21 fprint(2, "usage: srv [-a] [-A aname] [-k keypattern] addr [srvname]\n");
22 threadexitsall("usage");
23 }
25 void
26 threadmain(int argc, char **argv)
27 {
28 char *addr, *service;
30 fmtinstall('F', fcallfmt);
31 fmtinstall('M', dirmodefmt);
33 ARGBEGIN{
34 case 'D':
35 debug = 1;
36 break;
37 case 'A':
38 /* BUG: should be able to repeat this and establish multiple afids */
39 aname = EARGF(usage());
40 break;
41 case 'a':
42 doauth = 1;
43 break;
44 case 'k':
45 keypattern = EARGF(usage());
46 break;
47 default:
48 usage();
49 }ARGEND
51 if(argc != 1 && argc != 2)
52 usage();
54 addr = netmkaddr(argv[0], "tcp", "9fs");
55 if((fd = dial(addr, nil, nil, nil)) < 0)
56 sysfatal("dial %s: %r", addr);
58 if(doauth)
59 xauth();
61 if(argc == 2)
62 service = argv[1];
63 else
64 service = argv[0];
66 rfork(RFNOTEG);
67 if(post9pservice(fd, service) < 0)
68 sysfatal("post9pservice: %r");
70 threadexitsall(0);
71 }
73 void
74 do9p(Fcall *tx, Fcall *rx)
75 {
76 static uchar buf[9000];
77 static char ebuf[200];
78 int n;
80 n = convS2M(tx, buf, sizeof buf);
81 if(n == BIT16SZ){
82 werrstr("convS2M failed");
83 goto err;
84 }
85 if(debug)
86 fprint(2, "<- %F\n", tx);
87 if(write(fd, buf, n) != n)
88 goto err;
89 if((n = read9pmsg(fd, buf, sizeof buf)) < 0)
90 goto err;
91 if(n == 0){
92 werrstr("unexpected eof");
93 goto err;
94 }
95 if(convM2S(buf, n, rx) != n){
96 werrstr("convM2S failed");
97 goto err;
98 }
99 if(debug)
100 fprint(2, "-> %F\n", rx);
101 if(rx->type != Rerror && rx->type != tx->type+1){
102 werrstr("unexpected type");
103 goto err;
105 if(rx->tag != tx->tag){
106 werrstr("unexpected tag");
107 goto err;
109 return;
111 err:
112 rerrstr(ebuf, sizeof ebuf);
113 rx->ename = ebuf;
114 rx->type = Rerror;
115 return;
118 void
119 xauth(void)
121 Fcall tx, rx;
123 afid = 0;
124 tx.type = Tversion;
125 tx.tag = NOTAG;
126 tx.version = "9P2000";
127 tx.msize = 8192;
128 do9p(&tx, &rx);
129 if(rx.type == Rerror)
130 sysfatal("Tversion: %s", rx.ename);
131 msize = rx.msize;
133 tx.type = Tauth;
134 tx.tag = 1;
135 tx.afid = afid;
136 tx.uname = getuser();
137 tx.aname = aname;
138 do9p(&tx, &rx);
139 if(rx.type == Rerror){
140 fprint(2, "rx: %s\n", rx.ename);
141 afid = NOFID;
142 return;
145 if(xauth_proxy(auth_getkey, "proto=p9any role=client %s", keypattern) == nil)
146 sysfatal("authproxy: %r");
149 int
150 xread(void *buf, int n)
152 Fcall tx, rx;
154 tx.type = Tread;
155 tx.tag = 1;
156 tx.fid = 0; /* afid above */
157 tx.count = n;
158 tx.offset = 0;
159 do9p(&tx, &rx);
160 if(rx.type == Rerror){
161 werrstr("%s", rx.ename);
162 return -1;
165 if(rx.count > n){
166 werrstr("too much data returned");
167 return -1;
169 memmove(buf, rx.data, rx.count);
170 return rx.count;
173 int
174 xwrite(void *buf, int n)
176 Fcall tx, rx;
178 tx.type = Twrite;
179 tx.tag = 1;
180 tx.fid = 0; /* afid above */
181 tx.data = buf;
182 tx.count = n;
183 tx.offset = 0;
184 do9p(&tx, &rx);
185 if(rx.type == Rerror){
186 werrstr("%s", rx.ename);
187 return -1;
189 return n;
193 /*
194 * changed to add -A below
195 */
196 #undef _exits
197 int
198 post9pservice(int fd, char *name)
200 int i;
201 char *ns, *s;
202 Waitmsg *w;
204 if((ns = getns()) == nil)
205 return -1;
207 s = smprint("unix!%s/%s", ns, name);
208 free(ns);
209 if(s == nil)
210 return -1;
211 switch(fork()){
212 case -1:
213 return -1;
214 case 0:
215 dup(fd, 0);
216 dup(fd, 1);
217 for(i=3; i<20; i++)
218 close(i);
219 if(doauth)
220 execlp("9pserve", "9pserve", "-u",
221 "-M",
222 smprint("%d", msize),
223 "-A",
224 aname,
225 smprint("%d", afid),
226 s, (char*)0);
227 else
228 execlp("9pserve", "9pserve", "-u", s, (char*)0);
229 fprint(2, "exec 9pserve: %r\n");
230 _exits("exec");
231 default:
232 w = wait();
233 if(w == nil)
234 return -1;
235 close(fd);
236 free(s);
237 if(w->msg && w->msg[0]){
238 free(w);
239 werrstr("9pserve failed");
240 return -1;
242 free(w);
243 return 0;
247 enum { ARgiveup = 100 };
248 static int
249 dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey)
251 int ret;
253 for(;;){
254 if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey)
255 return ret;
256 if(getkey == nil)
257 return ARgiveup; /* don't know how */
258 if((*getkey)(rpc->arg) < 0)
259 return ARgiveup; /* user punted */
264 /*
265 * this just proxies what the factotum tells it to.
266 */
267 AuthInfo*
268 xfauth_proxy(AuthRpc *rpc, AuthGetkey *getkey, char *params)
270 char *buf;
271 int m, n, ret;
272 AuthInfo *a;
273 char oerr[ERRMAX];
275 rerrstr(oerr, sizeof oerr);
276 werrstr("UNKNOWN AUTH ERROR");
278 if(dorpc(rpc, "start", params, strlen(params), getkey) != ARok){
279 werrstr("fauth_proxy start: %r");
280 return nil;
283 buf = malloc(AuthRpcMax);
284 if(buf == nil)
285 return nil;
286 for(;;){
287 switch(dorpc(rpc, "read", nil, 0, getkey)){
288 case ARdone:
289 free(buf);
290 a = auth_getinfo(rpc);
291 errstr(oerr, sizeof oerr); /* no error, restore whatever was there */
292 return a;
293 case ARok:
294 if(xwrite(rpc->arg, rpc->narg) != rpc->narg){
295 werrstr("auth_proxy write fid: %r");
296 goto Error;
298 break;
299 case ARphase:
300 n = 0;
301 memset(buf, 0, AuthRpcMax);
302 while((ret = dorpc(rpc, "write", buf, n, getkey)) == ARtoosmall){
303 if(atoi(rpc->arg) > AuthRpcMax)
304 break;
305 m = xread(buf+n, atoi(rpc->arg)-n);
306 if(m <= 0){
307 if(m == 0)
308 werrstr("auth_proxy short read: %s", buf);
309 goto Error;
311 n += m;
313 if(ret != ARok){
314 werrstr("auth_proxy rpc write: %s: %r", buf);
315 goto Error;
317 break;
318 default:
319 werrstr("auth_proxy rpc: %r");
320 goto Error;
323 Error:
324 free(buf);
325 return nil;
328 AuthInfo*
329 xauth_proxy(AuthGetkey *getkey, char *fmt, ...)
331 char *p;
332 va_list arg;
333 AuthInfo *ai;
334 AuthRpc *rpc;
336 quotefmtinstall(); /* just in case */
337 va_start(arg, fmt);
338 p = vsmprint(fmt, arg);
339 va_end(arg);
341 rpc = auth_allocrpc();
342 if(rpc == nil){
343 free(p);
344 return nil;
347 ai = xfauth_proxy(rpc, getkey, p);
348 free(p);
349 auth_freerpc(rpc);
350 return ai;