xref: /plan9/sys/src/cmd/auth/secureidcheck.c (revision 7c70c028d2d46a27a61ae88e6df0eb0935d9da7a)
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