Blob


1 #include "std.h"
2 #include "dat.h"
4 /*
5 * Factotum RPC
6 *
7 * Must be paired write/read cycles on /mnt/factotum/rpc.
8 * The format of a request is verb, single space, data.
9 * Data format is verb-dependent; in particular, it can be binary.
10 * The format of a response is the same. The write only sets up
11 * the RPC. The read tries to execute it. If the /mnt/factotum/key
12 * file is open, we ask for new keys using that instead of returning
13 * an error in the RPC. This means the read blocks.
14 * Textual arguments are parsed with tokenize, so rc-style quoting
15 * rules apply.
16 *
17 * Only authentication protocol messages go here. Configuration
18 * is still via ctl (below).
19 *
20 * Request RPCs are:
21 * start attrs - initializes protocol for authentication, can fail.
22 * returns "ok read" or "ok write" on success.
23 * read - execute protocol read
24 * write - execute protocol write
25 * authinfo - if the protocol is finished, return the AI if any
26 * attr - return protocol information
27 * Return values are:
28 * error message - an error happened.
29 * ok [data] - success, possible data is request dependent.
30 * needkey attrs - request aborted, get me this key and try again
31 * badkey attrs - request aborted, this key might be bad
32 * done [haveai] - authentication is done [haveai: you can get an ai with authinfo]
33 */
35 char *rpcname[] =
36 {
37 "unknown",
38 "authinfo",
39 "attr",
40 "read",
41 "start",
42 "write",
43 };
45 static int
46 classify(char *s)
47 {
48 int i;
50 for(i=1; i<nelem(rpcname); i++)
51 if(strcmp(s, rpcname[i]) == 0)
52 return i;
53 return RpcUnknown;
54 }
56 int
57 rpcwrite(Conv *c, void *data, int count)
58 {
59 int op;
60 uchar *p;
62 if(count >= MaxRpc){
63 werrstr("rpc too large");
64 return -1;
65 }
67 /* cancel any current rpc */
68 c->rpc.op = RpcUnknown;
69 c->nreply = 0;
71 /* parse new rpc */
72 memmove(c->rpcbuf, data, count);
73 c->rpcbuf[count] = 0;
74 if(p = (uchar*)strchr((char*)c->rpcbuf, ' ')){
75 *p++ = '\0';
76 c->rpc.data = p;
77 c->rpc.count = count - (p - (uchar*)c->rpcbuf);
78 }else{
79 c->rpc.data = "";
80 c->rpc.count = 0;
81 }
82 op = classify(c->rpcbuf);
83 if(op == RpcUnknown){
84 werrstr("bad rpc verb: %s", c->rpcbuf);
85 return -1;
86 }
88 c->rpc.op = op;
89 return 0;
90 }
92 void
93 convthread(void *v)
94 {
95 Conv *c;
96 Attr *a;
97 char *role, *proto;
98 Proto *p;
99 Role *r;
101 c = v;
102 a = parseattr(c->rpc.data);
103 if(a == nil){
104 werrstr("empty attr");
105 goto out;
107 c->attr = a;
108 proto = strfindattr(a, "proto");
109 role = strfindattr(a, "role");
111 if(proto == nil){
112 werrstr("no proto in attrs");
113 goto out;
115 if(role == nil){
116 werrstr("no role in attrs");
117 goto out;
120 p = protolookup(proto);
121 if(p == nil){
122 werrstr("unknown proto %s", proto);
123 goto out;
126 c->proto = p;
127 for(r=p->roles; r->name; r++){
128 if(strcmp(r->name, role) != 0)
129 continue;
130 rpcrespond(c, "ok");
131 c->active = 1;
132 if((*r->fn)(c) == 0){
133 c->done = 1;
134 werrstr("protocol finished");
135 }else
136 werrstr("%s %s %s: %r", p->name, r->name, c->state);
137 goto out;
139 werrstr("unknown role");
141 out:
142 c->active = 0;
143 c->state = 0;
144 rerrstr(c->err, sizeof c->err);
145 rpcrespond(c, "error %r");
146 convclose(c);
149 static uchar* convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex);
151 void
152 rpcexec(Conv *c)
154 uchar *p;
156 switch(c->rpc.op){
157 case RpcRead:
158 if(c->rpc.count > 0){
159 rpcrespond(c, "error read takes no parameters");
160 break;
162 /* fall through */
163 default:
164 if(!c->active){
165 if(c->done)
166 rpcrespond(c, "done");
167 else
168 rpcrespond(c, "error %s", c->err);
169 break;
171 nbsendp(c->rpcwait, 0);
172 break;
173 case RpcUnknown:
174 break;
175 case RpcAuthinfo:
176 /* deprecated */
177 if(c->active)
178 rpcrespond(c, "error conversation still active");
179 else if(!c->done)
180 rpcrespond(c, "error conversation not successful");
181 else{
182 /* make up an auth info using the attr */
183 p = convAI2M((uchar*)c->reply+3, sizeof c->reply-3,
184 strfindattr(c->attr, "cuid"),
185 strfindattr(c->attr, "suid"),
186 strfindattr(c->attr, "cap"),
187 strfindattr(c->attr, "secret"));
188 if(p == nil)
189 rpcrespond(c, "error %r");
190 else
191 rpcrespondn(c, "ok", c->reply+3, p-(uchar*)(c->reply+3));
193 break;
194 case RpcAttr:
195 rpcrespond(c, "ok %A", c->attr);
196 break;
197 case RpcStart:
198 convreset(c);
199 c->ref++;
200 threadcreate(convthread, c, STACK);
201 break;
205 void
206 rpcrespond(Conv *c, char *fmt, ...)
208 va_list arg;
210 if(c->hangup)
211 return;
213 if(fmt == nil)
214 fmt = "";
216 va_start(arg, fmt);
217 c->nreply = vsnprint(c->reply, sizeof c->reply, fmt, arg);
218 va_end(arg);
219 (*c->kickreply)(c);
220 c->rpc.op = RpcUnknown;
223 void
224 rpcrespondn(Conv *c, char *verb, void *data, int count)
226 char *p;
228 if(c->hangup)
229 return;
231 if(strlen(verb)+1+count > sizeof c->reply){
232 print("RPC response too large; caller %#lux", getcallerpc(&c));
233 return;
236 strcpy(c->reply, verb);
237 p = c->reply + strlen(c->reply);
238 *p++ = ' ';
239 memmove(p, data, count);
240 c->nreply = count + (p - c->reply);
241 (*c->kickreply)(c);
242 c->rpc.op = RpcUnknown;
245 /* deprecated */
246 static uchar*
247 pstring(uchar *p, uchar *e, char *s)
249 uint n;
251 if(p == nil)
252 return nil;
253 if(s == nil)
254 s = "";
255 n = strlen(s);
256 if(p+n+BIT16SZ >= e)
257 return nil;
258 PBIT16(p, n);
259 p += BIT16SZ;
260 memmove(p, s, n);
261 p += n;
262 return p;
265 static uchar*
266 pcarray(uchar *p, uchar *e, uchar *s, uint n)
268 if(p == nil)
269 return nil;
270 if(s == nil){
271 if(n > 0)
272 sysfatal("pcarray");
273 s = (uchar*)"";
275 if(p+n+BIT16SZ >= e)
276 return nil;
277 PBIT16(p, n);
278 p += BIT16SZ;
279 memmove(p, s, n);
280 p += n;
281 return p;
284 static uchar*
285 convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex)
287 uchar *e = p+n;
288 uchar *secret;
289 int nsecret;
291 if(cuid == nil)
292 cuid = "";
293 if(suid == nil)
294 suid = "";
295 if(cap == nil)
296 cap = "";
297 if(hex == nil)
298 hex = "";
299 nsecret = strlen(hex)/2;
300 secret = emalloc(nsecret);
301 if(hexparse(hex, secret, nsecret) < 0){
302 werrstr("hexparse %s failed", hex); /* can't happen */
303 free(secret);
304 return nil;
306 p = pstring(p, e, cuid);
307 p = pstring(p, e, suid);
308 p = pstring(p, e, cap);
309 p = pcarray(p, e, secret, nsecret);
310 free(secret);
311 if(p == nil)
312 werrstr("authinfo too big");
313 return p;