secstore.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /*
  2. * Various files from /sys/src/cmd/auth/secstore, just enough
  3. * to download a file at boot time.
  4. */
  5. #include <u.h>
  6. #include <libc.h>
  7. #include <mp.h>
  8. #include <libsec.h>
  9. #include "drawterm.h"
  10. static void*
  11. emalloc(ulong n)
  12. {
  13. return mallocz(n, 1);
  14. }
  15. enum{ CHK = 16};
  16. enum{ MAXFILESIZE = 10*1024*1024 };
  17. enum{// PW status bits
  18. Enabled = (1<<0),
  19. STA = (1<<1), // extra SecurID step
  20. };
  21. static char testmess[] = "__secstore\tPAK\nC=%s\nm=0\n";
  22. int
  23. secdial(char *secstore)
  24. {
  25. char *p, buf[80], *f[3];
  26. int fd, nf;
  27. p = secstore; /* take it from writehostowner, if set there */
  28. if(*p == 0) /* else use the authserver */
  29. p = "$auth";
  30. /* translate $auth ourselves.
  31. * authaddr is something like il!host!566 or tcp!host!567.
  32. * extract host, accounting for a change of format to something
  33. * like il!host or tcp!host or host.
  34. */
  35. if(strcmp(p, "$auth")==0){
  36. if(authserver == nil)
  37. return -1;
  38. strecpy(buf, buf+sizeof buf, authserver);
  39. nf = getfields(buf, f, nelem(f), 0, "!");
  40. switch(nf){
  41. default:
  42. return -1;
  43. case 1:
  44. p = f[0];
  45. break;
  46. case 2:
  47. case 3:
  48. p = f[1];
  49. break;
  50. }
  51. }
  52. fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
  53. if(fd >= 0)
  54. return fd;
  55. return -1;
  56. }
  57. int
  58. havesecstore(char *addr, char *owner)
  59. {
  60. int m, n, fd;
  61. uchar buf[500];
  62. n = snprint((char*)buf, sizeof buf, testmess, owner);
  63. hnputs(buf, 0x8000+n-2);
  64. fd = secdial(addr);
  65. if(fd < 0)
  66. return 0;
  67. if(write(fd, buf, n) != n || readn(fd, buf, 2) != 2){
  68. close(fd);
  69. return 0;
  70. }
  71. n = ((buf[0]&0x7f)<<8) + buf[1];
  72. if(n+1 > sizeof buf){
  73. werrstr("implausibly large count %d", n);
  74. close(fd);
  75. return 0;
  76. }
  77. m = readn(fd, buf, n);
  78. close(fd);
  79. if(m != n){
  80. if(m >= 0)
  81. werrstr("short read from secstore");
  82. return 0;
  83. }
  84. buf[n] = 0;
  85. if(strcmp((char*)buf, "!account expired") == 0){
  86. werrstr("account expired");
  87. return 0;
  88. }
  89. return strcmp((char*)buf, "!account exists") == 0;
  90. }
  91. // delimited, authenticated, encrypted connection
  92. enum{ Maxmsg=4096 }; // messages > Maxmsg bytes are truncated
  93. typedef struct SConn SConn;
  94. extern SConn* newSConn(int); // arg is open file descriptor
  95. struct SConn{
  96. void *chan;
  97. int secretlen;
  98. int (*secret)(SConn*, uchar*, int);//
  99. int (*read)(SConn*, uchar*, int); // <0 if error; errmess in buffer
  100. int (*write)(SConn*, uchar*, int);
  101. void (*free)(SConn*); // also closes file descriptor
  102. };
  103. // secret(s,b,dir) sets secret for digest, encrypt, using the secretlen
  104. // bytes in b to form keys for the two directions;
  105. // set dir=0 in client, dir=1 in server
  106. // error convention: write !message in-band
  107. #define readstr secstore_readstr
  108. static void writerr(SConn*, char*);
  109. static int readstr(SConn*, char*); // call with buf of size Maxmsg+1
  110. // returns -1 upon error, with error message in buf
  111. typedef struct ConnState {
  112. uchar secret[SHA1dlen];
  113. ulong seqno;
  114. RC4state rc4;
  115. } ConnState;
  116. typedef struct SS{
  117. int fd; // file descriptor for read/write of encrypted data
  118. int alg; // if nonzero, "alg sha rc4_128"
  119. ConnState in, out;
  120. } SS;
  121. static int
  122. SC_secret(SConn *conn, uchar *sigma, int direction)
  123. {
  124. SS *ss = (SS*)(conn->chan);
  125. int nsigma = conn->secretlen;
  126. if(direction != 0){
  127. hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->out.secret, nil);
  128. hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->in.secret, nil);
  129. }else{
  130. hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->out.secret, nil);
  131. hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->in.secret, nil);
  132. }
  133. setupRC4state(&ss->in.rc4, ss->in.secret, 16); // restrict to 128 bits
  134. setupRC4state(&ss->out.rc4, ss->out.secret, 16);
  135. ss->alg = 1;
  136. return 0;
  137. }
  138. static void
  139. hash(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen])
  140. {
  141. DigestState sha;
  142. uchar seq[4];
  143. seq[0] = seqno>>24;
  144. seq[1] = seqno>>16;
  145. seq[2] = seqno>>8;
  146. seq[3] = seqno;
  147. memset(&sha, 0, sizeof sha);
  148. sha1(secret, SHA1dlen, nil, &sha);
  149. sha1(data, len, nil, &sha);
  150. sha1(seq, 4, d, &sha);
  151. }
  152. static int
  153. verify(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen])
  154. {
  155. DigestState sha;
  156. uchar seq[4];
  157. uchar digest[SHA1dlen];
  158. seq[0] = seqno>>24;
  159. seq[1] = seqno>>16;
  160. seq[2] = seqno>>8;
  161. seq[3] = seqno;
  162. memset(&sha, 0, sizeof sha);
  163. sha1(secret, SHA1dlen, nil, &sha);
  164. sha1(data, len, nil, &sha);
  165. sha1(seq, 4, digest, &sha);
  166. return memcmp(d, digest, SHA1dlen);
  167. }
  168. static int
  169. SC_read(SConn *conn, uchar *buf, int n)
  170. {
  171. SS *ss = (SS*)(conn->chan);
  172. uchar count[2], digest[SHA1dlen];
  173. int len, nr;
  174. if(read(ss->fd, count, 2) != 2 || (count[0]&0x80) == 0){
  175. werrstr("!SC_read invalid count");
  176. return -1;
  177. }
  178. len = (count[0]&0x7f)<<8 | count[1]; // SSL-style count; no pad
  179. if(ss->alg){
  180. len -= SHA1dlen;
  181. if(len <= 0 || readn(ss->fd, digest, SHA1dlen) != SHA1dlen){
  182. werrstr("!SC_read missing sha1");
  183. return -1;
  184. }
  185. if(len > n || readn(ss->fd, buf, len) != len){
  186. werrstr("!SC_read missing data");
  187. return -1;
  188. }
  189. rc4(&ss->in.rc4, digest, SHA1dlen);
  190. rc4(&ss->in.rc4, buf, len);
  191. if(verify(ss->in.secret, buf, len, ss->in.seqno, digest) != 0){
  192. werrstr("!SC_read integrity check failed");
  193. return -1;
  194. }
  195. }else{
  196. if(len <= 0 || len > n){
  197. werrstr("!SC_read implausible record length");
  198. return -1;
  199. }
  200. if( (nr = readn(ss->fd, buf, len)) != len){
  201. werrstr("!SC_read expected %d bytes, but got %d", len, nr);
  202. return -1;
  203. }
  204. }
  205. ss->in.seqno++;
  206. return len;
  207. }
  208. static int
  209. SC_write(SConn *conn, uchar *buf, int n)
  210. {
  211. SS *ss = (SS*)(conn->chan);
  212. uchar count[2], digest[SHA1dlen];
  213. int len;
  214. if(n <= 0 || n > Maxmsg+1){
  215. werrstr("!SC_write invalid n %d", n);
  216. return -1;
  217. }
  218. len = n;
  219. if(ss->alg)
  220. len += SHA1dlen;
  221. count[0] = 0x80 | len>>8;
  222. count[1] = len;
  223. if(write(ss->fd, count, 2) != 2){
  224. werrstr("!SC_write invalid count");
  225. return -1;
  226. }
  227. if(ss->alg){
  228. hash(ss->out.secret, buf, n, ss->out.seqno, digest);
  229. rc4(&ss->out.rc4, digest, SHA1dlen);
  230. rc4(&ss->out.rc4, buf, n);
  231. if(write(ss->fd, digest, SHA1dlen) != SHA1dlen ||
  232. write(ss->fd, buf, n) != n){
  233. werrstr("!SC_write error on send");
  234. return -1;
  235. }
  236. }else{
  237. if(write(ss->fd, buf, n) != n){
  238. werrstr("!SC_write error on send");
  239. return -1;
  240. }
  241. }
  242. ss->out.seqno++;
  243. return n;
  244. }
  245. static void
  246. SC_free(SConn *conn)
  247. {
  248. SS *ss = (SS*)(conn->chan);
  249. close(ss->fd);
  250. free(ss);
  251. free(conn);
  252. }
  253. SConn*
  254. newSConn(int fd)
  255. {
  256. SS *ss;
  257. SConn *conn;
  258. if(fd < 0)
  259. return nil;
  260. ss = (SS*)emalloc(sizeof(*ss));
  261. conn = (SConn*)emalloc(sizeof(*conn));
  262. ss->fd = fd;
  263. ss->alg = 0;
  264. conn->chan = (void*)ss;
  265. conn->secretlen = SHA1dlen;
  266. conn->free = SC_free;
  267. conn->secret = SC_secret;
  268. conn->read = SC_read;
  269. conn->write = SC_write;
  270. return conn;
  271. }
  272. static void
  273. writerr(SConn *conn, char *s)
  274. {
  275. char buf[Maxmsg];
  276. snprint(buf, Maxmsg, "!%s", s);
  277. conn->write(conn, (uchar*)buf, strlen(buf));
  278. }
  279. static int
  280. readstr(SConn *conn, char *s)
  281. {
  282. int n;
  283. n = conn->read(conn, (uchar*)s, Maxmsg);
  284. if(n >= 0){
  285. s[n] = 0;
  286. if(s[0] == '!'){
  287. memmove(s, s+1, n);
  288. n = -1;
  289. }
  290. }else{
  291. strcpy(s, "read error");
  292. }
  293. return n;
  294. }
  295. static char*
  296. getfile(SConn *conn, uchar *key, int nkey)
  297. {
  298. char *buf;
  299. int nbuf, n, nr, len;
  300. char s[Maxmsg+1], *gf;
  301. uchar skey[SHA1dlen], ib[Maxmsg+CHK], *ibr, *ibw;
  302. AESstate aes;
  303. DigestState *sha;
  304. gf = "factotum";
  305. memset(&aes, 0, sizeof aes);
  306. snprint(s, Maxmsg, "GET %s\n", gf);
  307. conn->write(conn, (uchar*)s, strlen(s));
  308. /* get file size */
  309. s[0] = '\0';
  310. if(readstr(conn, s) < 0){
  311. werrstr("secstore: %r");
  312. return nil;
  313. }
  314. if((len = atoi(s)) < 0){
  315. werrstr("secstore: remote file %s does not exist", gf);
  316. return nil;
  317. }else if(len > MAXFILESIZE){//assert
  318. werrstr("secstore: implausible file size %d for %s", len, gf);
  319. return nil;
  320. }
  321. ibr = ibw = ib;
  322. buf = nil;
  323. nbuf = 0;
  324. for(nr=0; nr < len;){
  325. if((n = conn->read(conn, ibw, Maxmsg)) <= 0){
  326. werrstr("secstore: empty file chunk n=%d nr=%d len=%d: %r", n, nr, len);
  327. return nil;
  328. }
  329. nr += n;
  330. ibw += n;
  331. if(!aes.setup){ /* first time, read 16 byte IV */
  332. if(n < 16){
  333. werrstr("secstore: no IV in file");
  334. return nil;
  335. }
  336. sha = sha1((uchar*)"aescbc file", 11, nil, nil);
  337. sha1(key, nkey, skey, sha);
  338. setupAESstate(&aes, skey, AESbsize, ibr);
  339. memset(skey, 0, sizeof skey);
  340. ibr += AESbsize;
  341. n -= AESbsize;
  342. }
  343. aesCBCdecrypt(ibw-n, n, &aes);
  344. n = ibw-ibr-CHK;
  345. if(n > 0){
  346. buf = realloc(buf, nbuf+n+1);
  347. if(buf == nil)
  348. sysfatal("out of memory");
  349. memmove(buf+nbuf, ibr, n);
  350. nbuf += n;
  351. ibr += n;
  352. }
  353. memmove(ib, ibr, ibw-ibr);
  354. ibw = ib + (ibw-ibr);
  355. ibr = ib;
  356. }
  357. n = ibw-ibr;
  358. if((n != CHK) || (memcmp(ib, "XXXXXXXXXXXXXXXX", CHK) != 0)){
  359. werrstr("secstore: decrypted file failed to authenticate!");
  360. free(buf);
  361. return nil;
  362. }
  363. if(nbuf == 0){
  364. werrstr("secstore got empty file");
  365. return nil;
  366. }
  367. buf[nbuf] = '\0';
  368. return buf;
  369. }
  370. static char VERSION[] = "secstore";
  371. typedef struct PAKparams{
  372. mpint *q, *p, *r, *g;
  373. } PAKparams;
  374. static PAKparams *pak;
  375. // This group was generated by the seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E.
  376. static void
  377. initPAKparams(void)
  378. {
  379. if(pak)
  380. return;
  381. pak = (PAKparams*)emalloc(sizeof(*pak));
  382. pak->q = strtomp("E0F0EF284E10796C5A2A511E94748BA03C795C13", nil, 16, nil);
  383. pak->p = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBD"
  384. "B12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A86"
  385. "3A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D9"
  386. "3D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D", nil, 16, nil);
  387. pak->r = strtomp("DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF"
  388. "2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887"
  389. "D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21"
  390. "C4656848614D888A4", nil, 16, nil);
  391. pak->g = strtomp("2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444"
  392. "ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD41"
  393. "0E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E"
  394. "2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1", nil, 16, nil);
  395. }
  396. // H = (sha(ver,C,sha(passphrase)))^r mod p,
  397. // a hash function expensive to attack by brute force.
  398. static void
  399. longhash(char *ver, char *C, uchar *passwd, mpint *H)
  400. {
  401. uchar *Cp;
  402. int i, n, nver, nC;
  403. uchar buf[140], key[1];
  404. nver = strlen(ver);
  405. nC = strlen(C);
  406. n = nver + nC + SHA1dlen;
  407. Cp = (uchar*)emalloc(n);
  408. memmove(Cp, ver, nver);
  409. memmove(Cp+nver, C, nC);
  410. memmove(Cp+nver+nC, passwd, SHA1dlen);
  411. for(i = 0; i < 7; i++){
  412. key[0] = 'A'+i;
  413. hmac_sha1(Cp, n, key, sizeof key, buf+i*SHA1dlen, nil);
  414. }
  415. memset(Cp, 0, n);
  416. free(Cp);
  417. betomp(buf, sizeof buf, H);
  418. mpmod(H, pak->p, H);
  419. mpexp(H, pak->r, pak->p, H);
  420. }
  421. // Hi = H^-1 mod p
  422. static char *
  423. PAK_Hi(char *C, char *passphrase, mpint *H, mpint *Hi)
  424. {
  425. uchar passhash[SHA1dlen];
  426. sha1((uchar *)passphrase, strlen(passphrase), passhash, nil);
  427. initPAKparams();
  428. longhash(VERSION, C, passhash, H);
  429. mpinvert(H, pak->p, Hi);
  430. return mptoa(Hi, 64, nil, 0);
  431. }
  432. // another, faster, hash function for each party to
  433. // confirm that the other has the right secrets.
  434. static void
  435. shorthash(char *mess, char *C, char *S, char *m, char *mu, char *sigma, char *Hi, uchar *digest)
  436. {
  437. SHA1state *state;
  438. state = sha1((uchar*)mess, strlen(mess), 0, 0);
  439. state = sha1((uchar*)C, strlen(C), 0, state);
  440. state = sha1((uchar*)S, strlen(S), 0, state);
  441. state = sha1((uchar*)m, strlen(m), 0, state);
  442. state = sha1((uchar*)mu, strlen(mu), 0, state);
  443. state = sha1((uchar*)sigma, strlen(sigma), 0, state);
  444. state = sha1((uchar*)Hi, strlen(Hi), 0, state);
  445. state = sha1((uchar*)mess, strlen(mess), 0, state);
  446. state = sha1((uchar*)C, strlen(C), 0, state);
  447. state = sha1((uchar*)S, strlen(S), 0, state);
  448. state = sha1((uchar*)m, strlen(m), 0, state);
  449. state = sha1((uchar*)mu, strlen(mu), 0, state);
  450. state = sha1((uchar*)sigma, strlen(sigma), 0, state);
  451. sha1((uchar*)Hi, strlen(Hi), digest, state);
  452. }
  453. // On input, conn provides an open channel to the server;
  454. // C is the name this client calls itself;
  455. // pass is the user's passphrase
  456. // On output, session secret has been set in conn
  457. // (unless return code is negative, which means failure).
  458. // If pS is not nil, it is set to the (alloc'd) name the server calls itself.
  459. static int
  460. PAKclient(SConn *conn, char *C, char *pass, char **pS)
  461. {
  462. char *mess, *mess2, *eol, *S, *hexmu, *ks, *hexm, *hexsigma = nil, *hexHi;
  463. char kc[2*SHA1dlen+1];
  464. uchar digest[SHA1dlen];
  465. int rc = -1, n;
  466. mpint *x, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
  467. mpint *H = mpnew(0), *Hi = mpnew(0);
  468. hexHi = PAK_Hi(C, pass, H, Hi);
  469. // random 1<=x<=q-1; send C, m=g**x H
  470. x = mprand(164, genrandom, nil);
  471. mpmod(x, pak->q, x);
  472. if(mpcmp(x, mpzero) == 0)
  473. mpassign(mpone, x);
  474. mpexp(pak->g, x, pak->p, m);
  475. mpmul(m, H, m);
  476. mpmod(m, pak->p, m);
  477. hexm = mptoa(m, 64, nil, 0);
  478. mess = (char*)emalloc(2*Maxmsg+2);
  479. mess2 = mess+Maxmsg+1;
  480. snprint(mess, Maxmsg, "%s\tPAK\nC=%s\nm=%s\n", VERSION, C, hexm);
  481. conn->write(conn, (uchar*)mess, strlen(mess));
  482. // recv g**y, S, check hash1(g**xy)
  483. if(readstr(conn, mess) < 0){
  484. fprint(2, "error: %s\n", mess);
  485. writerr(conn, "couldn't read g**y");
  486. goto done;
  487. }
  488. eol = strchr(mess, '\n');
  489. if(strncmp("mu=", mess, 3) != 0 || !eol || strncmp("\nk=", eol, 3) != 0){
  490. writerr(conn, "verifier syntax error");
  491. goto done;
  492. }
  493. hexmu = mess+3;
  494. *eol = 0;
  495. ks = eol+3;
  496. eol = strchr(ks, '\n');
  497. if(!eol || strncmp("\nS=", eol, 3) != 0){
  498. writerr(conn, "verifier syntax error for secstore 1.0");
  499. goto done;
  500. }
  501. *eol = 0;
  502. S = eol+3;
  503. eol = strchr(S, '\n');
  504. if(!eol){
  505. writerr(conn, "verifier syntax error for secstore 1.0");
  506. goto done;
  507. }
  508. *eol = 0;
  509. if(pS)
  510. *pS = strdup(S);
  511. strtomp(hexmu, nil, 64, mu);
  512. mpexp(mu, x, pak->p, sigma);
  513. hexsigma = mptoa(sigma, 64, nil, 0);
  514. shorthash("server", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  515. enc64(kc, sizeof kc, digest, SHA1dlen);
  516. if(strcmp(ks, kc) != 0){
  517. writerr(conn, "verifier didn't match");
  518. goto done;
  519. }
  520. // send hash2(g**xy)
  521. shorthash("client", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  522. enc64(kc, sizeof kc, digest, SHA1dlen);
  523. snprint(mess2, Maxmsg, "k'=%s\n", kc);
  524. conn->write(conn, (uchar*)mess2, strlen(mess2));
  525. // set session key
  526. shorthash("session", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  527. memset(hexsigma, 0, strlen(hexsigma));
  528. n = conn->secret(conn, digest, 0);
  529. memset(digest, 0, SHA1dlen);
  530. if(n < 0){//assert
  531. writerr(conn, "can't set secret");
  532. goto done;
  533. }
  534. rc = 0;
  535. done:
  536. mpfree(x);
  537. mpfree(sigma);
  538. mpfree(mu);
  539. mpfree(m);
  540. mpfree(Hi);
  541. mpfree(H);
  542. free(hexsigma);
  543. free(hexHi);
  544. free(hexm);
  545. free(mess);
  546. return rc;
  547. }
  548. char*
  549. secstorefetch(char *addr, char *owner, char *password)
  550. {
  551. int fd;
  552. char *rv;
  553. char s[Maxmsg+1], bye[10];
  554. SConn *conn;
  555. char *pass, *sta;
  556. sta = nil;
  557. conn = nil;
  558. rv = nil;
  559. if(password != nil && *password)
  560. pass = strdup(password);
  561. else
  562. pass = readcons("secstore password", nil, 1);
  563. if(pass==nil || strlen(pass)==0){
  564. werrstr("cancel");
  565. goto Out;
  566. }
  567. if((fd = secdial(addr)) < 0)
  568. goto Out;
  569. if((conn = newSConn(fd)) == nil)
  570. goto Out;
  571. if(PAKclient(conn, owner, pass, nil) < 0){
  572. werrstr("password mistyped?");
  573. goto Out;
  574. }
  575. if(readstr(conn, s) < 0)
  576. goto Out;
  577. if(strcmp(s, "STA") == 0){
  578. sta = readcons("STA PIN+SecureID", nil, 1);
  579. if(sta==nil || strlen(sta)==0){
  580. werrstr("cancel");
  581. goto Out;
  582. }
  583. if(strlen(sta) >= sizeof s - 3){
  584. werrstr("STA response too long");
  585. goto Out;
  586. }
  587. strcpy(s+3, sta);
  588. conn->write(conn, (uchar*)s, strlen(s));
  589. readstr(conn, s);
  590. }
  591. if(strcmp(s, "OK") !=0){
  592. werrstr("%s", s);
  593. goto Out;
  594. }
  595. if((rv = getfile(conn, (uchar*)pass, strlen(pass))) == nil)
  596. goto Out;
  597. strcpy(bye, "BYE");
  598. conn->write(conn, (uchar*)bye, 3);
  599. Out:
  600. if(conn)
  601. conn->free(conn);
  602. if(pass)
  603. free(pass);
  604. if(sta)
  605. free(sta);
  606. return rv;
  607. }