AuthInfo* auth_response(Chalstate *c) { int ret; AuthInfo *ai; ai = nil; if(c->afd < 0){ werrstr("auth_response: connection not open"); return nil; } if(c->resp == nil){ werrstr("auth_response: nil response"); return nil; } if(c->nresp == 0){ werrstr("auth_response: unspecified response length"); return nil; } if(c->user){ if(auth_rpc(c->rpc, "write", c->user, strlen(c->user)) != ARok){ /* * if this fails we're out of phase with factotum. * give up. */ goto Out; } } if(auth_rpc(c->rpc, "write", c->resp, c->nresp) != ARok){ /* * don't close the connection -- maybe we'll try again. */ return nil; } switch(ret = auth_rpc(c->rpc, "read", nil, 0)){ case ARok: default: werrstr("factotum protocol botch %d %s", ret, c->rpc->ibuf); break; case ARdone: ai = auth_getinfo(c->rpc); break; } Out: close(c->afd); auth_freerpc(c->rpc); c->afd = -1; c->rpc = nil; return ai; }
static int _authread(Afid *afid, void *data, int count) { AuthInfo *ai; switch(auth_rpc(afid->rpc, "read", nil, 0)){ case ARdone: ai = auth_getinfo(afid->rpc); if(ai == nil) return -1; auth_freeAI(ai); if(chatty9p) fprint(2, "authenticate %s/%s: ok\n", afid->uname, afid->aname); afid->authok = 1; return 0; case ARok: if(count < afid->rpc->narg){ werrstr("authread count too small"); return -1; } count = afid->rpc->narg; memmove(data, afid->rpc->arg, count); return count; case ARphase: default: werrstr("authrpc botch"); return -1; } }
static mpint* rpcdecrypt(AuthRpc *rpc, mpint *b) { mpint *a; char *p; p = mptoa(b, 16, nil, 0); if(auth_rpc(rpc, "write", p, strlen(p)) != ARok) sysfatal("factotum rsa write: %r"); free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok) sysfatal("factotum rsa read: %r"); a = strtomp(rpc->arg, nil, 16, nil); mpfree(b); return a; }
Attr* auth_attr(AuthRpc *rpc) { if(auth_rpc(rpc, "attr", nil, 0) != ARok) return nil; return _parseattr(rpc->arg); }
int authWrite(Fid* afid, void* data, int count) { assert(afid->rpc != nil); if(auth_rpc(afid->rpc, "write", data, count) != ARok) return -1; return count; }
/* * make factotum add wep keys to an 802.11 device */ int auth_wep(char *dev, char *fmt, ...) { AuthRpc *rpc; char *params, *p; int fd; va_list arg; int rv; rv = -1; if(dev == nil){ werrstr("no device specified"); return rv; } fd = open("/mnt/factotum/rpc", ORDWR); if(fd < 0) return rv; rpc = auth_allocrpc(fd); if(rpc != nil){ quotefmtinstall(); /* just in case */ va_start(arg, fmt); params = vsmprint(fmt, arg); va_end(arg); if(params != nil){ p = smprint("proto=wep %s", params); if(p != nil){ if(auth_rpc(rpc, "start", p, strlen(p)) == ARok && auth_rpc(rpc, "write", dev, strlen(dev)) == ARok) rv = 0; free(p); } free(params); } auth_freerpc(rpc); } close(fd); return rv; }
Chalstate* auth_challenge(char *fmt, ...) { char *p; va_list arg; Chalstate *c; quotefmtinstall(); /* just in case */ va_start(arg, fmt); p = vsmprint(fmt, arg); va_end(arg); if(p == nil) return nil; c = mallocz(sizeof(*c), 1); if(c == nil){ free(p); return nil; } if((c->afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ Error: auth_freechal(c); free(p); return nil; } if((c->rpc=auth_allocrpc(c->afd)) == nil || auth_rpc(c->rpc, "start", p, strlen(p)) != ARok || auth_rpc(c->rpc, "read", nil, 0) != ARok) goto Error; if(c->rpc->narg > sizeof(c->chal)-1){ werrstr("buffer too small for challenge"); goto Error; } memmove(c->chal, c->rpc->arg, c->rpc->narg); c->nchal = c->rpc->narg; free(p); return c; }
AuthInfo* auth_getinfo(AuthRpc *rpc) { AuthInfo *a; if(auth_rpc(rpc, "authinfo", nil, 0) != ARok) return nil; if(convM2AI((uchar*)rpc->arg, rpc->narg, &a) == nil){ return nil; } return a; }
static int dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey) { int ret; for(;;){ if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey) return ret; if(getkey == nil) return ARgiveup; /* don't know how */ if((*getkey)(rpc->arg) < 0) return ARgiveup; /* user punted */ } }
AuthInfo* auth_getinfo(AuthRpc *rpc) { AuthInfo *a; if(auth_rpc(rpc, "authinfo", nil, 0) != ARok) return nil; a = nil; if(convM2AI((uchar*)rpc->arg, rpc->narg, &a) == nil){ werrstr("bad auth info from factotum"); return nil; } return a; }
int authRead(Fid* afid, void* data, int count) { AuthInfo *ai; AuthRpc *rpc; if((rpc = afid->rpc) == nil){ werrstr("not an auth fid"); return -1; } switch(auth_rpc(rpc, "read", nil, 0)){ default: werrstr("fossil authRead: auth protocol not finished"); return -1; case ARdone: if((ai = auth_getinfo(rpc)) == nil){ werrstr("%r"); break; } if(ai->cuid == nil || *ai->cuid == '\0'){ werrstr("auth with no cuid"); auth_freeAI(ai); break; } assert(afid->cuname == nil); afid->cuname = vtstrdup(ai->cuid); auth_freeAI(ai); if(Dflag) fprint(2, "authRead cuname %s\n", afid->cuname); assert(afid->uid == nil); if((afid->uid = uidByUname(afid->cuname)) == nil){ werrstr("unknown user %#q", afid->cuname); break; } return 0; case ARok: if(count < rpc->narg){ werrstr("not enough data in auth read"); break; } memmove(data, rpc->arg, rpc->narg); return rpc->narg; case ARphase: werrstr("%r"); break; } return -1; }
void auth9p(Req *r) { char *spec; Afid *afid; afid = emalloc9p(sizeof(Afid)); afid->afd = open("/mnt/factotum/rpc", ORDWR); if(afid->afd < 0) goto error; if((afid->rpc = auth_allocrpc(afid->afd)) == nil) goto error; if(r->ifcall.uname[0] == 0) goto error; afid->uname = estrdup9p(r->ifcall.uname); afid->aname = estrdup9p(r->ifcall.aname); spec = r->srv->keyspec; if(spec == nil) spec = "proto=p9any role=server"; if(auth_rpc(afid->rpc, "start", spec, strlen(spec)) != ARok) goto error; r->afid->qid.type = QTAUTH; r->afid->qid.path = ++authgen; r->afid->qid.vers = 0; r->afid->omode = ORDWR; r->ofcall.qid = r->afid->qid; r->afid->aux = afid; respond(r, nil); return; error: if(afid->rpc) auth_freerpc(afid->rpc); if(afid->uname) free(afid->uname); if(afid->aname) free(afid->aname); if(afid->afd >= 0) close(afid->afd); free(afid); responderror(r); }
int authread(File *file, uchar *data, int count) { AuthInfo *ai; AuthRpc *rpc; Chan *chan; chan = file->cp; if((rpc = file->auth) == nil){ snprint(chan->err, sizeof(chan->err), "not an auth fid"); return -1; } switch(auth_rpc(rpc, "read", nil, 0)){ default: snprint(chan->err, sizeof(chan->err), "authread: auth protocol not finished"); return -1; case ARdone: if((ai = auth_getinfo(rpc)) == nil) goto Phase; file->uid = strtouid(ai->cuid); if(file->uid < 0){ snprint(chan->err, sizeof(chan->err), "unknown user '%s'", ai->cuid); auth_freeAI(ai); return -1; } auth_freeAI(ai); return 0; case ARok: if(count < rpc->narg){ snprint(chan->err, sizeof(chan->err), "not enough data in auth read"); return -1; } memmove(data, rpc->arg, rpc->narg); return rpc->narg; case ARphase: Phase: rerrstr(chan->err, sizeof(chan->err)); return -1; } }
int authwrite(File *file, uchar *data, int count) { AuthRpc *rpc; Chan *chan; chan = file->cp; if((rpc = file->auth) == nil){ snprint(chan->err, sizeof(chan->err), "not an auth fid"); return -1; } if(auth_rpc(rpc, "write", data, count) != ARok){ rerrstr(chan->err, sizeof(chan->err)); return -1; } return count; }
void authwrite(Req *r) { Afid *afid; Fid *fid; fid = r->fid; afid = fid->aux; if(afid == nil || r->fid->qid.type != QTAUTH){ respond(r, "not an auth fid"); return; } if(auth_rpc(afid->rpc, "write", r->ifcall.data, r->ifcall.count) != ARok){ responderror(r); return; } r->ofcall.count = r->ifcall.count; respond(r, nil); }
void* authnew(void) { AuthRpc *rpc; int fd; if(access("/mnt/factotum", 0) < 0) if((fd = open("/srv/factotum", ORDWR)) >= 0) mount(fd, -1, "/mnt", MBEFORE, ""); if((fd = open("/mnt/factotum/rpc", ORDWR)) < 0) return nil; if((rpc = auth_allocrpc(fd)) == nil){ close(fd); return nil; } if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){ authfree(rpc); return nil; } return rpc; }
static int authrsafn(Conn *c) { uint8_t chalbuf[32+SESSIDLEN], response[MD5dlen]; char *s, *p; int afd, ret; AuthRpc *rpc; Msg *m; mpint *chal, *decr, *unpad, *mod; debug(DBG_AUTH, "rsa!\n"); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n"); return -1; } if((rpc = auth_allocrpc(afd)) == nil){ debug(DBG_AUTH, "auth_allocrpc: %r\n"); close(afd); return -1; } s = "proto=rsa role=client"; if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){ debug(DBG_AUTH, "auth_rpc start %s failed: %r\n", s); auth_freerpc(rpc); close(afd); return -1; } ret = -1; debug(DBG_AUTH, "trying factotum rsa keys\n"); while(auth_rpc(rpc, "read", nil, 0) == ARok){ debug(DBG_AUTH, "try %s\n", (char*)rpc->arg); mod = strtomp(rpc->arg, nil, 16, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA, 16+(mpsignif(mod)+7/8)); putmpint(m, mod); sendmsg(m); mpfree(mod); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: debug(DBG_AUTH, "\tnot accepted %s\n", (char*)rpc->arg); free(m); continue; default: badmsg(m, 0); case SSH_SMSG_AUTH_RSA_CHALLENGE: break; } chal = getmpint(m); debug(DBG_AUTH, "\tgot challenge %B\n", chal); free(m); p = mptoa(chal, 16, nil, 0); mpfree(chal); if(p == nil){ debug(DBG_AUTH, "\tmptoa failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ debug(DBG_AUTH, "\tauth_rpc write failed: %r\n"); free(p); unpad = mpnew(0); /* it will fail, we'll go round again */ goto Keepgoing; } free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok){ debug(DBG_AUTH, "\tauth_rpc read failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } decr = strtomp(rpc->arg, nil, 16, nil); debug(DBG_AUTH, "\tdecrypted %B\n", decr); unpad = rsaunpad(decr); debug(DBG_AUTH, "\tunpadded %B\n", unpad); mpfree(decr); Keepgoing: mptoberjust(unpad, chalbuf, 32); mpfree(unpad); debug(DBG_AUTH, "\trjusted %.*H\n", 32, chalbuf); memmove(chalbuf+32, c->sessid, SESSIDLEN); debug(DBG_AUTH, "\tappend sesskey %.*H\n", 32, chalbuf); md5(chalbuf, 32+SESSIDLEN, response, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE, MD5dlen); putbytes(m, response, MD5dlen); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: free(m); continue; default: badmsg(m, 0); case SSH_SMSG_SUCCESS: break; } ret = 0; break; } auth_freerpc(rpc); close(afd); return ret; }
static int dorsa(mpint *mod, mpint *exp, mpint *chal, uint8_t chalbuf[32]) { int afd; AuthRpc *rpc; mpint *m; char buf[4096], *p; mpint *decr, *unpad; USED(exp); snprint(buf, sizeof buf, "proto=rsa service=ssh role=client"); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n"); return -1; } if((rpc = auth_allocrpc(afd)) == nil){ debug(DBG_AUTH, "auth_allocrpc: %r\n"); close(afd); return -1; } if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){ debug(DBG_AUTH, "auth_rpc start failed: %r\n"); Die: auth_freerpc(rpc); close(afd); return -1; } m = nil; debug(DBG_AUTH, "trying factotum rsa keys\n"); while(auth_rpc(rpc, "read", nil, 0) == ARok){ debug(DBG_AUTH, "try %s\n", (char*)rpc->arg); m = strtomp(rpc->arg, nil, 16, nil); if(mpcmp(m, mod) == 0) break; mpfree(m); m = nil; } if(m == nil) goto Die; mpfree(m); p = mptoa(chal, 16, nil, 0); if(p == nil){ debug(DBG_AUTH, "\tmptoa failed: %r\n"); goto Die; } if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ debug(DBG_AUTH, "\tauth_rpc write failed: %r\n"); free(p); goto Die; } free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok){ debug(DBG_AUTH, "\tauth_rpc read failed: %r\n"); goto Die; } decr = strtomp(rpc->arg, nil, 16, nil); if(decr == nil){ debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg); goto Die; } debug(DBG_AUTH, "\tdecrypted %B\n", decr); unpad = rsaunpad(decr); if(unpad == nil){ debug(DBG_AUTH, "\tunpad %B failed\n", decr); mpfree(decr); goto Die; } debug(DBG_AUTH, "\tunpadded %B\n", unpad); mpfree(decr); mptoberjust(unpad, chalbuf, 32); mpfree(unpad); auth_freerpc(rpc); close(afd); return 0; }
void sshserverhandshake(Conn *c) { char *p, buf[128]; Biobuf *b; Attr *a; int i, afd; mpint *m; AuthRpc *rpc; RSApub *key; /* * BUG: should use `attr' to get the key attributes * after the read, but that's not implemented yet. */ if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil) sysfatal("open /mnt/factotum/ctl: %r"); while((p = Brdline(b, '\n')) != nil){ p[Blinelen(b)-1] = '\0'; if(strstr(p, " proto=rsa ") && strstr(p, " service=sshserve ")) break; } if(p == nil) sysfatal("no sshserve keys found in /mnt/factotum/ctl"); a = _parseattr(p); Bterm(b); key = emalloc(sizeof(*key)); if((p = _strfindattr(a, "n")) == nil) sysfatal("no n in sshserve key"); if((key->n = strtomp(p, &p, 16, nil)) == nil || *p != 0) sysfatal("bad n in sshserve key"); if((p = _strfindattr(a, "ek")) == nil) sysfatal("no ek in sshserve key"); if((key->ek = strtomp(p, &p, 16, nil)) == nil || *p != 0) sysfatal("bad ek in sshserve key"); _freeattr(a); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0) sysfatal("open /mnt/factotum/rpc: %r"); if((rpc = auth_allocrpc(afd)) == nil) sysfatal("auth_allocrpc: %r"); p = "proto=rsa role=client service=sshserve"; if(auth_rpc(rpc, "start", p, strlen(p)) != ARok) sysfatal("auth_rpc start %s: %r", p); if(auth_rpc(rpc, "read", nil, 0) != ARok) sysfatal("auth_rpc read: %r"); m = strtomp(rpc->arg, nil, 16, nil); if(mpcmp(m, key->n) != 0) sysfatal("key in /mnt/factotum/ctl does not match rpc key"); mpfree(m); c->hostkey = key; /* send id string */ fprint(c->fd[0], "SSH-1.5-Plan9\n"); /* receive id string */ if(readstrnl(c->fd[0], buf, sizeof buf) < 0) sysfatal("reading server version: %r"); /* id string is "SSH-m.n-comment". We need m=1, n>=5. */ if(strncmp(buf, "SSH-", 4) != 0 || strtol(buf+4, &p, 10) != 1 || *p != '.' || strtol(p+1, &p, 10) < 5 || *p != '-') sysfatal("protocol mismatch; got %s, need SSH-1.x for x>=5", buf); for(i=0; i<COOKIELEN; i++) c->cookie[i] = fastrand(); calcsessid(c); send_ssh_smsg_public_key(c); recv_ssh_cmsg_session_key(c, rpc); auth_freerpc(rpc); close(afd); c->cstate = (*c->cipher->init)(c, 1); /* turns on encryption */ sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); authsrvuser(c); }