URI: 
       tp9cr.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tp9cr.c (6981B)
       ---
            1 /*
            2  * p9cr - one-sided challenge/response authentication
            3  *
            4  * Protocol:
            5  *
            6  *        C -> S: user
            7  *        S -> C: challenge
            8  *        C -> S: response
            9  *        S -> C: ok or bad
           10  *
           11  * Note that this is the protocol between factotum and the local
           12  * program, not between the two factotums.  The information
           13  * exchanged here is wrapped in other protocols by the local
           14  * programs.
           15  */
           16 
           17 #include "std.h"
           18 #include "dat.h"
           19 
           20 /* shared with auth dialing routines */
           21 typedef struct ServerState ServerState;
           22 struct ServerState
           23 {
           24         int asfd;
           25         Key *k;
           26         Ticketreq tr;
           27         Ticket t;
           28         char *dom;
           29         char *hostid;
           30 };
           31 
           32 enum
           33 {
           34         MAXCHAL = 64,
           35         MAXRESP = 64,
           36 };
           37 
           38 extern Proto p9cr, vnc;
           39 static int p9response(char*, uchar*, uchar*);
           40 // static int vncresponse(char*, uchar*, uchar*);
           41 static int p9crchal(ServerState *s, int, char*, uchar*, int);
           42 static int p9crresp(ServerState*, uchar*, int);
           43 
           44 static int
           45 p9crcheck(Key *k)
           46 {
           47         if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){
           48                 werrstr("need user and !password attributes");
           49                 return -1;
           50         }
           51         return 0;
           52 }
           53 
           54 static int
           55 p9crclient(Conv *c)
           56 {
           57         char *pw, *res, *user;
           58         int astype, challen, resplen, ntry, ret;
           59         Attr *attr;
           60         Key *k;
           61         uchar chal[MAXCHAL+1], resp[MAXRESP];
           62         int (*response)(char*, uchar*, uchar*);
           63 
           64         k = nil;
           65         res = nil;
           66         ret = -1;
           67         attr = c->attr;
           68         astype = -1;
           69 
           70         if(c->proto == &p9cr){
           71                 astype = AuthChal;
           72                 challen = NETCHLEN;
           73                 response = p9response;
           74                 attr = _mkattr(AttrNameval, "proto", "p9sk1", _delattr(_copyattr(attr), "proto"));
           75         }else if(c->proto == &vnc){
           76                 astype = AuthVNC;
           77                 challen = MAXCHAL;
           78         //        response = vncresponse;
           79                 werrstr("no vnc");
           80                 goto out;
           81         }else{
           82                 werrstr("bad proto");
           83                 goto out;
           84         }
           85 
           86         c->state = "find key";
           87         k = keyfetch(c, "%A %s", attr, c->proto->keyprompt);
           88         if(k == nil)
           89                 goto out;
           90 
           91         for(ntry=1;; ntry++){
           92                 if(c->attr != attr)
           93                         freeattr(c->attr);
           94                 c->attr = addattrs(copyattr(attr), k->attr);
           95 
           96                 if((pw = strfindattr(k->privattr, "!password")) == nil){
           97                         werrstr("key has no !password (cannot happen)");
           98                         goto out;
           99                 }
          100                 if((user = strfindattr(k->attr, "user")) == nil){
          101                         werrstr("key has no user (cannot happen)");
          102                         goto out;
          103                 }
          104 
          105                 if(convprint(c, "%s", user) < 0)
          106                         goto out;
          107 
          108                 if(convread(c, chal, challen) < 0)
          109                         goto out;
          110                 chal[challen] = 0;
          111 
          112                 if((resplen = (*response)(pw, chal, resp)) < 0)
          113                         goto out;
          114 
          115                 if(convwrite(c, resp, resplen) < 0)
          116                         goto out;
          117 
          118                 if(convreadm(c, &res) < 0)
          119                         goto out;
          120 
          121                 if(strcmp(res, "ok") == 0)
          122                         break;
          123 
          124                 if((k = keyreplace(c, k, "%s", res)) == nil){
          125                         c->state = "auth failed";
          126                         werrstr("%s", res);
          127                         goto out;
          128                 }
          129         }
          130 
          131         werrstr("succeeded");
          132         ret = 0;
          133 
          134 out:
          135         USED(astype);
          136         keyclose(k);
          137         if(c->attr != attr)
          138                 freeattr(attr);
          139         return ret;
          140 }
          141 
          142 static int
          143 p9crserver(Conv *c)
          144 {
          145         uchar chal[MAXCHAL], *resp, *resp1;
          146         char *user;
          147         ServerState s;
          148         int astype, ret, challen, resplen;
          149         Attr *a;
          150 
          151         ret = -1;
          152         user = nil;
          153         resp = nil;
          154         memset(&s, 0, sizeof s);
          155         s.asfd = -1;
          156 
          157         if(c->proto == &p9cr){
          158                 astype = AuthChal;
          159                 challen = NETCHLEN;
          160         }else if(c->proto == &vnc){
          161                 challen = MAXCHAL;
          162         }else{
          163                 werrstr("bad proto");
          164                 goto out;
          165         }
          166 
          167         c->state = "find key";
          168         if((s.k = plan9authkey(c->attr)) == nil)
          169                 goto out;
          170 
          171         a = copyattr(s.k->attr);
          172         a = delattr(a, "proto");
          173         c->attr = addattrs(c->attr, a);
          174         freeattr(a);
          175 
          176         c->state = "authdial";
          177         s.hostid = strfindattr(s.k->attr, "user");
          178         s.dom = strfindattr(s.k->attr, "dom");
          179         if((s.asfd = xioauthdial(nil, s.dom)) < 0){
          180                 werrstr("authdial %s: %r", s.dom);
          181                 goto out;
          182         }
          183 
          184         for(;;){
          185                 c->state = "read user";
          186                 if(convreadm(c, &user) < 0)
          187                         goto out;
          188 
          189                 c->state = "authchal";
          190                 if(p9crchal(&s, astype, user, chal, challen) < 0)
          191                         goto out;
          192 
          193                 c->state = "write challenge";
          194                 if(convwrite(c, chal, challen) < 0)
          195                         goto out;
          196 
          197                 c->state = "read response";
          198                 if((resplen = convreadm(c, (char**)(void*)&resp)) < 0)
          199                         goto out;
          200                 if(c->proto == &p9cr){
          201                         if(resplen > NETCHLEN){
          202                                 convprint(c, "bad response too long");
          203                                 goto out;
          204                         }
          205                         resp1 = emalloc(NETCHLEN);
          206                         memset(resp1, 0, NETCHLEN);
          207                         memmove(resp1, resp, resplen);
          208                         free(resp);
          209                         resp = resp1;
          210                         resplen = NETCHLEN;
          211                 }
          212 
          213                 c->state = "authwrite";
          214                 switch(p9crresp(&s, resp, resplen)){
          215                 case -1:
          216                         fprint(2, "p9crresp: %r\n");
          217                         goto out;
          218                 case 0:
          219                         c->state = "write status";
          220                         if(convprint(c, "bad authentication failed") < 0)
          221                                 goto out;
          222                         break;
          223                 case 1:
          224                         c->state = "write status";
          225                         if(convprint(c, "ok") < 0)
          226                                 goto out;
          227                         goto ok;
          228                 }
          229                 free(user);
          230                 free(resp);
          231                 user = nil;
          232                 resp = nil;
          233         }
          234 
          235 ok:
          236         ret = 0;
          237         c->attr = addcap(c->attr, c->sysuser, &s.t);
          238 
          239 out:
          240         keyclose(s.k);
          241         free(user);
          242         free(resp);
          243         xioclose(s.asfd);
          244         return ret;
          245 }
          246 
          247 static int
          248 p9crchal(ServerState *s, int astype, char *user, uchar *chal, int challen)
          249 {
          250         char trbuf[TICKREQLEN];
          251         Ticketreq tr;
          252         int n;
          253 
          254         memset(&tr, 0, sizeof tr);
          255 
          256         tr.type = astype;
          257 
          258         if(strlen(s->hostid) >= sizeof tr.hostid){
          259                 werrstr("hostid too long");
          260                 return -1;
          261         }
          262         strcpy(tr.hostid, s->hostid);
          263 
          264         if(strlen(s->dom) >= sizeof tr.authdom){
          265                 werrstr("domain too long");
          266                 return -1;
          267         }
          268         strcpy(tr.authdom, s->dom);
          269 
          270         if(strlen(user) >= sizeof tr.uid){
          271                 werrstr("user name too long");
          272                 return -1;
          273         }
          274         strcpy(tr.uid, user);
          275         convTR2M(&tr, trbuf);
          276 
          277         if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
          278                 return -1;
          279 
          280         if((n=xioasrdresp(s->asfd, chal, challen)) <= 0)
          281                 return -1;
          282         return n;
          283 }
          284 
          285 static int
          286 p9crresp(ServerState *s, uchar *resp, int resplen)
          287 {
          288         char tabuf[TICKETLEN+AUTHENTLEN];
          289         Authenticator a;
          290         Ticket t;
          291         Ticketreq tr;
          292 
          293         memset(&tr, 0, sizeof tr);        // TODO: what should tr be initialized to?
          294 
          295         if(xiowrite(s->asfd, resp, resplen) != resplen)
          296                 return -1;
          297 
          298         if(xioasrdresp(s->asfd, tabuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
          299                 return 0;
          300 
          301         convM2T(tabuf, &t, s->k->priv);
          302         if(t.num != AuthTs
          303         || memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
          304                 werrstr("key mismatch with auth server");
          305                 return -1;
          306         }
          307 
          308         convM2A(tabuf+TICKETLEN, &a, t.key);
          309         if(a.num != AuthAc
          310         || memcmp(a.chal, tr.chal, sizeof a.chal) != 0
          311         || a.id != 0){
          312                 werrstr("key2 mismatch with auth server");
          313                 return -1;
          314         }
          315 
          316         s->t = t;
          317         return 1;
          318 }
          319 
          320 static int
          321 p9response(char *pw, uchar *chal, uchar *resp)
          322 {
          323         char key[DESKEYLEN];
          324         uchar buf[8];
          325         ulong x;
          326 
          327         passtokey(key, pw);
          328         memset(buf, 0, 8);
          329         snprint((char*)buf, sizeof buf, "%d", atoi((char*)chal));
          330         if(encrypt(key, buf, 8) < 0){
          331                 werrstr("can't encrypt response");
          332                 return -1;
          333         }
          334         x = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
          335         return snprint((char*)resp, MAXRESP, "%.8lux", x);
          336 }
          337 
          338 /*
          339 static int
          340 vncresponse(char *pw, uchar *chal, uchar *resp)
          341 {
          342         DESstate des;
          343 
          344         memmove(resp, chal, MAXCHAL);
          345         setupDESstate(&des, 0, nil);  // XXX put key in for 0
          346         desECBencrypt(resp, MAXCHAL, &des);
          347         return MAXCHAL;
          348 }
          349 */
          350 
          351 static Role
          352 p9crroles[] =
          353 {
          354         "client", p9crclient,
          355         "server", p9crserver,
          356         0
          357 };
          358 
          359 Proto p9cr = {
          360         "p9cr",
          361         p9crroles,
          362         "user? !password?",
          363         p9crcheck,
          364         nil
          365 };
          366 
          367 /* still need to implement vnc key generator */
          368 Proto vnc = {
          369         "vnc",
          370         p9crroles,
          371         "user? !password?",
          372         p9crcheck,
          373         nil
          374 };