#include "ssh.h" #include typedef struct Key Key; struct Key { mpint *mod; mpint *ek; char *comment; }; typedef struct Achan Achan; struct Achan { int open; u32int chan; /* of remote */ uchar lbuf[4]; uint nlbuf; uint len; uchar *data; int ndata; int needeof; int needclosed; }; Achan achan[16]; static char* find(char **f, int nf, char *k) { int i, len; len = strlen(k); for(i=1; iarg); 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; } int startagent(Conn *c) { int ret; Msg *m; m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_SUCCESS: debug(DBG_AUTH, "agent allocated\n"); ret = 0; break; case SSH_SMSG_FAILURE: debug(DBG_AUTH, "agent failed to allocate\n"); ret = -1; break; default: badmsg(m, 0); ret = -1; break; } free(m); return ret; } void handlefullmsg(Conn*, Achan*); void handleagentmsg(Msg *m) { u32int chan, len; int n; Achan *a; assert(m->type == SSH_MSG_CHANNEL_DATA); debug(DBG_AUTH, "agent data\n"); debug(DBG_AUTH, "\t%.*H\n", (int)(m->ep - m->rp), m->rp); chan = getlong(m); len = getlong(m); if(m->rp+len != m->ep) sysfatal("got bad channel data"); if(chan >= nelem(achan)) error("bad channel in agent request"); a = &achan[chan]; while(m->rp < m->ep){ if(a->nlbuf < 4){ a->lbuf[a->nlbuf++] = getbyte(m); if(a->nlbuf == 4){ a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3]; a->data = erealloc(a->data, a->len); a->ndata = 0; } continue; } if(a->ndata < a->len){ n = a->len - a->ndata; if(n > m->ep - m->rp) n = m->ep - m->rp; memmove(a->data+a->ndata, getbytes(m, n), n); a->ndata += n; } if(a->ndata == a->len){ handlefullmsg(m->c, a); a->nlbuf = 0; } } } void handlefullmsg(Conn *c, Achan *a) { int i; u32int chan, len, n, rt; uchar type; Msg *m, mm; Msg *r; Key *k; int nk; mpint *mod, *ek, *chal; uchar sessid[16]; uchar chalbuf[32]; uchar digest[16]; DigestState *s; static int first; assert(a->len == a->ndata); chan = a->chan; mm.rp = a->data; mm.ep = a->data+a->ndata; mm.c = c; m = &mm; type = getbyte(m); if(first == 0){ first++; fmtinstall('H', encodefmt); } switch(type){ default: debug(DBG_AUTH, "unknown msg type\n"); Failure: debug(DBG_AUTH, "agent sending failure\n"); r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13); putlong(r, chan); putlong(r, 5); putlong(r, 1); putbyte(r, SSH_AGENT_FAILURE); sendmsg(r); return; case SSH_AGENTC_REQUEST_RSA_IDENTITIES: debug(DBG_AUTH, "agent request identities\n"); nk = listkeys(&k); if(nk < 0) goto Failure; len = 1+4; /* type, nk */ for(i=0; ic, SSH_MSG_CHANNEL_DATA, 12+len); putlong(r, chan); putlong(r, len+4); putlong(r, len); putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER); putlong(r, nk); for(i=0; irp, m->ep); if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){ mpfree(ek); mpfree(mod); mpfree(chal); goto Failure; } s = md5(chalbuf, 32, nil, nil); md5(sessid, 16, digest, s); r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16); putlong(r, chan); putlong(r, 4+16+1); putlong(r, 16+1); putbyte(r, SSH_AGENT_RSA_RESPONSE); putbytes(r, digest, 16); debug(DBG_AUTH, "digest %.16H\n", digest); sendmsg(r); mpfree(ek); mpfree(mod); mpfree(chal); return; case SSH_AGENTC_ADD_RSA_IDENTITY: goto Failure; /* n = getlong(m); pubmod = getmpint(m); pubexp = getmpint(m); privexp = getmpint(m); pinversemodq = getmpint(m); p = getmpint(m); q = getmpint(m); comment = getstring(m); add to factotum; send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE; */ case SSH_AGENTC_REMOVE_RSA_IDENTITY: goto Failure; /* n = getlong(m); pubmod = getmpint(m); pubexp = getmpint(m); tell factotum to del key send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE; */ } } void handleagentopen(Msg *m) { int i; u32int remote; assert(m->type == SSH_SMSG_AGENT_OPEN); remote = getlong(m); debug(DBG_AUTH, "agent open %d\n", remote); for(i=0; ic, SSH_MSG_CHANNEL_OPEN_FAILURE, 4); putlong(m, remote); sendmsg(m); return; } debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i); achan[i].open = 1; achan[i].needeof = 1; achan[i].needclosed = 1; achan[i].nlbuf = 0; achan[i].chan = remote; m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8); putlong(m, remote); putlong(m, i); sendmsg(m); } void handleagentieof(Msg *m) { u32int local; assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF); local = getlong(m); debug(DBG_AUTH, "agent close %d\n", local); if(local < nelem(achan)){ debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan); achan[local].open = 0; /* m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4); putlong(m, achan[local].chan); sendmsg(m); */ if(achan[local].needeof){ achan[local].needeof = 0; m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4); putlong(m, achan[local].chan); sendmsg(m); } } } void handleagentoclose(Msg *m) { u32int local; assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED); local = getlong(m); debug(DBG_AUTH, "agent close %d\n", local); if(local < nelem(achan)){ debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan); if(achan[local].needclosed){ achan[local].needclosed = 0; m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4); putlong(m, achan[local].chan); sendmsg(m); } } }