authsrv9.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <stdarg.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <syslog.h>
  8. #include <time.h>
  9. #include <unistd.h>
  10. #include "util.h"
  11. int dflag = 0;
  12. #define errstr (strerror(errno))
  13. static void sysfatal(char *fmt, ...);
  14. static void say(char *fmt, ...);
  15. static void warn(char *fmt, ...);
  16. enum {
  17. ANamelen = 28,
  18. ADomlen = 48,
  19. AErrlen = 64,
  20. Challen = 8,
  21. Secretlen = 32,
  22. Ticketreqlen = 1+ANamelen+ADomlen+Challen+ANamelen+ANamelen,
  23. Ticketlen = 1+Challen+2*ANamelen+Deskeylen,
  24. Passreqlen = 1+2*ANamelen+1+Secretlen,
  25. ATreq = 1,
  26. APass = 3,
  27. AOk = 4,
  28. AErr = 5,
  29. ATs = 64,
  30. ATc = 65,
  31. ATp = 68,
  32. };
  33. typedef struct User User;
  34. struct User
  35. {
  36. int keyok;
  37. uchar key[Deskeylen];
  38. int status;
  39. int expire;
  40. };
  41. typedef struct Ticketreq Ticketreq;
  42. typedef struct Ticket Ticket;
  43. typedef struct Passreq Passreq;
  44. struct Ticketreq
  45. {
  46. char which;
  47. char authid[ANamelen+1];
  48. char authdom[ADomlen+1];
  49. uchar chal[Challen];
  50. char hostid[ANamelen+1];
  51. char uid[ANamelen+1];
  52. };
  53. struct Ticket
  54. {
  55. uchar which;
  56. uchar chal[Challen];
  57. char cuid[ANamelen+1];
  58. char suid[ANamelen+1];
  59. uchar key[Deskeylen];
  60. };
  61. struct Passreq
  62. {
  63. int which;
  64. char oldpw[ANamelen+1];
  65. char newpw[ANamelen+1];
  66. int changesecret;
  67. char secret[Secretlen+1];
  68. };
  69. static void transact(void);
  70. static void
  71. usage(void)
  72. {
  73. fprint(2, "usage: authsrv9 [-d]\n");
  74. exit(1);
  75. }
  76. int
  77. main(int argc, char *argv[])
  78. {
  79. int c;
  80. randominit();
  81. openlog("authsrv9", 0, LOG_AUTH);
  82. while((c = getopt(argc, argv, "d")) != -1)
  83. switch(c) {
  84. case 'd':
  85. dflag++;
  86. break;
  87. default:
  88. usage();
  89. }
  90. argc -= optind;
  91. argv += optind;
  92. if(argc != 0)
  93. usage();
  94. /* openbsd's inetd redirects stderr to stdout (the network)... */
  95. close(2);
  96. open("/dev/null", O_WRONLY);
  97. alarm(2*60);
  98. for(;;)
  99. transact();
  100. }
  101. static void
  102. ewrite(uchar *p, int n)
  103. {
  104. if(write(1, p, n) != n)
  105. sysfatal("write: %s", errstr);
  106. say("wrote %d bytes", n);
  107. }
  108. static void
  109. autherror(int fatal, char *err)
  110. {
  111. uchar buf[1+AErrlen];
  112. say("autherror, fatal %d, err %s", fatal, err);
  113. memset(buf, 0, sizeof buf);
  114. buf[0] = AErr;
  115. memmove(buf+1, err, min(strlen(err), AErrlen));
  116. ewrite(buf, sizeof buf);
  117. if(fatal)
  118. exit(1);
  119. }
  120. static int
  121. readfile(char *path, void *buf, int buflen, int exact)
  122. {
  123. int fd;
  124. int n;
  125. memset(buf, 0, buflen);
  126. fd = open(path, O_RDONLY);
  127. if(fd < 0)
  128. return -1;
  129. n = readn(fd, buf, buflen);
  130. close(fd);
  131. if(n < 0)
  132. return -1;
  133. if(!exact && n == buflen)
  134. return -1;
  135. if(exact && n != buflen)
  136. return -1;
  137. return n;
  138. }
  139. static int
  140. writefile(char *path, uchar *buf, int buflen)
  141. {
  142. int fd;
  143. int n;
  144. fd = open(path, O_WRONLY|O_CREAT|O_TRUNC);
  145. if(fd < 0)
  146. return -1;
  147. n = write(fd, buf, buflen);
  148. close(fd);
  149. return n;
  150. }
  151. static int
  152. getinfo(char **authid, char **authdom)
  153. {
  154. char aid[ANamelen+1], adom[ANamelen+1];
  155. int naid, nadom;
  156. naid = readfile("/auth/authid", aid, sizeof aid-1, 0);
  157. if(naid < 0)
  158. return -1;
  159. nadom = readfile("/auth/authdom", adom, sizeof adom-1, 0);
  160. if(nadom < 0)
  161. return -1;
  162. aid[naid] = '\0';
  163. adom[nadom] = '\0';
  164. *authid = estrdup(aid);
  165. *authdom = estrdup(adom);
  166. return 0;
  167. }
  168. static void
  169. getuserinfo(char *uid, User *u)
  170. {
  171. char pre[128];
  172. char path[128];
  173. char buf[128];
  174. User t;
  175. char *e;
  176. uint expire;
  177. snprintf(pre, sizeof pre, "/auth/users/%s", uid);
  178. u->keyok = 0;
  179. memset(u->key, 0, sizeof u->key);
  180. u->status = 0;
  181. u->expire = 1;
  182. snprintf(path, sizeof path, "%s/key", pre);
  183. if(readfile(path, t.key, sizeof t.key, 1) < 0)
  184. return;
  185. snprintf(path, sizeof path, "%s/status", pre);
  186. if(readfile(path, buf, sizeof buf, 0) < 0)
  187. return;
  188. t.status = 0;
  189. if(eq(buf, "ok"))
  190. t.status = 1;
  191. else if(!eq(buf, "disabled"))
  192. warn("bad status in %s: %s", path, buf);
  193. snprintf(path, sizeof path, "%s/expire", pre);
  194. if(readfile(path, buf, sizeof buf, 0) < 0)
  195. return;
  196. t.expire = 1;
  197. if(eq(buf, "never")) {
  198. t.expire = 0;
  199. } else {
  200. expire = (uint)strtol(buf, &e, 10);
  201. if(*e == '\0')
  202. t.expire = expire;
  203. else
  204. warn("bad expire in %s: %s (remainder %s)", path, buf, e);
  205. }
  206. t.keyok = 1;
  207. memmove(u, &t, sizeof t);
  208. }
  209. static int
  210. move(void *to, void *from, int n)
  211. {
  212. memmove(to, from, n);
  213. return n;
  214. }
  215. static void
  216. ticketrequnpack(Ticketreq *tr, uchar *p)
  217. {
  218. memset(tr, 0, sizeof tr[0]);
  219. tr->which = *p++;
  220. p += move(tr->authid, p, ANamelen);
  221. p += move(tr->authdom, p, ADomlen);
  222. p += move(tr->chal, p, Challen);
  223. p += move(tr->hostid, p, ANamelen);
  224. p += move(tr->uid, p, ANamelen);
  225. }
  226. static void
  227. ticketmk(Ticket *t, int which, uchar *chal, char *hostid, char *idr, uchar *key)
  228. {
  229. memset(t, 0, sizeof (Ticket));
  230. t->which = which;
  231. memmove(t->chal, chal, sizeof t->chal);
  232. strcpy(t->cuid, hostid);
  233. strcpy(t->suid, idr);
  234. memmove(t->key, key, sizeof t->key);
  235. }
  236. static void
  237. ticketpack(Ticket *t, uchar *buf)
  238. {
  239. uchar *p;
  240. p = buf;
  241. *p++ = t->which;
  242. p += move(p, t->chal, Challen);
  243. p += move(p, t->cuid, ANamelen);
  244. p += move(p, t->suid, ANamelen);
  245. p += move(p, t->key, Deskeylen);
  246. }
  247. static void
  248. genkey(uchar *p)
  249. {
  250. randombuf(p, Deskeylen);
  251. }
  252. static void
  253. clear(void *p, int n)
  254. {
  255. memset(p, 0, n);
  256. }
  257. int
  258. allowed(char *uid)
  259. {
  260. char *path;
  261. char buf[2*1024+1];
  262. int fd;
  263. int n;
  264. char *p, *e;
  265. path = "/auth/badusers";
  266. fd = open(path, O_RDONLY);
  267. if(fd < 0) {
  268. warn("open %s: %s", path, errstr);
  269. return 0;
  270. }
  271. n = readn(fd, buf, sizeof buf-1);
  272. if(n < 0) {
  273. warn("read %s: %s", path, errstr);
  274. return 0;
  275. }
  276. if(n == sizeof buf) {
  277. warn("%s too long", path);
  278. return 0;
  279. }
  280. buf[n] = '\0';
  281. p = buf;
  282. for(;;) {
  283. e = strchr(p, '\n');
  284. if(e == nil)
  285. break;
  286. *e = '\0';
  287. if(strcmp(p, uid) == 0)
  288. return 0;
  289. p = e+1;
  290. }
  291. return 1;
  292. }
  293. static void
  294. authtreq(Ticketreq *tr)
  295. {
  296. char *authid, *authdom;
  297. User au, u;
  298. uchar ks[Deskeylen], kc[Deskeylen], kn[Deskeylen];
  299. uint now;
  300. char idr[ANamelen+1];
  301. Ticket tc, ts;
  302. uchar tcbuf[Ticketlen], tsbuf[Ticketlen];
  303. uchar tresp[1+Ticketlen+Ticketlen];
  304. int cok, sok;
  305. char *msg;
  306. /* # C->A: AuthTreq, IDs, DN, CHs, IDc, IDr */
  307. if(getinfo(&authid, &authdom) < 0) {
  308. warn("could not get authid & authdom");
  309. sysfatal("could not get authid & authdom");
  310. }
  311. now = time(nil);
  312. getuserinfo(authid, &au);
  313. say("authid, keyok %d, status %d, expire %u, now %u\n", au.keyok, au.status, au.expire, now);
  314. genkey(ks);
  315. sok = eq(tr->authid, authid) && eq(tr->authdom, authdom) && au.keyok && au.status && (au.expire == 0 || now > au.expire);
  316. getuserinfo(tr->hostid, &u);
  317. say("hostid '%s', user '%s', keyok %d, status %d, expire %u, now %u\n", tr->hostid, tr->uid, u.keyok, u.status, u.expire, now);
  318. genkey(kc);
  319. cok = u.keyok && u.status && (u.expire == 0 || u.expire > now);
  320. if(sok && cok) {
  321. memmove(ks, au.key, Deskeylen);
  322. memmove(kc, u.key, Deskeylen);
  323. }
  324. /* A->C: AuthOK, Kc{AuthTc, CHs, IDc, IDr, Kn}, Ks{AuthTs, CHs, IDc, IDr, Kn} */
  325. msg = "";
  326. strcpy(idr, "");
  327. if(eq(tr->hostid, tr->uid) || (eq(tr->hostid, authid) && allowed(tr->uid)))
  328. strcpy(idr, tr->uid);
  329. else
  330. msg = ", but hostid does not speak for uid";
  331. warn("ticketreq %s: authid %s, remote hostid %s, uid %s%s", (sok&&cok) ? "ok" : "bad", authid, tr->hostid, tr->uid, msg);
  332. genkey(kn);
  333. ticketmk(&tc, ATc, tr->chal, tr->hostid, idr, kn);
  334. ticketpack(&tc, tcbuf);
  335. authencrypt(kc, tcbuf, Ticketlen);
  336. if(0)say("ticket, cipher %s", hex(tcbuf, Ticketlen));
  337. ticketmk(&ts, ATs, tr->chal, tr->hostid, idr, kn);
  338. ticketpack(&ts, tsbuf);
  339. authencrypt(ks, tsbuf, Ticketlen);
  340. if(0)say("ticket, cipher %s", hex(tsbuf, Ticketlen));
  341. clear(kc, sizeof kc);
  342. clear(ks, sizeof ks);
  343. clear(kn, sizeof kn);
  344. clear(&tc, sizeof tc);
  345. clear(&ts, sizeof ts);
  346. clear(&au, sizeof au);
  347. clear(&u, sizeof u);
  348. tresp[0] = AOk;
  349. memmove(tresp+1, tcbuf, sizeof tcbuf);
  350. memmove(tresp+1+sizeof tcbuf, tsbuf, sizeof tsbuf);
  351. ewrite(tresp, sizeof tresp);
  352. }
  353. static void
  354. passwordrequnpack(Passreq *pr, uchar *buf)
  355. {
  356. uchar *p;
  357. memset(pr, 0, sizeof pr[0]);
  358. p = buf;
  359. pr->which = *p++;
  360. p += move(pr->oldpw, p, ANamelen);
  361. p += move(pr->newpw, p, ANamelen);
  362. pr->changesecret = *p++;
  363. p += move(pr->secret, p, Secretlen);
  364. }
  365. static char*
  366. checkpass(char *pw)
  367. {
  368. if(strlen(pw) < 8)
  369. return "bad password: too short";
  370. if(strlen(pw) > ANamelen)
  371. return "bad password: too long";
  372. return nil;
  373. }
  374. static void
  375. authpass(Ticketreq *tr)
  376. {
  377. User u;
  378. uint now;
  379. uchar kc[Deskeylen], kn[Deskeylen];
  380. Ticket tp;
  381. uchar tresp[1+Ticketlen];
  382. uchar prbuf[Passreqlen];
  383. Passreq pr;
  384. uchar okey[Deskeylen], nkey[Deskeylen];
  385. char *badpw;
  386. char path[128];
  387. int n;
  388. /*
  389. * C->A: AuthPass, IDc, DN, CHc, IDc, IDc
  390. * (request to change pass for tr->uid)
  391. */
  392. getuserinfo(tr->uid, &u);
  393. /* A->C: Kc{AuthTp, CHc, IDc, IDc, Kn} */
  394. now = time(nil);
  395. say("authpass for user %s, u.keyok %d, u.status %d, u.expire %u, now %u", tr->uid, u.keyok, u.status, u.expire, now);
  396. genkey(kc);
  397. if(u.keyok && u.status && (u.expire == 0 || now > u.expire))
  398. memmove(kc, u.key, Deskeylen);
  399. clear(&u, sizeof u);
  400. genkey(kn);
  401. ticketmk(&tp, ATp, tr->chal, tr->uid, tr->uid, kn);
  402. tresp[0] = AOk;
  403. ticketpack(&tp, tresp+1);
  404. clear(&tp, sizeof tp);
  405. authencrypt(kc, tresp+1, Ticketlen);
  406. ewrite(tresp, sizeof tresp);
  407. for(;;) {
  408. /* C->A: Kn{AuthPass, old, new, changesecret, secret} */
  409. n = readn(0, prbuf, sizeof prbuf);
  410. if(n < 0)
  411. sysfatal("read passwordreq: %s", errstr);
  412. if(n != sizeof prbuf)
  413. sysfatal("short read for password request, want %d, got %d", sizeof prbuf, n);
  414. authdecrypt(kn, prbuf, sizeof prbuf);
  415. passwordrequnpack(&pr, prbuf);
  416. clear(prbuf, sizeof prbuf);
  417. if(pr.which != APass) {
  418. warn("pass change: for uid %s: wrong message type, want %d, saw %d (wrong password used)", tr->uid, APass, pr.which);
  419. clear(&pr, sizeof pr);
  420. clear(kc, sizeof kc);
  421. autherror(1, "wrong message type for Passreq");
  422. }
  423. if(pr.changesecret) {
  424. warn("pass change: uid %s tried to change apop secret, not supported", tr->uid);
  425. autherror(0, "changing apop secret not supported");
  426. clear(&pr, sizeof pr);
  427. continue;
  428. }
  429. passtokey(okey, pr.oldpw);
  430. passtokey(nkey, pr.newpw);
  431. if(!memeq(kc, okey, sizeof okey)) {
  432. clear(&pr, sizeof pr);
  433. clear(okey, sizeof okey);
  434. clear(nkey, sizeof nkey);
  435. warn("pass change: uid %s gave bad old password", tr->uid);
  436. autherror(0, "bad old password");
  437. continue;
  438. }
  439. badpw = checkpass(pr.newpw);
  440. if(badpw != nil) {
  441. clear(&pr, sizeof pr);
  442. clear(okey, sizeof okey);
  443. clear(nkey, sizeof nkey);
  444. warn("pass change: uid %s gave bad new password: %s", tr->uid, badpw);
  445. autherror(0, badpw);
  446. continue;
  447. }
  448. snprintf(path, sizeof path, "/auth/users/%s/key", tr->uid);
  449. if(writefile(path, nkey, Deskeylen) < 0) {
  450. clear(&pr, sizeof pr);
  451. clear(okey, sizeof okey);
  452. clear(nkey, sizeof nkey);
  453. clear(kc, sizeof kc);
  454. warn("pass change: storing new key for user %s failed: %s", tr->uid, errstr);
  455. autherror(1, "storing new key failed");
  456. }
  457. clear(&pr, sizeof pr);
  458. clear(okey, sizeof okey);
  459. clear(nkey, sizeof nkey);
  460. clear(kc, sizeof kc);
  461. warn("pass change: password changed for user %s", tr->uid);
  462. /* A->C: AuthOK or AuthErr, 64-byte error message */
  463. tresp[0] = AOk;
  464. ewrite(tresp, 1);
  465. return;
  466. }
  467. }
  468. static void
  469. transact(void)
  470. {
  471. Ticketreq tr;
  472. uchar trbuf[Ticketreqlen];
  473. int n;
  474. say("reading ticketrequest");
  475. /* read ticket */
  476. n = readn(0, trbuf, sizeof trbuf);
  477. if(n < 0)
  478. sysfatal("read ticketreq: %s", errstr);
  479. if(n == 0)
  480. exit(0);
  481. if(n != sizeof trbuf)
  482. sysfatal("read ticketreq, want %d, got %d", sizeof trbuf, n);
  483. ticketrequnpack(&tr, trbuf);
  484. say("have ticketreq, which %d, authid %s authdom %s, chal %s hostid %s uid %s", tr.which, tr.authid, tr.authdom, hex(tr.chal, Challen), tr.hostid, tr.uid);
  485. switch(tr.which) {
  486. case ATreq:
  487. authtreq(&tr);
  488. break;
  489. case APass:
  490. authpass(&tr);
  491. break;
  492. default:
  493. autherror(1, "not supported");
  494. break;
  495. }
  496. }
  497. static void
  498. log(int level, char *fmt, va_list ap)
  499. {
  500. char *p;
  501. if(vasprintf(&p, fmt, ap) < 0)
  502. return;
  503. syslog(level, "%s (%s)", p, remoteaddr(0));
  504. free(p);
  505. }
  506. static void
  507. sysfatal(char *fmt, ...)
  508. {
  509. va_list ap;
  510. va_start(ap, fmt);
  511. log(LOG_NOTICE, fmt, ap);
  512. va_end(ap);
  513. exit(1);
  514. }
  515. static void
  516. warn(char *fmt, ...)
  517. {
  518. va_list ap;
  519. va_start(ap, fmt);
  520. log(LOG_WARNING, fmt, ap);
  521. va_end(ap);
  522. }
  523. static void
  524. say(char *fmt, ...)
  525. {
  526. va_list ap;
  527. if(!dflag)
  528. return;
  529. va_start(ap, fmt);
  530. log(LOG_INFO, fmt, ap);
  531. va_end(ap);
  532. }