-/* $OpenBSD: ssh.c,v 1.315 2008/06/12 04:06:00 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.326 2009/07/02 02:11:47 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>
extern char *__progname;
-/* Flag indicating whether debug mode is on. This can be set on the command line. */
+/* Flag indicating whether debug mode is on. May be set on the command line. */
int debug_flag = 0;
/* Flag indicating whether a tty should be allocated */
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"
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;
*/
umask(022);
- /* Initialize option structure to indicate that no values have been set. */
+ /*
+ * Initialize option structure to indicate that no values have been
+ * set.
+ */
initialize_options(&options);
/* 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:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
+ while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
+ "ACD:F:I:KL:MNO:PR:S:TVw: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;
options.tun_open = SSH_TUNMODE_DEFAULT;
options.tun_local = a2tun(optarg, &options.tun_remote);
if (options.tun_local == SSH_TUNID_ERR) {
- fprintf(stderr, "Bad tun device '%s'\n", optarg);
+ fprintf(stderr,
+ "Bad tun device '%s'\n", optarg);
exit(255);
}
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':
}
/* Cannot fork to background if no command. */
- if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag)
- fatal("Cannot fork into background without a command to execute.");
+ if (fork_after_authentication_flag && buffer_len(&command) == 0 &&
+ !no_shell_flag)
+ fatal("Cannot fork into background without a command "
+ "to execute.");
/* Allocate a tty by default if no command specified. */
if (buffer_len(&command) == 0)
/* Do not allocate a tty if stdin is not a tty. */
if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
if (tty_flag)
- logit("Pseudo-terminal will not be allocated because stdin is not a terminal.");
+ logit("Pseudo-terminal will not be allocated because "
+ "stdin is not a terminal.");
tty_flag = 0;
}
* Initialize "log" output. Since we are the client all output
* actually goes to stderr.
*/
- log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
- SYSLOG_FACILITY_USER, 1);
+ log_init(argv0,
+ options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
+ 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();
if (options.user == NULL)
options.user = xstrdup(pw->pw_name);
+ /* Get default port if port has not been set. */
+ if (options.port == 0) {
+ sp = getservbyname(SSH_SERVICE_NAME, "tcp");
+ options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
+ }
+
+ if (options.local_command != NULL) {
+ char thishost[NI_MAXHOST];
+
+ if (gethostname(thishost, sizeof(thishost)) == -1)
+ fatal("gethostname: %s", strerror(errno));
+ snprintf(buf, sizeof(buf), "%d", options.port);
+ debug3("expanding LocalCommand: %s", options.local_command);
+ cp = options.local_command;
+ options.local_command = percent_expand(cp, "d", pw->pw_dir,
+ "h", options.hostname? options.hostname : host,
+ "l", thishost, "n", host, "r", options.user, "p", buf,
+ "u", pw->pw_name, (char *)NULL);
+ debug3("expanded LocalCommand: %s", options.local_command);
+ xfree(cp);
+ }
+
if (options.hostname != NULL)
host = options.hostname;
*p = (char)tolower(*p);
}
- /* Get default port if port has not been set. */
- if (options.port == 0) {
- sp = getservbyname(SSH_SERVICE_NAME, "tcp");
- options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
- }
-
if (options.proxy_command != NULL &&
strcmp(options.proxy_command, "none") == 0) {
xfree(options.proxy_command);
* 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, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
- if (stat(buf, &st) < 0)
+ r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir,
+ strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
+ if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0)
if (mkdir(buf, 0700) < 0)
error("Could not create directory '%.200s'.", buf);
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
- /* Log into the remote system. This never returns if the login fails. */
+ /* Log into the remote system. Never returns if the login fails. */
ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
pw, timeout_ms);
{
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 "
logit("Warning: remote port forwarding failed for "
"listen port %d", rfwd->listen_port);
}
- if (++remote_forward_confirms_received == options.num_remote_forwards)
+ if (++remote_forward_confirms_received == options.num_remote_forwards) {
debug("All remote forwarding requests processed");
- /* XXX fork-after-authentication */
+ if (fork_after_authentication_flag) {
+ fork_after_authentication_flag = 0;
+ if (daemon(1, 1) < 0)
+ fatal("daemon() failed: %.200s",
+ strerror(errno));
+ }
+ }
}
static void
/* Enable compression if requested. */
if (options.compression) {
- debug("Requesting compression at level %d.", options.compression_level);
+ debug("Requesting compression at level %d.",
+ options.compression_level);
- if (options.compression_level < 1 || options.compression_level > 9)
- fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
+ if (options.compression_level < 1 ||
+ options.compression_level > 9)
+ fatal("Compression level must be from 1 (fast) to "
+ "9 (slow, best).");
/* Send the request. */
packet_start(SSH_CMSG_REQUEST_COMPRESSION);
else if (type == SSH_SMSG_FAILURE)
logit("Warning: Remote host refused compression.");
else
- packet_disconnect("Protocol error waiting for compression response.");
+ packet_disconnect("Protocol error waiting for "
+ "compression response.");
}
/* Allocate a pseudo tty if appropriate. */
if (tty_flag) {
interactive = 1;
have_tty = 1;
} else if (type == SSH_SMSG_FAILURE)
- logit("Warning: Remote host failed or refused to allocate a pseudo tty.");
+ logit("Warning: Remote host failed or refused to "
+ "allocate a pseudo tty.");
else
- packet_disconnect("Protocol error waiting for pty request response.");
+ packet_disconnect("Protocol error waiting for pty "
+ "request response.");
}
/* Request X11 forwarding if enabled and DISPLAY is set. */
display = getenv("DISPLAY");
client_x11_get_proto(display, options.xauth_location,
options.forward_x11_trusted, &proto, &data);
/* Request forwarding with authentication spoofing. */
- debug("Requesting X11 forwarding with authentication spoofing.");
+ debug("Requesting X11 forwarding with authentication "
+ "spoofing.");
x11_request_forwarding_with_spoofing(0, display, proto, data);
/* Read response from the server. */
} else if (type == SSH_SMSG_FAILURE) {
logit("Warning: Remote host denied X11 forwarding.");
} else {
- packet_disconnect("Protocol error waiting for X11 forwarding");
+ packet_disconnect("Protocol error waiting for X11 "
+ "forwarding");
}
}
/* Tell the packet module whether this is an interactive session. */
options.permit_local_command)
ssh_local_cmd(options.local_command);
- /* If requested, let ssh continue in the background. */
- if (fork_after_authentication_flag)
+ /*
+ * If requested and we are not interested in replies to remote
+ * forwarding requests, then let ssh continue in the background.
+ */
+ if (fork_after_authentication_flag &&
+ (!options.exit_on_forward_failure ||
+ options.num_remote_forwards == 0)) {
+ fork_after_authentication_flag = 0;
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
+ }
/*
* If a command was specified on the command line, execute the
int len = buffer_len(&command);
if (len > 900)
len = 900;
- debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
+ debug("Sending command: %.*s", len,
+ (u_char *)buffer_ptr(&command));
packet_start(SSH_CMSG_EXEC_CMD);
packet_put_string(buffer_ptr(&command), buffer_len(&command));
packet_send();
client_x11_get_proto(display, options.xauth_location,
options.forward_x11_trusted, &proto, &data);
/* Request forwarding with authentication spoofing. */
- debug("Requesting X11 forwarding with authentication spoofing.");
+ debug("Requesting X11 forwarding with authentication "
+ "spoofing.");
x11_request_forwarding_with_spoofing(id, display, proto, data);
interactive = 1;
/* XXX wait for reply */
id = ssh_session2_open();
/* If we don't expect to open a new session, then disallow it */
- if (options.control_master == SSHCTL_MASTER_NO) {
+ if (options.control_master == SSHCTL_MASTER_NO &&
+ (datafellows & SSH_NEW_OPENSSH)) {
debug("Requesting no-more-sessions@openssh.com");
packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring("no-more-sessions@openssh.com");
muxserver_listen();
/* If requested, let ssh continue in the background. */
- if (fork_after_authentication_flag)
+ if (fork_after_authentication_flag) {
+ fork_after_authentication_flag = 0;
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
+ }
return client_loop(tty_flag, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, id);
int count = 0;
for (i = 0; keys[i] != NULL; i++) {
count++;
- memmove(&options.identity_files[1], &options.identity_files[0],
+ memmove(&options.identity_files[1],
+ &options.identity_files[0],
sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
- memmove(&options.identity_keys[1], &options.identity_keys[0],
+ memmove(&options.identity_keys[1],
+ &options.identity_keys[0],
sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
options.num_identity_files++;
options.identity_keys[0] = keys[i];