void handleagentopen(Msg *m) { int i; uint32_t remote; assert(m->type == SSH_SMSG_AGENT_OPEN); remote = getlong(m); debug(DBG_AUTH, "agent open %d\n", remote); for(i=0; i<nelem(achan); i++) if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0) break; if(i == nelem(achan)){ m = allocmsg(m->c, 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); }
static int authtisfn(Conn *c) { int fd, n; char *chal, resp[256]; Msg *m; if(!c->interactive) return -1; debug(DBG_AUTH, "try TIS\n"); sendmsg(allocmsg(c, SSH_CMSG_AUTH_TIS, 0)); m = recvmsg(c, -1); switch(m->type){ default: badmsg(m, SSH_SMSG_AUTH_TIS_CHALLENGE); case SSH_SMSG_FAILURE: free(m); return -1; case SSH_SMSG_AUTH_TIS_CHALLENGE: break; } chal = getstring(m); free(m); if((fd = open("/dev/cons", ORDWR)) < 0) error("can't open console"); fprint(fd, "TIS Authentication\n%s", chal); n = read(fd, resp, sizeof resp-1); if(n < 0) resp[0] = '\0'; else resp[n] = '\0'; if(resp[0] == 0 || resp[0] == '\n') return -1; m = allocmsg(c, SSH_CMSG_AUTH_TIS_RESPONSE, 4+strlen(resp)); putstring(m, resp); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ default: badmsg(m, 0); case SSH_SMSG_SUCCESS: free(m); return 0; case SSH_SMSG_FAILURE: free(m); return -1; } }
static void sendwritemsg(Conn *c, char *buf, int n) { Msg *m; if(n==0) m = allocmsg(c, SSH_CMSG_EOF, 0); else{ m = allocmsg(c, SSH_CMSG_STDIN_DATA, 4+n); putlong(m, n); putbytes(m, buf, n); } sendmsg(m); }
static void authsrvuser(Conn *c) { int i; char *ns, *user; AuthInfo *ai; Msg *m; m = recvmsg(c, SSH_CMSG_USER); user = getstring(m); c->user = emalloc(strlen(user)+1); strcpy(c->user, user); free(m); ai = authusername(c); while(ai == nil){ /* * clumsy: if the client aborted the auth_tis early * we don't send a new failure. we check this by * looking at c->unget, which is only used in that * case. */ if(c->unget != nil) goto skipfailure; sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); skipfailure: m = recvmsg(c, -1); for(i=0; i<c->nokauthsrv; i++) if(c->okauthsrv[i]->firstmsg == m->type){ ai = (*c->okauthsrv[i]->fn)(c, m); break; } if(i==c->nokauthsrv) badmsg(m, 0); } sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); if(noworld(ai->cuid)) ns = "/lib/namespace.noworld"; else ns = nil; if(auth_chuid(ai, ns) < 0){ sshlog("auth_chuid to %s: %r", ai->cuid); sysfatal("auth_chuid: %r"); } sshlog("logged in as %s", ai->cuid); auth_freeAI(ai); }
void copyout(Conn *c, int fd, int mtype) { char buf[8192]; int n, max, pid; Msg *m; max = sizeof buf; if(max > maxmsg - 32) /* 32 is an overestimate of packet overhead */ max = maxmsg - 32; if(max <= 0) sysfatal("maximum message size too small"); switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){ case -1: sysfatal("fork: %r"); case 0: break; default: atexitkill(pid); return; } while((n = read(fd, buf, max)) > 0){ m = allocmsg(c, mtype, 4+n); putlong(m, n); putbytes(m, buf, n); sendmsg(m); } exits(nil); }
void StatusItem::GeneratePopUp(BPoint point, BRect openrect) { BString str(value); str.Append(" "); BString url; URLCrunch crunch(str.String(), str.Length()); BPopUpMenu* menu = new BPopUpMenu("URLs"); BMessage msg(M_LOAD_URL); BMessage* allocmsg(NULL); BMenuItem* item(NULL); while (crunch.Crunch(&url) != B_ERROR) { allocmsg = new BMessage(msg); allocmsg->AddString("url", url.String()); item = new BMenuItem(url.String(), allocmsg); menu->AddItem(item); allocmsg = NULL; } if (menu->CountItems() > 0) { menu->SetTargetForItems(be_app); menu->SetAsyncAutoDestruct(true); menu->Go(point, true, true, openrect, true); } else { delete menu; } }
static int authuser(Conn *c) { int i; Msg *m; m = allocmsg(c, SSH_CMSG_USER, 4+strlen(c->user)); putstring(m, c->user); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_SUCCESS: free(m); return 0; case SSH_SMSG_FAILURE: free(m); break; default: badmsg(m, 0); } for(i=0; i<c->nokauth; i++){ debug(DBG_AUTH, "authmask %#lux, consider %s (%#x)\n", c->authmask, c->okauth[i]->name, 1<<c->okauth[i]->id); if(c->authmask & (1<<c->okauth[i]->id)) if((*c->okauth[i]->fn)(c) == 0) return 0; } debug(DBG_AUTH, "no auth methods worked; (authmask=%#lux)\n", c->authmask); return -1; }
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; }
static int authpasswordfn(Conn *c) { Msg *m; UserPasswd *up; up = auth_getuserpasswd(c->interactive ? auth_getkey : nil, "proto=pass service=ssh server=%q user=%q", c->host, c->user); if(up == nil){ debug(DBG_AUTH, "getuserpasswd returned nothing (interactive=%d)\n", c->interactive); return -1; } debug(DBG_AUTH, "try using password from factotum\n"); m = allocmsg(c, SSH_CMSG_AUTH_PASSWORD, 4+strlen(up->passwd)); putstring(m, up->passwd); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ default: badmsg(m, 0); case SSH_SMSG_SUCCESS: free(m); return 0; case SSH_SMSG_FAILURE: free(m); return -1; } }
void sendwindowsize(Conn *c, int nrow, int ncol, int width, int height) { Msg *m; m = allocmsg(c, SSH_CMSG_WINDOW_SIZE, 4*4); putlong(m, nrow); putlong(m, ncol); putlong(m, width); putlong(m, height); sendmsg(m); }
static void send_ssh_cmsg_session_key(Conn *c) { int i, n, buflen, serverkeylen, hostkeylen; mpint *b; uchar *buf; Msg *m; RSApub *ksmall, *kbig; m = allocmsg(c, SSH_CMSG_SESSION_KEY, 2048); putbyte(m, c->cipher->id); putbytes(m, c->cookie, COOKIELEN); serverkeylen = mpsignif(c->serverkey->n); hostkeylen = mpsignif(c->hostkey->n); ksmall = kbig = nil; if(serverkeylen+128 <= hostkeylen){ ksmall = c->serverkey; kbig = c->hostkey; }else if(hostkeylen+128 <= serverkeylen){ ksmall = c->hostkey; kbig = c->serverkey; }else error("server session and host keys do not differ by at least 128 bits"); buflen = (mpsignif(kbig->n)+7)/8; buf = emalloc(buflen); debug(DBG_CRYPTO, "session key is %.*H\n", SESSKEYLEN, c->sesskey); memmove(buf, c->sesskey, SESSKEYLEN); for(i = 0; i < SESSIDLEN; i++) buf[i] ^= c->sessid[i]; debug(DBG_CRYPTO, "munged session key is %.*H\n", SESSKEYLEN, buf); b = rsaencryptbuf(ksmall, buf, SESSKEYLEN); n = (mpsignif(ksmall->n)+7) / 8; mptoberjust(b, buf, n); mpfree(b); debug(DBG_CRYPTO, "encrypted with ksmall is %.*H\n", n, buf); b = rsaencryptbuf(kbig, buf, n); putmpint(m, b); debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b); mpfree(b); memset(buf, 0, buflen); free(buf); putlong(m, c->flags); sendmsg(m); }
void handleagentoclose(Msg *m) { uint32_t 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); } } }
static void send_ssh_smsg_public_key(Conn *c) { int i; Msg *m; m = allocmsg(c, SSH_SMSG_PUBLIC_KEY, 2048); putbytes(m, c->cookie, COOKIELEN); putRSApub(m, c->serverkey); putRSApub(m, c->hostkey); putlong(m, c->flags); for(i=0; i<c->nokcipher; i++) c->ciphermask |= 1<<c->okcipher[i]->id; putlong(m, c->ciphermask); for(i=0; i<c->nokauthsrv; i++) c->authmask |= 1<<c->okauthsrv[i]->id; putlong(m, c->authmask); sendmsg(m); }
void requestpty(Conn *c) { char *term; int nrow, ncol, width, height; Msg *m; m = allocmsg(c, SSH_CMSG_REQUEST_PTY, 1024); if((term = getenv("TERM")) == nil) term = "9term"; putstring(m, term); readgeom(&nrow, &ncol, &width, &height); putlong(m, nrow); /* characters */ putlong(m, ncol); putlong(m, width); /* pixels */ putlong(m, height); if(rawhack) putbytes(m, rawptyopt, sizeof rawptyopt); else putbytes(m, ptyopt, sizeof ptyopt); sendmsg(m); m = recvmsg(c, 0); switch(m->type){ case SSH_SMSG_SUCCESS: debug(DBG_IO, "PTY allocated\n"); break; case SSH_SMSG_FAILURE: debug(DBG_IO, "PTY allocation failed\n"); break; default: badmsg(m, 0); } free(m); }
void handleagentieof(Msg *m) { uint32_t 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 handlefullmsg(Conn *c, Achan *a) { int i; uint32_t chan, len, n, rt; uint8_t type; Msg *m, mm; Msg *r; Key *k; int nk; mpint *mod, *ek, *chal; uint8_t sessid[16]; uint8_t chalbuf[32]; uint8_t 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; i<nk; i++){ len += 4; len += 2+(mpsignif(k[i].ek)+7)/8; len += 2+(mpsignif(k[i].mod)+7)/8; len += 4+strlen(k[i].comment); } r = allocmsg(m->c, 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; i<nk; i++){ debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment); putlong(r, mpsignif(k[i].mod)); putmpint(r, k[i].ek); putmpint(r, k[i].mod); putstring(r, k[i].comment); mpfree(k[i].ek); mpfree(k[i].mod); free(k[i].comment); } free(k); sendmsg(r); break; case SSH_AGENTC_RSA_CHALLENGE: n = getlong(m); USED(n); /* number of bits in key; who cares? */ ek = getmpint(m); mod = getmpint(m); chal = getmpint(m); memmove(sessid, getbytes(m, 16), 16); rt = getlong(m); debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n", ek, mod, chal, rt, m->rp, 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; */ } }
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; }
void startcmd(Conn *c, char *cmd, int *kidpid, int *kidin) { int i, pid, kpid; int pfd[3][2]; char *dir; char *sysname, *tz; Msg *m; Waitmsg *w; for(i=0; i<3; i++) if(pipe(pfd[i]) < 0) sysfatal("pipe: %r"); sysname = getenv("sysname"); tz = getenv("timezone"); switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){ case -1: sysfatal("fork: %r"); case 0: switch(kpid = rfork(RFPROC|RFNOTEG|RFENVG|RFFDG)){ case -1: sysfatal("fork: %r"); case 0: for(i=0; i<3; i++){ if(dup(pfd[i][1], i) < 0) sysfatal("dup: %r"); close(pfd[i][0]); close(pfd[i][1]); } putenv("user", c->user); if(sysname) putenv("sysname", sysname); if(tz) putenv("tz", tz); dir = smprint("/usr/%s", c->user); if(dir == nil || chdir(dir) < 0) chdir("/"); if(cmd){ putenv("service", "rx"); execl("/bin/rc", "rc", "-lc", cmd, nil); sysfatal("cannot exec /bin/rc: %r"); }else{ putenv("service", "con"); execl("/bin/ip/telnetd", "telnetd", "-tn", nil); sysfatal("cannot exec /bin/ip/telnetd: %r"); } default: *kidpid = kpid; rendezvous(kidpid, 0); for(;;){ if((w = wait()) == nil) sysfatal("wait: %r"); if(w->pid == kpid) break; free(w); } if(w->msg[0]){ m = allocmsg(c, SSH_MSG_DISCONNECT, 4+strlen(w->msg)); putstring(m, w->msg); sendmsg(m); }else{ m = allocmsg(c, SSH_SMSG_EXITSTATUS, 4); putlong(m, 0); sendmsg(m); } for(i=0; i<3; i++) close(pfd[i][0]); free(w); exits(nil); break; } default: atexitkill(pid); rendezvous(kidpid, 0); break; } for(i=0; i<3; i++) close(pfd[i][1]); copyout(c, pfd[1][0], SSH_SMSG_STDOUT_DATA); copyout(c, pfd[2][0], SSH_SMSG_STDERR_DATA); *kidin = pfd[0][0]; }
void fromnet(Conn *c) { int infd, kidpid, n; char *cmd; Msg *m; infd = kidpid = -1; for(;;){ m = recvmsg(c, -1); if(m == nil) exits(nil); switch(m->type){ default: //badmsg(m, 0); sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); break; case SSH_MSG_DISCONNECT: sysfatal("client disconnected"); case SSH_CMSG_REQUEST_PTY: sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); break; case SSH_CMSG_X11_REQUEST_FORWARDING: sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); break; case SSH_CMSG_MAX_PACKET_SIZE: maxmsg = getlong(m); sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); break; case SSH_CMSG_REQUEST_COMPRESSION: sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); break; case SSH_CMSG_EXEC_SHELL: startcmd(c, nil, &kidpid, &infd); goto InteractiveMode; case SSH_CMSG_EXEC_CMD: cmd = getstring(m); startcmd(c, cmd, &kidpid, &infd); goto InteractiveMode; } free(m); } InteractiveMode: for(;;){ free(m); m = recvmsg(c, -1); if(m == nil) exits(nil); switch(m->type){ default: badmsg(m, 0); case SSH_MSG_DISCONNECT: postnote(PNGROUP, kidpid, "hangup"); sysfatal("client disconnected"); case SSH_CMSG_STDIN_DATA: if(infd != 0){ n = getlong(m); write(infd, getbytes(m, n), n); } break; case SSH_CMSG_EOF: close(infd); infd = -1; break; case SSH_CMSG_EXIT_CONFIRMATION: /* sent by some clients as dying breath */ exits(nil); case SSH_CMSG_WINDOW_SIZE: /* we don't care */ break; } } }
void main(int argc, char **argv) { int i, dowinchange, fd, usepty; char *host, *cmd, *user, *p; char *f[16]; Conn c; Msg *m; fmtinstall('B', mpfmt); fmtinstall('H', encodefmt); atexit(atexitkiller); atexitkill(getpid()); dowinchange = 0; if(getenv("LINES")) dowinchange = 1; usepty = -1; user = nil; ARGBEGIN{ case 'B': /* undocumented, debugging */ doabort = 1; break; case 'D': /* undocumented, debugging */ debuglevel = strtol(EARGF(usage()), nil, 0); break; case 'l': /* deprecated */ case 'u': user = EARGF(usage()); break; case 'a': /* used by Unix scp implementations; we must ignore them. */ case 'x': break; case 'A': authlist = EARGF(usage()); break; case 'C': cooked = 1; break; case 'c': cipherlist = EARGF(usage()); break; case 'f': forwardagent = 1; break; case 'I': interactive = 0; break; case 'i': interactive = 1; break; case 'm': usemenu = 0; break; case 'P': usepty = 0; break; case 'p': usepty = 1; break; case 'R': rawhack = 1; break; case 'r': crstrip = 1; break; default: usage(); }ARGEND if(argc < 1) usage(); host = argv[0]; cmd = nil; if(argc > 1) cmd = buildcmd(argc-1, argv+1); if((p = strchr(host, '@')) != nil){ *p++ = '\0'; user = host; host = p; } if(user == nil) user = getenv("user"); if(user == nil) sysfatal("cannot find user name"); privatefactotum(); if(interactive==-1) interactive = isatty(0); if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0) sysfatal("dialing %s: %r", host); memset(&c, 0, sizeof c); c.interactive = interactive; c.fd[0] = c.fd[1] = fd; c.user = user; c.host = host; setaliases(&c, host); c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", "); c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher); for(i=0; i<c.nokcipher; i++) c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher)); c.nokauth = getfields(authlist, f, nelem(f), 1, ", "); c.okauth = emalloc(sizeof(Auth*)*c.nokauth); for(i=0; i<c.nokauth; i++) c.okauth[i] = findauth(f[i], allauth, nelem(allauth)); sshclienthandshake(&c); if(forwardagent){ if(startagent(&c) < 0) forwardagent = 0; } if(usepty == -1) usepty = cmd==nil; if(usepty) requestpty(&c); if(cmd){ m = allocmsg(&c, SSH_CMSG_EXEC_CMD, 4+strlen(cmd)); putstring(m, cmd); }else m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0); sendmsg(m); fromstdin(&c); rfork(RFNOTEG); /* only fromstdin gets notes */ if(dowinchange) winchanges(&c); fromnet(&c); exits(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); }