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
hide(Secret * shared,uchar * auth,Secret * pass,uchar * x)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
authcmp(Secret * shared,uchar * buf,int m,uchar * auth)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*
newRequest(uchar * auth)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
freePacket(Packet * p)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
ding(void * v,char * msg)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 *
rpc(char * dest,Secret * shared,Packet * req)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
setAttribute(Packet * p,uchar type,uchar * s,int n)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*
replymsg(Packet * p)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
logPacket(Packet * p)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*
getipv4addr(void)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*
secureidcheck(char * user,char * response)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 }
447