URI:
       tsecureidcheck.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
       ---
       tsecureidcheck.c (9068B)
       ---
            1 /* RFC2138 */
            2 #include <u.h>
            3 #include <libc.h>
            4 #include <ip.h>
            5 #include <ctype.h>
            6 #include <mp.h>
            7 #include <libsec.h>
            8 #include <bio.h>
            9 #include <ndb.h>
           10 #define AUTHLOG "auth"
           11 
           12 enum{        R_AccessRequest=1,        /* Packet code */
           13         R_AccessAccept=2,
           14         R_AccessReject=3,
           15         R_AccessChallenge=11,
           16         R_UserName=1,
           17         R_UserPassword=2,
           18         R_NASIPAddress=4,
           19         R_ReplyMessage=18,
           20         R_State=24,
           21         R_NASIdentifier=32
           22 };
           23 
           24 typedef struct Secret{
           25         uchar *s;
           26         int len;
           27 } Secret;
           28 
           29 typedef struct Attribute{
           30         struct Attribute *next;
           31         uchar type;
           32         uchar len;        /* number of bytes in value */
           33         uchar val[256];
           34 } Attribute;
           35 
           36 typedef struct Packet{
           37         uchar code, ID;
           38         uchar authenticator[16];
           39         Attribute first;
           40 } Packet;
           41 
           42 /* assumes pass is at most 16 chars */
           43 void
           44 hide(Secret *shared, uchar *auth, Secret *pass, uchar *x)
           45 {
           46         DigestState *M;
           47         int i, n = pass->len;
           48 
           49         M = md5(shared->s, shared->len, nil, nil);
           50         md5(auth, 16, x, M);
           51         if(n > 16)
           52                 n = 16;
           53         for(i = 0; i < n; i++)
           54                 x[i] ^= (pass->s)[i];
           55 }
           56 
           57 int
           58 authcmp(Secret *shared, uchar *buf, int m, uchar *auth)
           59 {
           60         DigestState *M;
           61         uchar x[16];
           62 
           63         M = md5(buf, 4, nil, nil); /* Code+ID+Length */
           64         M = md5(auth, 16, nil, M); /* RequestAuth */
           65         M = md5(buf+20, m-20, nil, M); /* Attributes */
           66         md5(shared->s, shared->len, x, M);
           67         return memcmp(x, buf+4, 16);
           68 }
           69 
           70 Packet*
           71 newRequest(uchar *auth)
           72 {
           73         static uchar ID = 0;
           74         Packet *p;
           75 
           76         p = (Packet*)malloc(sizeof(*p));
           77         if(p == nil)
           78                 return nil;
           79         p->code = R_AccessRequest;
           80         p->ID = ++ID;
           81         memmove(p->authenticator, auth, 16);
           82         p->first.next = nil;
           83         p->first.type = 0;
           84         return p;
           85 }
           86 
           87 void
           88 freePacket(Packet *p)
           89 {
           90         Attribute *a, *x;
           91 
           92         if(!p)
           93                 return;
           94         a = p->first.next;
           95         while(a){
           96                 x = a;
           97                 a = a->next;
           98                 free(x);
           99         }
          100         free(p);
          101 }
          102 
          103 int
          104 ding(void *v, char *msg)
          105 {
          106         USED(v);
          107 /*        syslog(0, AUTHLOG, "ding %s", msg); */
          108         if(strstr(msg, "alarm"))
          109                 return 1;
          110         return 0;
          111 }
          112 
          113 Packet *
          114 rpc(char *dest, Secret *shared, Packet *req)
          115 {
          116         uchar buf[4096], buf2[4096], *b, *e;
          117         Packet *resp;
          118         Attribute *a;
          119         int m, n, fd, try;
          120 
          121         /* marshal request */
          122         e = buf + sizeof buf;
          123         buf[0] = req->code;
          124         buf[1] = req->ID;
          125         memmove(buf+4, req->authenticator, 16);
          126         b = buf+20;
          127         for(a = &req->first; a; a = a->next){
          128                 if(b + 2 + a->len > e)
          129                         return nil;
          130                 *b++ = a->type;
          131                 *b++ = 2 + a->len;
          132                 memmove(b, a->val, a->len);
          133                 b += a->len;
          134         }
          135         n = b-buf;
          136         buf[2] = n>>8;
          137         buf[3] = n;
          138 
          139         /* send request, wait for reply */
          140         fd = dial(dest, 0, 0, 0);
          141         if(fd < 0){
          142                 syslog(0, AUTHLOG, "%s: rpc can't get udp channel", dest);
          143                 return nil;
          144         }
          145         atnotify(ding, 1);
          146         m = -1;
          147         for(try = 0; try < 2; try++){
          148                 alarm(4000);
          149                 m = write(fd, buf, n);
          150                 if(m != n){
          151                         syslog(0, AUTHLOG, "%s: rpc write err %d %d: %r", dest, m, n);
          152                         m = -1;
          153                         break;
          154                 }
          155                 m = read(fd, buf2, sizeof buf2);
          156                 alarm(0);
          157                 if(m < 0){
          158                         syslog(0, AUTHLOG, "%s rpc read err %d: %r", dest, m);
          159                         break; /* failure */
          160                 }
          161                 if(m == 0 || buf2[1] != buf[1]){  /* need matching ID */
          162                         syslog(0, AUTHLOG, "%s unmatched reply %d", dest, m);
          163                         continue;
          164                 }
          165                 if(authcmp(shared, buf2, m, buf+4) == 0)
          166                         break;
          167                 syslog(0, AUTHLOG, "%s bad rpc chksum", dest);
          168         }
          169         close(fd);
          170         if(m <= 0)
          171                 return nil;
          172 
          173         /* unmarshal reply */
          174         b = buf2;
          175         e = buf2+m;
          176         resp = (Packet*)malloc(sizeof(*resp));
          177         if(resp == nil)
          178                 return nil;
          179         resp->code = *b++;
          180         resp->ID = *b++;
          181         n = *b++;
          182         n = (n<<8) | *b++;
          183         if(m != n){
          184                 syslog(0, AUTHLOG, "rpc got %d bytes, length said %d", m, n);
          185                 if(m > n)
          186                         e = buf2+n;
          187         }
          188         memmove(resp->authenticator, b, 16);
          189         b += 16;
          190         a = &resp->first;
          191         a->type = 0;
          192         while(1){
          193                 if(b >= e){
          194                         a->next = nil;
          195                         break;                        /* exit loop */
          196                 }
          197                 a->type = *b++;
          198                 a->len = (*b++) - 2;
          199                 if(b + a->len > e){ /* corrupt packet */
          200                         a->next = nil;
          201                         freePacket(resp);
          202                         return nil;
          203                 }
          204                 memmove(a->val, b, a->len);
          205                 b += a->len;
          206                 if(b < e){  /* any more attributes? */
          207                         a->next = (Attribute*)malloc(sizeof(*a));
          208                         if(a->next == nil){
          209                                 free(req);
          210                                 return nil;
          211                         }
          212                         a = a->next;
          213                 }
          214         }
          215         return resp;
          216 }
          217 
          218 int
          219 setAttribute(Packet *p, uchar type, uchar *s, int n)
          220 {
          221         Attribute *a;
          222 
          223         a = &p->first;
          224         if(a->type != 0){
          225                 a = (Attribute*)malloc(sizeof(*a));
          226                 if(a == nil)
          227                         return -1;
          228                 a->next = p->first.next;
          229                 p->first.next = a;
          230         }
          231         a->type = type;
          232         a->len = n;
          233         if(a->len > 253 )  /* RFC2138, section 5 */
          234                 a->len = 253;
          235         memmove(a->val, s, a->len);
          236         return 0;
          237 }
          238 
          239 /* return a reply message attribute string */
          240 char*
          241 replymsg(Packet *p)
          242 {
          243         Attribute *a;
          244         static char buf[255];
          245 
          246         for(a = &p->first; a; a = a->next){
          247                 if(a->type == R_ReplyMessage){
          248                         if(a->len >= sizeof buf)
          249                                 a->len = sizeof(buf)-1;
          250                         memmove(buf, a->val, a->len);
          251                         buf[a->len] = 0;
          252                 }
          253         }
          254         return buf;
          255 }
          256 
          257 /* for convenience while debugging */
          258 char *replymess;
          259 Attribute *stateattr;
          260 
          261 void
          262 logPacket(Packet *p)
          263 {
          264         Attribute *a;
          265         char buf[255];
          266         char pbuf[4*1024];
          267         uchar *au = p->authenticator;
          268         int i;
          269         char *np, *e;
          270 
          271         e = pbuf + sizeof(pbuf);
          272 
          273         np = seprint(pbuf, e, "Packet ID=%d auth=%x %x %x... ", p->ID, au[0], au[1], au[2]);
          274         switch(p->code){
          275         case R_AccessRequest:
          276                 np = seprint(np, e, "request\n");
          277                 break;
          278         case R_AccessAccept:
          279                 np = seprint(np, e, "accept\n");
          280                 break;
          281         case R_AccessReject:
          282                 np = seprint(np, e, "reject\n");
          283                 break;
          284         case R_AccessChallenge:
          285                 np = seprint(np, e, "challenge\n");
          286                 break;
          287         default:
          288                 np = seprint(np, e, "code=%d\n", p->code);
          289                 break;
          290         }
          291         replymess = "0000000";
          292         for(a = &p->first; a; a = a->next){
          293                 if(a->len > 253 )
          294                         a->len = 253;
          295                 memmove(buf, a->val, a->len);
          296                 np = seprint(np, e, " [%d]", a->type);
          297                 for(i = 0; i<a->len; i++)
          298                         if(isprint(a->val[i]))
          299                                 np = seprint(np, e, "%c", a->val[i]);
          300                         else
          301                                 np = seprint(np, e, "\\%o", a->val[i]);
          302                 np = seprint(np, e, "\n");
          303                 buf[a->len] = 0;
          304                 if(a->type == R_ReplyMessage)
          305                         replymess = strdup(buf);
          306                 else if(a->type == R_State)
          307                         stateattr = a;
          308         }
          309 
          310         syslog(0, AUTHLOG, "%s", pbuf);
          311 }
          312 
          313 static uchar*
          314 getipv4addr(void)
          315 {
          316         Ipifc *nifc;
          317         Iplifc *lifc;
          318         static Ipifc *ifc;
          319 
          320         ifc = readipifc("/net", ifc, -1);
          321         for(nifc = ifc; nifc; nifc = nifc->next)
          322                 for(lifc = nifc->lifc; lifc; lifc = lifc->next)
          323                         if(ipcmp(lifc->ip, IPnoaddr) != 0 && ipcmp(lifc->ip, v4prefix) != 0)
          324                                 return lifc->ip;
          325         return nil;
          326 }
          327 
          328 extern Ndb *db;
          329 
          330 /* returns 0 on success, error message on failure */
          331 char*
          332 secureidcheck(char *user, char *response)
          333 {
          334         Packet *req = nil, *resp = nil;
          335         ulong u[4];
          336         uchar x[16];
          337         char *radiussecret;
          338         char ruser[ 64];
          339         char dest[3*IPaddrlen+20];
          340         Secret shared, pass;
          341         char *rv = "authentication failed";
          342         Ndbs s;
          343         Ndbtuple *t, *nt, *tt;
          344         uchar *ip;
          345         static Ndb *netdb;
          346 
          347         if(netdb == nil)
          348                 netdb = ndbopen(0);
          349 
          350         /* bad responses make them disable the fob, avoid silly checks */
          351         if(strlen(response) < 4 || strpbrk(response,"abcdefABCDEF") != nil)
          352                 goto out;
          353 
          354         /* get radius secret */
          355         radiussecret = ndbgetvalue(db, &s, "radius", "lra-radius", "secret", &t);
          356         if(radiussecret == nil){
          357                 syslog(0, AUTHLOG, "secureidcheck: nil radius secret: %r");
          358                 goto out;
          359         }
          360 
          361         /* translate user name if we have to */
          362         strcpy(ruser, user);
          363         for(nt = t; nt; nt = nt->entry){
          364                 if(strcmp(nt->attr, "uid") == 0 && strcmp(nt->val, user) == 0)
          365                         for(tt = nt->line; tt != nt; tt = tt->line)
          366                                 if(strcmp(tt->attr, "rid") == 0){
          367                                         strcpy(ruser, tt->val);
          368                                         break;
          369                                 }
          370         }
          371         ndbfree(t);
          372 
          373         u[0] = fastrand();
          374         u[1] = fastrand();
          375         u[2] = fastrand();
          376         u[3] = fastrand();
          377         req = newRequest((uchar*)u);
          378         if(req == nil)
          379                 goto out;
          380         shared.s = (uchar*)radiussecret;
          381         shared.len = strlen(radiussecret);
          382         ip = getipv4addr();
          383         if(ip == nil){
          384                 syslog(0, AUTHLOG, "no interfaces: %r\n");
          385                 goto out;
          386         }
          387         if(setAttribute(req, R_NASIPAddress, ip + IPv4off, 4) < 0)
          388                 goto out;
          389 
          390         if(setAttribute(req, R_UserName, (uchar*)ruser, strlen(ruser)) < 0)
          391                 goto out;
          392         pass.s = (uchar*)response;
          393         pass.len = strlen(response);
          394         hide(&shared, req->authenticator, &pass, x);
          395         if(setAttribute(req, R_UserPassword, x, 16) < 0)
          396                 goto out;
          397 
          398         t = ndbsearch(netdb, &s, "sys", "lra-radius");
          399         if(t == nil){
          400                 syslog(0, AUTHLOG, "secureidcheck: nil radius sys search: %r\n");
          401                 goto out;
          402         }
          403         for(nt = t; nt; nt = nt->entry){
          404                 if(strcmp(nt->attr, "ip") != 0)
          405                         continue;
          406 
          407                 snprint(dest,sizeof dest,"udp!%s!oradius", nt->val);
          408                 resp = rpc(dest, &shared, req);
          409                 if(resp == nil){
          410                         syslog(0, AUTHLOG, "%s nil response", dest);
          411                         continue;
          412                 }
          413                 if(resp->ID != req->ID){
          414                         syslog(0, AUTHLOG, "%s mismatched ID  req=%d resp=%d",
          415                                 dest, req->ID, resp->ID);
          416                         freePacket(resp);
          417                         resp = nil;
          418                         continue;
          419                 }
          420 
          421                 switch(resp->code){
          422                 case R_AccessAccept:
          423                         syslog(0, AUTHLOG, "%s accepted ruser=%s", dest, ruser);
          424                         rv = nil;
          425                         break;
          426                 case R_AccessReject:
          427                         syslog(0, AUTHLOG, "%s rejected ruser=%s %s", dest, ruser, replymsg(resp));
          428                         rv = "secureid failed";
          429                         break;
          430                 case R_AccessChallenge:
          431                         syslog(0, AUTHLOG, "%s challenge ruser=%s %s", dest, ruser, replymsg(resp));
          432                         rv = "secureid out of sync";
          433                         break;
          434                 default:
          435                         syslog(0, AUTHLOG, "%s code=%d ruser=%s %s", dest, resp->code, ruser, replymsg(resp));
          436                         break;
          437                 }
          438                 break; /* we have a proper reply, no need to ask again */
          439         }
          440         ndbfree(t);
          441         free(radiussecret);
          442 out:
          443         freePacket(req);
          444         freePacket(resp);
          445         return rv;
          446 }