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