diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | README.openssh2 | 36 | ||||
-rw-r--r-- | auth.c | 188 | ||||
-rw-r--r-- | auth.h | 4 | ||||
-rw-r--r-- | channels.c | 7 | ||||
-rw-r--r-- | compat.c | 6 | ||||
-rw-r--r-- | servconf.c | 12 | ||||
-rw-r--r-- | servconf.h | 3 | ||||
-rw-r--r-- | serverloop.c | 192 | ||||
-rw-r--r-- | session.c | 328 | ||||
-rw-r--r-- | session.h | 7 | ||||
-rw-r--r-- | ssh.h | 6 | ||||
-rw-r--r-- | sshd.c | 240 |
13 files changed, 1002 insertions, 37 deletions
@@ -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 | |||
6 | 20000406 | 14 | 20000406 |
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 | |||
3 | works: | ||
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) | ||
22 | todo: | ||
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 $ | ||
@@ -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" |
7 | RCSID("$OpenBSD: auth.c,v 1.1 2000/03/28 21:15:45 markus Exp $"); | 8 | RCSID("$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 */ |
25 | extern ServerOptions options; | 31 | extern ServerOptions options; |
26 | extern char *forced_command; | 32 | extern 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 | |||
615 | void input_service_request(int type, int plen); | ||
616 | void input_userauth_request(int type, int plen); | ||
617 | void ssh2_pty_cleanup(void); | ||
618 | |||
619 | typedef struct Authctxt Authctxt; | ||
620 | struct Authctxt { | ||
621 | char *user; | ||
622 | char *service; | ||
623 | struct passwd pw; | ||
624 | int valid; | ||
625 | }; | ||
626 | static Authctxt *authctxt = NULL; | ||
627 | static int userauth_success = 0; | ||
628 | |||
629 | struct passwd* | ||
630 | auth_get_user(void) | ||
631 | { | ||
632 | return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL; | ||
633 | } | ||
634 | struct passwd* | ||
635 | auth_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 | |||
673 | static void | ||
674 | protocol_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 | } | ||
682 | void | ||
683 | input_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 | } | ||
709 | void | ||
710 | input_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 | } | ||
785 | void | ||
786 | do_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 | } | ||
@@ -2,5 +2,9 @@ | |||
2 | #define AUTH_H | 2 | #define AUTH_H |
3 | 3 | ||
4 | void do_authentication(void); | 4 | void do_authentication(void); |
5 | void do_authentication2(void); | ||
6 | |||
7 | struct passwd * | ||
8 | auth_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" |
20 | RCSID("$Id: channels.c,v 1.22 2000/04/06 02:32:38 damien Exp $"); | 20 | RCSID("$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) | |||
674 | int | 674 | int |
675 | channel_check_window(Channel *c, fd_set * readset, fd_set * writeset) | 675 | channel_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 | } |
@@ -28,7 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include "includes.h" | 30 | #include "includes.h" |
31 | RCSID("$Id: compat.c,v 1.5 2000/04/06 02:32:39 damien Exp $"); | 31 | RCSID("$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" |
15 | RCSID("$Id: servconf.c,v 1.9 2000/03/09 10:27:51 damien Exp $"); | 15 | RCSID("$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 | ||
21 | static Buffer stdin_buffer; /* Buffer for stdin data. */ | 27 | static 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 | } |
81 | void | ||
82 | sigchld_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 | ||
607 | void | ||
608 | server_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 | |||
581 | void | 652 | void |
582 | server_input_stdin_data(int type, int plen) | 653 | server_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 | ||
696 | int | ||
697 | input_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 | |||
717 | void | ||
718 | server_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 | |||
786 | void | ||
787 | server_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 | } | ||
625 | void | 801 | void |
626 | server_init_dispatch_13() | 802 | server_init_dispatch_13() |
627 | { | 803 | { |
@@ -648,7 +824,9 @@ server_init_dispatch_15() | |||
648 | void | 824 | void |
649 | server_init_dispatch() | 825 | server_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(); |
@@ -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" |
7 | RCSID("$OpenBSD: session.c,v 1.1 2000/03/28 21:15:45 markus Exp $"); | 11 | RCSID("$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 | ||
1149 | int | ||
1150 | session_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 | |||
1167 | Session * | ||
1168 | session_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 | |||
1183 | Session * | ||
1184 | session_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 | |||
1198 | int | ||
1199 | session_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 | |||
1209 | int | ||
1210 | session_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 | |||
1248 | void | ||
1249 | session_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 | |||
1308 | void | ||
1309 | session_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 | |||
1129 | void | 1324 | void |
1130 | session_pty_cleanup(Session *s) | 1325 | session_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 | |||
1350 | void | ||
1351 | session_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 | |||
1390 | void | ||
1391 | session_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 | |||
1405 | void | ||
1406 | session_close(Session *s) | ||
1407 | { | ||
1408 | session_pty_cleanup(s); | ||
1409 | session_free(s); | ||
1410 | } | ||
1411 | |||
1412 | void | ||
1413 | session_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 | */ | ||
1429 | void | ||
1430 | session_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 | |||
1453 | void | ||
1454 | do_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 | } | ||
@@ -4,4 +4,11 @@ | |||
4 | /* SSH1 */ | 4 | /* SSH1 */ |
5 | void do_authenticated(struct passwd * pw); | 5 | void do_authenticated(struct passwd * pw); |
6 | 6 | ||
7 | /* SSH2 */ | ||
8 | void do_authenticated2(void); | ||
9 | int session_open(int id); | ||
10 | void session_input_channel_req(int id, void *arg); | ||
11 | void session_close_by_pid(pid_t pid, int status); | ||
12 | void session_close_by_channel(int id, void *arg); | ||
13 | |||
7 | #endif | 14 | #endif |
@@ -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(). */ |
487 | void fatal_remove_cleanup(void (*proc) (void *context), void *context); | 488 | void 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 | */ |
502 | void server_loop(int pid, int fdin, int fdout, int fderr); | 505 | void server_loop(int pid, int fdin, int fdout, int fderr); |
506 | void server_loop2(void); | ||
503 | 507 | ||
504 | /* Client side main loop for the interactive session. */ | 508 | /* Client side main loop for the interactive session. */ |
505 | int client_loop(int have_pty, int escape_char); | 509 | int client_loop(int have_pty, int escape_char); |
@@ -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" |
14 | RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); | 17 | RCSID("$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; | |||
70 | int IPv4or6 = AF_UNSPEC; | 77 | int IPv4or6 = AF_UNSPEC; |
71 | #endif | 78 | #endif |
72 | 79 | ||
80 | /* Flag indicating whether SSH2 is enabled */ | ||
81 | int 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. */ |
138 | void do_ssh1_kex(); | 148 | void do_ssh1_kex(); |
149 | void 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 | ||
269 | char * | ||
270 | chop(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 | |||
258 | void | 284 | void |
259 | sshd_exchange_identification(int sock_in, int sock_out) | 285 | sshd_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 | */ | ||
1104 | void | ||
1105 | do_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 | } | ||