summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2004-06-15 10:34:08 +1000
committerDamien Miller <djm@mindrot.org>2004-06-15 10:34:08 +1000
commit0e220dbfbcc9fe252e8f1f4890dbfa415aad35db (patch)
treeb78bab0c628cd5bdb0ec95340f533a1be2fae75f /ssh.c
parent05202ffe214115afa24bf6e7a6d8c8457e6759bb (diff)
- djm@cvs.openbsd.org 2004/06/13 15:03:02
[channels.c channels.h clientloop.c clientloop.h includes.h readconf.c] [readconf.h scp.1 sftp.1 ssh.1 ssh.c ssh_config.5] implement session multiplexing in the client (the server has supported this since 2.0); ok markus@
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c276
1 files changed, 184 insertions, 92 deletions
diff --git a/ssh.c b/ssh.c
index 3c21fa37d..1c6ec8b6a 100644
--- a/ssh.c
+++ b/ssh.c
@@ -40,7 +40,7 @@
40 */ 40 */
41 41
42#include "includes.h" 42#include "includes.h"
43RCSID("$OpenBSD: ssh.c,v 1.213 2004/05/08 00:01:37 deraadt Exp $"); 43RCSID("$OpenBSD: ssh.c,v 1.214 2004/06/13 15:03:02 djm Exp $");
44 44
45#include <openssl/evp.h> 45#include <openssl/evp.h>
46#include <openssl/err.h> 46#include <openssl/err.h>
@@ -53,21 +53,24 @@ RCSID("$OpenBSD: ssh.c,v 1.213 2004/05/08 00:01:37 deraadt Exp $");
53#include "xmalloc.h" 53#include "xmalloc.h"
54#include "packet.h" 54#include "packet.h"
55#include "buffer.h" 55#include "buffer.h"
56#include "bufaux.h"
56#include "channels.h" 57#include "channels.h"
57#include "key.h" 58#include "key.h"
58#include "authfd.h" 59#include "authfd.h"
59#include "authfile.h" 60#include "authfile.h"
60#include "pathnames.h" 61#include "pathnames.h"
62#include "dispatch.h"
61#include "clientloop.h" 63#include "clientloop.h"
62#include "log.h" 64#include "log.h"
63#include "readconf.h" 65#include "readconf.h"
64#include "sshconnect.h" 66#include "sshconnect.h"
65#include "dispatch.h"
66#include "misc.h" 67#include "misc.h"
67#include "kex.h" 68#include "kex.h"
68#include "mac.h" 69#include "mac.h"
69#include "sshpty.h" 70#include "sshpty.h"
70#include "match.h" 71#include "match.h"
72#include "msg.h"
73#include "monitor_fdpass.h"
71 74
72#ifdef SMARTCARD 75#ifdef SMARTCARD
73#include "scard.h" 76#include "scard.h"
@@ -141,6 +144,13 @@ static int client_global_request_id = 0;
141/* pid of proxycommand child process */ 144/* pid of proxycommand child process */
142pid_t proxy_command_pid = 0; 145pid_t proxy_command_pid = 0;
143 146
147/* fd to control socket */
148int control_fd = -1;
149
150/* Only used in control client mode */
151volatile sig_atomic_t control_client_terminate = 0;
152u_int control_server_pid = 0;
153
144/* Prints a help message to the user. This function never returns. */ 154/* Prints a help message to the user. This function never returns. */
145 155
146static void 156static void
@@ -158,6 +168,7 @@ usage(void)
158static int ssh_session(void); 168static int ssh_session(void);
159static int ssh_session2(void); 169static int ssh_session2(void);
160static void load_public_identity_files(void); 170static void load_public_identity_files(void);
171static void control_client(const char *path);
161 172
162/* 173/*
163 * Main program for the ssh client. 174 * Main program for the ssh client.
@@ -228,7 +239,7 @@ main(int ac, char **av)
228 239
229again: 240again:
230 while ((opt = getopt(ac, av, 241 while ((opt = getopt(ac, av,
231 "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVXY")) != -1) { 242 "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) {
232 switch (opt) { 243 switch (opt) {
233 case '1': 244 case '1':
234 options.protocol = SSH_PROTO_1; 245 options.protocol = SSH_PROTO_1;
@@ -364,6 +375,9 @@ again:
364 exit(1); 375 exit(1);
365 } 376 }
366 break; 377 break;
378 case 'M':
379 options.control_master = 1;
380 break;
367 case 'p': 381 case 'p':
368 options.port = a2port(optarg); 382 options.port = a2port(optarg);
369 if (options.port == 0) { 383 if (options.port == 0) {
@@ -432,6 +446,13 @@ again:
432 case 's': 446 case 's':
433 subsystem_flag = 1; 447 subsystem_flag = 1;
434 break; 448 break;
449 case 'S':
450 if (options.control_path != NULL)
451 free(options.control_path);
452 options.control_path = xstrdup(optarg);
453 if (options.control_master == -1)
454 options.control_master = 0;
455 break;
435 case 'b': 456 case 'b':
436 options.bind_address = optarg; 457 options.bind_address = optarg;
437 break; 458 break;
@@ -566,6 +587,13 @@ again:
566 strcmp(options.proxy_command, "none") == 0) 587 strcmp(options.proxy_command, "none") == 0)
567 options.proxy_command = NULL; 588 options.proxy_command = NULL;
568 589
590 if (options.control_path != NULL) {
591 options.control_path = tilde_expand_filename(
592 options.control_path, original_real_uid);
593 }
594 if (options.control_path != NULL && options.control_master == 0)
595 control_client(options.control_path); /* This doesn't return */
596
569 /* Open a connection to the remote host. */ 597 /* Open a connection to the remote host. */
570 if (ssh_connect(host, &hostaddr, options.port, 598 if (ssh_connect(host, &hostaddr, options.port,
571 options.address_family, options.connection_attempts, 599 options.address_family, options.connection_attempts,
@@ -678,6 +706,9 @@ again:
678 exit_status = compat20 ? ssh_session2() : ssh_session(); 706 exit_status = compat20 ? ssh_session2() : ssh_session();
679 packet_close(); 707 packet_close();
680 708
709 if (options.control_path != NULL && control_fd != -1)
710 unlink(options.control_path);
711
681 /* 712 /*
682 * Send SIGHUP to proxy command if used. We don't wait() in 713 * Send SIGHUP to proxy command if used. We don't wait() in
683 * case it hangs and instead rely on init to reap the child 714 * case it hangs and instead rely on init to reap the child
@@ -974,7 +1005,7 @@ ssh_session(void)
974} 1005}
975 1006
976static void 1007static void
977client_subsystem_reply(int type, u_int32_t seq, void *ctxt) 1008ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
978{ 1009{
979 int id, len; 1010 int id, len;
980 1011
@@ -1006,40 +1037,50 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
1006 options.remote_forwards[i].port); 1037 options.remote_forwards[i].port);
1007} 1038}
1008 1039
1009/* request pty/x11/agent/tcpfwd/shell for channel */
1010static void 1040static void
1011ssh_session2_setup(int id, void *arg) 1041ssh_control_listener(void)
1012{ 1042{
1013 int len; 1043 struct sockaddr_un addr;
1014 int interactive = 0; 1044 mode_t old_umask;
1015 struct termios tio; 1045
1046 if (options.control_path == NULL || options.control_master != 1)
1047 return;
1016 1048
1017 debug2("ssh_session2_setup: id %d", id); 1049 memset(&addr, '\0', sizeof(addr));
1050 addr.sun_family = AF_UNIX;
1051 addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
1052 strlen(options.control_path) + 1;
1018 1053
1019 if (tty_flag) { 1054 if (strlcpy(addr.sun_path, options.control_path,
1020 struct winsize ws; 1055 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
1021 char *cp; 1056 fatal("ControlPath too long");
1022 cp = getenv("TERM");
1023 if (!cp)
1024 cp = "";
1025 /* Store window size in the packet. */
1026 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
1027 memset(&ws, 0, sizeof(ws));
1028 1057
1029 channel_request_start(id, "pty-req", 0); 1058 if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1030 packet_put_cstring(cp); 1059 fatal("%s socket(): %s\n", __func__, strerror(errno));
1031 packet_put_int(ws.ws_col); 1060
1032 packet_put_int(ws.ws_row); 1061 old_umask = umask(0177);
1033 packet_put_int(ws.ws_xpixel); 1062 if (bind(control_fd, (struct sockaddr*)&addr, addr.sun_len) == -1) {
1034 packet_put_int(ws.ws_ypixel); 1063 control_fd = -1;
1035 tio = get_saved_tio(); 1064 if (errno == EINVAL)
1036 tty_make_modes(/*ignored*/ 0, &tio); 1065 fatal("ControlSocket %s already exists",
1037 packet_send(); 1066 options.control_path);
1038 interactive = 1; 1067 else
1039 /* XXX wait for reply */ 1068 fatal("%s bind(): %s\n", __func__, strerror(errno));
1040 } 1069 }
1041 if (options.forward_x11 && 1070 umask(old_umask);
1042 getenv("DISPLAY") != NULL) { 1071
1072 if (listen(control_fd, 64) == -1)
1073 fatal("%s listen(): %s\n", __func__, strerror(errno));
1074
1075 set_nonblock(control_fd);
1076}
1077
1078/* request pty/x11/agent/tcpfwd/shell for channel */
1079static void
1080ssh_session2_setup(int id, void *arg)
1081{
1082 int interactive = tty_flag;
1083 if (options.forward_x11 && getenv("DISPLAY") != NULL) {
1043 char *proto, *data; 1084 char *proto, *data;
1044 /* Get reasonable local authentication information. */ 1085 /* Get reasonable local authentication information. */
1045 x11_get_proto(&proto, &data); 1086 x11_get_proto(&proto, &data);
@@ -1057,65 +1098,8 @@ ssh_session2_setup(int id, void *arg)
1057 packet_send(); 1098 packet_send();
1058 } 1099 }
1059 1100
1060 /* Transfer any environment variables from client to server */ 1101 client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
1061 if (options.num_send_env != 0) { 1102 NULL, fileno(stdin), &command, &ssh_subsystem_reply);
1062 int i, j, matched;
1063 extern char **environ;
1064 char *name, *val;
1065
1066 debug("Sending environment.");
1067 for (i = 0; environ && environ[i] != NULL; i++) {
1068 /* Split */
1069 name = xstrdup(environ[i]);
1070 if ((val = strchr(name, '=')) == NULL) {
1071 free(name);
1072 continue;
1073 }
1074 *val++ = '\0';
1075
1076 matched = 0;
1077 for (j = 0; j < options.num_send_env; j++) {
1078 if (match_pattern(name, options.send_env[j])) {
1079 matched = 1;
1080 break;
1081 }
1082 }
1083 if (!matched) {
1084 debug3("Ignored env %s", name);
1085 free(name);
1086 continue;
1087 }
1088
1089 debug("Sending env %s = %s", name, val);
1090 channel_request_start(id, "env", 0);
1091 packet_put_cstring(name);
1092 packet_put_cstring(val);
1093 packet_send();
1094 free(name);
1095 }
1096 }
1097
1098 len = buffer_len(&command);
1099 if (len > 0) {
1100 if (len > 900)
1101 len = 900;
1102 if (subsystem_flag) {
1103 debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));
1104 channel_request_start(id, "subsystem", /*want reply*/ 1);
1105 /* register callback for reply */
1106 /* XXX we assume that client_loop has already been called */
1107 dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
1108 dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
1109 } else {
1110 debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
1111 channel_request_start(id, "exec", 0);
1112 }
1113 packet_put_string(buffer_ptr(&command), buffer_len(&command));
1114 packet_send();
1115 } else {
1116 channel_request_start(id, "shell", 0);
1117 packet_send();
1118 }
1119 1103
1120 packet_set_interactive(interactive); 1104 packet_set_interactive(interactive);
1121} 1105}
@@ -1161,7 +1145,7 @@ ssh_session2_open(void)
1161 1145
1162 channel_send_open(c->self); 1146 channel_send_open(c->self);
1163 if (!no_shell_flag) 1147 if (!no_shell_flag)
1164 channel_register_confirm(c->self, ssh_session2_setup); 1148 channel_register_confirm(c->self, ssh_session2_setup, NULL);
1165 1149
1166 return c->self; 1150 return c->self;
1167} 1151}
@@ -1173,6 +1157,7 @@ ssh_session2(void)
1173 1157
1174 /* XXX should be pre-session */ 1158 /* XXX should be pre-session */
1175 ssh_init_forwarding(); 1159 ssh_init_forwarding();
1160 ssh_control_listener();
1176 1161
1177 if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) 1162 if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
1178 id = ssh_session2_open(); 1163 id = ssh_session2_open();
@@ -1226,3 +1211,110 @@ load_public_identity_files(void)
1226 options.identity_keys[i] = public; 1211 options.identity_keys[i] = public;
1227 } 1212 }
1228} 1213}
1214
1215static void
1216control_client_sighandler(int signo)
1217{
1218 control_client_terminate = signo;
1219}
1220
1221static void
1222control_client_sigrelay(int signo)
1223{
1224 if (control_server_pid > 1)
1225 kill(control_server_pid, signo);
1226}
1227
1228static void
1229control_client(const char *path)
1230{
1231 struct sockaddr_un addr;
1232 int r, sock, exitval;
1233 Buffer m;
1234 char *cp;
1235
1236 memset(&addr, '\0', sizeof(addr));
1237 addr.sun_family = AF_UNIX;
1238 addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
1239 strlen(path) + 1;
1240
1241 if (strlcpy(addr.sun_path, path,
1242 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
1243 fatal("ControlPath too long");
1244
1245 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1246 fatal("%s socket(): %s", __func__, strerror(errno));
1247
1248 if (connect(sock, (struct sockaddr*)&addr, addr.sun_len) == -1)
1249 fatal("Couldn't connect to %s: %s", path, strerror(errno));
1250
1251 if ((cp = getenv("TERM")) == NULL)
1252 cp = "";
1253
1254 signal(SIGINT, control_client_sighandler);
1255 signal(SIGTERM, control_client_sighandler);
1256 signal(SIGWINCH, control_client_sigrelay);
1257
1258 buffer_init(&m);
1259
1260 /* Get PID of controlee */
1261 if (ssh_msg_recv(sock, &m) == -1)
1262 fatal("%s: msg_recv", __func__);
1263 if (buffer_get_char(&m) != 0)
1264 fatal("%s: wrong version", __func__);
1265 control_server_pid = buffer_get_int(&m);
1266
1267 /* XXX: env passing */
1268
1269 buffer_clear(&m);
1270 buffer_put_int(&m, tty_flag);
1271 buffer_put_int(&m, subsystem_flag);
1272 buffer_put_cstring(&m, cp);
1273
1274 buffer_append(&command, "\0", 1);
1275 buffer_put_cstring(&m, buffer_ptr(&command));
1276
1277 if (ssh_msg_send(sock, /* version */0, &m) == -1)
1278 fatal("%s: msg_send", __func__);
1279
1280 mm_send_fd(sock, STDIN_FILENO);
1281 mm_send_fd(sock, STDOUT_FILENO);
1282 mm_send_fd(sock, STDERR_FILENO);
1283
1284 /* Wait for reply, so master has a chance to gather ttymodes */
1285 buffer_clear(&m);
1286 if (ssh_msg_recv(sock, &m) == -1)
1287 fatal("%s: msg_recv", __func__);
1288 if (buffer_get_char(&m) != 0)
1289 fatal("%s: master returned error", __func__);
1290 buffer_free(&m);
1291
1292 if (tty_flag)
1293 enter_raw_mode();
1294
1295 /* Stick around until the controlee closes the client_fd */
1296 exitval = 0;
1297 for (;!control_client_terminate;) {
1298 r = read(sock, &exitval, sizeof(exitval));
1299 if (r == 0) {
1300 debug2("Received EOF from master");
1301 break;
1302 }
1303 if (r > 0)
1304 debug2("Received exit status from master %d", exitval);
1305 if (r == -1 && errno != EINTR)
1306 fatal("%s: read %s", __func__, strerror(errno));
1307 }
1308
1309 if (control_client_terminate)
1310 debug2("Exiting on signal %d", control_client_terminate);
1311
1312 close(sock);
1313
1314 leave_raw_mode();
1315
1316 if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
1317 fprintf(stderr, "Connection to master closed.\r\n");
1318
1319 exit(exitval);
1320}