summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--README.openssh236
-rw-r--r--auth.c188
-rw-r--r--auth.h4
-rw-r--r--channels.c7
-rw-r--r--compat.c6
-rw-r--r--servconf.c12
-rw-r--r--servconf.h3
-rw-r--r--serverloop.c192
-rw-r--r--session.c328
-rw-r--r--session.h7
-rw-r--r--ssh.h6
-rw-r--r--sshd.c240
13 files changed, 1002 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 857341344..976c3834f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,15 @@
2 - Avoid some compiler warnings in fake-get*.c 2 - Avoid some compiler warnings in fake-get*.c
3 - Add IPTOS macros for systems which lack them 3 - Add IPTOS macros for systems which lack them
4 - Only set define entropy collection macros if they are found 4 - Only set define entropy collection macros if they are found
5 5 - More large OpenBSD CVS updates:
6 - [auth.c auth.h servconf.c servconf.h serverloop.c session.c]
7 [session.h ssh.h sshd.c README.openssh2]
8 ssh2 server side, see README.openssh2; enable with 'sshd -2'
9 - [channels.c]
10 no adjust after close
11 - [sshd.c compat.c ]
12 interop w/ latest ssh.com windows client.
13
620000406 1420000406
7 - OpenBSD CVS update: 15 - OpenBSD CVS update:
8 - [channels.c] 16 - [channels.c]
diff --git a/README.openssh2 b/README.openssh2
new file mode 100644
index 000000000..59f8cf9f6
--- /dev/null
+++ b/README.openssh2
@@ -0,0 +1,36 @@
1$Id: README.openssh2,v 1.2 2000/04/06 21:28:22 markus Exp $
2
3works:
4 secsh-transport: works w/o rekey
5 proposal exchange, i.e. different enc/mac/comp per direction
6 encryption: blowfish-cbc, 3des-cbc, arcfour, cast128-cbc
7 mac: hmac-md5, hmac-sha1, (hmac-ripemd160)
8 compression: zlib, none
9 secsh-userauth: passwd only
10 secsh-connection: pty+shell or command, flow control works (window adjust)
11 tcp-forwarding: -L works
12 dss: verification works,
13 key database in ~/.ssh/known_hosts with bits == 0 hack
14 dss: signature works, keygen w/ openssl:
15 $ umask 077
16 $ openssl dsaparam 1024 -out dsa1024.pem
17 $ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
18 start sshd with '-2' flag
19 client interops w/ sshd2, lshd
20 server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT
21 server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
22todo:
23 re-keying
24 secsh-connection features:
25 tcp-forwarding, agent-fwd, x11-fwd
26 auth other than passwd:
27 pubkey, keyboard-interactive
28 config
29 server-auth w/ old host-keys
30 cleanup
31 advanced key storage?
32 keynote
33 sftp
34
35-markus
36$Date: 2000/04/06 21:28:22 $
diff --git a/auth.c b/auth.c
index 11b538172..e94a86e95 100644
--- a/auth.c
+++ b/auth.c
@@ -1,10 +1,11 @@
1/* 1/*
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved 3 * All rights reserved
4 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 */ 5 */
5 6
6#include "includes.h" 7#include "includes.h"
7RCSID("$OpenBSD: auth.c,v 1.1 2000/03/28 21:15:45 markus Exp $"); 8RCSID("$OpenBSD: auth.c,v 1.2 2000/04/06 08:55:22 markus Exp $");
8 9
9#include "xmalloc.h" 10#include "xmalloc.h"
10#include "rsa.h" 11#include "rsa.h"
@@ -15,12 +16,17 @@ RCSID("$OpenBSD: auth.c,v 1.1 2000/03/28 21:15:45 markus Exp $");
15#include "cipher.h" 16#include "cipher.h"
16#include "mpaux.h" 17#include "mpaux.h"
17#include "servconf.h" 18#include "servconf.h"
19#include "compat.h"
18#include "channels.h" 20#include "channels.h"
19#include "match.h" 21#include "match.h"
20 22
23#include "bufaux.h"
24#include "ssh2.h"
25#include "auth.h"
21#include "session.h" 26#include "session.h"
22#include "dispatch.h" 27#include "dispatch.h"
23 28
29
24/* import */ 30/* import */
25extern ServerOptions options; 31extern ServerOptions options;
26extern char *forced_command; 32extern char *forced_command;
@@ -604,3 +610,183 @@ do_authentication()
604 /* Perform session preparation. */ 610 /* Perform session preparation. */
605 do_authenticated(pw); 611 do_authenticated(pw);
606} 612}
613
614
615void input_service_request(int type, int plen);
616void input_userauth_request(int type, int plen);
617void ssh2_pty_cleanup(void);
618
619typedef struct Authctxt Authctxt;
620struct Authctxt {
621 char *user;
622 char *service;
623 struct passwd pw;
624 int valid;
625};
626static Authctxt *authctxt = NULL;
627static int userauth_success = 0;
628
629struct passwd*
630auth_get_user(void)
631{
632 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
633}
634struct passwd*
635auth_set_user(char *u, char *s)
636{
637 struct passwd *pw, *copy;
638
639 if (authctxt == NULL) {
640 authctxt = xmalloc(sizeof(*authctxt));
641 authctxt->valid = 0;
642 authctxt->user = xstrdup(u);
643 authctxt->service = xstrdup(s);
644 setproctitle("%s", u);
645 pw = getpwnam(u);
646 if (!pw || !allowed_user(pw)) {
647 log("auth_set_user: bad user %s", u);
648 return NULL;
649 }
650#ifdef USE_PAM
651 start_pam(pw);
652#endif
653 copy = &authctxt->pw;
654 memset(copy, 0, sizeof(*copy));
655 copy->pw_name = xstrdup(pw->pw_name);
656 copy->pw_passwd = xstrdup(pw->pw_passwd);
657 copy->pw_uid = pw->pw_uid;
658 copy->pw_gid = pw->pw_gid;
659 copy->pw_dir = xstrdup(pw->pw_dir);
660 copy->pw_shell = xstrdup(pw->pw_shell);
661 authctxt->valid = 1;
662 } else {
663 if (strcmp(u, authctxt->user) != 0 ||
664 strcmp(s, authctxt->service) != 0) {
665 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
666 u, s, authctxt->user, authctxt->service);
667 return NULL;
668 }
669 }
670 return auth_get_user();
671}
672
673static void
674protocol_error(int type, int plen)
675{
676 log("auth: protocol error: type %d plen %d", type, plen);
677 packet_start(SSH2_MSG_UNIMPLEMENTED);
678 packet_put_int(0);
679 packet_send();
680 packet_write_wait();
681}
682void
683input_service_request(int type, int plen)
684{
685 unsigned int len;
686 int accept = 0;
687 char *service = packet_get_string(&len);
688
689 if (strcmp(service, "ssh-userauth") == 0) {
690 if (!userauth_success) {
691 accept = 1;
692 /* now we can handle user-auth requests */
693 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
694 }
695 }
696 /* XXX all other service requests are denied */
697
698 if (accept) {
699 packet_start(SSH2_MSG_SERVICE_ACCEPT);
700 packet_put_cstring(service);
701 packet_send();
702 packet_write_wait();
703 } else {
704 debug("bad service request %s", service);
705 packet_disconnect("bad service request %s", service);
706 }
707 xfree(service);
708}
709void
710input_userauth_request(int type, int plen)
711{
712 static int try = 0;
713 unsigned int len;
714 int c, authenticated = 0;
715 char *user, *service, *method;
716 struct passwd *pw;
717
718 if (++try == AUTH_FAIL_MAX)
719 packet_disconnect("too many failed userauth_requests");
720
721 user = packet_get_string(&len);
722 service = packet_get_string(&len);
723 method = packet_get_string(&len);
724 debug("userauth-request for user %s service %s method %s", user, service, method);
725
726 /* XXX we only allow the ssh-connection service */
727 pw = auth_set_user(user, service);
728 if (pw && strcmp(service, "ssh-connection")==0) {
729 if (strcmp(method, "none") == 0 && try == 1) {
730#ifdef USE_PAM
731 /* Do PAM auth with password */
732 authenticated = auth_pam_password(pw, "");
733#else /* USE_PAM */
734 /* Try authentication with the password. */
735 authenticated = auth_password(pw, "");
736#endif /* USE_PAM */
737 } else if (strcmp(method, "password") == 0) {
738 char *password;
739 c = packet_get_char();
740 if (c)
741 debug("password change not supported");
742 password = packet_get_string(&len);
743#ifdef USE_PAM
744 /* Do PAM auth with password */
745 authenticated = auth_pam_password(pw, password);
746#else /* USE_PAM */
747 /* Try authentication with the password. */
748 authenticated = auth_password(pw, password);
749#endif /* USE_PAM */
750 memset(password, 0, len);
751 xfree(password);
752 } else if (strcmp(method, "publickey") == 0) {
753 /* XXX TODO */
754 char *pkalg;
755 char *pkblob;
756 c = packet_get_char();
757 pkalg = packet_get_string(&len);
758 pkblob = packet_get_string(&len);
759 xfree(pkalg);
760 xfree(pkblob);
761 }
762 }
763 /* XXX check if other auth methods are needed */
764 if (authenticated) {
765 /* turn off userauth */
766 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
767 /* success! */
768 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
769 packet_send();
770 packet_write_wait();
771 log("userauth success for %s", user);
772 /* now we can break out */
773 userauth_success = 1;
774 } else {
775 packet_start(SSH2_MSG_USERAUTH_FAILURE);
776 packet_put_cstring("password");
777 packet_put_char(0); /* partial success */
778 packet_send();
779 packet_write_wait();
780 }
781 xfree(service);
782 xfree(user);
783 xfree(method);
784}
785void
786do_authentication2()
787{
788 dispatch_init(&protocol_error);
789 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
790 dispatch_run(DISPATCH_BLOCK, &userauth_success);
791 do_authenticated2();
792}
diff --git a/auth.h b/auth.h
index 805177723..3771e826f 100644
--- a/auth.h
+++ b/auth.h
@@ -2,5 +2,9 @@
2#define AUTH_H 2#define AUTH_H
3 3
4void do_authentication(void); 4void do_authentication(void);
5void do_authentication2(void);
6
7struct passwd *
8auth_get_user(void);
5 9
6#endif 10#endif
diff --git a/channels.c b/channels.c
index f03cf92b4..c140b77dc 100644
--- a/channels.c
+++ b/channels.c
@@ -17,7 +17,7 @@
17 */ 17 */
18 18
19#include "includes.h" 19#include "includes.h"
20RCSID("$Id: channels.c,v 1.22 2000/04/06 02:32:38 damien Exp $"); 20RCSID("$Id: channels.c,v 1.23 2000/04/12 08:45:06 damien Exp $");
21 21
22#include "ssh.h" 22#include "ssh.h"
23#include "packet.h" 23#include "packet.h"
@@ -674,7 +674,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
674int 674int
675channel_check_window(Channel *c, fd_set * readset, fd_set * writeset) 675channel_check_window(Channel *c, fd_set * readset, fd_set * writeset)
676{ 676{
677 if (!(c->flags & CHAN_CLOSE_SENT) && 677 if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
678 c->local_window < c->local_window_max/2 && 678 c->local_window < c->local_window_max/2 &&
679 c->local_consumed > 0) { 679 c->local_consumed > 0) {
680 packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); 680 packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
@@ -837,7 +837,8 @@ channel_output_poll()
837 c->istate != CHAN_INPUT_WAIT_DRAIN) 837 c->istate != CHAN_INPUT_WAIT_DRAIN)
838 continue; 838 continue;
839 } 839 }
840 if (compat20 && (c->flags & CHAN_CLOSE_SENT)) { 840 if (compat20 &&
841 (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
841 debug("channel: %d: no data after CLOSE", c->self); 842 debug("channel: %d: no data after CLOSE", c->self);
842 continue; 843 continue;
843 } 844 }
diff --git a/compat.c b/compat.c
index d09f38ca6..c183866c3 100644
--- a/compat.c
+++ b/compat.c
@@ -28,7 +28,7 @@
28 */ 28 */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$Id: compat.c,v 1.5 2000/04/06 02:32:39 damien Exp $"); 31RCSID("$Id: compat.c,v 1.6 2000/04/12 08:45:06 damien Exp $");
32 32
33#include "ssh.h" 33#include "ssh.h"
34#include "packet.h" 34#include "packet.h"
@@ -58,9 +58,7 @@ compat_datafellows(const char *version)
58 size_t len; 58 size_t len;
59 static const char *check[] = { 59 static const char *check[] = {
60 "2.0.1", 60 "2.0.1",
61 "2.1.0.beta.9", 61 "2.1.0",
62 "2.1.0.pre.3",
63 "2.1.0.public.beta.1",
64 NULL 62 NULL
65 }; 63 };
66 for (i = 0; check[i]; i++) { 64 for (i = 0; check[i]; i++) {
diff --git a/servconf.c b/servconf.c
index b08ac671f..800c4d5f4 100644
--- a/servconf.c
+++ b/servconf.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$Id: servconf.c,v 1.9 2000/03/09 10:27:51 damien Exp $"); 15RCSID("$Id: servconf.c,v 1.10 2000/04/12 08:45:06 damien Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "servconf.h" 18#include "servconf.h"
@@ -31,6 +31,7 @@ initialize_server_options(ServerOptions *options)
31 options->ports_from_cmdline = 0; 31 options->ports_from_cmdline = 0;
32 options->listen_addrs = NULL; 32 options->listen_addrs = NULL;
33 options->host_key_file = NULL; 33 options->host_key_file = NULL;
34 options->dsa_key_file = NULL;
34 options->server_key_bits = -1; 35 options->server_key_bits = -1;
35 options->login_grace_time = -1; 36 options->login_grace_time = -1;
36 options->key_regeneration_time = -1; 37 options->key_regeneration_time = -1;
@@ -78,6 +79,8 @@ fill_default_server_options(ServerOptions *options)
78 add_listen_addr(options, NULL); 79 add_listen_addr(options, NULL);
79 if (options->host_key_file == NULL) 80 if (options->host_key_file == NULL)
80 options->host_key_file = HOST_KEY_FILE; 81 options->host_key_file = HOST_KEY_FILE;
82 if (options->dsa_key_file == NULL)
83 options->dsa_key_file = DSA_KEY_FILE;
81 if (options->server_key_bits == -1) 84 if (options->server_key_bits == -1)
82 options->server_key_bits = 768; 85 options->server_key_bits = 768;
83 if (options->login_grace_time == -1) 86 if (options->login_grace_time == -1)
@@ -159,7 +162,7 @@ typedef enum {
159 sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, 162 sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
160 sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, 163 sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
161 sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, 164 sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
162 sIgnoreUserKnownHosts 165 sIgnoreUserKnownHosts, sDSAKeyFile
163} ServerOpCodes; 166} ServerOpCodes;
164 167
165/* Textual representation of the tokens. */ 168/* Textual representation of the tokens. */
@@ -169,6 +172,7 @@ static struct {
169} keywords[] = { 172} keywords[] = {
170 { "port", sPort }, 173 { "port", sPort },
171 { "hostkey", sHostKeyFile }, 174 { "hostkey", sHostKeyFile },
175 { "dsakey", sDSAKeyFile },
172 { "serverkeybits", sServerKeyBits }, 176 { "serverkeybits", sServerKeyBits },
173 { "logingracetime", sLoginGraceTime }, 177 { "logingracetime", sLoginGraceTime },
174 { "keyregenerationinterval", sKeyRegenerationTime }, 178 { "keyregenerationinterval", sKeyRegenerationTime },
@@ -338,7 +342,9 @@ parse_int:
338 break; 342 break;
339 343
340 case sHostKeyFile: 344 case sHostKeyFile:
341 charptr = &options->host_key_file; 345 case sDSAKeyFile:
346 charptr = (opcode == sHostKeyFile ) ?
347 &options->host_key_file : &options->dsa_key_file;
342 cp = strtok(NULL, WHITESPACE); 348 cp = strtok(NULL, WHITESPACE);
343 if (!cp) { 349 if (!cp) {
344 fprintf(stderr, "%s line %d: missing file name.\n", 350 fprintf(stderr, "%s line %d: missing file name.\n",
diff --git a/servconf.h b/servconf.h
index ab5c22c7d..5ce3f1594 100644
--- a/servconf.h
+++ b/servconf.h
@@ -13,7 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$Id: servconf.h,v 1.6 2000/01/14 04:45:51 damien Exp $"); */ 16/* RCSID("$Id: servconf.h,v 1.7 2000/04/12 08:45:07 damien Exp $"); */
17 17
18#ifndef SERVCONF_H 18#ifndef SERVCONF_H
19#define SERVCONF_H 19#define SERVCONF_H
@@ -32,6 +32,7 @@ typedef struct {
32 char *listen_addr; /* Address on which the server listens. */ 32 char *listen_addr; /* Address on which the server listens. */
33 struct addrinfo *listen_addrs; /* Addresses on which the server listens. */ 33 struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
34 char *host_key_file; /* File containing host key. */ 34 char *host_key_file; /* File containing host key. */
35 char *dsa_key_file; /* File containing dsa host key. */
35 int server_key_bits;/* Size of the server key. */ 36 int server_key_bits;/* Size of the server key. */
36 int login_grace_time; /* Disconnect if no auth in this time 37 int login_grace_time; /* Disconnect if no auth in this time
37 * (sec). */ 38 * (sec). */
diff --git a/serverloop.c b/serverloop.c
index 8bf448ceb..0ea57faa0 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -5,6 +5,10 @@
5 * Created: Sun Sep 10 00:30:37 1995 ylo 5 * Created: Sun Sep 10 00:30:37 1995 ylo
6 * Server main loop for handling the interactive session. 6 * Server main loop for handling the interactive session.
7 */ 7 */
8/*
9 * SSH2 support by Markus Friedl.
10 * Copyright (c) 2000 Markus Friedl. All rights reserved.
11 */
8 12
9#include "includes.h" 13#include "includes.h"
10#include "xmalloc.h" 14#include "xmalloc.h"
@@ -16,6 +20,8 @@
16#include "channels.h" 20#include "channels.h"
17 21
18#include "compat.h" 22#include "compat.h"
23#include "ssh2.h"
24#include "session.h"
19#include "dispatch.h" 25#include "dispatch.h"
20 26
21static Buffer stdin_buffer; /* Buffer for stdin data. */ 27static Buffer stdin_buffer; /* Buffer for stdin data. */
@@ -72,6 +78,15 @@ sigchld_handler(int sig)
72 signal(SIGCHLD, sigchld_handler); 78 signal(SIGCHLD, sigchld_handler);
73 errno = save_errno; 79 errno = save_errno;
74} 80}
81void
82sigchld_handler2(int sig)
83{
84 int save_errno = errno;
85 debug("Received SIGCHLD.");
86 child_terminated = 1;
87 signal(SIGCHLD, sigchld_handler2);
88 errno = save_errno;
89}
75 90
76/* 91/*
77 * Make packets from buffered stderr data, and buffer it for sending 92 * Make packets from buffered stderr data, and buffer it for sending
@@ -154,15 +169,21 @@ retry_select:
154 * Read packets from the client unless we have too much buffered 169 * Read packets from the client unless we have too much buffered
155 * stdin or channel data. 170 * stdin or channel data.
156 */ 171 */
157 if (buffer_len(&stdin_buffer) < 4096 && 172 if (compat20) {
158 channel_not_very_much_buffered_data()) 173 // wrong: bad conditionXXX
159 FD_SET(connection_in, readset); 174 if (channel_not_very_much_buffered_data())
175 FD_SET(connection_in, readset);
176 } else {
177 if (buffer_len(&stdin_buffer) < 4096 &&
178 channel_not_very_much_buffered_data())
179 FD_SET(connection_in, readset);
180 }
160 181
161 /* 182 /*
162 * If there is not too much data already buffered going to the 183 * If there is not too much data already buffered going to the
163 * client, try to get some more data from the program. 184 * client, try to get some more data from the program.
164 */ 185 */
165 if (packet_not_very_much_data_to_write()) { 186 if (!compat20 && packet_not_very_much_data_to_write()) {
166 if (!fdout_eof) 187 if (!fdout_eof)
167 FD_SET(fdout, readset); 188 FD_SET(fdout, readset);
168 if (!fderr_eof) 189 if (!fderr_eof)
@@ -182,7 +203,7 @@ retry_select:
182 203
183 /* If we have buffered data, try to write some of that data to the 204 /* If we have buffered data, try to write some of that data to the
184 program. */ 205 program. */
185 if (fdin != -1 && buffer_len(&stdin_buffer) > 0) 206 if (!compat20 && fdin != -1 && buffer_len(&stdin_buffer) > 0)
186 FD_SET(fdin, writeset); 207 FD_SET(fdin, writeset);
187 208
188 /* Update the maximum descriptor number if appropriate. */ 209 /* Update the maximum descriptor number if appropriate. */
@@ -204,6 +225,8 @@ retry_select:
204 tv.tv_usec = 1000 * (max_time_milliseconds % 1000); 225 tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
205 tvp = &tv; 226 tvp = &tv;
206 } 227 }
228 if (tvp!=NULL)
229 debug("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
207 230
208 /* Wait for something to happen, or the timeout to expire. */ 231 /* Wait for something to happen, or the timeout to expire. */
209 ret = select(max_fd + 1, readset, writeset, NULL, tvp); 232 ret = select(max_fd + 1, readset, writeset, NULL, tvp);
@@ -250,6 +273,9 @@ process_input(fd_set * readset)
250 /* Buffer any received data. */ 273 /* Buffer any received data. */
251 packet_process_incoming(buf, len); 274 packet_process_incoming(buf, len);
252 } 275 }
276 if (compat20)
277 return;
278
253 /* Read and buffer any available stdout data from the program. */ 279 /* Read and buffer any available stdout data from the program. */
254 if (!fdout_eof && FD_ISSET(fdout, readset)) { 280 if (!fdout_eof && FD_ISSET(fdout, readset)) {
255 len = read(fdout, buf, sizeof(buf)); 281 len = read(fdout, buf, sizeof(buf));
@@ -279,7 +305,7 @@ process_output(fd_set * writeset)
279 int len; 305 int len;
280 306
281 /* Write buffered data to program stdin. */ 307 /* Write buffered data to program stdin. */
282 if (fdin != -1 && FD_ISSET(fdin, writeset)) { 308 if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
283 len = write(fdin, buffer_ptr(&stdin_buffer), 309 len = write(fdin, buffer_ptr(&stdin_buffer),
284 buffer_len(&stdin_buffer)); 310 buffer_len(&stdin_buffer));
285 if (len <= 0) { 311 if (len <= 0) {
@@ -578,6 +604,51 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
578 /* NOTREACHED */ 604 /* NOTREACHED */
579} 605}
580 606
607void
608server_loop2(void)
609{
610 fd_set readset, writeset;
611 int had_channel = 0;
612 int status;
613 pid_t pid;
614
615 debug("Entering interactive session for SSH2.");
616
617 signal(SIGCHLD, sigchld_handler2);
618 child_terminated = 0;
619 connection_in = packet_get_connection_in();
620 connection_out = packet_get_connection_out();
621 max_fd = connection_in;
622 if (connection_out > max_fd)
623 max_fd = connection_out;
624 server_init_dispatch();
625
626 for (;;) {
627 process_buffered_input_packets();
628 if (!had_channel && channel_still_open())
629 had_channel = 1;
630 if (had_channel && !channel_still_open()) {
631 debug("!channel_still_open.");
632 break;
633 }
634 if (packet_not_very_much_data_to_write())
635 channel_output_poll();
636 wait_until_can_do_something(&readset, &writeset, 0);
637 if (child_terminated) {
638 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
639 session_close_by_pid(pid, status);
640 child_terminated = 0;
641 }
642 channel_after_select(&readset, &writeset);
643 process_input(&readset);
644 process_output(&writeset);
645 }
646 signal(SIGCHLD, SIG_DFL);
647 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
648 session_close_by_pid(pid, status);
649 channel_stop_listening();
650}
651
581void 652void
582server_input_stdin_data(int type, int plen) 653server_input_stdin_data(int type, int plen)
583{ 654{
@@ -622,6 +693,111 @@ server_input_window_size(int type, int plen)
622 pty_change_window_size(fdin, row, col, xpixel, ypixel); 693 pty_change_window_size(fdin, row, col, xpixel, ypixel);
623} 694}
624 695
696int
697input_direct_tcpip(void)
698{
699 int sock;
700 char *host, *originator;
701 int host_port, originator_port;
702
703 host = packet_get_string(NULL);
704 host_port = packet_get_int();
705 originator = packet_get_string(NULL);
706 originator_port = packet_get_int();
707 /* XXX check permission */
708 sock = channel_connect_to(host, host_port);
709 xfree(host);
710 xfree(originator);
711 if (sock < 0)
712 return -1;
713 return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
714 sock, sock, -1, 4*1024, 32*1024, 0, xstrdup("direct-tcpip"));
715}
716
717void
718server_input_channel_open(int type, int plen)
719{
720 Channel *c = NULL;
721 char *ctype;
722 int id;
723 unsigned int len;
724 int rchan;
725 int rmaxpack;
726 int rwindow;
727
728 ctype = packet_get_string(&len);
729 rchan = packet_get_int();
730 rwindow = packet_get_int();
731 rmaxpack = packet_get_int();
732
733 log("channel_input_open: ctype %s rchan %d win %d max %d",
734 ctype, rchan, rwindow, rmaxpack);
735
736 if (strcmp(ctype, "session") == 0) {
737 debug("open session");
738 /*
739 * A server session has no fd to read or write
740 * until a CHANNEL_REQUEST for a shell is made,
741 * so we set the type to SSH_CHANNEL_LARVAL.
742 * Additionally, a callback for handling all
743 * CHANNEL_REQUEST messages is registered.
744 */
745 id = channel_new(ctype, SSH_CHANNEL_LARVAL,
746 -1, -1, -1, 0, 32*1024, 0, xstrdup("server-session"));
747 if (session_open(id) == 1) {
748 channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
749 session_input_channel_req, (void *)0);
750 channel_register_cleanup(id, session_close_by_channel);
751 c = channel_lookup(id);
752 } else {
753 debug("session open failed, free channel %d", id);
754 channel_free(id);
755 }
756 } else if (strcmp(ctype, "direct-tcpip") == 0) {
757 debug("open direct-tcpip");
758 id = input_direct_tcpip();
759 if (id >= 0)
760 c = channel_lookup(id);
761 }
762 if (c != NULL) {
763 debug("confirm %s", ctype);
764 c->remote_id = rchan;
765 c->remote_window = rwindow;
766 c->remote_maxpacket = rmaxpack;
767
768 packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
769 packet_put_int(c->remote_id);
770 packet_put_int(c->self);
771 packet_put_int(c->local_window);
772 packet_put_int(c->local_maxpacket);
773 packet_send();
774 } else {
775 debug("failure %s", ctype);
776 packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
777 packet_put_int(rchan);
778 packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
779 packet_put_cstring("bla bla");
780 packet_put_cstring("");
781 packet_send();
782 }
783 xfree(ctype);
784}
785
786void
787server_init_dispatch_20()
788{
789 debug("server_init_dispatch_20");
790 dispatch_init(&dispatch_protocol_error);
791 dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
792 dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
793 dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
794 dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
795 dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
796 dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
797 dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
798 dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
799 dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
800}
625void 801void
626server_init_dispatch_13() 802server_init_dispatch_13()
627{ 803{
@@ -648,7 +824,9 @@ server_init_dispatch_15()
648void 824void
649server_init_dispatch() 825server_init_dispatch()
650{ 826{
651 if (compat13) 827 if (compat20)
828 server_init_dispatch_20();
829 else if (compat13)
652 server_init_dispatch_13(); 830 server_init_dispatch_13();
653 else 831 else
654 server_init_dispatch_15(); 832 server_init_dispatch_15();
diff --git a/session.c b/session.c
index 2128fe394..835a46945 100644
--- a/session.c
+++ b/session.c
@@ -2,9 +2,13 @@
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved 3 * All rights reserved
4 */ 4 */
5/*
6 * SSH2 support by Markus Friedl.
7 * Copyright (c) 2000 Markus Friedl. All rights reserved.
8 */
5 9
6#include "includes.h" 10#include "includes.h"
7RCSID("$OpenBSD: session.c,v 1.1 2000/03/28 21:15:45 markus Exp $"); 11RCSID("$OpenBSD: session.c,v 1.2 2000/04/06 08:55:22 markus Exp $");
8 12
9#include "xmalloc.h" 13#include "xmalloc.h"
10#include "ssh.h" 14#include "ssh.h"
@@ -19,6 +23,10 @@ RCSID("$OpenBSD: session.c,v 1.1 2000/03/28 21:15:45 markus Exp $");
19#include "channels.h" 23#include "channels.h"
20#include "nchan.h" 24#include "nchan.h"
21 25
26#include "bufaux.h"
27#include "ssh2.h"
28#include "auth.h"
29
22/* types */ 30/* types */
23 31
24#define TTYSZ 64 32#define TTYSZ 64
@@ -448,9 +456,13 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
448 close(pout[1]); 456 close(pout[1]);
449 close(perr[1]); 457 close(perr[1]);
450 458
451 /* Enter the interactive session. */ 459 if (compat20) {
452 server_loop(pid, pin[1], pout[0], perr[0]); 460 session_set_fds(s, pin[1], pout[0], perr[0]);
453 /* server_loop has closed pin[1], pout[1], and perr[1]. */ 461 } else {
462 /* Enter the interactive session. */
463 server_loop(pid, pin[1], pout[0], perr[0]);
464 /* server_loop has closed pin[1], pout[1], and perr[1]. */
465 }
454#else /* USE_PIPES */ 466#else /* USE_PIPES */
455 /* We are the parent. Close the child sides of the socket pairs. */ 467 /* We are the parent. Close the child sides of the socket pairs. */
456 close(inout[0]); 468 close(inout[0]);
@@ -460,8 +472,12 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
460 * Enter the interactive session. Note: server_loop must be able to 472 * Enter the interactive session. Note: server_loop must be able to
461 * handle the case that fdin and fdout are the same. 473 * handle the case that fdin and fdout are the same.
462 */ 474 */
463 server_loop(pid, inout[1], inout[1], err[1]); 475 if (compat20) {
464 /* server_loop has closed inout[1] and err[1]. */ 476 session_set_fds(s, inout[1], inout[1], err[1]);
477 } else {
478 server_loop(pid, inout[1], inout[1], err[1]);
479 /* server_loop has closed inout[1] and err[1]. */
480 }
465#endif /* USE_PIPES */ 481#endif /* USE_PIPES */
466} 482}
467 483
@@ -631,9 +647,13 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
631 s->ptymaster = ptymaster; 647 s->ptymaster = ptymaster;
632 648
633 /* Enter interactive session. */ 649 /* Enter interactive session. */
634 server_loop(pid, ptyfd, fdout, -1); 650 if (compat20) {
635 /* server_loop _has_ closed ptyfd and fdout. */ 651 session_set_fds(s, ptyfd, fdout, -1);
636 session_pty_cleanup(s); 652 } else {
653 server_loop(pid, ptyfd, fdout, -1);
654 /* server_loop _has_ closed ptyfd and fdout. */
655 session_pty_cleanup(s);
656 }
637} 657}
638 658
639/* 659/*
@@ -1126,6 +1146,181 @@ session_dump(void)
1126 } 1146 }
1127} 1147}
1128 1148
1149int
1150session_open(int chanid)
1151{
1152 Session *s = session_new();
1153 debug("session_open: channel %d", chanid);
1154 if (s == NULL) {
1155 error("no more sessions");
1156 return 0;
1157 }
1158 debug("session_open: session %d: link with channel %d", s->self, chanid);
1159 s->chanid = chanid;
1160 s->pw = auth_get_user();
1161 if (s->pw == NULL)
1162 fatal("no user for session %i channel %d",
1163 s->self, s->chanid);
1164 return 1;
1165}
1166
1167Session *
1168session_by_channel(int id)
1169{
1170 int i;
1171 for(i = 0; i < MAX_SESSIONS; i++) {
1172 Session *s = &sessions[i];
1173 if (s->used && s->chanid == id) {
1174 debug("session_by_channel: session %d channel %d", i, id);
1175 return s;
1176 }
1177 }
1178 debug("session_by_channel: unknown channel %d", id);
1179 session_dump();
1180 return NULL;
1181}
1182
1183Session *
1184session_by_pid(pid_t pid)
1185{
1186 int i;
1187 debug("session_by_pid: pid %d", pid);
1188 for(i = 0; i < MAX_SESSIONS; i++) {
1189 Session *s = &sessions[i];
1190 if (s->used && s->pid == pid)
1191 return s;
1192 }
1193 error("session_by_pid: unknown pid %d", pid);
1194 session_dump();
1195 return NULL;
1196}
1197
1198int
1199session_window_change_req(Session *s)
1200{
1201 s->col = packet_get_int();
1202 s->row = packet_get_int();
1203 s->xpixel = packet_get_int();
1204 s->ypixel = packet_get_int();
1205 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1206 return 1;
1207}
1208
1209int
1210session_pty_req(Session *s)
1211{
1212 unsigned int len;
1213
1214 if (s->ttyfd != -1)
1215 return -1;
1216 s->term = packet_get_string(&len);
1217 s->col = packet_get_int();
1218 s->row = packet_get_int();
1219 s->xpixel = packet_get_int();
1220 s->ypixel = packet_get_int();
1221
1222 if (strcmp(s->term, "") == 0) {
1223 xfree(s->term);
1224 s->term = NULL;
1225 }
1226 /* Allocate a pty and open it. */
1227 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
1228 xfree(s->term);
1229 s->term = NULL;
1230 s->ptyfd = -1;
1231 s->ttyfd = -1;
1232 error("session_pty_req: session %d alloc failed", s->self);
1233 return -1;
1234 }
1235 debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1236 /*
1237 * Add a cleanup function to clear the utmp entry and record logout
1238 * time in case we call fatal() (e.g., the connection gets closed).
1239 */
1240 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
1241 pty_setowner(s->pw, s->tty);
1242 /* Get window size from the packet. */
1243 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1244
1245 return 1;
1246}
1247
1248void
1249session_input_channel_req(int id, void *arg)
1250{
1251 unsigned int len;
1252 int reply;
1253 int success = 0;
1254 char *rtype;
1255 Session *s;
1256 Channel *c;
1257
1258 rtype = packet_get_string(&len);
1259 reply = packet_get_char();
1260
1261 s = session_by_channel(id);
1262 if (s == NULL)
1263 fatal("session_input_channel_req: channel %d: no session", id);
1264 c = channel_lookup(id);
1265 if (c == NULL)
1266 fatal("session_input_channel_req: channel %d: bad channel", id);
1267
1268 debug("session_input_channel_req: session %d channel %d request %s reply %d",
1269 s->self, id, rtype, reply);
1270
1271 /*
1272 * a session is in LARVAL state until a shell
1273 * or programm is executed
1274 */
1275 if (c->type == SSH_CHANNEL_LARVAL) {
1276 if (strcmp(rtype, "shell") == 0) {
1277 if (s->ttyfd == -1)
1278 do_exec_no_pty(s, NULL, s->pw);
1279 else
1280 do_exec_pty(s, NULL, s->pw);
1281 success = 1;
1282 } else if (strcmp(rtype, "exec") == 0) {
1283 char *command = packet_get_string(&len);
1284 if (s->ttyfd == -1)
1285 do_exec_no_pty(s, command, s->pw);
1286 else
1287 do_exec_pty(s, command, s->pw);
1288 xfree(command);
1289 success = 1;
1290 } else if (strcmp(rtype, "pty-req") == 0) {
1291 if (session_pty_req(s) > 0)
1292 success = 1;
1293 }
1294 }
1295 if (strcmp(rtype, "window-change") == 0) {
1296 success = session_window_change_req(s);
1297 }
1298
1299 if (reply) {
1300 packet_start(success ?
1301 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
1302 packet_put_int(c->remote_id);
1303 packet_send();
1304 }
1305 xfree(rtype);
1306}
1307
1308void
1309session_set_fds(Session *s, int fdin, int fdout, int fderr)
1310{
1311 if (!compat20)
1312 fatal("session_set_fds: called for proto != 2.0");
1313 /*
1314 * now that have a child and a pipe to the child,
1315 * we can activate our channel and register the fd's
1316 */
1317 if (s->chanid == -1)
1318 fatal("no channel for session %d", s->self);
1319 channel_set_fds(s->chanid,
1320 fdout, fdin, fderr,
1321 fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ);
1322}
1323
1129void 1324void
1130session_pty_cleanup(Session *s) 1325session_pty_cleanup(Session *s)
1131{ 1326{
@@ -1151,3 +1346,118 @@ session_pty_cleanup(Session *s)
1151 if (close(s->ptymaster) < 0) 1346 if (close(s->ptymaster) < 0)
1152 error("close(s->ptymaster): %s", strerror(errno)); 1347 error("close(s->ptymaster): %s", strerror(errno));
1153} 1348}
1349
1350void
1351session_exit_message(Session *s, int status)
1352{
1353 Channel *c;
1354 if (s == NULL)
1355 fatal("session_close: no session");
1356 c = channel_lookup(s->chanid);
1357 if (c == NULL)
1358 fatal("session_close: session %d: no channel %d",
1359 s->self, s->chanid);
1360 debug("session_exit_message: session %d channel %d pid %d",
1361 s->self, s->chanid, s->pid);
1362
1363 if (WIFEXITED(status)) {
1364 channel_request_start(s->chanid,
1365 "exit-status", 0);
1366 packet_put_int(WEXITSTATUS(status));
1367 packet_send();
1368 } else if (WIFSIGNALED(status)) {
1369 channel_request_start(s->chanid,
1370 "exit-signal", 0);
1371 packet_put_int(WTERMSIG(status));
1372 packet_put_char(WCOREDUMP(status));
1373 packet_put_cstring("");
1374 packet_put_cstring("");
1375 packet_send();
1376 } else {
1377 /* Some weird exit cause. Just exit. */
1378 packet_disconnect("wait returned status %04x.", status);
1379 }
1380
1381 /* disconnect channel */
1382 debug("session_exit_message: release channel %d", s->chanid);
1383 channel_cancel_cleanup(s->chanid);
1384 if (c->istate == CHAN_INPUT_OPEN)
1385 chan_read_failed(c);
1386 chan_write_failed(c);
1387 s->chanid = -1;
1388}
1389
1390void
1391session_free(Session *s)
1392{
1393 debug("session_free: session %d pid %d", s->self, s->pid);
1394 if (s->term)
1395 xfree(s->term);
1396 if (s->display)
1397 xfree(s->display);
1398 if (s->auth_data)
1399 xfree(s->auth_data);
1400 if (s->auth_proto)
1401 xfree(s->auth_proto);
1402 s->used = 0;
1403}
1404
1405void
1406session_close(Session *s)
1407{
1408 session_pty_cleanup(s);
1409 session_free(s);
1410}
1411
1412void
1413session_close_by_pid(pid_t pid, int status)
1414{
1415 Session *s = session_by_pid(pid);
1416 if (s == NULL) {
1417 debug("session_close_by_pid: no session for pid %d", s->pid);
1418 return;
1419 }
1420 if (s->chanid != -1)
1421 session_exit_message(s, status);
1422 session_close(s);
1423}
1424
1425/*
1426 * this is called when a channel dies before
1427 * the session 'child' itself dies
1428 */
1429void
1430session_close_by_channel(int id, void *arg)
1431{
1432 Session *s = session_by_channel(id);
1433 if (s == NULL) {
1434 debug("session_close_by_channel: no session for channel %d", id);
1435 return;
1436 }
1437 /* disconnect channel */
1438 channel_cancel_cleanup(s->chanid);
1439 s->chanid = -1;
1440
1441 debug("session_close_by_channel: channel %d kill %d", id, s->pid);
1442 if (s->pid == 0) {
1443 /* close session immediately */
1444 session_close(s);
1445 } else {
1446 /* notify child, delay session cleanup */
1447 if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
1448 error("session_close_by_channel: kill %d: %s",
1449 s->pid, strerror(errno));
1450 }
1451}
1452
1453void
1454do_authenticated2(void)
1455{
1456 /*
1457 * Cancel the alarm we set to limit the time taken for
1458 * authentication.
1459 */
1460 alarm(0);
1461 log("do_authenticated2");
1462 server_loop2();
1463}
diff --git a/session.h b/session.h
index 2051b737d..a3427bcb0 100644
--- a/session.h
+++ b/session.h
@@ -4,4 +4,11 @@
4/* SSH1 */ 4/* SSH1 */
5void do_authenticated(struct passwd * pw); 5void do_authenticated(struct passwd * pw);
6 6
7/* SSH2 */
8void do_authenticated2(void);
9int session_open(int id);
10void session_input_channel_req(int id, void *arg);
11void session_close_by_pid(pid_t pid, int status);
12void session_close_by_channel(int id, void *arg);
13
7#endif 14#endif
diff --git a/ssh.h b/ssh.h
index cc8940b53..7c5bf9c52 100644
--- a/ssh.h
+++ b/ssh.h
@@ -13,7 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$Id: ssh.h,v 1.29 2000/04/01 01:09:26 damien Exp $"); */ 16/* RCSID("$Id: ssh.h,v 1.30 2000/04/12 08:45:07 damien Exp $"); */
17 17
18#ifndef SSH_H 18#ifndef SSH_H
19#define SSH_H 19#define SSH_H
@@ -90,6 +90,7 @@
90#define HOST_KEY_FILE ETCDIR "/ssh_host_key" 90#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
91#define SERVER_CONFIG_FILE ETCDIR "/sshd_config" 91#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
92#define HOST_CONFIG_FILE ETCDIR "/ssh_config" 92#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
93#define DSA_KEY_FILE ETCDIR "/ssh_dsa_key"
93 94
94#ifndef SSH_PROGRAM 95#ifndef SSH_PROGRAM
95#define SSH_PROGRAM "/usr/bin/ssh" 96#define SSH_PROGRAM "/usr/bin/ssh"
@@ -486,6 +487,8 @@ void fatal_add_cleanup(void (*proc) (void *context), void *context);
486/* Removes a cleanup function to be called at fatal(). */ 487/* Removes a cleanup function to be called at fatal(). */
487void fatal_remove_cleanup(void (*proc) (void *context), void *context); 488void fatal_remove_cleanup(void (*proc) (void *context), void *context);
488 489
490/* ---- misc */
491
489/* 492/*
490 * Expands tildes in the file name. Returns data allocated by xmalloc. 493 * Expands tildes in the file name. Returns data allocated by xmalloc.
491 * Warning: this calls getpw*. 494 * Warning: this calls getpw*.
@@ -500,6 +503,7 @@ char *tilde_expand_filename(const char *filename, uid_t my_uid);
500 * program). 503 * program).
501 */ 504 */
502void server_loop(int pid, int fdin, int fdout, int fderr); 505void server_loop(int pid, int fdin, int fdout, int fderr);
506void server_loop2(void);
503 507
504/* Client side main loop for the interactive session. */ 508/* Client side main loop for the interactive session. */
505int client_loop(int have_pty, int escape_char); 509int client_loop(int have_pty, int escape_char);
diff --git a/sshd.c b/sshd.c
index bb5685dc4..44782e397 100644
--- a/sshd.c
+++ b/sshd.c
@@ -8,10 +8,13 @@
8 * information to/from the application to the user client over an encrypted 8 * information to/from the application to the user client over an encrypted
9 * connection. This can also handle forwarding of X11, TCP/IP, and authentication 9 * connection. This can also handle forwarding of X11, TCP/IP, and authentication
10 * agent connections. 10 * agent connections.
11 *
12 * SSH2 implementation,
13 * Copyright (c) 2000 Markus Friedl. All rights reserved.
11 */ 14 */
12 15
13#include "includes.h" 16#include "includes.h"
14RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); 17RCSID("$OpenBSD: sshd.c,v 1.99 2000/04/07 09:17:39 markus Exp $");
15 18
16#include "xmalloc.h" 19#include "xmalloc.h"
17#include "rsa.h" 20#include "rsa.h"
@@ -25,6 +28,7 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $");
25#include "compat.h" 28#include "compat.h"
26#include "buffer.h" 29#include "buffer.h"
27 30
31#include "ssh2.h"
28#ifdef HAVE_OPENSSL 32#ifdef HAVE_OPENSSL
29# include <openssl/dh.h> 33# include <openssl/dh.h>
30# include <openssl/bn.h> 34# include <openssl/bn.h>
@@ -39,9 +43,12 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $");
39# include <ssl/dsa.h> 43# include <ssl/dsa.h>
40# include <ssl/rsa.h> 44# include <ssl/rsa.h>
41#endif 45#endif
46#include "kex.h"
42#include "key.h" 47#include "key.h"
48#include "dsa.h"
43 49
44#include "auth.h" 50#include "auth.h"
51#include "myproposal.h"
45 52
46#ifdef LIBWRAP 53#ifdef LIBWRAP
47#include <tcpd.h> 54#include <tcpd.h>
@@ -70,6 +77,9 @@ int IPv4or6 = AF_INET;
70int IPv4or6 = AF_UNSPEC; 77int IPv4or6 = AF_UNSPEC;
71#endif 78#endif
72 79
80/* Flag indicating whether SSH2 is enabled */
81int allow_ssh2 = 0;
82
73/* 83/*
74 * Debug mode flag. This can be set on the command line. If debug 84 * Debug mode flag. This can be set on the command line. If debug
75 * mode is enabled, extra debugging output will be sent to the system 85 * mode is enabled, extra debugging output will be sent to the system
@@ -136,6 +146,7 @@ unsigned char session_id[16];
136 146
137/* Prototypes for various functions defined later in this file. */ 147/* Prototypes for various functions defined later in this file. */
138void do_ssh1_kex(); 148void do_ssh1_kex();
149void do_ssh2_kex();
139 150
140/* 151/*
141 * Close all listening sockets 152 * Close all listening sockets
@@ -255,6 +266,21 @@ key_regeneration_alarm(int sig)
255 errno = save_errno; 266 errno = save_errno;
256} 267}
257 268
269char *
270chop(char *s)
271{
272 char *t = s;
273 while (*t) {
274 if(*t == '\n' || *t == '\r') {
275 *t = '\0';
276 return s;
277 }
278 t++;
279 }
280 return s;
281
282}
283
258void 284void
259sshd_exchange_identification(int sock_in, int sock_out) 285sshd_exchange_identification(int sock_in, int sock_out)
260{ 286{
@@ -265,7 +291,9 @@ sshd_exchange_identification(int sock_in, int sock_out)
265 char remote_version[256]; /* Must be at least as big as buf. */ 291 char remote_version[256]; /* Must be at least as big as buf. */
266 292
267 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 293 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
268 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); 294 allow_ssh2 ? 1 : PROTOCOL_MAJOR,
295 allow_ssh2 ? 99 : PROTOCOL_MINOR,
296 SSH_VERSION);
269 server_version_string = xstrdup(buf); 297 server_version_string = xstrdup(buf);
270 298
271 if (client_version_string == NULL) { 299 if (client_version_string == NULL) {
@@ -286,7 +314,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
286 buf[i] = '\n'; 314 buf[i] = '\n';
287 buf[i + 1] = 0; 315 buf[i + 1] = 0;
288 continue; 316 continue;
289 /*break; XXX eat \r */ 317 //break;
290 } 318 }
291 if (buf[i] == '\n') { 319 if (buf[i] == '\n') {
292 /* buf[i] == '\n' */ 320 /* buf[i] == '\n' */
@@ -315,6 +343,8 @@ sshd_exchange_identification(int sock_in, int sock_out)
315 debug("Client protocol version %d.%d; client software version %.100s", 343 debug("Client protocol version %d.%d; client software version %.100s",
316 remote_major, remote_minor, remote_version); 344 remote_major, remote_minor, remote_version);
317 345
346 compat_datafellows(remote_version);
347
318 switch(remote_major) { 348 switch(remote_major) {
319 case 1: 349 case 1:
320 if (remote_minor < 3) { 350 if (remote_minor < 3) {
@@ -324,7 +354,15 @@ sshd_exchange_identification(int sock_in, int sock_out)
324 /* note that this disables agent-forwarding */ 354 /* note that this disables agent-forwarding */
325 enable_compat13(); 355 enable_compat13();
326 } 356 }
327 break; 357 if (remote_minor != 99)
358 break;
359 /* FALLTHROUGH */
360 case 2:
361 if (allow_ssh2) {
362 enable_compat20();
363 break;
364 }
365 /* FALLTHROUGH */
328 default: 366 default:
329 s = "Protocol major versions differ.\n"; 367 s = "Protocol major versions differ.\n";
330 (void) atomicio(write, sock_out, s, strlen(s)); 368 (void) atomicio(write, sock_out, s, strlen(s));
@@ -335,6 +373,8 @@ sshd_exchange_identification(int sock_in, int sock_out)
335 fatal_cleanup(); 373 fatal_cleanup();
336 break; 374 break;
337 } 375 }
376 chop(server_version_string);
377 chop(client_version_string);
338} 378}
339 379
340/* 380/*
@@ -370,8 +410,11 @@ main(int ac, char **av)
370 initialize_server_options(&options); 410 initialize_server_options(&options);
371 411
372 /* Parse command-line arguments. */ 412 /* Parse command-line arguments. */
373 while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) { 413 while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ246")) != EOF) {
374 switch (opt) { 414 switch (opt) {
415 case '2':
416 allow_ssh2 = 1;
417 break;
375 case '4': 418 case '4':
376 IPv4or6 = AF_INET; 419 IPv4or6 = AF_INET;
377 break; 420 break;
@@ -837,9 +880,14 @@ main(int ac, char **av)
837 packet_set_nonblocking(); 880 packet_set_nonblocking();
838 881
839 /* perform the key exchange */ 882 /* perform the key exchange */
840 do_ssh1_kex();
841 /* authenticate user and start session */ 883 /* authenticate user and start session */
842 do_authentication(); 884 if (compat20) {
885 do_ssh2_kex();
886 do_authentication2();
887 } else {
888 do_ssh1_kex();
889 do_authentication();
890 }
843 891
844#ifdef KRB4 892#ifdef KRB4
845 /* Cleanup user's ticket cache file. */ 893 /* Cleanup user's ticket cache file. */
@@ -1049,3 +1097,181 @@ do_ssh1_kex()
1049 packet_send(); 1097 packet_send();
1050 packet_write_wait(); 1098 packet_write_wait();
1051} 1099}
1100
1101/*
1102 * SSH2 key exchange: diffie-hellman-group1-sha1
1103 */
1104void
1105do_ssh2_kex()
1106{
1107 Buffer *server_kexinit;
1108 Buffer *client_kexinit;
1109 int payload_len, dlen;
1110 int slen;
1111 unsigned int klen, kout;
1112 char *ptr;
1113 unsigned char *signature = NULL;
1114 unsigned char *server_host_key_blob = NULL;
1115 unsigned int sbloblen;
1116 DH *dh;
1117 BIGNUM *dh_client_pub = 0;
1118 BIGNUM *shared_secret = 0;
1119 int i;
1120 unsigned char *kbuf;
1121 unsigned char *hash;
1122 Kex *kex;
1123 Key *server_host_key;
1124 char *cprop[PROPOSAL_MAX];
1125 char *sprop[PROPOSAL_MAX];
1126
1127/* KEXINIT */
1128
1129 debug("Sending KEX init.");
1130
1131 for (i = 0; i < PROPOSAL_MAX; i++)
1132 sprop[i] = xstrdup(myproposal[i]);
1133 server_kexinit = kex_init(sprop);
1134 packet_start(SSH2_MSG_KEXINIT);
1135 packet_put_raw(buffer_ptr(server_kexinit), buffer_len(server_kexinit));
1136 packet_send();
1137 packet_write_wait();
1138
1139 debug("done");
1140
1141 packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
1142
1143 /*
1144 * save raw KEXINIT payload in buffer. this is used during
1145 * computation of the session_id and the session keys.
1146 */
1147 client_kexinit = xmalloc(sizeof(*client_kexinit));
1148 buffer_init(client_kexinit);
1149 ptr = packet_get_raw(&payload_len);
1150 buffer_append(client_kexinit, ptr, payload_len);
1151
1152 /* skip cookie */
1153 for (i = 0; i < 16; i++)
1154 (void) packet_get_char();
1155 /* save kex init proposal strings */
1156 for (i = 0; i < PROPOSAL_MAX; i++) {
1157 cprop[i] = packet_get_string(NULL);
1158 debug("got kexinit string: %s", cprop[i]);
1159 }
1160
1161 i = (int) packet_get_char();
1162 debug("first kex follow == %d", i);
1163 i = packet_get_int();
1164 debug("reserved == %d", i);
1165
1166 debug("done read kexinit");
1167 kex = kex_choose_conf(cprop, sprop, 1);
1168
1169/* KEXDH */
1170
1171 debug("Wait SSH2_MSG_KEXDH_INIT.");
1172 packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT);
1173
1174 /* key, cert */
1175 dh_client_pub = BN_new();
1176 if (dh_client_pub == NULL)
1177 fatal("dh_client_pub == NULL");
1178 packet_get_bignum2(dh_client_pub, &dlen);
1179
1180#ifdef DEBUG_KEXDH
1181 fprintf(stderr, "\ndh_client_pub= ");
1182 bignum_print(dh_client_pub);
1183 fprintf(stderr, "\n");
1184 debug("bits %d", BN_num_bits(dh_client_pub));
1185#endif
1186
1187 /* generate DH key */
1188 dh = new_dh_group1(); /* XXX depends on 'kex' */
1189
1190#ifdef DEBUG_KEXDH
1191 fprintf(stderr, "\np= ");
1192 bignum_print(dh->p);
1193 fprintf(stderr, "\ng= ");
1194 bignum_print(dh->g);
1195 fprintf(stderr, "\npub= ");
1196 bignum_print(dh->pub_key);
1197 fprintf(stderr, "\n");
1198#endif
1199
1200 klen = DH_size(dh);
1201 kbuf = xmalloc(klen);
1202 kout = DH_compute_key(kbuf, dh_client_pub, dh);
1203
1204#ifdef DEBUG_KEXDH
1205 debug("shared secret: len %d/%d", klen, kout);
1206 fprintf(stderr, "shared secret == ");
1207 for (i = 0; i< kout; i++)
1208 fprintf(stderr, "%02x", (kbuf[i])&0xff);
1209 fprintf(stderr, "\n");
1210#endif
1211 shared_secret = BN_new();
1212
1213 BN_bin2bn(kbuf, kout, shared_secret);
1214 memset(kbuf, 0, klen);
1215 xfree(kbuf);
1216
1217 server_host_key = dsa_get_serverkey(options.dsa_key_file);
1218 dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen);
1219
1220 /* calc H */ /* XXX depends on 'kex' */
1221 hash = kex_hash(
1222 client_version_string,
1223 server_version_string,
1224 buffer_ptr(client_kexinit), buffer_len(client_kexinit),
1225 buffer_ptr(server_kexinit), buffer_len(server_kexinit),
1226 (char *)server_host_key_blob, sbloblen,
1227 dh_client_pub,
1228 dh->pub_key,
1229 shared_secret
1230 );
1231 buffer_free(client_kexinit);
1232 buffer_free(server_kexinit);
1233 xfree(client_kexinit);
1234 xfree(server_kexinit);
1235#ifdef DEBUG_KEXDH
1236 fprintf(stderr, "hash == ");
1237 for (i = 0; i< 20; i++)
1238 fprintf(stderr, "%02x", (hash[i])&0xff);
1239 fprintf(stderr, "\n");
1240#endif
1241 /* sign H */
1242 dsa_sign(server_host_key, &signature, &slen, hash, 20);
1243 /* hashlen depends on KEX */
1244 key_free(server_host_key);
1245
1246 /* send server hostkey, DH pubkey 'f' and singed H */
1247 packet_start(SSH2_MSG_KEXDH_REPLY);
1248 packet_put_string((char *)server_host_key_blob, sbloblen);
1249 packet_put_bignum2(dh->pub_key); // f
1250 packet_put_string((char *)signature, slen);
1251 packet_send();
1252 packet_write_wait();
1253
1254 kex_derive_keys(kex, hash, shared_secret);
1255 packet_set_kex(kex);
1256
1257 /* have keys, free DH */
1258 DH_free(dh);
1259
1260 debug("send SSH2_MSG_NEWKEYS.");
1261 packet_start(SSH2_MSG_NEWKEYS);
1262 packet_send();
1263 packet_write_wait();
1264 debug("done: send SSH2_MSG_NEWKEYS.");
1265
1266 debug("Wait SSH2_MSG_NEWKEYS.");
1267 packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
1268 debug("GOT SSH2_MSG_NEWKEYS.");
1269
1270 /* send 1st encrypted/maced/compressed message */
1271 packet_start(SSH2_MSG_IGNORE);
1272 packet_put_cstring("markus");
1273 packet_send();
1274 packet_write_wait();
1275
1276 debug("done: KEX2.");
1277}