summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--chansession.h3
-rw-r--r--cli-authinteract.c5
-rw-r--r--cli-chansession.c60
-rw-r--r--cli-main.c42
-rw-r--r--cli-runopts.c218
-rw-r--r--cli-session.c32
-rw-r--r--common-channel.c5
-rw-r--r--common-session.c61
-rw-r--r--dbutil.c156
-rw-r--r--dbutil.h4
-rw-r--r--debug.h2
-rw-r--r--genrsa.c14
-rw-r--r--keyimport.c1
-rw-r--r--options.h16
-rw-r--r--packet.c6
-rw-r--r--runopts.h11
-rw-r--r--session.h9
-rw-r--r--svr-auth.c23
-rw-r--r--svr-chansession.c161
-rw-r--r--svr-runopts.c7
-rw-r--r--svr-session.c10
21 files changed, 586 insertions, 260 deletions
diff --git a/chansession.h b/chansession.h
index 213c285..4513b1a 100644
--- a/chansession.h
+++ b/chansession.h
@@ -78,6 +78,9 @@ void addnewvar(const char* param, const char* var);
void cli_send_chansess_request();
void cli_tty_cleanup();
void cli_chansess_winchange();
+#ifdef ENABLE_CLI_NETCAT
+void cli_send_netcat_request();
+#endif
void svr_chansessinitialise();
extern const struct ChanType svrchansess;
diff --git a/cli-authinteract.c b/cli-authinteract.c
index 5fe5bf1..7851578 100644
--- a/cli-authinteract.c
+++ b/cli-authinteract.c
@@ -77,6 +77,11 @@ void recv_msg_userauth_info_request() {
TRACE(("enter recv_msg_recv_userauth_info_request"))
+ /* Let the user know what password/host they are authing for */
+ if (!cli_ses.interact_request_received) {
+ fprintf(stderr, "Login for %s@%s\n", cli_opts.username,
+ cli_opts.remotehost);
+ }
cli_ses.interact_request_received = 1;
name = buf_getstring(ses.payload, NULL);
diff --git a/cli-chansession.c b/cli-chansession.c
index c92f902..07b9b9d 100644
--- a/cli-chansession.c
+++ b/cli-chansession.c
@@ -338,9 +338,8 @@ static void send_chansess_shell_req(struct Channel *channel) {
TRACE(("leave send_chansess_shell_req"))
}
-static int cli_initchansess(struct Channel *channel) {
-
-
+/* Shared for normal client channel and netcat-alike */
+static int cli_init_stdpipe_sess(struct Channel *channel) {
channel->writefd = STDOUT_FILENO;
setnonblocking(STDOUT_FILENO);
@@ -351,6 +350,12 @@ static int cli_initchansess(struct Channel *channel) {
setnonblocking(STDERR_FILENO);
channel->extrabuf = cbuf_new(opts.recv_window);
+ return 0;
+}
+
+static int cli_initchansess(struct Channel *channel) {
+
+ cli_init_stdpipe_sess(channel);
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
@@ -363,12 +368,48 @@ static int cli_initchansess(struct Channel *channel) {
}
return 0; /* Success */
+}
+
+#ifdef ENABLE_CLI_NETCAT
+
+void cli_send_netcat_request() {
+
+ const unsigned char* source_host = "127.0.0.1";
+ const int source_port = 22;
+
+ const struct ChanType cli_chan_netcat = {
+ 0, /* sepfds */
+ "direct-tcpip",
+ cli_init_stdpipe_sess, /* inithandler */
+ NULL,
+ NULL,
+ cli_closechansess
+ };
+
+ cli_opts.wantpty = 0;
+ if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
+ == DROPBEAR_FAILURE) {
+ dropbear_exit("Couldn't open initial channel");
+ }
+
+ buf_putstring(ses.writepayload, cli_opts.netcat_host,
+ strlen(cli_opts.netcat_host));
+ buf_putint(ses.writepayload, cli_opts.netcat_port);
+
+ /* originator ip - localhost is accurate enough */
+ buf_putstring(ses.writepayload, source_host, strlen(source_host));
+ buf_putint(ses.writepayload, source_port);
+
+ encrypt_packet();
+ TRACE(("leave cli_send_chansess_request"))
}
+#endif
void cli_send_chansess_request() {
TRACE(("enter cli_send_chansess_request"))
+
if (send_msg_channel_open_init(STDIN_FILENO, &clichansess)
== DROPBEAR_FAILURE) {
dropbear_exit("Couldn't open initial channel");
@@ -379,3 +420,16 @@ void cli_send_chansess_request() {
TRACE(("leave cli_send_chansess_request"))
}
+
+
+#if 0
+ while (cli_opts.localfwds != NULL) {
+ ret = cli_localtcp(cli_opts.localfwds->listenport,
+ cli_opts.localfwds->connectaddr,
+ cli_opts.localfwds->connectport);
+ if (ret == DROPBEAR_FAILURE) {
+ dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
+ cli_opts.localfwds->listenport,
+ cli_opts.localfwds->connectaddr,
+ cli_opts.localfwds->connectport);
+#endif
diff --git a/cli-main.c b/cli-main.c
index 68cf023..4ba43c0 100644
--- a/cli-main.c
+++ b/cli-main.c
@@ -32,6 +32,8 @@
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
static void cli_dropbear_log(int priority, const char* format, va_list param);
+static void cli_proxy_cmd(int *sock_in, int *sock_out);
+
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
int cli_main(int argc, char ** argv) {
@@ -39,7 +41,7 @@ int cli_main(int argc, char ** argv) {
int main(int argc, char ** argv) {
#endif
- int sock;
+ int sock_in, sock_out;
char* error = NULL;
char* hostandport;
int len;
@@ -58,10 +60,18 @@ int main(int argc, char ** argv) {
dropbear_exit("signal() error");
}
- sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
- 0, &error);
+#ifdef ENABLE_CLI_PROXYCMD
+ if (cli_opts.proxycmd) {
+ cli_proxy_cmd(&sock_in, &sock_out);
+ } else
+#endif
+ {
+ int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
+ 0, &error);
+ sock_in = sock_out = sock;
+ }
- if (sock < 0) {
+ if (sock_in < 0) {
dropbear_exit("%s", error);
}
@@ -72,7 +82,7 @@ int main(int argc, char ** argv) {
snprintf(hostandport, len, "%s:%s",
cli_opts.remotehost, cli_opts.remoteport);
- cli_session(sock, hostandport);
+ cli_session(sock_in, sock_out, hostandport);
/* not reached */
return -1;
@@ -112,3 +122,25 @@ static void cli_dropbear_log(int UNUSED(priority),
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
}
+
+static void exec_proxy_cmd(void *user_data_cmd) {
+ const char *cmd = user_data_cmd;
+ char *usershell;
+
+ usershell = m_strdup(get_user_shell());
+ run_shell_command(cmd, ses.maxfd, usershell);
+ dropbear_exit("Failed to run '%s'\n", cmd);
+}
+
+static void cli_proxy_cmd(int *sock_in, int *sock_out) {
+ int ret;
+
+ fill_passwd(cli_opts.own_user);
+
+ ret = spawn_command(exec_proxy_cmd, cli_opts.proxycmd,
+ sock_out, sock_in, NULL, NULL);
+ if (ret == DROPBEAR_FAILURE) {
+ dropbear_exit("Failed running proxy command");
+ *sock_in = *sock_out = -1;
+ }
+}
diff --git a/cli-runopts.c b/cli-runopts.c
index 42c5a9f..0641ec7 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -33,18 +33,23 @@
cli_runopts cli_opts; /* GLOBAL */
static void printhelp();
-static void parsehostname(char* userhostarg);
+static void parse_hostname(const char* orighostarg);
+static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
+static void fill_own_user();
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename);
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
-static void addforward(char* str, struct TCPFwdList** fwdlist);
+static void addforward(const char* str, struct TCPFwdList** fwdlist);
+#endif
+#ifdef ENABLE_CLI_NETCAT
+static void add_netcat(const char *str);
#endif
static void printhelp() {
fprintf(stderr, "Dropbear client v%s\n"
- "Usage: %s [options] [user@]host [command]\n"
+ "Usage: %s [options] [user@]host[/port] [command]\n"
"Options are:\n"
"-p <remoteport>\n"
"-l <username>\n"
@@ -65,6 +70,12 @@ static void printhelp() {
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
+#ifdef ENABLE_CLI_NETCAT
+ "-B <endhost:endport> Netcat-alike bouncing\n"
+#endif
+#ifdef ENABLE_CLI_PROXYCMD
+ "-J <proxy_program> Use program rather than tcp connection\n"
+#endif
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
@@ -87,6 +98,9 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_REMOTETCPFWD
int nextisremote = 0;
#endif
+#ifdef ENABLE_CLI_NETCAT
+ int nextisnetcat = 0;
+#endif
char* dummy = NULL; /* Not used for anything real */
char* recv_window_arg = NULL;
@@ -112,12 +126,17 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_REMOTETCPFWD
cli_opts.remotefwds = NULL;
#endif
+#ifdef ENABLE_CLI_PROXYCMD
+ cli_opts.proxycmd = NULL;
+#endif
/* not yet
opts.ipv4 = 1;
opts.ipv6 = 1;
*/
opts.recv_window = DEFAULT_RECV_WINDOW;
+ fill_own_user();
+
/* Iterate all the arguments */
for (i = 1; i < (unsigned int)argc; i++) {
#ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -144,6 +163,14 @@ void cli_getopts(int argc, char ** argv) {
continue;
}
#endif
+#ifdef ENABLE_CLI_NETCAT
+ if (nextisnetcat) {
+ TRACE(("nextisnetcat true"))
+ add_netcat(argv[i]);
+ nextisnetcat = 0;
+ continue;
+ }
+#endif
if (next) {
/* The previous flag set a value to assign */
*next = argv[i];
@@ -199,6 +226,16 @@ void cli_getopts(int argc, char ** argv) {
nextisremote = 1;
break;
#endif
+#ifdef ENABLE_CLI_NETCAT
+ case 'B':
+ nextisnetcat = 1;
+ break;
+#endif
+#ifdef ENABLE_CLI_PROXYCMD
+ case 'J':
+ next = &cli_opts.proxycmd;
+ break;
+#endif
case 'l':
next = &cli_opts.username;
break;
@@ -254,9 +291,11 @@ void cli_getopts(int argc, char ** argv) {
/* Either the hostname or commands */
if (cli_opts.remotehost == NULL) {
-
- parsehostname(argv[i]);
-
+#ifdef ENABLE_CLI_MULTIHOP
+ parse_multihop_hostname(argv[i], argv[0]);
+#else
+ parse_hostname(argv[i]);
+#endif
} else {
/* this is part of the commands to send - after this we
@@ -283,6 +322,8 @@ void cli_getopts(int argc, char ** argv) {
}
}
+ /* And now a few sanity checks and setup */
+
if (cli_opts.remotehost == NULL) {
printhelp();
exit(EXIT_FAILURE);
@@ -307,21 +348,23 @@ void cli_getopts(int argc, char ** argv) {
dropbear_exit("command required for -f");
}
- if (recv_window_arg)
- {
+ if (recv_window_arg) {
opts.recv_window = atol(recv_window_arg);
- if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW)
- {
+ if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
dropbear_exit("Bad recv window '%s'", recv_window_arg);
}
}
if (keepalive_arg) {
- opts.keepalive_secs = strtoul(keepalive_arg, NULL, 10);
- if (opts.keepalive_secs == 0 && errno == EINVAL)
- {
+ if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
}
+
+#ifdef ENABLE_CLI_NETCAT
+ if (cli_opts.cmd && cli_opts.netcat_host) {
+ dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
+ }
+#endif
}
@@ -350,16 +393,77 @@ static void loadidentityfile(const char* filename) {
}
#endif
+#ifdef ENABLE_CLI_MULTIHOP
+
+/* Sets up 'onion-forwarding' connections. This will spawn
+ * a separate dbclient process for each hop.
+ * As an example, if the cmdline is
+ * dbclient wrt,madako,canyons
+ * then we want to run:
+ * dbclient -J "dbclient -B canyons:22 wrt,madako" canyons
+ * and then the inner dbclient will recursively run:
+ * dbclient -J "dbclient -B madako:22 wrt" madako
+ * etc for as many hosts as we want.
+ *
+ * Ports for hosts can be specified as host/port.
+ */
+static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
+ char *userhostarg = NULL;
+ char *last_hop = NULL;;
+ char *remainder = NULL;
+
+ /* both scp and rsync parse a user@host argument
+ * and turn it into "-l user host". This breaks
+ * for our multihop syntax, so we suture it back together.
+ * This will break usernames that have both '@' and ',' in them,
+ * though that should be fairly uncommon. */
+ if (cli_opts.username
+ && strchr(cli_opts.username, ',')
+ && strchr(cli_opts.username, '@')) {
+ unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
+ userhostarg = m_malloc(len);
+ snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
+ } else {
+ userhostarg = m_strdup(orighostarg);
+ }
+
+ last_hop = strrchr(userhostarg, ',');
+ if (last_hop) {
+ if (last_hop == userhostarg) {
+ dropbear_exit("Bad multi-hop hostnames");
+ }
+ *last_hop = '\0';
+ last_hop++;
+ remainder = userhostarg;
+ userhostarg = last_hop;
+ }
+
+ parse_hostname(userhostarg);
-/* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding
- * - note that it will be modified */
-static void parsehostname(char* orighostarg) {
+ if (last_hop) {
+ /* Set up the proxycmd */
+ unsigned int cmd_len = 0;
+ if (cli_opts.proxycmd) {
+ dropbear_exit("-J can't be used with multihop mode");
+ }
+ if (cli_opts.remoteport == NULL) {
+ cli_opts.remoteport = "22";
+ }
+ cmd_len = strlen(remainder)
+ + strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ + strlen(argv0) + 30;
+ cli_opts.proxycmd = m_malloc(cmd_len);
+ snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
+ argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
+ }
+}
+#endif /* !ENABLE_CLI_MULTIHOP */
- uid_t uid;
- struct passwd *pw = NULL;
+/* Parses a [user@]hostname[/port] argument. */
+static void parse_hostname(const char* orighostarg) {
char *userhostarg = NULL;
+ char *port = NULL;
- /* We probably don't want to be editing argvs */
userhostarg = m_strdup(orighostarg);
cli_opts.remotehost = strchr(userhostarg, '@');
@@ -374,14 +478,13 @@ static void parsehostname(char* orighostarg) {
}
if (cli_opts.username == NULL) {
- uid = getuid();
-
- pw = getpwuid(uid);
- if (pw == NULL || pw->pw_name == NULL) {
- dropbear_exit("Unknown own user");
- }
+ cli_opts.username = m_strdup(cli_opts.own_user);
+ }
- cli_opts.username = m_strdup(pw->pw_name);
+ port = strchr(cli_opts.remotehost, '/');
+ if (port) {
+ *port = '\0';
+ cli_opts.remoteport = port+1;
}
if (cli_opts.remotehost[0] == '\0') {
@@ -389,10 +492,61 @@ static void parsehostname(char* orighostarg) {
}
}
+#ifdef ENABLE_CLI_NETCAT
+static void add_netcat(const char* origstr) {
+ char *portstr = NULL;
+
+ char * str = m_strdup(origstr);
+
+ portstr = strchr(str, ':');
+ if (portstr == NULL) {
+ TRACE(("No netcat port"))
+ goto fail;
+ }
+ *portstr = '\0';
+ portstr++;
+
+ if (strchr(portstr, ':')) {
+ TRACE(("Multiple netcat colons"))
+ goto fail;
+ }
+
+ if (m_str_to_uint(portstr, &cli_opts.netcat_port) == DROPBEAR_FAILURE) {
+ TRACE(("bad netcat port"))
+ goto fail;
+ }
+
+ if (cli_opts.netcat_port > 65535) {
+ TRACE(("too large netcat port"))
+ goto fail;
+ }
+
+ cli_opts.netcat_host = str;
+ return;
+
+fail:
+ dropbear_exit("Bad netcat endpoint '%s'", origstr);
+}
+#endif
+
+static void fill_own_user() {
+ uid_t uid;
+ struct passwd *pw = NULL;
+
+ uid = getuid();
+
+ pw = getpwuid(uid);
+ if (pw == NULL || pw->pw_name == NULL) {
+ dropbear_exit("Unknown own user");
+ }
+
+ cli_opts.own_user = m_strdup(pw->pw_name);
+}
+
#ifdef ENABLE_CLI_ANYTCPFWD
/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
* set, and add it to the forwarding list */
-static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
+static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
char * listenport = NULL;
char * connectport = NULL;
@@ -428,15 +582,13 @@ static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
/* Now we check the ports - note that the port ints are unsigned,
* the check later only checks for >= MAX_PORT */
- newfwd->listenport = strtol(listenport, NULL, 10);
- if (errno != 0) {
- TRACE(("bad listenport strtol"))
+ if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) {
+ TRACE(("bad listenport strtoul"))
goto fail;
}
- newfwd->connectport = strtol(connectport, NULL, 10);
- if (errno != 0) {
- TRACE(("bad connectport strtol"))
+ if (m_str_to_uint(connectport, &newfwd->connectport) == DROPBEAR_FAILURE) {
+ TRACE(("bad connectport strtoul"))
goto fail;
}
diff --git a/cli-session.c b/cli-session.c
index 360187f..d0a7361 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -74,13 +74,13 @@ static const struct ChanType *cli_chantypes[] = {
NULL /* Null termination */
};
-void cli_session(int sock, char* remotehost) {
+void cli_session(int sock_in, int sock_out, char* remotehost) {
seedrandom();
crypto_init();
- common_session_init(sock, remotehost);
+ common_session_init(sock_in, sock_out, remotehost);
chaninitialise(cli_chantypes);
@@ -197,20 +197,6 @@ static void cli_sessionloop() {
TRACE(("leave cli_sessionloop: cli_auth_try"))
return;
- /*
- case USERAUTH_SUCCESS_RCVD:
- send_msg_service_request(SSH_SERVICE_CONNECTION);
- cli_ses.state = SERVICE_CONN_REQ_SENT;
- TRACE(("leave cli_sessionloop: sent ssh-connection service req"))
- return;
-
- case SERVICE_CONN_ACCEPT_RCVD:
- cli_send_chansess_request();
- TRACE(("leave cli_sessionloop: cli_send_chansess_request"))
- cli_ses.state = SESSION_RUNNING;
- return;
- */
-
case USERAUTH_SUCCESS_RCVD:
if (cli_opts.backgrounded) {
@@ -235,7 +221,13 @@ static void cli_sessionloop() {
#ifdef ENABLE_CLI_REMOTETCPFWD
setup_remotetcp();
#endif
- if (!cli_opts.no_cmd) {
+
+#ifdef ENABLE_CLI_NETCAT
+ if (cli_opts.netcat_host) {
+ cli_send_netcat_request();
+ } else
+#endif
+ if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
TRACE(("leave cli_sessionloop: running"))
@@ -294,8 +286,10 @@ static void cli_remoteclosed() {
/* XXX TODO perhaps print a friendlier message if we get this but have
* already sent/received disconnect message(s) ??? */
- close(ses.sock);
- ses.sock = -1;
+ m_close(ses.sock_in);
+ m_close(ses.sock_out);
+ ses.sock_in = -1;
+ ses.sock_out = -1;
dropbear_exit("remote closed the connection");
}
diff --git a/common-channel.c b/common-channel.c
index 09fe425..2105184 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -572,6 +572,11 @@ void recv_msg_channel_request() {
channel = getchannel();
+ if (channel->sent_close) {
+ TRACE(("leave recv_msg_channel_request: already closed channel"))
+ return;
+ }
+
if (channel->type->reqhandler) {
channel->type->reqhandler(channel);
} else {
diff --git a/common-session.c b/common-session.c
index 79313f2..3d759b5 100644
--- a/common-session.c
+++ b/common-session.c
@@ -52,14 +52,15 @@ int exitflag = 0; /* GLOBAL */
/* called only at the start of a session, set up initial state */
-void common_session_init(int sock, char* remotehost) {
+void common_session_init(int sock_in, int sock_out, char* remotehost) {
TRACE(("enter session_init"))
ses.remotehost = remotehost;
- ses.sock = sock;
- ses.maxfd = sock;
+ ses.sock_in = sock_in;
+ ses.sock_out = sock_out;
+ ses.maxfd = MAX(sock_in, sock_out);
ses.connect_time = 0;
ses.last_packet_time = 0;
@@ -137,11 +138,11 @@ void session_loop(void(*loophandler)()) {
FD_ZERO(&writefd);
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
- if (ses.sock != -1) {
- FD_SET(ses.sock, &readfd);
- if (!isempty(&ses.writequeue)) {
- FD_SET(ses.sock, &writefd);
- }
+ if (ses.sock_in != -1) {
+ FD_SET(ses.sock_in, &readfd);
+ }
+ if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
+ FD_SET(ses.sock_out, &writefd);
}
/* We get woken up when signal handlers write to this pipe.
@@ -183,12 +184,14 @@ void session_loop(void(*loophandler)()) {
checktimeouts();
/* process session socket's incoming/outgoing data */
- if (ses.sock != -1) {
- if (FD_ISSET(ses.sock, &writefd) && !isempty(&ses.writequeue)) {
+ if (ses.sock_out != -1) {
+ if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) {
write_packet();
}
+ }
- if (FD_ISSET(ses.sock, &readfd)) {
+ if (ses.sock_in != -1) {
+ if (FD_ISSET(ses.sock_in, &readfd)) {
read_packet();
}
@@ -248,14 +251,14 @@ void session_identification() {
int i;
/* write our version string, this blocks */
- if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n",
+ if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n",
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
ses.remoteclosed();
}
/* If they send more than 50 lines, something is wrong */
for (i = 0; i < 50; i++) {
- len = ident_readln(ses.sock, linebuf, sizeof(linebuf));
+ len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
if (len < 0 && errno != EINTR) {
/* It failed */
@@ -411,3 +414,35 @@ static long select_timeout() {
ret = MIN(opts.keepalive_secs, ret);
return ret;
}
+
+const char* get_user_shell() {
+ /* an empty shell should be interpreted as "/bin/sh" */
+ if (ses.authstate.pw_shell[0] == '\0') {
+ return "/bin/sh";
+ } else {
+ return ses.authstate.pw_shell;
+ }
+}
+void fill_passwd(const char* username) {
+ struct passwd *pw = NULL;
+ if (ses.authstate.pw_name)
+ m_free(ses.authstate.pw_name);
+ if (ses.authstate.pw_dir)
+ m_free(ses.authstate.pw_dir);
+ if (ses.authstate.pw_shell)
+ m_free(ses.authstate.pw_shell);
+ if (ses.authstate.pw_passwd)
+ m_free(ses.authstate.pw_passwd);
+
+ pw = getpwnam(username);
+ if (!pw) {
+ return;
+ }
+ ses.authstate.pw_uid = pw->pw_uid;
+ ses.authstate.pw_gid = pw->pw_gid;
+ ses.authstate.pw_name = m_strdup(pw->pw_name);
+ ses.authstate.pw_dir = m_strdup(pw->pw_dir);
+ ses.authstate.pw_shell = m_strdup(pw->pw_shell);
+ ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
+}
+
diff --git a/dbutil.c b/dbutil.c
index 0967ddc..b016dc1 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -146,7 +146,7 @@ void dropbear_trace(const char* format, ...) {
}
va_start(param, format);
- fprintf(stderr, "TRACE: ");
+ fprintf(stderr, "TRACE (%d): ", getpid());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
@@ -321,9 +321,10 @@ int connect_remote(const char* remotehost, const char* remoteport,
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
- len = 20 + strlen(gai_strerror(err));
+ len = 100 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
- snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
+ snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
+ remotehost, remoteport, gai_strerror(err));
}
TRACE(("Error resolving: %s", gai_strerror(err)))
return -1;
@@ -389,6 +390,141 @@ int connect_remote(const char* remotehost, const char* remoteport,
return sock;
}
+/* Sets up a pipe for a, returning three non-blocking file descriptors
+ * and the pid. exec_fn is the function that will actually execute the child process,
+ * it will be run after the child has fork()ed, and is passed exec_data.
+ * If ret_errfd == NULL then stderr will not be captured.
+ * ret_pid can be passed as NULL to discard the pid. */
+int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
+ int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
+ int infds[2];
+ int outfds[2];
+ int errfds[2];
+ pid_t pid;
+
+ const int FDIN = 0;
+ const int FDOUT = 1;
+
+ /* redirect stdin/stdout/stderr */
+ if (pipe(infds) != 0) {
+ return DROPBEAR_FAILURE;
+ }
+ if (pipe(outfds) != 0) {
+ return DROPBEAR_FAILURE;
+ }
+ if (ret_errfd && pipe(errfds) != 0) {
+ return DROPBEAR_FAILURE;
+ }
+
+#ifdef __uClinux__
+ pid = vfork();
+#else
+ pid = fork();
+#endif
+
+ if (pid < 0) {
+ return DROPBEAR_FAILURE;
+ }
+
+ if (!pid) {
+ /* child */
+
+ TRACE(("back to normal sigchld"))
+ /* Revert to normal sigchld handling */
+ if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
+ dropbear_exit("signal() error");
+ }
+
+ /* redirect stdin/stdout */
+
+ if ((dup2(infds[FDIN], STDIN_FILENO) < 0) ||
+ (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
+ (ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
+ TRACE(("leave noptycommand: error redirecting FDs"))
+ dropbear_exit("child dup2() failure");
+ }
+
+ close(infds[FDOUT]);
+ close(infds[FDIN]);
+ close(outfds[FDIN]);
+ close(outfds[FDOUT]);
+ if (ret_errfd)
+ {
+ close(errfds[FDIN]);
+ close(errfds[FDOUT]);
+ }
+
+ exec_fn(exec_data);
+ /* not reached */
+ return DROPBEAR_FAILURE;
+ } else {
+ /* parent */
+ close(infds[FDIN]);
+ close(outfds[FDOUT]);
+
+ setnonblocking(outfds[FDIN]);
+ setnonblocking(infds[FDOUT]);
+
+ if (ret_errfd) {
+ close(errfds[FDOUT]);
+ setnonblocking(errfds[FDIN]);
+ }
+
+ if (ret_pid) {
+ *ret_pid = pid;
+ }
+
+ *ret_writefd = infds[FDOUT];
+ *ret_readfd = outfds[FDIN];
+ if (ret_errfd) {
+ *ret_errfd = errfds[FDIN];
+ }
+ return DROPBEAR_SUCCESS;
+ }
+}
+
+/* Runs a command with "sh -c". Will close FDs (except stdin/stdout/stderr) and
+ * re-enabled SIGPIPE. If cmd is NULL, will run a login shell.
+ */
+void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
+ char * argv[4];
+ char * baseshell = NULL;
+ unsigned int i;
+
+ baseshell = basename(usershell);
+
+ if (cmd != NULL) {
+ argv[0] = baseshell;
+ } else {
+ /* a login shell should be "-bash" for "/bin/bash" etc */
+ int len = strlen(baseshell) + 2; /* 2 for "-" */
+ argv[0] = (char*)m_malloc(len);
+ snprintf(argv[0], len, "-%s", baseshell);
+ }
+
+ if (cmd != NULL) {
+ argv[1] = "-c";
+ argv[2] = (char*)cmd;
+ argv[3] = NULL;
+ } else {
+ /* construct a shell of the form "-bash" etc */
+ argv[1] = NULL;
+ }
+
+ /* Re-enable SIGPIPE for the executed process */
+ if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {
+ dropbear_exit("signal() error");
+ }
+
+ /* close file descriptors except stdin/stdout/stderr
+ * Need to be sure FDs are closed here to avoid reading files as root */
+ for (i = 3; i <= maxfd; i++) {
+ m_close(i);
+ }
+
+ execv(usershell, argv);
+}
+
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
@@ -699,3 +835,17 @@ void disallow_core() {
lim.rlim_cur = lim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &lim);
}
+
+/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
+int m_str_to_uint(const char* str, unsigned int *val) {
+ errno = 0;
+ *val = strtoul(str, NULL, 10);
+ /* The c99 spec doesn't actually seem to define EINVAL, but most platforms
+ * I've looked at mention it in their manpage */
+ if ((*val == 0 && errno == EINVAL)
+ || (*val == ULONG_MAX && errno == ERANGE)) {
+ return DROPBEAR_FAILURE;
+ } else {
+ return DROPBEAR_SUCCESS;
+ }
+}
diff --git a/dbutil.h b/dbutil.h
index 856978d..706f35e 100644
--- a/dbutil.h
+++ b/dbutil.h
@@ -49,6 +49,9 @@ char * stripcontrol(const char * text);
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
+int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
+ int *writefd, int *readfd, int *errfd, pid_t *pid);
+void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
char* getaddrhostname(struct sockaddr_storage * addr);
@@ -64,6 +67,7 @@ void __m_free(void* ptr);
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
void disallow_core();
+int m_str_to_uint(const char* str, unsigned int *val);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
diff --git a/debug.h b/debug.h
index b8c2a57..a9cc0bd 100644
--- a/debug.h
+++ b/debug.h
@@ -39,7 +39,7 @@
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
-/*#define DEBUG_TRACE*/
+#define DEBUG_TRACE
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
diff --git a/genrsa.c b/genrsa.c
index 73a7984..7e5ecd5 100644
--- a/genrsa.c
+++ b/genrsa.c
@@ -62,17 +62,13 @@ rsa_key * gen_rsa_priv_key(unsigned int size) {
exit(1);
}
- /* PuTTY doesn't like it if the modulus isn't a multiple of 8 bits,
- * so we just generate them until we get one which is OK */
getrsaprime(key->p, &pminus, key->e, size/2);
- do {
- getrsaprime(key->q, &qminus, key->e, size/2);
+ getrsaprime(key->q, &qminus, key->e, size/2);
- if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
- fprintf(stderr, "rsa generation failed\n");
- exit(1);
- }
- } while (mp_count_bits(key->n) % 8 != 0);
+ if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
+ fprintf(stderr, "rsa generation failed\n");
+ exit(1);
+ }
/* lcm(p-1, q-1) */
if (mp_lcm(&pminus, &qminus, &lcm) != MP_OKAY) {
diff --git a/keyimport.c b/keyimport.c
index 1d3e3f5..76b92f1 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -701,7 +701,6 @@ static int openssh_write(const char *filename, sign_key *key,
int nnumbers = -1, pos, len, seqlen, i;
char *header = NULL, *footer = NULL;
char zero[1];
- unsigned char iv[8];
int ret = 0;
FILE *fp;
int keytype = -1;
diff --git a/options.h b/options.h
index 7b74829..e703450 100644
--- a/options.h
+++ b/options.h
@@ -60,12 +60,20 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define ENABLE_CLI_LOCALTCPFWD
#define ENABLE_CLI_REMOTETCPFWD
+/* Allow using -J <proxycommand> to run the connection through a
+ pipe to a program, rather the normal TCP connection */
+#define ENABLE_CLI_PROXYCMD
+
#define ENABLE_SVR_LOCALTCPFWD
#define ENABLE_SVR_REMOTETCPFWD
/* Enable Authentication Agent Forwarding - server only for now */
#define ENABLE_AGENTFWD
+/* Enable "Netcat mode". TODO describe here. */
+#define ENABLE_CLI_NETCAT
+
+
/* Encryption - at least one required.
* RFC Draft requires 3DES and recommends AES128 for interoperability.
* Including multiple keysize variants the same cipher
@@ -132,8 +140,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* but there's an interface via a PAM module - don't bother using it otherwise.
* You can't enable both PASSWORD and PAM. */
-#define ENABLE_SVR_PASSWORD_AUTH
-/*#define ENABLE_SVR_PAM_AUTH */ /* requires ./configure --enable-pam */
+//#define ENABLE_SVR_PASSWORD_AUTH
+#define ENABLE_SVR_PAM_AUTH /* requires ./configure --enable-pam */
#define ENABLE_SVR_PUBKEY_AUTH
/* Wether to ake public key options in authorized_keys file into account */
@@ -404,6 +412,10 @@ be overridden at runtime with -K. 0 disables keepalives */
#define USING_LISTENERS
#endif
+#if defined(ENABLE_CLI_NETCAT) && defined(ENABLE_CLI_PROXYCMD)
+#define ENABLE_CLI_MULTIHOP
+#endif
+
#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH)
#define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
#endif
diff --git a/packet.c b/packet.c
index c559dab..30f4758 100644
--- a/packet.c
+++ b/packet.c
@@ -61,7 +61,7 @@ void write_packet() {
len = writebuf->len - writebuf->pos;
dropbear_assert(len > 0);
/* Try to write as much as possible */
- written = write(ses.sock, buf_getptr(writebuf, len), len);
+ written = write(ses.sock_out, buf_getptr(writebuf, len), len);
if (written < 0) {
if (errno == EINTR) {
@@ -122,7 +122,7 @@ void read_packet() {
* mightn't be any available (EAGAIN) */
dropbear_assert(ses.readbuf != NULL);
maxlen = ses.readbuf->len - ses.readbuf->pos;
- len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen);
+ len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
if (len == 0) {
ses.remoteclosed();
@@ -171,7 +171,7 @@ static void read_packet_init() {
maxlen = blocksize - ses.readbuf->pos;
/* read the rest of the packet if possible */
- len = read(ses.sock, buf_getwriteptr(ses.readbuf, maxlen),
+ len = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
maxlen);
if (len == 0) {
ses.remoteclosed();
diff --git a/runopts.h b/runopts.h
index d6e8917..e9d2363 100644
--- a/runopts.h
+++ b/runopts.h
@@ -37,7 +37,7 @@ typedef struct runopts {
int listen_fwd_all;
#endif
unsigned int recv_window;
- time_t keepalive_secs;
+ unsigned int keepalive_secs;
} runopts;
@@ -101,6 +101,7 @@ typedef struct cli_runopts {
char *remotehost;
char *remoteport;
+ char *own_user;
char *username;
char *cmd;
@@ -118,6 +119,14 @@ typedef struct cli_runopts {
struct TCPFwdList * localfwds;
#endif
+#ifdef ENABLE_CLI_NETCAT
+ char *netcat_host;
+ unsigned int netcat_port;
+#endif
+#ifdef ENABLE_CLI_PROXYCMD
+ char *proxycmd;
+#endif
+
} cli_runopts;
extern cli_runopts cli_opts;
diff --git a/session.h b/session.h
index e11c959..b63a258 100644
--- a/session.h
+++ b/session.h
@@ -41,12 +41,14 @@
extern int sessinitdone; /* Is set to 0 somewhere */
extern int exitflag;
-void common_session_init(int sock, char* remotehost);
+void common_session_init(int sock_in, int sock_out, char* remotehost);
void session_loop(void(*loophandler)());
void common_session_cleanup();
void session_identification();
void send_msg_ignore();
+const char* get_user_shell();
+void fill_passwd(const char* username);
/* Server */
void svr_session(int sock, int childpipe, char *remotehost, char *addrstring);
@@ -54,7 +56,7 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param);
void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
-void cli_session(int sock, char *remotehost);
+void cli_session(int sock_in, int sock_out, char *remotehost);
void cli_session_cleanup();
void cleantext(unsigned char* dirtytext);
@@ -97,7 +99,8 @@ struct sshsession {
(cleared after auth once we're not
respecting AUTH_TIMEOUT any more) */
- int sock;
+ int sock_in;
+ int sock_out;
unsigned char *remotehost; /* the peer hostname */
diff --git a/svr-auth.c b/svr-auth.c
index 88909f3..4adf809 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -203,29 +203,6 @@ out:
m_free(methodname);
}
-static void fill_passwd(const char* username) {
- struct passwd *pw = NULL;
- if (ses.authstate.pw_name)
- m_free(ses.authstate.pw_name);
- if (ses.authstate.pw_dir)
- m_free(ses.authstate.pw_dir);
- if (ses.authstate.pw_shell)
- m_free(ses.authstate.pw_shell);
- if (ses.authstate.pw_passwd)
- m_free(ses.authstate.pw_passwd);
-
- pw = getpwnam(username);
- if (!pw) {
- return;
- }
- ses.authstate.pw_uid = pw->pw_uid;
- ses.authstate.pw_gid = pw->pw_gid;
- ses.authstate.pw_name = m_strdup(pw->pw_name);
- ses.authstate.pw_dir = m_strdup(pw->pw_dir);
- ses.authstate.pw_shell = m_strdup(pw->pw_shell);
- ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
-}
-
/* Check that the username exists, has a non-empty password, and has a valid
* shell.
diff --git a/svr-chansession.c b/svr-chansession.c
index 66cbabb..9b2a412 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -48,7 +48,7 @@ static int sessionsignal(struct ChanSess *chansess);
static int noptycommand(struct Channel *channel, struct ChanSess *chansess);
static int ptycommand(struct Channel *channel, struct ChanSess *chansess);
static int sessionwinchange(struct ChanSess *chansess);
-static void execchild(struct ChanSess *chansess);
+static void execchild(void *user_data_chansess);
static void addchildpid(struct ChanSess *chansess, pid_t pid);
static void sesssigchild_handler(int val);
static void closechansess(struct Channel *channel);
@@ -645,100 +645,37 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
* pty.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
-
- int infds[2];
- int outfds[2];
- int errfds[2];
- pid_t pid;
- unsigned int i;
+ int ret;
TRACE(("enter noptycommand"))
+ ret = spawn_command(execchild, chansess,
+ &channel->writefd, &channel->readfd, &channel->errfd,
+ &chansess->pid);
- /* redirect stdin/stdout/stderr */
- if (pipe(infds) != 0)
- return DROPBEAR_FAILURE;
- if (pipe(outfds) != 0)
- return DROPBEAR_FAILURE;
- if (pipe(errfds) != 0)
- return DROPBEAR_FAILURE;
-
-#ifdef __uClinux__
- pid = vfork();
-#else
- pid = fork();
-#endif
-
- if (pid < 0)
- return DROPBEAR_FAILURE;
-
- if (!pid) {
- /* child */
-
- TRACE(("back to normal sigchld"))
- /* Revert to normal sigchld handling */
- if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
- dropbear_exit("signal() error");
- }
-
- /* redirect stdin/stdout */
-#define FDIN 0
-#define FDOUT 1
- if ((dup2(infds[FDIN], STDIN_FILENO) < 0) ||
- (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
- (dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
- TRACE(("leave noptycommand: error redirecting FDs"))
- return DROPBEAR_FAILURE;
- }
-
- close(infds[FDOUT]);
- close(infds[FDIN]);
- close(outfds[FDIN]);
- close(outfds[FDOUT]);
- close(errfds[FDIN]);
- close(errfds[FDOUT]);
-
- execchild(chansess);
- /* not reached */
+ if (ret == DROPBEAR_FAILURE) {
+ return ret;
+ }
- } else {
- /* parent */
- TRACE(("continue noptycommand: parent"))
- chansess->pid = pid;
- TRACE(("child pid is %d", pid))
+ ses.maxfd = MAX(ses.maxfd, channel->writefd);
+ ses.maxfd = MAX(ses.maxfd, channel->readfd);
+ ses.maxfd = MAX(ses.maxfd, channel->errfd);
- addchildpid(chansess, pid);
+ addchildpid(chansess, chansess->pid);
- if (svr_ses.lastexit.exitpid != -1) {
- TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid))
- /* The child probably exited and the signal handler triggered
- * possibly before we got around to adding the childpid. So we fill
- * out its data manually */
- for (i = 0; i < svr_ses.childpidsize; i++) {
- if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) {
- TRACE(("found match for lastexitpid"))
- svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
- svr_ses.lastexit.exitpid = -1;
- }
+ if (svr_ses.lastexit.exitpid != -1) {
+ TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid))
+ /* The child probably exited and the signal handler triggered
+ * possibly before we got around to adding the childpid. So we fill
+ * out its data manually */
+ int i;
+ for (i = 0; i < svr_ses.childpidsize; i++) {
+ if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) {
+ TRACE(("found match for lastexitpid"))
+ svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
+ svr_ses.lastexit.exitpid = -1;
}
}
-
- close(infds[FDIN]);
- close(outfds[FDOUT]);
- close(errfds[FDOUT]);
- channel->writefd = infds[FDOUT];
- channel->readfd = outfds[FDIN];
- channel->errfd = errfds[FDIN];
- ses.maxfd = MAX(ses.maxfd, channel->writefd);
- ses.maxfd = MAX(ses.maxfd, channel->readfd);
- ses.maxfd = MAX(ses.maxfd, channel->errfd);
-
- setnonblocking(channel->readfd);
- setnonblocking(channel->writefd);
- setnonblocking(channel->errfd);
-
}
-#undef FDIN
-#undef FDOUT
TRACE(("leave noptycommand"))
return DROPBEAR_SUCCESS;
@@ -883,12 +820,9 @@ static void addchildpid(struct ChanSess *chansess, pid_t pid) {
/* Clean up, drop to user privileges, set up the environment and execute
* the command/shell. This function does not return. */
-static void execchild(struct ChanSess *chansess) {
-
- char *argv[4];
- char * usershell = NULL;
- char * baseshell = NULL;
- unsigned int i;
+static void execchild(void *user_data) {
+ struct ChanSess *chansess = user_data;
+ char *usershell = NULL;
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
* hostkey. can't think of a workaround to clear it */
@@ -901,12 +835,6 @@ static void execchild(struct ChanSess *chansess) {
reseedrandom();
#endif
- /* close file descriptors except stdin/stdout/stderr
- * Need to be sure FDs are closed here to avoid reading files as root */
- for (i = 3; i <= (unsigned int)ses.maxfd; i++) {
- m_close(i);
- }
-
/* clear environment */
/* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD
* etc. This is hazardous, so should only be used for debugging. */
@@ -945,18 +873,11 @@ static void execchild(struct ChanSess *chansess) {
}
}
- /* an empty shell should be interpreted as "/bin/sh" */
- if (ses.authstate.pw_shell[0] == '\0') {
- usershell = "/bin/sh";
- } else {
- usershell = ses.authstate.pw_shell;
- }
-
/* set env vars */
addnewvar("USER", ses.authstate.pw_name);
addnewvar("LOGNAME", ses.authstate.pw_name);
addnewvar("HOME", ses.authstate.pw_dir);
- addnewvar("SHELL", usershell);
+ addnewvar("SHELL", get_user_shell());
if (chansess->term != NULL) {
addnewvar("TERM", chansess->term);
}
@@ -975,32 +896,8 @@ static void execchild(struct ChanSess *chansess) {
agentset(chansess);
#endif
- /* Re-enable SIGPIPE for the executed process */
- if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {
- dropbear_exit("signal() error");
- }
-
- baseshell = basename(usershell);
-
- if (chansess->cmd != NULL) {
- argv[0] = baseshell;
- } else {
- /* a login shell should be "-bash" for "/bin/bash" etc */
- int len = strlen(baseshell) + 2; /* 2 for "-" */
- argv[0] = (char*)m_malloc(len);
- snprintf(argv[0], len, "-%s", baseshell);
- }
-
- if (chansess->cmd != NULL) {
- argv[1] = "-c";
- argv[2] = chansess->cmd;
- argv[3] = NULL;
- } else {
- /* construct a shell of the form "-bash" etc */
- argv[1] = NULL;
- }
-
- execv(usershell, argv);
+ usershell = m_strdup(get_user_shell());
+ run_shell_command(chansess->cmd, ses.maxfd, usershell);
/* only reached on error */
dropbear_exit("child failed");
diff --git a/svr-runopts.c b/svr-runopts.c
index 83c75c3..c8b6585 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -284,16 +284,13 @@ void svr_getopts(int argc, char ** argv) {
if (recv_window_arg) {
opts.recv_window = atol(recv_window_arg);
- if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW)
- {
+ if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
dropbear_exit("Bad recv window '%s'", recv_window_arg);
}
}
if (keepalive_arg) {
- opts.keepalive_secs = strtoul(keepalive_arg, NULL, 10);
- if (opts.keepalive_secs == 0 && errno == EINVAL)
- {
+ if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
}
diff --git a/svr-session.c b/svr-session.c
index 21d366e..eaccfe5 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -80,7 +80,7 @@ void svr_session(int sock, int childpipe,
reseedrandom();
crypto_init();
- common_session_init(sock, remotehost);
+ common_session_init(sock, sock, remotehost);
/* Initialise server specific parts of the session */
svr_ses.childpipe = childpipe;
@@ -186,7 +186,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param) {
localtime(&timesec)) == 0)
{
/* upon failure, just print the epoch-seconds time. */
- snprintf(datestr, sizeof(datestr), "%d", timesec);
+ snprintf(datestr, sizeof(datestr), "%d", (int)timesec);
}
fprintf(stderr, "[%d] %s %s\n", getpid(), datestr, printbuf);
}
@@ -195,8 +195,10 @@ void svr_dropbear_log(int priority, const char* format, va_list param) {
/* called when the remote side closes the connection */
static void svr_remoteclosed() {
- close(ses.sock);
- ses.sock = -1;
+ m_close(ses.sock_in);
+ m_close(ses.sock_out);
+ ses.sock_in = -1;
+ ses.sock_out = -1;
dropbear_close("Exited normally");
}