3 char *cipherlist = "blowfish rc4 3des";
4 char *authlist = "tis";
7 void startcmd(Conn*, char*, int*, int*);
10 Cipher *allcipher[] = {
19 Authsrv *allauthsrv[] = {
25 findcipher(char *name, Cipher **list, int nlist)
29 for(i=0; i<nlist; i++)
30 if(strcmp(name, list[i]->name) == 0)
32 error("unknown cipher %s", name);
37 findauthsrv(char *name, Authsrv **list, int nlist)
41 for(i=0; i<nlist; i++)
42 if(strcmp(name, list[i]->name) == 0)
44 error("unknown authsrv %s", name);
51 fprint(2, "usage: sshserve [-A authlist] [-c cipherlist] client-ip-address\n");
56 main(int argc, char **argv)
62 fmtinstall('B', mpfmt);
63 fmtinstall('H', encodefmt);
67 memset(&c, 0, sizeof c);
71 debuglevel = atoi(EARGF(usage()));
74 authlist = EARGF(usage());
77 cipherlist = EARGF(usage());
87 sshlog("connect from %s", c.host);
89 /* limit of 768 bits in remote host key? */
90 c.serverpriv = rsagen(768, 6, 0);
91 if(c.serverpriv == nil)
92 sysfatal("rsagen failed: %r");
93 c.serverkey = &c.serverpriv->pub;
95 c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
96 c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
97 for(i=0; i<c.nokcipher; i++)
98 c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
100 c.nokauthsrv = getfields(authlist, f, nelem(f), 1, ", ");
101 c.okauthsrv = emalloc(sizeof(Authsrv*)*c.nokauthsrv);
102 for(i=0; i<c.nokauthsrv; i++)
103 c.okauthsrv[i] = findauthsrv(f[i], allauthsrv, nelem(allauthsrv));
105 sshserverhandshake(&c);
125 sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
128 case SSH_MSG_DISCONNECT:
129 sysfatal("client disconnected");
131 case SSH_CMSG_REQUEST_PTY:
132 sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
135 case SSH_CMSG_X11_REQUEST_FORWARDING:
136 sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
139 case SSH_CMSG_MAX_PACKET_SIZE:
141 sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
144 case SSH_CMSG_REQUEST_COMPRESSION:
145 sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
148 case SSH_CMSG_EXEC_SHELL:
149 startcmd(c, nil, &kidpid, &infd);
150 goto InteractiveMode;
152 case SSH_CMSG_EXEC_CMD:
154 startcmd(c, cmd, &kidpid, &infd);
155 goto InteractiveMode;
170 case SSH_MSG_DISCONNECT:
171 postnote(PNGROUP, kidpid, "hangup");
172 sysfatal("client disconnected");
174 case SSH_CMSG_STDIN_DATA:
177 write(infd, getbytes(m, n), n);
186 case SSH_CMSG_EXIT_CONFIRMATION:
187 /* sent by some clients as dying breath */
190 case SSH_CMSG_WINDOW_SIZE:
198 copyout(Conn *c, int fd, int mtype)
205 if(max > maxmsg - 32) /* 32 is an overestimate of packet overhead */
208 sysfatal("maximum message size too small");
210 switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
212 sysfatal("fork: %r");
220 while((n = read(fd, buf, max)) > 0){
221 m = allocmsg(c, mtype, 4+n);
230 startcmd(Conn *c, char *cmd, int *kidpid, int *kidin)
241 sysfatal("pipe: %r");
243 sysname = getenv("sysname");
244 tz = getenv("timezone");
246 switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
248 sysfatal("fork: %r");
250 switch(kpid = rfork(RFPROC|RFNOTEG|RFENVG|RFFDG)){
252 sysfatal("fork: %r");
255 if(dup(pfd[i][1], i) < 0)
260 putenv("user", c->user);
262 putenv("sysname", sysname);
266 dir = smprint("/usr/%s", c->user);
267 if(dir == nil || chdir(dir) < 0)
270 putenv("service", "rx");
271 execl("/bin/rc", "rc", "-lc", cmd, nil);
272 sysfatal("cannot exec /bin/rc: %r");
274 putenv("service", "con");
275 execl("/bin/ip/telnetd", "telnetd", "-tn", nil);
276 sysfatal("cannot exec /bin/ip/telnetd: %r");
280 rendezvous(kidpid, 0);
282 if((w = wait()) == nil)
283 sysfatal("wait: %r");
289 m = allocmsg(c, SSH_MSG_DISCONNECT, 4+strlen(w->msg));
290 putstring(m, w->msg);
293 m = allocmsg(c, SSH_SMSG_EXITSTATUS, 4);
305 rendezvous(kidpid, 0);
312 copyout(c, pfd[1][0], SSH_SMSG_STDOUT_DATA);
313 copyout(c, pfd[2][0], SSH_SMSG_STDERR_DATA);