trpc.c - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       trpc.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 }