diff options
-rw-r--r-- | auth.h | 1 | ||||
-rw-r--r-- | cli-auth.c | 15 | ||||
-rw-r--r-- | cli-authinteract.c | 2 | ||||
-rw-r--r-- | cli-authpasswd.c | 5 | ||||
-rw-r--r-- | cli-session.c | 8 | ||||
-rw-r--r-- | common-channel.c | 3 | ||||
-rw-r--r-- | common-session.c | 12 | ||||
-rw-r--r-- | random.c | 31 | ||||
-rw-r--r-- | random.h | 1 | ||||
-rw-r--r-- | rsa.c | 1 | ||||
-rw-r--r-- | scp.c | 32 | ||||
-rw-r--r-- | svr-chansession.c | 15 | ||||
-rw-r--r-- | svr-main.c | 4 | ||||
-rw-r--r-- | svr-runopts.c | 8 | ||||
-rw-r--r-- | svr-session.c | 6 | ||||
-rw-r--r-- | svr-tcpfwd.c | 2 | ||||
-rw-r--r-- | tcp-accept.c | 2 |
17 files changed, 119 insertions, 29 deletions
@@ -52,6 +52,7 @@ void cli_pubkeyfail(); void cli_auth_password(); int cli_auth_pubkey(); void cli_auth_interactive(); +char* getpass_or_cancel(); #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */ @@ -278,3 +278,18 @@ void cli_auth_try() { TRACE(("leave cli_auth_try")) } + +/* A helper for getpass() that exits if the user cancels. The returned + * password is statically allocated by getpass() */ +char* getpass_or_cancel() +{ + char* password = NULL; + + password = getpass("Password: "); + + /* 0x03 is a ctrl-c character in the buffer. */ + if (password == NULL || strchr(password, '\3') != NULL) { + dropbear_close("Interrupted."); + } + return password; +} diff --git a/cli-authinteract.c b/cli-authinteract.c index ef65517..5a169cb 100644 --- a/cli-authinteract.c +++ b/cli-authinteract.c @@ -115,7 +115,7 @@ void recv_msg_userauth_info_request() { echo = buf_getbool(ses.payload); if (!echo) { - unsigned char* p = getpass(prompt); + unsigned char* p = getpass_or_cancel(prompt); response = m_strdup(p); m_burn(p, strlen(p)); } else { diff --git a/cli-authpasswd.c b/cli-authpasswd.c index ec290e0..5dffac4 100644 --- a/cli-authpasswd.c +++ b/cli-authpasswd.c @@ -125,10 +125,7 @@ void cli_auth_password() { password = gui_getpass("Password: "); else #endif - password = getpass("Password: "); - - if (password == NULL) - return 0; + password = getpass_or_cancel("Password: "); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); diff --git a/cli-session.c b/cli-session.c index 0e906e6..35510fa 100644 --- a/cli-session.c +++ b/cli-session.c @@ -76,12 +76,14 @@ static const struct ChanType *cli_chantypes[] = { void cli_session(int sock, char* remotehost) { + seedrandom(); + crypto_init(); + common_session_init(sock, remotehost); chaninitialise(cli_chantypes); - /* Set up cli_ses vars */ cli_session_init(); @@ -91,12 +93,8 @@ void cli_session(int sock, char* remotehost) { /* Exchange identification */ session_identification(); - seedrandom(); - send_msg_kexinit(); - /* XXX here we do stuff differently */ - session_loop(cli_sessionloop); /* Not reached */ diff --git a/common-channel.c b/common-channel.c index 7e8d428..68d2b48 100644 --- a/common-channel.c +++ b/common-channel.c @@ -181,7 +181,6 @@ void channelio(fd_set *readfds, fd_set *writefds) { struct Channel *channel; unsigned int i; - int ret; /* iterate through all the possible channels */ for (i = 0; i < ses.chansize; i++) { @@ -377,7 +376,7 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { cbuf_incrread(cbuf, len); channel->recvdonelen += len; - if (fd == channel->writefd && len == maxlen && channel->recveof) { + if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) { /* Check if we're closing up */ closewritefd(channel); TRACE(("leave writechannel: recveof set")) diff --git a/common-session.c b/common-session.c index e8dc650..4c15391 100644 --- a/common-session.c +++ b/common-session.c @@ -232,10 +232,8 @@ void session_identification() { dropbear_exit("Error writing ident string"); } - /* We allow up to 9 lines before the actual version string, to - * account for wrappers/cruft etc. According to the spec only the client - * needs to handle this, but no harm in letting the server handle it too */ - for (i = 0; i < 10; i++) { + /* If they send more than 50 lines, something is wrong */ + for (i = 0; i < 50; i++) { len = ident_readln(ses.sock, linebuf, sizeof(linebuf)); if (len < 0 && errno != EINTR) { @@ -259,6 +257,12 @@ void session_identification() { memcpy(ses.remoteident, linebuf, len); } + /* Shall assume that 2.x will be backwards compatible. */ + if (strncmp(ses.remoteident, "SSH-2.", 6) != 0 + && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) { + dropbear_exit("Incompatible remote version '%s'", ses.remoteident); + } + TRACE(("remoteident: %s", ses.remoteident)) } @@ -30,8 +30,8 @@ static int donerandinit = 0; /* this is used to generate unique output from the same hashpool */ -static unsigned int counter = 0; -#define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */ +static uint32_t counter = 0; +#define MAX_COUNTER 1<<31 /* the max value for the counter, so it won't loop */ static unsigned char hashpool[SHA1_HASH_SIZE]; @@ -132,7 +132,8 @@ void seedrandom() { hash_state hs; - /* initialise so compilers will be happy about hashing it */ + /* initialise so that things won't warn about + * hashing an undefined buffer */ if (!donerandinit) { m_burn(hashpool, sizeof(hashpool)); } @@ -150,6 +151,30 @@ void seedrandom() { donerandinit = 1; } +/* hash the current random pool with some unique identifiers + * for this process and point-in-time. this is used to separate + * the random pools for fork()ed processes. */ +void reseedrandom() { + + pid_t pid; + struct timeval tv; + + if (!donerandinit) { + dropbear_exit("seedrandom not done"); + } + + pid = getpid(); + gettimeofday(&tv, NULL); + + hash_state hs; + unsigned char hash[SHA1_HASH_SIZE]; + sha1_init(&hs); + sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); + sha1_process(&hs, (void*)&pid, sizeof(pid)); + sha1_process(&hs, (void*)&tv, sizeof(tv)); + sha1_done(&hs, hashpool); +} + /* return len bytes of pseudo-random data */ void genrandom(unsigned char* buf, unsigned int len) { @@ -28,6 +28,7 @@ struct mp_int; void seedrandom(); +void reseedrandom(); void genrandom(unsigned char* buf, int len); void addrandom(unsigned char* buf, int len); void gen_random_mpint(mp_int *max, mp_int *rand); @@ -264,7 +264,6 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data, DEF_MP_INT(rsa_tmp1); DEF_MP_INT(rsa_tmp2); DEF_MP_INT(rsa_tmp3); - unsigned char *tmpbuf; TRACE(("enter buf_put_rsa_sign")) dropbear_assert(key != NULL); @@ -166,8 +166,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) close(reserved[0]); close(reserved[1]); + // uClinux needs to build the args here before vforking, + // otherwise we do it later on. +#ifdef __uClinux__ + args.list[0] = ssh_program; + if (remuser != NULL) + addargs(&args, "-l%s", remuser); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); +#endif /* __uClinux__ */ + /* Fork a child to execute the command on the remote host using ssh. */ +#ifdef __uClinux__ + do_cmd_pid = vfork(); +#else do_cmd_pid = fork(); +#endif /* __uClinux__ */ if (do_cmd_pid == 0) { /* Child. */ close(pin[1]); @@ -177,6 +191,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) close(pin[0]); close(pout[1]); +#ifndef __uClinux__ args.list[0] = ssh_program; if (remuser != NULL) { addargs(&args, "-l"); @@ -184,6 +199,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) } addargs(&args, "%s", host); addargs(&args, "%s", cmd); +#endif execvp(ssh_program, args.list); perror(ssh_program); @@ -192,6 +208,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) fprintf(stderr, "Fatal error: fork: %s\n", strerror(errno)); exit(1); } + +#ifdef __uClinux__ + /* clean up command */ + /* pop cmd */ + free(args->list[--args->num]); + args->list[args->num]=NULL; + /* pop host */ + free(args->list[--args->num-1]); + args->list[args->num]=NULL; + /* pop user */ + if (remuser != NULL) { + free(args->list[--args->num-1]); + args->list[args->num]=NULL; + } +#endif /* __uClinux__ + /* Parent. Close the other side, and return the local side. */ close(pin[0]); *fdout = pin[1]; diff --git a/svr-chansession.c b/svr-chansession.c index 9a0932e..0916e7e 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -623,7 +623,12 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) { if (pipe(errfds) != 0) return DROPBEAR_FAILURE; +#ifdef __uClinux__ + pid = vfork(); +#else pid = fork(); +#endif + if (pid < 0) return DROPBEAR_FAILURE; @@ -714,7 +719,11 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { return DROPBEAR_FAILURE; } +#ifdef __uClinux__ + pid = vfork(); +#else pid = fork(); +#endif if (pid < 0) return DROPBEAR_FAILURE; @@ -828,12 +837,16 @@ static void execchild(struct ChanSess *chansess) { char * baseshell = NULL; unsigned int i; + /* with uClinux we'll have vfork()ed, so don't want to overwrite the + * hostkey. can't think of a workaround to clear it */ +#ifndef __uClinux__ /* wipe the hostkey */ sign_key_free(svr_opts.hostkey); svr_opts.hostkey = NULL; /* overwrite the prng state */ - seedrandom(); + reseedrandom(); +#endif /* close file descriptors except stdin/stdout/stderr * Need to be sure FDs are closed here to avoid reading files as root */ @@ -81,7 +81,7 @@ static void main_inetd() { socklen_t remoteaddrlen; char * addrstring = NULL; - /* Set up handlers, syslog */ + /* Set up handlers, syslog, seed random */ commonsetup(); remoteaddrlen = sizeof(remoteaddr); @@ -385,6 +385,8 @@ static void commonsetup() { /* Now we can setup the hostkeys - needs to be after logging is on, * otherwise we might end up blatting error messages to the socket */ loadhostkeys(); + + seedrandom(); } /* Set up listening sockets for all the requested ports */ diff --git a/svr-runopts.c b/svr-runopts.c index 6c42fb4..8d8b8df 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -105,8 +105,12 @@ void svr_getopts(int argc, char ** argv) { svr_opts.inetdmode = 0; svr_opts.portcount = 0; svr_opts.hostkey = NULL; +#ifdef ENABLE_SVR_LOCALTCPFWD svr_opts.nolocaltcp = 0; +#endif +#ifdef ENABLE_SVR_REMOTETCPFWD svr_opts.noremotetcp = 0; +#endif /* not yet opts.ipv4 = 1; opts.ipv6 = 1; @@ -154,12 +158,12 @@ void svr_getopts(int argc, char ** argv) { svr_opts.usingsyslog = 0; break; #endif -#ifndef DISABLE_LOCALTCPFWD +#ifdef ENABLE_SVR_LOCALTCPFWD case 'j': svr_opts.nolocaltcp = 1; break; #endif -#ifndef DISABLE_REMOTETCPFWD +#ifdef ENABLE_SVR_REMOTETCPFWD case 'k': svr_opts.noremotetcp = 1; break; diff --git a/svr-session.c b/svr-session.c index 408209d..70029f8 100644 --- a/svr-session.c +++ b/svr-session.c @@ -78,7 +78,9 @@ void svr_session(int sock, int childpipe, char* remotehost, char *addrstring) { struct timeval timeout; - + + reseedrandom(); + crypto_init(); common_session_init(sock, remotehost); @@ -110,8 +112,6 @@ void svr_session(int sock, int childpipe, /* exchange identification, version etc */ session_identification(); - seedrandom(); - /* start off with key exchange */ send_msg_kexinit(); diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c index 53a115e..6391c4c 100644 --- a/svr-tcpfwd.c +++ b/svr-tcpfwd.c @@ -80,7 +80,7 @@ void recv_msg_global_request_remotetcp() { reqname = buf_getstring(ses.payload, &namelen); wantreply = buf_getbool(ses.payload); - if (namelen > MAXNAMLEN) { + if (namelen > MAX_NAME_LEN) { TRACE(("name len is wrong: %d", namelen)) goto out; } diff --git a/tcp-accept.c b/tcp-accept.c index 90d72b3..ffb175e 100644 --- a/tcp-accept.c +++ b/tcp-accept.c @@ -47,7 +47,7 @@ static void tcp_acceptor(struct Listener *listener, int sock) { int fd; struct sockaddr_storage addr; - int len; + socklen_t len; char ipstring[NI_MAXHOST], portstring[NI_MAXSERV]; struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); |