plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

secstore.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 }