diff options
Diffstat (limited to 'src/cmd/secstore/secstore.c')
-rw-r--r-- | src/cmd/secstore/secstore.c | 585 |
1 files changed, 0 insertions, 585 deletions
diff --git a/src/cmd/secstore/secstore.c b/src/cmd/secstore/secstore.c deleted file mode 100644 index 864aa88d..00000000 --- a/src/cmd/secstore/secstore.c +++ /dev/null @@ -1,585 +0,0 @@ -/* network login client */ -#include <u.h> -#include <libc.h> -#include <mp.h> -#include <libsec.h> -#include <authsrv.h> -#include "SConn.h" -#include "secstore.h" -enum{ CHK = 16, MAXFILES = 100 }; - -typedef struct AuthConn{ - SConn *conn; - char pass[64]; - int passlen; -} AuthConn; - -int verbose; -Nvrsafe nvr; -char *SECSTORE_DIR; - -void -usage(void) -{ - fprint(2, "usage: secstore [-cin] [-g getfile] [-p putfile] [-r rmfile] [-s tcp!server!5356] [-u user] [-v]\n"); - exits("usage"); -} - -static int -getfile(SConn *conn, char *gf, uchar **buf, ulong *buflen, uchar *key, int nkey) -{ - int fd = -1; - int i, n, nr, nw, len; - char s[Maxmsg+1]; - uchar skey[SHA1dlen], ib[Maxmsg+CHK], *ibr, *ibw, *bufw, *bufe; - AESstate aes; - DigestState *sha; - - if(strchr(gf, '/')){ - fprint(2, "simple filenames, not paths like %s\n", gf); - return -1; - } - 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'; - bufw = bufe = nil; - if(readstr(conn, s) < 0){ - fprint(2, "remote: %s\n", s); - return -1; - } - len = atoi(s); - if(len == -1){ - fprint(2, "remote file %s does not exist\n", gf); - return -1; - }else if(len == -3){ - fprint(2, "implausible filesize for %s\n", gf); - return -1; - }else if(len < 0){ - fprint(2, "GET refused for %s\n", gf); - return -1; - } - if(buf != nil){ - *buflen = len - AESbsize - CHK; - *buf = bufw = emalloc(len); - bufe = bufw + len; - } - - /* directory listing */ - if(strcmp(gf,".")==0){ - if(buf != nil) - *buflen = len; - for(i=0; i < len; i += n){ - if((n = conn->read(conn, (uchar*)s, Maxmsg)) <= 0){ - fprint(2, "empty file chunk\n"); - return -1; - } - if(buf == nil) - write(1, s, n); - else - memmove((*buf)+i, s, n); - } - return 0; - } - - /* conn is already encrypted against wiretappers, - but gf is also encrypted against server breakin. */ - if(buf == nil && (fd =create(gf, OWRITE, 0600)) < 0){ - fprint(2, "can't open %s: %r\n", gf); - return -1; - } - - ibr = ibw = ib; - for(nr=0; nr < len;){ - if((n = conn->read(conn, ibw, Maxmsg)) <= 0){ - fprint(2, "empty file chunk n=%d nr=%d len=%d: %r\n", n, nr, len); - return -1; - } - nr += n; - ibw += n; - if(!aes.setup){ /* first time, read 16 byte IV */ - if(n < AESbsize){ - fprint(2, "no IV in file\n"); - 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){ - if(buf == nil){ - nw = write(fd, ibr, n); - if(nw != n){ - fprint(2, "write error on %s", gf); - return -1; - } - }else{ - assert(bufw+n <= bufe); - memmove(bufw, ibr, n); - bufw += n; - } - ibr += n; - } - memmove(ib, ibr, ibw-ibr); - ibw = ib + (ibw-ibr); - ibr = ib; - } - if(buf == nil) - close(fd); - n = ibw-ibr; - if((n != CHK) || (memcmp(ib, "XXXXXXXXXXXXXXXX", CHK) != 0)){ - fprint(2,"decrypted file failed to authenticate!\n"); - return -1; - } - return 0; -} - -// This sends a file to the secstore disk that can, in an emergency, be -// decrypted by the program aescbc.c. -static int -putfile(SConn *conn, char *pf, uchar *buf, ulong len, uchar *key, int nkey) -{ - int i, n, fd, ivo, bufi, done; - char s[Maxmsg]; - uchar skey[SHA1dlen], b[CHK+Maxmsg], IV[AESbsize]; - AESstate aes; - DigestState *sha; - - /* create initialization vector */ - srand(time(0)); /* doesn't need to be unpredictable */ - for(i=0; i<AESbsize; i++) - IV[i] = 0xff & rand(); - sha = sha1((uchar*)"aescbc file", 11, nil, nil); - sha1(key, nkey, skey, sha); - setupAESstate(&aes, skey, AESbsize, IV); - memset(skey, 0, sizeof skey); - - snprint(s, Maxmsg, "PUT %s\n", pf); - conn->write(conn, (uchar*)s, strlen(s)); - - if(buf == nil){ - /* get file size */ - if((fd = open(pf, OREAD)) < 0){ - fprint(2, "can't open %s: %r\n", pf); - return -1; - } - len = seek(fd, 0, 2); - seek(fd, 0, 0); - } else { - fd = -1; - } - if(len > MAXFILESIZE){ - fprint(2, "implausible filesize %ld for %s\n", len, pf); - return -1; - } - - /* send file size */ - snprint(s, Maxmsg, "%ld", len+AESbsize+CHK); - conn->write(conn, (uchar*)s, strlen(s)); - - /* send IV and file+XXXXX in Maxmsg chunks */ - ivo = AESbsize; - bufi = 0; - memcpy(b, IV, ivo); - for(done = 0; !done; ){ - if(buf == nil){ - n = read(fd, b+ivo, Maxmsg-ivo); - if(n < 0){ - fprint(2, "read error on %s: %r\n", pf); - return -1; - } - }else{ - if((n = len - bufi) > Maxmsg-ivo) - n = Maxmsg-ivo; - memcpy(b+ivo, buf+bufi, n); - bufi += n; - } - n += ivo; - ivo = 0; - if(n < Maxmsg){ /* EOF on input; append XX... */ - memset(b+n, 'X', CHK); - n += CHK; // might push n>Maxmsg - done = 1; - } - aesCBCencrypt(b, n, &aes); - if(n > Maxmsg){ - assert(done==1); - conn->write(conn, b, Maxmsg); - n -= Maxmsg; - memmove(b, b+Maxmsg, n); - } - conn->write(conn, b, n); - } - - if(buf == nil) - close(fd); - fprint(2, "saved %ld bytes\n", len); - - return 0; -} - -static int -removefile(SConn *conn, char *rf) -{ - char buf[Maxmsg]; - - if(strchr(rf, '/')){ - fprint(2, "simple filenames, not paths like %s\n", rf); - return -1; - } - - snprint(buf, Maxmsg, "RM %s\n", rf); - conn->write(conn, (uchar*)buf, strlen(buf)); - - return 0; -} - -static int -cmd(AuthConn *c, char **gf, int *Gflag, char **pf, char **rf) -{ - ulong len; - int rv = -1; - uchar *memfile, *memcur, *memnext; - - while(*gf != nil){ - if(verbose) - fprint(2, "get %s\n", *gf); - if(getfile(c->conn, *gf, *Gflag ? &memfile : nil, &len, (uchar*)c->pass, c->passlen) < 0) - goto Out; - if(*Gflag){ - // write one line at a time, as required by /mnt/factotum/ctl - memcur = memfile; - while(len>0){ - memnext = (uchar*)strchr((char*)memcur, '\n'); - if(memnext){ - write(1, memcur, memnext-memcur+1); - len -= memnext-memcur+1; - memcur = memnext+1; - }else{ - write(1, memcur, len); - break; - } - } - free(memfile); - } - gf++; - Gflag++; - } - while(*pf != nil){ - if(verbose) - fprint(2, "put %s\n", *pf); - if(putfile(c->conn, *pf, nil, 0, (uchar*)c->pass, c->passlen) < 0) - goto Out; - pf++; - } - while(*rf != nil){ - if(verbose) - fprint(2, "rm %s\n", *rf); - if(removefile(c->conn, *rf) < 0) - goto Out; - rf++; - } - - c->conn->write(c->conn, (uchar*)"BYE", 3); - rv = 0; - -Out: - c->conn->free(c->conn); - return rv; -} - -static int -chpasswd(AuthConn *c, char *id) -{ - ulong len; - int rv = -1, newpasslen = 0; - mpint *H, *Hi; - uchar *memfile; - char *newpass, *passck; - char *list, *cur, *next, *hexHi; - char *f[8], prompt[128]; - - H = mpnew(0); - Hi = mpnew(0); - // changing our password is vulnerable to connection failure - for(;;){ - snprint(prompt, sizeof(prompt), "new password for %s: ", id); - newpass = readcons(prompt, nil, 1); - if(newpass == nil) - goto Out; - if(strlen(newpass) >= 7) - break; - else if(strlen(newpass) == 0){ - fprint(2, "!password change aborted\n"); - goto Out; - } - print("!password must be at least 7 characters\n"); - } - newpasslen = strlen(newpass); - snprint(prompt, sizeof(prompt), "retype password: "); - passck = readcons(prompt, nil, 1); - if(passck == nil){ - fprint(2, "readcons failed\n"); - goto Out; - } - if(strcmp(passck, newpass) != 0){ - fprint(2, "passwords didn't match\n"); - goto Out; - } - - c->conn->write(c->conn, (uchar*)"CHPASS", strlen("CHPASS")); - hexHi = PAK_Hi(id, newpass, H, Hi); - c->conn->write(c->conn, (uchar*)hexHi, strlen(hexHi)); - free(hexHi); - mpfree(H); - mpfree(Hi); - - if(getfile(c->conn, ".", (uchar **)(void*)&list, &len, nil, 0) < 0){ - fprint(2, "directory listing failed.\n"); - goto Out; - } - - /* Loop over files and reencrypt them; try to keep going after error */ - for(cur=list; (next=strchr(cur, '\n')) != nil; cur=next+1){ - *next = '\0'; - if(tokenize(cur, f, nelem(f))< 1) - break; - fprint(2, "reencrypting '%s'\n", f[0]); - if(getfile(c->conn, f[0], &memfile, &len, (uchar*)c->pass, c->passlen) < 0){ - fprint(2, "getfile of '%s' failed\n", f[0]); - continue; - } - if(putfile(c->conn, f[0], memfile, len, (uchar*)newpass, newpasslen) < 0) - fprint(2, "putfile of '%s' failed\n", f[0]); - free(memfile); - } - free(list); - c->conn->write(c->conn, (uchar*)"BYE", 3); - rv = 0; - -Out: - if(newpass != nil){ - memset(newpass, 0, newpasslen); - free(newpass); - } - c->conn->free(c->conn); - return rv; -} - -static AuthConn* -login(char *id, char *dest, int pass_stdin, int pass_nvram) -{ - AuthConn *c; - int fd, n, ntry = 0; - char *S, *PINSTA = nil, *nl, s[Maxmsg+1], *pass; - - if(dest == nil){ - fprint(2, "tried to login with nil dest\n"); - exits("nil dest"); - } - c = emalloc(sizeof(*c)); - if(pass_nvram){ - /* if(readnvram(&nvr, 0) < 0) */ - exits("readnvram: %r"); - strecpy(c->pass, c->pass+sizeof c->pass, nvr.config); - } - if(pass_stdin){ - n = readn(0, s, Maxmsg-2); // so len(PINSTA)<Maxmsg-3 - if(n < 1) - exits("no password on standard input"); - s[n] = 0; - nl = strchr(s, '\n'); - if(nl){ - *nl++ = 0; - PINSTA = estrdup(nl); - nl = strchr(PINSTA, '\n'); - if(nl) - *nl = 0; - } - strecpy(c->pass, c->pass+sizeof c->pass, s); - } - while(1){ - if(verbose) - fprint(2, "dialing %s\n", dest); - if((fd = dial(dest, nil, nil, nil)) < 0){ - fprint(2, "can't dial %s\n", dest); - free(c); - return nil; - } - if((c->conn = newSConn(fd)) == nil){ - free(c); - return nil; - } - ntry++; - if(!pass_stdin && !pass_nvram){ - pass = readcons("secstore password", nil, 1); - if(pass == nil) - pass = estrdup(""); - if(strlen(pass) >= sizeof c->pass){ - fprint(2, "password too long, skipping secstore login\n"); - exits("password too long"); - } - strcpy(c->pass, pass); - memset(pass, 0, strlen(pass)); - free(pass); - } - if(c->pass[0]==0){ - fprint(2, "null password, skipping secstore login\n"); - exits("no password"); - } - if(PAKclient(c->conn, id, c->pass, &S) >= 0) - break; - c->conn->free(c->conn); - if(pass_stdin) - exits("invalid password on standard input"); - if(pass_nvram) - exits("invalid password in nvram"); - // and let user try retyping the password - if(ntry==3) - fprint(2, "Enter an empty password to quit.\n"); - } - c->passlen = strlen(c->pass); - fprint(2, "server: %s\n", S); - free(S); - if(readstr(c->conn, s) < 0){ - c->conn->free(c->conn); - free(c); - return nil; - } - if(strcmp(s, "STA") == 0){ - long sn; - if(pass_stdin){ - if(PINSTA) - strncpy(s+3, PINSTA, (sizeof s)-3); - else - exits("missing PIN+SecureID on standard input"); - free(PINSTA); - }else{ - pass = readcons("STA PIN+SecureID", nil, 1); - if(pass == nil) - pass = estrdup(""); - strncpy(s+3, pass, (sizeof s)-4); - memset(pass, 0, strlen(pass)); - free(pass); - } - sn = strlen(s+3); - if(verbose) - fprint(2, "%ld\n", sn); - c->conn->write(c->conn, (uchar*)s, sn+3); - readstr(c->conn, s); - } - if(strcmp(s, "OK") != 0){ - fprint(2, "%s\n", s); - c->conn->free(c->conn); - free(c); - return nil; - } - return c; -} - -int -main(int argc, char **argv) -{ - int chpass = 0, pass_stdin = 0, pass_nvram = 0, rc; - int ngfile = 0, npfile = 0, nrfile = 0, Gflag[MAXFILES+1]; - char *gfile[MAXFILES], *pfile[MAXFILES], *rfile[MAXFILES]; - char *serve, *tcpserve, *user; - AuthConn *c; - - serve = "$auth"; - user = getuser(); - memset(Gflag, 0, sizeof Gflag); - fmtinstall('B', mpfmt); - fmtinstall('H', encodefmt); - - ARGBEGIN{ - case 'c': - chpass = 1; - break; - case 'G': - Gflag[ngfile]++; - /* fall through */ - case 'g': - if(ngfile >= MAXFILES) - exits("too many gfiles"); - gfile[ngfile++] = ARGF(); - if(gfile[ngfile-1] == nil) - usage(); - break; - case 'i': - pass_stdin = 1; - break; - case 'n': - pass_nvram = 1; - break; - case 'p': - if(npfile >= MAXFILES) - exits("too many pfiles"); - pfile[npfile++] = ARGF(); - if(pfile[npfile-1] == nil) - usage(); - break; - case 'r': - if(nrfile >= MAXFILES) - exits("too many rfiles"); - rfile[nrfile++] = ARGF(); - if(rfile[nrfile-1] == nil) - usage(); - break; - case 's': - serve = EARGF(usage()); - break; - case 'u': - user = EARGF(usage()); - break; - case 'v': - verbose++; - break; - default: - usage(); - break; - }ARGEND; - gfile[ngfile] = nil; - pfile[npfile] = nil; - rfile[nrfile] = nil; - - if(argc!=0 || user==nil) - usage(); - - if(chpass && (ngfile || npfile || nrfile)){ - fprint(2, "Get, put, and remove invalid with password change.\n"); - exits("usage"); - } - - rc = strlen(serve)+sizeof("tcp!!99990"); - tcpserve = emalloc(rc); - if(strchr(serve,'!')) - strcpy(tcpserve, serve); - else - snprint(tcpserve, rc, "tcp!%s!5356", serve); - c = login(user, tcpserve, pass_stdin, pass_nvram); - free(tcpserve); - if(c == nil){ - fprint(2, "secstore authentication failed\n"); - exits("secstore authentication failed"); - } - if(chpass) - rc = chpasswd(c, user); - else - rc = cmd(c, gfile, Gflag, pfile, rfile); - if(rc < 0){ - fprint(2, "secstore cmd failed\n"); - exits("secstore cmd failed"); - } - exits(""); - return 0; -} - |