+/* $OpenBSD: ssh.c,v 1.276 2006/04/25 08:02:27 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.247 2005/07/04 00:58:43 djm Exp $");
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+
+#include <ctype.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <signal.h>
#include <openssl/evp.h>
#include <openssl/err.h>
{
fprintf(stderr,
"usage: ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
-" [-D port] [-e escape_char] [-F configfile]\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"
-" [user@]hostname [command]\n"
+" [-w tunnel:tunnel] [user@]hostname [command]\n"
);
- exit(1);
+ exit(255);
}
static int ssh_session(void);
struct servent *sp;
Forward fwd;
+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+ sanitise_stdfd();
+
__progname = ssh_get_progname(av[0]);
init_rng();
pw = getpwuid(original_real_uid);
if (!pw) {
logit("You don't exist, go away!");
- exit(1);
+ exit(255);
}
/* Take a copy of the returned structure. */
pw = pwcopy(pw);
/* Parse command-line arguments. */
host = NULL;
-again:
+ again:
while ((opt = getopt(ac, av,
- "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNO:PR:S:TVXY")) != -1) {
+ "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNO:PR:S:TVw:XY")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
if (opt == 'V')
exit(0);
break;
+ case 'w':
+ if (options.tun_open == -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);
+ exit(255);
+ }
+ break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
break;
else {
fprintf(stderr, "Bad escape character '%s'.\n",
optarg);
- exit(1);
+ exit(255);
}
break;
case 'c':
fprintf(stderr,
"Unknown cipher type '%s'\n",
optarg);
- exit(1);
+ exit(255);
}
if (options.cipher == SSH_CIPHER_3DES)
options.ciphers = "3des-cbc";
else {
fprintf(stderr, "Unknown mac type '%s'\n",
optarg);
- exit(1);
+ exit(255);
}
break;
case 'M':
options.port = a2port(optarg);
if (options.port == 0) {
fprintf(stderr, "Bad port '%s'\n", optarg);
- exit(1);
+ exit(255);
}
break;
case 'l':
fprintf(stderr,
"Bad local forwarding specification '%s'\n",
optarg);
- exit(1);
+ exit(255);
}
break;
fprintf(stderr,
"Bad remote forwarding specification "
"'%s'\n", optarg);
- exit(1);
+ exit(255);
}
break;
if ((fwd.listen_host = hpdelim(&cp)) == NULL) {
fprintf(stderr, "Bad dynamic forwarding "
"specification '%.100s'\n", optarg);
- exit(1);
+ exit(255);
}
if (cp != NULL) {
fwd.listen_port = a2port(cp);
fwd.listen_host = cleanhostname(fwd.listen_host);
} else {
fwd.listen_port = a2port(fwd.listen_host);
- fwd.listen_host = "";
+ fwd.listen_host = NULL;
}
if (fwd.listen_port == 0) {
fprintf(stderr, "Bad dynamic port '%s'\n",
optarg);
- exit(1);
+ exit(255);
}
add_local_forward(&options, &fwd);
xfree(p);
line = xstrdup(optarg);
if (process_config_line(&options, host ? host : "",
line, "command-line", 0, &dummy) != 0)
- exit(1);
+ exit(255);
xfree(line);
break;
case 's':
if (options.host_key_alias != NULL) {
for (p = options.host_key_alias; *p; p++)
if (isupper(*p))
- *p = tolower(*p);
+ *p = (char)tolower(*p);
}
/* Get default port if port has not been set. */
options.control_path = NULL;
if (options.control_path != NULL) {
+ char thishost[NI_MAXHOST];
+
+ if (gethostname(thishost, sizeof(thishost)) == -1)
+ fatal("gethostname: %s", strerror(errno));
snprintf(buf, sizeof(buf), "%d", options.port);
cp = tilde_expand_filename(options.control_path,
original_real_uid);
options.control_path = percent_expand(cp, "p", buf, "h", host,
- "r", options.user, (char *)NULL);
+ "r", options.user, "l", thishost, (char *)NULL);
xfree(cp);
}
if (mux_command != 0 && options.control_path == NULL)
original_effective_uid == 0 && options.use_privileged_port,
#endif
options.proxy_command) != 0)
- exit(1);
+ exit(255);
/*
* If we successfully made the connection, load the host private key
if (options.rhosts_rsa_authentication ||
options.hostbased_authentication) {
sensitive_data.nkeys = 3;
- sensitive_data.keys = xmalloc(sensitive_data.nkeys *
+ sensitive_data.keys = xcalloc(sensitive_data.nkeys,
sizeof(Key));
PRIV_START;
sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
- _PATH_HOST_KEY_FILE, "", NULL);
+ _PATH_HOST_KEY_FILE, "", NULL, NULL);
sensitive_data.keys[1] = key_load_private_type(KEY_DSA,
- _PATH_HOST_DSA_KEY_FILE, "", NULL);
+ _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL);
sensitive_data.keys[2] = key_load_private_type(KEY_RSA,
- _PATH_HOST_RSA_KEY_FILE, "", NULL);
+ _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL);
PRIV_END;
if (options.hostbased_authentication == 1 &&
/*
* Now that we are back to our own permissions, create ~/.ssh
- * directory if it doesn\'t already exist.
+ * 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)
for (i = 0; i < options.num_remote_forwards; i++) {
debug("Remote connections from %.200s:%d forwarded to "
"local address %.200s:%d",
- (options.remote_forwards[i].listen_host == NULL) ?
- (options.gateway_ports ? "*" : "LOCALHOST") :
- options.remote_forwards[i].listen_host,
+ (options.remote_forwards[i].listen_host == NULL) ?
+ "LOCALHOST" : options.remote_forwards[i].listen_host,
options.remote_forwards[i].listen_port,
options.remote_forwards[i].connect_host,
options.remote_forwards[i].connect_port);
check_agent_present(void)
{
if (options.forward_agent) {
- /* Clear agent forwarding if we don\'t have an agent. */
+ /* Clear agent forwarding if we don't have an agent. */
if (!ssh_agent_present())
options.forward_agent = 0;
}
/* Store window size in the packet. */
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
memset(&ws, 0, sizeof(ws));
- packet_put_int(ws.ws_row);
- packet_put_int(ws.ws_col);
- packet_put_int(ws.ws_xpixel);
- packet_put_int(ws.ws_ypixel);
+ packet_put_int((u_int)ws.ws_row);
+ packet_put_int((u_int)ws.ws_col);
+ packet_put_int((u_int)ws.ws_xpixel);
+ packet_put_int((u_int)ws.ws_ypixel);
/* Store tty modes in the packet. */
tty_make_modes(fileno(stdin), NULL);
fatal("ControlPath too long");
if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
- fatal("%s socket(): %s\n", __func__, strerror(errno));
+ fatal("%s socket(): %s", __func__, strerror(errno));
old_umask = umask(0177);
- if (bind(control_fd, (struct sockaddr*)&addr, addr_len) == -1) {
+ if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) {
control_fd = -1;
if (errno == EINVAL || errno == EADDRINUSE)
fatal("ControlSocket %s already exists",
options.control_path);
else
- fatal("%s bind(): %s\n", __func__, strerror(errno));
+ fatal("%s bind(): %s", __func__, strerror(errno));
}
umask(old_umask);
if (listen(control_fd, 64) == -1)
- fatal("%s listen(): %s\n", __func__, strerror(errno));
+ fatal("%s listen(): %s", __func__, strerror(errno));
set_nonblock(control_fd);
}
const char *display;
int interactive = tty_flag;
- display = getenv("DISPLAY");
+ display = getenv("DISPLAY");
if (options.forward_x11 && display != NULL) {
char *proto, *data;
/* Get reasonable local authentication information. */
packet_send();
}
+ if (options.tun_open != SSH_TUNMODE_NO) {
+ Channel *c;
+ int fd;
+
+ debug("Requesting tun.");
+ if ((fd = tun_open(options.tun_local,
+ options.tun_open)) >= 0) {
+ c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
+ CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+ 0, "tun", 1);
+ c->datagram = 1;
+#if defined(SSH_TUN_FILTER)
+ if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
+ channel_register_filter(c->self, sys_tun_infilter,
+ sys_tun_outfilter);
+#endif
+ packet_start(SSH2_MSG_CHANNEL_OPEN);
+ packet_put_cstring("tun@openssh.com");
+ packet_put_int(c->self);
+ packet_put_int(c->local_window_max);
+ packet_put_int(c->local_maxpacket);
+ packet_put_int(options.tun_open);
+ packet_put_int(options.tun_remote);
+ packet_send();
+ }
+ }
+
client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
id = ssh_session2_open();
+ /* Execute a local command */
+ if (options.local_command != NULL &&
+ options.permit_local_command)
+ ssh_local_cmd(options.local_command);
+
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
static void
load_public_identity_files(void)
{
- char *filename;
+ char *filename, *cp, thishost[NI_MAXHOST];
int i = 0;
Key *public;
+ struct passwd *pw;
#ifdef SMARTCARD
Key **keys;
xfree(keys);
}
#endif /* SMARTCARD */
+ if ((pw = getpwuid(original_real_uid)) == NULL)
+ fatal("load_public_identity_files: getpwuid failed");
+ if (gethostname(thishost, sizeof(thishost)) == -1)
+ fatal("load_public_identity_files: gethostname: %s",
+ strerror(errno));
for (; i < options.num_identity_files; i++) {
- filename = tilde_expand_filename(options.identity_files[i],
+ cp = tilde_expand_filename(options.identity_files[i],
original_real_uid);
+ filename = percent_expand(cp, "d", pw->pw_dir,
+ "u", pw->pw_name, "l", thishost, "h", host,
+ "r", options.user, (char *)NULL);
+ xfree(cp);
public = key_load_public(filename, NULL);
debug("identity file %s type %d", filename,
public ? public->type : -1);
int i;
char name[1024], *cp;
- strlcpy(name, env, sizeof(name));
+ if (strlcpy(name, env, sizeof(name)) >= sizeof(name))
+ fatal("env_permitted: name too long");
if ((cp = strchr(name, '=')) == NULL)
return (0);
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
fatal("%s socket(): %s", __func__, strerror(errno));
- if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) {
+ if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
if (mux_command != SSHMUX_COMMAND_OPEN) {
fatal("Control socket connect(%.100s): %s", path,
strerror(errno));
}
if (errno == ENOENT)
- debug("Control socket \"%.100s\" does not exist", path);
+ debug("Control socket \"%.100s\" does not exist", path);
else {
- error("Control socket connect(%.100s): %s", path,
+ error("Control socket connect(%.100s): %s", path,
strerror(errno));
}
- close(sock);
- return;
- }
-
- if (stdin_null_flag) {
- if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
- fatal("open(/dev/null): %s", strerror(errno));
- if (dup2(fd, STDIN_FILENO) == -1)
- fatal("dup2: %s", strerror(errno));
- if (fd > STDERR_FILENO)
- close(fd);
- }
-
+ close(sock);
+ return;
+ }
+
+ if (stdin_null_flag) {
+ if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
+ fatal("open(/dev/null): %s", strerror(errno));
+ if (dup2(fd, STDIN_FILENO) == -1)
+ fatal("dup2: %s", strerror(errno));
+ if (fd > STDERR_FILENO)
+ close(fd);
+ }
+
term = getenv("TERM");
flags = 0;