1d04cc87cSDavid du Colombier /*
2*7c70c028SDavid du Colombier * This code uses RADIUS as a portable way to validate tokens such as SecurID.
3*7c70c028SDavid du Colombier * It is relatively simple to send a UDP packet and get a response, but various
4*7c70c028SDavid du Colombier * things can go wrong. Speaking the proprietary ACE protocol would allow
5*7c70c028SDavid du Colombier * handling "next token code" and other error messages. More importantly, the
6*7c70c028SDavid du Colombier * timeout threshold is inherently hard to pick. We observe responses taking
7*7c70c028SDavid du Colombier * longer than 10 seconds in normal times. That is a long time to wait before
8*7c70c028SDavid du Colombier * retrying on a second server. Moreover, if the UDP response is lost, retrying
9*7c70c028SDavid du Colombier * on a second server will also fail because the valid token code may be
10*7c70c028SDavid du Colombier * presented only once. This whole approach is flawed, but best we can do.
11d04cc87cSDavid du Colombier */
127dd7cddfSDavid du Colombier /* RFC2138 */
137dd7cddfSDavid du Colombier #include <u.h>
147dd7cddfSDavid du Colombier #include <libc.h>
157dd7cddfSDavid du Colombier #include <ip.h>
167dd7cddfSDavid du Colombier #include <ctype.h>
177dd7cddfSDavid du Colombier #include <mp.h>
187dd7cddfSDavid du Colombier #include <libsec.h>
197dd7cddfSDavid du Colombier #include <bio.h>
207dd7cddfSDavid du Colombier #include <ndb.h>
21*7c70c028SDavid du Colombier
229a747e4fSDavid du Colombier #define AUTHLOG "auth"
237dd7cddfSDavid du Colombier
24*7c70c028SDavid du Colombier enum{
25*7c70c028SDavid du Colombier R_AccessRequest =1, /* Packet code */
267dd7cddfSDavid du Colombier R_AccessAccept =2,
277dd7cddfSDavid du Colombier R_AccessReject =3,
287dd7cddfSDavid du Colombier R_AccessChallenge=11,
297dd7cddfSDavid du Colombier R_UserName =1,
307dd7cddfSDavid du Colombier R_UserPassword =2,
317dd7cddfSDavid du Colombier R_NASIPAddress =4,
327dd7cddfSDavid du Colombier R_ReplyMessage =18,
337dd7cddfSDavid du Colombier R_State =24,
34*7c70c028SDavid du Colombier R_NASIdentifier =32,
357dd7cddfSDavid du Colombier };
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier typedef struct Secret{
387dd7cddfSDavid du Colombier uchar *s;
397dd7cddfSDavid du Colombier int len;
407dd7cddfSDavid du Colombier } Secret;
417dd7cddfSDavid du Colombier
427dd7cddfSDavid du Colombier typedef struct Attribute{
437dd7cddfSDavid du Colombier struct Attribute *next;
447dd7cddfSDavid du Colombier uchar type;
45*7c70c028SDavid du Colombier uchar len; /* number of bytes in value */
467dd7cddfSDavid du Colombier uchar val[256];
477dd7cddfSDavid du Colombier } Attribute;
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier typedef struct Packet{
507dd7cddfSDavid du Colombier uchar code, ID;
517dd7cddfSDavid du Colombier uchar authenticator[16];
527dd7cddfSDavid du Colombier Attribute first;
537dd7cddfSDavid du Colombier } Packet;
547dd7cddfSDavid du Colombier
55*7c70c028SDavid du Colombier /* assumes pass is at most 16 chars */
567dd7cddfSDavid du Colombier void
hide(Secret * shared,uchar * auth,Secret * pass,uchar * x)577dd7cddfSDavid du Colombier hide(Secret *shared, uchar *auth, Secret *pass, uchar *x)
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier DigestState *M;
607dd7cddfSDavid du Colombier int i, n = pass->len;
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier M = md5(shared->s, shared->len, nil, nil);
637dd7cddfSDavid du Colombier md5(auth, 16, x, M);
647dd7cddfSDavid du Colombier if(n > 16)
657dd7cddfSDavid du Colombier n = 16;
667dd7cddfSDavid du Colombier for(i = 0; i < n; i++)
67*7c70c028SDavid du Colombier x[i] ^= pass->s[i];
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier int
authcmp(Secret * shared,uchar * buf,int m,uchar * auth)717dd7cddfSDavid du Colombier authcmp(Secret *shared, uchar *buf, int m, uchar *auth)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier DigestState *M;
747dd7cddfSDavid du Colombier uchar x[16];
757dd7cddfSDavid du Colombier
76*7c70c028SDavid du Colombier M = md5(buf, 4, nil, nil); /* Code+ID+Length */
77*7c70c028SDavid du Colombier M = md5(auth, 16, nil, M); /* RequestAuth */
78*7c70c028SDavid du Colombier M = md5(buf+20, m-20, nil, M); /* Attributes */
797dd7cddfSDavid du Colombier md5(shared->s, shared->len, x, M);
807dd7cddfSDavid du Colombier return memcmp(x, buf+4, 16);
817dd7cddfSDavid du Colombier }
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier Packet*
newRequest(uchar * auth)847dd7cddfSDavid du Colombier newRequest(uchar *auth)
857dd7cddfSDavid du Colombier {
867dd7cddfSDavid du Colombier static uchar ID = 0;
877dd7cddfSDavid du Colombier Packet *p;
887dd7cddfSDavid du Colombier
897dd7cddfSDavid du Colombier p = (Packet*)malloc(sizeof(*p));
907dd7cddfSDavid du Colombier if(p == nil)
917dd7cddfSDavid du Colombier return nil;
927dd7cddfSDavid du Colombier p->code = R_AccessRequest;
937dd7cddfSDavid du Colombier p->ID = ++ID;
947dd7cddfSDavid du Colombier memmove(p->authenticator, auth, 16);
957dd7cddfSDavid du Colombier p->first.next = nil;
967dd7cddfSDavid du Colombier p->first.type = 0;
977dd7cddfSDavid du Colombier return p;
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier
1007dd7cddfSDavid du Colombier void
freePacket(Packet * p)1017dd7cddfSDavid du Colombier freePacket(Packet *p)
1027dd7cddfSDavid du Colombier {
1037dd7cddfSDavid du Colombier Attribute *a, *x;
1047dd7cddfSDavid du Colombier
10580ee5cbfSDavid du Colombier if(!p)
10680ee5cbfSDavid du Colombier return;
1077dd7cddfSDavid du Colombier a = p->first.next;
1087dd7cddfSDavid du Colombier while(a){
1097dd7cddfSDavid du Colombier x = a;
1107dd7cddfSDavid du Colombier a = a->next;
1117dd7cddfSDavid du Colombier free(x);
1127dd7cddfSDavid du Colombier }
1137dd7cddfSDavid du Colombier free(p);
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier int
ding(void *,char * msg)1177dd7cddfSDavid du Colombier ding(void*, char *msg)
1187dd7cddfSDavid du Colombier {
1199a747e4fSDavid du Colombier syslog(0, AUTHLOG, "ding %s", msg);
1207dd7cddfSDavid du Colombier if(strstr(msg, "alarm"))
1217dd7cddfSDavid du Colombier return 1;
1227dd7cddfSDavid du Colombier return 0;
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier Packet *
rpc(char * dest,Secret * shared,Packet * req)1267dd7cddfSDavid du Colombier rpc(char *dest, Secret *shared, Packet *req)
1277dd7cddfSDavid du Colombier {
1287dd7cddfSDavid du Colombier uchar buf[4096], buf2[4096], *b, *e;
1297dd7cddfSDavid du Colombier Packet *resp;
1307dd7cddfSDavid du Colombier Attribute *a;
1317dd7cddfSDavid du Colombier int m, n, fd, try;
1327dd7cddfSDavid du Colombier
133*7c70c028SDavid du Colombier /* marshal request */
1347dd7cddfSDavid du Colombier e = buf + sizeof buf;
1357dd7cddfSDavid du Colombier buf[0] = req->code;
1367dd7cddfSDavid du Colombier buf[1] = req->ID;
1377dd7cddfSDavid du Colombier memmove(buf+4, req->authenticator, 16);
1387dd7cddfSDavid du Colombier b = buf+20;
1397dd7cddfSDavid du Colombier for(a = &req->first; a; a = a->next){
1407dd7cddfSDavid du Colombier if(b + 2 + a->len > e)
1417dd7cddfSDavid du Colombier return nil;
1427dd7cddfSDavid du Colombier *b++ = a->type;
1437dd7cddfSDavid du Colombier *b++ = 2 + a->len;
1447dd7cddfSDavid du Colombier memmove(b, a->val, a->len);
1457dd7cddfSDavid du Colombier b += a->len;
1467dd7cddfSDavid du Colombier }
1477dd7cddfSDavid du Colombier n = b-buf;
1487dd7cddfSDavid du Colombier buf[2] = n>>8;
1497dd7cddfSDavid du Colombier buf[3] = n;
1507dd7cddfSDavid du Colombier
151*7c70c028SDavid du Colombier /* send request, wait for reply */
1527dd7cddfSDavid du Colombier fd = dial(dest, 0, 0, 0);
1537dd7cddfSDavid du Colombier if(fd < 0){
1549a747e4fSDavid du Colombier syslog(0, AUTHLOG, "%s: rpc can't get udp channel", dest);
1557dd7cddfSDavid du Colombier return nil;
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier atnotify(ding, 1);
1587dd7cddfSDavid du Colombier m = -1;
15980ee5cbfSDavid du Colombier for(try = 0; try < 2; try++){
160*7c70c028SDavid du Colombier /*
161*7c70c028SDavid du Colombier * increased timeout from 4sec to 15sec because
162*7c70c028SDavid du Colombier * corporate server really takes that long.
163*7c70c028SDavid du Colombier */
164d04cc87cSDavid du Colombier alarm(15000);
1657dd7cddfSDavid du Colombier m = write(fd, buf, n);
1667dd7cddfSDavid du Colombier if(m != n){
167*7c70c028SDavid du Colombier syslog(0, AUTHLOG, "%s: rpc write err %d %d: %r",
168*7c70c028SDavid du Colombier dest, m, n);
1697dd7cddfSDavid du Colombier m = -1;
1707dd7cddfSDavid du Colombier break;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier m = read(fd, buf2, sizeof buf2);
1737dd7cddfSDavid du Colombier alarm(0);
1749a747e4fSDavid du Colombier if(m < 0){
1759a747e4fSDavid du Colombier syslog(0, AUTHLOG, "%s rpc read err %d: %r", dest, m);
176*7c70c028SDavid du Colombier break; /* failure */
1779a747e4fSDavid du Colombier }
178*7c70c028SDavid du Colombier if(m == 0 || buf2[1] != buf[1]){ /* need matching ID */
1799a747e4fSDavid du Colombier syslog(0, AUTHLOG, "%s unmatched reply %d", dest, m);
1807dd7cddfSDavid du Colombier continue;
1819a747e4fSDavid du Colombier }
1827dd7cddfSDavid du Colombier if(authcmp(shared, buf2, m, buf+4) == 0)
1837dd7cddfSDavid du Colombier break;
1849a747e4fSDavid du Colombier syslog(0, AUTHLOG, "%s bad rpc chksum", dest);
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier close(fd);
1877dd7cddfSDavid du Colombier if(m <= 0)
1887dd7cddfSDavid du Colombier return nil;
1897dd7cddfSDavid du Colombier
190*7c70c028SDavid du Colombier /* unmarshal reply */
1917dd7cddfSDavid du Colombier b = buf2;
1927dd7cddfSDavid du Colombier e = buf2+m;
1937dd7cddfSDavid du Colombier resp = (Packet*)malloc(sizeof(*resp));
1947dd7cddfSDavid du Colombier if(resp == nil)
1957dd7cddfSDavid du Colombier return nil;
1967dd7cddfSDavid du Colombier resp->code = *b++;
1977dd7cddfSDavid du Colombier resp->ID = *b++;
1987dd7cddfSDavid du Colombier n = *b++;
1997dd7cddfSDavid du Colombier n = (n<<8) | *b++;
2007dd7cddfSDavid du Colombier if(m != n){
2019a747e4fSDavid du Colombier syslog(0, AUTHLOG, "rpc got %d bytes, length said %d", m, n);
2027dd7cddfSDavid du Colombier if(m > n)
2037dd7cddfSDavid du Colombier e = buf2+n;
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier memmove(resp->authenticator, b, 16);
2067dd7cddfSDavid du Colombier b += 16;
2077dd7cddfSDavid du Colombier a = &resp->first;
2087dd7cddfSDavid du Colombier a->type = 0;
209ec46fab0SDavid du Colombier for(;;){
2107dd7cddfSDavid du Colombier if(b >= e){
2117dd7cddfSDavid du Colombier a->next = nil;
212*7c70c028SDavid du Colombier break; /* exit loop */
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier a->type = *b++;
2157dd7cddfSDavid du Colombier a->len = (*b++) - 2;
216*7c70c028SDavid du Colombier if(b + a->len > e){ /* corrupt packet */
2177dd7cddfSDavid du Colombier a->next = nil;
2187dd7cddfSDavid du Colombier freePacket(resp);
2197dd7cddfSDavid du Colombier return nil;
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier memmove(a->val, b, a->len);
2227dd7cddfSDavid du Colombier b += a->len;
223*7c70c028SDavid du Colombier if(b < e){ /* any more attributes? */
2247dd7cddfSDavid du Colombier a->next = (Attribute*)malloc(sizeof(*a));
2257dd7cddfSDavid du Colombier if(a->next == nil){
2267dd7cddfSDavid du Colombier free(req);
2277dd7cddfSDavid du Colombier return nil;
2287dd7cddfSDavid du Colombier }
2297dd7cddfSDavid du Colombier a = a->next;
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier return resp;
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier int
setAttribute(Packet * p,uchar type,uchar * s,int n)2367dd7cddfSDavid du Colombier setAttribute(Packet *p, uchar type, uchar *s, int n)
2377dd7cddfSDavid du Colombier {
2387dd7cddfSDavid du Colombier Attribute *a;
2397dd7cddfSDavid du Colombier
2407dd7cddfSDavid du Colombier a = &p->first;
2417dd7cddfSDavid du Colombier if(a->type != 0){
2427dd7cddfSDavid du Colombier a = (Attribute*)malloc(sizeof(*a));
2437dd7cddfSDavid du Colombier if(a == nil)
2447dd7cddfSDavid du Colombier return -1;
2457dd7cddfSDavid du Colombier a->next = p->first.next;
2467dd7cddfSDavid du Colombier p->first.next = a;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier a->type = type;
2497dd7cddfSDavid du Colombier a->len = n;
250*7c70c028SDavid du Colombier if(a->len > 253) /* RFC2138, section 5 */
2517dd7cddfSDavid du Colombier a->len = 253;
2527dd7cddfSDavid du Colombier memmove(a->val, s, a->len);
2537dd7cddfSDavid du Colombier return 0;
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier
2563ff48bf5SDavid du Colombier /* return a reply message attribute string */
2573ff48bf5SDavid du Colombier char*
replymsg(Packet * p)2583ff48bf5SDavid du Colombier replymsg(Packet *p)
2593ff48bf5SDavid du Colombier {
2603ff48bf5SDavid du Colombier Attribute *a;
2613ff48bf5SDavid du Colombier static char buf[255];
2623ff48bf5SDavid du Colombier
263*7c70c028SDavid du Colombier for(a = &p->first; a; a = a->next)
2643ff48bf5SDavid du Colombier if(a->type == R_ReplyMessage){
2653ff48bf5SDavid du Colombier if(a->len >= sizeof buf)
2663ff48bf5SDavid du Colombier a->len = sizeof(buf)-1;
2673ff48bf5SDavid du Colombier memmove(buf, a->val, a->len);
2683ff48bf5SDavid du Colombier buf[a->len] = 0;
2693ff48bf5SDavid du Colombier }
2703ff48bf5SDavid du Colombier return buf;
2713ff48bf5SDavid du Colombier }
2727dd7cddfSDavid du Colombier
2737dd7cddfSDavid du Colombier /* for convenience while debugging */
2747dd7cddfSDavid du Colombier char *replymess;
2757dd7cddfSDavid du Colombier Attribute *stateattr;
2767dd7cddfSDavid du Colombier
2777dd7cddfSDavid du Colombier void
logPacket(Packet * p)2783ff48bf5SDavid du Colombier logPacket(Packet *p)
2797dd7cddfSDavid du Colombier {
2807dd7cddfSDavid du Colombier int i;
2813ff48bf5SDavid du Colombier char *np, *e;
282*7c70c028SDavid du Colombier char buf[255], pbuf[4*1024];
283*7c70c028SDavid du Colombier uchar *au = p->authenticator;
284*7c70c028SDavid du Colombier Attribute *a;
2857dd7cddfSDavid du Colombier
2863ff48bf5SDavid du Colombier e = pbuf + sizeof(pbuf);
2873ff48bf5SDavid du Colombier
288*7c70c028SDavid du Colombier np = seprint(pbuf, e, "Packet ID=%d auth=%x %x %x... ",
289*7c70c028SDavid du Colombier p->ID, au[0], au[1], au[2]);
2907dd7cddfSDavid du Colombier switch(p->code){
2917dd7cddfSDavid du Colombier case R_AccessRequest:
2923ff48bf5SDavid du Colombier np = seprint(np, e, "request\n");
2937dd7cddfSDavid du Colombier break;
2947dd7cddfSDavid du Colombier case R_AccessAccept:
2953ff48bf5SDavid du Colombier np = seprint(np, e, "accept\n");
2967dd7cddfSDavid du Colombier break;
2977dd7cddfSDavid du Colombier case R_AccessReject:
2983ff48bf5SDavid du Colombier np = seprint(np, e, "reject\n");
2997dd7cddfSDavid du Colombier break;
3007dd7cddfSDavid du Colombier case R_AccessChallenge:
3013ff48bf5SDavid du Colombier np = seprint(np, e, "challenge\n");
3027dd7cddfSDavid du Colombier break;
3037dd7cddfSDavid du Colombier default:
3043ff48bf5SDavid du Colombier np = seprint(np, e, "code=%d\n", p->code);
3057dd7cddfSDavid du Colombier break;
3067dd7cddfSDavid du Colombier }
3077dd7cddfSDavid du Colombier replymess = "0000000";
3087dd7cddfSDavid du Colombier for(a = &p->first; a; a = a->next){
3097dd7cddfSDavid du Colombier if(a->len > 253 )
3107dd7cddfSDavid du Colombier a->len = 253;
3117dd7cddfSDavid du Colombier memmove(buf, a->val, a->len);
3123ff48bf5SDavid du Colombier np = seprint(np, e, " [%d]", a->type);
3137dd7cddfSDavid du Colombier for(i = 0; i < a->len; i++)
3147dd7cddfSDavid du Colombier if(isprint(a->val[i]))
3153ff48bf5SDavid du Colombier np = seprint(np, e, "%c", a->val[i]);
3167dd7cddfSDavid du Colombier else
3173ff48bf5SDavid du Colombier np = seprint(np, e, "\\%o", a->val[i]);
3183ff48bf5SDavid du Colombier np = seprint(np, e, "\n");
3197dd7cddfSDavid du Colombier buf[a->len] = 0;
3207dd7cddfSDavid du Colombier if(a->type == R_ReplyMessage)
3217dd7cddfSDavid du Colombier replymess = strdup(buf);
3227dd7cddfSDavid du Colombier else if(a->type == R_State)
3237dd7cddfSDavid du Colombier stateattr = a;
3247dd7cddfSDavid du Colombier }
3253ff48bf5SDavid du Colombier
3263ff48bf5SDavid du Colombier syslog(0, AUTHLOG, "%s", pbuf);
3277dd7cddfSDavid du Colombier }
3287dd7cddfSDavid du Colombier
3299a747e4fSDavid du Colombier static uchar*
getipv4addr(void)3309a747e4fSDavid du Colombier getipv4addr(void)
3317dd7cddfSDavid du Colombier {
3329a747e4fSDavid du Colombier Ipifc *nifc;
3339a747e4fSDavid du Colombier Iplifc *lifc;
3349a747e4fSDavid du Colombier static Ipifc *ifc;
3357dd7cddfSDavid du Colombier
3369a747e4fSDavid du Colombier ifc = readipifc("/net", ifc, -1);
3379a747e4fSDavid du Colombier for(nifc = ifc; nifc; nifc = nifc->next)
3389a747e4fSDavid du Colombier for(lifc = nifc->lifc; lifc; lifc = lifc->next)
339*7c70c028SDavid du Colombier if (ipcmp(lifc->ip, IPnoaddr) != 0 &&
340*7c70c028SDavid du Colombier ipcmp(lifc->ip, v4prefix) != 0)
3419a747e4fSDavid du Colombier return lifc->ip;
3429a747e4fSDavid du Colombier return nil;
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier
3457dd7cddfSDavid du Colombier extern Ndb *db;
3467dd7cddfSDavid du Colombier
347cfdd14f4SDavid du Colombier /* returns 0 on success, error message on failure */
3483ff48bf5SDavid du Colombier char*
secureidcheck(char * user,char * response)3497dd7cddfSDavid du Colombier secureidcheck(char *user, char *response)
3507dd7cddfSDavid du Colombier {
351*7c70c028SDavid du Colombier char *radiussecret = nil;
3523ff48bf5SDavid du Colombier char *rv = "authentication failed";
353*7c70c028SDavid du Colombier char dest[3*IPaddrlen+20], ruser[64];
3549a747e4fSDavid du Colombier uchar *ip;
355*7c70c028SDavid du Colombier uchar x[16];
356*7c70c028SDavid du Colombier ulong u[4];
357*7c70c028SDavid du Colombier Ndbs s;
358*7c70c028SDavid du Colombier Ndbtuple *t = nil, *nt, *tt;
359*7c70c028SDavid du Colombier Packet *req = nil, *resp = nil;
360*7c70c028SDavid du Colombier Secret shared, pass;
3616b6b9ac8SDavid du Colombier static Ndb *netdb;
3626b6b9ac8SDavid du Colombier
3636b6b9ac8SDavid du Colombier if(netdb == nil)
3646b6b9ac8SDavid du Colombier netdb = ndbopen(0);
3657dd7cddfSDavid du Colombier
3667dd7cddfSDavid du Colombier /* bad responses make them disable the fob, avoid silly checks */
36780ee5cbfSDavid du Colombier if(strlen(response) < 4 || strpbrk(response,"abcdefABCDEF") != nil)
3689a747e4fSDavid du Colombier goto out;
3697dd7cddfSDavid du Colombier
3707dd7cddfSDavid du Colombier /* get radius secret */
37157837e0bSDavid du Colombier radiussecret = ndbgetvalue(db, &s, "radius", "lra-radius", "secret", &t);
37257837e0bSDavid du Colombier if(radiussecret == nil){
3739a747e4fSDavid du Colombier syslog(0, AUTHLOG, "secureidcheck: nil radius secret: %r");
3749a747e4fSDavid du Colombier goto out;
3759a747e4fSDavid du Colombier }
3767dd7cddfSDavid du Colombier
3777dd7cddfSDavid du Colombier /* translate user name if we have to */
3787dd7cddfSDavid du Colombier strcpy(ruser, user);
379*7c70c028SDavid du Colombier for(nt = t; nt; nt = nt->entry)
3807dd7cddfSDavid du Colombier if(strcmp(nt->attr, "uid") == 0 && strcmp(nt->val, user) == 0)
3817dd7cddfSDavid du Colombier for(tt = nt->line; tt != nt; tt = tt->line)
3827dd7cddfSDavid du Colombier if(strcmp(tt->attr, "rid") == 0){
3837dd7cddfSDavid du Colombier strcpy(ruser, tt->val);
3847dd7cddfSDavid du Colombier break;
3857dd7cddfSDavid du Colombier }
3867dd7cddfSDavid du Colombier ndbfree(t);
387*7c70c028SDavid du Colombier t = nil;
3887dd7cddfSDavid du Colombier
3897dd7cddfSDavid du Colombier u[0] = fastrand();
3907dd7cddfSDavid du Colombier u[1] = fastrand();
3917dd7cddfSDavid du Colombier u[2] = fastrand();
3927dd7cddfSDavid du Colombier u[3] = fastrand();
3937dd7cddfSDavid du Colombier req = newRequest((uchar*)u);
3947dd7cddfSDavid du Colombier if(req == nil)
3957dd7cddfSDavid du Colombier goto out;
3967dd7cddfSDavid du Colombier shared.s = (uchar*)radiussecret;
3977dd7cddfSDavid du Colombier shared.len = strlen(radiussecret);
3989a747e4fSDavid du Colombier ip = getipv4addr();
3999a747e4fSDavid du Colombier if(ip == nil){
4009a747e4fSDavid du Colombier syslog(0, AUTHLOG, "no interfaces: %r\n");
4017dd7cddfSDavid du Colombier goto out;
4029a747e4fSDavid du Colombier }
4039a747e4fSDavid du Colombier if(setAttribute(req, R_NASIPAddress, ip + IPv4off, 4) < 0)
4047dd7cddfSDavid du Colombier goto out;
4057dd7cddfSDavid du Colombier
4067dd7cddfSDavid du Colombier if(setAttribute(req, R_UserName, (uchar*)ruser, strlen(ruser)) < 0)
4077dd7cddfSDavid du Colombier goto out;
4087dd7cddfSDavid du Colombier pass.s = (uchar*)response;
4097dd7cddfSDavid du Colombier pass.len = strlen(response);
4107dd7cddfSDavid du Colombier hide(&shared, req->authenticator, &pass, x);
4117dd7cddfSDavid du Colombier if(setAttribute(req, R_UserPassword, x, 16) < 0)
4127dd7cddfSDavid du Colombier goto out;
4137dd7cddfSDavid du Colombier
4146b6b9ac8SDavid du Colombier t = ndbsearch(netdb, &s, "sys", "lra-radius");
41580ee5cbfSDavid du Colombier if(t == nil){
4169a747e4fSDavid du Colombier syslog(0, AUTHLOG, "secureidcheck: nil radius sys search: %r\n");
4177dd7cddfSDavid du Colombier goto out;
4187dd7cddfSDavid du Colombier }
41980ee5cbfSDavid du Colombier for(nt = t; nt; nt = nt->entry){
42080ee5cbfSDavid du Colombier if(strcmp(nt->attr, "ip") != 0)
42180ee5cbfSDavid du Colombier continue;
42280ee5cbfSDavid du Colombier
423208510e1SDavid du Colombier snprint(dest, sizeof dest, "udp!%s!radius", nt->val);
42480ee5cbfSDavid du Colombier resp = rpc(dest, &shared, req);
42580ee5cbfSDavid du Colombier if(resp == nil){
42680ee5cbfSDavid du Colombier syslog(0, AUTHLOG, "%s nil response", dest);
42780ee5cbfSDavid du Colombier continue;
42880ee5cbfSDavid du Colombier }
4297dd7cddfSDavid du Colombier if(resp->ID != req->ID){
43080ee5cbfSDavid du Colombier syslog(0, AUTHLOG, "%s mismatched ID req=%d resp=%d",
43180ee5cbfSDavid du Colombier dest, req->ID, resp->ID);
43280ee5cbfSDavid du Colombier freePacket(resp);
43380ee5cbfSDavid du Colombier resp = nil;
43480ee5cbfSDavid du Colombier continue;
4357dd7cddfSDavid du Colombier }
4367dd7cddfSDavid du Colombier
4377dd7cddfSDavid du Colombier switch(resp->code){
4387dd7cddfSDavid du Colombier case R_AccessAccept:
4393ff48bf5SDavid du Colombier syslog(0, AUTHLOG, "%s accepted ruser=%s", dest, ruser);
4403ff48bf5SDavid du Colombier rv = nil;
4417dd7cddfSDavid du Colombier break;
4427dd7cddfSDavid du Colombier case R_AccessReject:
443*7c70c028SDavid du Colombier syslog(0, AUTHLOG, "%s rejected ruser=%s %s",
444*7c70c028SDavid du Colombier dest, ruser, replymsg(resp));
4453ff48bf5SDavid du Colombier rv = "secureid failed";
4463ff48bf5SDavid du Colombier break;
4473ff48bf5SDavid du Colombier case R_AccessChallenge:
448*7c70c028SDavid du Colombier syslog(0, AUTHLOG, "%s challenge ruser=%s %s",
449*7c70c028SDavid du Colombier dest, ruser, replymsg(resp));
4503ff48bf5SDavid du Colombier rv = "secureid out of sync";
4517dd7cddfSDavid du Colombier break;
4527dd7cddfSDavid du Colombier default:
453*7c70c028SDavid du Colombier syslog(0, AUTHLOG, "%s code=%d ruser=%s %s",
454*7c70c028SDavid du Colombier dest, resp->code, ruser, replymsg(resp));
4557dd7cddfSDavid du Colombier break;
4567dd7cddfSDavid du Colombier }
457*7c70c028SDavid du Colombier break; /* we have a proper reply, no need to ask again */
45880ee5cbfSDavid du Colombier }
459*7c70c028SDavid du Colombier out:
460*7c70c028SDavid du Colombier if (t)
46180ee5cbfSDavid du Colombier ndbfree(t);
46257837e0bSDavid du Colombier free(radiussecret);
4637dd7cddfSDavid du Colombier freePacket(req);
4647dd7cddfSDavid du Colombier freePacket(resp);
4657dd7cddfSDavid du Colombier return rv;
4667dd7cddfSDavid du Colombier }
467