summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2005-01-04 13:07:27 +0000
committerColin Watson <cjwatson@debian.org>2005-01-04 13:07:27 +0000
commitfd0f611b70a83d80fe8793af785542ee5541b7cd (patch)
treebededd22bb7eeec52e20083237ab7e4113445a16 /ssh.c
parentc44fe9a5b9d3db96a7249b04d915f17e4a3a3b04 (diff)
parentebd2ce335af5861020c79fddb1ae35c03bf036cf (diff)
Merge 3.9p1 to the trunk.
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c315
1 files changed, 243 insertions, 72 deletions
diff --git a/ssh.c b/ssh.c
index 376b38b0a..0a2f8f711 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.209 2004/03/11 10:21:17 markus Exp $"); 43RCSID("$OpenBSD: ssh.c,v 1.224 2004/07/28 09:40:29 markus Exp $");
44 44
45#include <openssl/evp.h> 45#include <openssl/evp.h>
46#include <openssl/err.h> 46#include <openssl/err.h>
@@ -53,31 +53,31 @@ RCSID("$OpenBSD: ssh.c,v 1.209 2004/03/11 10:21:17 markus 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 "tildexpand.h"
66#include "dispatch.h"
67#include "misc.h" 67#include "misc.h"
68#include "kex.h" 68#include "kex.h"
69#include "mac.h" 69#include "mac.h"
70#include "sshtty.h" 70#include "sshpty.h"
71#include "match.h"
72#include "msg.h"
73#include "monitor_fdpass.h"
74#include "uidswap.h"
71 75
72#ifdef SMARTCARD 76#ifdef SMARTCARD
73#include "scard.h" 77#include "scard.h"
74#endif 78#endif
75 79
76#ifdef HAVE___PROGNAME
77extern char *__progname; 80extern char *__progname;
78#else
79char *__progname;
80#endif
81 81
82/* Flag indicating whether debug mode is on. This can be set on the command line. */ 82/* Flag indicating whether debug mode is on. This can be set on the command line. */
83int debug_flag = 0; 83int debug_flag = 0;
@@ -141,16 +141,23 @@ static int client_global_request_id = 0;
141/* pid of proxycommand child process */ 141/* pid of proxycommand child process */
142pid_t proxy_command_pid = 0; 142pid_t proxy_command_pid = 0;
143 143
144/* fd to control socket */
145int control_fd = -1;
146
147/* Only used in control client mode */
148volatile sig_atomic_t control_client_terminate = 0;
149u_int control_server_pid = 0;
150
144/* Prints a help message to the user. This function never returns. */ 151/* Prints a help message to the user. This function never returns. */
145 152
146static void 153static void
147usage(void) 154usage(void)
148{ 155{
149 fprintf(stderr, 156 fprintf(stderr,
150"usage: ssh [-1246AaCfghkNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n" 157"usage: ssh [-1246AaCfghkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
151" [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n" 158" [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n"
152" [-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]\n" 159" [-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]\n"
153" [-p port] [-R port:host:hostport] [user@]hostname [command]\n" 160" [-p port] [-R port:host:hostport] [-S ctl] [user@]hostname [command]\n"
154 ); 161 );
155 exit(1); 162 exit(1);
156} 163}
@@ -158,6 +165,7 @@ usage(void)
158static int ssh_session(void); 165static int ssh_session(void);
159static int ssh_session2(void); 166static int ssh_session2(void);
160static void load_public_identity_files(void); 167static void load_public_identity_files(void);
168static void control_client(const char *path);
161 169
162/* 170/*
163 * Main program for the ssh client. 171 * Main program for the ssh client.
@@ -228,7 +236,7 @@ main(int ac, char **av)
228 236
229again: 237again:
230 while ((opt = getopt(ac, av, 238 while ((opt = getopt(ac, av,
231 "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVXY")) != -1) { 239 "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) {
232 switch (opt) { 240 switch (opt) {
233 case '1': 241 case '1':
234 options.protocol = SSH_PROTO_1; 242 options.protocol = SSH_PROTO_1;
@@ -342,7 +350,7 @@ again:
342 if (ciphers_valid(optarg)) { 350 if (ciphers_valid(optarg)) {
343 /* SSH2 only */ 351 /* SSH2 only */
344 options.ciphers = xstrdup(optarg); 352 options.ciphers = xstrdup(optarg);
345 options.cipher = SSH_CIPHER_ILLEGAL; 353 options.cipher = SSH_CIPHER_INVALID;
346 } else { 354 } else {
347 /* SSH1 only */ 355 /* SSH1 only */
348 options.cipher = cipher_number(optarg); 356 options.cipher = cipher_number(optarg);
@@ -369,6 +377,10 @@ again:
369 exit(1); 377 exit(1);
370 } 378 }
371 break; 379 break;
380 case 'M':
381 options.control_master =
382 (options.control_master >= 1) ? 2 : 1;
383 break;
372 case 'p': 384 case 'p':
373 options.port = a2port(optarg); 385 options.port = a2port(optarg);
374 if (options.port == 0) { 386 if (options.port == 0) {
@@ -437,6 +449,11 @@ again:
437 case 's': 449 case 's':
438 subsystem_flag = 1; 450 subsystem_flag = 1;
439 break; 451 break;
452 case 'S':
453 if (options.control_path != NULL)
454 free(options.control_path);
455 options.control_path = xstrdup(optarg);
456 break;
440 case 'b': 457 case 'b':
441 options.bind_address = optarg; 458 options.bind_address = optarg;
442 break; 459 break;
@@ -531,16 +548,17 @@ again:
531 * file if the user specifies a config file on the command line. 548 * file if the user specifies a config file on the command line.
532 */ 549 */
533 if (config != NULL) { 550 if (config != NULL) {
534 if (!read_config_file(config, host, &options)) 551 if (!read_config_file(config, host, &options, 0))
535 fatal("Can't open user config file %.100s: " 552 fatal("Can't open user config file %.100s: "
536 "%.100s", config, strerror(errno)); 553 "%.100s", config, strerror(errno));
537 } else { 554 } else {
538 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, 555 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
539 _PATH_SSH_USER_CONFFILE); 556 _PATH_SSH_USER_CONFFILE);
540 (void)read_config_file(buf, host, &options); 557 (void)read_config_file(buf, host, &options, 1);
541 558
542 /* Read systemwide configuration file after use config. */ 559 /* Read systemwide configuration file after use config. */
543 (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options); 560 (void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
561 &options, 0);
544 } 562 }
545 563
546 /* Fill configuration defaults. */ 564 /* Fill configuration defaults. */
@@ -570,6 +588,13 @@ again:
570 strcmp(options.proxy_command, "none") == 0) 588 strcmp(options.proxy_command, "none") == 0)
571 options.proxy_command = NULL; 589 options.proxy_command = NULL;
572 590
591 if (options.control_path != NULL) {
592 options.control_path = tilde_expand_filename(
593 options.control_path, original_real_uid);
594 }
595 if (options.control_path != NULL && options.control_master == 0)
596 control_client(options.control_path); /* This doesn't return */
597
573 /* Open a connection to the remote host. */ 598 /* Open a connection to the remote host. */
574 if (ssh_connect(host, &hostaddr, options.port, 599 if (ssh_connect(host, &hostaddr, options.port,
575 options.address_family, options.connection_attempts, 600 options.address_family, options.connection_attempts,
@@ -625,8 +650,10 @@ again:
625 * user's home directory if it happens to be on a NFS volume where 650 * user's home directory if it happens to be on a NFS volume where
626 * root is mapped to nobody. 651 * root is mapped to nobody.
627 */ 652 */
628 seteuid(original_real_uid); 653 if (original_effective_uid == 0) {
629 setuid(original_real_uid); 654 PRIV_START;
655 permanently_set_uid(pw);
656 }
630 657
631 /* 658 /*
632 * Now that we are back to our own permissions, create ~/.ssh 659 * Now that we are back to our own permissions, create ~/.ssh
@@ -682,6 +709,9 @@ again:
682 exit_status = compat20 ? ssh_session2() : ssh_session(); 709 exit_status = compat20 ? ssh_session2() : ssh_session();
683 packet_close(); 710 packet_close();
684 711
712 if (options.control_path != NULL && control_fd != -1)
713 unlink(options.control_path);
714
685 /* 715 /*
686 * Send SIGHUP to proxy command if used. We don't wait() in 716 * Send SIGHUP to proxy command if used. We don't wait() in
687 * case it hangs and instead rely on init to reap the child 717 * case it hangs and instead rely on init to reap the child
@@ -781,17 +811,17 @@ x11_get_proto(char **_proto, char **_data)
781 * for the local connection. 811 * for the local connection.
782 */ 812 */
783 if (!got_data) { 813 if (!got_data) {
784 u_int32_t rand = 0; 814 u_int32_t rnd = 0;
785 815
786 logit("Warning: No xauth data; " 816 logit("Warning: No xauth data; "
787 "using fake authentication data for X11 forwarding."); 817 "using fake authentication data for X11 forwarding.");
788 strlcpy(proto, SSH_X11_PROTO, sizeof proto); 818 strlcpy(proto, SSH_X11_PROTO, sizeof proto);
789 for (i = 0; i < 16; i++) { 819 for (i = 0; i < 16; i++) {
790 if (i % 4 == 0) 820 if (i % 4 == 0)
791 rand = arc4random(); 821 rnd = arc4random();
792 snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", 822 snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
793 rand & 0xff); 823 rnd & 0xff);
794 rand >>= 8; 824 rnd >>= 8;
795 } 825 }
796 } 826 }
797} 827}
@@ -978,7 +1008,7 @@ ssh_session(void)
978} 1008}
979 1009
980static void 1010static void
981client_subsystem_reply(int type, u_int32_t seq, void *ctxt) 1011ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
982{ 1012{
983 int id, len; 1013 int id, len;
984 1014
@@ -1010,40 +1040,53 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
1010 options.remote_forwards[i].port); 1040 options.remote_forwards[i].port);
1011} 1041}
1012 1042
1013/* request pty/x11/agent/tcpfwd/shell for channel */
1014static void 1043static void
1015ssh_session2_setup(int id, void *arg) 1044ssh_control_listener(void)
1016{ 1045{
1017 int len; 1046 struct sockaddr_un addr;
1018 int interactive = 0; 1047 mode_t old_umask;
1019 struct termios tio; 1048 int addr_len;
1020 1049
1021 debug2("ssh_session2_setup: id %d", id); 1050 if (options.control_path == NULL || options.control_master <= 0)
1051 return;
1022 1052
1023 if (tty_flag) { 1053 memset(&addr, '\0', sizeof(addr));
1024 struct winsize ws; 1054 addr.sun_family = AF_UNIX;
1025 char *cp; 1055 addr_len = offsetof(struct sockaddr_un, sun_path) +
1026 cp = getenv("TERM"); 1056 strlen(options.control_path) + 1;
1027 if (!cp)
1028 cp = "";
1029 /* Store window size in the packet. */
1030 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
1031 memset(&ws, 0, sizeof(ws));
1032 1057
1033 channel_request_start(id, "pty-req", 0); 1058 if (strlcpy(addr.sun_path, options.control_path,
1034 packet_put_cstring(cp); 1059 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
1035 packet_put_int(ws.ws_col); 1060 fatal("ControlPath too long");
1036 packet_put_int(ws.ws_row); 1061
1037 packet_put_int(ws.ws_xpixel); 1062 if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1038 packet_put_int(ws.ws_ypixel); 1063 fatal("%s socket(): %s\n", __func__, strerror(errno));
1039 tio = get_saved_tio(); 1064
1040 tty_make_modes(/*ignored*/ 0, &tio); 1065 old_umask = umask(0177);
1041 packet_send(); 1066 if (bind(control_fd, (struct sockaddr*)&addr, addr_len) == -1) {
1042 interactive = 1; 1067 control_fd = -1;
1043 /* XXX wait for reply */ 1068 if (errno == EINVAL)
1069 fatal("ControlSocket %s already exists",
1070 options.control_path);
1071 else
1072 fatal("%s bind(): %s\n", __func__, strerror(errno));
1044 } 1073 }
1045 if (options.forward_x11 && 1074 umask(old_umask);
1046 getenv("DISPLAY") != NULL) { 1075
1076 if (listen(control_fd, 64) == -1)
1077 fatal("%s listen(): %s\n", __func__, strerror(errno));
1078
1079 set_nonblock(control_fd);
1080}
1081
1082/* request pty/x11/agent/tcpfwd/shell for channel */
1083static void
1084ssh_session2_setup(int id, void *arg)
1085{
1086 extern char **environ;
1087
1088 int interactive = tty_flag;
1089 if (options.forward_x11 && getenv("DISPLAY") != NULL) {
1047 char *proto, *data; 1090 char *proto, *data;
1048 /* Get reasonable local authentication information. */ 1091 /* Get reasonable local authentication information. */
1049 x11_get_proto(&proto, &data); 1092 x11_get_proto(&proto, &data);
@@ -1061,27 +1104,8 @@ ssh_session2_setup(int id, void *arg)
1061 packet_send(); 1104 packet_send();
1062 } 1105 }
1063 1106
1064 len = buffer_len(&command); 1107 client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
1065 if (len > 0) { 1108 NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
1066 if (len > 900)
1067 len = 900;
1068 if (subsystem_flag) {
1069 debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));
1070 channel_request_start(id, "subsystem", /*want reply*/ 1);
1071 /* register callback for reply */
1072 /* XXX we assume that client_loop has already been called */
1073 dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
1074 dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
1075 } else {
1076 debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
1077 channel_request_start(id, "exec", 0);
1078 }
1079 packet_put_string(buffer_ptr(&command), buffer_len(&command));
1080 packet_send();
1081 } else {
1082 channel_request_start(id, "shell", 0);
1083 packet_send();
1084 }
1085 1109
1086 packet_set_interactive(interactive); 1110 packet_set_interactive(interactive);
1087} 1111}
@@ -1127,7 +1151,7 @@ ssh_session2_open(void)
1127 1151
1128 channel_send_open(c->self); 1152 channel_send_open(c->self);
1129 if (!no_shell_flag) 1153 if (!no_shell_flag)
1130 channel_register_confirm(c->self, ssh_session2_setup); 1154 channel_register_confirm(c->self, ssh_session2_setup, NULL);
1131 1155
1132 return c->self; 1156 return c->self;
1133} 1157}
@@ -1139,6 +1163,7 @@ ssh_session2(void)
1139 1163
1140 /* XXX should be pre-session */ 1164 /* XXX should be pre-session */
1141 ssh_init_forwarding(); 1165 ssh_init_forwarding();
1166 ssh_control_listener();
1142 1167
1143 if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) 1168 if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
1144 id = ssh_session2_open(); 1169 id = ssh_session2_open();
@@ -1192,3 +1217,149 @@ load_public_identity_files(void)
1192 options.identity_keys[i] = public; 1217 options.identity_keys[i] = public;
1193 } 1218 }
1194} 1219}
1220
1221static void
1222control_client_sighandler(int signo)
1223{
1224 control_client_terminate = signo;
1225}
1226
1227static void
1228control_client_sigrelay(int signo)
1229{
1230 if (control_server_pid > 1)
1231 kill(control_server_pid, signo);
1232}
1233
1234static int
1235env_permitted(char *env)
1236{
1237 int i;
1238 char name[1024], *cp;
1239
1240 strlcpy(name, env, sizeof(name));
1241 if ((cp = strchr(name, '=')) == NULL)
1242 return (0);
1243
1244 *cp = '\0';
1245
1246 for (i = 0; i < options.num_send_env; i++)
1247 if (match_pattern(name, options.send_env[i]))
1248 return (1);
1249
1250 return (0);
1251}
1252
1253static void
1254control_client(const char *path)
1255{
1256 struct sockaddr_un addr;
1257 int i, r, sock, exitval, num_env, addr_len;
1258 Buffer m;
1259 char *cp;
1260 extern char **environ;
1261
1262 memset(&addr, '\0', sizeof(addr));
1263 addr.sun_family = AF_UNIX;
1264 addr_len = offsetof(struct sockaddr_un, sun_path) +
1265 strlen(path) + 1;
1266
1267 if (strlcpy(addr.sun_path, path,
1268 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
1269 fatal("ControlPath too long");
1270
1271 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1272 fatal("%s socket(): %s", __func__, strerror(errno));
1273
1274 if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1)
1275 fatal("Couldn't connect to %s: %s", path, strerror(errno));
1276
1277 if ((cp = getenv("TERM")) == NULL)
1278 cp = "";
1279
1280 buffer_init(&m);
1281
1282 /* Get PID of controlee */
1283 if (ssh_msg_recv(sock, &m) == -1)
1284 fatal("%s: msg_recv", __func__);
1285 if (buffer_get_char(&m) != 0)
1286 fatal("%s: wrong version", __func__);
1287 /* Connection allowed? */
1288 if (buffer_get_int(&m) != 1)
1289 fatal("Connection to master denied");
1290 control_server_pid = buffer_get_int(&m);
1291
1292 buffer_clear(&m);
1293 buffer_put_int(&m, tty_flag);
1294 buffer_put_int(&m, subsystem_flag);
1295 buffer_put_cstring(&m, cp);
1296
1297 buffer_append(&command, "\0", 1);
1298 buffer_put_cstring(&m, buffer_ptr(&command));
1299
1300 if (options.num_send_env == 0 || environ == NULL) {
1301 buffer_put_int(&m, 0);
1302 } else {
1303 /* Pass environment */
1304 num_env = 0;
1305 for (i = 0; environ[i] != NULL; i++)
1306 if (env_permitted(environ[i]))
1307 num_env++; /* Count */
1308
1309 buffer_put_int(&m, num_env);
1310
1311 for (i = 0; environ[i] != NULL && num_env >= 0; i++)
1312 if (env_permitted(environ[i])) {
1313 num_env--;
1314 buffer_put_cstring(&m, environ[i]);
1315 }
1316 }
1317
1318 if (ssh_msg_send(sock, /* version */0, &m) == -1)
1319 fatal("%s: msg_send", __func__);
1320
1321 mm_send_fd(sock, STDIN_FILENO);
1322 mm_send_fd(sock, STDOUT_FILENO);
1323 mm_send_fd(sock, STDERR_FILENO);
1324
1325 /* Wait for reply, so master has a chance to gather ttymodes */
1326 buffer_clear(&m);
1327 if (ssh_msg_recv(sock, &m) == -1)
1328 fatal("%s: msg_recv", __func__);
1329 if (buffer_get_char(&m) != 0)
1330 fatal("%s: master returned error", __func__);
1331 buffer_free(&m);
1332
1333 signal(SIGINT, control_client_sighandler);
1334 signal(SIGTERM, control_client_sighandler);
1335 signal(SIGWINCH, control_client_sigrelay);
1336
1337 if (tty_flag)
1338 enter_raw_mode();
1339
1340 /* Stick around until the controlee closes the client_fd */
1341 exitval = 0;
1342 for (;!control_client_terminate;) {
1343 r = read(sock, &exitval, sizeof(exitval));
1344 if (r == 0) {
1345 debug2("Received EOF from master");
1346 break;
1347 }
1348 if (r > 0)
1349 debug2("Received exit status from master %d", exitval);
1350 if (r == -1 && errno != EINTR)
1351 fatal("%s: read %s", __func__, strerror(errno));
1352 }
1353
1354 if (control_client_terminate)
1355 debug2("Exiting on signal %d", control_client_terminate);
1356
1357 close(sock);
1358
1359 leave_raw_mode();
1360
1361 if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
1362 fprintf(stderr, "Connection to master closed.\r\n");
1363
1364 exit(exitval);
1365}