-/* $OpenBSD: ssh.c,v 1.318 2008/07/02 13:47:39 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.324 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
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;
+ int i, opt, exit_status, use_syslog;
char *p, *cp, *line, buf[256];
struct stat st;
struct passwd *pw;
/* Parse command-line arguments. */
host = NULL;
+ use_syslog = 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: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;
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':
no_shell_flag = 1;
no_tty_flag = 1;
break;
- case 'T':
- no_tty_flag = 1;
- break;
case 'o':
dummy = 1;
line = xstrdup(optarg);
exit(255);
xfree(line);
break;
+ case 'T':
+ no_tty_flag = 1;
+ /* ensure that the user doesn't try to backdoor a */
+ /* null cipher switch on an interactive session */
+ /* so explicitly disable it no matter what */
+ options.none_switch=0;
+ break;
case 's':
subsystem_flag = 1;
break;
*/
log_init(av[0],
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 {
+ /*
+ * Since the config file parsing code aborts if it sees
+ * options it doesn't recognize, allow users to put
+ * options specific to compile-time add-ons in alternate
+ * config files so their primary config file will
+ * interoperate SSH versions that don't support those
+ * options.
+ */
+#ifdef GSSAPI
+ snprintf(buf, sizeof buf, "%.100s/%.100s.gssapi", pw->pw_dir,
+ _PATH_SSH_USER_CONFFILE);
+ (void)read_config_file(buf, host, &options, 1);
+#ifdef GSI
+ snprintf(buf, sizeof buf, "%.100s/%.100s.gsi", pw->pw_dir,
+ _PATH_SSH_USER_CONFFILE);
+ (void)read_config_file(buf, host, &options, 1);
+#endif
+#if defined(KRB5)
+ snprintf(buf, sizeof buf, "%.100s/%.100s.krb", pw->pw_dir,
+ _PATH_SSH_USER_CONFFILE);
+ (void)read_config_file(buf, host, &options, 1);
+#endif
+#endif
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
_PATH_SSH_USER_CONFFILE);
(void)read_config_file(buf, host, &options, 1);
channel_set_af(options.address_family);
/* reinit */
- log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
+ log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
seed_rng();
- if (options.user == NULL)
+ if (options.user == NULL) {
options.user = xstrdup(pw->pw_name);
+ options.implicit = 1;
+ }
+ else options.implicit = 0;
/* Get default port if port has not been set. */
if (options.port == 0) {
{
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 "
{
Channel *c;
int window, packetmax, in, out, err;
+ int sock;
+ int socksize;
+ int socksizelen = sizeof(int);
if (stdin_null_flag) {
in = open(_PATH_DEVNULL, O_RDONLY);
if (!isatty(err))
set_nonblock(err);
- window = CHAN_SES_WINDOW_DEFAULT;
+ /* we need to check to see if what they want to do about buffer */
+ /* sizes here. In a hpn to nonhpn connection we want to limit */
+ /* the window size to something reasonable in case the far side */
+ /* has the large window bug. In hpn to hpn connection we want to */
+ /* use the max window size but allow the user to override it */
+ /* lastly if they disabled hpn then use the ssh std window size */
+
+ /* so why don't we just do a getsockopt() here and set the */
+ /* ssh window to that? In the case of a autotuning receive */
+ /* window the window would get stuck at the initial buffer */
+ /* size generally less than 96k. Therefore we need to set the */
+ /* maximum ssh window size to the maximum hpn buffer size */
+ /* unless the user has specifically set the tcprcvbufpoll */
+ /* to no. In which case we *can* just set the window to the */
+ /* minimum of the hpn buffer size and tcp receive buffer size */
+
+ if (tty_flag)
+ options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
+ else
+ options.hpn_buffer_size = 2*1024*1024;
+
+ if (datafellows & SSH_BUG_LARGEWINDOW)
+ {
+ debug("HPN to Non-HPN Connection");
+ }
+ else
+ {
+ if (options.tcp_rcv_buf_poll <= 0)
+ {
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ &socksize, &socksizelen);
+ close(sock);
+ debug("socksize %d", socksize);
+ options.hpn_buffer_size = socksize;
+ debug ("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size);
+ }
+ else
+ {
+ if (options.tcp_rcv_buf > 0)
+ {
+ /*create a socket but don't connect it */
+ /* we use that the get the rcv socket size */
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ /* if they are using the tcp_rcv_buf option */
+ /* attempt to set the buffer size to that */
+ if (options.tcp_rcv_buf)
+ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&options.tcp_rcv_buf,
+ sizeof(options.tcp_rcv_buf));
+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ &socksize, &socksizelen);
+ close(sock);
+ debug("socksize %d", socksize);
+ options.hpn_buffer_size = socksize;
+ debug ("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size);
+ }
+ }
+
+ }
+
+ debug("Final hpn_buffer_size = %d", options.hpn_buffer_size);
+
+ window = options.hpn_buffer_size;
+
+ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
+
packetmax = CHAN_SES_PACKET_DEFAULT;
if (tty_flag) {
+ window = 4*CHAN_SES_PACKET_DEFAULT;
window >>= 1;
packetmax >>= 1;
}
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE,
"client-session", /*nonblock*/0);
-
+ if ((options.tcp_rcv_buf_poll > 0) && (!options.hpn_disabled)) {
+ c->dynamic_window = 1;
+ debug ("Enabled Dynamic Window Scaling\n");
+ }
debug3("ssh_session2_open: channel_new: %d", c->self);
channel_send_open(c->self);
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");