secstore.c 15 KB

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