diff options
author | Ben Lindstrom <mouring@eviladmin.org> | 2002-03-22 02:30:41 +0000 |
---|---|---|
committer | Ben Lindstrom <mouring@eviladmin.org> | 2002-03-22 02:30:41 +0000 |
commit | 7a2073c50b92c053594d48a651ebafae052a71ed (patch) | |
tree | 7cfceb925262a07a356b0667e19f33eec497b602 | |
parent | 0f345f5ee1e71e1e9f8780ec13b2da23b6a9f7f8 (diff) |
- provos@cvs.openbsd.org 2002/03/18 17:50:31
[auth-bsdauth.c auth-options.c auth-rh-rsa.c auth-rsa.c auth-skey.c auth.h
auth1.c auth2-chall.c auth2.c kex.c kex.h kexdh.c kexgex.c servconf.c
session.h servconf.h serverloop.c session.c sshd.c]
integrate privilege separated openssh; its turned off by default for now.
work done by me and markus@
applied, but outside of ensure that smaller code bits migrated with
their owners.. no work was tried to 'fix' it to work. =) Later project!
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | auth-bsdauth.c | 15 | ||||
-rw-r--r-- | auth-options.c | 80 | ||||
-rw-r--r-- | auth-rh-rsa.c | 6 | ||||
-rw-r--r-- | auth-rsa.c | 17 | ||||
-rw-r--r-- | auth-skey.c | 17 | ||||
-rw-r--r-- | auth.h | 5 | ||||
-rw-r--r-- | auth1.c | 25 | ||||
-rw-r--r-- | auth2-chall.c | 21 | ||||
-rw-r--r-- | auth2.c | 43 | ||||
-rw-r--r-- | kex.c | 8 | ||||
-rw-r--r-- | kex.h | 3 | ||||
-rw-r--r-- | kexdh.c | 5 | ||||
-rw-r--r-- | kexgex.c | 9 | ||||
-rw-r--r-- | monitor.c | 1440 | ||||
-rw-r--r-- | monitor.h | 78 | ||||
-rw-r--r-- | monitor_fdpass.c | 86 | ||||
-rw-r--r-- | monitor_fdpass.h | 32 | ||||
-rw-r--r-- | monitor_mm.c | 329 | ||||
-rw-r--r-- | monitor_mm.h | 64 | ||||
-rw-r--r-- | monitor_wrap.c | 894 | ||||
-rw-r--r-- | monitor_wrap.h | 85 | ||||
-rw-r--r-- | servconf.c | 42 | ||||
-rw-r--r-- | servconf.h | 5 | ||||
-rw-r--r-- | serverloop.c | 4 | ||||
-rw-r--r-- | session.c | 117 | ||||
-rw-r--r-- | session.h | 34 | ||||
-rw-r--r-- | sshd.c | 209 |
29 files changed, 3549 insertions, 138 deletions
@@ -59,6 +59,12 @@ | |||
59 | - provos@cvs.openbsd.org 2002/03/18 17:31:54 | 59 | - provos@cvs.openbsd.org 2002/03/18 17:31:54 |
60 | [compress.c] | 60 | [compress.c] |
61 | export compression streams for ssh-privsep | 61 | export compression streams for ssh-privsep |
62 | - provos@cvs.openbsd.org 2002/03/18 17:50:31 | ||
63 | [auth-bsdauth.c auth-options.c auth-rh-rsa.c auth-rsa.c auth-skey.c auth.h | ||
64 | auth1.c auth2-chall.c auth2.c kex.c kex.h kexdh.c kexgex.c servconf.c | ||
65 | session.h servconf.h serverloop.c session.c sshd.c] | ||
66 | integrate privilege separated openssh; its turned off by default for now. | ||
67 | work done by me and markus@ | ||
62 | 68 | ||
63 | 20020317 | 69 | 20020317 |
64 | - (tim) [configure.ac] Assume path given with --with-pid-dir=PATH is wanted, | 70 | - (tim) [configure.ac] Assume path given with --with-pid-dir=PATH is wanted, |
@@ -7905,4 +7911,4 @@ | |||
7905 | - Wrote replacements for strlcpy and mkdtemp | 7911 | - Wrote replacements for strlcpy and mkdtemp |
7906 | - Released 1.0pre1 | 7912 | - Released 1.0pre1 |
7907 | 7913 | ||
7908 | $Id: ChangeLog,v 1.1942 2002/03/22 01:51:24 mouring Exp $ | 7914 | $Id: ChangeLog,v 1.1943 2002/03/22 02:30:41 mouring Exp $ |
diff --git a/Makefile.in b/Makefile.in index 31aa8e583..cae801ef2 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Makefile.in,v 1.199 2002/03/13 02:19:42 djm Exp $ | 1 | # $Id: Makefile.in,v 1.200 2002/03/22 02:30:43 mouring Exp $ |
2 | 2 | ||
3 | prefix=@prefix@ | 3 | prefix=@prefix@ |
4 | exec_prefix=@exec_prefix@ | 4 | exec_prefix=@exec_prefix@ |
@@ -50,11 +50,11 @@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ | |||
50 | 50 | ||
51 | TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS) | 51 | TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS) |
52 | 52 | ||
53 | LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o | 53 | LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o |
54 | 54 | ||
55 | SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o | 55 | SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o |
56 | 56 | ||
57 | SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o | 57 | SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o monitor_mm.o monitor.o |
58 | 58 | ||
59 | MANPAGES = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out | 59 | MANPAGES = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out |
60 | MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 | 60 | MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 |
diff --git a/auth-bsdauth.c b/auth-bsdauth.c index b70d48f20..fa06732cc 100644 --- a/auth-bsdauth.c +++ b/auth-bsdauth.c | |||
@@ -22,12 +22,13 @@ | |||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ | 23 | */ |
24 | #include "includes.h" | 24 | #include "includes.h" |
25 | RCSID("$OpenBSD: auth-bsdauth.c,v 1.2 2001/12/19 07:18:56 deraadt Exp $"); | 25 | RCSID("$OpenBSD: auth-bsdauth.c,v 1.3 2002/03/18 17:50:31 provos Exp $"); |
26 | 26 | ||
27 | #ifdef BSD_AUTH | 27 | #ifdef BSD_AUTH |
28 | #include "xmalloc.h" | 28 | #include "xmalloc.h" |
29 | #include "auth.h" | 29 | #include "auth.h" |
30 | #include "log.h" | 30 | #include "log.h" |
31 | #include "monitor_wrap.h" | ||
31 | 32 | ||
32 | static void * | 33 | static void * |
33 | bsdauth_init_ctx(Authctxt *authctxt) | 34 | bsdauth_init_ctx(Authctxt *authctxt) |
@@ -35,7 +36,7 @@ bsdauth_init_ctx(Authctxt *authctxt) | |||
35 | return authctxt; | 36 | return authctxt; |
36 | } | 37 | } |
37 | 38 | ||
38 | static int | 39 | int |
39 | bsdauth_query(void *ctx, char **name, char **infotxt, | 40 | bsdauth_query(void *ctx, char **name, char **infotxt, |
40 | u_int *numprompts, char ***prompts, u_int **echo_on) | 41 | u_int *numprompts, char ***prompts, u_int **echo_on) |
41 | { | 42 | { |
@@ -76,7 +77,7 @@ bsdauth_query(void *ctx, char **name, char **infotxt, | |||
76 | return 0; | 77 | return 0; |
77 | } | 78 | } |
78 | 79 | ||
79 | static int | 80 | int |
80 | bsdauth_respond(void *ctx, u_int numresponses, char **responses) | 81 | bsdauth_respond(void *ctx, u_int numresponses, char **responses) |
81 | { | 82 | { |
82 | Authctxt *authctxt = ctx; | 83 | Authctxt *authctxt = ctx; |
@@ -113,4 +114,12 @@ KbdintDevice bsdauth_device = { | |||
113 | bsdauth_respond, | 114 | bsdauth_respond, |
114 | bsdauth_free_ctx | 115 | bsdauth_free_ctx |
115 | }; | 116 | }; |
117 | |||
118 | KbdintDevice mm_bsdauth_device = { | ||
119 | "bsdauth", | ||
120 | bsdauth_init_ctx, | ||
121 | mm_bsdauth_query, | ||
122 | mm_bsdauth_respond, | ||
123 | bsdauth_free_ctx | ||
124 | }; | ||
116 | #endif | 125 | #endif |
diff --git a/auth-options.c b/auth-options.c index 8df6a6dfc..48be6d8e0 100644 --- a/auth-options.c +++ b/auth-options.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "includes.h" | 12 | #include "includes.h" |
13 | RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $"); | 13 | RCSID("$OpenBSD: auth-options.c,v 1.22 2002/03/18 17:50:31 provos Exp $"); |
14 | 14 | ||
15 | #include "packet.h" | 15 | #include "packet.h" |
16 | #include "xmalloc.h" | 16 | #include "xmalloc.h" |
@@ -20,7 +20,13 @@ RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $"); | |||
20 | #include "channels.h" | 20 | #include "channels.h" |
21 | #include "auth-options.h" | 21 | #include "auth-options.h" |
22 | #include "servconf.h" | 22 | #include "servconf.h" |
23 | #include "bufaux.h" | ||
23 | #include "misc.h" | 24 | #include "misc.h" |
25 | #include "monitor_wrap.h" | ||
26 | |||
27 | /* Debugging messages */ | ||
28 | Buffer auth_debug; | ||
29 | int auth_debug_init; | ||
24 | 30 | ||
25 | /* Flags set authorized_keys flags */ | 31 | /* Flags set authorized_keys flags */ |
26 | int no_port_forwarding_flag = 0; | 32 | int no_port_forwarding_flag = 0; |
@@ -37,8 +43,27 @@ struct envstring *custom_environment = NULL; | |||
37 | extern ServerOptions options; | 43 | extern ServerOptions options; |
38 | 44 | ||
39 | void | 45 | void |
46 | auth_send_debug(Buffer *m) | ||
47 | { | ||
48 | char *msg; | ||
49 | |||
50 | while (buffer_len(m)) { | ||
51 | msg = buffer_get_string(m, NULL); | ||
52 | packet_send_debug("%s", msg); | ||
53 | xfree(msg); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | void | ||
40 | auth_clear_options(void) | 58 | auth_clear_options(void) |
41 | { | 59 | { |
60 | if (auth_debug_init) | ||
61 | buffer_clear(&auth_debug); | ||
62 | else { | ||
63 | buffer_init(&auth_debug); | ||
64 | auth_debug_init = 1; | ||
65 | } | ||
66 | |||
42 | no_agent_forwarding_flag = 0; | 67 | no_agent_forwarding_flag = 0; |
43 | no_port_forwarding_flag = 0; | 68 | no_port_forwarding_flag = 0; |
44 | no_pty_flag = 0; | 69 | no_pty_flag = 0; |
@@ -63,6 +88,7 @@ auth_clear_options(void) | |||
63 | int | 88 | int |
64 | auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | 89 | auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) |
65 | { | 90 | { |
91 | char tmp[1024]; | ||
66 | const char *cp; | 92 | const char *cp; |
67 | int i; | 93 | int i; |
68 | 94 | ||
@@ -75,28 +101,32 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
75 | while (*opts && *opts != ' ' && *opts != '\t') { | 101 | while (*opts && *opts != ' ' && *opts != '\t') { |
76 | cp = "no-port-forwarding"; | 102 | cp = "no-port-forwarding"; |
77 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { | 103 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
78 | packet_send_debug("Port forwarding disabled."); | 104 | snprintf(tmp, sizeof(tmp), "Port forwarding disabled."); |
105 | buffer_put_cstring(&auth_debug, tmp); | ||
79 | no_port_forwarding_flag = 1; | 106 | no_port_forwarding_flag = 1; |
80 | opts += strlen(cp); | 107 | opts += strlen(cp); |
81 | goto next_option; | 108 | goto next_option; |
82 | } | 109 | } |
83 | cp = "no-agent-forwarding"; | 110 | cp = "no-agent-forwarding"; |
84 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { | 111 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
85 | packet_send_debug("Agent forwarding disabled."); | 112 | snprintf(tmp, sizeof(tmp), "Agent forwarding disabled."); |
113 | buffer_put_cstring(&auth_debug, tmp); | ||
86 | no_agent_forwarding_flag = 1; | 114 | no_agent_forwarding_flag = 1; |
87 | opts += strlen(cp); | 115 | opts += strlen(cp); |
88 | goto next_option; | 116 | goto next_option; |
89 | } | 117 | } |
90 | cp = "no-X11-forwarding"; | 118 | cp = "no-X11-forwarding"; |
91 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { | 119 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
92 | packet_send_debug("X11 forwarding disabled."); | 120 | snprintf(tmp, sizeof(tmp), "X11 forwarding disabled."); |
121 | buffer_put_cstring(&auth_debug, tmp); | ||
93 | no_x11_forwarding_flag = 1; | 122 | no_x11_forwarding_flag = 1; |
94 | opts += strlen(cp); | 123 | opts += strlen(cp); |
95 | goto next_option; | 124 | goto next_option; |
96 | } | 125 | } |
97 | cp = "no-pty"; | 126 | cp = "no-pty"; |
98 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { | 127 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
99 | packet_send_debug("Pty allocation disabled."); | 128 | snprintf(tmp, sizeof(tmp), "Pty allocation disabled."); |
129 | buffer_put_cstring(&auth_debug, tmp); | ||
100 | no_pty_flag = 1; | 130 | no_pty_flag = 1; |
101 | opts += strlen(cp); | 131 | opts += strlen(cp); |
102 | goto next_option; | 132 | goto next_option; |
@@ -119,14 +149,16 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
119 | if (!*opts) { | 149 | if (!*opts) { |
120 | debug("%.100s, line %lu: missing end quote", | 150 | debug("%.100s, line %lu: missing end quote", |
121 | file, linenum); | 151 | file, linenum); |
122 | packet_send_debug("%.100s, line %lu: missing end quote", | 152 | snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", |
123 | file, linenum); | 153 | file, linenum); |
154 | buffer_put_cstring(&auth_debug, tmp); | ||
124 | xfree(forced_command); | 155 | xfree(forced_command); |
125 | forced_command = NULL; | 156 | forced_command = NULL; |
126 | goto bad_option; | 157 | goto bad_option; |
127 | } | 158 | } |
128 | forced_command[i] = 0; | 159 | forced_command[i] = 0; |
129 | packet_send_debug("Forced command: %.900s", forced_command); | 160 | snprintf(tmp, sizeof(tmp), "Forced command: %.900s", forced_command); |
161 | buffer_put_cstring(&auth_debug, tmp); | ||
130 | opts++; | 162 | opts++; |
131 | goto next_option; | 163 | goto next_option; |
132 | } | 164 | } |
@@ -151,13 +183,15 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
151 | if (!*opts) { | 183 | if (!*opts) { |
152 | debug("%.100s, line %lu: missing end quote", | 184 | debug("%.100s, line %lu: missing end quote", |
153 | file, linenum); | 185 | file, linenum); |
154 | packet_send_debug("%.100s, line %lu: missing end quote", | 186 | snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", |
155 | file, linenum); | 187 | file, linenum); |
188 | buffer_put_cstring(&auth_debug, tmp); | ||
156 | xfree(s); | 189 | xfree(s); |
157 | goto bad_option; | 190 | goto bad_option; |
158 | } | 191 | } |
159 | s[i] = 0; | 192 | s[i] = 0; |
160 | packet_send_debug("Adding to environment: %.900s", s); | 193 | snprintf(tmp, sizeof(tmp), "Adding to environment: %.900s", s); |
194 | buffer_put_cstring(&auth_debug, tmp); | ||
161 | debug("Adding to environment: %.900s", s); | 195 | debug("Adding to environment: %.900s", s); |
162 | opts++; | 196 | opts++; |
163 | new_envstring = xmalloc(sizeof(struct envstring)); | 197 | new_envstring = xmalloc(sizeof(struct envstring)); |
@@ -188,8 +222,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
188 | if (!*opts) { | 222 | if (!*opts) { |
189 | debug("%.100s, line %lu: missing end quote", | 223 | debug("%.100s, line %lu: missing end quote", |
190 | file, linenum); | 224 | file, linenum); |
191 | packet_send_debug("%.100s, line %lu: missing end quote", | 225 | snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", |
192 | file, linenum); | 226 | file, linenum); |
227 | buffer_put_cstring(&auth_debug, tmp); | ||
193 | xfree(patterns); | 228 | xfree(patterns); |
194 | goto bad_option; | 229 | goto bad_option; |
195 | } | 230 | } |
@@ -202,9 +237,11 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
202 | "correct key but not from a permitted " | 237 | "correct key but not from a permitted " |
203 | "host (host=%.200s, ip=%.200s).", | 238 | "host (host=%.200s, ip=%.200s).", |
204 | pw->pw_name, remote_host, remote_ip); | 239 | pw->pw_name, remote_host, remote_ip); |
205 | packet_send_debug("Your host '%.200s' is not " | 240 | snprintf(tmp, sizeof(tmp), |
241 | "Your host '%.200s' is not " | ||
206 | "permitted to use this key for login.", | 242 | "permitted to use this key for login.", |
207 | remote_host); | 243 | remote_host); |
244 | buffer_put_cstring(&auth_debug, tmp); | ||
208 | /* deny access */ | 245 | /* deny access */ |
209 | return 0; | 246 | return 0; |
210 | } | 247 | } |
@@ -233,8 +270,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
233 | if (!*opts) { | 270 | if (!*opts) { |
234 | debug("%.100s, line %lu: missing end quote", | 271 | debug("%.100s, line %lu: missing end quote", |
235 | file, linenum); | 272 | file, linenum); |
236 | packet_send_debug("%.100s, line %lu: missing end quote", | 273 | snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", |
237 | file, linenum); | 274 | file, linenum); |
275 | buffer_put_cstring(&auth_debug, tmp); | ||
238 | xfree(patterns); | 276 | xfree(patterns); |
239 | goto bad_option; | 277 | goto bad_option; |
240 | } | 278 | } |
@@ -244,16 +282,18 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
244 | sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { | 282 | sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { |
245 | debug("%.100s, line %lu: Bad permitopen specification " | 283 | debug("%.100s, line %lu: Bad permitopen specification " |
246 | "<%.100s>", file, linenum, patterns); | 284 | "<%.100s>", file, linenum, patterns); |
247 | packet_send_debug("%.100s, line %lu: " | 285 | snprintf(tmp, sizeof(tmp), "%.100s, line %lu: " |
248 | "Bad permitopen specification", file, linenum); | 286 | "Bad permitopen specification", file, linenum); |
287 | buffer_put_cstring(&auth_debug, tmp); | ||
249 | xfree(patterns); | 288 | xfree(patterns); |
250 | goto bad_option; | 289 | goto bad_option; |
251 | } | 290 | } |
252 | if ((port = a2port(sport)) == 0) { | 291 | if ((port = a2port(sport)) == 0) { |
253 | debug("%.100s, line %lu: Bad permitopen port <%.100s>", | 292 | debug("%.100s, line %lu: Bad permitopen port <%.100s>", |
254 | file, linenum, sport); | 293 | file, linenum, sport); |
255 | packet_send_debug("%.100s, line %lu: " | 294 | snprintf(tmp, sizeof(tmp), "%.100s, line %lu: " |
256 | "Bad permitopen port", file, linenum); | 295 | "Bad permitopen port", file, linenum); |
296 | buffer_put_cstring(&auth_debug, tmp); | ||
257 | xfree(patterns); | 297 | xfree(patterns); |
258 | goto bad_option; | 298 | goto bad_option; |
259 | } | 299 | } |
@@ -276,14 +316,24 @@ next_option: | |||
276 | opts++; | 316 | opts++; |
277 | /* Process the next option. */ | 317 | /* Process the next option. */ |
278 | } | 318 | } |
319 | |||
320 | if (!use_privsep) | ||
321 | auth_send_debug(&auth_debug); | ||
322 | |||
279 | /* grant access */ | 323 | /* grant access */ |
280 | return 1; | 324 | return 1; |
281 | 325 | ||
282 | bad_option: | 326 | bad_option: |
283 | log("Bad options in %.100s file, line %lu: %.50s", | 327 | log("Bad options in %.100s file, line %lu: %.50s", |
284 | file, linenum, opts); | 328 | file, linenum, opts); |
285 | packet_send_debug("Bad options in %.100s file, line %lu: %.50s", | 329 | snprintf(tmp, sizeof(tmp), |
330 | "Bad options in %.100s file, line %lu: %.50s", | ||
286 | file, linenum, opts); | 331 | file, linenum, opts); |
332 | buffer_put_cstring(&auth_debug, tmp); | ||
333 | |||
334 | if (!use_privsep) | ||
335 | auth_send_debug(&auth_debug); | ||
336 | |||
287 | /* deny access */ | 337 | /* deny access */ |
288 | return 0; | 338 | return 0; |
289 | } | 339 | } |
diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c index 2a88e18b3..c940ec581 100644 --- a/auth-rh-rsa.c +++ b/auth-rh-rsa.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include "includes.h" | 15 | #include "includes.h" |
16 | RCSID("$OpenBSD: auth-rh-rsa.c,v 1.31 2002/03/16 17:22:09 markus Exp $"); | 16 | RCSID("$OpenBSD: auth-rh-rsa.c,v 1.32 2002/03/18 17:50:31 provos Exp $"); |
17 | 17 | ||
18 | #include "packet.h" | 18 | #include "packet.h" |
19 | #include "uidswap.h" | 19 | #include "uidswap.h" |
@@ -25,6 +25,8 @@ RCSID("$OpenBSD: auth-rh-rsa.c,v 1.31 2002/03/16 17:22:09 markus Exp $"); | |||
25 | #include "auth.h" | 25 | #include "auth.h" |
26 | #include "canohost.h" | 26 | #include "canohost.h" |
27 | 27 | ||
28 | #include "monitor_wrap.h" | ||
29 | |||
28 | /* import */ | 30 | /* import */ |
29 | extern ServerOptions options; | 31 | extern ServerOptions options; |
30 | 32 | ||
@@ -69,7 +71,7 @@ auth_rhosts_rsa(struct passwd *pw, char *cuser, Key *client_host_key) | |||
69 | chost = (char *)get_canonical_hostname(options.verify_reverse_mapping); | 71 | chost = (char *)get_canonical_hostname(options.verify_reverse_mapping); |
70 | debug("Rhosts RSA authentication: canonical host %.900s", chost); | 72 | debug("Rhosts RSA authentication: canonical host %.900s", chost); |
71 | 73 | ||
72 | if (!auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key)) { | 74 | if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) { |
73 | debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); | 75 | debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); |
74 | packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); | 76 | packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); |
75 | return 0; | 77 | return 0; |
diff --git a/auth-rsa.c b/auth-rsa.c index ff9bf3b64..9c5d484b1 100644 --- a/auth-rsa.c +++ b/auth-rsa.c | |||
@@ -14,7 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include "includes.h" | 16 | #include "includes.h" |
17 | RCSID("$OpenBSD: auth-rsa.c,v 1.51 2002/03/14 16:56:33 markus Exp $"); | 17 | RCSID("$OpenBSD: auth-rsa.c,v 1.52 2002/03/18 17:50:31 provos Exp $"); |
18 | 18 | ||
19 | #include <openssl/rsa.h> | 19 | #include <openssl/rsa.h> |
20 | #include <openssl/md5.h> | 20 | #include <openssl/md5.h> |
@@ -32,6 +32,7 @@ RCSID("$OpenBSD: auth-rsa.c,v 1.51 2002/03/14 16:56:33 markus Exp $"); | |||
32 | #include "servconf.h" | 32 | #include "servconf.h" |
33 | #include "auth.h" | 33 | #include "auth.h" |
34 | #include "hostfile.h" | 34 | #include "hostfile.h" |
35 | #include "monitor_wrap.h" | ||
35 | 36 | ||
36 | /* import */ | 37 | /* import */ |
37 | extern ServerOptions options; | 38 | extern ServerOptions options; |
@@ -52,7 +53,7 @@ extern u_char session_id[16]; | |||
52 | * description of the options. | 53 | * description of the options. |
53 | */ | 54 | */ |
54 | 55 | ||
55 | static BIGNUM * | 56 | BIGNUM * |
56 | auth_rsa_generate_challenge(Key *key) | 57 | auth_rsa_generate_challenge(Key *key) |
57 | { | 58 | { |
58 | BIGNUM *challenge; | 59 | BIGNUM *challenge; |
@@ -70,7 +71,7 @@ auth_rsa_generate_challenge(Key *key) | |||
70 | return challenge; | 71 | return challenge; |
71 | } | 72 | } |
72 | 73 | ||
73 | static int | 74 | int |
74 | auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) | 75 | auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) |
75 | { | 76 | { |
76 | u_char buf[32], mdbuf[16]; | 77 | u_char buf[32], mdbuf[16]; |
@@ -113,7 +114,7 @@ auth_rsa_challenge_dialog(Key *key) | |||
113 | if ((encrypted_challenge = BN_new()) == NULL) | 114 | if ((encrypted_challenge = BN_new()) == NULL) |
114 | fatal("auth_rsa_challenge_dialog: BN_new() failed"); | 115 | fatal("auth_rsa_challenge_dialog: BN_new() failed"); |
115 | 116 | ||
116 | challenge = auth_rsa_generate_challenge(key); | 117 | challenge = PRIVSEP(auth_rsa_generate_challenge(key)); |
117 | 118 | ||
118 | /* Encrypt the challenge with the public key. */ | 119 | /* Encrypt the challenge with the public key. */ |
119 | rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); | 120 | rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); |
@@ -131,7 +132,7 @@ auth_rsa_challenge_dialog(Key *key) | |||
131 | response[i] = packet_get_char(); | 132 | response[i] = packet_get_char(); |
132 | packet_check_eom(); | 133 | packet_check_eom(); |
133 | 134 | ||
134 | success = auth_rsa_verify_response(key, challenge, response); | 135 | success = PRIVSEP(auth_rsa_verify_response(key, challenge, response)); |
135 | BN_clear_free(challenge); | 136 | BN_clear_free(challenge); |
136 | return (success); | 137 | return (success); |
137 | } | 138 | } |
@@ -141,11 +142,11 @@ auth_rsa_challenge_dialog(Key *key) | |||
141 | * return key if login is allowed, NULL otherwise | 142 | * return key if login is allowed, NULL otherwise |
142 | */ | 143 | */ |
143 | 144 | ||
144 | static int | 145 | int |
145 | auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) | 146 | auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) |
146 | { | 147 | { |
147 | char line[8192], *file; | 148 | char line[8192], *file; |
148 | int allowed; | 149 | int allowed = 0; |
149 | u_int bits; | 150 | u_int bits; |
150 | FILE *f; | 151 | FILE *f; |
151 | u_long linenum = 0; | 152 | u_long linenum = 0; |
@@ -284,7 +285,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) | |||
284 | if (pw == NULL) | 285 | if (pw == NULL) |
285 | return 0; | 286 | return 0; |
286 | 287 | ||
287 | if (auth_rsa_key_allowed(pw, client_n, &key) == 0) { | 288 | if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { |
288 | auth_clear_options(); | 289 | auth_clear_options(); |
289 | return (0); | 290 | return (0); |
290 | } | 291 | } |
diff --git a/auth-skey.c b/auth-skey.c index df19f7507..e897d1875 100644 --- a/auth-skey.c +++ b/auth-skey.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ | 23 | */ |
24 | #include "includes.h" | 24 | #include "includes.h" |
25 | RCSID("$OpenBSD: auth-skey.c,v 1.16 2002/01/12 13:10:29 markus Exp $"); | 25 | RCSID("$OpenBSD: auth-skey.c,v 1.17 2002/03/18 17:50:31 provos Exp $"); |
26 | 26 | ||
27 | #ifdef SKEY | 27 | #ifdef SKEY |
28 | 28 | ||
@@ -30,6 +30,7 @@ RCSID("$OpenBSD: auth-skey.c,v 1.16 2002/01/12 13:10:29 markus Exp $"); | |||
30 | 30 | ||
31 | #include "xmalloc.h" | 31 | #include "xmalloc.h" |
32 | #include "auth.h" | 32 | #include "auth.h" |
33 | #include "monitor_wrap.h" | ||
33 | 34 | ||
34 | static void * | 35 | static void * |
35 | skey_init_ctx(Authctxt *authctxt) | 36 | skey_init_ctx(Authctxt *authctxt) |
@@ -37,8 +38,6 @@ skey_init_ctx(Authctxt *authctxt) | |||
37 | return authctxt; | 38 | return authctxt; |
38 | } | 39 | } |
39 | 40 | ||
40 | #define PROMPT "\nS/Key Password: " | ||
41 | |||
42 | static int | 41 | static int |
43 | skey_query(void *ctx, char **name, char **infotxt, | 42 | skey_query(void *ctx, char **name, char **infotxt, |
44 | u_int* numprompts, char ***prompts, u_int **echo_on) | 43 | u_int* numprompts, char ***prompts, u_int **echo_on) |
@@ -58,10 +57,10 @@ skey_query(void *ctx, char **name, char **infotxt, | |||
58 | *echo_on = xmalloc(*numprompts * sizeof(u_int)); | 57 | *echo_on = xmalloc(*numprompts * sizeof(u_int)); |
59 | (*echo_on)[0] = 0; | 58 | (*echo_on)[0] = 0; |
60 | 59 | ||
61 | len = strlen(challenge) + strlen(PROMPT) + 1; | 60 | len = strlen(challenge) + strlen(SKEY_PROMPT) + 1; |
62 | p = xmalloc(len); | 61 | p = xmalloc(len); |
63 | strlcpy(p, challenge, len); | 62 | strlcpy(p, challenge, len); |
64 | strlcat(p, PROMPT, len); | 63 | strlcat(p, SKEY_PROMPT, len); |
65 | (*prompts)[0] = p; | 64 | (*prompts)[0] = p; |
66 | 65 | ||
67 | return 0; | 66 | return 0; |
@@ -93,4 +92,12 @@ KbdintDevice skey_device = { | |||
93 | skey_respond, | 92 | skey_respond, |
94 | skey_free_ctx | 93 | skey_free_ctx |
95 | }; | 94 | }; |
95 | |||
96 | KbdintDevice mm_skey_device = { | ||
97 | "skey", | ||
98 | skey_init_ctx, | ||
99 | mm_skey_query, | ||
100 | mm_skey_respond, | ||
101 | skey_free_ctx | ||
102 | }; | ||
96 | #endif /* SKEY */ | 103 | #endif /* SKEY */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.h,v 1.33 2002/03/18 01:12:14 provos Exp $ */ | 1 | /* $OpenBSD: auth.h,v 1.34 2002/03/18 17:50:31 provos Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -129,6 +129,8 @@ void auth_log(Authctxt *, int, char *, char *); | |||
129 | void userauth_finish(Authctxt *, int, char *); | 129 | void userauth_finish(Authctxt *, int, char *); |
130 | int auth_root_allowed(char *); | 130 | int auth_root_allowed(char *); |
131 | 131 | ||
132 | void privsep_challenge_enable(void); | ||
133 | |||
132 | int auth2_challenge(Authctxt *, char *); | 134 | int auth2_challenge(Authctxt *, char *); |
133 | void auth2_challenge_stop(Authctxt *); | 135 | void auth2_challenge_stop(Authctxt *); |
134 | 136 | ||
@@ -155,4 +157,5 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *, | |||
155 | #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) | 157 | #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) |
156 | #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" | 158 | #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" |
157 | 159 | ||
160 | #define SKEY_PROMPT "\nS/Key Password: " | ||
158 | #endif | 161 | #endif |
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "includes.h" | 12 | #include "includes.h" |
13 | RCSID("$OpenBSD: auth1.c,v 1.37 2002/03/18 01:12:14 provos Exp $"); | 13 | RCSID("$OpenBSD: auth1.c,v 1.38 2002/03/18 17:50:31 provos Exp $"); |
14 | 14 | ||
15 | #include "xmalloc.h" | 15 | #include "xmalloc.h" |
16 | #include "rsa.h" | 16 | #include "rsa.h" |
@@ -26,6 +26,7 @@ RCSID("$OpenBSD: auth1.c,v 1.37 2002/03/18 01:12:14 provos Exp $"); | |||
26 | #include "session.h" | 26 | #include "session.h" |
27 | #include "misc.h" | 27 | #include "misc.h" |
28 | #include "uidswap.h" | 28 | #include "uidswap.h" |
29 | #include "monitor_wrap.h" | ||
29 | 30 | ||
30 | /* import */ | 31 | /* import */ |
31 | extern ServerOptions options; | 32 | extern ServerOptions options; |
@@ -89,7 +90,7 @@ do_authloop(Authctxt *authctxt) | |||
89 | #elif defined(HAVE_OSF_SIA) | 90 | #elif defined(HAVE_OSF_SIA) |
90 | 0) { | 91 | 0) { |
91 | #else | 92 | #else |
92 | auth_password(authctxt, "")) { | 93 | PRIVSEP(auth_password(authctxt, ""))) { |
93 | #endif | 94 | #endif |
94 | auth_log(authctxt, 1, "without authentication", ""); | 95 | auth_log(authctxt, 1, "without authentication", ""); |
95 | return; | 96 | return; |
@@ -253,9 +254,8 @@ do_authloop(Authctxt *authctxt) | |||
253 | /* Do SIA auth with password */ | 254 | /* Do SIA auth with password */ |
254 | authenticated = auth_sia_password(authctxt->user, | 255 | authenticated = auth_sia_password(authctxt->user, |
255 | password); | 256 | password); |
256 | #else /* !USE_PAM && !HAVE_OSF_SIA */ | ||
257 | /* Try authentication with the password. */ | 257 | /* Try authentication with the password. */ |
258 | authenticated = auth_password(authctxt, password); | 258 | authenticated = PRIVSEP(auth_password(authctxt, password)); |
259 | #endif /* USE_PAM */ | 259 | #endif /* USE_PAM */ |
260 | 260 | ||
261 | memset(password, 0, strlen(password)); | 261 | memset(password, 0, strlen(password)); |
@@ -359,7 +359,7 @@ Authctxt * | |||
359 | do_authentication(void) | 359 | do_authentication(void) |
360 | { | 360 | { |
361 | Authctxt *authctxt; | 361 | Authctxt *authctxt; |
362 | struct passwd *pw; | 362 | struct passwd *pw = NULL, *pwent; |
363 | u_int ulen; | 363 | u_int ulen; |
364 | char *p, *user, *style = NULL; | 364 | char *p, *user, *style = NULL; |
365 | 365 | ||
@@ -382,17 +382,22 @@ do_authentication(void) | |||
382 | authctxt->style = style; | 382 | authctxt->style = style; |
383 | 383 | ||
384 | /* Verify that the user is a valid user. */ | 384 | /* Verify that the user is a valid user. */ |
385 | pw = getpwnamallow(user); | 385 | pwent = PRIVSEP(getpwnamallow(user)); |
386 | if (pw) { | 386 | if (pwent) { |
387 | authctxt->valid = 1; | 387 | authctxt->valid = 1; |
388 | pw = pwcopy(pw); | 388 | pw = pwcopy(pwent); |
389 | } else { | 389 | } else { |
390 | debug("do_authentication: illegal user %s", user); | 390 | debug("do_authentication: illegal user %s", user); |
391 | pw = NULL; | 391 | pw = NULL; |
392 | } | 392 | } |
393 | /* Free memory */ | ||
394 | if (use_privsep && pwent != NULL) | ||
395 | pwfree(pwent); | ||
396 | |||
393 | authctxt->pw = pw; | 397 | authctxt->pw = pw; |
394 | 398 | ||
395 | setproctitle("%s", pw ? user : "unknown"); | 399 | setproctitle("%s%s", pw ? user : "unknown", |
400 | use_privsep ? " [net]" : ""); | ||
396 | 401 | ||
397 | #ifdef USE_PAM | 402 | #ifdef USE_PAM |
398 | start_pam(pw == NULL ? "NOUSER" : user); | 403 | start_pam(pw == NULL ? "NOUSER" : user); |
@@ -403,7 +408,7 @@ do_authentication(void) | |||
403 | * the server. (Unless you are running Windows) | 408 | * the server. (Unless you are running Windows) |
404 | */ | 409 | */ |
405 | #ifndef HAVE_CYGWIN | 410 | #ifndef HAVE_CYGWIN |
406 | if (getuid() != 0 && pw && pw->pw_uid != getuid()) | 411 | if (!use_privsep && getuid() != 0 && pw && pw->pw_uid != getuid()) |
407 | packet_disconnect("Cannot change user when server not running as root."); | 412 | packet_disconnect("Cannot change user when server not running as root."); |
408 | #endif | 413 | #endif |
409 | 414 | ||
diff --git a/auth2-chall.c b/auth2-chall.c index 9f1d93275..38f955a02 100644 --- a/auth2-chall.c +++ b/auth2-chall.c | |||
@@ -23,7 +23,7 @@ | |||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ | 24 | */ |
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: auth2-chall.c,v 1.16 2002/01/13 17:57:37 markus Exp $"); | 26 | RCSID("$OpenBSD: auth2-chall.c,v 1.17 2002/03/18 17:50:31 provos Exp $"); |
27 | 27 | ||
28 | #include "ssh2.h" | 28 | #include "ssh2.h" |
29 | #include "auth.h" | 29 | #include "auth.h" |
@@ -310,3 +310,22 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt) | |||
310 | userauth_finish(authctxt, authenticated, method); | 310 | userauth_finish(authctxt, authenticated, method); |
311 | xfree(method); | 311 | xfree(method); |
312 | } | 312 | } |
313 | |||
314 | void | ||
315 | privsep_challenge_enable(void) | ||
316 | { | ||
317 | #ifdef BSD_AUTH | ||
318 | extern KbdintDevice mm_bsdauth_device; | ||
319 | #endif | ||
320 | #ifdef SKEY | ||
321 | extern KbdintDevice mm_skey_device; | ||
322 | #endif | ||
323 | /* As long as SSHv1 has devices[0] hard coded this is fine */ | ||
324 | #ifdef BSD_AUTH | ||
325 | devices[0] = &mm_bsdauth_device; | ||
326 | #else | ||
327 | #ifdef SKEY | ||
328 | devices[0] = &mm_skey_device; | ||
329 | #endif | ||
330 | #endif | ||
331 | } | ||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: auth2.c,v 1.87 2002/03/18 01:12:14 provos Exp $"); | 26 | RCSID("$OpenBSD: auth2.c,v 1.88 2002/03/18 17:50:31 provos Exp $"); |
27 | 27 | ||
28 | #include <openssl/evp.h> | 28 | #include <openssl/evp.h> |
29 | 29 | ||
@@ -51,13 +51,14 @@ RCSID("$OpenBSD: auth2.c,v 1.87 2002/03/18 01:12:14 provos Exp $"); | |||
51 | #include "hostfile.h" | 51 | #include "hostfile.h" |
52 | #include "canohost.h" | 52 | #include "canohost.h" |
53 | #include "match.h" | 53 | #include "match.h" |
54 | #include "monitor_wrap.h" | ||
54 | 55 | ||
55 | /* import */ | 56 | /* import */ |
56 | extern ServerOptions options; | 57 | extern ServerOptions options; |
57 | extern u_char *session_id2; | 58 | extern u_char *session_id2; |
58 | extern int session_id2_len; | 59 | extern int session_id2_len; |
59 | 60 | ||
60 | static Authctxt *x_authctxt = NULL; | 61 | Authctxt *x_authctxt = NULL; |
61 | static int one = 1; | 62 | static int one = 1; |
62 | 63 | ||
63 | typedef struct Authmethod Authmethod; | 64 | typedef struct Authmethod Authmethod; |
@@ -75,8 +76,8 @@ static void input_userauth_request(int, u_int32_t, void *); | |||
75 | /* helper */ | 76 | /* helper */ |
76 | static Authmethod *authmethod_lookup(const char *); | 77 | static Authmethod *authmethod_lookup(const char *); |
77 | static char *authmethods_get(void); | 78 | static char *authmethods_get(void); |
78 | static int user_key_allowed(struct passwd *, Key *); | 79 | int user_key_allowed(struct passwd *, Key *); |
79 | static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); | 80 | int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); |
80 | 81 | ||
81 | /* auth */ | 82 | /* auth */ |
82 | static void userauth_banner(void); | 83 | static void userauth_banner(void); |
@@ -185,7 +186,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
185 | if (authctxt->attempt++ == 0) { | 186 | if (authctxt->attempt++ == 0) { |
186 | /* setup auth context */ | 187 | /* setup auth context */ |
187 | struct passwd *pw = NULL; | 188 | struct passwd *pw = NULL; |
188 | pw = getpwnamallow(user); | 189 | pw = PRIVSEP(getpwnamallow(user)); |
189 | if (pw && strcmp(service, "ssh-connection")==0) { | 190 | if (pw && strcmp(service, "ssh-connection")==0) { |
190 | authctxt->pw = pwcopy(pw); | 191 | authctxt->pw = pwcopy(pw); |
191 | authctxt->valid = 1; | 192 | authctxt->valid = 1; |
@@ -199,10 +200,18 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
199 | start_pam("NOUSER"); | 200 | start_pam("NOUSER"); |
200 | #endif | 201 | #endif |
201 | } | 202 | } |
202 | setproctitle("%s", pw ? user : "unknown"); | 203 | /* Free memory */ |
204 | if (use_privsep && pw != NULL) | ||
205 | pwfree(pw); | ||
206 | |||
207 | setproctitle("%s%s", pw ? user : "unknown", | ||
208 | use_privsep ? " [net]" : ""); | ||
203 | authctxt->user = xstrdup(user); | 209 | authctxt->user = xstrdup(user); |
204 | authctxt->service = xstrdup(service); | 210 | authctxt->service = xstrdup(service); |
205 | authctxt->style = style ? xstrdup(style) : NULL; | 211 | authctxt->style = style ? xstrdup(style) : NULL; |
212 | |||
213 | if (use_privsep) | ||
214 | mm_inform_authserv(service, style); | ||
206 | } else if (strcmp(user, authctxt->user) != 0 || | 215 | } else if (strcmp(user, authctxt->user) != 0 || |
207 | strcmp(service, authctxt->service) != 0) { | 216 | strcmp(service, authctxt->service) != 0) { |
208 | packet_disconnect("Change of username or service not allowed: " | 217 | packet_disconnect("Change of username or service not allowed: " |
@@ -333,7 +342,7 @@ userauth_none(Authctxt *authctxt) | |||
333 | #elif defined(HAVE_OSF_SIA) | 342 | #elif defined(HAVE_OSF_SIA) |
334 | return 0; | 343 | return 0; |
335 | #else /* !HAVE_OSF_SIA && !USE_PAM */ | 344 | #else /* !HAVE_OSF_SIA && !USE_PAM */ |
336 | return auth_password(authctxt, ""); | 345 | return PRIVSEP(auth_password(authctxt, "")); |
337 | #endif /* USE_PAM */ | 346 | #endif /* USE_PAM */ |
338 | } | 347 | } |
339 | 348 | ||
@@ -358,7 +367,7 @@ userauth_passwd(Authctxt *authctxt) | |||
358 | #elif defined(HAVE_OSF_SIA) | 367 | #elif defined(HAVE_OSF_SIA) |
359 | auth_sia_password(authctxt->user, password) == 1) | 368 | auth_sia_password(authctxt->user, password) == 1) |
360 | #else /* !USE_PAM && !HAVE_OSF_SIA */ | 369 | #else /* !USE_PAM && !HAVE_OSF_SIA */ |
361 | auth_password(authctxt, password) == 1) | 370 | PRIVSEP(auth_password(authctxt, password)) == 1) |
362 | #endif /* USE_PAM */ | 371 | #endif /* USE_PAM */ |
363 | authenticated = 1; | 372 | authenticated = 1; |
364 | memset(password, 0, len); | 373 | memset(password, 0, len); |
@@ -468,8 +477,10 @@ userauth_pubkey(Authctxt *authctxt) | |||
468 | buffer_dump(&b); | 477 | buffer_dump(&b); |
469 | #endif | 478 | #endif |
470 | /* test for correct signature */ | 479 | /* test for correct signature */ |
471 | if (user_key_allowed(authctxt->pw, key) && | 480 | authenticated = 0; |
472 | key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) | 481 | if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && |
482 | PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), | ||
483 | buffer_len(&b))) == 1) | ||
473 | authenticated = 1; | 484 | authenticated = 1; |
474 | buffer_clear(&b); | 485 | buffer_clear(&b); |
475 | xfree(sig); | 486 | xfree(sig); |
@@ -485,7 +496,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
485 | * if a user is not allowed to login. is this an | 496 | * if a user is not allowed to login. is this an |
486 | * issue? -markus | 497 | * issue? -markus |
487 | */ | 498 | */ |
488 | if (user_key_allowed(authctxt->pw, key)) { | 499 | if (PRIVSEP(user_key_allowed(authctxt->pw, key))) { |
489 | packet_start(SSH2_MSG_USERAUTH_PK_OK); | 500 | packet_start(SSH2_MSG_USERAUTH_PK_OK); |
490 | packet_put_string(pkalg, alen); | 501 | packet_put_string(pkalg, alen); |
491 | packet_put_string(pkblob, blen); | 502 | packet_put_string(pkblob, blen); |
@@ -573,8 +584,10 @@ userauth_hostbased(Authctxt *authctxt) | |||
573 | buffer_dump(&b); | 584 | buffer_dump(&b); |
574 | #endif | 585 | #endif |
575 | /* test for allowed key and correct signature */ | 586 | /* test for allowed key and correct signature */ |
576 | if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) && | 587 | authenticated = 0; |
577 | key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) | 588 | if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && |
589 | PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), | ||
590 | buffer_len(&b))) == 1) | ||
578 | authenticated = 1; | 591 | authenticated = 1; |
579 | 592 | ||
580 | buffer_clear(&b); | 593 | buffer_clear(&b); |
@@ -731,7 +744,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
731 | } | 744 | } |
732 | 745 | ||
733 | /* check whether given key is in .ssh/authorized_keys* */ | 746 | /* check whether given key is in .ssh/authorized_keys* */ |
734 | static int | 747 | int |
735 | user_key_allowed(struct passwd *pw, Key *key) | 748 | user_key_allowed(struct passwd *pw, Key *key) |
736 | { | 749 | { |
737 | int success; | 750 | int success; |
@@ -751,7 +764,7 @@ user_key_allowed(struct passwd *pw, Key *key) | |||
751 | } | 764 | } |
752 | 765 | ||
753 | /* return 1 if given hostkey is allowed */ | 766 | /* return 1 if given hostkey is allowed */ |
754 | static int | 767 | int |
755 | hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, | 768 | hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, |
756 | Key *key) | 769 | Key *key) |
757 | { | 770 | { |
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $"); | 26 | RCSID("$OpenBSD: kex.c,v 1.48 2002/03/18 17:50:31 provos Exp $"); |
27 | 27 | ||
28 | #include <openssl/crypto.h> | 28 | #include <openssl/crypto.h> |
29 | 29 | ||
@@ -40,9 +40,15 @@ RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $"); | |||
40 | #include "mac.h" | 40 | #include "mac.h" |
41 | #include "match.h" | 41 | #include "match.h" |
42 | #include "dispatch.h" | 42 | #include "dispatch.h" |
43 | #include "monitor.h" | ||
43 | 44 | ||
44 | #define KEX_COOKIE_LEN 16 | 45 | #define KEX_COOKIE_LEN 16 |
45 | 46 | ||
47 | /* Use privilege separation for sshd */ | ||
48 | int use_privsep; | ||
49 | struct monitor *monitor; | ||
50 | |||
51 | |||
46 | /* prototype */ | 52 | /* prototype */ |
47 | static void kex_kexinit_finish(Kex *); | 53 | static void kex_kexinit_finish(Kex *); |
48 | static void kex_choose_conf(Kex *); | 54 | static void kex_choose_conf(Kex *); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.h,v 1.29 2002/02/14 23:41:01 markus Exp $ */ | 1 | /* $OpenBSD: kex.h,v 1.30 2002/03/18 17:50:31 provos Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -111,6 +111,7 @@ struct Kex { | |||
111 | char *server_version_string; | 111 | char *server_version_string; |
112 | int (*verify_host_key)(Key *); | 112 | int (*verify_host_key)(Key *); |
113 | Key *(*load_host_key)(int); | 113 | Key *(*load_host_key)(int); |
114 | int (*host_key_index)(Key *); | ||
114 | }; | 115 | }; |
115 | 116 | ||
116 | Kex *kex_setup(char *[PROPOSAL_MAX]); | 117 | Kex *kex_setup(char *[PROPOSAL_MAX]); |
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: kexdh.c,v 1.17 2002/02/28 15:46:33 markus Exp $"); | 26 | RCSID("$OpenBSD: kexdh.c,v 1.18 2002/03/18 17:50:31 provos Exp $"); |
27 | 27 | ||
28 | #include <openssl/crypto.h> | 28 | #include <openssl/crypto.h> |
29 | #include <openssl/bn.h> | 29 | #include <openssl/bn.h> |
@@ -37,6 +37,7 @@ RCSID("$OpenBSD: kexdh.c,v 1.17 2002/02/28 15:46:33 markus Exp $"); | |||
37 | #include "packet.h" | 37 | #include "packet.h" |
38 | #include "dh.h" | 38 | #include "dh.h" |
39 | #include "ssh2.h" | 39 | #include "ssh2.h" |
40 | #include "monitor_wrap.h" | ||
40 | 41 | ||
41 | static u_char * | 42 | static u_char * |
42 | kex_dh_hash( | 43 | kex_dh_hash( |
@@ -275,7 +276,7 @@ kexdh_server(Kex *kex) | |||
275 | 276 | ||
276 | /* sign H */ | 277 | /* sign H */ |
277 | /* XXX hashlen depends on KEX */ | 278 | /* XXX hashlen depends on KEX */ |
278 | key_sign(server_host_key, &signature, &slen, hash, 20); | 279 | PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); |
279 | 280 | ||
280 | /* destroy_sensitive_data(); */ | 281 | /* destroy_sensitive_data(); */ |
281 | 282 | ||
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include "includes.h" | 26 | #include "includes.h" |
27 | RCSID("$OpenBSD: kexgex.c,v 1.20 2002/02/28 15:46:33 markus Exp $"); | 27 | RCSID("$OpenBSD: kexgex.c,v 1.21 2002/03/18 17:50:31 provos Exp $"); |
28 | 28 | ||
29 | #include <openssl/bn.h> | 29 | #include <openssl/bn.h> |
30 | 30 | ||
@@ -38,6 +38,7 @@ RCSID("$OpenBSD: kexgex.c,v 1.20 2002/02/28 15:46:33 markus Exp $"); | |||
38 | #include "dh.h" | 38 | #include "dh.h" |
39 | #include "ssh2.h" | 39 | #include "ssh2.h" |
40 | #include "compat.h" | 40 | #include "compat.h" |
41 | #include "monitor_wrap.h" | ||
41 | 42 | ||
42 | static u_char * | 43 | static u_char * |
43 | kexgex_hash( | 44 | kexgex_hash( |
@@ -296,7 +297,8 @@ kexgex_server(Kex *kex) | |||
296 | fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", | 297 | fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", |
297 | min, nbits, max); | 298 | min, nbits, max); |
298 | 299 | ||
299 | dh = choose_dh(min, nbits, max); | 300 | /* Contact privileged parent */ |
301 | dh = PRIVSEP(choose_dh(min, nbits, max)); | ||
300 | if (dh == NULL) | 302 | if (dh == NULL) |
301 | packet_disconnect("Protocol error: no matching DH grp found"); | 303 | packet_disconnect("Protocol error: no matching DH grp found"); |
302 | 304 | ||
@@ -379,7 +381,7 @@ kexgex_server(Kex *kex) | |||
379 | 381 | ||
380 | /* sign H */ | 382 | /* sign H */ |
381 | /* XXX hashlen depends on KEX */ | 383 | /* XXX hashlen depends on KEX */ |
382 | key_sign(server_host_key, &signature, &slen, hash, 20); | 384 | PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); |
383 | 385 | ||
384 | /* destroy_sensitive_data(); */ | 386 | /* destroy_sensitive_data(); */ |
385 | 387 | ||
@@ -390,6 +392,7 @@ kexgex_server(Kex *kex) | |||
390 | packet_put_bignum2(dh->pub_key); /* f */ | 392 | packet_put_bignum2(dh->pub_key); /* f */ |
391 | packet_put_string(signature, slen); | 393 | packet_put_string(signature, slen); |
392 | packet_send(); | 394 | packet_send(); |
395 | |||
393 | xfree(signature); | 396 | xfree(signature); |
394 | xfree(server_host_key_blob); | 397 | xfree(server_host_key_blob); |
395 | /* have keys, free DH */ | 398 | /* have keys, free DH */ |
diff --git a/monitor.c b/monitor.c new file mode 100644 index 000000000..921ad985a --- /dev/null +++ b/monitor.c | |||
@@ -0,0 +1,1440 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | RCSID("$OpenBSD: monitor.c,v 1.6 2002/03/21 18:38:33 stevesk Exp $"); | ||
29 | |||
30 | #include <openssl/dh.h> | ||
31 | |||
32 | #ifdef SKEY | ||
33 | #include <skey.h> | ||
34 | #endif | ||
35 | |||
36 | #include "ssh.h" | ||
37 | #include "auth.h" | ||
38 | #include "kex.h" | ||
39 | #include "dh.h" | ||
40 | #include "zlib.h" | ||
41 | #include "packet.h" | ||
42 | #include "auth-options.h" | ||
43 | #include "sshpty.h" | ||
44 | #include "channels.h" | ||
45 | #include "session.h" | ||
46 | #include "sshlogin.h" | ||
47 | #include "canohost.h" | ||
48 | #include "log.h" | ||
49 | #include "servconf.h" | ||
50 | #include "monitor.h" | ||
51 | #include "monitor_mm.h" | ||
52 | #include "monitor_wrap.h" | ||
53 | #include "monitor_fdpass.h" | ||
54 | #include "xmalloc.h" | ||
55 | #include "misc.h" | ||
56 | #include "buffer.h" | ||
57 | #include "bufaux.h" | ||
58 | #include "compat.h" | ||
59 | #include "ssh2.h" | ||
60 | #include "mpaux.h" | ||
61 | |||
62 | /* Imports */ | ||
63 | extern ServerOptions options; | ||
64 | extern u_int utmp_len; | ||
65 | extern Newkeys *current_keys[]; | ||
66 | extern z_stream incoming_stream; | ||
67 | extern z_stream outgoing_stream; | ||
68 | extern u_char session_id[]; | ||
69 | extern Buffer input, output; | ||
70 | extern Buffer auth_debug; | ||
71 | extern int auth_debug_init; | ||
72 | |||
73 | /* State exported from the child */ | ||
74 | |||
75 | struct { | ||
76 | z_stream incoming; | ||
77 | z_stream outgoing; | ||
78 | u_char *keyin; | ||
79 | u_int keyinlen; | ||
80 | u_char *keyout; | ||
81 | u_int keyoutlen; | ||
82 | u_char *ivin; | ||
83 | u_int ivinlen; | ||
84 | u_char *ivout; | ||
85 | u_int ivoutlen; | ||
86 | int ssh1cipher; | ||
87 | int ssh1protoflags; | ||
88 | u_char *input; | ||
89 | u_int ilen; | ||
90 | u_char *output; | ||
91 | u_int olen; | ||
92 | } child_state; | ||
93 | |||
94 | /* Functions on the montior that answer unprivileged requests */ | ||
95 | |||
96 | int mm_answer_moduli(int, Buffer *); | ||
97 | int mm_answer_sign(int, Buffer *); | ||
98 | int mm_answer_pwnamallow(int, Buffer *); | ||
99 | int mm_answer_authserv(int, Buffer *); | ||
100 | int mm_answer_authpassword(int, Buffer *); | ||
101 | int mm_answer_bsdauthquery(int, Buffer *); | ||
102 | int mm_answer_bsdauthrespond(int, Buffer *); | ||
103 | int mm_answer_skeyquery(int, Buffer *); | ||
104 | int mm_answer_skeyrespond(int, Buffer *); | ||
105 | int mm_answer_keyallowed(int, Buffer *); | ||
106 | int mm_answer_keyverify(int, Buffer *); | ||
107 | int mm_answer_pty(int, Buffer *); | ||
108 | int mm_answer_pty_cleanup(int, Buffer *); | ||
109 | int mm_answer_term(int, Buffer *); | ||
110 | int mm_answer_rsa_keyallowed(int, Buffer *); | ||
111 | int mm_answer_rsa_challenge(int, Buffer *); | ||
112 | int mm_answer_rsa_response(int, Buffer *); | ||
113 | int mm_answer_sesskey(int, Buffer *); | ||
114 | int mm_answer_sessid(int, Buffer *); | ||
115 | |||
116 | static Authctxt *authctxt; | ||
117 | static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ | ||
118 | |||
119 | /* local state for key verify */ | ||
120 | static u_char *key_blob = NULL; | ||
121 | static u_int key_bloblen = 0; | ||
122 | static int key_blobtype = MM_NOKEY; | ||
123 | static u_char *hostbased_cuser = NULL; | ||
124 | static u_char *hostbased_chost = NULL; | ||
125 | static char *auth_method = "unknown"; | ||
126 | |||
127 | struct mon_table { | ||
128 | enum monitor_reqtype type; | ||
129 | int flags; | ||
130 | int (*f)(int, Buffer *); | ||
131 | }; | ||
132 | |||
133 | #define MON_ISAUTH 0x0004 /* Required for Authentication */ | ||
134 | #define MON_AUTHDECIDE 0x0008 /* Decides Authentication */ | ||
135 | #define MON_ONCE 0x0010 /* Disable after calling */ | ||
136 | |||
137 | #define MON_AUTH (MON_ISAUTH|MON_AUTHDECIDE) | ||
138 | |||
139 | #define MON_PERMIT 0x1000 /* Request is permitted */ | ||
140 | |||
141 | struct mon_table mon_dispatch_proto20[] = { | ||
142 | {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, | ||
143 | {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, | ||
144 | {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, | ||
145 | {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, | ||
146 | {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, | ||
147 | #ifdef BSD_AUTH | ||
148 | {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, | ||
149 | {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond}, | ||
150 | #endif | ||
151 | #ifdef SKEY | ||
152 | {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, | ||
153 | {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, | ||
154 | #endif | ||
155 | {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, | ||
156 | {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, | ||
157 | {0, 0, NULL} | ||
158 | }; | ||
159 | |||
160 | struct mon_table mon_dispatch_postauth20[] = { | ||
161 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, | ||
162 | {MONITOR_REQ_SIGN, 0, mm_answer_sign}, | ||
163 | {MONITOR_REQ_PTY, 0, mm_answer_pty}, | ||
164 | {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, | ||
165 | {MONITOR_REQ_TERM, 0, mm_answer_term}, | ||
166 | {0, 0, NULL} | ||
167 | }; | ||
168 | |||
169 | struct mon_table mon_dispatch_proto15[] = { | ||
170 | {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, | ||
171 | {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, | ||
172 | {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, | ||
173 | {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, | ||
174 | {MONITOR_REQ_RSAKEYALLOWED, MON_ISAUTH, mm_answer_rsa_keyallowed}, | ||
175 | {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, | ||
176 | {MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge}, | ||
177 | {MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response}, | ||
178 | #ifdef BSD_AUTH | ||
179 | {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, | ||
180 | {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond}, | ||
181 | #endif | ||
182 | #ifdef SKEY | ||
183 | {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, | ||
184 | {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, | ||
185 | #endif | ||
186 | {0, 0, NULL} | ||
187 | }; | ||
188 | |||
189 | struct mon_table mon_dispatch_postauth15[] = { | ||
190 | {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, | ||
191 | {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, | ||
192 | {MONITOR_REQ_TERM, 0, mm_answer_term}, | ||
193 | {0, 0, NULL} | ||
194 | }; | ||
195 | |||
196 | struct mon_table *mon_dispatch; | ||
197 | |||
198 | /* Specifies if a certain message is allowed at the moment */ | ||
199 | |||
200 | static void | ||
201 | monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit) | ||
202 | { | ||
203 | while (ent->f != NULL) { | ||
204 | if (ent->type == type) { | ||
205 | ent->flags &= ~MON_PERMIT; | ||
206 | ent->flags |= permit ? MON_PERMIT : 0; | ||
207 | return; | ||
208 | } | ||
209 | ent++; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | static void | ||
214 | monitor_permit_authentications(int permit) | ||
215 | { | ||
216 | struct mon_table *ent = mon_dispatch; | ||
217 | |||
218 | while (ent->f != NULL) { | ||
219 | if (ent->flags & MON_AUTH) { | ||
220 | ent->flags &= ~MON_PERMIT; | ||
221 | ent->flags |= permit ? MON_PERMIT : 0; | ||
222 | } | ||
223 | ent++; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | Authctxt * | ||
228 | monitor_child_preauth(struct monitor *monitor) | ||
229 | { | ||
230 | struct mon_table *ent; | ||
231 | int authenticated = 0; | ||
232 | |||
233 | debug3("preauth child monitor started"); | ||
234 | |||
235 | if (compat20) { | ||
236 | mon_dispatch = mon_dispatch_proto20; | ||
237 | |||
238 | /* Permit requests for moduli and signatures */ | ||
239 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | ||
240 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | ||
241 | } else { | ||
242 | mon_dispatch = mon_dispatch_proto15; | ||
243 | |||
244 | monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); | ||
245 | } | ||
246 | |||
247 | authctxt = authctxt_new(); | ||
248 | |||
249 | /* The first few requests do not require asynchronous access */ | ||
250 | while (!authenticated) { | ||
251 | authenticated = monitor_read(monitor, mon_dispatch, &ent); | ||
252 | if (authenticated) { | ||
253 | if (!(ent->flags & MON_AUTHDECIDE)) | ||
254 | fatal("%s: unexpected authentication from %d", | ||
255 | __FUNCTION__, ent->type); | ||
256 | if (authctxt->pw->pw_uid == 0 && | ||
257 | !auth_root_allowed(auth_method)) | ||
258 | authenticated = 0; | ||
259 | } | ||
260 | |||
261 | if (ent->flags & MON_AUTHDECIDE) { | ||
262 | auth_log(authctxt, authenticated, auth_method, | ||
263 | compat20 ? " ssh2" : ""); | ||
264 | if (!authenticated) | ||
265 | authctxt->failures++; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | if (!authctxt->valid) | ||
270 | fatal("%s: authenticated invalid user", __FUNCTION__); | ||
271 | |||
272 | debug("%s: %s has been authenticated by privileged process", | ||
273 | __FUNCTION__, authctxt->user); | ||
274 | |||
275 | mm_get_keystate(monitor); | ||
276 | |||
277 | return (authctxt); | ||
278 | } | ||
279 | |||
280 | void | ||
281 | monitor_child_postauth(struct monitor *monitor) | ||
282 | { | ||
283 | if (compat20) { | ||
284 | mon_dispatch = mon_dispatch_postauth20; | ||
285 | |||
286 | /* Permit requests for moduli and signatures */ | ||
287 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | ||
288 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | ||
289 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | ||
290 | |||
291 | } else { | ||
292 | mon_dispatch = mon_dispatch_postauth15; | ||
293 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | ||
294 | } | ||
295 | if (!no_pty_flag) { | ||
296 | monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); | ||
297 | monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); | ||
298 | } | ||
299 | |||
300 | for (;;) | ||
301 | monitor_read(monitor, mon_dispatch, NULL); | ||
302 | } | ||
303 | |||
304 | void | ||
305 | monitor_sync(struct monitor *monitor) | ||
306 | { | ||
307 | /* The member allocation is not visible, so sync it */ | ||
308 | mm_share_sync(&monitor->m_zlib, &monitor->m_zback); | ||
309 | } | ||
310 | |||
311 | int | ||
312 | monitor_read(struct monitor *monitor, struct mon_table *ent, | ||
313 | struct mon_table **pent) | ||
314 | { | ||
315 | Buffer m; | ||
316 | int ret; | ||
317 | u_char type; | ||
318 | |||
319 | buffer_init(&m); | ||
320 | |||
321 | mm_request_receive(monitor->m_sendfd, &m); | ||
322 | type = buffer_get_char(&m); | ||
323 | |||
324 | debug3("%s: checking request %d", __FUNCTION__, type); | ||
325 | |||
326 | while (ent->f != NULL) { | ||
327 | if (ent->type == type) | ||
328 | break; | ||
329 | ent++; | ||
330 | } | ||
331 | |||
332 | if (ent->f != NULL) { | ||
333 | if (!(ent->flags & MON_PERMIT)) | ||
334 | fatal("%s: unpermitted request %d", __FUNCTION__, | ||
335 | type); | ||
336 | ret = (*ent->f)(monitor->m_sendfd, &m); | ||
337 | buffer_free(&m); | ||
338 | |||
339 | /* The child may use this request only once, disable it */ | ||
340 | if (ent->flags & MON_ONCE) { | ||
341 | debug2("%s: %d used once, disabling now", __FUNCTION__, | ||
342 | type); | ||
343 | ent->flags &= ~MON_PERMIT; | ||
344 | } | ||
345 | |||
346 | if (pent != NULL) | ||
347 | *pent = ent; | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | fatal("%s: unsupported request: %d\n", __FUNCTION__, type); | ||
353 | |||
354 | /* NOTREACHED */ | ||
355 | return (-1); | ||
356 | } | ||
357 | |||
358 | /* allowed key state */ | ||
359 | static int | ||
360 | monitor_allowed_key(u_char *blob, u_int bloblen) | ||
361 | { | ||
362 | /* make sure key is allowed */ | ||
363 | if (key_blob == NULL || key_bloblen != bloblen || | ||
364 | memcmp(key_blob, blob, key_bloblen)) | ||
365 | return (0); | ||
366 | return (1); | ||
367 | } | ||
368 | |||
369 | static void | ||
370 | monitor_reset_key_state(void) | ||
371 | { | ||
372 | /* reset state */ | ||
373 | if (key_blob != NULL) | ||
374 | xfree(key_blob); | ||
375 | if (hostbased_cuser != NULL) | ||
376 | xfree(hostbased_cuser); | ||
377 | if (hostbased_chost != NULL) | ||
378 | xfree(hostbased_chost); | ||
379 | key_blob = NULL; | ||
380 | key_bloblen = 0; | ||
381 | key_blobtype = MM_NOKEY; | ||
382 | hostbased_cuser = NULL; | ||
383 | hostbased_chost = NULL; | ||
384 | } | ||
385 | |||
386 | int | ||
387 | mm_answer_moduli(int socket, Buffer *m) | ||
388 | { | ||
389 | DH *dh; | ||
390 | int min, want, max; | ||
391 | |||
392 | min = buffer_get_int(m); | ||
393 | want = buffer_get_int(m); | ||
394 | max = buffer_get_int(m); | ||
395 | |||
396 | debug3("%s: got parameters: %d %d %d", | ||
397 | __FUNCTION__, min, want, max); | ||
398 | /* We need to check here, too, in case the child got corrupted */ | ||
399 | if (max < min || want < min || max < want) | ||
400 | fatal("%s: bad parameters: %d %d %d", | ||
401 | __FUNCTION__, min, want, max); | ||
402 | |||
403 | buffer_clear(m); | ||
404 | |||
405 | dh = choose_dh(min, want, max); | ||
406 | if (dh == NULL) { | ||
407 | buffer_put_char(m, 0); | ||
408 | return (0); | ||
409 | } else { | ||
410 | /* Send first bignum */ | ||
411 | buffer_put_char(m, 1); | ||
412 | buffer_put_bignum2(m, dh->p); | ||
413 | buffer_put_bignum2(m, dh->g); | ||
414 | |||
415 | DH_free(dh); | ||
416 | } | ||
417 | mm_request_send(socket, MONITOR_ANS_MODULI, m); | ||
418 | return (0); | ||
419 | } | ||
420 | |||
421 | int | ||
422 | mm_answer_sign(int socket, Buffer *m) | ||
423 | { | ||
424 | Key *key; | ||
425 | u_char *p; | ||
426 | u_char *signature; | ||
427 | u_int siglen, datlen; | ||
428 | int keyid; | ||
429 | |||
430 | debug3("%s", __FUNCTION__); | ||
431 | |||
432 | keyid = buffer_get_int(m); | ||
433 | p = buffer_get_string(m, &datlen); | ||
434 | |||
435 | if (datlen != 20) | ||
436 | fatal("%s: data length incorrect: %d", __FUNCTION__, datlen); | ||
437 | |||
438 | if ((key = get_hostkey_by_index(keyid)) == NULL) | ||
439 | fatal("%s: no hostkey from index %d", __FUNCTION__, keyid); | ||
440 | if (key_sign(key, &signature, &siglen, p, datlen) < 0) | ||
441 | fatal("%s: key_sign failed", __FUNCTION__); | ||
442 | |||
443 | debug3("%s: signature %p(%d)", __FUNCTION__, signature, siglen); | ||
444 | |||
445 | buffer_clear(m); | ||
446 | buffer_put_string(m, signature, siglen); | ||
447 | |||
448 | xfree(p); | ||
449 | xfree(signature); | ||
450 | |||
451 | mm_request_send(socket, MONITOR_ANS_SIGN, m); | ||
452 | |||
453 | /* Turn on permissions for getpwnam */ | ||
454 | monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); | ||
455 | |||
456 | return (0); | ||
457 | } | ||
458 | |||
459 | /* Retrieves the password entry and also checks if the user is permitted */ | ||
460 | |||
461 | int | ||
462 | mm_answer_pwnamallow(int socket, Buffer *m) | ||
463 | { | ||
464 | char *login; | ||
465 | struct passwd *pwent; | ||
466 | int allowed = 0; | ||
467 | |||
468 | debug3("%s", __FUNCTION__); | ||
469 | |||
470 | if (authctxt->attempt++ != 0) | ||
471 | fatal("%s: multiple attempts for getpwnam", __FUNCTION__); | ||
472 | |||
473 | login = buffer_get_string(m, NULL); | ||
474 | |||
475 | pwent = getpwnamallow(login); | ||
476 | |||
477 | authctxt->user = xstrdup(login); | ||
478 | setproctitle("%s [priv]", pwent ? login : "unknown"); | ||
479 | xfree(login); | ||
480 | |||
481 | buffer_clear(m); | ||
482 | |||
483 | if (pwent == NULL) { | ||
484 | buffer_put_char(m, 0); | ||
485 | goto out; | ||
486 | } | ||
487 | |||
488 | allowed = 1; | ||
489 | authctxt->pw = pwent; | ||
490 | authctxt->valid = 1; | ||
491 | |||
492 | buffer_put_char(m, 1); | ||
493 | buffer_put_string(m, pwent, sizeof(struct passwd)); | ||
494 | buffer_put_cstring(m, pwent->pw_name); | ||
495 | buffer_put_cstring(m, "*"); | ||
496 | buffer_put_cstring(m, pwent->pw_gecos); | ||
497 | buffer_put_cstring(m, pwent->pw_class); | ||
498 | buffer_put_cstring(m, pwent->pw_dir); | ||
499 | buffer_put_cstring(m, pwent->pw_shell); | ||
500 | |||
501 | out: | ||
502 | debug3("%s: sending MONITOR_ANS_PWNAM: %d", __FUNCTION__, allowed); | ||
503 | mm_request_send(socket, MONITOR_ANS_PWNAM, m); | ||
504 | |||
505 | /* For SSHv1 allow authentication now */ | ||
506 | if (!compat20) | ||
507 | monitor_permit_authentications(1); | ||
508 | else | ||
509 | /* Allow service/style information on the auth context */ | ||
510 | monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); | ||
511 | |||
512 | |||
513 | return (0); | ||
514 | } | ||
515 | |||
516 | int | ||
517 | mm_answer_authserv(int socket, Buffer *m) | ||
518 | { | ||
519 | monitor_permit_authentications(1); | ||
520 | |||
521 | authctxt->service = buffer_get_string(m, NULL); | ||
522 | authctxt->style = buffer_get_string(m, NULL); | ||
523 | debug3("%s: service=%s, style=%s", | ||
524 | __FUNCTION__, authctxt->service, authctxt->style); | ||
525 | |||
526 | if (strlen(authctxt->style) == 0) { | ||
527 | xfree(authctxt->style); | ||
528 | authctxt->style = NULL; | ||
529 | } | ||
530 | |||
531 | return (0); | ||
532 | } | ||
533 | |||
534 | int | ||
535 | mm_answer_authpassword(int socket, Buffer *m) | ||
536 | { | ||
537 | static int call_count; | ||
538 | char *passwd; | ||
539 | int authenticated, plen; | ||
540 | |||
541 | passwd = buffer_get_string(m, &plen); | ||
542 | /* Only authenticate if the context is valid */ | ||
543 | authenticated = authctxt->valid && auth_password(authctxt, passwd); | ||
544 | memset(passwd, 0, strlen(passwd)); | ||
545 | xfree(passwd); | ||
546 | |||
547 | buffer_clear(m); | ||
548 | buffer_put_int(m, authenticated); | ||
549 | |||
550 | debug3("%s: sending result %d", __FUNCTION__, authenticated); | ||
551 | mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m); | ||
552 | |||
553 | call_count++; | ||
554 | if (plen == 0 && call_count == 1) | ||
555 | auth_method = "none"; | ||
556 | else | ||
557 | auth_method = "password"; | ||
558 | |||
559 | /* Causes monitor loop to terminate if authenticated */ | ||
560 | return (authenticated); | ||
561 | } | ||
562 | |||
563 | #ifdef BSD_AUTH | ||
564 | int | ||
565 | mm_answer_bsdauthquery(int socket, Buffer *m) | ||
566 | { | ||
567 | char *name, *infotxt; | ||
568 | u_int numprompts; | ||
569 | u_int *echo_on; | ||
570 | char **prompts; | ||
571 | int res; | ||
572 | |||
573 | res = bsdauth_query(authctxt, &name, &infotxt, &numprompts, | ||
574 | &prompts, &echo_on); | ||
575 | |||
576 | buffer_clear(m); | ||
577 | buffer_put_int(m, res); | ||
578 | if (res != -1) | ||
579 | buffer_put_cstring(m, prompts[0]); | ||
580 | |||
581 | debug3("%s: sending challenge res: %d", __FUNCTION__, res); | ||
582 | mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m); | ||
583 | |||
584 | if (res != -1) { | ||
585 | xfree(name); | ||
586 | xfree(infotxt); | ||
587 | xfree(prompts); | ||
588 | xfree(echo_on); | ||
589 | } | ||
590 | |||
591 | return (0); | ||
592 | } | ||
593 | |||
594 | int | ||
595 | mm_answer_bsdauthrespond(int socket, Buffer *m) | ||
596 | { | ||
597 | char *response; | ||
598 | int authok; | ||
599 | |||
600 | if (authctxt->as == 0) | ||
601 | fatal("%s: no bsd auth session", __FUNCTION__); | ||
602 | |||
603 | response = buffer_get_string(m, NULL); | ||
604 | authok = auth_userresponse(authctxt->as, response, 0); | ||
605 | authctxt->as = NULL; | ||
606 | debug3("%s: <%s> = <%d>", __FUNCTION__, response, authok); | ||
607 | xfree(response); | ||
608 | |||
609 | buffer_clear(m); | ||
610 | buffer_put_int(m, authok); | ||
611 | |||
612 | debug3("%s: sending authenticated: %d", __FUNCTION__, authok); | ||
613 | mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m); | ||
614 | |||
615 | auth_method = "bsdauth"; | ||
616 | |||
617 | return (authok != 0); | ||
618 | } | ||
619 | #endif | ||
620 | |||
621 | #ifdef SKEY | ||
622 | int | ||
623 | mm_answer_skeyquery(int socket, Buffer *m) | ||
624 | { | ||
625 | struct skey skey; | ||
626 | char challenge[1024]; | ||
627 | int res; | ||
628 | |||
629 | res = skeychallenge(&skey, authctxt->user, challenge); | ||
630 | |||
631 | buffer_clear(m); | ||
632 | buffer_put_int(m, res); | ||
633 | if (res != -1) | ||
634 | buffer_put_cstring(m, challenge); | ||
635 | |||
636 | debug3("%s: sending challenge res: %d", __FUNCTION__, res); | ||
637 | mm_request_send(socket, MONITOR_ANS_SKEYQUERY, m); | ||
638 | |||
639 | return (0); | ||
640 | } | ||
641 | |||
642 | int | ||
643 | mm_answer_skeyrespond(int socket, Buffer *m) | ||
644 | { | ||
645 | char *response; | ||
646 | int authok; | ||
647 | |||
648 | response = buffer_get_string(m, NULL); | ||
649 | |||
650 | authok = (authctxt->valid && | ||
651 | skey_haskey(authctxt->pw->pw_name) == 0 && | ||
652 | skey_passcheck(authctxt->pw->pw_name, response) != -1); | ||
653 | |||
654 | xfree(response); | ||
655 | |||
656 | buffer_clear(m); | ||
657 | buffer_put_int(m, authok); | ||
658 | |||
659 | debug3("%s: sending authenticated: %d", __FUNCTION__, authok); | ||
660 | mm_request_send(socket, MONITOR_ANS_SKEYRESPOND, m); | ||
661 | |||
662 | auth_method = "skey"; | ||
663 | |||
664 | return (authok != 0); | ||
665 | } | ||
666 | #endif | ||
667 | |||
668 | static void | ||
669 | mm_append_debug(Buffer *m) | ||
670 | { | ||
671 | if (auth_debug_init && buffer_len(&auth_debug)) { | ||
672 | debug3("%s: Appending debug messages for child", __FUNCTION__); | ||
673 | buffer_append(m, buffer_ptr(&auth_debug), | ||
674 | buffer_len(&auth_debug)); | ||
675 | buffer_clear(&auth_debug); | ||
676 | } | ||
677 | } | ||
678 | |||
679 | int | ||
680 | mm_answer_keyallowed(int socket, Buffer *m) | ||
681 | { | ||
682 | Key *key; | ||
683 | u_char *cuser, *chost, *blob; | ||
684 | u_int bloblen; | ||
685 | enum mm_keytype type = 0; | ||
686 | int allowed = 0; | ||
687 | |||
688 | debug3("%s entering", __FUNCTION__); | ||
689 | |||
690 | type = buffer_get_int(m); | ||
691 | cuser = buffer_get_string(m, NULL); | ||
692 | chost = buffer_get_string(m, NULL); | ||
693 | blob = buffer_get_string(m, &bloblen); | ||
694 | |||
695 | key = key_from_blob(blob, bloblen); | ||
696 | |||
697 | if ((compat20 && type == MM_RSAHOSTKEY) || | ||
698 | (!compat20 && type != MM_RSAHOSTKEY)) | ||
699 | fatal("%s: key type and protocol mismatch", __FUNCTION__); | ||
700 | |||
701 | debug3("%s: key_from_blob: %p", __FUNCTION__, key); | ||
702 | |||
703 | if (key != NULL && authctxt->pw != NULL) { | ||
704 | switch(type) { | ||
705 | case MM_USERKEY: | ||
706 | allowed = user_key_allowed(authctxt->pw, key); | ||
707 | break; | ||
708 | case MM_HOSTKEY: | ||
709 | allowed = hostbased_key_allowed(authctxt->pw, | ||
710 | cuser, chost, key); | ||
711 | break; | ||
712 | case MM_RSAHOSTKEY: | ||
713 | key->type = KEY_RSA1; /* XXX */ | ||
714 | allowed = auth_rhosts_rsa_key_allowed(authctxt->pw, | ||
715 | cuser, chost, key); | ||
716 | break; | ||
717 | default: | ||
718 | fatal("%s: unknown key type %d", __FUNCTION__, type); | ||
719 | break; | ||
720 | } | ||
721 | key_free(key); | ||
722 | } | ||
723 | |||
724 | /* clear temporarily storage (used by verify) */ | ||
725 | monitor_reset_key_state(); | ||
726 | |||
727 | if (allowed) { | ||
728 | /* Save temporarily for comparison in verify */ | ||
729 | key_blob = blob; | ||
730 | key_bloblen = bloblen; | ||
731 | key_blobtype = type; | ||
732 | hostbased_cuser = cuser; | ||
733 | hostbased_chost = chost; | ||
734 | } | ||
735 | |||
736 | debug3("%s: key %p is %s", | ||
737 | __FUNCTION__, key, allowed ? "allowed" : "disallowed"); | ||
738 | |||
739 | buffer_clear(m); | ||
740 | buffer_put_int(m, allowed); | ||
741 | |||
742 | mm_append_debug(m); | ||
743 | |||
744 | mm_request_send(socket, MONITOR_ANS_KEYALLOWED, m); | ||
745 | |||
746 | if (type == MM_RSAHOSTKEY) | ||
747 | monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); | ||
748 | |||
749 | return (0); | ||
750 | } | ||
751 | |||
752 | static int | ||
753 | monitor_valid_userblob(u_char *data, u_int datalen) | ||
754 | { | ||
755 | Buffer b; | ||
756 | u_char *p; | ||
757 | u_int len; | ||
758 | int fail = 0; | ||
759 | int session_id2_len = 20 /*XXX should get from [net] */; | ||
760 | |||
761 | buffer_init(&b); | ||
762 | buffer_append(&b, data, datalen); | ||
763 | |||
764 | if (datafellows & SSH_OLD_SESSIONID) { | ||
765 | buffer_consume(&b, session_id2_len); | ||
766 | } else { | ||
767 | xfree(buffer_get_string(&b, &len)); | ||
768 | if (len != session_id2_len) | ||
769 | fail++; | ||
770 | } | ||
771 | if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) | ||
772 | fail++; | ||
773 | p = buffer_get_string(&b, NULL); | ||
774 | if (strcmp(authctxt->user, p) != 0) { | ||
775 | log("wrong user name passed to monitor: expected %s != %.100s", | ||
776 | authctxt->user, p); | ||
777 | fail++; | ||
778 | } | ||
779 | xfree(p); | ||
780 | buffer_skip_string(&b); | ||
781 | if (datafellows & SSH_BUG_PKAUTH) { | ||
782 | if (!buffer_get_char(&b)) | ||
783 | fail++; | ||
784 | } else { | ||
785 | p = buffer_get_string(&b, NULL); | ||
786 | if (strcmp("publickey", p) != 0) | ||
787 | fail++; | ||
788 | xfree(p); | ||
789 | if (!buffer_get_char(&b)) | ||
790 | fail++; | ||
791 | buffer_skip_string(&b); | ||
792 | } | ||
793 | buffer_skip_string(&b); | ||
794 | if (buffer_len(&b) != 0) | ||
795 | fail++; | ||
796 | buffer_free(&b); | ||
797 | return (fail == 0); | ||
798 | } | ||
799 | |||
800 | static int | ||
801 | monitor_valid_hostbasedblob(u_char *data, u_int datalen, u_char *cuser, | ||
802 | u_char *chost) | ||
803 | { | ||
804 | Buffer b; | ||
805 | u_char *p; | ||
806 | u_int len; | ||
807 | int fail = 0; | ||
808 | int session_id2_len = 20 /*XXX should get from [net] */; | ||
809 | |||
810 | buffer_init(&b); | ||
811 | buffer_append(&b, data, datalen); | ||
812 | |||
813 | xfree(buffer_get_string(&b, &len)); | ||
814 | if (len != session_id2_len) | ||
815 | fail++; | ||
816 | if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) | ||
817 | fail++; | ||
818 | p = buffer_get_string(&b, NULL); | ||
819 | if (strcmp(authctxt->user, p) != 0) { | ||
820 | log("wrong user name passed to monitor: expected %s != %.100s", | ||
821 | authctxt->user, p); | ||
822 | fail++; | ||
823 | } | ||
824 | xfree(p); | ||
825 | buffer_skip_string(&b); /* service */ | ||
826 | p = buffer_get_string(&b, NULL); | ||
827 | if (strcmp(p, "hostbased") != 0) | ||
828 | fail++; | ||
829 | xfree(p); | ||
830 | buffer_skip_string(&b); /* pkalg */ | ||
831 | buffer_skip_string(&b); /* pkblob */ | ||
832 | |||
833 | /* verify client host, strip trailing dot if necessary */ | ||
834 | p = buffer_get_string(&b, NULL); | ||
835 | if (((len = strlen(p)) > 0) && p[len - 1] == '.') | ||
836 | p[len - 1] = '\0'; | ||
837 | if (strcmp(p, chost) != 0) | ||
838 | fail++; | ||
839 | xfree(p); | ||
840 | |||
841 | /* verify client user */ | ||
842 | p = buffer_get_string(&b, NULL); | ||
843 | if (strcmp(p, cuser) != 0) | ||
844 | fail++; | ||
845 | xfree(p); | ||
846 | |||
847 | if (buffer_len(&b) != 0) | ||
848 | fail++; | ||
849 | buffer_free(&b); | ||
850 | return (fail == 0); | ||
851 | } | ||
852 | |||
853 | int | ||
854 | mm_answer_keyverify(int socket, Buffer *m) | ||
855 | { | ||
856 | Key *key; | ||
857 | u_char *signature, *data, *blob; | ||
858 | u_int signaturelen, datalen, bloblen; | ||
859 | int verified = 0; | ||
860 | int valid_data = 0; | ||
861 | |||
862 | blob = buffer_get_string(m, &bloblen); | ||
863 | signature = buffer_get_string(m, &signaturelen); | ||
864 | data = buffer_get_string(m, &datalen); | ||
865 | |||
866 | if (hostbased_cuser == NULL || hostbased_chost == NULL || | ||
867 | monitor_allowed_key(blob, bloblen) == NULL) | ||
868 | fatal("%s: bad key, not previously allowed", __FUNCTION__); | ||
869 | |||
870 | key = key_from_blob(blob, bloblen); | ||
871 | if (key == NULL) | ||
872 | fatal("%s: bad public key blob", __FUNCTION__); | ||
873 | |||
874 | switch (key_blobtype) { | ||
875 | case MM_USERKEY: | ||
876 | valid_data = monitor_valid_userblob(data, datalen); | ||
877 | break; | ||
878 | case MM_HOSTKEY: | ||
879 | valid_data = monitor_valid_hostbasedblob(data, datalen, | ||
880 | hostbased_cuser, hostbased_chost); | ||
881 | break; | ||
882 | default: | ||
883 | valid_data = 0; | ||
884 | break; | ||
885 | } | ||
886 | if (!valid_data) | ||
887 | fatal("%s: bad signature data blob", __FUNCTION__); | ||
888 | |||
889 | verified = key_verify(key, signature, signaturelen, data, datalen); | ||
890 | debug3("%s: key %p signature %s", | ||
891 | __FUNCTION__, key, verified ? "verified" : "unverified"); | ||
892 | |||
893 | key_free(key); | ||
894 | xfree(blob); | ||
895 | xfree(signature); | ||
896 | xfree(data); | ||
897 | |||
898 | monitor_reset_key_state(); | ||
899 | |||
900 | buffer_clear(m); | ||
901 | buffer_put_int(m, verified); | ||
902 | mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m); | ||
903 | |||
904 | auth_method = "publickey"; | ||
905 | |||
906 | return (verified); | ||
907 | } | ||
908 | |||
909 | static void | ||
910 | mm_record_login(Session *s, struct passwd *pw) | ||
911 | { | ||
912 | socklen_t fromlen; | ||
913 | struct sockaddr_storage from; | ||
914 | |||
915 | /* | ||
916 | * Get IP address of client. If the connection is not a socket, let | ||
917 | * the address be 0.0.0.0. | ||
918 | */ | ||
919 | memset(&from, 0, sizeof(from)); | ||
920 | if (packet_connection_is_on_socket()) { | ||
921 | fromlen = sizeof(from); | ||
922 | if (getpeername(packet_get_connection_in(), | ||
923 | (struct sockaddr *) & from, &fromlen) < 0) { | ||
924 | debug("getpeername: %.100s", strerror(errno)); | ||
925 | fatal_cleanup(); | ||
926 | } | ||
927 | } | ||
928 | /* Record that there was a login on that tty from the remote host. */ | ||
929 | record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, | ||
930 | get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), | ||
931 | (struct sockaddr *)&from); | ||
932 | } | ||
933 | |||
934 | static void | ||
935 | mm_session_close(Session *s) | ||
936 | { | ||
937 | debug3("%s: session %d pid %d", __FUNCTION__, s->self, s->pid); | ||
938 | if (s->ttyfd != -1) { | ||
939 | debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ptyfd); | ||
940 | fatal_remove_cleanup(session_pty_cleanup2, (void *)s); | ||
941 | session_pty_cleanup2(s); | ||
942 | } | ||
943 | s->used = 0; | ||
944 | } | ||
945 | |||
946 | int | ||
947 | mm_answer_pty(int socket, Buffer *m) | ||
948 | { | ||
949 | extern struct monitor *monitor; | ||
950 | Session *s; | ||
951 | int res, fd0; | ||
952 | |||
953 | debug3("%s entering", __FUNCTION__); | ||
954 | |||
955 | buffer_clear(m); | ||
956 | s = session_new(); | ||
957 | if (s == NULL) | ||
958 | goto error; | ||
959 | s->authctxt = authctxt; | ||
960 | s->pw = authctxt->pw; | ||
961 | s->pid = monitor->m_pid; | ||
962 | res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); | ||
963 | if (res == 0) | ||
964 | goto error; | ||
965 | fatal_add_cleanup(session_pty_cleanup2, (void *)s); | ||
966 | pty_setowner(authctxt->pw, s->tty); | ||
967 | |||
968 | buffer_put_int(m, 1); | ||
969 | buffer_put_cstring(m, s->tty); | ||
970 | mm_request_send(socket, MONITOR_ANS_PTY, m); | ||
971 | |||
972 | mm_send_fd(socket, s->ptyfd); | ||
973 | mm_send_fd(socket, s->ttyfd); | ||
974 | |||
975 | /* We need to trick ttyslot */ | ||
976 | if (dup2(s->ttyfd, 0) == -1) | ||
977 | fatal("%s: dup2", __FUNCTION__); | ||
978 | |||
979 | mm_record_login(s, authctxt->pw); | ||
980 | |||
981 | /* Now we can close the file descriptor again */ | ||
982 | close(0); | ||
983 | |||
984 | /* make sure nothing uses fd 0 */ | ||
985 | if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0) | ||
986 | fatal("%s: open(/dev/null): %s", __FUNCTION__, strerror(errno)); | ||
987 | if (fd0 != 0) | ||
988 | error("%s: fd0 %d != 0", __FUNCTION__, fd0); | ||
989 | |||
990 | /* slave is not needed */ | ||
991 | close(s->ttyfd); | ||
992 | s->ttyfd = s->ptyfd; | ||
993 | /* no need to dup() because nobody closes ptyfd */ | ||
994 | s->ptymaster = s->ptyfd; | ||
995 | |||
996 | debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ttyfd); | ||
997 | |||
998 | return (0); | ||
999 | |||
1000 | error: | ||
1001 | if (s != NULL) | ||
1002 | mm_session_close(s); | ||
1003 | buffer_put_int(m, 0); | ||
1004 | mm_request_send(socket, MONITOR_ANS_PTY, m); | ||
1005 | return (0); | ||
1006 | } | ||
1007 | |||
1008 | int | ||
1009 | mm_answer_pty_cleanup(int socket, Buffer *m) | ||
1010 | { | ||
1011 | Session *s; | ||
1012 | char *tty; | ||
1013 | |||
1014 | debug3("%s entering", __FUNCTION__); | ||
1015 | |||
1016 | tty = buffer_get_string(m, NULL); | ||
1017 | if ((s = session_by_tty(tty)) != NULL) | ||
1018 | mm_session_close(s); | ||
1019 | buffer_clear(m); | ||
1020 | xfree(tty); | ||
1021 | return (0); | ||
1022 | } | ||
1023 | |||
1024 | int | ||
1025 | mm_answer_sesskey(int socket, Buffer *m) | ||
1026 | { | ||
1027 | BIGNUM *p; | ||
1028 | int rsafail; | ||
1029 | |||
1030 | /* Turn off permissions */ | ||
1031 | monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); | ||
1032 | |||
1033 | if ((p = BN_new()) == NULL) | ||
1034 | fatal("%s: BN_new", __FUNCTION__); | ||
1035 | |||
1036 | buffer_get_bignum2(m, p); | ||
1037 | |||
1038 | rsafail = ssh1_session_key(p); | ||
1039 | |||
1040 | buffer_clear(m); | ||
1041 | buffer_put_int(m, rsafail); | ||
1042 | buffer_put_bignum2(m, p); | ||
1043 | |||
1044 | BN_clear_free(p); | ||
1045 | |||
1046 | mm_request_send(socket, MONITOR_ANS_SESSKEY, m); | ||
1047 | |||
1048 | /* Turn on permissions for sessid passing */ | ||
1049 | monitor_permit(mon_dispatch, MONITOR_REQ_SESSID, 1); | ||
1050 | |||
1051 | return (0); | ||
1052 | } | ||
1053 | |||
1054 | int | ||
1055 | mm_answer_sessid(int socket, Buffer *m) | ||
1056 | { | ||
1057 | int i; | ||
1058 | |||
1059 | debug3("%s entering", __FUNCTION__); | ||
1060 | |||
1061 | if (buffer_len(m) != 16) | ||
1062 | fatal("%s: bad ssh1 session id", __FUNCTION__); | ||
1063 | for (i = 0; i < 16; i++) | ||
1064 | session_id[i] = buffer_get_char(m); | ||
1065 | |||
1066 | /* Turn on permissions for getpwnam */ | ||
1067 | monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); | ||
1068 | |||
1069 | return (0); | ||
1070 | } | ||
1071 | |||
1072 | int | ||
1073 | mm_answer_rsa_keyallowed(int socket, Buffer *m) | ||
1074 | { | ||
1075 | BIGNUM *client_n; | ||
1076 | Key *key = NULL; | ||
1077 | u_char *blob = NULL; | ||
1078 | u_int blen = 0; | ||
1079 | int allowed = 0; | ||
1080 | |||
1081 | debug3("%s entering", __FUNCTION__); | ||
1082 | |||
1083 | if (authctxt->valid) { | ||
1084 | if ((client_n = BN_new()) == NULL) | ||
1085 | fatal("%s: BN_new", __FUNCTION__); | ||
1086 | buffer_get_bignum2(m, client_n); | ||
1087 | allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); | ||
1088 | BN_clear_free(client_n); | ||
1089 | } | ||
1090 | buffer_clear(m); | ||
1091 | buffer_put_int(m, allowed); | ||
1092 | |||
1093 | /* clear temporarily storage (used by generate challenge) */ | ||
1094 | monitor_reset_key_state(); | ||
1095 | |||
1096 | if (allowed && key != NULL) { | ||
1097 | key->type = KEY_RSA; /* cheat for key_to_blob */ | ||
1098 | if (key_to_blob(key, &blob, &blen) == 0) | ||
1099 | fatal("%s: key_to_blob failed", __FUNCTION__); | ||
1100 | buffer_put_string(m, blob, blen); | ||
1101 | |||
1102 | /* Save temporarily for comparison in verify */ | ||
1103 | key_blob = blob; | ||
1104 | key_bloblen = blen; | ||
1105 | key_blobtype = MM_RSAUSERKEY; | ||
1106 | key_free(key); | ||
1107 | } | ||
1108 | |||
1109 | mm_append_debug(m); | ||
1110 | |||
1111 | mm_request_send(socket, MONITOR_ANS_RSAKEYALLOWED, m); | ||
1112 | |||
1113 | monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); | ||
1114 | monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0); | ||
1115 | return (0); | ||
1116 | } | ||
1117 | |||
1118 | int | ||
1119 | mm_answer_rsa_challenge(int socket, Buffer *m) | ||
1120 | { | ||
1121 | Key *key = NULL; | ||
1122 | u_char *blob; | ||
1123 | u_int blen; | ||
1124 | |||
1125 | debug3("%s entering", __FUNCTION__); | ||
1126 | |||
1127 | if (!authctxt->valid) | ||
1128 | fatal("%s: authctxt not valid", __FUNCTION__); | ||
1129 | blob = buffer_get_string(m, &blen); | ||
1130 | if (!monitor_allowed_key(blob, blen)) | ||
1131 | fatal("%s: bad key, not previously allowed", __FUNCTION__); | ||
1132 | if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) | ||
1133 | fatal("%s: key type mismatch", __FUNCTION__); | ||
1134 | if ((key = key_from_blob(blob, blen)) == NULL) | ||
1135 | fatal("%s: received bad key", __FUNCTION__); | ||
1136 | |||
1137 | if (ssh1_challenge) | ||
1138 | BN_clear_free(ssh1_challenge); | ||
1139 | ssh1_challenge = auth_rsa_generate_challenge(key); | ||
1140 | |||
1141 | buffer_clear(m); | ||
1142 | buffer_put_bignum2(m, ssh1_challenge); | ||
1143 | |||
1144 | debug3("%s sending reply", __FUNCTION__); | ||
1145 | mm_request_send(socket, MONITOR_ANS_RSACHALLENGE, m); | ||
1146 | |||
1147 | monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1); | ||
1148 | return (0); | ||
1149 | } | ||
1150 | |||
1151 | int | ||
1152 | mm_answer_rsa_response(int socket, Buffer *m) | ||
1153 | { | ||
1154 | Key *key = NULL; | ||
1155 | u_char *blob, *response; | ||
1156 | u_int blen, len; | ||
1157 | int success; | ||
1158 | |||
1159 | debug3("%s entering", __FUNCTION__); | ||
1160 | |||
1161 | if (!authctxt->valid) | ||
1162 | fatal("%s: authctxt not valid", __FUNCTION__); | ||
1163 | if (ssh1_challenge == NULL) | ||
1164 | fatal("%s: no ssh1_challenge", __FUNCTION__); | ||
1165 | |||
1166 | blob = buffer_get_string(m, &blen); | ||
1167 | if (!monitor_allowed_key(blob, blen)) | ||
1168 | fatal("%s: bad key, not previously allowed", __FUNCTION__); | ||
1169 | if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) | ||
1170 | fatal("%s: key type mismatch: %d", __FUNCTION__, key_blobtype); | ||
1171 | if ((key = key_from_blob(blob, blen)) == NULL) | ||
1172 | fatal("%s: received bad key", __FUNCTION__); | ||
1173 | response = buffer_get_string(m, &len); | ||
1174 | if (len != 16) | ||
1175 | fatal("%s: received bad response to challenge", __FUNCTION__); | ||
1176 | success = auth_rsa_verify_response(key, ssh1_challenge, response); | ||
1177 | |||
1178 | key_free(key); | ||
1179 | xfree(response); | ||
1180 | |||
1181 | auth_method = key_blobtype == MM_RSAUSERKEY ? "rsa" : "rhosts-rsa"; | ||
1182 | |||
1183 | /* reset state */ | ||
1184 | BN_clear_free(ssh1_challenge); | ||
1185 | ssh1_challenge = NULL; | ||
1186 | monitor_reset_key_state(); | ||
1187 | |||
1188 | buffer_clear(m); | ||
1189 | buffer_put_int(m, success); | ||
1190 | mm_request_send(socket, MONITOR_ANS_RSARESPONSE, m); | ||
1191 | |||
1192 | return (success); | ||
1193 | } | ||
1194 | |||
1195 | int | ||
1196 | mm_answer_term(int socket, Buffer *req) | ||
1197 | { | ||
1198 | extern struct monitor *monitor; | ||
1199 | int res, status; | ||
1200 | |||
1201 | debug3("%s: tearing down sessions", __FUNCTION__); | ||
1202 | |||
1203 | /* The child is terminating */ | ||
1204 | session_destroy_all(&mm_session_close); | ||
1205 | |||
1206 | if (waitpid(monitor->m_pid, &status, 0) == -1) | ||
1207 | exit(1); | ||
1208 | |||
1209 | res = WIFEXITED(status) ? WEXITSTATUS(status) : 1; | ||
1210 | |||
1211 | /* Terminate process */ | ||
1212 | exit (res); | ||
1213 | } | ||
1214 | |||
1215 | void | ||
1216 | monitor_apply_keystate(struct monitor *monitor) | ||
1217 | { | ||
1218 | if (compat20) { | ||
1219 | set_newkeys(MODE_IN); | ||
1220 | set_newkeys(MODE_OUT); | ||
1221 | } else { | ||
1222 | u_char key[SSH_SESSION_KEY_LENGTH]; | ||
1223 | |||
1224 | memset(key, 'a', sizeof(key)); | ||
1225 | packet_set_protocol_flags(child_state.ssh1protoflags); | ||
1226 | packet_set_encryption_key(key, SSH_SESSION_KEY_LENGTH, | ||
1227 | child_state.ssh1cipher); | ||
1228 | } | ||
1229 | |||
1230 | packet_set_keycontext(MODE_OUT, child_state.keyout); | ||
1231 | xfree(child_state.keyout); | ||
1232 | packet_set_keycontext(MODE_IN, child_state.keyin); | ||
1233 | xfree(child_state.keyin); | ||
1234 | |||
1235 | if (!compat20) { | ||
1236 | packet_set_iv(MODE_OUT, child_state.ivout); | ||
1237 | xfree(child_state.ivout); | ||
1238 | packet_set_iv(MODE_IN, child_state.ivin); | ||
1239 | xfree(child_state.ivin); | ||
1240 | } | ||
1241 | |||
1242 | memcpy(&incoming_stream, &child_state.incoming, | ||
1243 | sizeof(incoming_stream)); | ||
1244 | memcpy(&outgoing_stream, &child_state.outgoing, | ||
1245 | sizeof(outgoing_stream)); | ||
1246 | |||
1247 | /* Update with new address */ | ||
1248 | mm_init_compression(monitor->m_zlib); | ||
1249 | |||
1250 | /* Network I/O buffers */ | ||
1251 | /* XXX inefficient for large buffers, need: buffer_init_from_string */ | ||
1252 | buffer_clear(&input); | ||
1253 | buffer_append(&input, child_state.input, child_state.ilen); | ||
1254 | memset(child_state.input, 0, child_state.ilen); | ||
1255 | xfree(child_state.input); | ||
1256 | |||
1257 | buffer_clear(&output); | ||
1258 | buffer_append(&output, child_state.output, child_state.olen); | ||
1259 | memset(child_state.output, 0, child_state.olen); | ||
1260 | xfree(child_state.output); | ||
1261 | } | ||
1262 | |||
1263 | static Kex * | ||
1264 | mm_get_kex(Buffer *m) | ||
1265 | { | ||
1266 | Kex *kex; | ||
1267 | void *blob; | ||
1268 | u_int bloblen; | ||
1269 | |||
1270 | kex = xmalloc(sizeof(*kex)); | ||
1271 | memset(kex, 0, sizeof(*kex)); | ||
1272 | kex->session_id = buffer_get_string(m, &kex->session_id_len); | ||
1273 | kex->we_need = buffer_get_int(m); | ||
1274 | kex->server = 1; | ||
1275 | kex->hostkey_type = buffer_get_int(m); | ||
1276 | kex->kex_type = buffer_get_int(m); | ||
1277 | blob = buffer_get_string(m, &bloblen); | ||
1278 | buffer_init(&kex->my); | ||
1279 | buffer_append(&kex->my, blob, bloblen); | ||
1280 | xfree(blob); | ||
1281 | blob = buffer_get_string(m, &bloblen); | ||
1282 | buffer_init(&kex->peer); | ||
1283 | buffer_append(&kex->peer, blob, bloblen); | ||
1284 | xfree(blob); | ||
1285 | kex->done = 1; | ||
1286 | kex->flags = buffer_get_int(m); | ||
1287 | kex->client_version_string = buffer_get_string(m, NULL); | ||
1288 | kex->server_version_string = buffer_get_string(m, NULL); | ||
1289 | kex->load_host_key=&get_hostkey_by_type; | ||
1290 | kex->host_key_index=&get_hostkey_index; | ||
1291 | |||
1292 | return (kex); | ||
1293 | } | ||
1294 | |||
1295 | /* This function requries careful sanity checking */ | ||
1296 | |||
1297 | void | ||
1298 | mm_get_keystate(struct monitor *monitor) | ||
1299 | { | ||
1300 | Buffer m; | ||
1301 | u_char *blob, *p; | ||
1302 | u_int bloblen, plen; | ||
1303 | |||
1304 | debug3("%s: Waiting for new keys", __FUNCTION__); | ||
1305 | |||
1306 | buffer_init(&m); | ||
1307 | mm_request_receive_expect(monitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m); | ||
1308 | if (!compat20) { | ||
1309 | child_state.ssh1protoflags = buffer_get_int(&m); | ||
1310 | child_state.ssh1cipher = buffer_get_int(&m); | ||
1311 | child_state.ivout = buffer_get_string(&m, | ||
1312 | &child_state.ivoutlen); | ||
1313 | child_state.ivin = buffer_get_string(&m, &child_state.ivinlen); | ||
1314 | goto skip; | ||
1315 | } else { | ||
1316 | /* Get the Kex for rekeying */ | ||
1317 | *monitor->m_pkex = mm_get_kex(&m); | ||
1318 | } | ||
1319 | |||
1320 | blob = buffer_get_string(&m, &bloblen); | ||
1321 | current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); | ||
1322 | xfree(blob); | ||
1323 | |||
1324 | debug3("%s: Waiting for second key", __FUNCTION__); | ||
1325 | blob = buffer_get_string(&m, &bloblen); | ||
1326 | current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); | ||
1327 | xfree(blob); | ||
1328 | |||
1329 | /* Now get sequence numbers for the packets */ | ||
1330 | packet_set_seqnr(MODE_OUT, buffer_get_int(&m)); | ||
1331 | packet_set_seqnr(MODE_IN, buffer_get_int(&m)); | ||
1332 | |||
1333 | skip: | ||
1334 | /* Get the key context */ | ||
1335 | child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen); | ||
1336 | child_state.keyin = buffer_get_string(&m, &child_state.keyinlen); | ||
1337 | |||
1338 | debug3("%s: Getting compression state", __FUNCTION__); | ||
1339 | /* Get compression state */ | ||
1340 | p = buffer_get_string(&m, &plen); | ||
1341 | if (plen != sizeof(child_state.outgoing)) | ||
1342 | fatal("%s: bad request size", __FUNCTION__); | ||
1343 | memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing)); | ||
1344 | xfree(p); | ||
1345 | |||
1346 | p = buffer_get_string(&m, &plen); | ||
1347 | if (plen != sizeof(child_state.incoming)) | ||
1348 | fatal("%s: bad request size", __FUNCTION__); | ||
1349 | memcpy(&child_state.incoming, p, sizeof(child_state.incoming)); | ||
1350 | xfree(p); | ||
1351 | |||
1352 | /* Network I/O buffers */ | ||
1353 | debug3("%s: Getting Network I/O buffers", __FUNCTION__); | ||
1354 | child_state.input = buffer_get_string(&m, &child_state.ilen); | ||
1355 | child_state.output = buffer_get_string(&m, &child_state.olen); | ||
1356 | |||
1357 | buffer_free(&m); | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | /* Allocation functions for zlib */ | ||
1362 | void * | ||
1363 | mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) | ||
1364 | { | ||
1365 | void *address; | ||
1366 | |||
1367 | address = mm_malloc(mm, size * ncount); | ||
1368 | |||
1369 | return (address); | ||
1370 | } | ||
1371 | |||
1372 | void | ||
1373 | mm_zfree(struct mm_master *mm, void *address) | ||
1374 | { | ||
1375 | mm_free(mm, address); | ||
1376 | } | ||
1377 | |||
1378 | void | ||
1379 | mm_init_compression(struct mm_master *mm) | ||
1380 | { | ||
1381 | outgoing_stream.zalloc = (alloc_func)mm_zalloc; | ||
1382 | outgoing_stream.zfree = (free_func)mm_zfree; | ||
1383 | outgoing_stream.opaque = mm; | ||
1384 | |||
1385 | incoming_stream.zalloc = (alloc_func)mm_zalloc; | ||
1386 | incoming_stream.zfree = (free_func)mm_zfree; | ||
1387 | incoming_stream.opaque = mm; | ||
1388 | } | ||
1389 | |||
1390 | /* XXX */ | ||
1391 | |||
1392 | #define FD_CLOSEONEXEC(x) do { \ | ||
1393 | if (fcntl(x, F_SETFD, 1) == -1) \ | ||
1394 | fatal("fcntl(%d, F_SETFD)", x); \ | ||
1395 | } while (0) | ||
1396 | |||
1397 | static void | ||
1398 | monitor_socketpair(int *pair) | ||
1399 | { | ||
1400 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) | ||
1401 | fatal("%s: socketpair", __FUNCTION__); | ||
1402 | FD_CLOSEONEXEC(pair[0]); | ||
1403 | FD_CLOSEONEXEC(pair[1]); | ||
1404 | } | ||
1405 | |||
1406 | #define MM_MEMSIZE 65536 | ||
1407 | |||
1408 | struct monitor * | ||
1409 | monitor_init(void) | ||
1410 | { | ||
1411 | struct monitor *mon; | ||
1412 | int pair[2]; | ||
1413 | |||
1414 | mon = xmalloc(sizeof(*mon)); | ||
1415 | |||
1416 | monitor_socketpair(pair); | ||
1417 | |||
1418 | mon->m_recvfd = pair[0]; | ||
1419 | mon->m_sendfd = pair[1]; | ||
1420 | |||
1421 | /* Used to share zlib space across processes */ | ||
1422 | mon->m_zback = mm_create(NULL, MM_MEMSIZE); | ||
1423 | mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE); | ||
1424 | |||
1425 | /* Compression needs to share state across borders */ | ||
1426 | mm_init_compression(mon->m_zlib); | ||
1427 | |||
1428 | return mon; | ||
1429 | } | ||
1430 | |||
1431 | void | ||
1432 | monitor_reinit(struct monitor *mon) | ||
1433 | { | ||
1434 | int pair[2]; | ||
1435 | |||
1436 | monitor_socketpair(pair); | ||
1437 | |||
1438 | mon->m_recvfd = pair[0]; | ||
1439 | mon->m_sendfd = pair[1]; | ||
1440 | } | ||
diff --git a/monitor.h b/monitor.h new file mode 100644 index 000000000..da7f780b2 --- /dev/null +++ b/monitor.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #ifndef _MONITOR_H_ | ||
27 | #define _MONITOR_H_ | ||
28 | |||
29 | enum monitor_reqtype { | ||
30 | MONITOR_REQ_MODULI, MONITOR_ANS_MODULI, | ||
31 | MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV, | ||
32 | MONITOR_REQ_SIGN, MONITOR_ANS_SIGN, | ||
33 | MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM, | ||
34 | MONITOR_REQ_AUTHPASSWORD, MONITOR_ANS_AUTHPASSWORD, | ||
35 | MONITOR_REQ_BSDAUTHQUERY, MONITOR_ANS_BSDAUTHQUERY, | ||
36 | MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND, | ||
37 | MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY, | ||
38 | MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND, | ||
39 | MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED, | ||
40 | MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY, | ||
41 | MONITOR_REQ_KEYEXPORT, | ||
42 | MONITOR_REQ_PTY, MONITOR_ANS_PTY, | ||
43 | MONITOR_REQ_PTYCLEANUP, | ||
44 | MONITOR_REQ_SESSKEY, MONITOR_ANS_SESSKEY, | ||
45 | MONITOR_REQ_SESSID, | ||
46 | MONITOR_REQ_RSAKEYALLOWED, MONITOR_ANS_RSAKEYALLOWED, | ||
47 | MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE, | ||
48 | MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE, | ||
49 | MONITOR_REQ_TERM, | ||
50 | }; | ||
51 | |||
52 | struct mm_master; | ||
53 | struct monitor { | ||
54 | int m_recvfd; | ||
55 | int m_sendfd; | ||
56 | struct mm_master *m_zback; | ||
57 | struct mm_master *m_zlib; | ||
58 | struct Kex **m_pkex; | ||
59 | int m_pid; | ||
60 | }; | ||
61 | |||
62 | struct monitor *monitor_init(void); | ||
63 | void monitor_reinit(struct monitor *); | ||
64 | void monitor_sync(struct monitor *); | ||
65 | |||
66 | struct Authctxt; | ||
67 | struct Authctxt *monitor_child_preauth(struct monitor *); | ||
68 | void monitor_child_postauth(struct monitor *); | ||
69 | |||
70 | struct mon_table; | ||
71 | int monitor_read(struct monitor*, struct mon_table *, struct mon_table **); | ||
72 | |||
73 | /* Prototypes for request sending and receiving */ | ||
74 | void mm_request_send(int, enum monitor_reqtype, Buffer *); | ||
75 | void mm_request_receive(int, Buffer *); | ||
76 | void mm_request_receive_expect(int, enum monitor_reqtype, Buffer *); | ||
77 | |||
78 | #endif /* _MONITOR_H_ */ | ||
diff --git a/monitor_fdpass.c b/monitor_fdpass.c new file mode 100644 index 000000000..7785535bb --- /dev/null +++ b/monitor_fdpass.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Copyright 2001 Niels Provos <provos@citi.umich.edu> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #include "includes.h" | ||
27 | RCSID("$OpenBSD: monitor_fdpass.c,v 1.1 2002/03/18 17:27:22 provos Exp $"); | ||
28 | |||
29 | #include <sys/uio.h> | ||
30 | |||
31 | #include "log.h" | ||
32 | #include "monitor_fdpass.h" | ||
33 | |||
34 | void | ||
35 | mm_send_fd(int socket, int fd) | ||
36 | { | ||
37 | struct msghdr msg; | ||
38 | char tmp[CMSG_SPACE(sizeof(int))]; | ||
39 | struct cmsghdr *cmsg; | ||
40 | struct iovec vec; | ||
41 | char ch; | ||
42 | |||
43 | memset(&msg, 0, sizeof(msg)); | ||
44 | msg.msg_control = (caddr_t)tmp; | ||
45 | msg.msg_controllen = CMSG_LEN(sizeof(int)); | ||
46 | cmsg = CMSG_FIRSTHDR(&msg); | ||
47 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); | ||
48 | cmsg->cmsg_level = SOL_SOCKET; | ||
49 | cmsg->cmsg_type = SCM_RIGHTS; | ||
50 | *(int *)CMSG_DATA(cmsg) = fd; | ||
51 | |||
52 | vec.iov_base = &ch; | ||
53 | vec.iov_len = 1; | ||
54 | msg.msg_iov = &vec; | ||
55 | msg.msg_iovlen = 1; | ||
56 | |||
57 | if (sendmsg(socket, &msg, 0) == -1) | ||
58 | fatal("%s: sendmsg(%d)", __FUNCTION__, fd); | ||
59 | } | ||
60 | |||
61 | int | ||
62 | mm_receive_fd(int socket) | ||
63 | { | ||
64 | struct msghdr msg; | ||
65 | char tmp[CMSG_SPACE(sizeof(int))]; | ||
66 | struct cmsghdr *cmsg; | ||
67 | struct iovec vec; | ||
68 | char ch; | ||
69 | |||
70 | memset(&msg, 0, sizeof(msg)); | ||
71 | vec.iov_base = &ch; | ||
72 | vec.iov_len = 1; | ||
73 | msg.msg_iov = &vec; | ||
74 | msg.msg_iovlen = 1; | ||
75 | msg.msg_control = tmp; | ||
76 | msg.msg_controllen = sizeof(tmp); | ||
77 | |||
78 | if (recvmsg(socket, &msg, 0) == -1) | ||
79 | fatal("%s: recvmsg", __FUNCTION__); | ||
80 | |||
81 | cmsg = CMSG_FIRSTHDR(&msg); | ||
82 | if (cmsg->cmsg_type != SCM_RIGHTS) | ||
83 | fatal("%s: expected type %d got %d", __FUNCTION__, | ||
84 | SCM_RIGHTS, cmsg->cmsg_type); | ||
85 | return (*(int *)CMSG_DATA(cmsg)); | ||
86 | } | ||
diff --git a/monitor_fdpass.h b/monitor_fdpass.h new file mode 100644 index 000000000..cb6b71c93 --- /dev/null +++ b/monitor_fdpass.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #ifndef _MM_FDPASS_H_ | ||
27 | #define _MM_FDPASS_H_ | ||
28 | |||
29 | void mm_send_fd(int, int); | ||
30 | int mm_receive_fd(int); | ||
31 | |||
32 | #endif /* _MM_FDPASS_H_ */ | ||
diff --git a/monitor_mm.c b/monitor_mm.c new file mode 100644 index 000000000..bce98c93c --- /dev/null +++ b/monitor_mm.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #include "includes.h" | ||
27 | RCSID("$OpenBSD: monitor_mm.c,v 1.3 2002/03/19 10:41:32 markus Exp $"); | ||
28 | |||
29 | #include <sys/mman.h> | ||
30 | |||
31 | #include "ssh.h" | ||
32 | #include "xmalloc.h" | ||
33 | #include "log.h" | ||
34 | #include "monitor_mm.h" | ||
35 | |||
36 | static int | ||
37 | mm_compare(struct mm_share *a, struct mm_share *b) | ||
38 | { | ||
39 | return ((char *)a->address - (char *)b->address); | ||
40 | } | ||
41 | |||
42 | RB_GENERATE(mmtree, mm_share, next, mm_compare) | ||
43 | |||
44 | static struct mm_share * | ||
45 | mm_make_entry(struct mm_master *mm, struct mmtree *head, | ||
46 | void *address, size_t size) | ||
47 | { | ||
48 | struct mm_share *tmp, *tmp2; | ||
49 | |||
50 | if (mm->mmalloc == NULL) | ||
51 | tmp = xmalloc(sizeof(struct mm_share)); | ||
52 | else | ||
53 | tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share)); | ||
54 | tmp->address = address; | ||
55 | tmp->size = size; | ||
56 | |||
57 | tmp2 = RB_INSERT(mmtree, head, tmp); | ||
58 | if (tmp2 != NULL) | ||
59 | fatal("mm_make_entry(%p): double address %p->%p(%d)", | ||
60 | mm, tmp2, address, size); | ||
61 | |||
62 | return (tmp); | ||
63 | } | ||
64 | |||
65 | /* Creates a shared memory area of a certain size */ | ||
66 | |||
67 | struct mm_master * | ||
68 | mm_create(struct mm_master *mmalloc, size_t size) | ||
69 | { | ||
70 | void *address; | ||
71 | struct mm_master *mm; | ||
72 | |||
73 | if (mmalloc == NULL) | ||
74 | mm = xmalloc(sizeof(struct mm_master)); | ||
75 | else | ||
76 | mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); | ||
77 | |||
78 | /* | ||
79 | * If the memory map has a mm_master it can be completely | ||
80 | * shared including authentication between the child | ||
81 | * and the client. | ||
82 | */ | ||
83 | mm->mmalloc = mmalloc; | ||
84 | |||
85 | address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, | ||
86 | -1, 0); | ||
87 | if (address == MAP_FAILED) | ||
88 | fatal("mmap(%d)", size); | ||
89 | |||
90 | mm->address = address; | ||
91 | mm->size = size; | ||
92 | |||
93 | RB_INIT(&mm->rb_free); | ||
94 | RB_INIT(&mm->rb_allocated); | ||
95 | |||
96 | mm_make_entry(mm, &mm->rb_free, address, size); | ||
97 | |||
98 | return (mm); | ||
99 | } | ||
100 | |||
101 | /* Frees either the allocated or the free list */ | ||
102 | |||
103 | static void | ||
104 | mm_freelist(struct mm_master *mmalloc, struct mmtree *head) | ||
105 | { | ||
106 | struct mm_share *mms, *next; | ||
107 | |||
108 | for (mms = RB_ROOT(head); mms; mms = next) { | ||
109 | next = RB_NEXT(mmtree, head, mms); | ||
110 | RB_REMOVE(mmtree, head, mms); | ||
111 | if (mmalloc == NULL) | ||
112 | xfree(mms); | ||
113 | else | ||
114 | mm_free(mmalloc, mms); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* Destroys a memory mapped area */ | ||
119 | |||
120 | void | ||
121 | mm_destroy(struct mm_master *mm) | ||
122 | { | ||
123 | mm_freelist(mm->mmalloc, &mm->rb_free); | ||
124 | mm_freelist(mm->mmalloc, &mm->rb_allocated); | ||
125 | |||
126 | if (munmap(mm->address, mm->size) == -1) | ||
127 | fatal("munmap(%p, %d)", mm->address, mm->size); | ||
128 | if (mm->mmalloc == NULL) | ||
129 | xfree(mm); | ||
130 | else | ||
131 | mm_free(mm->mmalloc, mm); | ||
132 | } | ||
133 | |||
134 | void * | ||
135 | mm_xmalloc(struct mm_master *mm, size_t size) | ||
136 | { | ||
137 | void *address; | ||
138 | |||
139 | address = mm_malloc(mm, size); | ||
140 | if (address == NULL) | ||
141 | fatal("%s: mm_malloc(%d)", __FUNCTION__, size); | ||
142 | return (address); | ||
143 | } | ||
144 | |||
145 | |||
146 | /* Allocates data from a memory mapped area */ | ||
147 | |||
148 | void * | ||
149 | mm_malloc(struct mm_master *mm, size_t size) | ||
150 | { | ||
151 | struct mm_share *mms, *tmp; | ||
152 | |||
153 | if (size == 0) | ||
154 | fatal("mm_malloc: try to allocate 0 space"); | ||
155 | |||
156 | size = ((size + MM_MINSIZE - 1) / MM_MINSIZE) * MM_MINSIZE; | ||
157 | |||
158 | RB_FOREACH(mms, mmtree, &mm->rb_free) { | ||
159 | if (mms->size >= size) | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | if (mms == NULL) | ||
164 | return (NULL); | ||
165 | |||
166 | /* Debug */ | ||
167 | memset(mms->address, 0xd0, size); | ||
168 | |||
169 | tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size); | ||
170 | |||
171 | /* Does not change order in RB tree */ | ||
172 | mms->size -= size; | ||
173 | mms->address = (u_char *)mms->address + size; | ||
174 | |||
175 | if (mms->size == 0) { | ||
176 | RB_REMOVE(mmtree, &mm->rb_free, mms); | ||
177 | if (mm->mmalloc == NULL) | ||
178 | xfree(mms); | ||
179 | else | ||
180 | mm_free(mm->mmalloc, mms); | ||
181 | } | ||
182 | |||
183 | return (tmp->address); | ||
184 | } | ||
185 | |||
186 | /* Frees memory in a memory mapped area */ | ||
187 | |||
188 | void | ||
189 | mm_free(struct mm_master *mm, void *address) | ||
190 | { | ||
191 | struct mm_share *mms, *prev, tmp; | ||
192 | |||
193 | tmp.address = address; | ||
194 | mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp); | ||
195 | if (mms == NULL) | ||
196 | fatal("mm_free(%p): can not find %p", mm, address); | ||
197 | |||
198 | /* Debug */ | ||
199 | memset(mms->address, 0xd0, mms->size); | ||
200 | |||
201 | /* Remove from allocated list and insert in free list */ | ||
202 | RB_REMOVE(mmtree, &mm->rb_allocated, mms); | ||
203 | if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL) | ||
204 | fatal("mm_free(%p): double address %p", mm, address); | ||
205 | |||
206 | /* Find previous entry */ | ||
207 | prev = mms; | ||
208 | if (RB_LEFT(prev, next)) { | ||
209 | prev = RB_LEFT(prev, next); | ||
210 | while (RB_RIGHT(prev, next)) | ||
211 | prev = RB_RIGHT(prev, next); | ||
212 | } else { | ||
213 | if (RB_PARENT(prev, next) && | ||
214 | (prev == RB_RIGHT(RB_PARENT(prev, next), next))) | ||
215 | prev = RB_PARENT(prev, next); | ||
216 | else { | ||
217 | while (RB_PARENT(prev, next) && | ||
218 | (prev == RB_LEFT(RB_PARENT(prev, next), next))) | ||
219 | prev = RB_PARENT(prev, next); | ||
220 | prev = RB_PARENT(prev, next); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /* Check if range does not overlap */ | ||
225 | if (prev != NULL && MM_ADDRESS_END(prev) > address) | ||
226 | fatal("mm_free: memory corruption: %p(%d) > %p", | ||
227 | prev->address, prev->size, address); | ||
228 | |||
229 | /* See if we can merge backwards */ | ||
230 | if (prev != NULL && MM_ADDRESS_END(prev) == address) { | ||
231 | prev->size += mms->size; | ||
232 | RB_REMOVE(mmtree, &mm->rb_free, mms); | ||
233 | if (mm->mmalloc == NULL) | ||
234 | xfree(mms); | ||
235 | else | ||
236 | mm_free(mm->mmalloc, mms); | ||
237 | } else | ||
238 | prev = mms; | ||
239 | |||
240 | if (prev == NULL) | ||
241 | return; | ||
242 | |||
243 | /* Check if we can merge forwards */ | ||
244 | mms = RB_NEXT(mmtree, &mm->rb_free, prev); | ||
245 | if (mms == NULL) | ||
246 | return; | ||
247 | |||
248 | if (MM_ADDRESS_END(prev) > mms->address) | ||
249 | fatal("mm_free: memory corruption: %p < %p(%d)", | ||
250 | mms->address, prev->address, prev->size); | ||
251 | if (MM_ADDRESS_END(prev) != mms->address) | ||
252 | return; | ||
253 | |||
254 | prev->size += mms->size; | ||
255 | RB_REMOVE(mmtree, &mm->rb_free, mms); | ||
256 | |||
257 | if (mm->mmalloc == NULL) | ||
258 | xfree(mms); | ||
259 | else | ||
260 | mm_free(mm->mmalloc, mms); | ||
261 | } | ||
262 | |||
263 | static void | ||
264 | mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree, | ||
265 | struct mm_master *mm, struct mm_master *mmold) | ||
266 | { | ||
267 | struct mm_master *mmalloc = mm->mmalloc; | ||
268 | struct mm_share *mms, *new; | ||
269 | |||
270 | /* Sync free list */ | ||
271 | RB_FOREACH(mms, mmtree, oldtree) { | ||
272 | /* Check the values */ | ||
273 | mm_memvalid(mmold, mms, sizeof(struct mm_share)); | ||
274 | mm_memvalid(mm, mms->address, mms->size); | ||
275 | |||
276 | new = mm_xmalloc(mmalloc, sizeof(struct mm_share)); | ||
277 | memcpy(new, mms, sizeof(struct mm_share)); | ||
278 | RB_INSERT(mmtree, newtree, new); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | void | ||
283 | mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc) | ||
284 | { | ||
285 | struct mm_master *mm; | ||
286 | struct mm_master *mmalloc; | ||
287 | struct mm_master *mmold; | ||
288 | struct mmtree rb_free, rb_allocated; | ||
289 | |||
290 | debug3("%s: Share sync", __FUNCTION__); | ||
291 | |||
292 | mm = *pmm; | ||
293 | mmold = mm->mmalloc; | ||
294 | mm_memvalid(mmold, mm, sizeof(*mm)); | ||
295 | |||
296 | mmalloc = mm_create(NULL, mm->size); | ||
297 | mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); | ||
298 | memcpy(mm, *pmm, sizeof(struct mm_master)); | ||
299 | mm->mmalloc = mmalloc; | ||
300 | |||
301 | rb_free = mm->rb_free; | ||
302 | rb_allocated = mm->rb_allocated; | ||
303 | |||
304 | RB_INIT(&mm->rb_free); | ||
305 | RB_INIT(&mm->rb_allocated); | ||
306 | |||
307 | mm_sync_list(&rb_free, &mm->rb_free, mm, mmold); | ||
308 | mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold); | ||
309 | |||
310 | mm_destroy(mmold); | ||
311 | |||
312 | *pmm = mm; | ||
313 | *pmmalloc = mmalloc; | ||
314 | |||
315 | debug3("%s: Share sync end", __FUNCTION__); | ||
316 | } | ||
317 | |||
318 | void | ||
319 | mm_memvalid(struct mm_master *mm, void *address, size_t size) | ||
320 | { | ||
321 | void *end = (u_char *)address + size; | ||
322 | |||
323 | if (address < mm->address) | ||
324 | fatal("mm_memvalid: address too small: %p", address); | ||
325 | if (end < address) | ||
326 | fatal("mm_memvalid: end < address: %p < %p", end, address); | ||
327 | if (end > (void *)((u_char *)mm->address + mm->size)) | ||
328 | fatal("mm_memvalid: address too large: %p", address); | ||
329 | } | ||
diff --git a/monitor_mm.h b/monitor_mm.h new file mode 100644 index 000000000..43442609c --- /dev/null +++ b/monitor_mm.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #ifndef _MM_H_ | ||
27 | #define _MM_H_ | ||
28 | #include <sys/tree.h> | ||
29 | |||
30 | struct mm_share { | ||
31 | RB_ENTRY(mm_share) next; | ||
32 | void *address; | ||
33 | size_t size; | ||
34 | }; | ||
35 | |||
36 | struct mm_master { | ||
37 | RB_HEAD(mmtree, mm_share) rb_free; | ||
38 | struct mmtree rb_allocated; | ||
39 | void *address; | ||
40 | size_t size; | ||
41 | |||
42 | struct mm_master *mmalloc; /* Used to completely share */ | ||
43 | |||
44 | int write; /* used to writing to other party */ | ||
45 | int read; /* used for reading from other party */ | ||
46 | }; | ||
47 | |||
48 | RB_PROTOTYPE(mmtree, mm_share, next, mm_compare) | ||
49 | |||
50 | #define MM_MINSIZE 128 | ||
51 | |||
52 | #define MM_ADDRESS_END(x) (void *)((u_char *)(x)->address + (x)->size) | ||
53 | |||
54 | struct mm_master *mm_create(struct mm_master *, size_t); | ||
55 | void mm_destroy(struct mm_master *); | ||
56 | |||
57 | void mm_share_sync(struct mm_master **, struct mm_master **); | ||
58 | |||
59 | void *mm_malloc(struct mm_master *, size_t); | ||
60 | void *mm_xmalloc(struct mm_master *, size_t); | ||
61 | void mm_free(struct mm_master *, void *); | ||
62 | |||
63 | void mm_memvalid(struct mm_master *, void *, size_t); | ||
64 | #endif /* _MM_H_ */ | ||
diff --git a/monitor_wrap.c b/monitor_wrap.c new file mode 100644 index 000000000..e477cff25 --- /dev/null +++ b/monitor_wrap.c | |||
@@ -0,0 +1,894 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | RCSID("$OpenBSD: monitor_wrap.c,v 1.4 2002/03/19 14:27:39 markus Exp $"); | ||
29 | |||
30 | #include <openssl/bn.h> | ||
31 | #include <openssl/dh.h> | ||
32 | |||
33 | #include "ssh.h" | ||
34 | #include "dh.h" | ||
35 | #include "kex.h" | ||
36 | #include "auth.h" | ||
37 | #include "buffer.h" | ||
38 | #include "bufaux.h" | ||
39 | #include "packet.h" | ||
40 | #include "mac.h" | ||
41 | #include "log.h" | ||
42 | #include "zlib.h" | ||
43 | #include "monitor.h" | ||
44 | #include "monitor_wrap.h" | ||
45 | #include "xmalloc.h" | ||
46 | #include "atomicio.h" | ||
47 | #include "monitor_fdpass.h" | ||
48 | #include "getput.h" | ||
49 | |||
50 | #include "auth.h" | ||
51 | #include "channels.h" | ||
52 | #include "session.h" | ||
53 | |||
54 | /* Imports */ | ||
55 | extern int compat20; | ||
56 | extern Newkeys *newkeys[]; | ||
57 | extern z_stream incoming_stream; | ||
58 | extern z_stream outgoing_stream; | ||
59 | extern struct monitor *monitor; | ||
60 | extern Buffer input, output; | ||
61 | |||
62 | void | ||
63 | mm_request_send(int socket, enum monitor_reqtype type, Buffer *m) | ||
64 | { | ||
65 | u_char buf[5]; | ||
66 | u_int mlen = buffer_len(m); | ||
67 | |||
68 | debug3("%s entering: type %d", __FUNCTION__, type); | ||
69 | |||
70 | PUT_32BIT(buf, mlen + 1); | ||
71 | buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */ | ||
72 | if (atomicio(write, socket, buf, sizeof(buf)) != sizeof(buf)) | ||
73 | fatal("%s: write", __FUNCTION__); | ||
74 | if (atomicio(write, socket, buffer_ptr(m), mlen) != mlen) | ||
75 | fatal("%s: write", __FUNCTION__); | ||
76 | } | ||
77 | |||
78 | void | ||
79 | mm_request_receive(int socket, Buffer *m) | ||
80 | { | ||
81 | u_char buf[4]; | ||
82 | ssize_t res; | ||
83 | u_int msg_len; | ||
84 | |||
85 | debug3("%s entering", __FUNCTION__); | ||
86 | |||
87 | res = atomicio(read, socket, buf, sizeof(buf)); | ||
88 | if (res != sizeof(buf)) { | ||
89 | if (res == 0) | ||
90 | fatal_cleanup(); | ||
91 | fatal("%s: read: %d", __FUNCTION__, res); | ||
92 | } | ||
93 | msg_len = GET_32BIT(buf); | ||
94 | if (msg_len > 256 * 1024) | ||
95 | fatal("%s: read: bad msg_len %d", __FUNCTION__, msg_len); | ||
96 | buffer_clear(m); | ||
97 | buffer_append_space(m, msg_len); | ||
98 | res = atomicio(read, socket, buffer_ptr(m), msg_len); | ||
99 | if (res != msg_len) | ||
100 | fatal("%s: read: %d != msg_len", __FUNCTION__, res); | ||
101 | } | ||
102 | |||
103 | void | ||
104 | mm_request_receive_expect(int socket, enum monitor_reqtype type, Buffer *m) | ||
105 | { | ||
106 | u_char rtype; | ||
107 | |||
108 | debug3("%s entering: type %d", __FUNCTION__, type); | ||
109 | |||
110 | mm_request_receive(socket, m); | ||
111 | rtype = buffer_get_char(m); | ||
112 | if (rtype != type) | ||
113 | fatal("%s: read: rtype %d != type %d", __FUNCTION__, | ||
114 | rtype, type); | ||
115 | } | ||
116 | |||
117 | DH * | ||
118 | mm_choose_dh(int min, int nbits, int max) | ||
119 | { | ||
120 | BIGNUM *p, *g; | ||
121 | int success = 0; | ||
122 | Buffer m; | ||
123 | |||
124 | buffer_init(&m); | ||
125 | buffer_put_int(&m, min); | ||
126 | buffer_put_int(&m, nbits); | ||
127 | buffer_put_int(&m, max); | ||
128 | |||
129 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_MODULI, &m); | ||
130 | |||
131 | debug3("%s: waiting for MONITOR_ANS_MODULI", __FUNCTION__); | ||
132 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_MODULI, &m); | ||
133 | |||
134 | success = buffer_get_char(&m); | ||
135 | if (success == 0) | ||
136 | fatal("%s: MONITOR_ANS_MODULI failed", __FUNCTION__); | ||
137 | |||
138 | if ((p = BN_new()) == NULL) | ||
139 | fatal("%s: BN_new failed", __FUNCTION__); | ||
140 | if ((g = BN_new()) == NULL) | ||
141 | fatal("%s: BN_new failed", __FUNCTION__); | ||
142 | buffer_get_bignum2(&m, p); | ||
143 | buffer_get_bignum2(&m, g); | ||
144 | |||
145 | debug3("%s: remaining %d", __FUNCTION__, buffer_len(&m)); | ||
146 | buffer_free(&m); | ||
147 | |||
148 | return (dh_new_group(g, p)); | ||
149 | } | ||
150 | |||
151 | int | ||
152 | mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) | ||
153 | { | ||
154 | Kex *kex = *monitor->m_pkex; | ||
155 | Buffer m; | ||
156 | |||
157 | debug3("%s entering", __FUNCTION__); | ||
158 | |||
159 | buffer_init(&m); | ||
160 | buffer_put_int(&m, kex->host_key_index(key)); | ||
161 | buffer_put_string(&m, data, datalen); | ||
162 | |||
163 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_SIGN, &m); | ||
164 | |||
165 | debug3("%s: waiting for MONITOR_ANS_SIGN", __FUNCTION__); | ||
166 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SIGN, &m); | ||
167 | *sigp = buffer_get_string(&m, lenp); | ||
168 | buffer_free(&m); | ||
169 | |||
170 | return (0); | ||
171 | } | ||
172 | |||
173 | struct passwd * | ||
174 | mm_getpwnamallow(const char *login) | ||
175 | { | ||
176 | Buffer m; | ||
177 | struct passwd *pw; | ||
178 | u_int pwlen; | ||
179 | |||
180 | debug3("%s entering", __FUNCTION__); | ||
181 | |||
182 | buffer_init(&m); | ||
183 | buffer_put_cstring(&m, login); | ||
184 | |||
185 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_PWNAM, &m); | ||
186 | |||
187 | debug3("%s: waiting for MONITOR_ANS_PWNAM", __FUNCTION__); | ||
188 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_PWNAM, &m); | ||
189 | |||
190 | if (buffer_get_char(&m) == 0) { | ||
191 | buffer_free(&m); | ||
192 | return (NULL); | ||
193 | } | ||
194 | pw = buffer_get_string(&m, &pwlen); | ||
195 | if (pwlen != sizeof(struct passwd)) | ||
196 | fatal("%s: struct passwd size mismatch", __FUNCTION__); | ||
197 | pw->pw_name = buffer_get_string(&m, NULL); | ||
198 | pw->pw_passwd = buffer_get_string(&m, NULL); | ||
199 | pw->pw_gecos = buffer_get_string(&m, NULL); | ||
200 | pw->pw_class = buffer_get_string(&m, NULL); | ||
201 | pw->pw_dir = buffer_get_string(&m, NULL); | ||
202 | pw->pw_shell = buffer_get_string(&m, NULL); | ||
203 | buffer_free(&m); | ||
204 | |||
205 | return (pw); | ||
206 | } | ||
207 | |||
208 | /* Inform the privileged process about service and style */ | ||
209 | |||
210 | void | ||
211 | mm_inform_authserv(char *service, char *style) | ||
212 | { | ||
213 | Buffer m; | ||
214 | |||
215 | debug3("%s entering", __FUNCTION__); | ||
216 | |||
217 | buffer_init(&m); | ||
218 | buffer_put_cstring(&m, service); | ||
219 | buffer_put_cstring(&m, style ? style : ""); | ||
220 | |||
221 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m); | ||
222 | |||
223 | buffer_free(&m); | ||
224 | } | ||
225 | |||
226 | /* Do the password authentication */ | ||
227 | int | ||
228 | mm_auth_password(Authctxt *authctxt, char *password) | ||
229 | { | ||
230 | Buffer m; | ||
231 | int authenticated = 0; | ||
232 | |||
233 | debug3("%s entering", __FUNCTION__); | ||
234 | |||
235 | buffer_init(&m); | ||
236 | buffer_put_cstring(&m, password); | ||
237 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, &m); | ||
238 | |||
239 | debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __FUNCTION__); | ||
240 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_AUTHPASSWORD, &m); | ||
241 | |||
242 | authenticated = buffer_get_int(&m); | ||
243 | |||
244 | buffer_free(&m); | ||
245 | |||
246 | debug3("%s: user %sauthenticated", | ||
247 | __FUNCTION__, authenticated ? "" : "not "); | ||
248 | return (authenticated); | ||
249 | } | ||
250 | |||
251 | int | ||
252 | mm_user_key_allowed(struct passwd *pw, Key *key) | ||
253 | { | ||
254 | return (mm_key_allowed(MM_USERKEY, NULL, NULL, key)); | ||
255 | } | ||
256 | |||
257 | int | ||
258 | mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host, | ||
259 | Key *key) | ||
260 | { | ||
261 | return (mm_key_allowed(MM_HOSTKEY, user, host, key)); | ||
262 | } | ||
263 | |||
264 | int | ||
265 | mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user, | ||
266 | char *host, Key *key) | ||
267 | { | ||
268 | int ret; | ||
269 | |||
270 | key->type = KEY_RSA; /* XXX hack for key_to_blob */ | ||
271 | ret = mm_key_allowed(MM_RSAHOSTKEY, user, host, key); | ||
272 | key->type = KEY_RSA1; | ||
273 | return (ret); | ||
274 | } | ||
275 | |||
276 | static void | ||
277 | mm_send_debug(Buffer *m) | ||
278 | { | ||
279 | char *msg; | ||
280 | |||
281 | while (buffer_len(m)) { | ||
282 | msg = buffer_get_string(m, NULL); | ||
283 | debug3("%s: Sending debug: %s", __FUNCTION__, msg); | ||
284 | packet_send_debug("%s", msg); | ||
285 | xfree(msg); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | int | ||
290 | mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) | ||
291 | { | ||
292 | Buffer m; | ||
293 | u_char *blob; | ||
294 | u_int len; | ||
295 | int allowed = 0; | ||
296 | |||
297 | debug3("%s entering", __FUNCTION__); | ||
298 | |||
299 | /* Convert the key to a blob and the pass it over */ | ||
300 | if (!key_to_blob(key, &blob, &len)) | ||
301 | return (0); | ||
302 | |||
303 | buffer_init(&m); | ||
304 | buffer_put_int(&m, type); | ||
305 | buffer_put_cstring(&m, user ? user : ""); | ||
306 | buffer_put_cstring(&m, host ? host : ""); | ||
307 | buffer_put_string(&m, blob, len); | ||
308 | xfree(blob); | ||
309 | |||
310 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m); | ||
311 | |||
312 | debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __FUNCTION__); | ||
313 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m); | ||
314 | |||
315 | allowed = buffer_get_int(&m); | ||
316 | |||
317 | /* Send potential debug messages */ | ||
318 | mm_send_debug(&m); | ||
319 | |||
320 | buffer_free(&m); | ||
321 | |||
322 | return (allowed); | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * This key verify needs to send the key type along, because the | ||
327 | * privileged parent makes the decision if the key is allowed | ||
328 | * for authentication. | ||
329 | */ | ||
330 | |||
331 | int | ||
332 | mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) | ||
333 | { | ||
334 | Buffer m; | ||
335 | u_char *blob; | ||
336 | u_int len; | ||
337 | int verified = 0; | ||
338 | |||
339 | debug3("%s entering", __FUNCTION__); | ||
340 | |||
341 | /* Convert the key to a blob and the pass it over */ | ||
342 | if (!key_to_blob(key, &blob, &len)) | ||
343 | return (0); | ||
344 | |||
345 | buffer_init(&m); | ||
346 | buffer_put_string(&m, blob, len); | ||
347 | buffer_put_string(&m, sig, siglen); | ||
348 | buffer_put_string(&m, data, datalen); | ||
349 | xfree(blob); | ||
350 | |||
351 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); | ||
352 | |||
353 | debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __FUNCTION__); | ||
354 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m); | ||
355 | |||
356 | verified = buffer_get_int(&m); | ||
357 | |||
358 | buffer_free(&m); | ||
359 | |||
360 | return (verified); | ||
361 | } | ||
362 | |||
363 | /* Export key state after authentication */ | ||
364 | Newkeys * | ||
365 | mm_newkeys_from_blob(u_char *blob, int blen) | ||
366 | { | ||
367 | Buffer b; | ||
368 | u_int len; | ||
369 | Newkeys *newkey = NULL; | ||
370 | Enc *enc; | ||
371 | Mac *mac; | ||
372 | Comp *comp; | ||
373 | |||
374 | debug3("%s: %p(%d)", __FUNCTION__, blob, blen); | ||
375 | #ifdef DEBUG_PK | ||
376 | dump_base64(stderr, blob, blen); | ||
377 | #endif | ||
378 | buffer_init(&b); | ||
379 | buffer_append(&b, blob, blen); | ||
380 | |||
381 | newkey = xmalloc(sizeof(*newkey)); | ||
382 | enc = &newkey->enc; | ||
383 | mac = &newkey->mac; | ||
384 | comp = &newkey->comp; | ||
385 | |||
386 | /* Enc structure */ | ||
387 | enc->name = buffer_get_string(&b, NULL); | ||
388 | buffer_get(&b, &enc->cipher, sizeof(enc->cipher)); | ||
389 | enc->enabled = buffer_get_int(&b); | ||
390 | enc->block_size = buffer_get_int(&b); | ||
391 | enc->key = buffer_get_string(&b, &enc->key_len); | ||
392 | enc->iv = buffer_get_string(&b, &len); | ||
393 | if (len != enc->block_size) | ||
394 | fatal("%s: bad ivlen: expected %d != %d", __FUNCTION__, | ||
395 | enc->block_size, len); | ||
396 | |||
397 | if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) | ||
398 | fatal("%s: bad cipher name %s or pointer %p", __FUNCTION__, | ||
399 | enc->name, enc->cipher); | ||
400 | |||
401 | /* Mac structure */ | ||
402 | mac->name = buffer_get_string(&b, NULL); | ||
403 | if (mac->name == NULL || mac_init(mac, mac->name) == -1) | ||
404 | fatal("%s: can not init mac %s", __FUNCTION__, mac->name); | ||
405 | mac->enabled = buffer_get_int(&b); | ||
406 | mac->key = buffer_get_string(&b, &len); | ||
407 | if (len > mac->key_len) | ||
408 | fatal("%s: bad mac key lenght: %d > %d", __FUNCTION__, len, | ||
409 | mac->key_len); | ||
410 | mac->key_len = len; | ||
411 | |||
412 | /* Comp structure */ | ||
413 | comp->type = buffer_get_int(&b); | ||
414 | comp->enabled = buffer_get_int(&b); | ||
415 | comp->name = buffer_get_string(&b, NULL); | ||
416 | |||
417 | len = buffer_len(&b); | ||
418 | if (len != 0) | ||
419 | error("newkeys_from_blob: remaining bytes in blob %d", len); | ||
420 | buffer_free(&b); | ||
421 | return (newkey); | ||
422 | } | ||
423 | |||
424 | int | ||
425 | mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) | ||
426 | { | ||
427 | Buffer b; | ||
428 | int len; | ||
429 | u_char *buf; | ||
430 | Enc *enc; | ||
431 | Mac *mac; | ||
432 | Comp *comp; | ||
433 | Newkeys *newkey = newkeys[mode]; | ||
434 | |||
435 | debug3("%s: converting %p", __FUNCTION__, newkey); | ||
436 | |||
437 | if (newkey == NULL) { | ||
438 | error("%s: newkey == NULL", __FUNCTION__); | ||
439 | return 0; | ||
440 | } | ||
441 | enc = &newkey->enc; | ||
442 | mac = &newkey->mac; | ||
443 | comp = &newkey->comp; | ||
444 | |||
445 | buffer_init(&b); | ||
446 | /* Enc structure */ | ||
447 | buffer_put_cstring(&b, enc->name); | ||
448 | /* The cipher struct is constant and shared, you export pointer */ | ||
449 | buffer_append(&b, &enc->cipher, sizeof(enc->cipher)); | ||
450 | buffer_put_int(&b, enc->enabled); | ||
451 | buffer_put_int(&b, enc->block_size); | ||
452 | buffer_put_string(&b, enc->key, enc->key_len); | ||
453 | packet_get_keyiv(mode, enc->iv, enc->block_size); | ||
454 | buffer_put_string(&b, enc->iv, enc->block_size); | ||
455 | |||
456 | /* Mac structure */ | ||
457 | buffer_put_cstring(&b, mac->name); | ||
458 | buffer_put_int(&b, mac->enabled); | ||
459 | buffer_put_string(&b, mac->key, mac->key_len); | ||
460 | |||
461 | /* Comp structure */ | ||
462 | buffer_put_int(&b, comp->type); | ||
463 | buffer_put_int(&b, comp->enabled); | ||
464 | buffer_put_cstring(&b, comp->name); | ||
465 | |||
466 | len = buffer_len(&b); | ||
467 | buf = xmalloc(len); | ||
468 | memcpy(buf, buffer_ptr(&b), len); | ||
469 | memset(buffer_ptr(&b), 0, len); | ||
470 | buffer_free(&b); | ||
471 | if (lenp != NULL) | ||
472 | *lenp = len; | ||
473 | if (blobp != NULL) | ||
474 | *blobp = buf; | ||
475 | return len; | ||
476 | } | ||
477 | |||
478 | static void | ||
479 | mm_send_kex(Buffer *m, Kex *kex) | ||
480 | { | ||
481 | buffer_put_string(m, kex->session_id, kex->session_id_len); | ||
482 | buffer_put_int(m, kex->we_need); | ||
483 | buffer_put_int(m, kex->hostkey_type); | ||
484 | buffer_put_int(m, kex->kex_type); | ||
485 | buffer_put_string(m, buffer_ptr(&kex->my), buffer_len(&kex->my)); | ||
486 | buffer_put_string(m, buffer_ptr(&kex->peer), buffer_len(&kex->peer)); | ||
487 | buffer_put_int(m, kex->flags); | ||
488 | buffer_put_cstring(m, kex->client_version_string); | ||
489 | buffer_put_cstring(m, kex->server_version_string); | ||
490 | } | ||
491 | |||
492 | void | ||
493 | mm_send_keystate(struct monitor *monitor) | ||
494 | { | ||
495 | Buffer m; | ||
496 | u_char *blob, *p; | ||
497 | u_int bloblen, plen; | ||
498 | |||
499 | buffer_init(&m); | ||
500 | |||
501 | if (!compat20) { | ||
502 | u_char iv[24]; | ||
503 | int ivlen; | ||
504 | |||
505 | buffer_put_int(&m, packet_get_protocol_flags()); | ||
506 | |||
507 | buffer_put_int(&m, packet_get_ssh1_cipher()); | ||
508 | |||
509 | debug3("%s: Sending ssh1 IV", __FUNCTION__); | ||
510 | ivlen = packet_get_keyiv_len(MODE_OUT); | ||
511 | packet_get_keyiv(MODE_OUT, iv, ivlen); | ||
512 | buffer_put_string(&m, iv, ivlen); | ||
513 | ivlen = packet_get_keyiv_len(MODE_OUT); | ||
514 | packet_get_keyiv(MODE_IN, iv, ivlen); | ||
515 | buffer_put_string(&m, iv, ivlen); | ||
516 | goto skip; | ||
517 | } else { | ||
518 | /* Kex for rekeying */ | ||
519 | mm_send_kex(&m, *monitor->m_pkex); | ||
520 | } | ||
521 | |||
522 | debug3("%s: Sending new keys: %p %p", | ||
523 | __FUNCTION__, newkeys[MODE_OUT], newkeys[MODE_IN]); | ||
524 | |||
525 | /* Keys from Kex */ | ||
526 | if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) | ||
527 | fatal("%s: conversion of newkeys failed", __FUNCTION__); | ||
528 | |||
529 | buffer_put_string(&m, blob, bloblen); | ||
530 | xfree(blob); | ||
531 | |||
532 | if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) | ||
533 | fatal("%s: conversion of newkeys failed", __FUNCTION__); | ||
534 | |||
535 | buffer_put_string(&m, blob, bloblen); | ||
536 | xfree(blob); | ||
537 | |||
538 | buffer_put_int(&m, packet_get_seqnr(MODE_OUT)); | ||
539 | buffer_put_int(&m, packet_get_seqnr(MODE_IN)); | ||
540 | |||
541 | debug3("%s: New keys have been sent", __FUNCTION__); | ||
542 | skip: | ||
543 | /* More key context */ | ||
544 | plen = packet_get_keycontext(MODE_OUT, NULL); | ||
545 | p = xmalloc(plen+1); | ||
546 | packet_get_keycontext(MODE_OUT, p); | ||
547 | buffer_put_string(&m, p, plen); | ||
548 | xfree(p); | ||
549 | |||
550 | plen = packet_get_keycontext(MODE_IN, NULL); | ||
551 | p = xmalloc(plen+1); | ||
552 | packet_get_keycontext(MODE_IN, p); | ||
553 | buffer_put_string(&m, p, plen); | ||
554 | xfree(p); | ||
555 | |||
556 | /* Compression state */ | ||
557 | debug3("%s: Sending compression state", __FUNCTION__); | ||
558 | buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream)); | ||
559 | buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream)); | ||
560 | |||
561 | /* Network I/O buffers */ | ||
562 | buffer_put_string(&m, buffer_ptr(&input), buffer_len(&input)); | ||
563 | buffer_put_string(&m, buffer_ptr(&output), buffer_len(&output)); | ||
564 | |||
565 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m); | ||
566 | debug3("%s: Finished sending state", __FUNCTION__); | ||
567 | |||
568 | buffer_free(&m); | ||
569 | } | ||
570 | |||
571 | int | ||
572 | mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) | ||
573 | { | ||
574 | Buffer m; | ||
575 | u_char *p; | ||
576 | int success = 0; | ||
577 | |||
578 | buffer_init(&m); | ||
579 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_PTY, &m); | ||
580 | |||
581 | debug3("%s: waiting for MONITOR_ANS_PTY", __FUNCTION__); | ||
582 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_PTY, &m); | ||
583 | |||
584 | success = buffer_get_int(&m); | ||
585 | if (success == 0) { | ||
586 | debug3("%s: pty alloc failed", __FUNCTION__); | ||
587 | buffer_free(&m); | ||
588 | return (0); | ||
589 | } | ||
590 | p = buffer_get_string(&m, NULL); | ||
591 | buffer_free(&m); | ||
592 | |||
593 | strlcpy(namebuf, p, namebuflen); /* Possible truncation */ | ||
594 | xfree(p); | ||
595 | |||
596 | *ptyfd = mm_receive_fd(monitor->m_recvfd); | ||
597 | *ttyfd = mm_receive_fd(monitor->m_recvfd); | ||
598 | |||
599 | /* Success */ | ||
600 | return (1); | ||
601 | } | ||
602 | |||
603 | void | ||
604 | mm_session_pty_cleanup2(void *session) | ||
605 | { | ||
606 | Session *s = session; | ||
607 | Buffer m; | ||
608 | |||
609 | if (s->ttyfd == -1) | ||
610 | return; | ||
611 | buffer_init(&m); | ||
612 | buffer_put_cstring(&m, s->tty); | ||
613 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, &m); | ||
614 | buffer_free(&m); | ||
615 | |||
616 | /* closed dup'ed master */ | ||
617 | if (close(s->ptymaster) < 0) | ||
618 | error("close(s->ptymaster): %s", strerror(errno)); | ||
619 | |||
620 | /* unlink pty from session */ | ||
621 | s->ttyfd = -1; | ||
622 | } | ||
623 | |||
624 | /* Request process termination */ | ||
625 | |||
626 | void | ||
627 | mm_terminate(void) | ||
628 | { | ||
629 | Buffer m; | ||
630 | |||
631 | buffer_init(&m); | ||
632 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_TERM, &m); | ||
633 | buffer_free(&m); | ||
634 | } | ||
635 | |||
636 | int | ||
637 | mm_ssh1_session_key(BIGNUM *num) | ||
638 | { | ||
639 | int rsafail; | ||
640 | Buffer m; | ||
641 | |||
642 | buffer_init(&m); | ||
643 | buffer_put_bignum2(&m, num); | ||
644 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_SESSKEY, &m); | ||
645 | |||
646 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SESSKEY, &m); | ||
647 | |||
648 | rsafail = buffer_get_int(&m); | ||
649 | buffer_get_bignum2(&m, num); | ||
650 | |||
651 | buffer_free(&m); | ||
652 | |||
653 | return (rsafail); | ||
654 | } | ||
655 | |||
656 | static void | ||
657 | mm_chall_setup(char **name, char **infotxt, u_int *numprompts, | ||
658 | char ***prompts, u_int **echo_on) | ||
659 | { | ||
660 | *name = xstrdup(""); | ||
661 | *infotxt = xstrdup(""); | ||
662 | *numprompts = 1; | ||
663 | *prompts = xmalloc(*numprompts * sizeof(char*)); | ||
664 | *echo_on = xmalloc(*numprompts * sizeof(u_int)); | ||
665 | (*echo_on)[0] = 0; | ||
666 | } | ||
667 | |||
668 | int | ||
669 | mm_bsdauth_query(void *ctx, char **name, char **infotxt, | ||
670 | u_int *numprompts, char ***prompts, u_int **echo_on) | ||
671 | { | ||
672 | Buffer m; | ||
673 | int res; | ||
674 | char *challenge; | ||
675 | |||
676 | debug3("%s: entering", __FUNCTION__); | ||
677 | |||
678 | buffer_init(&m); | ||
679 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m); | ||
680 | |||
681 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY, | ||
682 | &m); | ||
683 | res = buffer_get_int(&m); | ||
684 | if (res == -1) { | ||
685 | debug3("%s: no challenge", __FUNCTION__); | ||
686 | buffer_free(&m); | ||
687 | return (-1); | ||
688 | } | ||
689 | |||
690 | /* Get the challenge, and format the response */ | ||
691 | challenge = buffer_get_string(&m, NULL); | ||
692 | buffer_free(&m); | ||
693 | |||
694 | mm_chall_setup(name, infotxt, numprompts, prompts, echo_on); | ||
695 | (*prompts)[0] = challenge; | ||
696 | |||
697 | debug3("%s: received challenge: %s", __FUNCTION__, challenge); | ||
698 | |||
699 | return (0); | ||
700 | } | ||
701 | |||
702 | int | ||
703 | mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses) | ||
704 | { | ||
705 | Buffer m; | ||
706 | int authok; | ||
707 | |||
708 | debug3("%s: entering", __FUNCTION__); | ||
709 | if (numresponses != 1) | ||
710 | return (-1); | ||
711 | |||
712 | buffer_init(&m); | ||
713 | buffer_put_cstring(&m, responses[0]); | ||
714 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m); | ||
715 | |||
716 | mm_request_receive_expect(monitor->m_recvfd, | ||
717 | MONITOR_ANS_BSDAUTHRESPOND, &m); | ||
718 | |||
719 | authok = buffer_get_int(&m); | ||
720 | buffer_free(&m); | ||
721 | |||
722 | return ((authok == 0) ? -1 : 0); | ||
723 | } | ||
724 | |||
725 | int | ||
726 | mm_skey_query(void *ctx, char **name, char **infotxt, | ||
727 | u_int *numprompts, char ***prompts, u_int **echo_on) | ||
728 | { | ||
729 | Buffer m; | ||
730 | int len, res; | ||
731 | char *p, *challenge; | ||
732 | |||
733 | debug3("%s: entering", __FUNCTION__); | ||
734 | |||
735 | buffer_init(&m); | ||
736 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m); | ||
737 | |||
738 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SKEYQUERY, | ||
739 | &m); | ||
740 | res = buffer_get_int(&m); | ||
741 | if (res == -1) { | ||
742 | debug3("%s: no challenge", __FUNCTION__); | ||
743 | buffer_free(&m); | ||
744 | return (-1); | ||
745 | } | ||
746 | |||
747 | /* Get the challenge, and format the response */ | ||
748 | challenge = buffer_get_string(&m, NULL); | ||
749 | buffer_free(&m); | ||
750 | |||
751 | debug3("%s: received challenge: %s", __FUNCTION__, challenge); | ||
752 | |||
753 | mm_chall_setup(name, infotxt, numprompts, prompts, echo_on); | ||
754 | |||
755 | len = strlen(challenge) + strlen(SKEY_PROMPT) + 1; | ||
756 | p = xmalloc(len); | ||
757 | strlcpy(p, challenge, len); | ||
758 | strlcat(p, SKEY_PROMPT, len); | ||
759 | (*prompts)[0] = p; | ||
760 | xfree(challenge); | ||
761 | |||
762 | return (0); | ||
763 | } | ||
764 | |||
765 | int | ||
766 | mm_skey_respond(void *ctx, u_int numresponses, char **responses) | ||
767 | { | ||
768 | Buffer m; | ||
769 | int authok; | ||
770 | |||
771 | debug3("%s: entering", __FUNCTION__); | ||
772 | if (numresponses != 1) | ||
773 | return (-1); | ||
774 | |||
775 | buffer_init(&m); | ||
776 | buffer_put_cstring(&m, responses[0]); | ||
777 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m); | ||
778 | |||
779 | mm_request_receive_expect(monitor->m_recvfd, | ||
780 | MONITOR_ANS_SKEYRESPOND, &m); | ||
781 | |||
782 | authok = buffer_get_int(&m); | ||
783 | buffer_free(&m); | ||
784 | |||
785 | return ((authok == 0) ? -1 : 0); | ||
786 | } | ||
787 | |||
788 | void | ||
789 | mm_ssh1_session_id(u_char session_id[16]) | ||
790 | { | ||
791 | Buffer m; | ||
792 | int i; | ||
793 | |||
794 | debug3("%s entering", __FUNCTION__); | ||
795 | |||
796 | buffer_init(&m); | ||
797 | for (i = 0; i < 16; i++) | ||
798 | buffer_put_char(&m, session_id[i]); | ||
799 | |||
800 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_SESSID, &m); | ||
801 | buffer_free(&m); | ||
802 | } | ||
803 | |||
804 | int | ||
805 | mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) | ||
806 | { | ||
807 | Buffer m; | ||
808 | Key *key; | ||
809 | u_char *blob; | ||
810 | u_int blen; | ||
811 | int allowed = 0; | ||
812 | |||
813 | debug3("%s entering", __FUNCTION__); | ||
814 | |||
815 | buffer_init(&m); | ||
816 | buffer_put_bignum2(&m, client_n); | ||
817 | |||
818 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSAKEYALLOWED, &m); | ||
819 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSAKEYALLOWED, &m); | ||
820 | |||
821 | allowed = buffer_get_int(&m); | ||
822 | |||
823 | if (allowed && rkey != NULL) { | ||
824 | blob = buffer_get_string(&m, &blen); | ||
825 | if ((key = key_from_blob(blob, blen)) == NULL) | ||
826 | fatal("%s: key_from_blob failed", __FUNCTION__); | ||
827 | *rkey = key; | ||
828 | xfree(blob); | ||
829 | } | ||
830 | mm_send_debug(&m); | ||
831 | buffer_free(&m); | ||
832 | |||
833 | return (allowed); | ||
834 | } | ||
835 | |||
836 | BIGNUM * | ||
837 | mm_auth_rsa_generate_challenge(Key *key) | ||
838 | { | ||
839 | Buffer m; | ||
840 | BIGNUM *challenge; | ||
841 | u_char *blob; | ||
842 | u_int blen; | ||
843 | |||
844 | debug3("%s entering", __FUNCTION__); | ||
845 | |||
846 | if ((challenge = BN_new()) == NULL) | ||
847 | fatal("%s: BN_new failed", __FUNCTION__); | ||
848 | |||
849 | key->type = KEY_RSA; /* XXX cheat for key_to_blob */ | ||
850 | if (key_to_blob(key, &blob, &blen) == 0) | ||
851 | fatal("%s: key_to_blob failed", __FUNCTION__); | ||
852 | key->type = KEY_RSA1; | ||
853 | |||
854 | buffer_init(&m); | ||
855 | buffer_put_string(&m, blob, blen); | ||
856 | xfree(blob); | ||
857 | |||
858 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSACHALLENGE, &m); | ||
859 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSACHALLENGE, &m); | ||
860 | |||
861 | buffer_get_bignum2(&m, challenge); | ||
862 | buffer_free(&m); | ||
863 | |||
864 | return (challenge); | ||
865 | } | ||
866 | |||
867 | int | ||
868 | mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16]) | ||
869 | { | ||
870 | Buffer m; | ||
871 | u_char *blob; | ||
872 | u_int blen; | ||
873 | int success = 0; | ||
874 | |||
875 | debug3("%s entering", __FUNCTION__); | ||
876 | |||
877 | key->type = KEY_RSA; /* XXX cheat for key_to_blob */ | ||
878 | if (key_to_blob(key, &blob, &blen) == 0) | ||
879 | fatal("%s: key_to_blob failed", __FUNCTION__); | ||
880 | key->type = KEY_RSA1; | ||
881 | |||
882 | buffer_init(&m); | ||
883 | buffer_put_string(&m, blob, blen); | ||
884 | buffer_put_string(&m, response, 16); | ||
885 | xfree(blob); | ||
886 | |||
887 | mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSARESPONSE, &m); | ||
888 | mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSARESPONSE, &m); | ||
889 | |||
890 | success = buffer_get_int(&m); | ||
891 | buffer_free(&m); | ||
892 | |||
893 | return (success); | ||
894 | } | ||
diff --git a/monitor_wrap.h b/monitor_wrap.h new file mode 100644 index 000000000..a75b90502 --- /dev/null +++ b/monitor_wrap.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #ifndef _MM_WRAP_H_ | ||
27 | #define _MM_WRAP_H_ | ||
28 | #include "key.h" | ||
29 | #include "buffer.h" | ||
30 | |||
31 | extern int use_privsep; | ||
32 | #define PRIVSEP(x) (use_privsep ? mm_##x : x) | ||
33 | |||
34 | enum mm_keytype {MM_NOKEY, MM_HOSTKEY, MM_USERKEY, MM_RSAHOSTKEY, MM_RSAUSERKEY}; | ||
35 | |||
36 | struct monitor; | ||
37 | struct mm_master; | ||
38 | struct passwd; | ||
39 | struct Authctxt; | ||
40 | |||
41 | DH *mm_choose_dh(int, int, int); | ||
42 | int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int); | ||
43 | void mm_inform_authserv(char *, char *); | ||
44 | struct passwd *mm_getpwnamallow(const char *); | ||
45 | int mm_auth_password(struct Authctxt *, char *); | ||
46 | int mm_key_allowed(enum mm_keytype, char *, char *, Key *); | ||
47 | int mm_user_key_allowed(struct passwd *, Key *); | ||
48 | int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); | ||
49 | int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); | ||
50 | int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); | ||
51 | int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); | ||
52 | int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); | ||
53 | BIGNUM *mm_auth_rsa_generate_challenge(Key *); | ||
54 | |||
55 | void mm_terminate(void); | ||
56 | int mm_pty_allocate(int *, int *, char *, int); | ||
57 | void mm_session_pty_cleanup2(void *); | ||
58 | |||
59 | /* SSHv1 interfaces */ | ||
60 | void mm_ssh1_session_id(u_char *); | ||
61 | int mm_ssh1_session_key(BIGNUM *); | ||
62 | |||
63 | /* Key export functions */ | ||
64 | struct Newkeys *mm_newkeys_from_blob(u_char *, int); | ||
65 | int mm_newkeys_to_blob(int, u_char **, u_int *); | ||
66 | |||
67 | void monitor_apply_keystate(struct monitor *); | ||
68 | void mm_get_keystate(struct monitor *); | ||
69 | void mm_send_keystate(struct monitor*); | ||
70 | |||
71 | /* bsdauth */ | ||
72 | int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); | ||
73 | int mm_bsdauth_respond(void *, u_int, char **); | ||
74 | |||
75 | /* skey */ | ||
76 | int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **); | ||
77 | int mm_skey_respond(void *, u_int, char **); | ||
78 | |||
79 | /* zlib allocation hooks */ | ||
80 | |||
81 | void *mm_zalloc(struct mm_master *, u_int, u_int); | ||
82 | void mm_zfree(struct mm_master *, void *); | ||
83 | void mm_init_compression(struct mm_master *); | ||
84 | |||
85 | #endif /* _MM_H_ */ | ||
diff --git a/servconf.c b/servconf.c index 9bbd994ca..3b6b55e93 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "includes.h" | 12 | #include "includes.h" |
13 | RCSID("$OpenBSD: servconf.c,v 1.101 2002/02/04 12:15:25 markus Exp $"); | 13 | RCSID("$OpenBSD: servconf.c,v 1.102 2002/03/18 17:50:31 provos Exp $"); |
14 | 14 | ||
15 | #if defined(KRB4) || defined(KRB5) | 15 | #if defined(KRB4) || defined(KRB5) |
16 | #include <krb.h> | 16 | #include <krb.h> |
@@ -36,6 +36,8 @@ static void add_one_listen_addr(ServerOptions *, char *, u_short); | |||
36 | 36 | ||
37 | /* AF_UNSPEC or AF_INET or AF_INET6 */ | 37 | /* AF_UNSPEC or AF_INET or AF_INET6 */ |
38 | extern int IPv4or6; | 38 | extern int IPv4or6; |
39 | /* Use of privilege separation or not */ | ||
40 | extern int use_privsep; | ||
39 | 41 | ||
40 | /* Initializes the server options to their default values. */ | 42 | /* Initializes the server options to their default values. */ |
41 | 43 | ||
@@ -110,6 +112,13 @@ initialize_server_options(ServerOptions *options) | |||
110 | options->client_alive_count_max = -1; | 112 | options->client_alive_count_max = -1; |
111 | options->authorized_keys_file = NULL; | 113 | options->authorized_keys_file = NULL; |
112 | options->authorized_keys_file2 = NULL; | 114 | options->authorized_keys_file2 = NULL; |
115 | |||
116 | options->unprivileged_user = -1; | ||
117 | options->unprivileged_group = -1; | ||
118 | options->unprivileged_dir = NULL; | ||
119 | |||
120 | /* Needs to be accessable in many places */ | ||
121 | use_privsep = -1; | ||
113 | } | 122 | } |
114 | 123 | ||
115 | void | 124 | void |
@@ -235,6 +244,16 @@ fill_default_server_options(ServerOptions *options) | |||
235 | } | 244 | } |
236 | if (options->authorized_keys_file == NULL) | 245 | if (options->authorized_keys_file == NULL) |
237 | options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; | 246 | options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; |
247 | |||
248 | /* Turn privilege separation _off_ by default */ | ||
249 | if (use_privsep == -1) | ||
250 | use_privsep = 0; | ||
251 | if (options->unprivileged_user == -1) | ||
252 | options->unprivileged_user = 32767; | ||
253 | if (options->unprivileged_group == -1) | ||
254 | options->unprivileged_group = 32767; | ||
255 | if (options->unprivileged_dir == NULL) | ||
256 | options->unprivileged_dir = "/var/empty"; | ||
238 | } | 257 | } |
239 | 258 | ||
240 | /* Keyword tokens. */ | 259 | /* Keyword tokens. */ |
@@ -267,6 +286,7 @@ typedef enum { | |||
267 | sBanner, sVerifyReverseMapping, sHostbasedAuthentication, | 286 | sBanner, sVerifyReverseMapping, sHostbasedAuthentication, |
268 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | 287 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, |
269 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, | 288 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, |
289 | sUsePrivilegeSeparation, sUnprivUser, sUnprivGroup, sUnprivDir, | ||
270 | sDeprecated | 290 | sDeprecated |
271 | } ServerOpCodes; | 291 | } ServerOpCodes; |
272 | 292 | ||
@@ -342,6 +362,10 @@ static struct { | |||
342 | { "clientalivecountmax", sClientAliveCountMax }, | 362 | { "clientalivecountmax", sClientAliveCountMax }, |
343 | { "authorizedkeysfile", sAuthorizedKeysFile }, | 363 | { "authorizedkeysfile", sAuthorizedKeysFile }, |
344 | { "authorizedkeysfile2", sAuthorizedKeysFile2 }, | 364 | { "authorizedkeysfile2", sAuthorizedKeysFile2 }, |
365 | { "useprivilegeseparation", sUsePrivilegeSeparation}, | ||
366 | { "unprivuser", sUnprivUser}, | ||
367 | { "unprivgroup", sUnprivGroup}, | ||
368 | { "unprivdir", sUnprivDir}, | ||
345 | { NULL, sBadOption } | 369 | { NULL, sBadOption } |
346 | }; | 370 | }; |
347 | 371 | ||
@@ -718,6 +742,22 @@ parse_flag: | |||
718 | intptr = &options->allow_tcp_forwarding; | 742 | intptr = &options->allow_tcp_forwarding; |
719 | goto parse_flag; | 743 | goto parse_flag; |
720 | 744 | ||
745 | case sUsePrivilegeSeparation: | ||
746 | intptr = &use_privsep; | ||
747 | goto parse_flag; | ||
748 | |||
749 | case sUnprivUser: | ||
750 | intptr = &options->unprivileged_user; | ||
751 | goto parse_flag; | ||
752 | |||
753 | case sUnprivGroup: | ||
754 | intptr = &options->unprivileged_group; | ||
755 | goto parse_flag; | ||
756 | |||
757 | case sUnprivDir: | ||
758 | charptr = &options->unprivileged_dir; | ||
759 | goto parse_filename; | ||
760 | |||
721 | case sAllowUsers: | 761 | case sAllowUsers: |
722 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 762 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
723 | if (options->num_allow_users >= MAX_ALLOW_USERS) | 763 | if (options->num_allow_users >= MAX_ALLOW_USERS) |
diff --git a/servconf.h b/servconf.h index 3134b222a..b5d110a5a 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.54 2002/03/04 17:27:39 stevesk Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.55 2002/03/18 17:50:31 provos Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -131,6 +131,9 @@ typedef struct { | |||
131 | char *authorized_keys_file2; | 131 | char *authorized_keys_file2; |
132 | int pam_authentication_via_kbd_int; | 132 | int pam_authentication_via_kbd_int; |
133 | 133 | ||
134 | int unprivileged_user; /* User unprivileged child uses */ | ||
135 | int unprivileged_group; /* Group unprivileged child uses */ | ||
136 | char *unprivileged_dir; /* Chroot dir for unprivileged user */ | ||
134 | } ServerOptions; | 137 | } ServerOptions; |
135 | 138 | ||
136 | void initialize_server_options(ServerOptions *); | 139 | void initialize_server_options(ServerOptions *); |
diff --git a/serverloop.c b/serverloop.c index 46b12ee3d..f3a659188 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -35,7 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "includes.h" | 37 | #include "includes.h" |
38 | RCSID("$OpenBSD: serverloop.c,v 1.98 2002/02/06 14:55:16 markus Exp $"); | 38 | RCSID("$OpenBSD: serverloop.c,v 1.99 2002/03/18 17:50:31 provos Exp $"); |
39 | 39 | ||
40 | #include "xmalloc.h" | 40 | #include "xmalloc.h" |
41 | #include "packet.h" | 41 | #include "packet.h" |
@@ -784,7 +784,7 @@ server_loop2(Authctxt *authctxt) | |||
784 | channel_free_all(); | 784 | channel_free_all(); |
785 | 785 | ||
786 | /* free remaining sessions, e.g. remove wtmp entries */ | 786 | /* free remaining sessions, e.g. remove wtmp entries */ |
787 | session_destroy_all(); | 787 | session_destroy_all(NULL); |
788 | } | 788 | } |
789 | 789 | ||
790 | static void | 790 | static void |
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include "includes.h" | 35 | #include "includes.h" |
36 | RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $"); | 36 | RCSID("$OpenBSD: session.c,v 1.130 2002/03/18 17:50:31 provos Exp $"); |
37 | 37 | ||
38 | #include "ssh.h" | 38 | #include "ssh.h" |
39 | #include "ssh1.h" | 39 | #include "ssh1.h" |
@@ -56,6 +56,7 @@ RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $"); | |||
56 | #include "serverloop.h" | 56 | #include "serverloop.h" |
57 | #include "canohost.h" | 57 | #include "canohost.h" |
58 | #include "session.h" | 58 | #include "session.h" |
59 | #include "monitor_wrap.h" | ||
59 | 60 | ||
60 | #ifdef HAVE_CYGWIN | 61 | #ifdef HAVE_CYGWIN |
61 | #include <windows.h> | 62 | #include <windows.h> |
@@ -63,39 +64,11 @@ RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $"); | |||
63 | #define is_winnt (GetVersion() < 0x80000000) | 64 | #define is_winnt (GetVersion() < 0x80000000) |
64 | #endif | 65 | #endif |
65 | 66 | ||
66 | /* types */ | ||
67 | |||
68 | #define TTYSZ 64 | ||
69 | typedef struct Session Session; | ||
70 | struct Session { | ||
71 | int used; | ||
72 | int self; | ||
73 | struct passwd *pw; | ||
74 | Authctxt *authctxt; | ||
75 | pid_t pid; | ||
76 | /* tty */ | ||
77 | char *term; | ||
78 | int ptyfd, ttyfd, ptymaster; | ||
79 | int row, col, xpixel, ypixel; | ||
80 | char tty[TTYSZ]; | ||
81 | /* X11 */ | ||
82 | int display_number; | ||
83 | char *display; | ||
84 | int screen; | ||
85 | char *auth_display; | ||
86 | char *auth_proto; | ||
87 | char *auth_data; | ||
88 | int single_connection; | ||
89 | /* proto 2 */ | ||
90 | int chanid; | ||
91 | int is_subsystem; | ||
92 | }; | ||
93 | |||
94 | /* func */ | 67 | /* func */ |
95 | 68 | ||
96 | Session *session_new(void); | 69 | Session *session_new(void); |
97 | void session_set_fds(Session *, int, int, int); | 70 | void session_set_fds(Session *, int, int, int); |
98 | static void session_pty_cleanup(void *); | 71 | void session_pty_cleanup(void *); |
99 | void session_proctitle(Session *); | 72 | void session_proctitle(Session *); |
100 | int session_setup_x11fwd(Session *); | 73 | int session_setup_x11fwd(Session *); |
101 | void do_exec_pty(Session *, const char *); | 74 | void do_exec_pty(Session *, const char *); |
@@ -112,7 +85,6 @@ int check_quietlogin(Session *, const char *); | |||
112 | static void do_authenticated1(Authctxt *); | 85 | static void do_authenticated1(Authctxt *); |
113 | static void do_authenticated2(Authctxt *); | 86 | static void do_authenticated2(Authctxt *); |
114 | 87 | ||
115 | static void session_close(Session *); | ||
116 | static int session_pty_req(Session *); | 88 | static int session_pty_req(Session *); |
117 | 89 | ||
118 | /* import */ | 90 | /* import */ |
@@ -1087,7 +1059,7 @@ do_nologin(struct passwd *pw) | |||
1087 | } | 1059 | } |
1088 | 1060 | ||
1089 | /* Set login name, uid, gid, and groups. */ | 1061 | /* Set login name, uid, gid, and groups. */ |
1090 | static void | 1062 | void |
1091 | do_setusercontext(struct passwd *pw) | 1063 | do_setusercontext(struct passwd *pw) |
1092 | { | 1064 | { |
1093 | #ifdef HAVE_CYGWIN | 1065 | #ifdef HAVE_CYGWIN |
@@ -1142,6 +1114,23 @@ do_setusercontext(struct passwd *pw) | |||
1142 | fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); | 1114 | fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); |
1143 | } | 1115 | } |
1144 | 1116 | ||
1117 | void | ||
1118 | launch_login(struct passwd *pw, const char *hostname) | ||
1119 | { | ||
1120 | /* Launch login(1). */ | ||
1121 | |||
1122 | execl("/usr/bin/login", "login", "-h", hostname, | ||
1123 | #ifdef LOGIN_NEEDS_TERM | ||
1124 | (s->term ? s->term : "unknown"), | ||
1125 | #endif /* LOGIN_NEEDS_TERM */ | ||
1126 | "-p", "-f", "--", pw->pw_name, (char *)NULL); | ||
1127 | |||
1128 | /* Login couldn't be executed, die. */ | ||
1129 | |||
1130 | perror("login"); | ||
1131 | exit(1); | ||
1132 | } | ||
1133 | |||
1145 | /* | 1134 | /* |
1146 | * Performs common processing for the child, such as setting up the | 1135 | * Performs common processing for the child, such as setting up the |
1147 | * environment, closing extra file descriptors, setting the user and group | 1136 | * environment, closing extra file descriptors, setting the user and group |
@@ -1267,18 +1256,8 @@ do_child(Session *s, const char *command) | |||
1267 | signal(SIGPIPE, SIG_DFL); | 1256 | signal(SIGPIPE, SIG_DFL); |
1268 | 1257 | ||
1269 | if (options.use_login) { | 1258 | if (options.use_login) { |
1270 | /* Launch login(1). */ | 1259 | launch_login(pw, hostname); |
1271 | 1260 | /* NEVERREACHED */ | |
1272 | execl(LOGIN_PROGRAM, "login", "-h", hostname, | ||
1273 | #ifdef LOGIN_NEEDS_TERM | ||
1274 | (s->term ? s->term : "unknown"), | ||
1275 | #endif /* LOGIN_NEEDS_TERM */ | ||
1276 | "-p", "-f", "--", pw->pw_name, (char *)NULL); | ||
1277 | |||
1278 | /* Login couldn't be executed, die. */ | ||
1279 | |||
1280 | perror("login"); | ||
1281 | exit(1); | ||
1282 | } | 1261 | } |
1283 | 1262 | ||
1284 | /* Get the last component of the shell name. */ | 1263 | /* Get the last component of the shell name. */ |
@@ -1388,6 +1367,22 @@ session_open(Authctxt *authctxt, int chanid) | |||
1388 | return 1; | 1367 | return 1; |
1389 | } | 1368 | } |
1390 | 1369 | ||
1370 | Session * | ||
1371 | session_by_tty(char *tty) | ||
1372 | { | ||
1373 | int i; | ||
1374 | for (i = 0; i < MAX_SESSIONS; i++) { | ||
1375 | Session *s = &sessions[i]; | ||
1376 | if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { | ||
1377 | debug("session_by_tty: session %d tty %s", i, tty); | ||
1378 | return s; | ||
1379 | } | ||
1380 | } | ||
1381 | debug("session_by_tty: unknown tty %.100s", tty); | ||
1382 | session_dump(); | ||
1383 | return NULL; | ||
1384 | } | ||
1385 | |||
1391 | static Session * | 1386 | static Session * |
1392 | session_by_channel(int id) | 1387 | session_by_channel(int id) |
1393 | { | 1388 | { |
@@ -1436,7 +1431,7 @@ session_pty_req(Session *s) | |||
1436 | { | 1431 | { |
1437 | u_int len; | 1432 | u_int len; |
1438 | int n_bytes; | 1433 | int n_bytes; |
1439 | 1434 | ||
1440 | if (no_pty_flag) { | 1435 | if (no_pty_flag) { |
1441 | debug("Allocating a pty not permitted for this authentication."); | 1436 | debug("Allocating a pty not permitted for this authentication."); |
1442 | return 0; | 1437 | return 0; |
@@ -1465,7 +1460,7 @@ session_pty_req(Session *s) | |||
1465 | 1460 | ||
1466 | /* Allocate a pty and open it. */ | 1461 | /* Allocate a pty and open it. */ |
1467 | debug("Allocating pty."); | 1462 | debug("Allocating pty."); |
1468 | if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) { | 1463 | if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { |
1469 | if (s->term) | 1464 | if (s->term) |
1470 | xfree(s->term); | 1465 | xfree(s->term); |
1471 | s->term = NULL; | 1466 | s->term = NULL; |
@@ -1486,7 +1481,8 @@ session_pty_req(Session *s) | |||
1486 | * time in case we call fatal() (e.g., the connection gets closed). | 1481 | * time in case we call fatal() (e.g., the connection gets closed). |
1487 | */ | 1482 | */ |
1488 | fatal_add_cleanup(session_pty_cleanup, (void *)s); | 1483 | fatal_add_cleanup(session_pty_cleanup, (void *)s); |
1489 | pty_setowner(s->pw, s->tty); | 1484 | if (!use_privsep) |
1485 | pty_setowner(s->pw, s->tty); | ||
1490 | 1486 | ||
1491 | /* Set window size from the packet. */ | 1487 | /* Set window size from the packet. */ |
1492 | pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); | 1488 | pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); |
@@ -1649,8 +1645,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) | |||
1649 | * Function to perform pty cleanup. Also called if we get aborted abnormally | 1645 | * Function to perform pty cleanup. Also called if we get aborted abnormally |
1650 | * (e.g., due to a dropped connection). | 1646 | * (e.g., due to a dropped connection). |
1651 | */ | 1647 | */ |
1652 | static void | 1648 | void |
1653 | session_pty_cleanup(void *session) | 1649 | session_pty_cleanup2(void *session) |
1654 | { | 1650 | { |
1655 | Session *s = session; | 1651 | Session *s = session; |
1656 | 1652 | ||
@@ -1668,7 +1664,8 @@ session_pty_cleanup(void *session) | |||
1668 | record_logout(s->pid, s->tty, s->pw->pw_name); | 1664 | record_logout(s->pid, s->tty, s->pw->pw_name); |
1669 | 1665 | ||
1670 | /* Release the pseudo-tty. */ | 1666 | /* Release the pseudo-tty. */ |
1671 | pty_release(s->tty); | 1667 | if (getuid() == 0) |
1668 | pty_release(s->tty); | ||
1672 | 1669 | ||
1673 | /* | 1670 | /* |
1674 | * Close the server side of the socket pairs. We must do this after | 1671 | * Close the server side of the socket pairs. We must do this after |
@@ -1676,12 +1673,18 @@ session_pty_cleanup(void *session) | |||
1676 | * while we're still cleaning up. | 1673 | * while we're still cleaning up. |
1677 | */ | 1674 | */ |
1678 | if (close(s->ptymaster) < 0) | 1675 | if (close(s->ptymaster) < 0) |
1679 | error("close(s->ptymaster): %s", strerror(errno)); | 1676 | error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); |
1680 | 1677 | ||
1681 | /* unlink pty from session */ | 1678 | /* unlink pty from session */ |
1682 | s->ttyfd = -1; | 1679 | s->ttyfd = -1; |
1683 | } | 1680 | } |
1684 | 1681 | ||
1682 | void | ||
1683 | session_pty_cleanup(void *session) | ||
1684 | { | ||
1685 | PRIVSEP(session_pty_cleanup2(session)); | ||
1686 | } | ||
1687 | |||
1685 | static void | 1688 | static void |
1686 | session_exit_message(Session *s, int status) | 1689 | session_exit_message(Session *s, int status) |
1687 | { | 1690 | { |
@@ -1727,7 +1730,7 @@ session_exit_message(Session *s, int status) | |||
1727 | s->chanid = -1; | 1730 | s->chanid = -1; |
1728 | } | 1731 | } |
1729 | 1732 | ||
1730 | static void | 1733 | void |
1731 | session_close(Session *s) | 1734 | session_close(Session *s) |
1732 | { | 1735 | { |
1733 | debug("session_close: session %d pid %d", s->self, s->pid); | 1736 | debug("session_close: session %d pid %d", s->self, s->pid); |
@@ -1794,13 +1797,17 @@ session_close_by_channel(int id, void *arg) | |||
1794 | } | 1797 | } |
1795 | 1798 | ||
1796 | void | 1799 | void |
1797 | session_destroy_all(void) | 1800 | session_destroy_all(void (*closefunc)(Session *)) |
1798 | { | 1801 | { |
1799 | int i; | 1802 | int i; |
1800 | for (i = 0; i < MAX_SESSIONS; i++) { | 1803 | for (i = 0; i < MAX_SESSIONS; i++) { |
1801 | Session *s = &sessions[i]; | 1804 | Session *s = &sessions[i]; |
1802 | if (s->used) | 1805 | if (s->used) { |
1803 | session_close(s); | 1806 | if (closefunc != NULL) |
1807 | closefunc(s); | ||
1808 | else | ||
1809 | session_close(s); | ||
1810 | } | ||
1804 | } | 1811 | } |
1805 | } | 1812 | } |
1806 | 1813 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.h,v 1.14 2002/02/03 17:53:25 markus Exp $ */ | 1 | /* $OpenBSD: session.h,v 1.15 2002/03/18 17:50:31 provos Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -26,12 +26,42 @@ | |||
26 | #ifndef SESSION_H | 26 | #ifndef SESSION_H |
27 | #define SESSION_H | 27 | #define SESSION_H |
28 | 28 | ||
29 | #define TTYSZ 64 | ||
30 | typedef struct Session Session; | ||
31 | struct Session { | ||
32 | int used; | ||
33 | int self; | ||
34 | struct passwd *pw; | ||
35 | Authctxt *authctxt; | ||
36 | pid_t pid; | ||
37 | /* tty */ | ||
38 | char *term; | ||
39 | int ptyfd, ttyfd, ptymaster; | ||
40 | int row, col, xpixel, ypixel; | ||
41 | char tty[TTYSZ]; | ||
42 | /* X11 */ | ||
43 | int display_number; | ||
44 | char *display; | ||
45 | int screen; | ||
46 | char *auth_display; | ||
47 | char *auth_proto; | ||
48 | char *auth_data; | ||
49 | int single_connection; | ||
50 | /* proto 2 */ | ||
51 | int chanid; | ||
52 | int is_subsystem; | ||
53 | }; | ||
54 | |||
29 | void do_authenticated(Authctxt *); | 55 | void do_authenticated(Authctxt *); |
30 | 56 | ||
31 | int session_open(Authctxt*, int); | 57 | int session_open(Authctxt*, int); |
32 | int session_input_channel_req(Channel *, const char *); | 58 | int session_input_channel_req(Channel *, const char *); |
33 | void session_close_by_pid(pid_t, int); | 59 | void session_close_by_pid(pid_t, int); |
34 | void session_close_by_channel(int, void *); | 60 | void session_close_by_channel(int, void *); |
35 | void session_destroy_all(void); | 61 | void session_destroy_all(void (*)(Session *)); |
36 | 62 | ||
63 | Session *session_new(void); | ||
64 | Session *session_by_tty(char *); | ||
65 | void session_close(Session *); | ||
66 | void do_setusercontext(struct passwd *); | ||
37 | #endif | 67 | #endif |
@@ -15,8 +15,10 @@ | |||
15 | * called by a name other than "ssh" or "Secure Shell". | 15 | * called by a name other than "ssh" or "Secure Shell". |
16 | * | 16 | * |
17 | * SSH2 implementation: | 17 | * SSH2 implementation: |
18 | * Privilege Separation: | ||
18 | * | 19 | * |
19 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 20 | * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. |
21 | * Copyright (c) 2002 Niels Provos. All rights reserved. | ||
20 | * | 22 | * |
21 | * Redistribution and use in source and binary forms, with or without | 23 | * Redistribution and use in source and binary forms, with or without |
22 | * modification, are permitted provided that the following conditions | 24 | * modification, are permitted provided that the following conditions |
@@ -40,11 +42,12 @@ | |||
40 | */ | 42 | */ |
41 | 43 | ||
42 | #include "includes.h" | 44 | #include "includes.h" |
43 | RCSID("$OpenBSD: sshd.c,v 1.230 2002/03/18 01:12:14 provos Exp $"); | 45 | RCSID("$OpenBSD: sshd.c,v 1.231 2002/03/18 17:50:31 provos Exp $"); |
44 | 46 | ||
45 | #include <openssl/dh.h> | 47 | #include <openssl/dh.h> |
46 | #include <openssl/bn.h> | 48 | #include <openssl/bn.h> |
47 | #include <openssl/md5.h> | 49 | #include <openssl/md5.h> |
50 | #include <openssl/rand.h> | ||
48 | 51 | ||
49 | #include "ssh.h" | 52 | #include "ssh.h" |
50 | #include "ssh1.h" | 53 | #include "ssh1.h" |
@@ -73,6 +76,10 @@ RCSID("$OpenBSD: sshd.c,v 1.230 2002/03/18 01:12:14 provos Exp $"); | |||
73 | #include "dispatch.h" | 76 | #include "dispatch.h" |
74 | #include "channels.h" | 77 | #include "channels.h" |
75 | #include "session.h" | 78 | #include "session.h" |
79 | #include "monitor_mm.h" | ||
80 | #include "monitor.h" | ||
81 | #include "monitor_wrap.h" | ||
82 | #include "monitor_fdpass.h" | ||
76 | 83 | ||
77 | #ifdef LIBWRAP | 84 | #ifdef LIBWRAP |
78 | #include <tcpd.h> | 85 | #include <tcpd.h> |
@@ -190,8 +197,13 @@ u_int utmp_len = MAXHOSTNAMELEN; | |||
190 | int *startup_pipes = NULL; | 197 | int *startup_pipes = NULL; |
191 | int startup_pipe; /* in child */ | 198 | int startup_pipe; /* in child */ |
192 | 199 | ||
200 | /* variables used for privilege separation */ | ||
201 | extern struct monitor *monitor; | ||
202 | extern int use_privsep; | ||
203 | |||
193 | /* Prototypes for various functions defined later in this file. */ | 204 | /* Prototypes for various functions defined later in this file. */ |
194 | void destroy_sensitive_data(void); | 205 | void destroy_sensitive_data(void); |
206 | void demote_sensitive_data(void); | ||
195 | 207 | ||
196 | static void do_ssh1_kex(void); | 208 | static void do_ssh1_kex(void); |
197 | static void do_ssh2_kex(void); | 209 | static void do_ssh2_kex(void); |
@@ -478,6 +490,115 @@ destroy_sensitive_data(void) | |||
478 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); | 490 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); |
479 | } | 491 | } |
480 | 492 | ||
493 | /* Demote private to public keys for network child */ | ||
494 | void | ||
495 | demote_sensitive_data(void) | ||
496 | { | ||
497 | Key *tmp; | ||
498 | int i; | ||
499 | |||
500 | if (sensitive_data.server_key) { | ||
501 | tmp = key_demote(sensitive_data.server_key); | ||
502 | key_free(sensitive_data.server_key); | ||
503 | sensitive_data.server_key = tmp; | ||
504 | } | ||
505 | |||
506 | for (i = 0; i < options.num_host_key_files; i++) { | ||
507 | if (sensitive_data.host_keys[i]) { | ||
508 | tmp = key_demote(sensitive_data.host_keys[i]); | ||
509 | key_free(sensitive_data.host_keys[i]); | ||
510 | sensitive_data.host_keys[i] = tmp; | ||
511 | if (tmp->type == KEY_RSA1) | ||
512 | sensitive_data.ssh1_host_key = tmp; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ | ||
517 | } | ||
518 | |||
519 | void | ||
520 | privsep_preauth_child(void) | ||
521 | { | ||
522 | u_int32_t rand[256]; | ||
523 | int i; | ||
524 | |||
525 | /* Enable challenge-response authentication for privilege separation */ | ||
526 | privsep_challenge_enable(); | ||
527 | |||
528 | for (i = 0; i < 256; i++) | ||
529 | rand[i] = arc4random(); | ||
530 | RAND_seed(rand, sizeof(rand)); | ||
531 | |||
532 | /* Demote the private keys to public keys. */ | ||
533 | demote_sensitive_data(); | ||
534 | |||
535 | /* Change our root directory*/ | ||
536 | if (chroot(options.unprivileged_dir) == -1) | ||
537 | fatal("chroot(/var/empty)"); | ||
538 | if (chdir("/") == -1) | ||
539 | fatal("chdir(/)"); | ||
540 | |||
541 | /* Drop our privileges */ | ||
542 | setegid(options.unprivileged_group); | ||
543 | setgid(options.unprivileged_group); | ||
544 | seteuid(options.unprivileged_user); | ||
545 | setuid(options.unprivileged_user); | ||
546 | } | ||
547 | |||
548 | void | ||
549 | privsep_postauth(Authctxt *authctxt, pid_t pid) | ||
550 | { | ||
551 | extern Authctxt *x_authctxt; | ||
552 | int status; | ||
553 | |||
554 | /* Wait for the child's exit status */ | ||
555 | waitpid(pid, &status, 0); | ||
556 | |||
557 | /* XXX - Remote port forwarding */ | ||
558 | x_authctxt = authctxt; | ||
559 | |||
560 | if (authctxt->pw->pw_uid == 0 || options.use_login) { | ||
561 | /* File descriptor passing is broken or root login */ | ||
562 | monitor_apply_keystate(monitor); | ||
563 | use_privsep = 0; | ||
564 | return; | ||
565 | } | ||
566 | |||
567 | /* Authentication complete */ | ||
568 | alarm(0); | ||
569 | if (startup_pipe != -1) { | ||
570 | close(startup_pipe); | ||
571 | startup_pipe = -1; | ||
572 | } | ||
573 | |||
574 | /* New socket pair */ | ||
575 | monitor_reinit(monitor); | ||
576 | |||
577 | monitor->m_pid = fork(); | ||
578 | if (monitor->m_pid == -1) | ||
579 | fatal("fork of unprivileged child failed"); | ||
580 | else if (monitor->m_pid != 0) { | ||
581 | debug2("User child is on pid %d", pid); | ||
582 | close(monitor->m_recvfd); | ||
583 | monitor_child_postauth(monitor); | ||
584 | |||
585 | /* NEVERREACHED */ | ||
586 | exit(0); | ||
587 | } | ||
588 | |||
589 | close(monitor->m_sendfd); | ||
590 | |||
591 | /* Demote the private keys to public keys. */ | ||
592 | demote_sensitive_data(); | ||
593 | |||
594 | /* Drop privileges */ | ||
595 | do_setusercontext(authctxt->pw); | ||
596 | |||
597 | /* It is safe now to apply the key state */ | ||
598 | monitor_apply_keystate(monitor); | ||
599 | } | ||
600 | |||
601 | |||
481 | static char * | 602 | static char * |
482 | list_hostkey_types(void) | 603 | list_hostkey_types(void) |
483 | { | 604 | { |
@@ -507,7 +628,7 @@ list_hostkey_types(void) | |||
507 | return p; | 628 | return p; |
508 | } | 629 | } |
509 | 630 | ||
510 | static Key * | 631 | Key * |
511 | get_hostkey_by_type(int type) | 632 | get_hostkey_by_type(int type) |
512 | { | 633 | { |
513 | int i; | 634 | int i; |
@@ -519,6 +640,25 @@ get_hostkey_by_type(int type) | |||
519 | return NULL; | 640 | return NULL; |
520 | } | 641 | } |
521 | 642 | ||
643 | Key * | ||
644 | get_hostkey_by_index(int ind) | ||
645 | { | ||
646 | if (ind < 0 || ind >= options.num_host_key_files) | ||
647 | return (NULL); | ||
648 | return (sensitive_data.host_keys[ind]); | ||
649 | } | ||
650 | |||
651 | int | ||
652 | get_hostkey_index(Key *key) | ||
653 | { | ||
654 | int i; | ||
655 | for (i = 0; i < options.num_host_key_files; i++) { | ||
656 | if (key == sensitive_data.host_keys[i]) | ||
657 | return (i); | ||
658 | } | ||
659 | return (-1); | ||
660 | } | ||
661 | |||
522 | /* | 662 | /* |
523 | * returns 1 if connection should be dropped, 0 otherwise. | 663 | * returns 1 if connection should be dropped, 0 otherwise. |
524 | * dropping starts at connection #max_startups_begin with a probability | 664 | * dropping starts at connection #max_startups_begin with a probability |
@@ -1233,6 +1373,37 @@ main(int ac, char **av) | |||
1233 | 1373 | ||
1234 | packet_set_nonblocking(); | 1374 | packet_set_nonblocking(); |
1235 | 1375 | ||
1376 | if (!use_privsep) | ||
1377 | goto skip_privilegeseparation; | ||
1378 | |||
1379 | /* Set up unprivileged child process to deal with network data */ | ||
1380 | monitor = monitor_init(); | ||
1381 | /* Store a pointer to the kex for later rekeying */ | ||
1382 | monitor->m_pkex = &xxx_kex; | ||
1383 | |||
1384 | pid = fork(); | ||
1385 | if (pid == -1) | ||
1386 | fatal("fork of unprivileged child failed"); | ||
1387 | else if (pid != 0) { | ||
1388 | debug2("Network child is on pid %d", pid); | ||
1389 | |||
1390 | close(monitor->m_recvfd); | ||
1391 | authctxt = monitor_child_preauth(monitor); | ||
1392 | close(monitor->m_sendfd); | ||
1393 | |||
1394 | /* Sync memory */ | ||
1395 | monitor_sync(monitor); | ||
1396 | goto authenticated; | ||
1397 | } else { | ||
1398 | close(monitor->m_sendfd); | ||
1399 | |||
1400 | /* Demote the child */ | ||
1401 | if (getuid() == 0 || geteuid() == 0) | ||
1402 | privsep_preauth_child(); | ||
1403 | } | ||
1404 | |||
1405 | skip_privilegeseparation: | ||
1406 | |||
1236 | /* perform the key exchange */ | 1407 | /* perform the key exchange */ |
1237 | /* authenticate user and start session */ | 1408 | /* authenticate user and start session */ |
1238 | if (compat20) { | 1409 | if (compat20) { |
@@ -1242,6 +1413,23 @@ main(int ac, char **av) | |||
1242 | do_ssh1_kex(); | 1413 | do_ssh1_kex(); |
1243 | authctxt = do_authentication(); | 1414 | authctxt = do_authentication(); |
1244 | } | 1415 | } |
1416 | if (use_privsep) | ||
1417 | mm_send_keystate(monitor); | ||
1418 | |||
1419 | /* If we use privilege separation, the unprivileged child exits */ | ||
1420 | if (use_privsep) | ||
1421 | exit(0); | ||
1422 | |||
1423 | authenticated: | ||
1424 | /* | ||
1425 | * In privilege separation, we fork another child and prepare | ||
1426 | * file descriptor passing. | ||
1427 | */ | ||
1428 | if (use_privsep) { | ||
1429 | privsep_postauth(authctxt, pid); | ||
1430 | if (!compat20) | ||
1431 | destroy_sensitive_data(); | ||
1432 | } | ||
1245 | 1433 | ||
1246 | /* Perform session preparation. */ | 1434 | /* Perform session preparation. */ |
1247 | do_authenticated(authctxt); | 1435 | do_authenticated(authctxt); |
@@ -1254,6 +1442,10 @@ main(int ac, char **av) | |||
1254 | #endif /* USE_PAM */ | 1442 | #endif /* USE_PAM */ |
1255 | 1443 | ||
1256 | packet_close(); | 1444 | packet_close(); |
1445 | |||
1446 | if (use_privsep) | ||
1447 | mm_terminate(); | ||
1448 | |||
1257 | exit(0); | 1449 | exit(0); |
1258 | } | 1450 | } |
1259 | 1451 | ||
@@ -1261,7 +1453,7 @@ main(int ac, char **av) | |||
1261 | * Decrypt session_key_int using our private server key and private host key | 1453 | * Decrypt session_key_int using our private server key and private host key |
1262 | * (key with larger modulus first). | 1454 | * (key with larger modulus first). |
1263 | */ | 1455 | */ |
1264 | static int | 1456 | int |
1265 | ssh1_session_key(BIGNUM *session_key_int) | 1457 | ssh1_session_key(BIGNUM *session_key_int) |
1266 | { | 1458 | { |
1267 | int rsafail = 0; | 1459 | int rsafail = 0; |
@@ -1417,7 +1609,8 @@ do_ssh1_kex(void) | |||
1417 | packet_check_eom(); | 1609 | packet_check_eom(); |
1418 | 1610 | ||
1419 | /* Decrypt session_key_int using host/server keys */ | 1611 | /* Decrypt session_key_int using host/server keys */ |
1420 | rsafail = ssh1_session_key(session_key_int); | 1612 | rsafail = PRIVSEP(ssh1_session_key(session_key_int)); |
1613 | |||
1421 | /* | 1614 | /* |
1422 | * Extract session key from the decrypted integer. The key is in the | 1615 | * Extract session key from the decrypted integer. The key is in the |
1423 | * least significant 256 bits of the integer; the first byte of the | 1616 | * least significant 256 bits of the integer; the first byte of the |
@@ -1468,9 +1661,12 @@ do_ssh1_kex(void) | |||
1468 | for (i = 0; i < 16; i++) | 1661 | for (i = 0; i < 16; i++) |
1469 | session_id[i] = session_key[i] ^ session_key[i + 16]; | 1662 | session_id[i] = session_key[i] ^ session_key[i + 16]; |
1470 | } | 1663 | } |
1471 | /* Destroy the private and public keys. They will no longer be needed. */ | 1664 | /* Destroy the private and public keys. No longer. */ |
1472 | destroy_sensitive_data(); | 1665 | destroy_sensitive_data(); |
1473 | 1666 | ||
1667 | if (use_privsep) | ||
1668 | mm_ssh1_session_id(session_id); | ||
1669 | |||
1474 | /* Destroy the decrypted integer. It is no longer needed. */ | 1670 | /* Destroy the decrypted integer. It is no longer needed. */ |
1475 | BN_clear_free(session_key_int); | 1671 | BN_clear_free(session_key_int); |
1476 | 1672 | ||
@@ -1517,6 +1713,7 @@ do_ssh2_kex(void) | |||
1517 | kex->client_version_string=client_version_string; | 1713 | kex->client_version_string=client_version_string; |
1518 | kex->server_version_string=server_version_string; | 1714 | kex->server_version_string=server_version_string; |
1519 | kex->load_host_key=&get_hostkey_by_type; | 1715 | kex->load_host_key=&get_hostkey_by_type; |
1716 | kex->host_key_index=&get_hostkey_index; | ||
1520 | 1717 | ||
1521 | xxx_kex = kex; | 1718 | xxx_kex = kex; |
1522 | 1719 | ||