xref: /plan9/sys/src/cmd/auth/authsrv.c (revision f54edc786b9c49b2c7ab1c0695cdc8c698b11f4d)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <ndb.h>
59a747e4fSDavid du Colombier #include <regexp.h>
69a747e4fSDavid du Colombier #include <mp.h>
79a747e4fSDavid du Colombier #include <libsec.h>
89a747e4fSDavid du Colombier #include <authsrv.h>
99a747e4fSDavid du Colombier #include "authcmdlib.h"
109a747e4fSDavid du Colombier 
119a747e4fSDavid du Colombier int debug;
129a747e4fSDavid du Colombier Ndb *db;
139a747e4fSDavid du Colombier char raddr[128];
149a747e4fSDavid du Colombier 
159a747e4fSDavid du Colombier /* Microsoft auth constants */
169a747e4fSDavid du Colombier enum {
179a747e4fSDavid du Colombier 	MShashlen = 16,
189a747e4fSDavid du Colombier 	MSchallen = 8,
199a747e4fSDavid du Colombier 	MSresplen = 24,
209a747e4fSDavid du Colombier };
219a747e4fSDavid du Colombier 
229a747e4fSDavid du Colombier int	ticketrequest(Ticketreq*);
239a747e4fSDavid du Colombier void	challengebox(Ticketreq*);
249a747e4fSDavid du Colombier void	changepasswd(Ticketreq*);
259a747e4fSDavid du Colombier void	apop(Ticketreq*, int);
269a747e4fSDavid du Colombier void	chap(Ticketreq*);
279a747e4fSDavid du Colombier void	mschap(Ticketreq*);
289a747e4fSDavid du Colombier void	http(Ticketreq*);
299a747e4fSDavid du Colombier void	vnc(Ticketreq*);
309a747e4fSDavid du Colombier int	speaksfor(char*, char*);
319a747e4fSDavid du Colombier void	replyerror(char*, ...);
329a747e4fSDavid du Colombier void	getraddr(char*);
339a747e4fSDavid du Colombier void	mkkey(char*);
349a747e4fSDavid du Colombier void	randombytes(uchar*, int);
359a747e4fSDavid du Colombier void	nthash(uchar hash[MShashlen], char *passwd);
369a747e4fSDavid du Colombier void	lmhash(uchar hash[MShashlen], char *passwd);
379a747e4fSDavid du Colombier void	mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);
389a747e4fSDavid du Colombier void	desencrypt(uchar data[8], uchar key[7]);
399a747e4fSDavid du Colombier int	tickauthreply(Ticketreq*, char*);
409a747e4fSDavid du Colombier void	safecpy(char*, char*, int);
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier 
439a747e4fSDavid du Colombier void
main(int argc,char * argv[])449a747e4fSDavid du Colombier main(int argc, char *argv[])
459a747e4fSDavid du Colombier {
469a747e4fSDavid du Colombier 	char buf[TICKREQLEN];
479a747e4fSDavid du Colombier 	Ticketreq tr;
489a747e4fSDavid du Colombier 
499a747e4fSDavid du Colombier 	ARGBEGIN{
509a747e4fSDavid du Colombier 	case 'd':
519a747e4fSDavid du Colombier 		debug++;
529a747e4fSDavid du Colombier 	}ARGEND
539a747e4fSDavid du Colombier 
549a747e4fSDavid du Colombier 	strcpy(raddr, "unknown");
559a747e4fSDavid du Colombier 	if(argc >= 1)
569a747e4fSDavid du Colombier 		getraddr(argv[argc-1]);
579a747e4fSDavid du Colombier 
589a747e4fSDavid du Colombier 	alarm(10*60*1000);	/* kill a connection after 10 minutes */
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier 	db = ndbopen("/lib/ndb/auth");
619a747e4fSDavid du Colombier 	if(db == 0)
629a747e4fSDavid du Colombier 		syslog(0, AUTHLOG, "no /lib/ndb/auth");
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier 	srand(time(0)*getpid());
659a747e4fSDavid du Colombier 	for(;;){
669a747e4fSDavid du Colombier 		if(readn(0, buf, TICKREQLEN) <= 0)
679a747e4fSDavid du Colombier 			exits(0);
689a747e4fSDavid du Colombier 
699a747e4fSDavid du Colombier 		convM2TR(buf, &tr);
709a747e4fSDavid du Colombier 		switch(buf[0]){
719a747e4fSDavid du Colombier 		case AuthTreq:
729a747e4fSDavid du Colombier 			ticketrequest(&tr);
739a747e4fSDavid du Colombier 			break;
749a747e4fSDavid du Colombier 		case AuthChal:
759a747e4fSDavid du Colombier 			challengebox(&tr);
769a747e4fSDavid du Colombier 			break;
779a747e4fSDavid du Colombier 		case AuthPass:
789a747e4fSDavid du Colombier 			changepasswd(&tr);
799a747e4fSDavid du Colombier 			break;
809a747e4fSDavid du Colombier 		case AuthApop:
819a747e4fSDavid du Colombier 			apop(&tr, AuthApop);
829a747e4fSDavid du Colombier 			break;
839a747e4fSDavid du Colombier 		case AuthChap:
849a747e4fSDavid du Colombier 			chap(&tr);
859a747e4fSDavid du Colombier 			break;
869a747e4fSDavid du Colombier 		case AuthMSchap:
879a747e4fSDavid du Colombier 			mschap(&tr);
889a747e4fSDavid du Colombier 			break;
899a747e4fSDavid du Colombier 		case AuthCram:
909a747e4fSDavid du Colombier 			apop(&tr, AuthCram);
919a747e4fSDavid du Colombier 			break;
929a747e4fSDavid du Colombier 		case AuthHttp:
939a747e4fSDavid du Colombier 			http(&tr);
949a747e4fSDavid du Colombier 			break;
959a747e4fSDavid du Colombier 		case AuthVNC:
969a747e4fSDavid du Colombier 			vnc(&tr);
979a747e4fSDavid du Colombier 			break;
989a747e4fSDavid du Colombier 		default:
999a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "unknown ticket request type: %d", buf[0]);
1006b6b9ac8SDavid du Colombier 			exits(0);
1019a747e4fSDavid du Colombier 		}
1029a747e4fSDavid du Colombier 	}
103b85a8364SDavid du Colombier 	/* not reached */
1049a747e4fSDavid du Colombier }
1059a747e4fSDavid du Colombier 
1069a747e4fSDavid du Colombier int
ticketrequest(Ticketreq * tr)1079a747e4fSDavid du Colombier ticketrequest(Ticketreq *tr)
1089a747e4fSDavid du Colombier {
1099a747e4fSDavid du Colombier 	char akey[DESKEYLEN];
1109a747e4fSDavid du Colombier 	char hkey[DESKEYLEN];
1119a747e4fSDavid du Colombier 	Ticket t;
1129a747e4fSDavid du Colombier 	char tbuf[2*TICKETLEN+1];
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier 	if(findkey(KEYDB, tr->authid, akey) == 0){
1159a747e4fSDavid du Colombier 		/* make one up so caller doesn't know it was wrong */
1169a747e4fSDavid du Colombier 		mkkey(akey);
1179a747e4fSDavid du Colombier 		if(debug)
1189a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "tr-fail authid %s", raddr);
1199a747e4fSDavid du Colombier 	}
1209a747e4fSDavid du Colombier 	if(findkey(KEYDB, tr->hostid, hkey) == 0){
1219a747e4fSDavid du Colombier 		/* make one up so caller doesn't know it was wrong */
1229a747e4fSDavid du Colombier 		mkkey(hkey);
1239a747e4fSDavid du Colombier 		if(debug)
1249a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr);
1259a747e4fSDavid du Colombier 	}
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier 	memset(&t, 0, sizeof(t));
1289a747e4fSDavid du Colombier 	memmove(t.chal, tr->chal, CHALLEN);
1299a747e4fSDavid du Colombier 	strcpy(t.cuid, tr->uid);
1309a747e4fSDavid du Colombier 	if(speaksfor(tr->hostid, tr->uid))
1319a747e4fSDavid du Colombier 		strcpy(t.suid, tr->uid);
132d9306527SDavid du Colombier 	else {
133d9306527SDavid du Colombier 		mkkey(akey);
134d9306527SDavid du Colombier 		mkkey(hkey);
135d9306527SDavid du Colombier 		if(debug)
136d9306527SDavid du Colombier 			syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",
137d9306527SDavid du Colombier 				tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
138d9306527SDavid du Colombier 	}
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier 	mkkey(t.key);
1419a747e4fSDavid du Colombier 
1429a747e4fSDavid du Colombier 	tbuf[0] = AuthOK;
1439a747e4fSDavid du Colombier 	t.num = AuthTc;
1449a747e4fSDavid du Colombier 	convT2M(&t, tbuf+1, hkey);
1459a747e4fSDavid du Colombier 	t.num = AuthTs;
1469a747e4fSDavid du Colombier 	convT2M(&t, tbuf+1+TICKETLEN, akey);
1479a747e4fSDavid du Colombier 	if(write(1, tbuf, 2*TICKETLEN+1) < 0){
1489a747e4fSDavid du Colombier 		if(debug)
1499a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup",
1509a747e4fSDavid du Colombier 				tr->uid, tr->hostid, raddr);
1519a747e4fSDavid du Colombier 		exits(0);
1529a747e4fSDavid du Colombier 	}
1539a747e4fSDavid du Colombier 	if(debug)
1549a747e4fSDavid du Colombier 		syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s",
1559a747e4fSDavid du Colombier 			tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
1569a747e4fSDavid du Colombier 
1579a747e4fSDavid du Colombier 	return 0;
1589a747e4fSDavid du Colombier }
1599a747e4fSDavid du Colombier 
1609a747e4fSDavid du Colombier void
challengebox(Ticketreq * tr)1619a747e4fSDavid du Colombier challengebox(Ticketreq *tr)
1629a747e4fSDavid du Colombier {
1639a747e4fSDavid du Colombier 	long chal;
1649a747e4fSDavid du Colombier 	char *key, *netkey;
1659a747e4fSDavid du Colombier 	char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], hkey[DESKEYLEN];
1669a747e4fSDavid du Colombier 	char buf[NETCHLEN+1];
1673ff48bf5SDavid du Colombier 	char *err;
1689a747e4fSDavid du Colombier 
1699a747e4fSDavid du Colombier 	key = findkey(KEYDB, tr->uid, kbuf);
1709a747e4fSDavid du Colombier 	netkey = findkey(NETKEYDB, tr->uid, nkbuf);
1719a747e4fSDavid du Colombier 	if(key == 0 && netkey == 0){
1729a747e4fSDavid du Colombier 		/* make one up so caller doesn't know it was wrong */
1739a747e4fSDavid du Colombier 		mkkey(nkbuf);
1749a747e4fSDavid du Colombier 		netkey = nkbuf;
1759a747e4fSDavid du Colombier 		if(debug)
1769a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr);
1779a747e4fSDavid du Colombier 	}
1789a747e4fSDavid du Colombier 	if(findkey(KEYDB, tr->hostid, hkey) == 0){
1799a747e4fSDavid du Colombier 		/* make one up so caller doesn't know it was wrong */
1809a747e4fSDavid du Colombier 		mkkey(hkey);
1819a747e4fSDavid du Colombier 		if(debug)
1829a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid,
1839a747e4fSDavid du Colombier 				tr->uid, raddr);
1849a747e4fSDavid du Colombier 	}
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier 	/*
1879a747e4fSDavid du Colombier 	 * challenge-response
1889a747e4fSDavid du Colombier 	 */
1899a747e4fSDavid du Colombier 	memset(buf, 0, sizeof(buf));
1909a747e4fSDavid du Colombier 	buf[0] = AuthOK;
1919a747e4fSDavid du Colombier 	chal = lnrand(MAXNETCHAL);
192*f54edc78SDavid du Colombier 	snprint(buf+1, sizeof buf - 1, "%lud", chal);
1939a747e4fSDavid du Colombier 	if(write(1, buf, NETCHLEN+1) < 0)
1949a747e4fSDavid du Colombier 		exits(0);
1959a747e4fSDavid du Colombier 	if(readn(0, buf, NETCHLEN) < 0)
1969a747e4fSDavid du Colombier 		exits(0);
1979a747e4fSDavid du Colombier 	if(!(key && netcheck(key, chal, buf))
1989a747e4fSDavid du Colombier 	&& !(netkey && netcheck(netkey, chal, buf))
1993ff48bf5SDavid du Colombier 	&& (err = secureidcheck(tr->uid, buf)) != nil){
2003ff48bf5SDavid du Colombier 		replyerror("cr-fail %s %s %s", err, tr->uid, raddr);
2019a747e4fSDavid du Colombier 		logfail(tr->uid);
2029a747e4fSDavid du Colombier 		if(debug)
2039a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "cr-fail %s@%s(%s): bad resp",
2049a747e4fSDavid du Colombier 				tr->uid, tr->hostid, raddr);
2059a747e4fSDavid du Colombier 		return;
2069a747e4fSDavid du Colombier 	}
2079a747e4fSDavid du Colombier 	succeed(tr->uid);
2089a747e4fSDavid du Colombier 
2099a747e4fSDavid du Colombier 	/*
2109a747e4fSDavid du Colombier 	 *  reply with ticket & authenticator
2119a747e4fSDavid du Colombier 	 */
2129a747e4fSDavid du Colombier 	if(tickauthreply(tr, hkey) < 0){
2139a747e4fSDavid du Colombier 		if(debug)
2149a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup",
2159a747e4fSDavid du Colombier 				tr->uid, tr->hostid, raddr);
2169a747e4fSDavid du Colombier 		exits(0);
2179a747e4fSDavid du Colombier 	}
2189a747e4fSDavid du Colombier 
2199a747e4fSDavid du Colombier 	if(debug)
2209a747e4fSDavid du Colombier 		syslog(0, AUTHLOG, "cr-ok %s@%s(%s)",
2219a747e4fSDavid du Colombier 			tr->uid, tr->hostid, raddr);
2229a747e4fSDavid du Colombier }
2239a747e4fSDavid du Colombier 
2249a747e4fSDavid du Colombier void
changepasswd(Ticketreq * tr)2259a747e4fSDavid du Colombier changepasswd(Ticketreq *tr)
2269a747e4fSDavid du Colombier {
2279a747e4fSDavid du Colombier 	Ticket t;
2289a747e4fSDavid du Colombier 	char tbuf[TICKETLEN+1];
2299a747e4fSDavid du Colombier 	char prbuf[PASSREQLEN];
2309a747e4fSDavid du Colombier 	Passwordreq pr;
2319a747e4fSDavid du Colombier 	char okey[DESKEYLEN], nkey[DESKEYLEN];
2329a747e4fSDavid du Colombier 	char *err;
2339a747e4fSDavid du Colombier 
2349a747e4fSDavid du Colombier 	if(findkey(KEYDB, tr->uid, okey) == 0){
2359a747e4fSDavid du Colombier 		/* make one up so caller doesn't know it was wrong */
2369a747e4fSDavid du Colombier 		mkkey(okey);
2379a747e4fSDavid du Colombier 		syslog(0, AUTHLOG, "cp-fail uid %s", raddr);
2389a747e4fSDavid du Colombier 	}
2399a747e4fSDavid du Colombier 
2409a747e4fSDavid du Colombier 	/* send back a ticket with a new key */
2419a747e4fSDavid du Colombier 	memmove(t.chal, tr->chal, CHALLEN);
2429a747e4fSDavid du Colombier 	mkkey(t.key);
2439a747e4fSDavid du Colombier 	tbuf[0] = AuthOK;
2449a747e4fSDavid du Colombier 	t.num = AuthTp;
2459a747e4fSDavid du Colombier 	safecpy(t.cuid, tr->uid, sizeof(t.cuid));
2469a747e4fSDavid du Colombier 	safecpy(t.suid, tr->uid, sizeof(t.suid));
2479a747e4fSDavid du Colombier 	convT2M(&t, tbuf+1, okey);
2489a747e4fSDavid du Colombier 	write(1, tbuf, sizeof(tbuf));
2499a747e4fSDavid du Colombier 
2509a747e4fSDavid du Colombier 	/* loop trying passwords out */
2519a747e4fSDavid du Colombier 	for(;;){
2529a747e4fSDavid du Colombier 		if(readn(0, prbuf, PASSREQLEN) < 0)
2539a747e4fSDavid du Colombier 			exits(0);
2549a747e4fSDavid du Colombier 		convM2PR(prbuf, &pr, t.key);
2559a747e4fSDavid du Colombier 		if(pr.num != AuthPass){
2569a747e4fSDavid du Colombier 			replyerror("protocol botch1: %s", raddr);
2579a747e4fSDavid du Colombier 			exits(0);
2589a747e4fSDavid du Colombier 		}
2599a747e4fSDavid du Colombier 		passtokey(nkey, pr.old);
2609a747e4fSDavid du Colombier 		if(memcmp(nkey, okey, DESKEYLEN)){
2619a747e4fSDavid du Colombier 			replyerror("protocol botch2: %s", raddr);
2629a747e4fSDavid du Colombier 			continue;
2639a747e4fSDavid du Colombier 		}
2649a747e4fSDavid du Colombier 		if(*pr.new){
2659a747e4fSDavid du Colombier 			err = okpasswd(pr.new);
2669a747e4fSDavid du Colombier 			if(err){
2679a747e4fSDavid du Colombier 				replyerror("%s %s", err, raddr);
2689a747e4fSDavid du Colombier 				continue;
2699a747e4fSDavid du Colombier 			}
2709a747e4fSDavid du Colombier 			passtokey(nkey, pr.new);
2719a747e4fSDavid du Colombier 		}
2729a747e4fSDavid du Colombier 		if(pr.changesecret && setsecret(KEYDB, tr->uid, pr.secret) == 0){
2739a747e4fSDavid du Colombier 			replyerror("can't write secret %s", raddr);
2749a747e4fSDavid du Colombier 			continue;
2759a747e4fSDavid du Colombier 		}
2769a747e4fSDavid du Colombier 		if(*pr.new && setkey(KEYDB, tr->uid, nkey) == 0){
2779a747e4fSDavid du Colombier 			replyerror("can't write key %s", raddr);
2789a747e4fSDavid du Colombier 			continue;
2799a747e4fSDavid du Colombier 		}
2809a747e4fSDavid du Colombier 		break;
2819a747e4fSDavid du Colombier 	}
2829a747e4fSDavid du Colombier 
2839a747e4fSDavid du Colombier 	prbuf[0] = AuthOK;
2849a747e4fSDavid du Colombier 	write(1, prbuf, 1);
2859a747e4fSDavid du Colombier 	succeed(tr->uid);
2869a747e4fSDavid du Colombier 	return;
2879a747e4fSDavid du Colombier }
2889a747e4fSDavid du Colombier 
2899a747e4fSDavid du Colombier void
http(Ticketreq * tr)2909a747e4fSDavid du Colombier http(Ticketreq *tr)
2919a747e4fSDavid du Colombier {
2929a747e4fSDavid du Colombier 	Ticket t;
2939a747e4fSDavid du Colombier 	char tbuf[TICKETLEN+1];
2949a747e4fSDavid du Colombier 	char key[DESKEYLEN];
2959a747e4fSDavid du Colombier 	char *p;
2969a747e4fSDavid du Colombier 	Biobuf *b;
2979a747e4fSDavid du Colombier 	int n;
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier 	n = strlen(tr->uid);
3009a747e4fSDavid du Colombier 	b = Bopen("/sys/lib/httppasswords", OREAD);
3019a747e4fSDavid du Colombier 	if(b == nil){
3029a747e4fSDavid du Colombier 		replyerror("no password file", raddr);
3039a747e4fSDavid du Colombier 		return;
3049a747e4fSDavid du Colombier 	}
3059a747e4fSDavid du Colombier 
3069a747e4fSDavid du Colombier 	/* find key */
3079a747e4fSDavid du Colombier 	for(;;){
3089a747e4fSDavid du Colombier 		p = Brdline(b, '\n');
3099a747e4fSDavid du Colombier 		if(p == nil)
3109a747e4fSDavid du Colombier 			break;
3119a747e4fSDavid du Colombier 		p[Blinelen(b)-1] = 0;
3129a747e4fSDavid du Colombier 		if(strncmp(p, tr->uid, n) == 0)
3139a747e4fSDavid du Colombier 		if(p[n] == ' ' || p[n] == '\t'){
3149a747e4fSDavid du Colombier 			p += n;
3159a747e4fSDavid du Colombier 			break;
3169a747e4fSDavid du Colombier 		}
3179a747e4fSDavid du Colombier 	}
3189a747e4fSDavid du Colombier 	Bterm(b);
3199a747e4fSDavid du Colombier 	if(p == nil) {
3209a747e4fSDavid du Colombier 		randombytes((uchar*)key, DESKEYLEN);
3219a747e4fSDavid du Colombier 	} else {
3229a747e4fSDavid du Colombier 		while(*p == ' ' || *p == '\t')
3239a747e4fSDavid du Colombier 			p++;
3249a747e4fSDavid du Colombier 		passtokey(key, p);
3259a747e4fSDavid du Colombier 	}
3269a747e4fSDavid du Colombier 
3279a747e4fSDavid du Colombier 	/* send back a ticket encrypted with the key */
3289a747e4fSDavid du Colombier 	randombytes((uchar*)t.chal, CHALLEN);
3299a747e4fSDavid du Colombier 	mkkey(t.key);
3309a747e4fSDavid du Colombier 	tbuf[0] = AuthOK;
3319a747e4fSDavid du Colombier 	t.num = AuthHr;
3329a747e4fSDavid du Colombier 	safecpy(t.cuid, tr->uid, sizeof(t.cuid));
3339a747e4fSDavid du Colombier 	safecpy(t.suid, tr->uid, sizeof(t.suid));
3349a747e4fSDavid du Colombier 	convT2M(&t, tbuf+1, key);
3359a747e4fSDavid du Colombier 	write(1, tbuf, sizeof(tbuf));
3369a747e4fSDavid du Colombier }
3379a747e4fSDavid du Colombier 
3389a747e4fSDavid du Colombier static char*
domainname(void)3399a747e4fSDavid du Colombier domainname(void)
3409a747e4fSDavid du Colombier {
3419a747e4fSDavid du Colombier 	static char sysname[Maxpath];
34257837e0bSDavid du Colombier 	static char *domain;
3439a747e4fSDavid du Colombier 	int n;
3449a747e4fSDavid du Colombier 
34557837e0bSDavid du Colombier 	if(domain)
3469a747e4fSDavid du Colombier 		return domain;
3479a747e4fSDavid du Colombier 	if(*sysname)
3489a747e4fSDavid du Colombier 		return sysname;
3499a747e4fSDavid du Colombier 
35057837e0bSDavid du Colombier 	domain = csgetvalue(0, "sys", sysname, "dom", nil);
35157837e0bSDavid du Colombier 	if(domain)
35257837e0bSDavid du Colombier 		return domain;
35357837e0bSDavid du Colombier 
3549a747e4fSDavid du Colombier 	n = readfile("/dev/sysname", sysname, sizeof(sysname)-1);
3559a747e4fSDavid du Colombier 	if(n < 0){
3569a747e4fSDavid du Colombier 		strcpy(sysname, "kremvax");
3579a747e4fSDavid du Colombier 		return sysname;
3589a747e4fSDavid du Colombier 	}
3599a747e4fSDavid du Colombier 	sysname[n] = 0;
3609a747e4fSDavid du Colombier 
3619a747e4fSDavid du Colombier 	return sysname;
3629a747e4fSDavid du Colombier }
3639a747e4fSDavid du Colombier 
3649a747e4fSDavid du Colombier static int
h2b(char c)3659a747e4fSDavid du Colombier h2b(char c)
3669a747e4fSDavid du Colombier {
3679a747e4fSDavid du Colombier 	if(c >= '0' && c <= '9')
3689a747e4fSDavid du Colombier 		return c - '0';
3699a747e4fSDavid du Colombier 	if(c >= 'A' && c <= 'F')
3709a747e4fSDavid du Colombier 		return c - 'A' + 10;
3719a747e4fSDavid du Colombier 	if(c >= 'a' && c <= 'f')
3729a747e4fSDavid du Colombier 		return c - 'a' + 10;
3739a747e4fSDavid du Colombier 	return 0;
3749a747e4fSDavid du Colombier }
3759a747e4fSDavid du Colombier 
3769a747e4fSDavid du Colombier void
apop(Ticketreq * tr,int type)3779a747e4fSDavid du Colombier apop(Ticketreq *tr, int type)
3789a747e4fSDavid du Colombier {
3799a747e4fSDavid du Colombier 	int challen, i, tries;
3809a747e4fSDavid du Colombier 	char *secret, *hkey, *p;
3819a747e4fSDavid du Colombier 	Ticketreq treq;
3829a747e4fSDavid du Colombier 	DigestState *s;
3839a747e4fSDavid du Colombier 	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
3849a747e4fSDavid du Colombier 	char tbuf[TICKREQLEN];
3859a747e4fSDavid du Colombier 	char buf[MD5dlen*2];
3869a747e4fSDavid du Colombier 	uchar digest[MD5dlen], resp[MD5dlen];
3879a747e4fSDavid du Colombier 	ulong rb[4];
3889a747e4fSDavid du Colombier 	char chal[256];
3899a747e4fSDavid du Colombier 
3909a747e4fSDavid du Colombier 	USED(tr);
3919a747e4fSDavid du Colombier 
3929a747e4fSDavid du Colombier 	/*
3939a747e4fSDavid du Colombier 	 *  Create a challenge and send it.
3949a747e4fSDavid du Colombier 	 */
3959a747e4fSDavid du Colombier 	randombytes((uchar*)rb, sizeof(rb));
3969a747e4fSDavid du Colombier 	p = chal;
3979a747e4fSDavid du Colombier 	p += snprint(p, sizeof(chal), "<%lux%lux.%lux%lux@%s>",
3989a747e4fSDavid du Colombier 		rb[0], rb[1], rb[2], rb[3], domainname());
3999a747e4fSDavid du Colombier 	challen = p - chal;
4009a747e4fSDavid du Colombier 	print("%c%-5d%s", AuthOKvar, challen, chal);
4019a747e4fSDavid du Colombier 
4029a747e4fSDavid du Colombier 	/* give user a few attempts */
4039a747e4fSDavid du Colombier 	for(tries = 0; ; tries++) {
4049a747e4fSDavid du Colombier 		/*
4059a747e4fSDavid du Colombier 		 *  get ticket request
4069a747e4fSDavid du Colombier 		 */
4079a747e4fSDavid du Colombier 		if(readn(0, tbuf, TICKREQLEN) < 0)
4089a747e4fSDavid du Colombier 			exits(0);
4099a747e4fSDavid du Colombier 		convM2TR(tbuf, &treq);
4109a747e4fSDavid du Colombier 		tr = &treq;
4119a747e4fSDavid du Colombier 		if(tr->type != type)
4129a747e4fSDavid du Colombier 			exits(0);
4139a747e4fSDavid du Colombier 
4149a747e4fSDavid du Colombier 		/*
4159a747e4fSDavid du Colombier 		 * read response
4169a747e4fSDavid du Colombier 		 */
4179a747e4fSDavid du Colombier 		if(readn(0, buf, MD5dlen*2) < 0)
4189a747e4fSDavid du Colombier 			exits(0);
4199a747e4fSDavid du Colombier 		for(i = 0; i < MD5dlen; i++)
4209a747e4fSDavid du Colombier 			resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]);
4219a747e4fSDavid du Colombier 
4229a747e4fSDavid du Colombier 		/*
4239a747e4fSDavid du Colombier 		 * lookup
4249a747e4fSDavid du Colombier 		 */
4259a747e4fSDavid du Colombier 		secret = findsecret(KEYDB, tr->uid, sbuf);
4269a747e4fSDavid du Colombier 		hkey = findkey(KEYDB, tr->hostid, hbuf);
4279a747e4fSDavid du Colombier 		if(hkey == 0 || secret == 0){
4289a747e4fSDavid du Colombier 			replyerror("apop-fail bad response %s", raddr);
4299a747e4fSDavid du Colombier 			logfail(tr->uid);
4309a747e4fSDavid du Colombier 			if(tries > 5)
4319a747e4fSDavid du Colombier 				return;
4329a747e4fSDavid du Colombier 			continue;
4339a747e4fSDavid du Colombier 		}
4349a747e4fSDavid du Colombier 
4359a747e4fSDavid du Colombier 		/*
4369a747e4fSDavid du Colombier 		 *  check for match
4379a747e4fSDavid du Colombier 		 */
4389a747e4fSDavid du Colombier 		if(type == AuthCram){
4399a747e4fSDavid du Colombier 			hmac_md5((uchar*)chal, challen,
4409a747e4fSDavid du Colombier 				(uchar*)secret, strlen(secret),
4419a747e4fSDavid du Colombier 				digest, nil);
4429a747e4fSDavid du Colombier 		} else {
4439a747e4fSDavid du Colombier 			s = md5((uchar*)chal, challen, 0, 0);
4449a747e4fSDavid du Colombier 			md5((uchar*)secret, strlen(secret), digest, s);
4459a747e4fSDavid du Colombier 		}
4469a747e4fSDavid du Colombier 		if(memcmp(digest, resp, MD5dlen) != 0){
4479a747e4fSDavid du Colombier 			replyerror("apop-fail bad response %s", raddr);
4489a747e4fSDavid du Colombier 			logfail(tr->uid);
4499a747e4fSDavid du Colombier 			if(tries > 5)
4509a747e4fSDavid du Colombier 				return;
4519a747e4fSDavid du Colombier 			continue;
4529a747e4fSDavid du Colombier 		}
4539a747e4fSDavid du Colombier 		break;
4549a747e4fSDavid du Colombier 	}
4559a747e4fSDavid du Colombier 
4569a747e4fSDavid du Colombier 	succeed(tr->uid);
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier 	/*
4599a747e4fSDavid du Colombier 	 *  reply with ticket & authenticator
4609a747e4fSDavid du Colombier 	 */
4619a747e4fSDavid du Colombier 	if(tickauthreply(tr, hkey) < 0)
4629a747e4fSDavid du Colombier 		exits(0);
4639a747e4fSDavid du Colombier 
4649a747e4fSDavid du Colombier 	if(debug){
4659a747e4fSDavid du Colombier 		if(type == AuthCram)
4669a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr);
4679a747e4fSDavid du Colombier 		else
4689a747e4fSDavid du Colombier 			syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr);
4699a747e4fSDavid du Colombier 	}
4709a747e4fSDavid du Colombier }
4719a747e4fSDavid du Colombier 
4729a747e4fSDavid du Colombier enum {
4739a747e4fSDavid du Colombier 	VNCchallen=	16,
4749a747e4fSDavid du Colombier };
4759a747e4fSDavid du Colombier 
4769a747e4fSDavid du Colombier /* VNC reverses the bits of each byte before using as a des key */
4779a747e4fSDavid du Colombier uchar swizzletab[256] = {
4789a747e4fSDavid du Colombier  0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
4799a747e4fSDavid du Colombier  0x8, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
4809a747e4fSDavid du Colombier  0x4, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
4819a747e4fSDavid du Colombier  0xc, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
4829a747e4fSDavid du Colombier  0x2, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
4839a747e4fSDavid du Colombier  0xa, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
4849a747e4fSDavid du Colombier  0x6, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
4859a747e4fSDavid du Colombier  0xe, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
4869a747e4fSDavid du Colombier  0x1, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
4879a747e4fSDavid du Colombier  0x9, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
4889a747e4fSDavid du Colombier  0x5, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
4899a747e4fSDavid du Colombier  0xd, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
4909a747e4fSDavid du Colombier  0x3, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
4919a747e4fSDavid du Colombier  0xb, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
4929a747e4fSDavid du Colombier  0x7, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
4939a747e4fSDavid du Colombier  0xf, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
4949a747e4fSDavid du Colombier };
4959a747e4fSDavid du Colombier 
4969a747e4fSDavid du Colombier void
vnc(Ticketreq * tr)4979a747e4fSDavid du Colombier vnc(Ticketreq *tr)
4989a747e4fSDavid du Colombier {
4999a747e4fSDavid du Colombier 	uchar chal[VNCchallen+6];
5009a747e4fSDavid du Colombier 	uchar reply[VNCchallen];
5019a747e4fSDavid du Colombier 	char *secret, *hkey;
5029a747e4fSDavid du Colombier 	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
5039a747e4fSDavid du Colombier 	DESstate s;
5049a747e4fSDavid du Colombier 	int i;
5059a747e4fSDavid du Colombier 
5069a747e4fSDavid du Colombier 	/*
5079a747e4fSDavid du Colombier 	 *  Create a challenge and send it.
5089a747e4fSDavid du Colombier 	 */
5099a747e4fSDavid du Colombier 	randombytes(chal+6, VNCchallen);
5109a747e4fSDavid du Colombier 	chal[0] = AuthOKvar;
511*f54edc78SDavid du Colombier 	snprint((char*)chal+1, sizeof chal - 1, "%-5d", VNCchallen);
5129a747e4fSDavid du Colombier 	if(write(1, chal, sizeof(chal)) != sizeof(chal))
5139a747e4fSDavid du Colombier 		return;
5149a747e4fSDavid du Colombier 
5159a747e4fSDavid du Colombier 	/*
5169a747e4fSDavid du Colombier 	 *  lookup keys (and swizzle bits)
5179a747e4fSDavid du Colombier 	 */
5189a747e4fSDavid du Colombier 	memset(sbuf, 0, sizeof(sbuf));
5199a747e4fSDavid du Colombier 	secret = findsecret(KEYDB, tr->uid, sbuf);
5209a747e4fSDavid du Colombier 	if(secret == 0){
5219a747e4fSDavid du Colombier 		randombytes((uchar*)sbuf, sizeof(sbuf));
5229a747e4fSDavid du Colombier 		secret = sbuf;
5239a747e4fSDavid du Colombier 	}
5249a747e4fSDavid du Colombier 	for(i = 0; i < 8; i++)
5259a747e4fSDavid du Colombier 		secret[i] = swizzletab[(uchar)secret[i]];
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier 	hkey = findkey(KEYDB, tr->hostid, hbuf);
5289a747e4fSDavid du Colombier 	if(hkey == 0){
5299a747e4fSDavid du Colombier 		randombytes((uchar*)hbuf, sizeof(hbuf));
5309a747e4fSDavid du Colombier 		hkey = hbuf;
5319a747e4fSDavid du Colombier 	}
5329a747e4fSDavid du Colombier 
5339a747e4fSDavid du Colombier 	/*
5349a747e4fSDavid du Colombier 	 *  get response
5359a747e4fSDavid du Colombier 	 */
5369a747e4fSDavid du Colombier 	if(readn(0, reply, sizeof(reply)) != sizeof(reply))
5379a747e4fSDavid du Colombier 		return;
5389a747e4fSDavid du Colombier 
5399a747e4fSDavid du Colombier 	/*
5409a747e4fSDavid du Colombier 	 *  decrypt response and compare
5419a747e4fSDavid du Colombier 	 */
5429a747e4fSDavid du Colombier 	setupDESstate(&s, (uchar*)secret, nil);
5439a747e4fSDavid du Colombier 	desECBdecrypt(reply, sizeof(reply), &s);
5449a747e4fSDavid du Colombier 	if(memcmp(reply, chal+6, VNCchallen) != 0){
5459a747e4fSDavid du Colombier 		replyerror("vnc-fail bad response %s", raddr);
5469a747e4fSDavid du Colombier 		logfail(tr->uid);
5479a747e4fSDavid du Colombier 		return;
5489a747e4fSDavid du Colombier 	}
5499a747e4fSDavid du Colombier 	succeed(tr->uid);
5509a747e4fSDavid du Colombier 
5519a747e4fSDavid du Colombier 	/*
5529a747e4fSDavid du Colombier 	 *  reply with ticket & authenticator
5539a747e4fSDavid du Colombier 	 */
5549a747e4fSDavid du Colombier 	if(tickauthreply(tr, hkey) < 0)
5559a747e4fSDavid du Colombier 		exits(0);
5569a747e4fSDavid du Colombier 
5579a747e4fSDavid du Colombier 	if(debug)
5589a747e4fSDavid du Colombier 		syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr);
5599a747e4fSDavid du Colombier }
5609a747e4fSDavid du Colombier 
5619a747e4fSDavid du Colombier void
chap(Ticketreq * tr)5629a747e4fSDavid du Colombier chap(Ticketreq *tr)
5639a747e4fSDavid du Colombier {
5649a747e4fSDavid du Colombier 	char *secret, *hkey;
5659a747e4fSDavid du Colombier 	DigestState *s;
5669a747e4fSDavid du Colombier 	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
5679a747e4fSDavid du Colombier 	uchar digest[MD5dlen];
5689a747e4fSDavid du Colombier 	char chal[CHALLEN];
5699a747e4fSDavid du Colombier 	OChapreply reply;
5709a747e4fSDavid du Colombier 
5719a747e4fSDavid du Colombier 	/*
5729a747e4fSDavid du Colombier 	 *  Create a challenge and send it.
5739a747e4fSDavid du Colombier 	 */
5749a747e4fSDavid du Colombier 	randombytes((uchar*)chal, sizeof(chal));
5759a747e4fSDavid du Colombier 	write(1, chal, sizeof(chal));
5769a747e4fSDavid du Colombier 
5779a747e4fSDavid du Colombier 	/*
5789a747e4fSDavid du Colombier 	 *  get chap reply
5799a747e4fSDavid du Colombier 	 */
5809a747e4fSDavid du Colombier 	if(readn(0, &reply, sizeof(reply)) < 0)
5819a747e4fSDavid du Colombier 		exits(0);
5829a747e4fSDavid du Colombier 	safecpy(tr->uid, reply.uid, sizeof(tr->uid));
5839a747e4fSDavid du Colombier 
5849a747e4fSDavid du Colombier 	/*
5859a747e4fSDavid du Colombier 	 * lookup
5869a747e4fSDavid du Colombier 	 */
5879a747e4fSDavid du Colombier 	secret = findsecret(KEYDB, tr->uid, sbuf);
5889a747e4fSDavid du Colombier 	hkey = findkey(KEYDB, tr->hostid, hbuf);
5899a747e4fSDavid du Colombier 	if(hkey == 0 || secret == 0){
5909a747e4fSDavid du Colombier 		replyerror("chap-fail bad response %s", raddr);
5919a747e4fSDavid du Colombier 		logfail(tr->uid);
5929a747e4fSDavid du Colombier 		exits(0);
5939a747e4fSDavid du Colombier 	}
5949a747e4fSDavid du Colombier 
5959a747e4fSDavid du Colombier 	/*
5969a747e4fSDavid du Colombier 	 *  check for match
5979a747e4fSDavid du Colombier 	 */
5989a747e4fSDavid du Colombier 	s = md5(&reply.id, 1, 0, 0);
5999a747e4fSDavid du Colombier 	md5((uchar*)secret, strlen(secret), 0, s);
6009a747e4fSDavid du Colombier 	md5((uchar*)chal, sizeof(chal), digest, s);
6019a747e4fSDavid du Colombier 
6029a747e4fSDavid du Colombier 	if(memcmp(digest, reply.resp, MD5dlen) != 0){
6039a747e4fSDavid du Colombier 		replyerror("chap-fail bad response %s", raddr);
6049a747e4fSDavid du Colombier 		logfail(tr->uid);
6059a747e4fSDavid du Colombier 		exits(0);
6069a747e4fSDavid du Colombier 	}
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier 	succeed(tr->uid);
6099a747e4fSDavid du Colombier 
6109a747e4fSDavid du Colombier 	/*
6119a747e4fSDavid du Colombier 	 *  reply with ticket & authenticator
6129a747e4fSDavid du Colombier 	 */
6139a747e4fSDavid du Colombier 	if(tickauthreply(tr, hkey) < 0)
6149a747e4fSDavid du Colombier 		exits(0);
6159a747e4fSDavid du Colombier 
6169a747e4fSDavid du Colombier 	if(debug)
6179a747e4fSDavid du Colombier 		syslog(0, AUTHLOG, "chap-ok %s %s", tr->uid, raddr);
6189a747e4fSDavid du Colombier }
6199a747e4fSDavid du Colombier 
6209a747e4fSDavid du Colombier void
printresp(uchar resp[MSresplen])6219a747e4fSDavid du Colombier printresp(uchar resp[MSresplen])
6229a747e4fSDavid du Colombier {
6239a747e4fSDavid du Colombier 	char buf[200], *p;
6249a747e4fSDavid du Colombier 	int i;
6259a747e4fSDavid du Colombier 
6269a747e4fSDavid du Colombier 	p = buf;
6279a747e4fSDavid du Colombier 	for(i=0; i<MSresplen; i++)
6289a747e4fSDavid du Colombier 		p += sprint(p, "%.2ux ", resp[i]);
6299a747e4fSDavid du Colombier 	syslog(0, AUTHLOG, "resp = %s", buf);
6309a747e4fSDavid du Colombier }
6319a747e4fSDavid du Colombier 
6329a747e4fSDavid du Colombier 
6339a747e4fSDavid du Colombier void
mschap(Ticketreq * tr)6349a747e4fSDavid du Colombier mschap(Ticketreq *tr)
6359a747e4fSDavid du Colombier {
6369a747e4fSDavid du Colombier 
6379a747e4fSDavid du Colombier 	char *secret, *hkey;
6389a747e4fSDavid du Colombier 	char sbuf[SECRETLEN], hbuf[DESKEYLEN];
6399a747e4fSDavid du Colombier 	uchar chal[CHALLEN];
6409a747e4fSDavid du Colombier 	uchar hash[MShashlen];
6419a747e4fSDavid du Colombier 	uchar hash2[MShashlen];
6429a747e4fSDavid du Colombier 	uchar resp[MSresplen];
6439a747e4fSDavid du Colombier 	OMSchapreply reply;
6443b86f2f8SDavid du Colombier 	int dupe, lmok, ntok;
6459a747e4fSDavid du Colombier 	DigestState *s;
6469a747e4fSDavid du Colombier 	uchar digest[SHA1dlen];
6479a747e4fSDavid du Colombier 
6489a747e4fSDavid du Colombier 	/*
6499a747e4fSDavid du Colombier 	 *  Create a challenge and send it.
6509a747e4fSDavid du Colombier 	 */
6519a747e4fSDavid du Colombier 	randombytes((uchar*)chal, sizeof(chal));
6529a747e4fSDavid du Colombier 	write(1, chal, sizeof(chal));
6539a747e4fSDavid du Colombier 
6549a747e4fSDavid du Colombier 	/*
6559a747e4fSDavid du Colombier 	 *  get chap reply
6569a747e4fSDavid du Colombier 	 */
6579a747e4fSDavid du Colombier 	if(readn(0, &reply, sizeof(reply)) < 0)
6589a747e4fSDavid du Colombier 		exits(0);
6599a747e4fSDavid du Colombier 
6609a747e4fSDavid du Colombier 	safecpy(tr->uid, reply.uid, sizeof(tr->uid));
6619a747e4fSDavid du Colombier 	/*
6629a747e4fSDavid du Colombier 	 * lookup
6639a747e4fSDavid du Colombier 	 */
6649a747e4fSDavid du Colombier 	secret = findsecret(KEYDB, tr->uid, sbuf);
6659a747e4fSDavid du Colombier 	hkey = findkey(KEYDB, tr->hostid, hbuf);
6669a747e4fSDavid du Colombier 	if(hkey == 0 || secret == 0){
6673b86f2f8SDavid du Colombier 		replyerror("mschap-fail bad response %s/%s(%s)",
6683b86f2f8SDavid du Colombier 			tr->uid, tr->hostid, raddr);
6699a747e4fSDavid du Colombier 		logfail(tr->uid);
6709a747e4fSDavid du Colombier 		exits(0);
6719a747e4fSDavid du Colombier 	}
6729a747e4fSDavid du Colombier 
6739a747e4fSDavid du Colombier 	lmhash(hash, secret);
6749a747e4fSDavid du Colombier 	mschalresp(resp, hash, chal);
6759a747e4fSDavid du Colombier 	lmok = memcmp(resp, reply.LMresp, MSresplen) == 0;
6769a747e4fSDavid du Colombier 	nthash(hash, secret);
6779a747e4fSDavid du Colombier 	mschalresp(resp, hash, chal);
6789a747e4fSDavid du Colombier 	ntok = memcmp(resp, reply.NTresp, MSresplen) == 0;
6793b86f2f8SDavid du Colombier 	dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
6809a747e4fSDavid du Colombier 
6813b86f2f8SDavid du Colombier 	/*
6823b86f2f8SDavid du Colombier 	 * It is valid to send the same response in both the LM and NTLM
6833b86f2f8SDavid du Colombier 	 * fields provided one of them is correct, if neither matches,
6843b86f2f8SDavid du Colombier 	 * or the two fields are different and either fails to match,
6853b86f2f8SDavid du Colombier 	 * the whole sha-bang fails.
6863b86f2f8SDavid du Colombier 	 *
6873b86f2f8SDavid du Colombier 	 * This is an improvement in security as it allows clients who
6883b86f2f8SDavid du Colombier 	 * wish to do NTLM auth (which is insecure) not to send
6893b86f2f8SDavid du Colombier 	 * LM tokens (which is very insecure).
6903b86f2f8SDavid du Colombier 	 *
6913b86f2f8SDavid du Colombier 	 * Windows servers supports clients doing this also though
6923b86f2f8SDavid du Colombier 	 * windows clients don't seem to use the feature.
6933b86f2f8SDavid du Colombier 	 */
6943b86f2f8SDavid du Colombier 	if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){
6953b86f2f8SDavid du Colombier 		replyerror("mschap-fail bad response %s/%s(%s) %d,%d,%d",
6963b86f2f8SDavid du Colombier 			tr->uid, tr->hostid, raddr, dupe, lmok, ntok);
6979a747e4fSDavid du Colombier 		logfail(tr->uid);
6989a747e4fSDavid du Colombier 		exits(0);
6999a747e4fSDavid du Colombier 	}
7009a747e4fSDavid du Colombier 
7019a747e4fSDavid du Colombier 	succeed(tr->uid);
7029a747e4fSDavid du Colombier 
7039a747e4fSDavid du Colombier 	/*
7049a747e4fSDavid du Colombier 	 *  reply with ticket & authenticator
7059a747e4fSDavid du Colombier 	 */
7069a747e4fSDavid du Colombier 	if(tickauthreply(tr, hkey) < 0)
7079a747e4fSDavid du Colombier 		exits(0);
7089a747e4fSDavid du Colombier 
7099a747e4fSDavid du Colombier 	if(debug)
7103b86f2f8SDavid du Colombier 		replyerror("mschap-ok %s/%s(%s) %ux",
7113b86f2f8SDavid du Colombier 			tr->uid, tr->hostid, raddr);
7129a747e4fSDavid du Colombier 
7139a747e4fSDavid du Colombier 	nthash(hash, secret);
7149a747e4fSDavid du Colombier 	md4(hash, 16, hash2, 0);
7159a747e4fSDavid du Colombier 	s = sha1(hash2, 16, 0, 0);
7169a747e4fSDavid du Colombier 	sha1(hash2, 16, 0, s);
7179a747e4fSDavid du Colombier 	sha1(chal, 8, digest, s);
7189a747e4fSDavid du Colombier 
7199a747e4fSDavid du Colombier 	if(write(1, digest, 16) < 0)
7209a747e4fSDavid du Colombier 		exits(0);
7219a747e4fSDavid du Colombier }
7229a747e4fSDavid du Colombier 
7239a747e4fSDavid du Colombier void
nthash(uchar hash[MShashlen],char * passwd)7249a747e4fSDavid du Colombier nthash(uchar hash[MShashlen], char *passwd)
7259a747e4fSDavid du Colombier {
7269a747e4fSDavid du Colombier 	uchar buf[512];
7279a747e4fSDavid du Colombier 	int i;
7289a747e4fSDavid du Colombier 
729543f26abSDavid du Colombier 	for (i = 0; *passwd && i + 1 < sizeof(buf);) {
730543f26abSDavid du Colombier 		Rune r;
731543f26abSDavid du Colombier 		passwd += chartorune(&r, passwd);
732543f26abSDavid du Colombier 		buf[i++] = r;
733543f26abSDavid du Colombier 		buf[i++] = r >> 8;
7349a747e4fSDavid du Colombier 	}
7359a747e4fSDavid du Colombier 
7369a747e4fSDavid du Colombier 	memset(hash, 0, 16);
7379a747e4fSDavid du Colombier 
7389a747e4fSDavid du Colombier 	md4(buf, i, hash, 0);
7399a747e4fSDavid du Colombier }
7409a747e4fSDavid du Colombier 
7419a747e4fSDavid du Colombier void
lmhash(uchar hash[MShashlen],char * passwd)7429a747e4fSDavid du Colombier lmhash(uchar hash[MShashlen], char *passwd)
7439a747e4fSDavid du Colombier {
7449a747e4fSDavid du Colombier 	uchar buf[14];
7459a747e4fSDavid du Colombier 	char *stdtext = "KGS!@#$%";
7469a747e4fSDavid du Colombier 	int i;
7479a747e4fSDavid du Colombier 
7489a747e4fSDavid du Colombier 	strncpy((char*)buf, passwd, sizeof(buf));
7499a747e4fSDavid du Colombier 	for(i=0; i<sizeof(buf); i++)
7509a747e4fSDavid du Colombier 		if(buf[i] >= 'a' && buf[i] <= 'z')
7519a747e4fSDavid du Colombier 			buf[i] += 'A' - 'a';
7529a747e4fSDavid du Colombier 
7539a747e4fSDavid du Colombier 	memset(hash, 0, 16);
7549a747e4fSDavid du Colombier 	memcpy(hash, stdtext, 8);
7559a747e4fSDavid du Colombier 	memcpy(hash+8, stdtext, 8);
7569a747e4fSDavid du Colombier 
7579a747e4fSDavid du Colombier 	desencrypt(hash, buf);
7589a747e4fSDavid du Colombier 	desencrypt(hash+8, buf+7);
7599a747e4fSDavid du Colombier }
7609a747e4fSDavid du Colombier 
7619a747e4fSDavid du Colombier void
mschalresp(uchar resp[MSresplen],uchar hash[MShashlen],uchar chal[MSchallen])7629a747e4fSDavid du Colombier mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
7639a747e4fSDavid du Colombier {
7649a747e4fSDavid du Colombier 	int i;
7659a747e4fSDavid du Colombier 	uchar buf[21];
7669a747e4fSDavid du Colombier 
7679a747e4fSDavid du Colombier 	memset(buf, 0, sizeof(buf));
7689a747e4fSDavid du Colombier 	memcpy(buf, hash, MShashlen);
7699a747e4fSDavid du Colombier 
7709a747e4fSDavid du Colombier 	for(i=0; i<3; i++) {
7719a747e4fSDavid du Colombier 		memmove(resp+i*MSchallen, chal, MSchallen);
7729a747e4fSDavid du Colombier 		desencrypt(resp+i*MSchallen, buf+i*7);
7739a747e4fSDavid du Colombier 	}
7749a747e4fSDavid du Colombier }
7759a747e4fSDavid du Colombier 
7769a747e4fSDavid du Colombier void
desencrypt(uchar data[8],uchar key[7])7779a747e4fSDavid du Colombier desencrypt(uchar data[8], uchar key[7])
7789a747e4fSDavid du Colombier {
7799a747e4fSDavid du Colombier 	ulong ekey[32];
7809a747e4fSDavid du Colombier 
7819a747e4fSDavid du Colombier 	key_setup(key, ekey);
7829a747e4fSDavid du Colombier 	block_cipher(ekey, data, 0);
7839a747e4fSDavid du Colombier }
7849a747e4fSDavid du Colombier 
7859a747e4fSDavid du Colombier /*
7869a747e4fSDavid du Colombier  *  return true of the speaker may speak for the user
7879a747e4fSDavid du Colombier  *
7889a747e4fSDavid du Colombier  *  a speaker may always speak for himself/herself
7899a747e4fSDavid du Colombier  */
7909a747e4fSDavid du Colombier int
speaksfor(char * speaker,char * user)7919a747e4fSDavid du Colombier speaksfor(char *speaker, char *user)
7929a747e4fSDavid du Colombier {
7939a747e4fSDavid du Colombier 	Ndbtuple *tp, *ntp;
7949a747e4fSDavid du Colombier 	Ndbs s;
7959a747e4fSDavid du Colombier 	int ok;
7969a747e4fSDavid du Colombier 	char notuser[Maxpath];
7979a747e4fSDavid du Colombier 
7989a747e4fSDavid du Colombier 	if(strcmp(speaker, user) == 0)
7999a747e4fSDavid du Colombier 		return 1;
8009a747e4fSDavid du Colombier 
8019a747e4fSDavid du Colombier 	if(db == 0)
8029a747e4fSDavid du Colombier 		return 0;
8039a747e4fSDavid du Colombier 
8049a747e4fSDavid du Colombier 	tp = ndbsearch(db, &s, "hostid", speaker);
8059a747e4fSDavid du Colombier 	if(tp == 0)
8069a747e4fSDavid du Colombier 		return 0;
8079a747e4fSDavid du Colombier 
8089a747e4fSDavid du Colombier 	ok = 0;
8099a747e4fSDavid du Colombier 	snprint(notuser, sizeof notuser, "!%s", user);
8109a747e4fSDavid du Colombier 	for(ntp = tp; ntp; ntp = ntp->entry)
8119a747e4fSDavid du Colombier 		if(strcmp(ntp->attr, "uid") == 0){
8120833d6c2SDavid du Colombier 			if(strcmp(ntp->val, notuser) == 0){
8130833d6c2SDavid du Colombier 				ok = 0;
8149a747e4fSDavid du Colombier 				break;
8150833d6c2SDavid du Colombier 			}
8169a747e4fSDavid du Colombier 			if(*ntp->val == '*' || strcmp(ntp->val, user) == 0)
8179a747e4fSDavid du Colombier 				ok = 1;
8189a747e4fSDavid du Colombier 		}
8199a747e4fSDavid du Colombier 	ndbfree(tp);
8209a747e4fSDavid du Colombier 	return ok;
8219a747e4fSDavid du Colombier }
8229a747e4fSDavid du Colombier 
8239a747e4fSDavid du Colombier /*
8249a747e4fSDavid du Colombier  *  return an error reply
8259a747e4fSDavid du Colombier  */
8269a747e4fSDavid du Colombier void
replyerror(char * fmt,...)8279a747e4fSDavid du Colombier replyerror(char *fmt, ...)
8289a747e4fSDavid du Colombier {
8299a747e4fSDavid du Colombier 	char buf[AERRLEN+1];
8309a747e4fSDavid du Colombier 	va_list arg;
8319a747e4fSDavid du Colombier 
8329a747e4fSDavid du Colombier 	memset(buf, 0, sizeof(buf));
8339a747e4fSDavid du Colombier 	va_start(arg, fmt);
8349a747e4fSDavid du Colombier 	vseprint(buf + 1, buf + sizeof(buf), fmt, arg);
8359a747e4fSDavid du Colombier 	va_end(arg);
8369a747e4fSDavid du Colombier 	buf[AERRLEN] = 0;
8379a747e4fSDavid du Colombier 	buf[0] = AuthErr;
8389a747e4fSDavid du Colombier 	write(1, buf, AERRLEN+1);
8399a747e4fSDavid du Colombier 	syslog(0, AUTHLOG, buf+1);
8409a747e4fSDavid du Colombier }
8419a747e4fSDavid du Colombier 
8429a747e4fSDavid du Colombier void
getraddr(char * dir)8439a747e4fSDavid du Colombier getraddr(char *dir)
8449a747e4fSDavid du Colombier {
8459a747e4fSDavid du Colombier 	int n;
8469a747e4fSDavid du Colombier 	char *cp;
8479a747e4fSDavid du Colombier 	char file[Maxpath];
8489a747e4fSDavid du Colombier 
8499a747e4fSDavid du Colombier 	raddr[0] = 0;
8509a747e4fSDavid du Colombier 	snprint(file, sizeof(file), "%s/remote", dir);
8519a747e4fSDavid du Colombier 	n = readfile(file, raddr, sizeof(raddr)-1);
8529a747e4fSDavid du Colombier 	if(n < 0)
8539a747e4fSDavid du Colombier 		return;
8549a747e4fSDavid du Colombier 	raddr[n] = 0;
8559a747e4fSDavid du Colombier 
8569a747e4fSDavid du Colombier 	cp = strchr(raddr, '\n');
8579a747e4fSDavid du Colombier 	if(cp)
8589a747e4fSDavid du Colombier 		*cp = 0;
8599a747e4fSDavid du Colombier 	cp = strchr(raddr, '!');
8609a747e4fSDavid du Colombier 	if(cp)
8619a747e4fSDavid du Colombier 		*cp = 0;
8629a747e4fSDavid du Colombier }
8639a747e4fSDavid du Colombier 
8649a747e4fSDavid du Colombier void
mkkey(char * k)8659a747e4fSDavid du Colombier mkkey(char *k)
8669a747e4fSDavid du Colombier {
8679a747e4fSDavid du Colombier 	randombytes((uchar*)k, DESKEYLEN);
8689a747e4fSDavid du Colombier }
8699a747e4fSDavid du Colombier 
8709a747e4fSDavid du Colombier void
randombytes(uchar * buf,int len)8719a747e4fSDavid du Colombier randombytes(uchar *buf, int len)
8729a747e4fSDavid du Colombier {
8739a747e4fSDavid du Colombier 	int i;
8749a747e4fSDavid du Colombier 
8759a747e4fSDavid du Colombier 	if(readfile("/dev/random", (char*)buf, len) >= 0)
8769a747e4fSDavid du Colombier 		return;
8779a747e4fSDavid du Colombier 
8789a747e4fSDavid du Colombier 	for(i = 0; i < len; i++)
8799a747e4fSDavid du Colombier 		buf[i] = rand();
8809a747e4fSDavid du Colombier }
8819a747e4fSDavid du Colombier 
8829a747e4fSDavid du Colombier /*
8839a747e4fSDavid du Colombier  *  reply with ticket and authenticator
8849a747e4fSDavid du Colombier  */
8859a747e4fSDavid du Colombier int
tickauthreply(Ticketreq * tr,char * hkey)8869a747e4fSDavid du Colombier tickauthreply(Ticketreq *tr, char *hkey)
8879a747e4fSDavid du Colombier {
8889a747e4fSDavid du Colombier 	Ticket t;
8899a747e4fSDavid du Colombier 	Authenticator a;
8909a747e4fSDavid du Colombier 	char buf[TICKETLEN+AUTHENTLEN+1];
8919a747e4fSDavid du Colombier 
8929a747e4fSDavid du Colombier 	memset(&t, 0, sizeof(t));
8939a747e4fSDavid du Colombier 	memmove(t.chal, tr->chal, CHALLEN);
8949a747e4fSDavid du Colombier 	safecpy(t.cuid, tr->uid, sizeof t.cuid);
8959a747e4fSDavid du Colombier 	safecpy(t.suid, tr->uid, sizeof t.suid);
8969a747e4fSDavid du Colombier 	mkkey(t.key);
8979a747e4fSDavid du Colombier 	buf[0] = AuthOK;
8989a747e4fSDavid du Colombier 	t.num = AuthTs;
8999a747e4fSDavid du Colombier 	convT2M(&t, buf+1, hkey);
9009a747e4fSDavid du Colombier 	memmove(a.chal, t.chal, CHALLEN);
9019a747e4fSDavid du Colombier 	a.num = AuthAc;
9029a747e4fSDavid du Colombier 	a.id = 0;
9039a747e4fSDavid du Colombier 	convA2M(&a, buf+TICKETLEN+1, t.key);
9049a747e4fSDavid du Colombier 	if(write(1, buf, TICKETLEN+AUTHENTLEN+1) < 0)
9059a747e4fSDavid du Colombier 		return -1;
9069a747e4fSDavid du Colombier 	return 0;
9079a747e4fSDavid du Colombier }
9089a747e4fSDavid du Colombier 
9099a747e4fSDavid du Colombier void
safecpy(char * to,char * from,int len)9109a747e4fSDavid du Colombier safecpy(char *to, char *from, int len)
9119a747e4fSDavid du Colombier {
9129a747e4fSDavid du Colombier 	strncpy(to, from, len);
9139a747e4fSDavid du Colombier 	to[len-1] = 0;
9149a747e4fSDavid du Colombier }
915