wpa support for tcp boot, remove duplicate secstore code from factotum

to run aux/wpa at boot, we need factotum to be running. tho
factotum was started only after the network was configured.

what we do now is start factotum early, not fetching keys
from secstore. once network is available and the auth server
is known, we fetch keys from secstore using auth/secstore in
bootrc.

to pass the authserver for p9 authentication to factotum, we
write it in /net/ndb and the special _authdial() in factotum
will picks it up.

as we are using auth/secstore binary in any case, we remove
the duplicated secstore code from factotum and make it just
exec auth/secstore to fetch the keys on startup (unless -n
or -S is specified).
This commit is contained in:
cinap_lenrek 2014-04-18 20:55:41 +02:00
parent fc15a01d1d
commit 8d0e4cf37b
7 changed files with 102 additions and 726 deletions

View file

@ -78,15 +78,9 @@ fn main{
}
}
# config method
$mp(1) $ma
# authentication agent
if(test -f /srv/factotum){
rm -f /srv/factotum
user=`{cat /dev/hostowner}
}
x=(/boot/factotum -sfactotum)
if(! test -f /srv/factotum){
x=(/boot/factotum -n -sfactotum)
if(~ $service cpu){
x=($x -S)
if(~ -k $ff)
@ -99,6 +93,19 @@ fn main{
if(! ~ $#debugfactotum 0)
x=($x -p)
must $x
}
# config method
$mp(1) $ma
# load keys from secstore
if(~ $#auth 1 && test -x /bin/auth/secstore && test -f /mnt/factotum/ctl){
x=(auth/secstore -G factotum -s $auth)
if(~ $service cpu)
$x -n >/mnt/factotum/ctl
if(~ $status *readnvram* || ! ~ $service cpu)
$x >/mnt/factotum/ctl
}
# connect method
$mp(2) $ma

View file

@ -1,6 +1,20 @@
#!/bin/rc
fn confignet{
# get primary default interface if not specified
if(~ $#* 0){
e=/net/ether*
if(! ~ $e '/net/ether*')
*=(ether $e(1))
}
# setup wifi encryption if any
if(~ $1 ether && ~ $service terminal && test -x /bin/aux/wpa){
if(grep -s '^status: need authentication' $2/ifstats){
aux/wpa -p $2
}
}
must ip/ipconfig -p $*
if(~ $#fs 0)
fs=`{awk -F'=' '/fs=/{print $2; exit}' /net/ndb}
@ -8,8 +22,11 @@ fn confignet{
auth=`{awk -F'=' '/auth=/{print $2; exit}' /net/ndb}
if(~ $#fs 0)
ask fs ' ip is? ' $auth
if(~ $#auth 0)
if(~ $#auth 0){
ask auth ' ip is? ' $fs
if(~ $#auth 1)
echo ' auth='^$auth >>/net/ndb
}
}
fn connecttcp{

View file

@ -179,10 +179,6 @@ void rpcread(Req*);
void rpcwrite(Req*);
void retrpc(Req*, int, Fsstate*);
/* secstore.c */
int havesecstore(void);
int secstorefetch(char*);
/* util.c */
#define emalloc emalloc9p
#define estrdup estrdup9p
@ -217,7 +213,6 @@ void promptforhostowner(void);
char *readcons(char*, char*, int);
int replacekey(Key*, int before);
char *safecpy(char*, char*, int);
int secdial(void);
Attr *setattr(Attr*, char*, ...);
Attr *setattrs(Attr*, Attr*);
void sethostowner(void);

View file

@ -59,13 +59,11 @@ void
main(int argc, char **argv)
{
int i, trysecstore;
char err[ERRMAX], *s;
char *s;
Dir d;
Proto *p;
char *secstorepw;
trysecstore = 1;
secstorepw = nil;
ARGBEGIN{
case 'D':
@ -147,13 +145,11 @@ main(int argc, char **argv)
}
if(sflag){
s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw);
s = getnvramkey(kflag ? NVwrite : NVwriteonerr, nil);
if(s == nil)
fprint(2, "factotum warning: cannot read nvram: %r\n");
else if(ctlwrite(s, 0) < 0)
fprint(2, "factotum warning: cannot add nvram key: %r\n");
if(secstorepw != nil)
trysecstore = 1;
if (s != nil) {
memset(s, 0, strlen(s));
free(s);
@ -162,26 +158,6 @@ main(int argc, char **argv)
promptforhostowner();
owner = getuser();
if(trysecstore){
if(havesecstore() == 1){
while(secstorefetch(secstorepw) < 0){
rerrstr(err, sizeof err);
if(strcmp(err, "cancel") == 0)
break;
fprint(2, "factotum: secstorefetch: %r\n");
fprint(2, "Enter an empty password to quit.\n");
free(secstorepw);
secstorepw = nil; /* just try nvram pw once */
}
}else{
/*
rerrstr(err, sizeof err);
if(*err)
fprint(2, "factotum: havesecstore: %r\n");
*/
}
}
postmountsrv(&fs, service, mtpt, MBEFORE);
if(service){
nulldir(&d);
@ -193,6 +169,18 @@ main(int argc, char **argv)
fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s);
free(s);
}
if(trysecstore){
if(fork() == 0){
int fd;
if((fd = open(smprint("%s/factotum/ctl", mtpt), OWRITE)) < 0)
sysfatal("can't open factotum: %r");
dup(fd, 1);
execl("/bin/auth/secstore", "secstore", "-G", "factotum", nil);
exits(nil);
}
waitpid();
}
exits(nil);
}

View file

@ -23,7 +23,6 @@ FOFILES=\
log.$O\
rpc.$O\
util.$O\
secstore.$O\
HFILES=\
dat.h\

View file

@ -1,628 +0,0 @@
/*
* Various files from /sys/src/cmd/auth/secstore, just enough
* to download a file at boot time.
*/
#include "dat.h"
#include <ip.h>
enum{ CHK = 16};
enum{ MAXFILESIZE = 10*1024*1024 };
enum{// PW status bits
Enabled = (1<<0),
STA = (1<<1), // extra SecurID step
};
static char testmess[] = "__secstore\tPAK\nC=%s\nm=0\n";
int
havesecstore(void)
{
int m, n, fd;
uchar buf[500];
n = snprint((char*)buf, sizeof buf, testmess, owner);
hnputs(buf, 0x8000+n-2);
fd = secdial();
if(fd < 0)
return 0;
if(write(fd, buf, n) != n || readn(fd, buf, 2) != 2){
close(fd);
return 0;
}
n = ((buf[0]&0x7f)<<8) + buf[1];
if(n+1 > sizeof buf){
werrstr("implausibly large count %d", n);
close(fd);
return 0;
}
m = readn(fd, buf, n);
close(fd);
if(m != n){
if(m >= 0)
werrstr("short read from secstore");
return 0;
}
buf[n] = 0;
if(strcmp((char*)buf, "!account expired") == 0){
werrstr("account expired");
return 0;
}
return strcmp((char*)buf, "!account exists") == 0;
}
// delimited, authenticated, encrypted connection
enum{ Maxmsg=4096 }; // messages > Maxmsg bytes are truncated
typedef struct SConn SConn;
extern SConn* newSConn(int); // arg is open file descriptor
struct SConn{
void *chan;
int secretlen;
int (*secret)(SConn*, uchar*, int);//
int (*read)(SConn*, uchar*, int); // <0 if error; errmess in buffer
int (*write)(SConn*, uchar*, int);
void (*free)(SConn*); // also closes file descriptor
};
// secret(s,b,dir) sets secret for digest, encrypt, using the secretlen
// bytes in b to form keys for the two directions;
// set dir=0 in client, dir=1 in server
// error convention: write !message in-band
#define readstr secstore_readstr
static void writerr(SConn*, char*);
static int readstr(SConn*, char*); // call with buf of size Maxmsg+1
// returns -1 upon error, with error message in buf
typedef struct ConnState {
uchar secret[SHA1dlen];
ulong seqno;
RC4state rc4;
} ConnState;
typedef struct SS{
int fd; // file descriptor for read/write of encrypted data
int alg; // if nonzero, "alg sha rc4_128"
ConnState in, out;
} SS;
static int
SC_secret(SConn *conn, uchar *sigma, int direction)
{
SS *ss = (SS*)(conn->chan);
int nsigma = conn->secretlen;
if(direction != 0){
hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->out.secret, nil);
hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->in.secret, nil);
}else{
hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->out.secret, nil);
hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->in.secret, nil);
}
setupRC4state(&ss->in.rc4, ss->in.secret, 16); // restrict to 128 bits
setupRC4state(&ss->out.rc4, ss->out.secret, 16);
ss->alg = 1;
return 0;
}
static void
hash(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen])
{
DigestState sha;
uchar seq[4];
seq[0] = seqno>>24;
seq[1] = seqno>>16;
seq[2] = seqno>>8;
seq[3] = seqno;
memset(&sha, 0, sizeof sha);
sha1(secret, SHA1dlen, nil, &sha);
sha1(data, len, nil, &sha);
sha1(seq, 4, d, &sha);
}
static int
verify(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen])
{
DigestState sha;
uchar seq[4];
uchar digest[SHA1dlen];
seq[0] = seqno>>24;
seq[1] = seqno>>16;
seq[2] = seqno>>8;
seq[3] = seqno;
memset(&sha, 0, sizeof sha);
sha1(secret, SHA1dlen, nil, &sha);
sha1(data, len, nil, &sha);
sha1(seq, 4, digest, &sha);
return memcmp(d, digest, SHA1dlen);
}
static int
SC_read(SConn *conn, uchar *buf, int n)
{
SS *ss = (SS*)(conn->chan);
uchar count[2], digest[SHA1dlen];
int len, nr;
if(read(ss->fd, count, 2) != 2 || count[0]&0x80 == 0){
werrstr("!SC_read invalid count");
return -1;
}
len = (count[0]&0x7f)<<8 | count[1]; // SSL-style count; no pad
if(ss->alg){
len -= SHA1dlen;
if(len <= 0 || readn(ss->fd, digest, SHA1dlen) != SHA1dlen){
werrstr("!SC_read missing sha1");
return -1;
}
if(len > n || readn(ss->fd, buf, len) != len){
werrstr("!SC_read missing data");
return -1;
}
rc4(&ss->in.rc4, digest, SHA1dlen);
rc4(&ss->in.rc4, buf, len);
if(verify(ss->in.secret, buf, len, ss->in.seqno, digest) != 0){
werrstr("!SC_read integrity check failed");
return -1;
}
}else{
if(len <= 0 || len > n){
werrstr("!SC_read implausible record length");
return -1;
}
if( (nr = readn(ss->fd, buf, len)) != len){
werrstr("!SC_read expected %d bytes, but got %d", len, nr);
return -1;
}
}
ss->in.seqno++;
return len;
}
static int
SC_write(SConn *conn, uchar *buf, int n)
{
SS *ss = (SS*)(conn->chan);
uchar count[2], digest[SHA1dlen], enc[Maxmsg+1];
int len;
if(n <= 0 || n > Maxmsg+1){
werrstr("!SC_write invalid n %d", n);
return -1;
}
len = n;
if(ss->alg)
len += SHA1dlen;
count[0] = 0x80 | len>>8;
count[1] = len;
if(write(ss->fd, count, 2) != 2){
werrstr("!SC_write invalid count");
return -1;
}
if(ss->alg){
hash(ss->out.secret, buf, n, ss->out.seqno, digest);
rc4(&ss->out.rc4, digest, SHA1dlen);
memcpy(enc, buf, n);
rc4(&ss->out.rc4, enc, n);
if(write(ss->fd, digest, SHA1dlen) != SHA1dlen ||
write(ss->fd, enc, n) != n){
werrstr("!SC_write error on send");
return -1;
}
}else{
if(write(ss->fd, buf, n) != n){
werrstr("!SC_write error on send");
return -1;
}
}
ss->out.seqno++;
return n;
}
static void
SC_free(SConn *conn)
{
SS *ss = (SS*)(conn->chan);
close(ss->fd);
free(ss);
free(conn);
}
SConn*
newSConn(int fd)
{
SS *ss;
SConn *conn;
if(fd < 0)
return nil;
ss = (SS*)emalloc(sizeof(*ss));
conn = (SConn*)emalloc(sizeof(*conn));
ss->fd = fd;
ss->alg = 0;
conn->chan = (void*)ss;
conn->secretlen = SHA1dlen;
conn->free = SC_free;
conn->secret = SC_secret;
conn->read = SC_read;
conn->write = SC_write;
return conn;
}
static void
writerr(SConn *conn, char *s)
{
char buf[Maxmsg];
snprint(buf, Maxmsg, "!%s", s);
conn->write(conn, (uchar*)buf, strlen(buf));
}
static int
readstr(SConn *conn, char *s)
{
int n;
n = conn->read(conn, (uchar*)s, Maxmsg);
if(n >= 0){
s[n] = 0;
if(s[0] == '!'){
memmove(s, s+1, n);
n = -1;
}
}else{
strcpy(s, "read error");
}
return n;
}
static int
getfile(SConn *conn, uchar *key, int nkey)
{
char *buf;
int nbuf, n, nr, len;
char s[Maxmsg+1], *gf, *p, *q;
uchar skey[SHA1dlen], ib[Maxmsg+CHK], *ibr, *ibw;
AESstate aes;
DigestState *sha;
gf = "factotum";
memset(&aes, 0, sizeof aes);
snprint(s, Maxmsg, "GET %s\n", gf);
conn->write(conn, (uchar*)s, strlen(s));
/* get file size */
s[0] = '\0';
if(readstr(conn, s) < 0){
werrstr("secstore: %r");
return -1;
}
if((len = atoi(s)) < 0){
werrstr("secstore: remote file %s does not exist", gf);
return -1;
}else if(len > MAXFILESIZE){//assert
werrstr("secstore: implausible file size %d for %s", len, gf);
return -1;
}
ibr = ibw = ib;
buf = nil;
nbuf = 0;
for(nr=0; nr < len;){
if((n = conn->read(conn, ibw, Maxmsg)) <= 0){
werrstr("secstore: empty file chunk n=%d nr=%d len=%d: %r", n, nr, len);
return -1;
}
nr += n;
ibw += n;
if(!aes.setup){ /* first time, read 16 byte IV */
if(n < 16){
werrstr("secstore: no IV in file");
return -1;
}
sha = sha1((uchar*)"aescbc file", 11, nil, nil);
sha1(key, nkey, skey, sha);
setupAESstate(&aes, skey, AESbsize, ibr);
memset(skey, 0, sizeof skey);
ibr += AESbsize;
n -= AESbsize;
}
aesCBCdecrypt(ibw-n, n, &aes);
n = ibw-ibr-CHK;
if(n > 0){
buf = erealloc(buf, nbuf+n+1);
memmove(buf+nbuf, ibr, n);
nbuf += n;
ibr += n;
}
memmove(ib, ibr, ibw-ibr);
ibw = ib + (ibw-ibr);
ibr = ib;
}
n = ibw-ibr;
if((n != CHK) || (memcmp(ib, "XXXXXXXXXXXXXXXX", CHK) != 0)){
werrstr("secstore: decrypted file failed to authenticate!");
free(buf);
return -1;
}
if(nbuf == 0){
werrstr("secstore got empty file");
return -1;
}
buf[nbuf] = '\0';
p = buf;
n = 0;
while(p){
if(q = strchr(p, '\n'))
*q++ = '\0';
n++;
if(ctlwrite(p, 0) < 0)
fprint(2, "factotum: secstore(%s) line %d: %r\n", gf, n);
p = q;
}
free(buf);
return 0;
}
static char VERSION[] = "secstore";
typedef struct PAKparams{
mpint *q, *p, *r, *g;
} PAKparams;
static PAKparams *pak;
// This group was generated by the seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E.
static void
initPAKparams(void)
{
if(pak)
return;
pak = (PAKparams*)emalloc(sizeof(*pak));
pak->q = strtomp("E0F0EF284E10796C5A2A511E94748BA03C795C13", nil, 16, nil);
pak->p = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBD"
"B12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A86"
"3A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D9"
"3D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D", nil, 16, nil);
pak->r = strtomp("DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF"
"2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887"
"D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21"
"C4656848614D888A4", nil, 16, nil);
pak->g = strtomp("2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444"
"ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD41"
"0E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E"
"2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1", nil, 16, nil);
}
// H = (sha(ver,C,sha(passphrase)))^r mod p,
// a hash function expensive to attack by brute force.
static void
longhash(char *ver, char *C, uchar *passwd, mpint *H)
{
uchar *Cp;
int i, n, nver, nC;
uchar buf[140], key[1];
nver = strlen(ver);
nC = strlen(C);
n = nver + nC + SHA1dlen;
Cp = (uchar*)emalloc(n);
memmove(Cp, ver, nver);
memmove(Cp+nver, C, nC);
memmove(Cp+nver+nC, passwd, SHA1dlen);
for(i = 0; i < 7; i++){
key[0] = 'A'+i;
hmac_sha1(Cp, n, key, sizeof key, buf+i*SHA1dlen, nil);
}
memset(Cp, 0, n);
free(Cp);
betomp(buf, sizeof buf, H);
mpmod(H, pak->p, H);
mpexp(H, pak->r, pak->p, H);
}
// Hi = H^-1 mod p
static char *
PAK_Hi(char *C, char *passphrase, mpint *H, mpint *Hi)
{
uchar passhash[SHA1dlen];
sha1((uchar *)passphrase, strlen(passphrase), passhash, nil);
initPAKparams();
longhash(VERSION, C, passhash, H);
mpinvert(H, pak->p, Hi);
return mptoa(Hi, 64, nil, 0);
}
// another, faster, hash function for each party to
// confirm that the other has the right secrets.
static void
shorthash(char *mess, char *C, char *S, char *m, char *mu, char *sigma, char *Hi, uchar *digest)
{
SHA1state *state;
state = sha1((uchar*)mess, strlen(mess), 0, 0);
state = sha1((uchar*)C, strlen(C), 0, state);
state = sha1((uchar*)S, strlen(S), 0, state);
state = sha1((uchar*)m, strlen(m), 0, state);
state = sha1((uchar*)mu, strlen(mu), 0, state);
state = sha1((uchar*)sigma, strlen(sigma), 0, state);
state = sha1((uchar*)Hi, strlen(Hi), 0, state);
state = sha1((uchar*)mess, strlen(mess), 0, state);
state = sha1((uchar*)C, strlen(C), 0, state);
state = sha1((uchar*)S, strlen(S), 0, state);
state = sha1((uchar*)m, strlen(m), 0, state);
state = sha1((uchar*)mu, strlen(mu), 0, state);
state = sha1((uchar*)sigma, strlen(sigma), 0, state);
sha1((uchar*)Hi, strlen(Hi), digest, state);
}
// On input, conn provides an open channel to the server;
// C is the name this client calls itself;
// pass is the user's passphrase
// On output, session secret has been set in conn
// (unless return code is negative, which means failure).
// If pS is not nil, it is set to the (alloc'd) name the server calls itself.
static int
PAKclient(SConn *conn, char *C, char *pass, char **pS)
{
char *mess, *mess2, *eol, *S, *hexmu, *ks, *hexm, *hexsigma = nil, *hexHi;
char kc[2*SHA1dlen+1];
uchar digest[SHA1dlen];
int rc = -1, n;
mpint *x, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
mpint *H = mpnew(0), *Hi = mpnew(0);
hexHi = PAK_Hi(C, pass, H, Hi);
// random 1<=x<=q-1; send C, m=g**x H
x = mprand(164, genrandom, nil);
mpmod(x, pak->q, x);
if(mpcmp(x, mpzero) == 0)
mpassign(mpone, x);
mpexp(pak->g, x, pak->p, m);
mpmul(m, H, m);
mpmod(m, pak->p, m);
hexm = mptoa(m, 64, nil, 0);
mess = (char*)emalloc(2*Maxmsg+2);
mess2 = mess+Maxmsg+1;
snprint(mess, Maxmsg, "%s\tPAK\nC=%s\nm=%s\n", VERSION, C, hexm);
conn->write(conn, (uchar*)mess, strlen(mess));
// recv g**y, S, check hash1(g**xy)
if(readstr(conn, mess) < 0){
fprint(2, "factotum: error: %s\n", mess);
writerr(conn, "couldn't read g**y");
goto done;
}
eol = strchr(mess, '\n');
if(strncmp("mu=", mess, 3) != 0 || !eol || strncmp("\nk=", eol, 3) != 0){
writerr(conn, "verifier syntax error");
goto done;
}
hexmu = mess+3;
*eol = 0;
ks = eol+3;
eol = strchr(ks, '\n');
if(!eol || strncmp("\nS=", eol, 3) != 0){
writerr(conn, "verifier syntax error for secstore 1.0");
goto done;
}
*eol = 0;
S = eol+3;
eol = strchr(S, '\n');
if(!eol){
writerr(conn, "verifier syntax error for secstore 1.0");
goto done;
}
*eol = 0;
if(pS)
*pS = estrdup(S);
strtomp(hexmu, nil, 64, mu);
mpexp(mu, x, pak->p, sigma);
hexsigma = mptoa(sigma, 64, nil, 0);
shorthash("server", C, S, hexm, hexmu, hexsigma, hexHi, digest);
enc64(kc, sizeof kc, digest, SHA1dlen);
if(strcmp(ks, kc) != 0){
writerr(conn, "verifier didn't match");
goto done;
}
// send hash2(g**xy)
shorthash("client", C, S, hexm, hexmu, hexsigma, hexHi, digest);
enc64(kc, sizeof kc, digest, SHA1dlen);
snprint(mess2, Maxmsg, "k'=%s\n", kc);
conn->write(conn, (uchar*)mess2, strlen(mess2));
// set session key
shorthash("session", C, S, hexm, hexmu, hexsigma, hexHi, digest);
memset(hexsigma, 0, strlen(hexsigma));
n = conn->secret(conn, digest, 0);
memset(digest, 0, SHA1dlen);
if(n < 0){//assert
writerr(conn, "can't set secret");
goto done;
}
rc = 0;
done:
mpfree(x);
mpfree(sigma);
mpfree(mu);
mpfree(m);
mpfree(Hi);
mpfree(H);
free(hexsigma);
free(hexHi);
free(hexm);
free(mess);
return rc;
}
int
secstorefetch(char *password)
{
int rv = -1, fd;
char s[Maxmsg+1];
SConn *conn;
char *pass, *sta;
sta = nil;
conn = nil;
if(password != nil && *password)
pass = estrdup(password);
else
pass = readcons("secstore password", nil, 1);
if(pass==nil || strlen(pass)==0){
werrstr("cancel");
goto Out;
}
if((fd = secdial()) < 0)
goto Out;
if((conn = newSConn(fd)) == nil)
goto Out;
if(PAKclient(conn, owner, pass, nil) < 0){
werrstr("password mistyped?");
goto Out;
}
if(readstr(conn, s) < 0)
goto Out;
if(strcmp(s, "STA") == 0){
sta = readcons("STA PIN+SecureID", nil, 1);
if(sta==nil || strlen(sta)==0){
werrstr("cancel");
goto Out;
}
if(strlen(sta) >= sizeof s - 3){
werrstr("STA response too long");
goto Out;
}
strcpy(s+3, sta);
conn->write(conn, (uchar*)s, strlen(s));
readstr(conn, s);
}
if(strcmp(s, "OK") !=0){
werrstr("%s", s);
goto Out;
}
if(getfile(conn, (uchar*)pass, strlen(pass)) < 0)
goto Out;
conn->write(conn, (uchar*)"BYE", 3);
rv = 0;
Out:
if(conn)
conn->free(conn);
if(pass)
free(pass);
if(sta)
free(sta);
return rv;
}

View file

@ -22,6 +22,45 @@ bindnetcs(void)
return 0;
}
/* get auth= attribute value from /net/ndb */
static char*
netndbauthaddr(void)
{
enum { CHUNK = 1024 };
char *b, *p, *e;
int fd, n, m;
if((fd = open("/net/ndb", OREAD)) < 0)
return nil;
m = 0;
b = nil;
for(;;){
if((p = realloc(b, m+CHUNK+1)) == nil)
break;
b = p;
if((n = read(fd, b+m, CHUNK)) <= 0)
break;
m += n;
}
close(fd);
if(b == nil)
return nil;
b[m] = '\0';
p = strstr(b, "auth=");
if(p != nil && p > b && strchr("\n\t ", p[-1]) == nil)
p = nil;
if(p != nil){
p += strlen("auth=");
for(e = p; *e != '\0'; e++)
if(strchr("\n\t ", *e) != nil)
break;
*e = '\0';
p = estrdup(p);
}
free(b);
return p;
}
int
_authdial(char *net, char *authdom)
{
@ -35,7 +74,8 @@ _authdial(char *net, char *authdom)
/*
* If we failed to mount /srv/cs, assume that
* we're still bootstrapping the system and dial
* the one auth server passed to us on the command line.
* the one auth server passed to us on the command line or
* look for auth= attribute in /net/ndb.
* In normal operation, it is important *not* to do this,
* because the bootstrap auth server is only good for
* a single auth domain.
@ -43,9 +83,9 @@ _authdial(char *net, char *authdom)
* The ticket request code should really check the
* remote authentication domain too.
*/
/* use the auth server passed to us as an arg */
fd = -1;
if(authaddr == nil)
authaddr = netndbauthaddr();
if(authaddr != nil){
fd = dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
if(fd < 0)
@ -56,46 +96,6 @@ _authdial(char *net, char *authdom)
return fd;
}
int
secdial(void)
{
char *p, buf[80], *f[3];
int fd, nf;
p = secstore; /* take it from writehostowner, if set there */
if(*p == 0) /* else use the authserver */
p = "$auth";
if(bindnetcs() >= 0)
return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
/* translate $auth ourselves.
* authaddr is something like il!host!566 or tcp!host!567.
* extract host, accounting for a change of format to something
* like il!host or tcp!host or host.
*/
if(strcmp(p, "$auth")==0){
if(authaddr == nil)
return -1;
safecpy(buf, authaddr, sizeof buf);
nf = getfields(buf, f, nelem(f), 0, "!");
switch(nf){
default:
return -1;
case 1:
p = f[0];
break;
case 2:
case 3:
p = f[1];
break;
}
}
fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
if(fd >= 0)
return fd;
return -1;
}
/*
* prompt user for a key. don't care about memory leaks, runs standalone
*/
@ -483,7 +483,7 @@ getnvramkey(int flag, char **secstorepw)
*/
memmove(spw, safe.config, CONFIGLEN);
spw[CONFIGLEN] = 0;
if(spw[0] != 0)
if(spw[0] != 0 && secstorepw != nil)
*secstorepw = estrdup(spw);
/*
@ -955,10 +955,8 @@ writehostowner(char *owner)
int fd;
char *s;
if((s = strchr(owner,'@')) != nil){
*s++ = 0;
strncpy(secstore, s, (sizeof secstore)-1);
}
if((s = strchr(owner,'@')) != nil)
*s = 0;
fd = open("#c/hostowner", OWRITE);
if(fd >= 0){
if(fprint(fd, "%s", owner) < 0)