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
17 * Only authentication protocol messages go here. Configuration
18 * is still via ctl (below).
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
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]
50 for(i=1; i<nelem(rpcname); i++)
51 if(strcmp(s, rpcname[i]) == 0)
57 rpcwrite(Conv *c, void *data, int count)
63 werrstr("rpc too large");
67 /* cancel any current rpc */
68 c->rpc.op = RpcUnknown;
72 memmove(c->rpcbuf, data, count);
74 if(p = (uchar*)strchr((char*)c->rpcbuf, ' ')){
77 c->rpc.count = count - (p - (uchar*)c->rpcbuf);
82 op = classify(c->rpcbuf);
84 werrstr("bad rpc verb: %s", c->rpcbuf);
102 a = parseattr(c->rpc.data);
104 werrstr("empty attr");
108 proto = strfindattr(a, "proto");
109 role = strfindattr(a, "role");
112 werrstr("no proto in attrs");
116 werrstr("no role in attrs");
120 p = protolookup(proto);
122 werrstr("unknown proto %s", proto);
127 for(r=p->roles; r->name; r++){
128 if(strcmp(r->name, role) != 0)
132 if((*r->fn)(c) == 0){
134 werrstr("protocol finished");
136 werrstr("%s %s %s: %r", p->name, r->name, c->state);
139 werrstr("unknown role");
144 rerrstr(c->err, sizeof c->err);
145 rpcrespond(c, "error %r");
149 static uchar* convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex);
158 if(c->rpc.count > 0){
159 rpcrespond(c, "error read takes no parameters");
166 rpcrespond(c, "done");
168 rpcrespond(c, "error %s", c->err);
171 nbsendp(c->rpcwait, 0);
178 rpcrespond(c, "error conversation still active");
180 rpcrespond(c, "error conversation not successful");
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"));
189 rpcrespond(c, "error %r");
191 rpcrespondn(c, "ok", c->reply+3, p-(uchar*)(c->reply+3));
195 rpcrespond(c, "ok %A", c->attr);
200 threadcreate(convthread, c, STACK);
206 rpcrespond(Conv *c, char *fmt, ...)
217 c->nreply = vsnprint(c->reply, sizeof c->reply, fmt, arg);
220 c->rpc.op = RpcUnknown;
224 rpcrespondn(Conv *c, char *verb, void *data, int count)
231 if(strlen(verb)+1+count > sizeof c->reply){
232 print("RPC response too large; caller %#lux", getcallerpc(&c));
236 strcpy(c->reply, verb);
237 p = c->reply + strlen(c->reply);
239 memmove(p, data, count);
240 c->nreply = count + (p - c->reply);
242 c->rpc.op = RpcUnknown;
247 pstring(uchar *p, uchar *e, char *s)
266 pcarray(uchar *p, uchar *e, uchar *s, uint n)
285 convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *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 */
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);
312 werrstr("authinfo too big");