📄 authsrv.c
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <ndb.h>#include <regexp.h>#include <mp.h>#include <libsec.h>#include <authsrv.h>#include "authcmdlib.h"int debug;Ndb *db;char raddr[128];/* Microsoft auth constants */enum { MShashlen = 16, MSchallen = 8, MSresplen = 24,};int ticketrequest(Ticketreq*);void challengebox(Ticketreq*);void changepasswd(Ticketreq*);void apop(Ticketreq*, int);void chap(Ticketreq*);void mschap(Ticketreq*);void http(Ticketreq*);void vnc(Ticketreq*);int speaksfor(char*, char*);void replyerror(char*, ...);void getraddr(char*);void mkkey(char*);void randombytes(uchar*, int);void nthash(uchar hash[MShashlen], char *passwd);void lmhash(uchar hash[MShashlen], char *passwd);void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);void desencrypt(uchar data[8], uchar key[7]);int tickauthreply(Ticketreq*, char*);void safecpy(char*, char*, int);voidmain(int argc, char *argv[]){ char buf[TICKREQLEN]; Ticketreq tr; ARGBEGIN{ case 'd': debug++; }ARGEND strcpy(raddr, "unknown"); if(argc >= 1) getraddr(argv[argc-1]); alarm(10*60*1000); /* kill a connection after 10 minutes */ db = ndbopen("/lib/ndb/auth"); if(db == 0) syslog(0, AUTHLOG, "no /lib/ndb/auth"); srand(time(0)*getpid()); for(;;){ if(readn(0, buf, TICKREQLEN) <= 0) exits(0); convM2TR(buf, &tr); switch(buf[0]){ 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); break; case AuthCram: apop(&tr, AuthCram); break; case AuthHttp: http(&tr); break; case AuthVNC: vnc(&tr); break; default: syslog(0, AUTHLOG, "unknown ticket request type: %d", buf[0]); exits(0); } } /* not reached */}intticketrequest(Ticketreq *tr){ char akey[DESKEYLEN]; char hkey[DESKEYLEN]; Ticket t; char tbuf[2*TICKETLEN+1]; if(findkey(KEYDB, tr->authid, akey) == 0){ /* make one up so caller doesn't know it was wrong */ mkkey(akey); if(debug) syslog(0, AUTHLOG, "tr-fail authid %s", raddr); } if(findkey(KEYDB, tr->hostid, hkey) == 0){ /* make one up so caller doesn't know it was wrong */ mkkey(hkey); if(debug) syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr); } memset(&t, 0, sizeof(t)); memmove(t.chal, tr->chal, CHALLEN); strcpy(t.cuid, tr->uid); if(speaksfor(tr->hostid, tr->uid)) strcpy(t.suid, tr->uid); else { mkkey(akey); mkkey(hkey); if(debug) syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for", tr->uid, tr->hostid, raddr, tr->uid, tr->authid); } mkkey(t.key); tbuf[0] = AuthOK; t.num = AuthTc; convT2M(&t, tbuf+1, hkey); t.num = AuthTs; convT2M(&t, tbuf+1+TICKETLEN, akey); if(write(1, tbuf, 2*TICKETLEN+1) < 0){ if(debug) syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup", tr->uid, tr->hostid, raddr); exits(0); } if(debug) syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s", tr->uid, tr->hostid, raddr, tr->uid, tr->authid); return 0;}voidchallengebox(Ticketreq *tr){ long chal; char *key, *netkey; char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], hkey[DESKEYLEN]; char buf[NETCHLEN+1]; char *err; key = findkey(KEYDB, tr->uid, kbuf); netkey = findkey(NETKEYDB, tr->uid, nkbuf); if(key == 0 && netkey == 0){ /* make one up so caller doesn't know it was wrong */ mkkey(nkbuf); netkey = nkbuf; if(debug) syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr); } if(findkey(KEYDB, tr->hostid, hkey) == 0){ /* make one up so caller doesn't know it was wrong */ mkkey(hkey); if(debug) 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 = lnrand(MAXNETCHAL); sprint(buf+1, "%lud", chal); if(write(1, buf, NETCHLEN+1) < 0) exits(0); if(readn(0, buf, NETCHLEN) < 0) exits(0); if(!(key && netcheck(key, chal, buf)) && !(netkey && netcheck(netkey, chal, buf)) && (err = secureidcheck(tr->uid, buf)) != nil){ replyerror("cr-fail %s %s %s", err, tr->uid, raddr); logfail(tr->uid); if(debug) syslog(0, AUTHLOG, "cr-fail %s@%s(%s): bad resp", tr->uid, tr->hostid, raddr); return; } succeed(tr->uid); /* * reply with ticket & authenticator */ if(tickauthreply(tr, hkey) < 0){ if(debug) syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup", tr->uid, tr->hostid, raddr); exits(0); } if(debug) syslog(0, AUTHLOG, "cr-ok %s@%s(%s)", tr->uid, tr->hostid, raddr);}voidchangepasswd(Ticketreq *tr){ Ticket t; char tbuf[TICKETLEN+1]; char prbuf[PASSREQLEN]; Passwordreq pr; char okey[DESKEYLEN], nkey[DESKEYLEN]; char *err; if(findkey(KEYDB, tr->uid, okey) == 0){ /* make one up so caller doesn't know it was wrong */ mkkey(okey); syslog(0, AUTHLOG, "cp-fail uid %s", raddr); } /* send back a ticket with a new key */ memmove(t.chal, tr->chal, CHALLEN); mkkey(t.key); tbuf[0] = AuthOK; t.num = AuthTp; safecpy(t.cuid, tr->uid, sizeof(t.cuid)); safecpy(t.suid, tr->uid, sizeof(t.suid)); convT2M(&t, tbuf+1, okey); write(1, tbuf, sizeof(tbuf)); /* loop trying passwords out */ for(;;){ if(readn(0, prbuf, PASSREQLEN) < 0) exits(0); convM2PR(prbuf, &pr, t.key); if(pr.num != AuthPass){ replyerror("protocol botch1: %s", raddr); exits(0); } passtokey(nkey, pr.old); if(memcmp(nkey, okey, DESKEYLEN)){ replyerror("protocol botch2: %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; } break; } prbuf[0] = AuthOK; write(1, prbuf, 1); succeed(tr->uid); return;}voidhttp(Ticketreq *tr){ Ticket t; char tbuf[TICKETLEN+1]; char key[DESKEYLEN]; char *p; Biobuf *b; int n; n = strlen(tr->uid); b = Bopen("/sys/lib/httppasswords", OREAD); if(b == nil){ replyerror("no password file", raddr); return; } /* find key */ for(;;){ p = Brdline(b, '\n'); if(p == nil) break; p[Blinelen(b)-1] = 0; if(strncmp(p, tr->uid, n) == 0) if(p[n] == ' ' || p[n] == '\t'){ p += n; break; } } Bterm(b); if(p == nil) { randombytes((uchar*)key, DESKEYLEN); } else { while(*p == ' ' || *p == '\t') p++; passtokey(key, p); } /* send back a ticket encrypted with the key */ randombytes((uchar*)t.chal, CHALLEN); mkkey(t.key); tbuf[0] = AuthOK; t.num = AuthHr; safecpy(t.cuid, tr->uid, sizeof(t.cuid)); safecpy(t.suid, tr->uid, sizeof(t.suid)); convT2M(&t, tbuf+1, key); write(1, tbuf, sizeof(tbuf));}static char*domainname(void){ static char sysname[Maxpath]; static char *domain; int n; if(domain) return domain; if(*sysname) return sysname; domain = csgetvalue(0, "sys", sysname, "dom", nil); if(domain) 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, tries; char *secret, *hkey, *p; Ticketreq treq; DigestState *s; char sbuf[SECRETLEN], hbuf[DESKEYLEN]; char tbuf[TICKREQLEN]; char buf[MD5dlen*2]; uchar digest[MD5dlen], resp[MD5dlen]; ulong rb[4]; char chal[256]; USED(tr); /* * Create a challenge and send it. */ randombytes((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); /* give user a few attempts */ for(tries = 0; ; tries++) { /* * get ticket request */ if(readn(0, tbuf, TICKREQLEN) < 0) exits(0); convM2TR(tbuf, &treq); tr = &treq; if(tr->type != type) exits(0); /* * read response */ if(readn(0, buf, MD5dlen*2) < 0) 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); hkey = findkey(KEYDB, tr->hostid, hbuf); if(hkey == 0 || secret == 0){ replyerror("apop-fail bad response %s", raddr); logfail(tr->uid); if(tries > 5) return; continue; } /* * 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(memcmp(digest, resp, MD5dlen) != 0){ replyerror("apop-fail bad response %s", raddr); logfail(tr->uid); if(tries > 5) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -