authp9any.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. * 4th Edition p9any/p9sk1 authentication based on auth9p1.c
  3. * Nigel Roles (nigel@9fs.org) 2003
  4. */
  5. #include <plan9.h>
  6. #include <fcall.h>
  7. #include <u9fs.h>
  8. #include <stdlib.h> /* for random stuff */
  9. typedef struct Ticket Ticket;
  10. typedef struct Ticketreq Ticketreq;
  11. typedef struct Authenticator Authenticator;
  12. enum
  13. {
  14. DOMLEN= 48, /* length of an authentication domain name */
  15. CHALLEN= 8 /* length of a challenge */
  16. };
  17. enum {
  18. HaveProtos,
  19. NeedProto,
  20. NeedChal,
  21. HaveTreq,
  22. NeedTicket,
  23. HaveAuth,
  24. Established,
  25. };
  26. /* encryption numberings (anti-replay) */
  27. enum
  28. {
  29. AuthTreq=1, /* ticket request */
  30. AuthChal=2, /* challenge box request */
  31. AuthPass=3, /* change password */
  32. AuthOK=4, /* fixed length reply follows */
  33. AuthErr=5, /* error follows */
  34. AuthMod=6, /* modify user */
  35. AuthApop=7, /* apop authentication for pop3 */
  36. AuthOKvar=9, /* variable length reply follows */
  37. AuthChap=10, /* chap authentication for ppp */
  38. AuthMSchap=11, /* MS chap authentication for ppp */
  39. AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
  40. AuthHttp=13, /* http domain login */
  41. AuthVNC=14, /* http domain login */
  42. AuthTs=64, /* ticket encrypted with server's key */
  43. AuthTc, /* ticket encrypted with client's key */
  44. AuthAs, /* server generated authenticator */
  45. AuthAc, /* client generated authenticator */
  46. AuthTp, /* ticket encrypted with client's key for password change */
  47. AuthHr /* http reply */
  48. };
  49. struct Ticketreq
  50. {
  51. char type;
  52. char authid[NAMELEN]; /* server's encryption id */
  53. char authdom[DOMLEN]; /* server's authentication domain */
  54. char chal[CHALLEN]; /* challenge from server */
  55. char hostid[NAMELEN]; /* host's encryption id */
  56. char uid[NAMELEN]; /* uid of requesting user on host */
  57. };
  58. #define TICKREQLEN (3*NAMELEN+CHALLEN+DOMLEN+1)
  59. struct Ticket
  60. {
  61. char num; /* replay protection */
  62. char chal[CHALLEN]; /* server challenge */
  63. char cuid[NAMELEN]; /* uid on client */
  64. char suid[NAMELEN]; /* uid on server */
  65. char key[DESKEYLEN]; /* nonce DES key */
  66. };
  67. #define TICKETLEN (CHALLEN+2*NAMELEN+DESKEYLEN+1)
  68. struct Authenticator
  69. {
  70. char num; /* replay protection */
  71. char chal[CHALLEN];
  72. ulong id; /* authenticator id, ++'d with each auth */
  73. };
  74. #define AUTHENTLEN (CHALLEN+4+1)
  75. extern int chatty9p;
  76. static int convT2M(Ticket*, char*, char*);
  77. static void convM2T(char*, Ticket*, char*);
  78. static void convM2Tnoenc(char*, Ticket*);
  79. static int convA2M(Authenticator*, char*, char*);
  80. static void convM2A(char*, Authenticator*, char*);
  81. static int convTR2M(Ticketreq*, char*);
  82. static void convM2TR(char*, Ticketreq*);
  83. static int passtokey(char*, char*);
  84. /*
  85. * destructively encrypt the buffer, which
  86. * must be at least 8 characters long.
  87. */
  88. static int
  89. encrypt9p(void *key, void *vbuf, int n)
  90. {
  91. char ekey[128], *buf;
  92. int i, r;
  93. if(n < 8)
  94. return 0;
  95. key_setup(key, ekey);
  96. buf = vbuf;
  97. n--;
  98. r = n % 7;
  99. n /= 7;
  100. for(i = 0; i < n; i++){
  101. block_cipher(ekey, buf, 0);
  102. buf += 7;
  103. }
  104. if(r)
  105. block_cipher(ekey, buf - 7 + r, 0);
  106. return 1;
  107. }
  108. /*
  109. * destructively decrypt the buffer, which
  110. * must be at least 8 characters long.
  111. */
  112. static int
  113. decrypt9p(void *key, void *vbuf, int n)
  114. {
  115. char ekey[128], *buf;
  116. int i, r;
  117. if(n < 8)
  118. return 0;
  119. key_setup(key, ekey);
  120. buf = vbuf;
  121. n--;
  122. r = n % 7;
  123. n /= 7;
  124. buf += n * 7;
  125. if(r)
  126. block_cipher(ekey, buf - 7 + r, 1);
  127. for(i = 0; i < n; i++){
  128. buf -= 7;
  129. block_cipher(ekey, buf, 1);
  130. }
  131. return 1;
  132. }
  133. #define CHAR(x) *p++ = f->x
  134. #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
  135. #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
  136. #define LONG(x) VLONG(f->x)
  137. #define STRING(x,n) memmove(p, f->x, n); p += n
  138. static int
  139. convTR2M(Ticketreq *f, char *ap)
  140. {
  141. int n;
  142. uchar *p;
  143. p = (uchar*)ap;
  144. CHAR(type);
  145. STRING(authid, NAMELEN);
  146. STRING(authdom, DOMLEN);
  147. STRING(chal, CHALLEN);
  148. STRING(hostid, NAMELEN);
  149. STRING(uid, NAMELEN);
  150. n = p - (uchar*)ap;
  151. return n;
  152. }
  153. static int
  154. convT2M(Ticket *f, char *ap, char *key)
  155. {
  156. int n;
  157. uchar *p;
  158. p = (uchar*)ap;
  159. CHAR(num);
  160. STRING(chal, CHALLEN);
  161. STRING(cuid, NAMELEN);
  162. STRING(suid, NAMELEN);
  163. STRING(key, DESKEYLEN);
  164. n = p - (uchar*)ap;
  165. if(key)
  166. encrypt9p(key, ap, n);
  167. return n;
  168. }
  169. int
  170. convA2M(Authenticator *f, char *ap, char *key)
  171. {
  172. int n;
  173. uchar *p;
  174. p = (uchar*)ap;
  175. CHAR(num);
  176. STRING(chal, CHALLEN);
  177. LONG(id);
  178. n = p - (uchar*)ap;
  179. if(key)
  180. encrypt9p(key, ap, n);
  181. return n;
  182. }
  183. #undef CHAR
  184. #undef SHORT
  185. #undef VLONG
  186. #undef LONG
  187. #undef STRING
  188. #define CHAR(x) f->x = *p++
  189. #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
  190. #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
  191. #define LONG(x) VLONG(f->x)
  192. #define STRING(x,n) memmove(f->x, p, n); p += n
  193. void
  194. convM2A(char *ap, Authenticator *f, char *key)
  195. {
  196. uchar *p;
  197. if(key)
  198. decrypt9p(key, ap, AUTHENTLEN);
  199. p = (uchar*)ap;
  200. CHAR(num);
  201. STRING(chal, CHALLEN);
  202. LONG(id);
  203. USED(p);
  204. }
  205. void
  206. convM2T(char *ap, Ticket *f, char *key)
  207. {
  208. uchar *p;
  209. if(key)
  210. decrypt9p(key, ap, TICKETLEN);
  211. p = (uchar*)ap;
  212. CHAR(num);
  213. STRING(chal, CHALLEN);
  214. STRING(cuid, NAMELEN);
  215. f->cuid[NAMELEN-1] = 0;
  216. STRING(suid, NAMELEN);
  217. f->suid[NAMELEN-1] = 0;
  218. STRING(key, DESKEYLEN);
  219. USED(p);
  220. }
  221. #undef CHAR
  222. #undef SHORT
  223. #undef LONG
  224. #undef VLONG
  225. #undef STRING
  226. static int
  227. passtokey(char *key, char *p)
  228. {
  229. uchar buf[NAMELEN], *t;
  230. int i, n;
  231. n = strlen(p);
  232. if(n >= NAMELEN)
  233. n = NAMELEN-1;
  234. memset(buf, ' ', 8);
  235. t = buf;
  236. strncpy((char*)t, p, n);
  237. t[n] = 0;
  238. memset(key, 0, DESKEYLEN);
  239. for(;;){
  240. for(i = 0; i < DESKEYLEN; i++)
  241. key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
  242. if(n <= 8)
  243. return 1;
  244. n -= 8;
  245. t += 8;
  246. if(n < 8){
  247. t -= 8 - n;
  248. n = 8;
  249. }
  250. encrypt9p(key, t, 8);
  251. }
  252. return 1; /* not reached */
  253. }
  254. static char authkey[DESKEYLEN];
  255. static char *authid;
  256. static char *authdom;
  257. static char *haveprotosmsg;
  258. static char *needprotomsg;
  259. static void
  260. p9anyinit(void)
  261. {
  262. int n, fd;
  263. char abuf[200];
  264. char *af, *f[4];
  265. af = autharg;
  266. if(af == nil)
  267. af = "/etc/u9fs.key";
  268. if((fd = open(af, OREAD)) < 0)
  269. sysfatal("can't open key file '%s'", af);
  270. if((n = readn(fd, abuf, sizeof(abuf)-1)) < 0)
  271. sysfatal("can't read key file '%s'", af);
  272. if (n > 0 && abuf[n - 1] == '\n')
  273. n--;
  274. abuf[n] = '\0';
  275. if(getfields(abuf, f, nelem(f), 0, "\n") != 3)
  276. sysfatal("key file '%s' not exactly 3 lines", af);
  277. passtokey(authkey, f[0]);
  278. authid = strdup(f[1]);
  279. authdom = strdup(f[2]);
  280. haveprotosmsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
  281. sprint(haveprotosmsg, "p9sk1@%s", authdom);
  282. needprotomsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
  283. sprint(needprotomsg, "p9sk1 %s", authdom);
  284. }
  285. typedef struct AuthSession {
  286. int state;
  287. char *uname;
  288. char *aname;
  289. char cchal[CHALLEN];
  290. Ticketreq tr;
  291. Ticket t;
  292. } AuthSession;
  293. static char*
  294. p9anyauth(Fcall *rx, Fcall *tx)
  295. {
  296. AuthSession *sp;
  297. Fid *f;
  298. char *ep;
  299. sp = malloc(sizeof(AuthSession));
  300. f = newauthfid(rx->afid, sp, &ep);
  301. if (f == nil) {
  302. free(sp);
  303. return ep;
  304. }
  305. if (chatty9p)
  306. fprint(2, "p9anyauth: afid %d\n", rx->afid);
  307. sp->state = HaveProtos;
  308. sp->uname = strdup(rx->uname);
  309. sp->aname = strdup(rx->aname);
  310. tx->aqid.type = QTAUTH;
  311. tx->aqid.path = 1;
  312. tx->aqid.vers = 0;
  313. return nil;
  314. }
  315. static char *
  316. p9anyattach(Fcall *rx, Fcall *tx)
  317. {
  318. AuthSession *sp;
  319. Fid *f;
  320. char *ep;
  321. f = oldauthfid(rx->afid, (void **)&sp, &ep);
  322. if (f == nil)
  323. return ep;
  324. if (chatty9p)
  325. fprint(2, "p9anyattach: afid %d state %d\n", rx->afid, sp->state);
  326. if (sp->state == Established && strcmp(rx->uname, sp->uname) == 0
  327. && strcmp(rx->aname, sp->aname) == 0)
  328. return nil;
  329. return "authentication failed";
  330. }
  331. static int
  332. readstr(Fcall *rx, Fcall *tx, char *s, int len)
  333. {
  334. if (rx->offset >= len)
  335. return 0;
  336. tx->count = len - rx->offset;
  337. if (tx->count > rx->count)
  338. tx->count = rx->count;
  339. memcpy(tx->data, s + rx->offset, tx->count);
  340. return tx->count;
  341. }
  342. static char *
  343. p9anyread(Fcall *rx, Fcall *tx)
  344. {
  345. AuthSession *sp;
  346. char *ep;
  347. Fid *f;
  348. f = oldauthfid(rx->afid, (void **)&sp, &ep);
  349. if (f == nil)
  350. return ep;
  351. if (chatty9p)
  352. fprint(2, "p9anyread: afid %d state %d\n", rx->fid, sp->state);
  353. switch (sp->state) {
  354. case HaveProtos:
  355. readstr(rx, tx, haveprotosmsg, strlen(haveprotosmsg) + 1);
  356. if (rx->offset + tx->count == strlen(haveprotosmsg) + 1)
  357. sp->state = NeedProto;
  358. return nil;
  359. case HaveTreq:
  360. if (rx->count != TICKREQLEN)
  361. goto botch;
  362. convTR2M(&sp->tr, tx->data);
  363. tx->count = TICKREQLEN;
  364. sp->state = NeedTicket;
  365. return nil;
  366. case HaveAuth: {
  367. Authenticator a;
  368. if (rx->count != AUTHENTLEN)
  369. goto botch;
  370. a.num = AuthAs;
  371. memmove(a.chal, sp->cchal, CHALLEN);
  372. a.id = 0;
  373. convA2M(&a, (char*)tx->data, sp->t.key);
  374. memset(sp->t.key, 0, sizeof(sp->t.key));
  375. tx->count = rx->count;
  376. sp->state = Established;
  377. return nil;
  378. }
  379. default:
  380. botch:
  381. return "protocol botch";
  382. }
  383. }
  384. static char *
  385. p9anywrite(Fcall *rx, Fcall *tx)
  386. {
  387. AuthSession *sp;
  388. char *ep;
  389. Fid *f;
  390. f = oldauthfid(rx->afid, (void **)&sp, &ep);
  391. if (f == nil)
  392. return ep;
  393. if (chatty9p)
  394. fprint(2, "p9anywrite: afid %d state %d\n", rx->fid, sp->state);
  395. switch (sp->state) {
  396. case NeedProto:
  397. if (rx->count != strlen(needprotomsg) + 1)
  398. return "protocol response wrong length";
  399. if (memcmp(rx->data, needprotomsg, rx->count) != 0)
  400. return "unacceptable protocol";
  401. sp->state = NeedChal;
  402. tx->count = rx->count;
  403. return nil;
  404. case NeedChal:
  405. if (rx->count != CHALLEN)
  406. goto botch;
  407. memmove(sp->cchal, rx->data, CHALLEN);
  408. sp->tr.type = AuthTreq;
  409. safecpy(sp->tr.authid, authid, sizeof(sp->tr.authid));
  410. safecpy(sp->tr.authdom, authdom, sizeof(sp->tr.authdom));
  411. randombytes((uchar *)sp->tr.chal, CHALLEN);
  412. safecpy(sp->tr.hostid, "", sizeof(sp->tr.hostid));
  413. safecpy(sp->tr.uid, "", sizeof(sp->tr.uid));
  414. tx->count = rx->count;
  415. sp->state = HaveTreq;
  416. return nil;
  417. case NeedTicket: {
  418. Authenticator a;
  419. if (rx->count != TICKETLEN + AUTHENTLEN) {
  420. fprint(2, "bad length in attach");
  421. goto botch;
  422. }
  423. convM2T((char*)rx->data, &sp->t, authkey);
  424. if (sp->t.num != AuthTs) {
  425. fprint(2, "bad AuthTs in attach\n");
  426. goto botch;
  427. }
  428. if (memcmp(sp->t.chal, sp->tr.chal, CHALLEN) != 0) {
  429. fprint(2, "bad challenge in attach\n");
  430. goto botch;
  431. }
  432. convM2A((char*)rx->data + TICKETLEN, &a, sp->t.key);
  433. if (a.num != AuthAc) {
  434. fprint(2, "bad AuthAs in attach\n");
  435. goto botch;
  436. }
  437. if(memcmp(a.chal, sp->tr.chal, CHALLEN) != 0) {
  438. fprint(2, "bad challenge in attach 2\n");
  439. goto botch;
  440. }
  441. sp->state = HaveAuth;
  442. tx->count = rx->count;
  443. return nil;
  444. }
  445. default:
  446. botch:
  447. return "protocol botch";
  448. }
  449. }
  450. static void
  451. safefree(char *p)
  452. {
  453. if (p) {
  454. memset(p, 0, strlen(p));
  455. free(p);
  456. }
  457. }
  458. static char *
  459. p9anyclunk(Fcall *rx, Fcall *tx)
  460. {
  461. Fid *f;
  462. AuthSession *sp;
  463. char *ep;
  464. f = oldauthfid(rx->afid, (void **)&sp, &ep);
  465. if (f == nil)
  466. return ep;
  467. if (chatty9p)
  468. fprint(2, "p9anyclunk: afid %d\n", rx->fid);
  469. safefree(sp->uname);
  470. safefree(sp->aname);
  471. memset(sp, 0, sizeof(sp));
  472. free(sp);
  473. return nil;
  474. }
  475. Auth authp9any = {
  476. "p9any",
  477. p9anyauth,
  478. p9anyattach,
  479. p9anyinit,
  480. p9anyread,
  481. p9anywrite,
  482. p9anyclunk,
  483. };