authsrv.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <ndb.h>
  13. #include <regexp.h>
  14. #include <mp.h>
  15. #include <libsec.h>
  16. #include <authsrv.h>
  17. #include "authcmdlib.h"
  18. int debug;
  19. Ndb *db;
  20. char raddr[128];
  21. /* Microsoft auth constants */
  22. enum {
  23. MShashlen = 16,
  24. MSchallen = 8,
  25. MSresplen = 24,
  26. };
  27. int ticketrequest(Ticketreq*);
  28. void challengebox(Ticketreq*);
  29. void changepasswd(Ticketreq*);
  30. void apop(Ticketreq*, int);
  31. void chap(Ticketreq*);
  32. void mschap(Ticketreq*);
  33. void http(Ticketreq*);
  34. void vnc(Ticketreq*);
  35. int speaksfor(char*, char*);
  36. void replyerror(char*, ...);
  37. void getraddr(char*);
  38. void mkkey(char*);
  39. void randombytes(uint8_t*, int);
  40. void nthash(uint8_t hash[MShashlen], char *passwd);
  41. void lmhash(uint8_t hash[MShashlen], char *passwd);
  42. void mschalresp(uint8_t resp[MSresplen], uint8_t hash[MShashlen],
  43. uint8_t chal[MSchallen]);
  44. void desencrypt(uint8_t data[8], uint8_t key[7]);
  45. int tickauthreply(Ticketreq*, char*);
  46. void safecpy(char*, char*, int);
  47. void
  48. main(int argc, char *argv[])
  49. {
  50. char buf[TICKREQLEN];
  51. Ticketreq tr;
  52. ARGBEGIN{
  53. case 'd':
  54. debug++;
  55. }ARGEND
  56. strcpy(raddr, "unknown");
  57. if(argc >= 1)
  58. getraddr(argv[argc-1]);
  59. alarm(10*60*1000); /* kill a connection after 10 minutes */
  60. db = ndbopen("/lib/ndb/auth");
  61. if(db == 0)
  62. syslog(0, AUTHLOG, "no /lib/ndb/auth");
  63. srand(time(0)*getpid());
  64. for(;;){
  65. if(readn(0, buf, TICKREQLEN) <= 0)
  66. exits(0);
  67. convM2TR(buf, &tr);
  68. switch(buf[0]){
  69. case AuthTreq:
  70. ticketrequest(&tr);
  71. break;
  72. case AuthChal:
  73. challengebox(&tr);
  74. break;
  75. case AuthPass:
  76. changepasswd(&tr);
  77. break;
  78. case AuthApop:
  79. apop(&tr, AuthApop);
  80. break;
  81. case AuthChap:
  82. chap(&tr);
  83. break;
  84. case AuthMSchap:
  85. mschap(&tr);
  86. break;
  87. case AuthCram:
  88. apop(&tr, AuthCram);
  89. break;
  90. case AuthHttp:
  91. http(&tr);
  92. break;
  93. case AuthVNC:
  94. vnc(&tr);
  95. break;
  96. default:
  97. syslog(0, AUTHLOG, "unknown ticket request type: %d", buf[0]);
  98. exits(0);
  99. }
  100. }
  101. /* not reached */
  102. }
  103. int
  104. ticketrequest(Ticketreq *tr)
  105. {
  106. char akey[DESKEYLEN];
  107. char hkey[DESKEYLEN];
  108. Ticket t;
  109. char tbuf[2*TICKETLEN+1];
  110. if(findkey(KEYDB, tr->authid, akey) == 0){
  111. /* make one up so caller doesn't know it was wrong */
  112. mkkey(akey);
  113. if(debug)
  114. syslog(0, AUTHLOG, "tr-fail authid %s", raddr);
  115. }
  116. if(findkey(KEYDB, tr->hostid, hkey) == 0){
  117. /* make one up so caller doesn't know it was wrong */
  118. mkkey(hkey);
  119. if(debug)
  120. syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr);
  121. }
  122. memset(&t, 0, sizeof(t));
  123. memmove(t.chal, tr->chal, CHALLEN);
  124. strcpy(t.cuid, tr->uid);
  125. if(speaksfor(tr->hostid, tr->uid))
  126. strcpy(t.suid, tr->uid);
  127. else {
  128. mkkey(akey);
  129. mkkey(hkey);
  130. if(debug)
  131. syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",
  132. tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
  133. }
  134. mkkey(t.key);
  135. tbuf[0] = AuthOK;
  136. t.num = AuthTc;
  137. convT2M(&t, tbuf+1, hkey);
  138. t.num = AuthTs;
  139. convT2M(&t, tbuf+1+TICKETLEN, akey);
  140. if(write(1, tbuf, 2*TICKETLEN+1) < 0){
  141. if(debug)
  142. syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup",
  143. tr->uid, tr->hostid, raddr);
  144. exits(0);
  145. }
  146. if(debug)
  147. syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s",
  148. tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
  149. return 0;
  150. }
  151. void
  152. challengebox(Ticketreq *tr)
  153. {
  154. int32_t chal;
  155. char *key, *netkey;
  156. char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], hkey[DESKEYLEN];
  157. char buf[NETCHLEN+1];
  158. char *err;
  159. key = findkey(KEYDB, tr->uid, kbuf);
  160. netkey = findkey(NETKEYDB, tr->uid, nkbuf);
  161. if(key == 0 && netkey == 0){
  162. /* make one up so caller doesn't know it was wrong */
  163. mkkey(nkbuf);
  164. netkey = nkbuf;
  165. if(debug)
  166. syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr);
  167. }
  168. if(findkey(KEYDB, tr->hostid, hkey) == 0){
  169. /* make one up so caller doesn't know it was wrong */
  170. mkkey(hkey);
  171. if(debug)
  172. syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid,
  173. tr->uid, raddr);
  174. }
  175. /*
  176. * challenge-response
  177. */
  178. memset(buf, 0, sizeof(buf));
  179. buf[0] = AuthOK;
  180. chal = lnrand(MAXNETCHAL);
  181. snprint(buf+1, sizeof buf - 1, "%lu", chal);
  182. if(write(1, buf, NETCHLEN+1) < 0)
  183. exits(0);
  184. if(readn(0, buf, NETCHLEN) < 0)
  185. exits(0);
  186. if(!(key && netcheck(key, chal, buf))
  187. && !(netkey && netcheck(netkey, chal, buf))
  188. && (err = secureidcheck(tr->uid, buf)) != nil){
  189. replyerror("cr-fail %s %s %s", err, tr->uid, raddr);
  190. logfail(tr->uid);
  191. if(debug)
  192. syslog(0, AUTHLOG, "cr-fail %s@%s(%s): bad resp",
  193. tr->uid, tr->hostid, raddr);
  194. return;
  195. }
  196. succeed(tr->uid);
  197. /*
  198. * reply with ticket & authenticator
  199. */
  200. if(tickauthreply(tr, hkey) < 0){
  201. if(debug)
  202. syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup",
  203. tr->uid, tr->hostid, raddr);
  204. exits(0);
  205. }
  206. if(debug)
  207. syslog(0, AUTHLOG, "cr-ok %s@%s(%s)",
  208. tr->uid, tr->hostid, raddr);
  209. }
  210. void
  211. changepasswd(Ticketreq *tr)
  212. {
  213. Ticket t;
  214. char tbuf[TICKETLEN+1];
  215. char prbuf[PASSREQLEN];
  216. Passwordreq pr;
  217. char okey[DESKEYLEN], nkey[DESKEYLEN];
  218. char *err;
  219. if(findkey(KEYDB, tr->uid, okey) == 0){
  220. /* make one up so caller doesn't know it was wrong */
  221. mkkey(okey);
  222. syslog(0, AUTHLOG, "cp-fail uid %s", raddr);
  223. }
  224. /* send back a ticket with a new key */
  225. memmove(t.chal, tr->chal, CHALLEN);
  226. mkkey(t.key);
  227. tbuf[0] = AuthOK;
  228. t.num = AuthTp;
  229. safecpy(t.cuid, tr->uid, sizeof(t.cuid));
  230. safecpy(t.suid, tr->uid, sizeof(t.suid));
  231. convT2M(&t, tbuf+1, okey);
  232. write(1, tbuf, sizeof(tbuf));
  233. /* loop trying passwords out */
  234. for(;;){
  235. if(readn(0, prbuf, PASSREQLEN) < 0)
  236. exits(0);
  237. convM2PR(prbuf, &pr, t.key);
  238. if(pr.num != AuthPass){
  239. replyerror("protocol botch1: %s", raddr);
  240. exits(0);
  241. }
  242. passtokey(nkey, pr.old);
  243. if(memcmp(nkey, okey, DESKEYLEN)){
  244. replyerror("protocol botch2: %s", raddr);
  245. continue;
  246. }
  247. if(*pr.new){
  248. err = okpasswd(pr.new);
  249. if(err){
  250. replyerror("%s %s", err, raddr);
  251. continue;
  252. }
  253. passtokey(nkey, pr.new);
  254. }
  255. if(pr.changesecret && setsecret(KEYDB, tr->uid, pr.secret) == 0){
  256. replyerror("can't write secret %s", raddr);
  257. continue;
  258. }
  259. if(*pr.new && setkey(KEYDB, tr->uid, nkey) == 0){
  260. replyerror("can't write key %s", raddr);
  261. continue;
  262. }
  263. break;
  264. }
  265. prbuf[0] = AuthOK;
  266. write(1, prbuf, 1);
  267. succeed(tr->uid);
  268. return;
  269. }
  270. void
  271. http(Ticketreq *tr)
  272. {
  273. Ticket t;
  274. char tbuf[TICKETLEN+1];
  275. char key[DESKEYLEN];
  276. char *p;
  277. Biobuf *b;
  278. int n;
  279. n = strlen(tr->uid);
  280. b = Bopen("/sys/lib/httppasswords", OREAD);
  281. if(b == nil){
  282. replyerror("no password file", raddr);
  283. return;
  284. }
  285. /* find key */
  286. for(;;){
  287. p = Brdline(b, '\n');
  288. if(p == nil)
  289. break;
  290. p[Blinelen(b)-1] = 0;
  291. if(strncmp(p, tr->uid, n) == 0)
  292. if(p[n] == ' ' || p[n] == '\t'){
  293. p += n;
  294. break;
  295. }
  296. }
  297. Bterm(b);
  298. if(p == nil) {
  299. randombytes((uint8_t*)key, DESKEYLEN);
  300. } else {
  301. while(*p == ' ' || *p == '\t')
  302. p++;
  303. passtokey(key, p);
  304. }
  305. /* send back a ticket encrypted with the key */
  306. randombytes((uint8_t*)t.chal, CHALLEN);
  307. mkkey(t.key);
  308. tbuf[0] = AuthOK;
  309. t.num = AuthHr;
  310. safecpy(t.cuid, tr->uid, sizeof(t.cuid));
  311. safecpy(t.suid, tr->uid, sizeof(t.suid));
  312. convT2M(&t, tbuf+1, key);
  313. write(1, tbuf, sizeof(tbuf));
  314. }
  315. static char*
  316. domainname(void)
  317. {
  318. static char sysname[Maxpath];
  319. static char *domain;
  320. int n;
  321. if(domain)
  322. return domain;
  323. if(*sysname)
  324. return sysname;
  325. domain = csgetvalue(0, "sys", sysname, "dom", nil);
  326. if(domain)
  327. return domain;
  328. n = readfile("/dev/sysname", sysname, sizeof(sysname)-1);
  329. if(n < 0){
  330. strcpy(sysname, "kremvax");
  331. return sysname;
  332. }
  333. sysname[n] = 0;
  334. return sysname;
  335. }
  336. static int
  337. h2b(char c)
  338. {
  339. if(c >= '0' && c <= '9')
  340. return c - '0';
  341. if(c >= 'A' && c <= 'F')
  342. return c - 'A' + 10;
  343. if(c >= 'a' && c <= 'f')
  344. return c - 'a' + 10;
  345. return 0;
  346. }
  347. void
  348. apop(Ticketreq *tr, int type)
  349. {
  350. int challen, i, tries;
  351. char *secret, *hkey, *p;
  352. Ticketreq treq;
  353. DigestState *s;
  354. char sbuf[SECRETLEN], hbuf[DESKEYLEN];
  355. char tbuf[TICKREQLEN];
  356. char buf[MD5dlen*2];
  357. uint8_t digest[MD5dlen], resp[MD5dlen];
  358. uint32_t rb[4];
  359. char chal[256];
  360. USED(tr);
  361. /*
  362. * Create a challenge and send it.
  363. */
  364. randombytes((uint8_t*)rb, sizeof(rb));
  365. p = chal;
  366. p += snprint(p, sizeof(chal), "<%lx%lx.%lx%lx@%s>",
  367. rb[0], rb[1], rb[2], rb[3], domainname());
  368. challen = p - chal;
  369. print("%c%-5d%s", AuthOKvar, challen, chal);
  370. /* give user a few attempts */
  371. for(tries = 0; ; tries++) {
  372. /*
  373. * get ticket request
  374. */
  375. if(readn(0, tbuf, TICKREQLEN) < 0)
  376. exits(0);
  377. convM2TR(tbuf, &treq);
  378. tr = &treq;
  379. if(tr->type != type)
  380. exits(0);
  381. /*
  382. * read response
  383. */
  384. if(readn(0, buf, MD5dlen*2) < 0)
  385. exits(0);
  386. for(i = 0; i < MD5dlen; i++)
  387. resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]);
  388. /*
  389. * lookup
  390. */
  391. secret = findsecret(KEYDB, tr->uid, sbuf);
  392. hkey = findkey(KEYDB, tr->hostid, hbuf);
  393. if(hkey == 0 || secret == 0){
  394. replyerror("apop-fail bad response %s", raddr);
  395. logfail(tr->uid);
  396. if(tries > 5)
  397. return;
  398. continue;
  399. }
  400. /*
  401. * check for match
  402. */
  403. if(type == AuthCram){
  404. hmac_md5((uint8_t*)chal, challen,
  405. (uint8_t*)secret, strlen(secret),
  406. digest, nil);
  407. } else {
  408. s = md5((uint8_t*)chal, challen, 0, 0);
  409. md5((uint8_t*)secret, strlen(secret), digest, s);
  410. }
  411. if(memcmp(digest, resp, MD5dlen) != 0){
  412. replyerror("apop-fail bad response %s", raddr);
  413. logfail(tr->uid);
  414. if(tries > 5)
  415. return;
  416. continue;
  417. }
  418. break;
  419. }
  420. succeed(tr->uid);
  421. /*
  422. * reply with ticket & authenticator
  423. */
  424. if(tickauthreply(tr, hkey) < 0)
  425. exits(0);
  426. if(debug){
  427. if(type == AuthCram)
  428. syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr);
  429. else
  430. syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr);
  431. }
  432. }
  433. enum {
  434. VNCchallen= 16,
  435. };
  436. /* VNC reverses the bits of each byte before using as a des key */
  437. uint8_t swizzletab[256] = {
  438. 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
  439. 0x8, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
  440. 0x4, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
  441. 0xc, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
  442. 0x2, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
  443. 0xa, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
  444. 0x6, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
  445. 0xe, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
  446. 0x1, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
  447. 0x9, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
  448. 0x5, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
  449. 0xd, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
  450. 0x3, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
  451. 0xb, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
  452. 0x7, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
  453. 0xf, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
  454. };
  455. void
  456. vnc(Ticketreq *tr)
  457. {
  458. uint8_t chal[VNCchallen+6];
  459. uint8_t reply[VNCchallen];
  460. char *secret, *hkey;
  461. char sbuf[SECRETLEN], hbuf[DESKEYLEN];
  462. DESstate s;
  463. int i;
  464. /*
  465. * Create a challenge and send it.
  466. */
  467. randombytes(chal+6, VNCchallen);
  468. chal[0] = AuthOKvar;
  469. snprint((char*)chal+1, sizeof chal - 1, "%-5d", VNCchallen);
  470. if(write(1, chal, sizeof(chal)) != sizeof(chal))
  471. return;
  472. /*
  473. * lookup keys (and swizzle bits)
  474. */
  475. memset(sbuf, 0, sizeof(sbuf));
  476. secret = findsecret(KEYDB, tr->uid, sbuf);
  477. if(secret == 0){
  478. randombytes((uint8_t*)sbuf, sizeof(sbuf));
  479. secret = sbuf;
  480. }
  481. for(i = 0; i < 8; i++)
  482. secret[i] = swizzletab[(uint8_t)secret[i]];
  483. hkey = findkey(KEYDB, tr->hostid, hbuf);
  484. if(hkey == 0){
  485. randombytes((uint8_t*)hbuf, sizeof(hbuf));
  486. hkey = hbuf;
  487. }
  488. /*
  489. * get response
  490. */
  491. if(readn(0, reply, sizeof(reply)) != sizeof(reply))
  492. return;
  493. /*
  494. * decrypt response and compare
  495. */
  496. setupDESstate(&s, (uint8_t*)secret, nil);
  497. desECBdecrypt(reply, sizeof(reply), &s);
  498. if(memcmp(reply, chal+6, VNCchallen) != 0){
  499. replyerror("vnc-fail bad response %s", raddr);
  500. logfail(tr->uid);
  501. return;
  502. }
  503. succeed(tr->uid);
  504. /*
  505. * reply with ticket & authenticator
  506. */
  507. if(tickauthreply(tr, hkey) < 0)
  508. exits(0);
  509. if(debug)
  510. syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr);
  511. }
  512. void
  513. chap(Ticketreq *tr)
  514. {
  515. char *secret, *hkey;
  516. DigestState *s;
  517. char sbuf[SECRETLEN], hbuf[DESKEYLEN];
  518. uint8_t digest[MD5dlen];
  519. char chal[CHALLEN];
  520. OChapreply reply;
  521. /*
  522. * Create a challenge and send it.
  523. */
  524. randombytes((uint8_t*)chal, sizeof(chal));
  525. write(1, chal, sizeof(chal));
  526. /*
  527. * get chap reply
  528. */
  529. if(readn(0, &reply, sizeof(reply)) < 0)
  530. exits(0);
  531. safecpy(tr->uid, reply.uid, sizeof(tr->uid));
  532. /*
  533. * lookup
  534. */
  535. secret = findsecret(KEYDB, tr->uid, sbuf);
  536. hkey = findkey(KEYDB, tr->hostid, hbuf);
  537. if(hkey == 0 || secret == 0){
  538. replyerror("chap-fail bad response %s", raddr);
  539. logfail(tr->uid);
  540. exits(0);
  541. }
  542. /*
  543. * check for match
  544. */
  545. s = md5(&reply.id, 1, 0, 0);
  546. md5((uint8_t*)secret, strlen(secret), 0, s);
  547. md5((uint8_t*)chal, sizeof(chal), digest, s);
  548. if(memcmp(digest, reply.resp, MD5dlen) != 0){
  549. replyerror("chap-fail bad response %s", raddr);
  550. logfail(tr->uid);
  551. exits(0);
  552. }
  553. succeed(tr->uid);
  554. /*
  555. * reply with ticket & authenticator
  556. */
  557. if(tickauthreply(tr, hkey) < 0)
  558. exits(0);
  559. if(debug)
  560. syslog(0, AUTHLOG, "chap-ok %s %s", tr->uid, raddr);
  561. }
  562. void
  563. printresp(uint8_t resp[MSresplen])
  564. {
  565. char buf[200], *p;
  566. int i;
  567. p = buf;
  568. for(i=0; i<MSresplen; i++)
  569. p += sprint(p, "%.2ux ", resp[i]);
  570. syslog(0, AUTHLOG, "resp = %s", buf);
  571. }
  572. void
  573. mschap(Ticketreq *tr)
  574. {
  575. char *secret, *hkey;
  576. char sbuf[SECRETLEN], hbuf[DESKEYLEN];
  577. uint8_t chal[CHALLEN];
  578. uint8_t hash[MShashlen];
  579. uint8_t hash2[MShashlen];
  580. uint8_t resp[MSresplen];
  581. OMSchapreply reply;
  582. int dupe, lmok, ntok;
  583. DigestState *s;
  584. uint8_t digest[SHA1dlen];
  585. /*
  586. * Create a challenge and send it.
  587. */
  588. randombytes((uint8_t*)chal, sizeof(chal));
  589. write(1, chal, sizeof(chal));
  590. /*
  591. * get chap reply
  592. */
  593. if(readn(0, &reply, sizeof(reply)) < 0)
  594. exits(0);
  595. safecpy(tr->uid, reply.uid, sizeof(tr->uid));
  596. /*
  597. * lookup
  598. */
  599. secret = findsecret(KEYDB, tr->uid, sbuf);
  600. hkey = findkey(KEYDB, tr->hostid, hbuf);
  601. if(hkey == 0 || secret == 0){
  602. replyerror("mschap-fail bad response %s/%s(%s)",
  603. tr->uid, tr->hostid, raddr);
  604. logfail(tr->uid);
  605. exits(0);
  606. }
  607. lmhash(hash, secret);
  608. mschalresp(resp, hash, chal);
  609. lmok = memcmp(resp, reply.LMresp, MSresplen) == 0;
  610. nthash(hash, secret);
  611. mschalresp(resp, hash, chal);
  612. ntok = memcmp(resp, reply.NTresp, MSresplen) == 0;
  613. dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
  614. /*
  615. * It is valid to send the same response in both the LM and NTLM
  616. * fields provided one of them is correct, if neither matches,
  617. * or the two fields are different and either fails to match,
  618. * the whole sha-bang fails.
  619. *
  620. * This is an improvement in security as it allows clients who
  621. * wish to do NTLM auth (which is insecure) not to send
  622. * LM tokens (which is very insecure).
  623. *
  624. * Windows servers supports clients doing this also though
  625. * windows clients don't seem to use the feature.
  626. */
  627. if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){
  628. replyerror("mschap-fail bad response %s/%s(%s) %d,%d,%d",
  629. tr->uid, tr->hostid, raddr, dupe, lmok, ntok);
  630. logfail(tr->uid);
  631. exits(0);
  632. }
  633. succeed(tr->uid);
  634. /*
  635. * reply with ticket & authenticator
  636. */
  637. if(tickauthreply(tr, hkey) < 0)
  638. exits(0);
  639. if(debug)
  640. replyerror("mschap-ok %s/%s(%s) %x",
  641. tr->uid, tr->hostid, raddr);
  642. nthash(hash, secret);
  643. md4(hash, 16, hash2, 0);
  644. s = sha1(hash2, 16, 0, 0);
  645. sha1(hash2, 16, 0, s);
  646. sha1(chal, 8, digest, s);
  647. if(write(1, digest, 16) < 0)
  648. exits(0);
  649. }
  650. void
  651. nthash(uint8_t hash[MShashlen], char *passwd)
  652. {
  653. uint8_t buf[512];
  654. int i;
  655. for (i = 0; *passwd && i + 1 < sizeof(buf);) {
  656. Rune r;
  657. passwd += chartorune(&r, passwd);
  658. buf[i++] = r;
  659. buf[i++] = r >> 8;
  660. }
  661. memset(hash, 0, 16);
  662. md4(buf, i, hash, 0);
  663. }
  664. void
  665. lmhash(uint8_t hash[MShashlen], char *passwd)
  666. {
  667. uint8_t buf[14];
  668. char *stdtext = "KGS!@#$%";
  669. int i;
  670. strncpy((char*)buf, passwd, sizeof(buf));
  671. for(i=0; i<sizeof(buf); i++)
  672. if(buf[i] >= 'a' && buf[i] <= 'z')
  673. buf[i] += 'A' - 'a';
  674. memset(hash, 0, 16);
  675. memcpy(hash, stdtext, 8);
  676. memcpy(hash+8, stdtext, 8);
  677. desencrypt(hash, buf);
  678. desencrypt(hash+8, buf+7);
  679. }
  680. void
  681. mschalresp(uint8_t resp[MSresplen], uint8_t hash[MShashlen],
  682. uint8_t chal[MSchallen])
  683. {
  684. int i;
  685. uint8_t buf[21];
  686. memset(buf, 0, sizeof(buf));
  687. memcpy(buf, hash, MShashlen);
  688. for(i=0; i<3; i++) {
  689. memmove(resp+i*MSchallen, chal, MSchallen);
  690. desencrypt(resp+i*MSchallen, buf+i*7);
  691. }
  692. }
  693. void
  694. desencrypt(uint8_t data[8], uint8_t key[7])
  695. {
  696. uint32_t ekey[32];
  697. key_setup(key, ekey);
  698. block_cipher(ekey, data, 0);
  699. }
  700. /*
  701. * return true of the speaker may speak for the user
  702. *
  703. * a speaker may always speak for himself/herself
  704. */
  705. int
  706. speaksfor(char *speaker, char *user)
  707. {
  708. Ndbtuple *tp, *ntp;
  709. Ndbs s;
  710. int ok;
  711. char notuser[Maxpath];
  712. if(strcmp(speaker, user) == 0)
  713. return 1;
  714. if(db == 0)
  715. return 0;
  716. tp = ndbsearch(db, &s, "hostid", speaker);
  717. if(tp == 0)
  718. return 0;
  719. ok = 0;
  720. snprint(notuser, sizeof notuser, "!%s", user);
  721. for(ntp = tp; ntp; ntp = ntp->entry)
  722. if(strcmp(ntp->attr, "uid") == 0){
  723. if(strcmp(ntp->val, notuser) == 0){
  724. ok = 0;
  725. break;
  726. }
  727. if(*ntp->val == '*' || strcmp(ntp->val, user) == 0)
  728. ok = 1;
  729. }
  730. ndbfree(tp);
  731. return ok;
  732. }
  733. /*
  734. * return an error reply
  735. */
  736. void
  737. replyerror(char *fmt, ...)
  738. {
  739. char buf[AERRLEN+1];
  740. va_list arg;
  741. memset(buf, 0, sizeof(buf));
  742. va_start(arg, fmt);
  743. vseprint(buf + 1, buf + sizeof(buf), fmt, arg);
  744. va_end(arg);
  745. buf[AERRLEN] = 0;
  746. buf[0] = AuthErr;
  747. write(1, buf, AERRLEN+1);
  748. syslog(0, AUTHLOG, buf+1);
  749. }
  750. void
  751. getraddr(char *dir)
  752. {
  753. int n;
  754. char *cp;
  755. char file[Maxpath];
  756. raddr[0] = 0;
  757. snprint(file, sizeof(file), "%s/remote", dir);
  758. n = readfile(file, raddr, sizeof(raddr)-1);
  759. if(n < 0)
  760. return;
  761. raddr[n] = 0;
  762. cp = strchr(raddr, '\n');
  763. if(cp)
  764. *cp = 0;
  765. cp = strchr(raddr, '!');
  766. if(cp)
  767. *cp = 0;
  768. }
  769. void
  770. mkkey(char *k)
  771. {
  772. randombytes((uint8_t*)k, DESKEYLEN);
  773. }
  774. void
  775. randombytes(uint8_t *buf, int len)
  776. {
  777. int i;
  778. if(readfile("/dev/random", (char*)buf, len) >= 0)
  779. return;
  780. for(i = 0; i < len; i++)
  781. buf[i] = rand();
  782. }
  783. /*
  784. * reply with ticket and authenticator
  785. */
  786. int
  787. tickauthreply(Ticketreq *tr, char *hkey)
  788. {
  789. Ticket t;
  790. Authenticator a;
  791. char buf[TICKETLEN+AUTHENTLEN+1];
  792. memset(&t, 0, sizeof(t));
  793. memmove(t.chal, tr->chal, CHALLEN);
  794. safecpy(t.cuid, tr->uid, sizeof t.cuid);
  795. safecpy(t.suid, tr->uid, sizeof t.suid);
  796. mkkey(t.key);
  797. buf[0] = AuthOK;
  798. t.num = AuthTs;
  799. convT2M(&t, buf+1, hkey);
  800. memmove(a.chal, t.chal, CHALLEN);
  801. a.num = AuthAc;
  802. a.id = 0;
  803. convA2M(&a, buf+TICKETLEN+1, t.key);
  804. if(write(1, buf, TICKETLEN+AUTHENTLEN+1) < 0)
  805. return -1;
  806. return 0;
  807. }
  808. void
  809. safecpy(char *to, char *from, int len)
  810. {
  811. strncpy(to, from, len);
  812. to[len-1] = 0;
  813. }