1189 lines · 25.7 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <bio.h>#include <ndb.h>#include <regexp.h>#include <libsec.h>#include <authsrv.h>#include "authcmdlib.h" Ndb *db;char raddr[128];uchar zeros[32]; typedef struct Keyslot Keyslot;struct Keyslot{	Authkey;	char	id[ANAMELEN];};Keyslot hkey, akey, ukey;uchar keyseed[SHA2_256dlen]; char ticketform; /* Microsoft auth constants */enum {	MShashlen = 16,	MSchallen = 8,	MSresplen = 24,	MSchallenv2 = 16,}; void	pak(Ticketreq*);void	ticketrequest(Ticketreq*);void	challengebox(Ticketreq*);void	changepasswd(Ticketreq*);void	apop(Ticketreq*, int);void	chap(Ticketreq*);void	ntlm(Ticketreq*);void	mschap(Ticketreq*, int);void	vnc(Ticketreq*);int	speaksfor(char*, char*);void	replyerror(char*, ...);void	getraddr(char*);void	initkeyseed(void);void	mkkey(char*, Authkey*);void	mkticket(Ticketreq*, Ticket*);void	nthash(uchar hash[MShashlen], char *passwd);void	lmhash(uchar hash[MShashlen], char *passwd);void	ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom);void	mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);void	desencrypt(uchar data[8], uchar key[7]);void	tickauthreply(Ticketreq*, Authkey*);void	tickauthreply2(Ticketreq*, Authkey*, uchar *, int, uchar *, int);void	safecpy(char*, char*, int);void	catch(void*, char*); voidmain(int argc, char *argv[]){	char buf[TICKREQLEN];	Ticketreq tr;	int n; 	ARGBEGIN{	case 'N':		ticketform = 1;		break;	}ARGEND 	strcpy(raddr, "unknown");	if(argc >= 1)		getraddr(argv[argc-1]); 	alarm(10*60*1000);	/* kill a connection after 10 minutes */ 	private();	initkeyseed(); 	db = ndbopen("/lib/ndb/auth");	if(db == 0)		syslog(0, AUTHLOG, "no /lib/ndb/auth"); 	for(;;){		n = readn(0, buf, sizeof(buf));		if(n <= 0 || convM2TR(buf, n, &tr) <= 0)			exits(0);		switch(tr.type){		case AuthTreq:			ticketrequest(&tr);			break;		case AuthChal:			challengebox(&tr);			break;		case AuthPass:			changepasswd(&tr);			break;		case AuthApop:			apop(&tr, AuthApop);			break;		case AuthChap:			chap(&tr);			break;		case AuthMSchap:			mschap(&tr, MSchallen);			break;		case AuthMSchapv2:			mschap(&tr, MSchallenv2);			break;		case AuthNTLM:			ntlm(&tr);			break;		case AuthCram:			apop(&tr, AuthCram);			break;		case AuthVNC:			vnc(&tr);			break;		case AuthPAK:			pak(&tr);			continue;		default:			syslog(0, AUTHLOG, "unknown ticket request type: %d", tr.type);			exits(0);		}		/* invalidate pak keys */		akey.id[0] = 0;		hkey.id[0] = 0;		ukey.id[0] = 0;	}	/* not reached */} voidpak1(char *u, Keyslot *k){	uchar y[PAKYLEN];	PAKpriv p; 	safecpy(k->id, u, sizeof(k->id));	if(!findkey(KEYDB, k->id, k) || tsmemcmp(k->aes, zeros, AESKEYLEN) == 0) {		syslog(0, AUTHLOG, "pak-fail no AES key for id %s", k->id);		/* make one up so caller doesn't know it was wrong */		mkkey(k->id, k);		authpak_hash(k, k->id);	}	authpak_new(&p, k, y, 0);	if(write(1, y, PAKYLEN) != PAKYLEN)		exits(0);	if(readn(0, y, PAKYLEN) != PAKYLEN)		exits(0);	if(authpak_finish(&p, k, y))		exits(0);} voidpak(Ticketreq *tr){	static uchar ok[1] = {AuthOK}; 	if(write(1, ok, 1) != 1)		exits(0); 	/* invalidate pak keys */	akey.id[0] = 0;	hkey.id[0] = 0;	ukey.id[0] = 0; 	if(tr->hostid[0]) {		if(tr->authid[0])			pak1(tr->authid, &akey);		pak1(tr->hostid, &hkey);	} else if(tr->uid[0]) {		pak1(tr->uid, &ukey);	} 	ticketform = 1;} intgetkey(char *u, Keyslot *k){	/* empty user id is an error */	if(*u == 0)		exits(0); 	if(k == &hkey && strcmp(u, k->id) == 0)		return 1;	if(k == &akey && strcmp(u, k->id) == 0)		return 1;	if(k == &ukey && strcmp(u, k->id) == 0)		return 1; 	if(ticketform != 0){		syslog(0, AUTHLOG, "need DES key for %s, but DES is disabled", u);		replyerror("DES is disabled");		exits(0);	} 	return findkey(KEYDB, u, k);} voidticketrequest(Ticketreq *tr){	char tbuf[2*MAXTICKETLEN+1];	Ticket t;	int n; 	if(tr->uid[0] == 0)		exits(0);	if(!getkey(tr->authid, &akey)){		/* make one up so caller doesn't know it was wrong */		mkkey(tr->authid, &akey);		syslog(0, AUTHLOG, "tr-fail authid %s", tr->authid);	}	if(!getkey(tr->hostid, &hkey)){		/* make one up so caller doesn't know it was wrong */		mkkey(tr->hostid, &hkey);		syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr);	}	mkticket(tr, &t);	if(!speaksfor(tr->hostid, tr->uid)){		mkkey(tr->authid, &akey);		mkkey(tr->hostid, &hkey);		syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",			tr->uid, tr->hostid, raddr, tr->uid, tr->authid);	}	n = 0;	tbuf[n++] = AuthOK;	t.num = AuthTc;	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &hkey);	t.num = AuthTs;	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &akey);	if(write(1, tbuf, n) != n)		exits(0); 	syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s", tr->uid, tr->hostid, raddr, tr->uid, tr->authid);} voidchallengebox(Ticketreq *tr){	char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], buf[NETCHLEN+1];	char *key, *netkey, *err;	long chal; 	if(tr->uid[0] == 0)		exits(0);	key = finddeskey(KEYDB, tr->uid, kbuf);	netkey = finddeskey(NETKEYDB, tr->uid, nkbuf);	if(key == nil && netkey == nil){		/* make one up so caller doesn't know it was wrong */		genrandom((uchar*)nkbuf, DESKEYLEN);		netkey = nkbuf;		syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr);	} 	if(!getkey(tr->hostid, &hkey)){		/* make one up so caller doesn't know it was wrong */		mkkey(tr->hostid, &hkey);		syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid, tr->uid, raddr);	} 	/*	 * challenge-response	 */	memset(buf, 0, sizeof(buf));	buf[0] = AuthOK;	chal = nfastrand(MAXNETCHAL);	sprint(buf+1, "%lud", chal);	if(write(1, buf, NETCHLEN+1) != NETCHLEN+1)		exits(0);	if(readn(0, buf, NETCHLEN) != NETCHLEN)		exits(0);	if(!(key != nil && netcheck(key, chal, buf))	&& !(netkey != nil && netcheck(netkey, chal, buf))	&& (err = secureidcheck(tr->uid, buf)) != nil){		replyerror("cr-fail %s %s %s", err, tr->uid, raddr);		logfail(tr->uid);		return;	}	succeed(tr->uid); 	/*	 *  reply with ticket & authenticator	 */	tickauthreply(tr, &hkey); 	syslog(0, AUTHLOG, "cr-ok %s@%s(%s)", tr->uid, tr->hostid, raddr);} voidchangepasswd(Ticketreq *tr){	char tbuf[MAXTICKETLEN+1], prbuf[MAXPASSREQLEN], *err;	Passwordreq pr;	Authkey nkey;	Ticket t;	int n, m; 	if(!getkey(tr->uid, &ukey)){		/* make one up so caller doesn't know it was wrong */		mkkey(tr->uid, &ukey);		syslog(0, AUTHLOG, "cp-fail uid %s@%s", tr->uid, raddr);	} 	/* send back a ticket with a new key */	mkticket(tr, &t);	t.num = AuthTp;	n = 0;	tbuf[n++] = AuthOK;	n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &ukey);	if(write(1, tbuf, n) != n)		exits(0); 	/* loop trying passwords out */	for(;;){		for(n=0; (m = convM2PR(prbuf, n, &pr, &t)) <= 0; n += m){			m = -m;			if(m <= n || m > sizeof(prbuf))				exits(0);			m -= n;			if(readn(0, prbuf+n, m) != m)				exits(0);		}		if(pr.num != AuthPass){			replyerror("protocol botch1: %s", raddr);			exits(0);		}		passtokey(&nkey, pr.old);		if(tsmemcmp(ukey.des, nkey.des, DESKEYLEN) != 0){			replyerror("protocol botch2: %s", raddr);			continue;		}		if(tsmemcmp(ukey.aes, zeros, AESKEYLEN) != 0 && tsmemcmp(ukey.aes, nkey.aes, AESKEYLEN) != 0){			replyerror("protocol botch3: %s", raddr);			continue;		}		if(*pr.new){			err = okpasswd(pr.new);			if(err){				replyerror("%s %s", err, raddr);				continue;			}			passtokey(&nkey, pr.new);		}		if(pr.changesecret && setsecret(KEYDB, tr->uid, pr.secret) == 0){			replyerror("can't write secret %s", raddr);			continue;		}		if(*pr.new && setkey(KEYDB, tr->uid, &nkey) == 0){			replyerror("can't write key %s", raddr);			continue;		}		memmove(ukey.des, nkey.des, DESKEYLEN);		memmove(ukey.aes, nkey.aes, AESKEYLEN);		break;	}	succeed(tr->uid); 	prbuf[0] = AuthOK;	if(write(1, prbuf, 1) != 1)		exits(0);} static char*domainname(void){	static char sysname[Maxpath];	static char *domain;	int n; 	if(domain != nil)		return domain;	if(*sysname)		return sysname; 	domain = csgetvalue(0, "sys", sysname, "dom", nil);	if(domain != nil)		return domain; 	n = readfile("/dev/sysname", sysname, sizeof(sysname)-1);	if(n < 0){		strcpy(sysname, "kremvax");		return sysname;	}	sysname[n] = 0; 	return sysname;} static inth2b(char c){	if(c >= '0' && c <= '9')		return c - '0';	if(c >= 'A' && c <= 'F')		return c - 'A' + 10;	if(c >= 'a' && c <= 'f')		return c - 'a' + 10;	return 0;} voidapop(Ticketreq *tr, int type){	int challen, i, n, tries;	char *secret, *p;	Ticketreq treq;	DigestState *s;	char sbuf[SECRETLEN];	char trbuf[TICKREQLEN];	char buf[MD5dlen*2];	uchar digest[MD5dlen], resp[MD5dlen];	ulong rb[4];	char chal[256]; 	USED(tr); 	/*	 *  Create a challenge and send it.	 */	genrandom((uchar*)rb, sizeof(rb));	p = chal;	p += snprint(p, sizeof(chal), "<%lux%lux.%lux%lux@%s>",		rb[0], rb[1], rb[2], rb[3], domainname());	challen = p - chal;	print("%c%-5d%s", AuthOKvar, challen, chal); 	tries = 5;Retry:	if(--tries < 0)		exits(0); 	/*	 *  get ticket request	 */	n = readn(0, trbuf, sizeof(trbuf));	if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0)		exits(0);	tr = &treq;	if(tr->type != type || tr->uid[0] == 0)		exits(0); 	/*	 * read response	 */	if(readn(0, buf, MD5dlen*2) != MD5dlen*2)		exits(0);	for(i = 0; i < MD5dlen; i++)		resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]); 	/*	 * lookup	 */	secret = findsecret(KEYDB, tr->uid, sbuf);	if(!getkey(tr->hostid, &hkey) || secret == nil){		replyerror("apop-fail bad response %s", raddr);		goto Retry;	} 	/*	 *  check for match	 */	if(type == AuthCram){		hmac_md5((uchar*)chal, challen,			(uchar*)secret, strlen(secret),			digest, nil);	} else {		s = md5((uchar*)chal, challen, 0, 0);		md5((uchar*)secret, strlen(secret), digest, s);	}	if(tsmemcmp(digest, resp, MD5dlen) != 0){		replyerror("apop-fail bad response %s", raddr);		logfail(tr->uid);		goto Retry;	} 	succeed(tr->uid); 	/*	 *  reply with ticket & authenticator	 */	tickauthreply(tr, &hkey); 	if(type == AuthCram)		syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr);	else		syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr);} enum {	VNCchallen=	16,}; /* VNC reverses the bits of each byte before using as a des key */uchar swizzletab[256] = { 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x8, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,

Lines 1–500 of 1189.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t