void main(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 */ }
AuthInfo* p9any(int fd) { char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u; char *pass; char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN]; char authkey[DESKEYLEN]; Authenticator auth; int afd, i, n, v2; Ticketreq tr; Ticket t; AuthInfo *ai; if((afd = open("/mnt/factotum/ctl", ORDWR)) >= 0) return p9anyfactotum(fd, afd); if(readstr(fd, buf, sizeof buf) < 0) fatal(1, "cannot read p9any negotiation"); bbuf = buf; v2 = 0; if(strncmp(buf, "v.2 ", 4) == 0){ v2 = 1; bbuf += 4; } if((p = strchr(bbuf, ' '))) *p = 0; p = bbuf; if((dom = strchr(p, '@')) == nil) fatal(1, "bad p9any domain"); *dom++ = 0; if(strcmp(p, "p9sk1") != 0) fatal(1, "server did not offer p9sk1"); sprint(buf2, "%s %s", p, dom); if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1) fatal(1, "cannot write user/domain choice in p9any"); if(v2){ if(readstr(fd, buf, sizeof buf) != 3) fatal(1, "cannot read OK in p9any"); if(memcmp(buf, "OK\0", 3) != 0) fatal(1, "did not get OK in p9any"); } for(i=0; i<CHALLEN; i++) cchal[i] = fastrand(); if(write(fd, cchal, 8) != 8) fatal(1, "cannot write p9sk1 challenge"); if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN) fatal(1, "cannot read ticket request in p9sk1"); convM2TR(trbuf, &tr); u = user; pass = findkey(&u, tr.authdom); if(pass == nil) again: pass = getkey(u, tr.authdom); if(pass == nil) fatal(1, "no password"); passtokey(authkey, pass); memset(pass, 0, strlen(pass)); tr.type = AuthTreq; strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u); strecpy(tr.uid, tr.uid+sizeof tr.uid, u); convTR2M(&tr, trbuf); if(gettickets(&tr, authkey, trbuf, tbuf) < 0) fatal(1, "cannot get auth tickets in p9sk1"); convM2T(tbuf, &t, authkey); if(t.num != AuthTc){ print("?password mismatch with auth server\n"); goto again; } memmove(tbuf, tbuf+TICKETLEN, TICKETLEN); auth.num = AuthAc; memmove(auth.chal, tr.chal, CHALLEN); auth.id = 0; convA2M(&auth, tbuf+TICKETLEN, t.key); if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN) fatal(1, "cannot send ticket and authenticator back in p9sk1"); if((n=readn(fd, tbuf, AUTHENTLEN)) != AUTHENTLEN || memcmp(tbuf, "cpu:", 4) == 0){ if(n <= 4) fatal(1, "cannot read authenticator in p9sk1"); /* * didn't send back authenticator: * sent back fatal error message. */ memmove(buf, tbuf, n); i = readn(fd, buf+n, sizeof buf-n-1); if(i > 0) n += i; buf[n] = 0; werrstr(""); fatal(0, "server says: %s", buf); } convM2A(tbuf, &auth, t.key); if(auth.num != AuthAs || memcmp(auth.chal, cchal, CHALLEN) != 0 || auth.id != 0){ print("?you and auth server agree about password.\n"); print("?server is confused.\n"); fatal(0, "server lies got %llux.%d want %llux.%d", *(int64_t*)auth.chal, auth.id, *(int64_t*)cchal, 0); } //print("i am %s there.\n", t.suid); ai = mallocz(sizeof(AuthInfo), 1); ai->secret = mallocz(8, 1); des56to64((uint8_t*)t.key, ai->secret); ai->nsecret = 8; ai->suid = strdup(t.suid); ai->cuid = strdup(t.cuid); memset(authkey, 0, sizeof authkey); return ai; }
void apop(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; continue; } break; } succeed(tr->uid); /* * reply with ticket & authenticator */ if(tickauthreply(tr, hkey) < 0) exits(0); if(debug){ if(type == AuthCram) syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr); else syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr); } }