rpc.c (6591B)
1 #include "std.h" 2 #include "dat.h" 3 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 */ 34 35 char *rpcname[] = 36 { 37 "unknown", 38 "authinfo", 39 "attr", 40 "read", 41 "start", 42 "write", 43 "readhex", 44 "writehex" 45 }; 46 47 static int 48 classify(char *s) 49 { 50 int i; 51 52 for(i=1; i<nelem(rpcname); i++) 53 if(strcmp(s, rpcname[i]) == 0) 54 return i; 55 return RpcUnknown; 56 } 57 58 int 59 rpcwrite(Conv *c, void *data, int count) 60 { 61 int op; 62 uchar *p; 63 64 if(count >= MaxRpc){ 65 werrstr("rpc too large"); 66 return -1; 67 } 68 69 /* cancel any current rpc */ 70 c->rpc.op = RpcUnknown; 71 c->nreply = 0; 72 73 /* parse new rpc */ 74 memmove(c->rpcbuf, data, count); 75 c->rpcbuf[count] = 0; 76 if(p = (uchar*)strchr((char*)c->rpcbuf, ' ')){ 77 *p++ = '\0'; 78 c->rpc.data = p; 79 c->rpc.count = count - (p - (uchar*)c->rpcbuf); 80 }else{ 81 c->rpc.data = ""; 82 c->rpc.count = 0; 83 } 84 op = classify(c->rpcbuf); 85 if(op == RpcUnknown){ 86 werrstr("bad rpc verb: %s", c->rpcbuf); 87 return -1; 88 } 89 90 c->rpc.op = op; 91 return 0; 92 } 93 94 void 95 convthread(void *v) 96 { 97 Conv *c; 98 Attr *a; 99 char *role, *proto; 100 Proto *p; 101 Role *r; 102 103 c = v; 104 a = parseattr(c->rpc.data); 105 if(a == nil){ 106 werrstr("empty attr"); 107 goto out; 108 } 109 c->attr = a; 110 proto = strfindattr(a, "proto"); 111 if(proto == nil){ 112 werrstr("no proto in attrs"); 113 goto out; 114 } 115 116 p = protolookup(proto); 117 if(p == nil){ 118 werrstr("unknown proto %s", proto); 119 goto out; 120 } 121 c->proto = p; 122 123 role = strfindattr(a, "role"); 124 if(role == nil){ 125 werrstr("no role in attrs"); 126 goto out; 127 } 128 129 for(r=p->roles; r->name; r++){ 130 if(strcmp(r->name, role) != 0) 131 continue; 132 rpcrespond(c, "ok"); 133 c->active = 1; 134 if((*r->fn)(c) == 0){ 135 c->done = 1; 136 werrstr("protocol finished"); 137 }else 138 werrstr("%s %s %s: %r", p->name, r->name, c->state); 139 goto out; 140 } 141 werrstr("unknown role"); 142 143 out: 144 c->active = 0; 145 c->state = 0; 146 rerrstr(c->err, sizeof c->err); 147 rpcrespond(c, "error %r"); 148 convclose(c); 149 } 150 151 static uchar* convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex); 152 153 void 154 rpcexec(Conv *c) 155 { 156 uchar *p; 157 158 c->rpc.hex = 0; 159 switch(c->rpc.op){ 160 case RpcWriteHex: 161 c->rpc.op = RpcWrite; 162 if(dec16(c->rpc.data, c->rpc.count, c->rpc.data, c->rpc.count) != c->rpc.count/2){ 163 rpcrespond(c, "bad hex"); 164 break; 165 } 166 c->rpc.count /= 2; 167 goto Default; 168 case RpcReadHex: 169 c->rpc.hex = 1; 170 c->rpc.op = RpcRead; 171 /* fall through */ 172 case RpcRead: 173 if(c->rpc.count > 0){ 174 rpcrespond(c, "error read takes no parameters"); 175 break; 176 } 177 /* fall through */ 178 default: 179 Default: 180 if(!c->active){ 181 if(c->done) 182 rpcrespond(c, "done"); 183 else 184 rpcrespond(c, "error %s", c->err); 185 break; 186 } 187 nbsendp(c->rpcwait, 0); 188 break; 189 case RpcUnknown: 190 break; 191 case RpcAuthinfo: 192 /* deprecated */ 193 if(c->active) 194 rpcrespond(c, "error conversation still active"); 195 else if(!c->done) 196 rpcrespond(c, "error conversation not successful"); 197 else{ 198 /* make up an auth info using the attr */ 199 p = convAI2M((uchar*)c->reply+3, sizeof c->reply-3, 200 strfindattr(c->attr, "cuid"), 201 strfindattr(c->attr, "suid"), 202 strfindattr(c->attr, "cap"), 203 strfindattr(c->attr, "secret")); 204 if(p == nil) 205 rpcrespond(c, "error %r"); 206 else 207 rpcrespondn(c, "ok", c->reply+3, p-(uchar*)(c->reply+3)); 208 } 209 break; 210 case RpcAttr: 211 rpcrespond(c, "ok %A", c->attr); 212 break; 213 case RpcStart: 214 convreset(c); 215 c->ref++; 216 threadcreate(convthread, c, STACK); 217 break; 218 } 219 } 220 221 void 222 rpcrespond(Conv *c, char *fmt, ...) 223 { 224 va_list arg; 225 226 if(c->hangup) 227 return; 228 229 if(fmt == nil) 230 fmt = ""; 231 232 va_start(arg, fmt); 233 c->nreply = vsnprint(c->reply, sizeof c->reply, fmt, arg); 234 va_end(arg); 235 (*c->kickreply)(c); 236 c->rpc.op = RpcUnknown; 237 } 238 239 void 240 rpcrespondn(Conv *c, char *verb, void *data, int count) 241 { 242 char *p; 243 int need, hex; 244 245 if(c->hangup) 246 return; 247 248 need = strlen(verb)+1+count; 249 hex = 0; 250 if(c->rpc.hex && strcmp(verb, "ok") == 0){ 251 need += count; 252 hex = 1; 253 } 254 if(need > sizeof c->reply){ 255 print("RPC response too large; caller %#lux", getcallerpc(&c)); 256 return; 257 } 258 259 strcpy(c->reply, verb); 260 p = c->reply + strlen(c->reply); 261 *p++ = ' '; 262 if(hex){ 263 enc16(p, 2*count+1, data, count); 264 p += 2*count; 265 }else{ 266 memmove(p, data, count); 267 p += count; 268 } 269 c->nreply = p - c->reply; 270 (*c->kickreply)(c); 271 c->rpc.op = RpcUnknown; 272 } 273 274 /* deprecated */ 275 static uchar* 276 pstring(uchar *p, uchar *e, char *s) 277 { 278 uint n; 279 280 if(p == nil) 281 return nil; 282 if(s == nil) 283 s = ""; 284 n = strlen(s); 285 if(p+n+BIT16SZ >= e) 286 return nil; 287 PBIT16(p, n); 288 p += BIT16SZ; 289 memmove(p, s, n); 290 p += n; 291 return p; 292 } 293 294 static uchar* 295 pcarray(uchar *p, uchar *e, uchar *s, uint n) 296 { 297 if(p == nil) 298 return nil; 299 if(s == nil){ 300 if(n > 0) 301 sysfatal("pcarray"); 302 s = (uchar*)""; 303 } 304 if(p+n+BIT16SZ >= e) 305 return nil; 306 PBIT16(p, n); 307 p += BIT16SZ; 308 memmove(p, s, n); 309 p += n; 310 return p; 311 } 312 313 static uchar* 314 convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex) 315 { 316 uchar *e = p+n; 317 uchar *secret; 318 int nsecret; 319 320 if(cuid == nil) 321 cuid = ""; 322 if(suid == nil) 323 suid = ""; 324 if(cap == nil) 325 cap = ""; 326 if(hex == nil) 327 hex = ""; 328 nsecret = strlen(hex)/2; 329 secret = emalloc(nsecret); 330 if(hexparse(hex, secret, nsecret) < 0){ 331 werrstr("hexparse %s failed", hex); /* can't happen */ 332 free(secret); 333 return nil; 334 } 335 p = pstring(p, e, cuid); 336 p = pstring(p, e, suid); 337 p = pstring(p, e, cap); 338 p = pcarray(p, e, secret, nsecret); 339 free(secret); 340 if(p == nil) 341 werrstr("authinfo too big"); 342 return p; 343 }