-/* $OpenBSD: ssh.c,v 1.319 2008/09/11 14:22:37 markus Exp $ */
+/* $OpenBSD: ssh.c,v 1.331 2010/01/11 01:39:46 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
#endif
#include <sys/resource.h>
#include <sys/ioctl.h>
+#include <sys/param.h>
#include <sys/socket.h>
#include <ctype.h>
#include "match.h"
#include "msg.h"
#include "uidswap.h"
+#include "roaming.h"
#include "version.h"
#ifdef SMARTCARD
*/
int fork_after_authentication_flag = 0;
+/* forward stdio to remote host and port */
+char *stdio_forward_host = NULL;
+int stdio_forward_port = 0;
+
/*
* General data structure for command line options and options configurable
* in configuration files. See readconf.h.
usage(void)
{
fprintf(stderr,
-"usage: ssh [-1246AaCfgKkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
+"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n"
" [-D [bind_address:]port] [-e escape_char] [-F configfile]\n"
" [-i identity_file] [-L [bind_address:]port:host:hostport]\n"
" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
" [-R [bind_address:]port:host:hostport] [-S ctl_path]\n"
-" [-w local_tun[:remote_tun]] [user@]hostname [command]\n"
+" [-W host:port] [-w local_tun[:remote_tun]]\n"
+" [user@]hostname [command]\n"
);
exit(255);
}
int
main(int ac, char **av)
{
- int i, opt, exit_status;
- char *p, *cp, *line, buf[256];
+ int i, r, opt, exit_status, use_syslog;
+ char *p, *cp, *line, *argv0, buf[MAXPATHLEN];
struct stat st;
struct passwd *pw;
int dummy, timeout_ms;
/* Parse command-line arguments. */
host = NULL;
+ use_syslog = 0;
+ argv0 = av[0];
again:
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
- "ACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
+ "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
case 'X':
options.forward_x11 = 1;
break;
+ case 'y':
+ use_syslog = 1;
+ break;
case 'Y':
options.forward_x11 = 1;
options.forward_x11_trusted = 1;
exit(255);
}
break;
+ case 'W':
+ if (parse_forward(&fwd, optarg, 1, 0)) {
+ stdio_forward_host = fwd.listen_host;
+ stdio_forward_port = fwd.listen_port;
+ xfree(fwd.connect_host);
+ } else {
+ fprintf(stderr,
+ "Bad stdio forwarding specification '%s'\n",
+ optarg);
+ exit(255);
+ }
+ no_tty_flag = 1;
+ no_shell_flag = 1;
+ options.clear_forwardings = 1;
+ options.exit_on_forward_failure = 1;
+ break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
break;
break;
case 'p':
options.port = a2port(optarg);
- if (options.port == 0) {
+ if (options.port <= 0) {
fprintf(stderr, "Bad port '%s'\n", optarg);
exit(255);
}
break;
case 'L':
- if (parse_forward(&fwd, optarg))
+ if (parse_forward(&fwd, optarg, 0, 0))
add_local_forward(&options, &fwd);
else {
fprintf(stderr,
break;
case 'R':
- if (parse_forward(&fwd, optarg)) {
+ if (parse_forward(&fwd, optarg, 0, 1)) {
add_remote_forward(&options, &fwd);
} else {
fprintf(stderr,
break;
case 'D':
- cp = p = xstrdup(optarg);
- memset(&fwd, '\0', sizeof(fwd));
- fwd.connect_host = "socks";
- if ((fwd.listen_host = hpdelim(&cp)) == NULL) {
- fprintf(stderr, "Bad dynamic forwarding "
- "specification '%.100s'\n", optarg);
- exit(255);
- }
- if (cp != NULL) {
- fwd.listen_port = a2port(cp);
- fwd.listen_host =
- cleanhostname(fwd.listen_host);
+ if (parse_forward(&fwd, optarg, 1, 0)) {
+ add_local_forward(&options, &fwd);
} else {
- fwd.listen_port = a2port(fwd.listen_host);
- fwd.listen_host = NULL;
- }
-
- if (fwd.listen_port == 0) {
- fprintf(stderr, "Bad dynamic port '%s'\n",
- optarg);
+ fprintf(stderr,
+ "Bad dynamic forwarding specification "
+ "'%s'\n", optarg);
exit(255);
}
- add_local_forward(&options, &fwd);
- xfree(p);
break;
case 'C':
ac -= optind;
av += optind;
- if (ac > 0 && !host && **av != '-') {
+ if (ac > 0 && !host) {
if (strrchr(*av, '@')) {
p = xstrdup(*av);
cp = strrchr(p, '@');
* Initialize "log" output. Since we are the client all output
* actually goes to stderr.
*/
- log_init(av[0],
+ log_init(argv0,
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
- SYSLOG_FACILITY_USER, 1);
+ SYSLOG_FACILITY_USER, !use_syslog);
/*
* Read per-user configuration file. Ignore the system wide config
fatal("Can't open user config file %.100s: "
"%.100s", config, strerror(errno));
} else {
- snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
+ r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
_PATH_SSH_USER_CONFFILE);
- (void)read_config_file(buf, host, &options, 1);
+ if (r > 0 && (size_t)r < sizeof(buf))
+ (void)read_config_file(buf, host, &options, 1);
/* Read systemwide configuration file after use config. */
(void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
channel_set_af(options.address_family);
/* reinit */
- log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
+ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
seed_rng();
* Now that we are back to our own permissions, create ~/.ssh
* directory if it doesn't already exist.
*/
- snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir,
+ r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir,
strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
- if (stat(buf, &st) < 0)
+ if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0)
if (mkdir(buf, 0700) < 0)
error("Could not create directory '%.200s'.", buf);
{
Forward *rfwd = (Forward *)ctxt;
+ /* XXX verbose() on failure? */
debug("remote forward %s for: listen %d, connect %s:%d",
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+ if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) {
+ logit("Allocated port %u for remote forward to %s:%d",
+ packet_get_int(),
+ rfwd->connect_host, rfwd->connect_port);
+ }
+
if (type == SSH2_MSG_REQUEST_FAILURE) {
if (options.exit_on_forward_failure)
fatal("Error: remote port forwarding failed for "
}
}
+static void
+client_cleanup_stdio_fwd(int id, void *arg)
+{
+ debug("stdio forwarding: done");
+ cleanup_exit(0);
+}
+
+static int
+client_setup_stdio_fwd(const char *host_to_connect, u_short port_to_connect)
+{
+ Channel *c;
+
+ debug3("client_setup_stdio_fwd %s:%d", host_to_connect,
+ port_to_connect);
+ if ((c = channel_connect_stdio_fwd(host_to_connect, port_to_connect))
+ == NULL)
+ return 0;
+ channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
+ return 1;
+}
+
static void
ssh_init_forwarding(void)
{
int success = 0;
int i;
+ if (stdio_forward_host != NULL) {
+ if (!compat20) {
+ fatal("stdio forwarding require Protocol 2");
+ }
+ if (!client_setup_stdio_fwd(stdio_forward_host,
+ stdio_forward_port))
+ fatal("Failed to connect in stdio forward mode.");
+ }
+
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
debug("Local connections to %.200s:%d forwarded to remote "
fatal("daemon() failed: %.200s", strerror(errno));
}
+ if (options.use_roaming)
+ request_roaming();
+
return client_loop(tty_flag, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, id);
}