tp9cr.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
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 };