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