1 | /* |
---|
2 | |
---|
3 | sshconnect.c |
---|
4 | |
---|
5 | Author: Tatu Ylonen <ylo@cs.hut.fi> |
---|
6 | |
---|
7 | Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
---|
8 | All rights reserved |
---|
9 | |
---|
10 | Created: Sat Mar 18 22:15:47 1995 ylo |
---|
11 | |
---|
12 | Code to connect to a remote host, and to perform the client side of the |
---|
13 | login (authentication) dialog. |
---|
14 | |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | * $Id: sshconnect.c,v 1.3 1999-03-08 18:20:09 danw Exp $ |
---|
19 | * $Log: not supported by cvs2svn $ |
---|
20 | * Revision 1.2 1998/11/09 16:25:24 ghudson |
---|
21 | * Close some possible buffer overflows. |
---|
22 | * |
---|
23 | * Revision 1.1.1.3 1998/05/13 19:11:27 danw |
---|
24 | * Import of ssh 1.2.23 |
---|
25 | * |
---|
26 | * Revision 1.1.1.4 1999/03/08 17:43:24 danw |
---|
27 | * Import of ssh 1.2.26 |
---|
28 | * |
---|
29 | * Revision 1.30 1998/07/08 14:55:18 tri |
---|
30 | * Fixed version negotiation so, that ssh 2 |
---|
31 | * compatibility is even remotedly possible. |
---|
32 | * |
---|
33 | * Revision 1.29 1998/07/08 00:47:33 kivinen |
---|
34 | * Moved some debug messages around. |
---|
35 | * |
---|
36 | * Revision 1.28 1998/06/11 00:10:50 kivinen |
---|
37 | * Added ENABLE_SO_LINGER ifdef. |
---|
38 | * |
---|
39 | * Revision 1.27 1998/05/23 20:25:58 kivinen |
---|
40 | * Changed () -> (void). |
---|
41 | * |
---|
42 | * Revision 1.26 1998/04/30 01:56:01 kivinen |
---|
43 | * Added PasswordPromptLogin and PasswordPromptHost option code. |
---|
44 | * Added check that proxy command isn't empty. |
---|
45 | * |
---|
46 | * Revision 1.25 1998/03/27 17:04:04 kivinen |
---|
47 | * Changed socks support to support socks.h. Added |
---|
48 | * ENABLE_TCP_NODELAY support. Fixed kerberos initialization code |
---|
49 | * so ssh will check the error codes of initialization function. |
---|
50 | * |
---|
51 | * Revision 1.24 1998/01/02 06:23:28 kivinen |
---|
52 | * Changed "foo's password" prompt to "foo@bar's password". |
---|
53 | * |
---|
54 | * Revision 1.23 1997/04/27 21:55:51 kivinen |
---|
55 | * Added F-SECURE stuff. |
---|
56 | * |
---|
57 | * Revision 1.22 1997/04/23 00:05:01 kivinen |
---|
58 | * Implemented NumberOfPasswordPrompts option. |
---|
59 | * |
---|
60 | * Revision 1.21 1997/04/17 04:16:32 kivinen |
---|
61 | * Added strict_host_key_checking == 2 (== ask) support. |
---|
62 | * Moved asking of confirmation from user to read_confirmation |
---|
63 | * function. |
---|
64 | * Added checks that if in batch_mode do not ask confirmations. |
---|
65 | * |
---|
66 | * Revision 1.20 1997/04/05 22:02:04 kivinen |
---|
67 | * Removed restriction that ssh only used priviledged port if |
---|
68 | * server port was < 1024. Fixed KRB5 support. |
---|
69 | * |
---|
70 | * Revision 1.19 1997/03/27 03:11:35 kivinen |
---|
71 | * Added kerberos patches from Glenn Machin. |
---|
72 | * |
---|
73 | * Revision 1.18 1997/03/26 07:11:08 kivinen |
---|
74 | * Added local localhost mapping. |
---|
75 | * Fixed some messages. |
---|
76 | * Allow password authentication even when host key have |
---|
77 | * changed, because we ask about it from user. |
---|
78 | * |
---|
79 | * Revision 1.17 1997/03/26 05:35:30 kivinen |
---|
80 | * Changed uid 0 to UID_ROOT. |
---|
81 | * |
---|
82 | * Revision 1.16 1997/03/25 05:47:15 kivinen |
---|
83 | * Added Rgethostbyname for SOCKS5. |
---|
84 | * |
---|
85 | * Revision 1.15 1997/03/19 21:16:22 kivinen |
---|
86 | * Added local mapping of "localhost" to "127.0.0.1" to avoid dns |
---|
87 | * attacks for localhost (the host key checking is disabled for |
---|
88 | * localhost). |
---|
89 | * Added yes/no prompt if host key is not known or changed. |
---|
90 | * Disabled x11 and port forwardings if host key have changed. |
---|
91 | * |
---|
92 | * Revision 1.14 1997/03/19 17:45:36 kivinen |
---|
93 | * Added SECURE_RPC, SECURE_NFS and NIS_PLUS support from Andy |
---|
94 | * Polyakov <appro@fy.chalmers.se>. |
---|
95 | * Disabled agent forwarding if host key doesn't match. |
---|
96 | * Added TIS authentication code from Andre April |
---|
97 | * <Andre.April@cediti.be>. |
---|
98 | * |
---|
99 | * Revision 1.13 1996/12/04 18:15:08 ttsalo |
---|
100 | * Added calls to ssh_close_authentication_connection |
---|
101 | * |
---|
102 | * Revision 1.12 1996/11/12 18:44:41 kivinen |
---|
103 | * Changed password back to foos's password, as I was informed |
---|
104 | * that Webster was in illiterate and the previous version was |
---|
105 | * correct when using English grammar. |
---|
106 | * |
---|
107 | * Revision 1.11 1996/11/07 06:48:12 kivinen |
---|
108 | * Fixed foos's password: prompt to foos' password:. |
---|
109 | * |
---|
110 | * Revision 1.10 1996/11/04 16:19:29 ttsalo |
---|
111 | * Improved error handling in code receiving protocol version byte |
---|
112 | * |
---|
113 | * Revision 1.9 1996/11/04 14:37:16 ttsalo |
---|
114 | * Fixed someone's typo (...VERSION_MAJOR... -> ...MAJOR_VERSION...) |
---|
115 | * |
---|
116 | * Revision 1.8 1996/11/04 06:34:24 ylo |
---|
117 | * Updated processing of check_emulation output. |
---|
118 | * |
---|
119 | * Revision 1.7 1996/10/29 22:47:16 kivinen |
---|
120 | * log -> log_msg. |
---|
121 | * Added username to password prompt. |
---|
122 | * |
---|
123 | * Revision 1.6 1996/05/25 23:33:12 ylo |
---|
124 | * Fixed a minor bug in the logic used to determine whether to allocate |
---|
125 | * a privileged local port. |
---|
126 | * |
---|
127 | * Revision 1.5 1996/04/26 00:24:10 ylo |
---|
128 | * Fixed SOCKS code. |
---|
129 | * Fixed reconnecting with SOCKS. |
---|
130 | * |
---|
131 | * Revision 1.4 1996/04/22 23:49:46 huima |
---|
132 | * Changed protocol version to 1.4, added calls to emulate module. |
---|
133 | * |
---|
134 | * Revision 1.3 1996/02/19 16:07:23 huima |
---|
135 | * Minor fixes. |
---|
136 | * |
---|
137 | * Revision 1.2 1996/02/18 21:50:23 ylo |
---|
138 | * Added a call to userfile_close_pipes in proxy code. |
---|
139 | * |
---|
140 | * Revision 1.1.1.1 1996/02/18 21:38:12 ylo |
---|
141 | * Imported ssh-1.2.13. |
---|
142 | * |
---|
143 | * Revision 1.15 1995/09/27 02:16:40 ylo |
---|
144 | * Eliminated compiler warning. |
---|
145 | * |
---|
146 | * Revision 1.14 1995/09/25 00:02:55 ylo |
---|
147 | * Added connection_attempts. |
---|
148 | * Added screen number forwarding. |
---|
149 | * |
---|
150 | * Revision 1.13 1995/09/22 22:23:23 ylo |
---|
151 | * Changed interface of ssh_login to use the option structure |
---|
152 | * instead of numerous individual arguments. |
---|
153 | * |
---|
154 | * Revision 1.12 1995/09/21 17:17:44 ylo |
---|
155 | * Added original_real_uid argument to ssh_connect. |
---|
156 | * |
---|
157 | * Revision 1.11 1995/09/13 12:03:55 ylo |
---|
158 | * Added debugging output to print uids. |
---|
159 | * |
---|
160 | * Revision 1.10 1995/09/10 22:48:29 ylo |
---|
161 | * Added original_real_uid parameter to ssh_login. Changed to |
---|
162 | * use it. |
---|
163 | * Fixed read_passphrase arguments. |
---|
164 | * |
---|
165 | * Revision 1.9 1995/09/09 21:26:46 ylo |
---|
166 | * /m/shadows/u2/users/ylo/ssh/README |
---|
167 | * |
---|
168 | * Revision 1.8 1995/09/06 16:01:12 ylo |
---|
169 | * Added BROKEN_INET_ADDR. |
---|
170 | * |
---|
171 | * Revision 1.7 1995/08/31 09:24:23 ylo |
---|
172 | * Fixed user_hostfile name processing. |
---|
173 | * |
---|
174 | * Revision 1.6 1995/08/21 23:29:32 ylo |
---|
175 | * Clear sockaddr_in before using. |
---|
176 | * Pass session_id and response_type to ssh_decrypt_challenge. |
---|
177 | * |
---|
178 | * Revision 1.5 1995/07/27 02:18:13 ylo |
---|
179 | * Tell packet_set_encryption_key that we are the client. |
---|
180 | * |
---|
181 | * Revision 1.4 1995/07/27 00:40:56 ylo |
---|
182 | * Added GlobalKnownHostsFile and UserKnownHostsFile. |
---|
183 | * |
---|
184 | * Revision 1.3 1995/07/26 23:19:20 ylo |
---|
185 | * Removed include version.h. |
---|
186 | * |
---|
187 | * Added code for protocol version 1.1. This involves changes in |
---|
188 | * the session key exchange code and RSA responses to make |
---|
189 | * replay impossible and to bind RSA responses to a particular |
---|
190 | * session so that a corrupt server cannot pass them on to |
---|
191 | * another connection. Moved rsa response code to a separate function. |
---|
192 | * |
---|
193 | * Fixed session key exchange to match the RFC draft. |
---|
194 | * |
---|
195 | * Prints a warning if server uses older protocol version (but |
---|
196 | * compatibility code still supports the older version). |
---|
197 | * |
---|
198 | * Revision 1.2 1995/07/13 01:40:32 ylo |
---|
199 | * Removed "Last modified" header. |
---|
200 | * Added cvs log. |
---|
201 | * |
---|
202 | * $Endlog$ |
---|
203 | */ |
---|
204 | |
---|
205 | #include "includes.h" |
---|
206 | #include <gmp.h> |
---|
207 | #include "xmalloc.h" |
---|
208 | #include "randoms.h" |
---|
209 | #include "rsa.h" |
---|
210 | #include "ssh.h" |
---|
211 | #include "packet.h" |
---|
212 | #include "authfd.h" |
---|
213 | #include "cipher.h" |
---|
214 | #include "md5.h" |
---|
215 | #include "mpaux.h" |
---|
216 | #include "userfile.h" |
---|
217 | #include "emulate.h" |
---|
218 | |
---|
219 | #ifdef KERBEROS |
---|
220 | #ifdef KRB5 |
---|
221 | #include <krb5.h> |
---|
222 | |
---|
223 | /* Global the contexts */ |
---|
224 | krb5_context ssh_context = 0; |
---|
225 | krb5_auth_context auth_context = 0; |
---|
226 | #endif /* KRB5 */ |
---|
227 | #endif /* KERBEROS */ |
---|
228 | |
---|
229 | /* Session id for the current session. */ |
---|
230 | unsigned char session_id[16]; |
---|
231 | |
---|
232 | /* Connect to the given ssh server using a proxy command. */ |
---|
233 | |
---|
234 | int ssh_proxy_connect(const char *host, int port, uid_t original_real_uid, |
---|
235 | const char *proxy_command, RandomState *random_state) |
---|
236 | { |
---|
237 | Buffer command; |
---|
238 | const char *cp; |
---|
239 | char *command_string; |
---|
240 | int pin[2], pout[2]; |
---|
241 | int pid; |
---|
242 | char portstring[100]; |
---|
243 | |
---|
244 | /* Convert the port number into a string. */ |
---|
245 | sprintf(portstring, "%d", port); |
---|
246 | |
---|
247 | /* Build the final command string in the buffer by making the appropriate |
---|
248 | substitutions to the given proxy command. */ |
---|
249 | buffer_init(&command); |
---|
250 | for (cp = proxy_command; *cp; cp++) |
---|
251 | { |
---|
252 | if (cp[0] == '%' && cp[1] == '%') |
---|
253 | { |
---|
254 | buffer_append(&command, "%", 1); |
---|
255 | cp++; |
---|
256 | continue; |
---|
257 | } |
---|
258 | if (cp[0] == '%' && cp[1] == 'h') |
---|
259 | { |
---|
260 | buffer_append(&command, host, strlen(host)); |
---|
261 | cp++; |
---|
262 | continue; |
---|
263 | } |
---|
264 | if (cp[0] == '%' && cp[1] == 'p') |
---|
265 | { |
---|
266 | buffer_append(&command, portstring, strlen(portstring)); |
---|
267 | cp++; |
---|
268 | continue; |
---|
269 | } |
---|
270 | buffer_append(&command, cp, 1); |
---|
271 | } |
---|
272 | buffer_append(&command, "\0", 1); |
---|
273 | |
---|
274 | /* Get the final command string. */ |
---|
275 | command_string = buffer_ptr(&command); |
---|
276 | |
---|
277 | /* Create pipes for communicating with the proxy. */ |
---|
278 | if (pipe(pin) < 0 || pipe(pout) < 0) |
---|
279 | fatal("Could not create pipes to communicate with the proxy: %.100s", |
---|
280 | strerror(errno)); |
---|
281 | |
---|
282 | debug("Executing proxy command: %.500s", command_string); |
---|
283 | |
---|
284 | /* Fork and execute the proxy command. */ |
---|
285 | if ((pid = fork()) == 0) |
---|
286 | { |
---|
287 | char *argv[10]; |
---|
288 | |
---|
289 | /* Close all pipes to userfile. */ |
---|
290 | userfile_close_pipes(); |
---|
291 | |
---|
292 | /* Child. Permanently give up superuser privileges. */ |
---|
293 | if (setuid(getuid()) < 0) |
---|
294 | fatal("setuid: %.100s", strerror(errno)); |
---|
295 | |
---|
296 | /* Redirect stdin and stdout. */ |
---|
297 | close(pin[1]); |
---|
298 | if (pin[0] != 0) |
---|
299 | { |
---|
300 | if (dup2(pin[0], 0) < 0) |
---|
301 | perror("dup2 stdin"); |
---|
302 | close(pin[0]); |
---|
303 | } |
---|
304 | close(pout[0]); |
---|
305 | if (dup2(pout[1], 1) < 0) |
---|
306 | perror("dup2 stdout"); |
---|
307 | close(pout[1]); /* Cannot be 1 because pin allocated two descriptors. */ |
---|
308 | |
---|
309 | /* Stderr is left as it is so that error messages get printed on |
---|
310 | the user's terminal. */ |
---|
311 | argv[0] = "/bin/sh"; |
---|
312 | argv[1] = "-c"; |
---|
313 | argv[2] = command_string; |
---|
314 | argv[3] = NULL; |
---|
315 | |
---|
316 | /* Execute the proxy command. Note that we gave up any extra |
---|
317 | privileges above. */ |
---|
318 | execv("/bin/sh", argv); |
---|
319 | perror("/bin/sh"); |
---|
320 | exit(1); |
---|
321 | } |
---|
322 | /* Parent. */ |
---|
323 | if (pid < 0) |
---|
324 | fatal("fork failed: %.100s", strerror(errno)); |
---|
325 | |
---|
326 | /* Close child side of the descriptors. */ |
---|
327 | close(pin[0]); |
---|
328 | close(pout[1]); |
---|
329 | |
---|
330 | /* Free the command name. */ |
---|
331 | buffer_free(&command); |
---|
332 | |
---|
333 | /* Set the connection file descriptors. */ |
---|
334 | packet_set_connection(pout[0], pin[1], random_state); |
---|
335 | |
---|
336 | return 1; |
---|
337 | } |
---|
338 | |
---|
339 | /* Creates a (possibly privileged) socket for use as the ssh connection. */ |
---|
340 | |
---|
341 | int ssh_create_socket(uid_t original_real_uid, int privileged) |
---|
342 | { |
---|
343 | int sock; |
---|
344 | |
---|
345 | /* If we are running as root and want to connect to a privileged port, |
---|
346 | bind our own socket to a privileged port. */ |
---|
347 | if (privileged) |
---|
348 | { |
---|
349 | struct sockaddr_in sin; |
---|
350 | int p; |
---|
351 | for (p = 1023; p > 512; p--) |
---|
352 | { |
---|
353 | sock = socket(AF_INET, SOCK_STREAM, 0); |
---|
354 | if (sock < 0) |
---|
355 | fatal("socket: %.100s", strerror(errno)); |
---|
356 | |
---|
357 | /* Initialize the desired sockaddr_in structure. */ |
---|
358 | memset(&sin, 0, sizeof(sin)); |
---|
359 | sin.sin_family = AF_INET; |
---|
360 | sin.sin_addr.s_addr = INADDR_ANY; |
---|
361 | sin.sin_port = htons(p); |
---|
362 | |
---|
363 | /* Try to bind the socket to the privileged port. */ |
---|
364 | #if defined(SOCKS) && !defined(HAVE_SOCKS_H) |
---|
365 | if (Rbind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) |
---|
366 | break; /* Success. */ |
---|
367 | #else /* SOCKS */ |
---|
368 | if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) |
---|
369 | break; /* Success. */ |
---|
370 | #endif /* SOCKS */ |
---|
371 | if (errno == EADDRINUSE) |
---|
372 | { |
---|
373 | close(sock); |
---|
374 | continue; |
---|
375 | } |
---|
376 | fatal("bind: %.100s", strerror(errno)); |
---|
377 | } |
---|
378 | debug("Allocated local port %d.", p); |
---|
379 | } |
---|
380 | else |
---|
381 | { |
---|
382 | /* Just create an ordinary socket on arbitrary port. */ |
---|
383 | sock = socket(AF_INET, SOCK_STREAM, 0); |
---|
384 | if (sock < 0) |
---|
385 | fatal("socket: %.100s", strerror(errno)); |
---|
386 | } |
---|
387 | return sock; |
---|
388 | } |
---|
389 | |
---|
390 | /* Opens a TCP/IP connection to the remote server on the given host. If |
---|
391 | port is 0, the default port will be used. If anonymous is zero, |
---|
392 | a privileged port will be allocated to make the connection. |
---|
393 | This requires super-user privileges if anonymous is false. |
---|
394 | Connection_attempts specifies the maximum number of tries (one per |
---|
395 | second). If proxy_command is non-NULL, it specifies the command (with %h |
---|
396 | and %p substituted for host and port, respectively) to use to contact |
---|
397 | the daemon. */ |
---|
398 | |
---|
399 | int ssh_connect(const char *host, int port, int connection_attempts, |
---|
400 | int anonymous, uid_t original_real_uid, |
---|
401 | const char *proxy_command, RandomState *random_state) |
---|
402 | { |
---|
403 | int sock = -1, attempt, i; |
---|
404 | int on = 1; |
---|
405 | struct servent *sp; |
---|
406 | struct hostent *hp; |
---|
407 | struct sockaddr_in hostaddr; |
---|
408 | #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER) |
---|
409 | struct linger linger; |
---|
410 | #endif /* SO_LINGER */ |
---|
411 | |
---|
412 | debug("ssh_connect: getuid %d geteuid %d anon %d", |
---|
413 | (int)getuid(), (int)geteuid(), anonymous); |
---|
414 | |
---|
415 | /* Get default port if port has not been set. */ |
---|
416 | if (port == 0) |
---|
417 | { |
---|
418 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); |
---|
419 | if (sp) |
---|
420 | port = ntohs(sp->s_port); |
---|
421 | else |
---|
422 | port = SSH_DEFAULT_PORT; |
---|
423 | } |
---|
424 | |
---|
425 | /* Map localhost to ip-address locally */ |
---|
426 | if (strcmp(host, "localhost") == 0) |
---|
427 | host = "127.0.0.1"; |
---|
428 | |
---|
429 | /* If a proxy command is given, connect using it. */ |
---|
430 | if (proxy_command != NULL && *proxy_command) |
---|
431 | return ssh_proxy_connect(host, port, original_real_uid, proxy_command, |
---|
432 | random_state); |
---|
433 | |
---|
434 | /* No proxy command. */ |
---|
435 | |
---|
436 | /* No host lookup made yet. */ |
---|
437 | hp = NULL; |
---|
438 | |
---|
439 | /* Try to connect several times. On some machines, the first time will |
---|
440 | sometimes fail. In general socket code appears to behave quite |
---|
441 | magically on many machines. */ |
---|
442 | for (attempt = 0; attempt < connection_attempts; attempt++) |
---|
443 | { |
---|
444 | if (attempt > 0) |
---|
445 | debug("Trying again..."); |
---|
446 | |
---|
447 | /* Try to parse the host name as a numeric inet address. */ |
---|
448 | memset(&hostaddr, 0, sizeof(hostaddr)); |
---|
449 | hostaddr.sin_family = AF_INET; |
---|
450 | hostaddr.sin_port = htons(port); |
---|
451 | #ifdef BROKEN_INET_ADDR |
---|
452 | hostaddr.sin_addr.s_addr = inet_network(host); |
---|
453 | #else /* BROKEN_INET_ADDR */ |
---|
454 | hostaddr.sin_addr.s_addr = inet_addr(host); |
---|
455 | #endif /* BROKEN_INET_ADDR */ |
---|
456 | if ((hostaddr.sin_addr.s_addr & 0xffffffff) != 0xffffffff) |
---|
457 | { |
---|
458 | /* Create a socket. */ |
---|
459 | sock = ssh_create_socket(original_real_uid, |
---|
460 | !anonymous && geteuid() == UID_ROOT); |
---|
461 | |
---|
462 | /* Valid numeric IP address */ |
---|
463 | debug("Connecting to %.100s port %d.", |
---|
464 | inet_ntoa(hostaddr.sin_addr), port); |
---|
465 | |
---|
466 | /* Connect to the host. */ |
---|
467 | #if defined(SOCKS) && !defined(HAVE_SOCKS_H) |
---|
468 | if (Rconnect(sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) |
---|
469 | #else /* SOCKS */ |
---|
470 | if (connect(sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) |
---|
471 | #endif /* SOCKS */ |
---|
472 | >= 0) |
---|
473 | { |
---|
474 | /* Successful connect. */ |
---|
475 | break; |
---|
476 | } |
---|
477 | debug("connect: %.100s", strerror(errno)); |
---|
478 | |
---|
479 | /* Destroy the failed socket. */ |
---|
480 | shutdown(sock, 2); |
---|
481 | close(sock); |
---|
482 | } |
---|
483 | else |
---|
484 | { |
---|
485 | /* Not a valid numeric inet address. */ |
---|
486 | /* Map host name to an address. */ |
---|
487 | if (!hp) |
---|
488 | { |
---|
489 | struct hostent *hp_static; |
---|
490 | |
---|
491 | #if defined(SOCKS5) && !defined(HAVE_SOCKS_H) |
---|
492 | hp_static = Rgethostbyname(host); |
---|
493 | #else |
---|
494 | hp_static = gethostbyname(host); |
---|
495 | #endif |
---|
496 | if (hp_static) |
---|
497 | { |
---|
498 | hp = xmalloc(sizeof(struct hostent)); |
---|
499 | memcpy(hp, hp_static, sizeof(struct hostent)); |
---|
500 | |
---|
501 | /* Copy list of addresses, not just pointers. |
---|
502 | We don't use h_name & h_aliases so leave them as is */ |
---|
503 | for (i = 0; hp_static->h_addr_list[i]; i++) |
---|
504 | ; /* count them */ |
---|
505 | hp->h_addr_list = xmalloc((i + 1) * |
---|
506 | sizeof(hp_static->h_addr_list[0])); |
---|
507 | for (i = 0; hp_static->h_addr_list[i]; i++) |
---|
508 | { |
---|
509 | hp->h_addr_list[i] = xmalloc(hp->h_length); |
---|
510 | memcpy(hp->h_addr_list[i], hp_static->h_addr_list[i], |
---|
511 | hp->h_length); |
---|
512 | } |
---|
513 | hp->h_addr_list[i] = NULL; /* last one */ |
---|
514 | } |
---|
515 | } |
---|
516 | if (!hp) |
---|
517 | fatal("Bad host name: %.100s", host); |
---|
518 | if (!hp->h_addr_list[0]) |
---|
519 | fatal("Host does not have an IP address: %.100s", host); |
---|
520 | |
---|
521 | /* Loop through addresses for this host, and try each one in |
---|
522 | sequence until the connection succeeds. */ |
---|
523 | for (i = 0; hp->h_addr_list[i]; i++) |
---|
524 | { |
---|
525 | /* Set the address to connect to. */ |
---|
526 | hostaddr.sin_family = hp->h_addrtype; |
---|
527 | memcpy(&hostaddr.sin_addr, hp->h_addr_list[i], |
---|
528 | sizeof(hostaddr.sin_addr)); |
---|
529 | |
---|
530 | debug("Connecting to %.200s [%.100s] port %d.", |
---|
531 | host, inet_ntoa(hostaddr.sin_addr), port); |
---|
532 | |
---|
533 | /* Create a socket for connecting. */ |
---|
534 | sock = ssh_create_socket(original_real_uid, |
---|
535 | !anonymous && geteuid() == UID_ROOT); |
---|
536 | |
---|
537 | /* Connect to the host. */ |
---|
538 | #if defined(SOCKS) && !defined(HAVE_SOCKS_H) |
---|
539 | if (Rconnect(sock, (struct sockaddr *)&hostaddr, |
---|
540 | sizeof(hostaddr)) >= 0) |
---|
541 | #else /* SOCKS */ |
---|
542 | if (connect(sock, (struct sockaddr *)&hostaddr, |
---|
543 | sizeof(hostaddr)) >= 0) |
---|
544 | #endif /* SOCKS */ |
---|
545 | { |
---|
546 | /* Successful connection. */ |
---|
547 | break; |
---|
548 | } |
---|
549 | debug("connect: %.100s", strerror(errno)); |
---|
550 | |
---|
551 | /* Close the failed socket; there appear to be some problems |
---|
552 | when reusing a socket for which connect() has already |
---|
553 | returned an error. */ |
---|
554 | shutdown(sock, 2); |
---|
555 | close(sock); |
---|
556 | } |
---|
557 | if (hp->h_addr_list[i]) |
---|
558 | break; /* Successful connection. */ |
---|
559 | } |
---|
560 | |
---|
561 | /* Sleep a moment before retrying. */ |
---|
562 | sleep(1); |
---|
563 | } |
---|
564 | |
---|
565 | if (hp) |
---|
566 | { |
---|
567 | for (i = 0; hp->h_addr_list[i]; i++) |
---|
568 | xfree(hp->h_addr_list[i]); |
---|
569 | xfree(hp->h_addr_list); |
---|
570 | xfree(hp); |
---|
571 | } |
---|
572 | |
---|
573 | /* Return failure if we didn't get a successful connection. */ |
---|
574 | if (attempt >= connection_attempts) |
---|
575 | return 0; |
---|
576 | |
---|
577 | debug("Connection established."); |
---|
578 | |
---|
579 | /* Set socket options. We would like the socket to disappear as soon as |
---|
580 | it has been closed for whatever reason. */ |
---|
581 | /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ |
---|
582 | #if defined(TCP_NODELAY) && defined(ENABLE_TCP_NODELAY) |
---|
583 | setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)); |
---|
584 | #endif /* TCP_NODELAY */ |
---|
585 | #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER) |
---|
586 | linger.l_onoff = 1; |
---|
587 | linger.l_linger = 15; |
---|
588 | setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); |
---|
589 | #endif /* SO_LINGER */ |
---|
590 | |
---|
591 | /* Set the connection. */ |
---|
592 | packet_set_connection(sock, sock, random_state); |
---|
593 | |
---|
594 | return 1; |
---|
595 | } |
---|
596 | |
---|
597 | /* Checks if the user has an authentication agent, and if so, tries to |
---|
598 | authenticate using the agent. */ |
---|
599 | |
---|
600 | int try_agent_authentication(void) |
---|
601 | { |
---|
602 | int status, type, bits; |
---|
603 | MP_INT e, n, challenge; |
---|
604 | char *comment; |
---|
605 | AuthenticationConnection *auth; |
---|
606 | unsigned char response[16]; |
---|
607 | unsigned int i; |
---|
608 | |
---|
609 | /* Get connection to the agent. */ |
---|
610 | auth = ssh_get_authentication_connection(); |
---|
611 | if (!auth) |
---|
612 | return 0; |
---|
613 | |
---|
614 | mpz_init(&e); |
---|
615 | mpz_init(&n); |
---|
616 | mpz_init(&challenge); |
---|
617 | |
---|
618 | /* Loop through identities served by the agent. */ |
---|
619 | for (status = ssh_get_first_identity(auth, &bits, &e, &n, &comment); |
---|
620 | status; |
---|
621 | status = ssh_get_next_identity(auth, &bits, &e, &n, &comment)) |
---|
622 | { |
---|
623 | /* Try this identity. */ |
---|
624 | debug("Trying RSA authentication via agent with '%.100s'", comment); |
---|
625 | xfree(comment); |
---|
626 | |
---|
627 | /* Tell the server that we are willing to authenticate using this key. */ |
---|
628 | packet_start(SSH_CMSG_AUTH_RSA); |
---|
629 | packet_put_mp_int(&n); |
---|
630 | packet_send(); |
---|
631 | packet_write_wait(); |
---|
632 | |
---|
633 | /* Wait for server's response. */ |
---|
634 | type = packet_read(); |
---|
635 | |
---|
636 | /* The server sends failure if it doesn\'t like our key or does not |
---|
637 | support RSA authentication. */ |
---|
638 | if (type == SSH_SMSG_FAILURE) |
---|
639 | { |
---|
640 | debug("Server refused our key."); |
---|
641 | continue; |
---|
642 | } |
---|
643 | |
---|
644 | /* Otherwise it should have sent a challenge. */ |
---|
645 | if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) |
---|
646 | packet_disconnect("Protocol error during RSA authentication: %d", |
---|
647 | type); |
---|
648 | |
---|
649 | packet_get_mp_int(&challenge); |
---|
650 | |
---|
651 | debug("Received RSA challenge from server."); |
---|
652 | |
---|
653 | /* Ask the agent to decrypt the challenge. */ |
---|
654 | if (!ssh_decrypt_challenge(auth, bits, &e, &n, &challenge, |
---|
655 | session_id, 1, response)) |
---|
656 | { |
---|
657 | /* The agent failed to authenticate this identifier although it |
---|
658 | advertised it supports this. Just return a wrong value. */ |
---|
659 | log_msg("Authentication agent failed to decrypt challenge."); |
---|
660 | memset(response, 0, sizeof(response)); |
---|
661 | } |
---|
662 | |
---|
663 | debug("Sending response to RSA challenge."); |
---|
664 | |
---|
665 | /* Send the decrypted challenge back to the server. */ |
---|
666 | packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); |
---|
667 | for (i = 0; i < 16; i++) |
---|
668 | packet_put_char(response[i]); |
---|
669 | packet_send(); |
---|
670 | packet_write_wait(); |
---|
671 | |
---|
672 | /* Wait for response from the server. */ |
---|
673 | type = packet_read(); |
---|
674 | |
---|
675 | /* The server returns success if it accepted the authentication. */ |
---|
676 | if (type == SSH_SMSG_SUCCESS) |
---|
677 | { |
---|
678 | debug("RSA authentication accepted by server."); |
---|
679 | mpz_clear(&e); |
---|
680 | mpz_clear(&n); |
---|
681 | mpz_clear(&challenge); |
---|
682 | ssh_close_authentication_connection(auth); |
---|
683 | return 1; |
---|
684 | } |
---|
685 | |
---|
686 | /* Otherwise it should return failure. */ |
---|
687 | if (type != SSH_SMSG_FAILURE) |
---|
688 | { |
---|
689 | ssh_close_authentication_connection(auth); |
---|
690 | packet_disconnect("Protocol error waiting RSA auth response: %d", |
---|
691 | type); |
---|
692 | } |
---|
693 | } |
---|
694 | |
---|
695 | mpz_clear(&e); |
---|
696 | mpz_clear(&n); |
---|
697 | mpz_clear(&challenge); |
---|
698 | |
---|
699 | ssh_close_authentication_connection(auth); |
---|
700 | |
---|
701 | debug("RSA authentication using agent refused."); |
---|
702 | return 0; |
---|
703 | } |
---|
704 | |
---|
705 | /* Computes the proper response to a RSA challenge, and sends the response to |
---|
706 | the server. */ |
---|
707 | |
---|
708 | void respond_to_rsa_challenge(MP_INT *challenge, RSAPrivateKey *prv) |
---|
709 | { |
---|
710 | unsigned char buf[32], response[16]; |
---|
711 | struct MD5Context md; |
---|
712 | int i; |
---|
713 | |
---|
714 | /* Decrypt the challenge using the private key. */ |
---|
715 | rsa_private_decrypt(challenge, challenge, prv); |
---|
716 | |
---|
717 | /* Compute the response. */ |
---|
718 | /* The response is MD5 of decrypted challenge plus session id. */ |
---|
719 | mp_linearize_msb_first(buf, 32, challenge); |
---|
720 | MD5Init(&md); |
---|
721 | MD5Update(&md, buf, 32); |
---|
722 | MD5Update(&md, session_id, 16); |
---|
723 | MD5Final(response, &md); |
---|
724 | |
---|
725 | debug("Sending response to host key RSA challenge."); |
---|
726 | |
---|
727 | /* Send the response back to the server. */ |
---|
728 | packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); |
---|
729 | for (i = 0; i < 16; i++) |
---|
730 | packet_put_char(response[i]); |
---|
731 | packet_send(); |
---|
732 | packet_write_wait(); |
---|
733 | |
---|
734 | memset(buf, 0, sizeof(buf)); |
---|
735 | memset(response, 0, sizeof(response)); |
---|
736 | memset(&md, 0, sizeof(md)); |
---|
737 | } |
---|
738 | |
---|
739 | /* Checks if the user has authentication file, and if so, tries to authenticate |
---|
740 | the user using it. */ |
---|
741 | |
---|
742 | int try_rsa_authentication(struct passwd *pw, const char *authfile, |
---|
743 | int may_ask_passphrase) |
---|
744 | { |
---|
745 | MP_INT challenge; |
---|
746 | RSAPrivateKey private_key; |
---|
747 | RSAPublicKey public_key; |
---|
748 | char *passphrase, *comment; |
---|
749 | int type, i; |
---|
750 | int done; |
---|
751 | |
---|
752 | /* Try to load identification for the authentication key. */ |
---|
753 | if (!load_public_key(pw->pw_uid, authfile, &public_key, &comment)) |
---|
754 | return 0; /* Could not load it. Fail. */ |
---|
755 | |
---|
756 | debug("Trying RSA authentication with key '%.100s'", comment); |
---|
757 | |
---|
758 | /* Tell the server that we are willing to authenticate using this key. */ |
---|
759 | packet_start(SSH_CMSG_AUTH_RSA); |
---|
760 | packet_put_mp_int(&public_key.n); |
---|
761 | packet_send(); |
---|
762 | packet_write_wait(); |
---|
763 | |
---|
764 | /* We no longer need the public key. */ |
---|
765 | rsa_clear_public_key(&public_key); |
---|
766 | |
---|
767 | /* Wait for server's response. */ |
---|
768 | type = packet_read(); |
---|
769 | |
---|
770 | /* The server responds with failure if it doesn\'t like our key or doesn\'t |
---|
771 | support RSA authentication. */ |
---|
772 | if (type == SSH_SMSG_FAILURE) |
---|
773 | { |
---|
774 | debug("Server refused our key."); |
---|
775 | xfree(comment); |
---|
776 | return 0; /* Server refuses to authenticate with this key. */ |
---|
777 | } |
---|
778 | |
---|
779 | /* Otherwise, the server should respond with a challenge. */ |
---|
780 | if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) |
---|
781 | packet_disconnect("Protocol error during RSA authentication: %d", type); |
---|
782 | |
---|
783 | /* Get the challenge from the packet. */ |
---|
784 | mpz_init(&challenge); |
---|
785 | packet_get_mp_int(&challenge); |
---|
786 | |
---|
787 | debug("Received RSA challenge from server."); |
---|
788 | |
---|
789 | /* Load the private key. Try first with empty passphrase; if it fails, |
---|
790 | ask for a passphrase. */ |
---|
791 | done = load_private_key(pw->pw_uid, authfile, "", &private_key, NULL); |
---|
792 | #ifdef SECURE_RPC |
---|
793 | if (!done) |
---|
794 | { |
---|
795 | passphrase = userfile_get_des_1_magic_phrase(pw->pw_uid); |
---|
796 | if (passphrase != NULL) |
---|
797 | { |
---|
798 | done = load_private_key(pw->pw_uid, authfile, passphrase, |
---|
799 | &private_key, NULL); |
---|
800 | if (done) |
---|
801 | debug("Using SUN-DES-1 magic phrase to decrypt the private key."); |
---|
802 | memset(passphrase, 0, strlen(passphrase)); |
---|
803 | xfree(passphrase); |
---|
804 | } |
---|
805 | } |
---|
806 | #endif |
---|
807 | if (!done) |
---|
808 | { |
---|
809 | char buf[300]; |
---|
810 | /* Request passphrase from the user. We read from /dev/tty to make |
---|
811 | this work even if stdin has been redirected. If running in |
---|
812 | batch mode, we just use the empty passphrase, which will fail and |
---|
813 | return. */ |
---|
814 | sprintf(buf, "Enter passphrase for RSA key '%.100s': ", comment); |
---|
815 | if (may_ask_passphrase) |
---|
816 | passphrase = read_passphrase(pw->pw_uid, buf, 0); |
---|
817 | else |
---|
818 | { |
---|
819 | debug("Will not query passphrase for %.100s in batch mode.", |
---|
820 | comment); |
---|
821 | passphrase = xstrdup(""); |
---|
822 | } |
---|
823 | |
---|
824 | /* Load the authentication file using the pasphrase. */ |
---|
825 | if (!load_private_key(pw->pw_uid, authfile, passphrase, &private_key, |
---|
826 | NULL)) |
---|
827 | { |
---|
828 | memset(passphrase, 0, strlen(passphrase)); |
---|
829 | xfree(passphrase); |
---|
830 | error("Bad passphrase."); |
---|
831 | |
---|
832 | /* Send a dummy response packet to avoid protocol error. */ |
---|
833 | packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); |
---|
834 | for (i = 0; i < 16; i++) |
---|
835 | packet_put_char(0); |
---|
836 | packet_send(); |
---|
837 | packet_write_wait(); |
---|
838 | |
---|
839 | /* Expect the server to reject it... */ |
---|
840 | packet_read_expect(SSH_SMSG_FAILURE); |
---|
841 | xfree(comment); |
---|
842 | return 0; |
---|
843 | } |
---|
844 | |
---|
845 | /* Destroy the passphrase. */ |
---|
846 | memset(passphrase, 0, strlen(passphrase)); |
---|
847 | xfree(passphrase); |
---|
848 | } |
---|
849 | |
---|
850 | /* We no longer need the comment. */ |
---|
851 | xfree(comment); |
---|
852 | |
---|
853 | /* Compute and send a response to the challenge. */ |
---|
854 | respond_to_rsa_challenge(&challenge, &private_key); |
---|
855 | |
---|
856 | /* Destroy the private key. */ |
---|
857 | rsa_clear_private_key(&private_key); |
---|
858 | |
---|
859 | /* We no longer need the challenge. */ |
---|
860 | mpz_clear(&challenge); |
---|
861 | |
---|
862 | /* Wait for response from the server. */ |
---|
863 | type = packet_read(); |
---|
864 | if (type == SSH_SMSG_SUCCESS) |
---|
865 | { |
---|
866 | debug("RSA authentication accepted by server."); |
---|
867 | return 1; |
---|
868 | } |
---|
869 | if (type != SSH_SMSG_FAILURE) |
---|
870 | packet_disconnect("Protocol error waiting RSA auth response: %d", type); |
---|
871 | debug("RSA authentication refused."); |
---|
872 | return 0; |
---|
873 | } |
---|
874 | |
---|
875 | /* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv |
---|
876 | authentication and RSA host authentication. */ |
---|
877 | |
---|
878 | int try_rhosts_rsa_authentication(const char *local_user, |
---|
879 | RSAPrivateKey *host_key) |
---|
880 | { |
---|
881 | int type; |
---|
882 | MP_INT challenge; |
---|
883 | |
---|
884 | debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication."); |
---|
885 | |
---|
886 | /* Tell the server that we are willing to authenticate using this key. */ |
---|
887 | packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); |
---|
888 | packet_put_string(local_user, strlen(local_user)); |
---|
889 | packet_put_int(host_key->bits); |
---|
890 | packet_put_mp_int(&host_key->e); |
---|
891 | packet_put_mp_int(&host_key->n); |
---|
892 | packet_send(); |
---|
893 | packet_write_wait(); |
---|
894 | |
---|
895 | /* Wait for server's response. */ |
---|
896 | type = packet_read(); |
---|
897 | |
---|
898 | /* The server responds with failure if it doesn't admit our .rhosts |
---|
899 | authentication or doesn't know our host key. */ |
---|
900 | if (type == SSH_SMSG_FAILURE) |
---|
901 | { |
---|
902 | debug("Server refused our rhosts authentication or host key."); |
---|
903 | return 0; /* Server refuses to authenticate us with this method. */ |
---|
904 | } |
---|
905 | |
---|
906 | /* Otherwise, the server should respond with a challenge. */ |
---|
907 | if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) |
---|
908 | packet_disconnect("Protocol error during RSA authentication: %d", type); |
---|
909 | |
---|
910 | /* Get the challenge from the packet. */ |
---|
911 | mpz_init(&challenge); |
---|
912 | packet_get_mp_int(&challenge); |
---|
913 | |
---|
914 | debug("Received RSA challenge for host key from server."); |
---|
915 | |
---|
916 | /* Compute a response to the challenge. */ |
---|
917 | respond_to_rsa_challenge(&challenge, host_key); |
---|
918 | |
---|
919 | /* We no longer need the challenge. */ |
---|
920 | mpz_clear(&challenge); |
---|
921 | |
---|
922 | /* Wait for response from the server. */ |
---|
923 | type = packet_read(); |
---|
924 | if (type == SSH_SMSG_SUCCESS) |
---|
925 | { |
---|
926 | debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server."); |
---|
927 | return 1; |
---|
928 | } |
---|
929 | if (type != SSH_SMSG_FAILURE) |
---|
930 | packet_disconnect("Protocol error waiting RSA auth response: %d", type); |
---|
931 | debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused."); |
---|
932 | return 0; |
---|
933 | } |
---|
934 | |
---|
935 | #ifdef KERBEROS |
---|
936 | int try_kerberos_authentication(void) |
---|
937 | { |
---|
938 | #ifdef KRB5 |
---|
939 | char *remotehost; |
---|
940 | krb5_data auth; |
---|
941 | krb5_error_code r; |
---|
942 | int tempint, type; |
---|
943 | krb5_ccache ccache; |
---|
944 | krb5_creds creds; |
---|
945 | krb5_creds * new_creds = 0; |
---|
946 | int ap_opts, ret_stat = 0; |
---|
947 | krb5_keyblock *session_key = 0; |
---|
948 | krb5_ap_rep_enc_part *repl = 0; |
---|
949 | struct sockaddr_in local, foreign; |
---|
950 | |
---|
951 | memset(&auth, 0 , sizeof(auth)); |
---|
952 | remotehost = (char *) get_canonical_hostname(); |
---|
953 | if (!ssh_context) |
---|
954 | { |
---|
955 | if ((r = krb5_init_context(&ssh_context))) |
---|
956 | fatal("Kerberos V5: %.100s while initializing krb5.", error_message(r)); |
---|
957 | krb5_init_ets(ssh_context); |
---|
958 | } |
---|
959 | |
---|
960 | if ((r = krb5_cc_default(ssh_context, &ccache))) |
---|
961 | { |
---|
962 | debug("Kerberos V5: could not get default ccache."); |
---|
963 | goto cleanup; |
---|
964 | } |
---|
965 | |
---|
966 | memset((char *)&creds, 0, sizeof(creds)); |
---|
967 | if ((r = krb5_sname_to_principal(ssh_context, remotehost, |
---|
968 | "host", KRB5_NT_SRV_HST, |
---|
969 | &creds.server))) |
---|
970 | { |
---|
971 | debug("Kerberos V5: error while constructing service name: %.100s.", |
---|
972 | error_message(r)); |
---|
973 | goto cleanup; |
---|
974 | } |
---|
975 | if ((r = krb5_cc_get_principal(ssh_context, ccache, |
---|
976 | &creds.client))) |
---|
977 | { |
---|
978 | debug("Kerberos V5: failure on principal (%.100s).", |
---|
979 | error_message(r)); |
---|
980 | goto cleanup; |
---|
981 | } |
---|
982 | |
---|
983 | creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC; |
---|
984 | if ((r = krb5_get_credentials(ssh_context, 0, |
---|
985 | ccache, &creds, &new_creds))) |
---|
986 | { |
---|
987 | debug("Kerberos V5: failure on credentials(%.100s).", |
---|
988 | error_message(r)); |
---|
989 | goto cleanup; |
---|
990 | } |
---|
991 | |
---|
992 | /* ap_opts = AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY; */ |
---|
993 | ap_opts = 0; |
---|
994 | |
---|
995 | if (!auth_context) |
---|
996 | { |
---|
997 | if ((r = krb5_auth_con_init(ssh_context, &auth_context))) |
---|
998 | { |
---|
999 | debug("Kerberos V5: failed to init auth_context (%.100s)", |
---|
1000 | error_message(r)); |
---|
1001 | goto cleanup; |
---|
1002 | } |
---|
1003 | krb5_auth_con_setflags(ssh_context, auth_context, |
---|
1004 | KRB5_AUTH_CONTEXT_RET_TIME); |
---|
1005 | } |
---|
1006 | |
---|
1007 | if ((r = krb5_mk_req_extended(ssh_context, &auth_context, ap_opts, |
---|
1008 | 0, new_creds, &auth))) |
---|
1009 | { |
---|
1010 | debug("Kerberos V5: failed krb5_mk_req_extended (%.100s)", |
---|
1011 | error_message(r)); |
---|
1012 | goto cleanup; |
---|
1013 | } |
---|
1014 | |
---|
1015 | /* Send authentication info to server. */ |
---|
1016 | packet_start(SSH_CMSG_AUTH_KERBEROS); |
---|
1017 | packet_put_string((char *) auth.data, auth.length); |
---|
1018 | packet_send(); |
---|
1019 | packet_write_wait(); |
---|
1020 | |
---|
1021 | tempint = sizeof(local); |
---|
1022 | memset(&local, 0, tempint); |
---|
1023 | if (getsockname(packet_get_connection_in(), |
---|
1024 | (struct sockaddr *) &local, &tempint) < 0) |
---|
1025 | debug("getsockname failed: %.100s", strerror(errno)); |
---|
1026 | |
---|
1027 | tempint = sizeof(foreign); |
---|
1028 | memset(&foreign, 0, tempint); |
---|
1029 | if (getpeername(packet_get_connection_in(), |
---|
1030 | (struct sockaddr *)&foreign, &tempint) < 0) |
---|
1031 | debug("getpeername failed: %.100s", strerror(errno)); |
---|
1032 | |
---|
1033 | if (auth.data) |
---|
1034 | { |
---|
1035 | free(auth.data); |
---|
1036 | auth.data = 0; |
---|
1037 | } |
---|
1038 | |
---|
1039 | /* Get server reply. */ |
---|
1040 | type = packet_read(); |
---|
1041 | switch(type) |
---|
1042 | { |
---|
1043 | case SSH_SMSG_FAILURE: |
---|
1044 | debug("Kerberos V5 authentication failed."); |
---|
1045 | goto cleanup; |
---|
1046 | |
---|
1047 | case SSH_SMSG_AUTH_KERBEROS_RESPONSE: |
---|
1048 | /* Get server's response. */ |
---|
1049 | auth.data = packet_get_string((unsigned int *) &auth.length); |
---|
1050 | |
---|
1051 | /* If his response isn't properly encrypted with the session key, |
---|
1052 | he's bogus. Also krb5_rd_rep will fail when MUTUAL AUTH is |
---|
1053 | requested and the server does not send back a session encrypted |
---|
1054 | time stamp */ |
---|
1055 | |
---|
1056 | if (r = krb5_rd_rep(ssh_context, auth_context, &auth, &repl)) |
---|
1057 | { |
---|
1058 | packet_disconnect("Kerberos V5 Authentication failed: %.100s", |
---|
1059 | error_message(r)); |
---|
1060 | goto cleanup; |
---|
1061 | } |
---|
1062 | else |
---|
1063 | { |
---|
1064 | debug("Kerberos V5 authentication accepted."); |
---|
1065 | ret_stat = 1; |
---|
1066 | } |
---|
1067 | break; |
---|
1068 | |
---|
1069 | default: |
---|
1070 | packet_disconnect("Protocol error on Kerberos V5 response: %d", type); |
---|
1071 | goto cleanup; |
---|
1072 | } |
---|
1073 | |
---|
1074 | cleanup: |
---|
1075 | krb5_free_cred_contents(ssh_context, &creds); |
---|
1076 | if (new_creds) |
---|
1077 | krb5_free_creds(ssh_context, new_creds); |
---|
1078 | if (session_key) |
---|
1079 | krb5_free_keyblock(ssh_context, session_key); |
---|
1080 | if (auth.data) |
---|
1081 | free(auth.data); |
---|
1082 | if (repl) |
---|
1083 | krb5_free_ap_rep_enc_part(ssh_context, repl); |
---|
1084 | |
---|
1085 | return(ret_stat); |
---|
1086 | #endif /* KRB5 */ |
---|
1087 | } |
---|
1088 | #endif /* KERBEROS */ |
---|
1089 | |
---|
1090 | #ifdef KERBEROS_TGT_PASSING |
---|
1091 | /* Forward our local Kerberos tgt to the server. */ |
---|
1092 | int send_kerberos_tgt(void) |
---|
1093 | { |
---|
1094 | #ifdef KRB5 |
---|
1095 | char *remotehost; |
---|
1096 | krb5_principal client; |
---|
1097 | krb5_principal server; |
---|
1098 | krb5_ccache ccache; |
---|
1099 | krb5_data outbuf; |
---|
1100 | krb5_error_code r; |
---|
1101 | int type; |
---|
1102 | char server_name[512]; |
---|
1103 | |
---|
1104 | remotehost = (char *) get_canonical_hostname(); |
---|
1105 | memset(&outbuf, 0 , sizeof(outbuf)); |
---|
1106 | |
---|
1107 | debug("Trying Kerberos V5 TGT passing."); |
---|
1108 | |
---|
1109 | if (!ssh_context) |
---|
1110 | { |
---|
1111 | if ((r = krb5_init_context(&ssh_context))) |
---|
1112 | fatal("Kerberos V5: %.100s while initializing krb5.", error_message(r)); |
---|
1113 | krb5_init_ets(ssh_context); |
---|
1114 | } |
---|
1115 | if (!auth_context) |
---|
1116 | { |
---|
1117 | if ((r = krb5_auth_con_init(ssh_context, &auth_context))) |
---|
1118 | { |
---|
1119 | debug("Kerberos V5: failed to init auth_context (%.100s)", |
---|
1120 | error_message(r)); |
---|
1121 | return 0 ; |
---|
1122 | } |
---|
1123 | krb5_auth_con_setflags(ssh_context, auth_context, |
---|
1124 | KRB5_AUTH_CONTEXT_RET_TIME); |
---|
1125 | } |
---|
1126 | |
---|
1127 | if ((r = krb5_cc_default(ssh_context, &ccache))) |
---|
1128 | { |
---|
1129 | debug("Kerberos V5: could not get default ccache."); |
---|
1130 | return 0 ; |
---|
1131 | } |
---|
1132 | |
---|
1133 | if ((r = krb5_cc_get_principal(ssh_context, ccache, |
---|
1134 | &client))) |
---|
1135 | { |
---|
1136 | debug("Kerberos V5: failure on principal (%.100s)", |
---|
1137 | error_message(r)); |
---|
1138 | return 0 ; |
---|
1139 | } |
---|
1140 | |
---|
1141 | /* Somewhat of a hack here. We need to get the TGT for the |
---|
1142 | clients realm. However if remotehost is in another realm |
---|
1143 | krb5_fwd_tgt_creds will try to go to that realm to get |
---|
1144 | the TGT, which will fail. So we create the server |
---|
1145 | principal and point it to clients realm. This way |
---|
1146 | we pass over a TGT of the clients realm. */ |
---|
1147 | |
---|
1148 | sprintf(server_name,"host/%.100s@", remotehost); |
---|
1149 | strncat(server_name,client->realm.data,client->realm.length); |
---|
1150 | krb5_parse_name(ssh_context,server_name, &server); |
---|
1151 | server->type = KRB5_NT_SRV_HST; |
---|
1152 | |
---|
1153 | |
---|
1154 | if ((r = krb5_fwd_tgt_creds(ssh_context, auth_context, 0, client, |
---|
1155 | server, ccache, 1, &outbuf))) |
---|
1156 | { |
---|
1157 | debug("Kerberos V5 krb5_fwd_tgt_creds failure (%.100s)", |
---|
1158 | error_message(r)); |
---|
1159 | krb5_free_principal(ssh_context, client); |
---|
1160 | krb5_free_principal(ssh_context, server); |
---|
1161 | return 0 ; |
---|
1162 | } |
---|
1163 | packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); |
---|
1164 | packet_put_string((char *)outbuf.data, outbuf.length); |
---|
1165 | packet_send(); |
---|
1166 | packet_write_wait(); |
---|
1167 | |
---|
1168 | if (outbuf.data) |
---|
1169 | free(outbuf.data); |
---|
1170 | krb5_free_principal(ssh_context, client); |
---|
1171 | krb5_free_principal(ssh_context, server); |
---|
1172 | |
---|
1173 | type = packet_read(); |
---|
1174 | if (type == SSH_SMSG_SUCCESS) |
---|
1175 | { |
---|
1176 | debug("Kerberos V5 TGT passing was successful."); |
---|
1177 | return 1; |
---|
1178 | } |
---|
1179 | else |
---|
1180 | if (type != SSH_SMSG_FAILURE) |
---|
1181 | packet_disconnect("Protocol error on Kerberos tgt response: %d", type); |
---|
1182 | else |
---|
1183 | debug("Kerberos V5 TGT passing failed."); |
---|
1184 | |
---|
1185 | return 0; |
---|
1186 | #endif /* KRB5 */ |
---|
1187 | } |
---|
1188 | #endif /* KERBEROS_TGT_PASSING */ |
---|
1189 | |
---|
1190 | /* Waits for the server identification string, and sends our own identification |
---|
1191 | string. */ |
---|
1192 | |
---|
1193 | void ssh_exchange_identification(void) |
---|
1194 | { |
---|
1195 | char buf[256], remote_version[256]; /* must be same size! */ |
---|
1196 | int remote_major, remote_minor, i; |
---|
1197 | int my_major, my_minor; |
---|
1198 | int len; |
---|
1199 | int connection_in = packet_get_connection_in(); |
---|
1200 | int connection_out = packet_get_connection_out(); |
---|
1201 | |
---|
1202 | /* Read other side\'s version identification. */ |
---|
1203 | for (i = 0; i < sizeof(buf) - 1; i++) |
---|
1204 | { |
---|
1205 | len = read(connection_in, &buf[i], 1); |
---|
1206 | if (len == 0) |
---|
1207 | fatal("Connection closed by foreign host."); |
---|
1208 | else |
---|
1209 | if (len < 0) |
---|
1210 | fatal("read: %.100s", strerror(errno)); |
---|
1211 | if (buf[i] == '\r') |
---|
1212 | { |
---|
1213 | buf[i] = '\n'; |
---|
1214 | buf[i + 1] = 0; |
---|
1215 | i++; |
---|
1216 | } |
---|
1217 | if (buf[i] == '\n') |
---|
1218 | { |
---|
1219 | buf[i + 1] = 0; |
---|
1220 | break; |
---|
1221 | } |
---|
1222 | } |
---|
1223 | buf[sizeof(buf) - 1] = 0; |
---|
1224 | |
---|
1225 | /* Check that the versions match. In future this might accept several |
---|
1226 | versions and set appropriate flags to handle them. */ |
---|
1227 | if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, |
---|
1228 | remote_version) != 3) |
---|
1229 | fatal("Bad remote protocol version identification: '%.100s'", buf); |
---|
1230 | debug("Remote protocol version %d.%d, remote software version %.100s", |
---|
1231 | remote_major, remote_minor, remote_version); |
---|
1232 | |
---|
1233 | switch (check_emulation(remote_major, remote_minor, |
---|
1234 | &my_major, &my_minor)) |
---|
1235 | { |
---|
1236 | case EMULATE_VERSION_TOO_OLD: |
---|
1237 | fatal("Remote machine has too old SSH software version."); |
---|
1238 | case EMULATE_MAJOR_VERSION_MISMATCH: |
---|
1239 | fatal("Major protocol versions incompatible."); |
---|
1240 | case EMULATE_VERSION_NEWER: |
---|
1241 | /* We will emulate the old version. */ |
---|
1242 | break; |
---|
1243 | case EMULATE_VERSION_OK: |
---|
1244 | break; |
---|
1245 | default: |
---|
1246 | fatal("Unexpected return value from check_emulation."); |
---|
1247 | } |
---|
1248 | |
---|
1249 | sprintf(buf, "SSH-%d.%d-%.100s", |
---|
1250 | my_major, my_minor, SSH_VERSION); |
---|
1251 | #ifdef F_SECURE_COMMERCIAL |
---|
1252 | |
---|
1253 | #endif /* F_SECURE_COMMERCIAL */ |
---|
1254 | strcat(buf, "\n"); |
---|
1255 | if (write(connection_out, buf, strlen(buf)) != strlen(buf)) |
---|
1256 | fatal("write: %.100s", strerror(errno)); |
---|
1257 | } |
---|
1258 | |
---|
1259 | /* Starts a dialog with the server, and authenticates the current user on the |
---|
1260 | server. This does not need any extra privileges. The basic connection |
---|
1261 | to the server must already have been established before this is called. |
---|
1262 | User is the remote user; if it is NULL, the current local user name will |
---|
1263 | be used. Anonymous indicates that no rhosts authentication will be used. |
---|
1264 | If login fails, this function prints an error and never returns. |
---|
1265 | This function does not require super-user privileges. */ |
---|
1266 | |
---|
1267 | void ssh_login(RandomState *state, int host_key_valid, |
---|
1268 | RSAPrivateKey *own_host_key, |
---|
1269 | const char *orighost, |
---|
1270 | Options *options, uid_t original_real_uid) |
---|
1271 | { |
---|
1272 | int i, type, len, f; |
---|
1273 | char buf[1024], seedbuf[16]; |
---|
1274 | char *password; |
---|
1275 | struct passwd *pw; |
---|
1276 | MP_INT key; |
---|
1277 | RSAPublicKey host_key; |
---|
1278 | RSAPublicKey public_key; |
---|
1279 | unsigned char session_key[SSH_SESSION_KEY_LENGTH]; |
---|
1280 | const char *server_user, *local_user; |
---|
1281 | char *cp, *host; |
---|
1282 | struct stat st; |
---|
1283 | unsigned char check_bytes[8]; |
---|
1284 | unsigned int supported_ciphers, supported_authentications, protocol_flags; |
---|
1285 | HostStatus host_status; |
---|
1286 | #ifdef KERBEROS |
---|
1287 | #ifdef KRB5 |
---|
1288 | char *kuser; |
---|
1289 | krb5_ccache ccache; |
---|
1290 | krb5_error_code problem; |
---|
1291 | krb5_principal client; |
---|
1292 | #endif |
---|
1293 | #endif |
---|
1294 | |
---|
1295 | /* Convert the user-supplied hostname into all lowercase. */ |
---|
1296 | host = xstrdup(orighost); |
---|
1297 | for (cp = host; *cp; cp++) |
---|
1298 | if (isupper(*cp)) |
---|
1299 | *cp = tolower(*cp); |
---|
1300 | |
---|
1301 | /* Map localhost to ip-address locally */ |
---|
1302 | if (strcmp(host, "localhost") == 0) |
---|
1303 | { |
---|
1304 | xfree(host); |
---|
1305 | host = xstrdup("127.0.0.1"); |
---|
1306 | } |
---|
1307 | |
---|
1308 | /* Exchange protocol version identification strings with the server. */ |
---|
1309 | ssh_exchange_identification(); |
---|
1310 | |
---|
1311 | /* Put the connection into non-blocking mode. */ |
---|
1312 | packet_set_nonblocking(); |
---|
1313 | |
---|
1314 | /* Get local user name. Use it as server user if no user name |
---|
1315 | was given. */ |
---|
1316 | pw = getpwuid(original_real_uid); |
---|
1317 | if (!pw) |
---|
1318 | fatal("User id %d not found from user database.", original_real_uid); |
---|
1319 | local_user = xstrdup(pw->pw_name); |
---|
1320 | server_user = options->user ? options->user : local_user; |
---|
1321 | |
---|
1322 | debug("Waiting for server public key."); |
---|
1323 | |
---|
1324 | /* Wait for a public key packet from the server. */ |
---|
1325 | packet_read_expect(SSH_SMSG_PUBLIC_KEY); |
---|
1326 | |
---|
1327 | /* Get check bytes from the packet. */ |
---|
1328 | for (i = 0; i < 8; i++) |
---|
1329 | check_bytes[i] = packet_get_char(); |
---|
1330 | |
---|
1331 | /* Get the public key. */ |
---|
1332 | public_key.bits = packet_get_int(); |
---|
1333 | mpz_init(&public_key.e); |
---|
1334 | packet_get_mp_int(&public_key.e); |
---|
1335 | mpz_init(&public_key.n); |
---|
1336 | packet_get_mp_int(&public_key.n); |
---|
1337 | |
---|
1338 | /* Get the host key. */ |
---|
1339 | host_key.bits = packet_get_int(); |
---|
1340 | mpz_init(&host_key.e); |
---|
1341 | packet_get_mp_int(&host_key.e); |
---|
1342 | mpz_init(&host_key.n); |
---|
1343 | packet_get_mp_int(&host_key.n); |
---|
1344 | |
---|
1345 | /* Get protocol flags. */ |
---|
1346 | protocol_flags = packet_get_int(); |
---|
1347 | packet_set_protocol_flags(protocol_flags); |
---|
1348 | |
---|
1349 | /* Get supported cipher types. */ |
---|
1350 | supported_ciphers = packet_get_int(); |
---|
1351 | |
---|
1352 | /* Get supported authentication types. */ |
---|
1353 | supported_authentications = packet_get_int(); |
---|
1354 | |
---|
1355 | debug("Received server public key (%d bits) and host key (%d bits).", |
---|
1356 | public_key.bits, host_key.bits); |
---|
1357 | |
---|
1358 | /* Compute the session id. */ |
---|
1359 | compute_session_id(session_id, check_bytes, host_key.bits, &host_key.n, |
---|
1360 | public_key.bits, &public_key.n); |
---|
1361 | |
---|
1362 | /* Check if the host key is present in the user's list of known hosts |
---|
1363 | or in the systemwide list. */ |
---|
1364 | host_status = check_host_in_hostfile(original_real_uid, |
---|
1365 | options->user_hostfile, |
---|
1366 | host, host_key.bits, |
---|
1367 | &host_key.e, &host_key.n); |
---|
1368 | if (host_status == HOST_NEW) |
---|
1369 | host_status = check_host_in_hostfile(original_real_uid, |
---|
1370 | options->system_hostfile, host, |
---|
1371 | host_key.bits, &host_key.e, |
---|
1372 | &host_key.n); |
---|
1373 | |
---|
1374 | /* Force accepting of the host key for localhost and 127.0.0.1. |
---|
1375 | The problem is that if the home directory is NFS-mounted to multiple |
---|
1376 | machines, localhost will refer to a different machine in each of them, |
---|
1377 | and the user will get bogus HOST_CHANGED warnings. This essentially |
---|
1378 | disables host authentication for localhost; however, this is probably |
---|
1379 | not a real problem. */ |
---|
1380 | if (strcmp(host, "127.0.0.1") == 0) |
---|
1381 | { |
---|
1382 | debug("Forcing accepting of host key for localhost."); |
---|
1383 | host_status = HOST_OK; |
---|
1384 | } |
---|
1385 | |
---|
1386 | switch (host_status) |
---|
1387 | { |
---|
1388 | case HOST_OK: |
---|
1389 | /* The host is known and the key matches. */ |
---|
1390 | debug("Host '%.200s' is known and matches the host key.", host); |
---|
1391 | break; |
---|
1392 | case HOST_NEW: |
---|
1393 | /* The host is new. */ |
---|
1394 | if (options->strict_host_key_checking == 1) |
---|
1395 | { /* User has requested strict host key checking. We will not |
---|
1396 | add the host key automatically. The only alternative left |
---|
1397 | is to abort. */ |
---|
1398 | fatal("No host key is known for %.200s and you have requested strict checking.", host); |
---|
1399 | } |
---|
1400 | |
---|
1401 | error("Host key not found from the list of known hosts."); |
---|
1402 | if (options->strict_host_key_checking == 2) |
---|
1403 | { |
---|
1404 | if (options->batch_mode) |
---|
1405 | fatal("No host key is known for %.200s and cannot confirm operation when running in batch mode.", host); |
---|
1406 | |
---|
1407 | read_confirmation("Are you sure you want to continue connecting (yes/no)? "); |
---|
1408 | } |
---|
1409 | /* If not in strict mode, add the key automatically to the local |
---|
1410 | known_hosts file. */ |
---|
1411 | if (!add_host_to_hostfile(original_real_uid, |
---|
1412 | options->user_hostfile, host, host_key.bits, |
---|
1413 | &host_key.e, &host_key.n)) |
---|
1414 | log_msg("Failed to add the host to the list of known hosts (%.500s).", |
---|
1415 | options->user_hostfile); |
---|
1416 | else |
---|
1417 | log_msg("Host '%.200s' added to the list of known hosts.", host); |
---|
1418 | break; |
---|
1419 | case HOST_CHANGED: |
---|
1420 | /* The host key has changed. */ |
---|
1421 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
---|
1422 | error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @"); |
---|
1423 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
---|
1424 | error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
---|
1425 | error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
---|
1426 | error("It is also possible that the host key has just been changed."); |
---|
1427 | error("Please contact your system administrator."); |
---|
1428 | error("Add correct host key in %.100s to get rid of this message.", |
---|
1429 | options->user_hostfile); |
---|
1430 | |
---|
1431 | /* If strict host key checking is in use, the user will have to edit |
---|
1432 | the key manually and we can only abort. */ |
---|
1433 | if (options->strict_host_key_checking == 1) |
---|
1434 | fatal("Host key for %.200s has changed and you have requested strict checking.", host); |
---|
1435 | |
---|
1436 | /* If strict host key checking has not been requested, allow the |
---|
1437 | connection but without password authentication. */ |
---|
1438 | if (options->forward_agent) |
---|
1439 | { |
---|
1440 | error("Agent forwarding is disabled to avoid attacks by corrupted servers."); |
---|
1441 | options->forward_agent = 0; |
---|
1442 | } |
---|
1443 | if (options->forward_x11) |
---|
1444 | { |
---|
1445 | error("X11 forwarding is disabled to avoid attacks by corrupted servers."); |
---|
1446 | options->forward_x11 = 0; |
---|
1447 | } |
---|
1448 | if (options->num_local_forwards > 0) |
---|
1449 | { |
---|
1450 | error("Local port forwarding is disabled to avoid attacks by corrupted servers."); |
---|
1451 | options->num_local_forwards = 0; |
---|
1452 | } |
---|
1453 | if (options->num_remote_forwards) |
---|
1454 | { |
---|
1455 | error("Remote port forwarding is disabled to avoid attacks by corrupted servers."); |
---|
1456 | options->num_remote_forwards = 0; |
---|
1457 | } |
---|
1458 | |
---|
1459 | if (options->strict_host_key_checking == 2) |
---|
1460 | { |
---|
1461 | if (options->batch_mode) |
---|
1462 | fatal("No host key is known for %.200s and cannot confirm operation when running in batch mode.", host); |
---|
1463 | |
---|
1464 | read_confirmation("Are you sure you want to continue connecting (yes/no)? "); |
---|
1465 | } |
---|
1466 | |
---|
1467 | /* XXX Should permit the user to change to use the new id. This could |
---|
1468 | be done by converting the host key to an identifying sentence, tell |
---|
1469 | that the host identifies itself by that sentence, and ask the user |
---|
1470 | if he/she whishes to accept the authentication. */ |
---|
1471 | break; |
---|
1472 | } |
---|
1473 | /* Generate a session key. */ |
---|
1474 | |
---|
1475 | /* Initialize the random number generator. */ |
---|
1476 | sprintf(buf, "%.500s/%.200s", pw->pw_dir, SSH_CLIENT_SEEDFILE); |
---|
1477 | if (userfile_stat(pw->pw_uid, buf, &st) < 0) |
---|
1478 | log_msg("Creating random seed file ~/%.200s. This may take a while.", |
---|
1479 | SSH_CLIENT_SEEDFILE); |
---|
1480 | else |
---|
1481 | debug("Initializing random; seed file %.900s", buf); |
---|
1482 | random_initialize(state, pw->pw_uid, buf); |
---|
1483 | |
---|
1484 | /* Read also some random data from the systemwide random seed file to |
---|
1485 | avoid the user being able to guess his own session key when running |
---|
1486 | as root. */ |
---|
1487 | f = open(SSH_DAEMON_SEED_FILE, O_RDONLY); |
---|
1488 | if (f >= 0) |
---|
1489 | { |
---|
1490 | len = read(f, seedbuf, sizeof(seedbuf)); /* Try to read 128 bits. */ |
---|
1491 | if (len > 0) |
---|
1492 | { |
---|
1493 | random_add_noise(state, seedbuf, len); |
---|
1494 | random_stir(state); |
---|
1495 | } |
---|
1496 | close(f); |
---|
1497 | } |
---|
1498 | |
---|
1499 | /* Generate an encryption key for the session. The key is a 256 bit |
---|
1500 | random number, interpreted as a 32-byte key, with the least significant |
---|
1501 | 8 bits being the first byte of the key. */ |
---|
1502 | for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) |
---|
1503 | session_key[i] = random_get_byte(state); |
---|
1504 | |
---|
1505 | /* Save the new random state. */ |
---|
1506 | random_save(state, pw->pw_uid, buf); |
---|
1507 | |
---|
1508 | /* According to the protocol spec, the first byte of the session key is |
---|
1509 | the highest byte of the integer. The session key is xored with the |
---|
1510 | first 16 bytes of the session id. */ |
---|
1511 | mpz_init_set_ui(&key, 0); |
---|
1512 | for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) |
---|
1513 | { |
---|
1514 | mpz_mul_2exp(&key, &key, 8); |
---|
1515 | if (i < 16) |
---|
1516 | mpz_add_ui(&key, &key, session_key[i] ^ session_id[i]); |
---|
1517 | else |
---|
1518 | mpz_add_ui(&key, &key, session_key[i]); |
---|
1519 | } |
---|
1520 | |
---|
1521 | /* Encrypt the integer using the public key and host key of the server |
---|
1522 | (key with smaller modulus first). */ |
---|
1523 | if (mpz_cmp(&public_key.n, &host_key.n) < 0) |
---|
1524 | { |
---|
1525 | /* Public key has smaller modulus. */ |
---|
1526 | assert(host_key.bits >= public_key.bits + SSH_KEY_BITS_RESERVED); |
---|
1527 | |
---|
1528 | rsa_public_encrypt(&key, &key, &public_key, state); |
---|
1529 | rsa_public_encrypt(&key, &key, &host_key, state); |
---|
1530 | } |
---|
1531 | else |
---|
1532 | { |
---|
1533 | /* Host key has smaller modulus (or they are equal). */ |
---|
1534 | assert(public_key.bits >= host_key.bits + SSH_KEY_BITS_RESERVED); |
---|
1535 | |
---|
1536 | rsa_public_encrypt(&key, &key, &host_key, state); |
---|
1537 | rsa_public_encrypt(&key, &key, &public_key, state); |
---|
1538 | } |
---|
1539 | |
---|
1540 | if (options->cipher == SSH_CIPHER_NOT_SET) |
---|
1541 | if (cipher_mask() & supported_ciphers & (1 << SSH_CIPHER_IDEA)) |
---|
1542 | options->cipher = SSH_CIPHER_IDEA; |
---|
1543 | else |
---|
1544 | { |
---|
1545 | debug("IDEA not supported, using %.100s instead.", |
---|
1546 | cipher_name(SSH_FALLBACK_CIPHER)); |
---|
1547 | options->cipher = SSH_FALLBACK_CIPHER; |
---|
1548 | } |
---|
1549 | |
---|
1550 | /* Check that the selected cipher is supported. */ |
---|
1551 | if (!(supported_ciphers & (1 << options->cipher))) |
---|
1552 | fatal("Selected cipher type %.100s not supported by server.", |
---|
1553 | cipher_name(options->cipher)); |
---|
1554 | |
---|
1555 | debug("Encryption type: %.100s", cipher_name(options->cipher)); |
---|
1556 | |
---|
1557 | /* Send the encrypted session key to the server. */ |
---|
1558 | packet_start(SSH_CMSG_SESSION_KEY); |
---|
1559 | packet_put_char(options->cipher); |
---|
1560 | |
---|
1561 | /* Send the check bytes back to the server. */ |
---|
1562 | for (i = 0; i < 8; i++) |
---|
1563 | packet_put_char(check_bytes[i]); |
---|
1564 | |
---|
1565 | /* Send the encrypted encryption key. */ |
---|
1566 | packet_put_mp_int(&key); |
---|
1567 | |
---|
1568 | /* Send protocol flags. */ |
---|
1569 | packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN); |
---|
1570 | |
---|
1571 | /* Send the packet now. */ |
---|
1572 | packet_send(); |
---|
1573 | packet_write_wait(); |
---|
1574 | |
---|
1575 | /* Destroy the session key integer and the public keys since we no longer |
---|
1576 | need them. */ |
---|
1577 | mpz_clear(&key); |
---|
1578 | rsa_clear_public_key(&public_key); |
---|
1579 | rsa_clear_public_key(&host_key); |
---|
1580 | |
---|
1581 | debug("Sent encrypted session key."); |
---|
1582 | |
---|
1583 | /* Set the encryption key. */ |
---|
1584 | packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, |
---|
1585 | options->cipher, 1); |
---|
1586 | |
---|
1587 | /* We will no longer need the session key here. Destroy any extra copies. */ |
---|
1588 | memset(session_key, 0, sizeof(session_key)); |
---|
1589 | |
---|
1590 | /* Expect a success message from the server. Note that this message will |
---|
1591 | be received in encrypted form. */ |
---|
1592 | packet_read_expect(SSH_SMSG_SUCCESS); |
---|
1593 | |
---|
1594 | debug("Received encrypted confirmation."); |
---|
1595 | |
---|
1596 | #ifdef KERBEROS |
---|
1597 | #ifdef KRB5 |
---|
1598 | if (!ssh_context) |
---|
1599 | { |
---|
1600 | if ((problem = krb5_init_context(&ssh_context))) |
---|
1601 | fatal("Kerberos V5: %.100s while initializing krb5.", |
---|
1602 | error_message(problem)); |
---|
1603 | krb5_init_ets(ssh_context); |
---|
1604 | } |
---|
1605 | if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && |
---|
1606 | options->kerberos_authentication && options->no_user_given ) |
---|
1607 | { |
---|
1608 | /* Send over fully qualified kerberos username for the |
---|
1609 | remote username. Let the server figure out what the |
---|
1610 | localname should be. */ |
---|
1611 | |
---|
1612 | if (!krb5_cc_default(ssh_context, &ccache)) |
---|
1613 | { |
---|
1614 | if ((problem = krb5_cc_get_principal(ssh_context, ccache, |
---|
1615 | &client))) |
---|
1616 | { |
---|
1617 | debug("Kerberos V5: failure on principal (%.100s).", |
---|
1618 | error_message(problem)); |
---|
1619 | } |
---|
1620 | else { |
---|
1621 | if (!krb5_unparse_name(ssh_context, client, &kuser)) |
---|
1622 | server_user = kuser; |
---|
1623 | krb5_free_principal(ssh_context, client); |
---|
1624 | } |
---|
1625 | } |
---|
1626 | else |
---|
1627 | debug("Kerberos V5: could not get default ccache."); |
---|
1628 | } |
---|
1629 | #endif /* KRB5 */ |
---|
1630 | #endif /* KERBEROS */ |
---|
1631 | |
---|
1632 | /* Send the name of the user to log in as on the server. */ |
---|
1633 | packet_start(SSH_CMSG_USER); |
---|
1634 | packet_put_string(server_user, strlen(server_user)); |
---|
1635 | packet_send(); |
---|
1636 | packet_write_wait(); |
---|
1637 | |
---|
1638 | /* The server should respond with success if no authentication is needed |
---|
1639 | (the user has no password). Otherwise the server responds with |
---|
1640 | failure. */ |
---|
1641 | type = packet_read(); |
---|
1642 | if (type == SSH_SMSG_SUCCESS) |
---|
1643 | return; /* Connection was accepted without authentication. */ |
---|
1644 | if (type != SSH_SMSG_FAILURE) |
---|
1645 | packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", |
---|
1646 | type); |
---|
1647 | |
---|
1648 | #ifdef KERBEROS_TGT_PASSING |
---|
1649 | /* Try Kerberos tgt passing if the server supports it. */ |
---|
1650 | if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && |
---|
1651 | options->kerberos_tgt_passing) |
---|
1652 | { |
---|
1653 | if (options->cipher == SSH_CIPHER_NONE) |
---|
1654 | log_msg("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); |
---|
1655 | (void)send_kerberos_tgt(); |
---|
1656 | } |
---|
1657 | #endif /* KERBEROS_TGT_PASSING */ |
---|
1658 | |
---|
1659 | #ifdef KERBEROS |
---|
1660 | #ifdef KRB5 |
---|
1661 | if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && |
---|
1662 | options->kerberos_authentication) |
---|
1663 | { |
---|
1664 | debug("Trying Kerberos V5 authentication."); |
---|
1665 | #endif |
---|
1666 | if (try_kerberos_authentication()) { |
---|
1667 | /* The server should respond with success or failure. */ |
---|
1668 | type = packet_read(); |
---|
1669 | if (type == SSH_SMSG_SUCCESS) |
---|
1670 | return; /* Successful connection. */ |
---|
1671 | if (type != SSH_SMSG_FAILURE) |
---|
1672 | packet_disconnect("Protocol error: got %d in response to Kerberos auth", type); |
---|
1673 | } |
---|
1674 | #ifdef KRB5 |
---|
1675 | } |
---|
1676 | #endif |
---|
1677 | #endif /* KERBEROS */ |
---|
1678 | |
---|
1679 | /* Use rhosts authentication if running in privileged socket and we do not |
---|
1680 | wish to remain anonymous. */ |
---|
1681 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && |
---|
1682 | options->rhosts_authentication) |
---|
1683 | { |
---|
1684 | debug("Trying rhosts authentication."); |
---|
1685 | packet_start(SSH_CMSG_AUTH_RHOSTS); |
---|
1686 | packet_put_string(local_user, strlen(local_user)); |
---|
1687 | packet_send(); |
---|
1688 | packet_write_wait(); |
---|
1689 | |
---|
1690 | /* The server should respond with success or failure. */ |
---|
1691 | type = packet_read(); |
---|
1692 | if (type == SSH_SMSG_SUCCESS) |
---|
1693 | return; /* Successful connection. */ |
---|
1694 | if (type != SSH_SMSG_FAILURE) |
---|
1695 | packet_disconnect("Protocol error: got %d in response to rhosts auth", |
---|
1696 | type); |
---|
1697 | } |
---|
1698 | |
---|
1699 | /* Try .rhosts or /etc/hosts.equiv authentication with RSA host |
---|
1700 | authentication. */ |
---|
1701 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && |
---|
1702 | options->rhosts_rsa_authentication && host_key_valid) |
---|
1703 | { |
---|
1704 | if (try_rhosts_rsa_authentication(local_user, own_host_key)) |
---|
1705 | return; /* Successful authentication. */ |
---|
1706 | } |
---|
1707 | |
---|
1708 | /* Try RSA authentication if the server supports it. */ |
---|
1709 | if ((supported_authentications & (1 << SSH_AUTH_RSA)) && |
---|
1710 | options->rsa_authentication) |
---|
1711 | { |
---|
1712 | /* Try RSA authentication using the authentication agent. The agent |
---|
1713 | is tried first because no passphrase is needed for it, whereas |
---|
1714 | identity files may require passphrases. */ |
---|
1715 | if (try_agent_authentication()) |
---|
1716 | return; /* Successful connection. */ |
---|
1717 | |
---|
1718 | /* Try RSA authentication for each identity. */ |
---|
1719 | for (i = 0; i < options->num_identity_files; i++) |
---|
1720 | if (try_rsa_authentication(pw, options->identity_files[i], |
---|
1721 | !options->batch_mode)) |
---|
1722 | return; /* Successful connection. */ |
---|
1723 | } |
---|
1724 | |
---|
1725 | /* Support for TIS authentication server |
---|
1726 | Contributed by Andre April <Andre.April@cediti.be>. */ |
---|
1727 | /* Try Tis authentication daemon if the server supports it. */ |
---|
1728 | if ((supported_authentications & (1 << SSH_AUTH_TIS)) && |
---|
1729 | options->tis_authentication && !options->batch_mode) |
---|
1730 | { |
---|
1731 | char *prompt; |
---|
1732 | debug("Doing TIS authentication."); |
---|
1733 | if (options->cipher == SSH_CIPHER_NONE) |
---|
1734 | log_msg("WARNING: Encryption is disabled! Password will be transmitted in clear text."); |
---|
1735 | packet_start(SSH_CMSG_AUTH_TIS); |
---|
1736 | packet_send(); |
---|
1737 | packet_write_wait(); |
---|
1738 | |
---|
1739 | type = packet_read(); |
---|
1740 | if (type == SSH_SMSG_FAILURE) { |
---|
1741 | /* Authentication failure : either the authentication server is */ |
---|
1742 | /* not accessible (or unknown) or the user is not registered on */ |
---|
1743 | /* the authentication server. Try next authentication method. */ |
---|
1744 | debug("User cannot be identifier on authentication server."); |
---|
1745 | } else { |
---|
1746 | if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) { |
---|
1747 | packet_disconnect("Protocol error: got %d in response to TIS auth request", |
---|
1748 | type); |
---|
1749 | } |
---|
1750 | prompt = packet_get_string(NULL); |
---|
1751 | /* Asks for password */ |
---|
1752 | password = read_passphrase(pw->pw_uid, prompt, 0); |
---|
1753 | packet_start(SSH_CMSG_AUTH_TIS_RESPONSE); |
---|
1754 | packet_put_string(password, strlen(password)); |
---|
1755 | memset(password, 0, strlen(password)); |
---|
1756 | xfree(password); |
---|
1757 | packet_send(); |
---|
1758 | packet_write_wait(); |
---|
1759 | |
---|
1760 | type = packet_read(); |
---|
1761 | if (type == SSH_SMSG_SUCCESS) |
---|
1762 | return; /* Successful connection. */ |
---|
1763 | if (type != SSH_SMSG_FAILURE) |
---|
1764 | packet_disconnect("Protocol error: got %d in response to TIS auth", |
---|
1765 | type); |
---|
1766 | } |
---|
1767 | } |
---|
1768 | |
---|
1769 | /* Try password authentication if the server supports it. */ |
---|
1770 | if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && |
---|
1771 | options->password_authentication && !options->batch_mode) |
---|
1772 | { |
---|
1773 | char prompt[80]; |
---|
1774 | debug("Doing password authentication."); |
---|
1775 | if (options->cipher == SSH_CIPHER_NONE) |
---|
1776 | log_msg("WARNING: Encryption is disabled! Password will be transmitted in clear text."); |
---|
1777 | if (options->password_prompt_login && options->password_prompt_host) |
---|
1778 | sprintf(prompt, "%.30s@%.30s's password: ", server_user, host); |
---|
1779 | else if (!options->password_prompt_login && |
---|
1780 | !options->password_prompt_host) |
---|
1781 | sprintf(prompt, "Password: "); |
---|
1782 | else if (options->password_prompt_login) |
---|
1783 | sprintf(prompt, "%.30s's password: ", server_user); |
---|
1784 | else |
---|
1785 | sprintf(prompt, "%.30s password: ", host); |
---|
1786 | |
---|
1787 | for(i = 0; i < options->number_of_password_prompts; i++) |
---|
1788 | { |
---|
1789 | password = read_passphrase(pw->pw_uid, prompt, 0); |
---|
1790 | packet_start(SSH_CMSG_AUTH_PASSWORD); |
---|
1791 | packet_put_string(password, strlen(password)); |
---|
1792 | memset(password, 0, strlen(password)); |
---|
1793 | xfree(password); |
---|
1794 | packet_send(); |
---|
1795 | packet_write_wait(); |
---|
1796 | |
---|
1797 | type = packet_read(); |
---|
1798 | if (type == SSH_SMSG_SUCCESS) |
---|
1799 | return; /* Successful connection. */ |
---|
1800 | if (type != SSH_SMSG_FAILURE) |
---|
1801 | packet_disconnect("Protocol error: got %d in response to passwd auth", |
---|
1802 | type); |
---|
1803 | } |
---|
1804 | } |
---|
1805 | |
---|
1806 | /* All authentication methods have failed. Exit with an error message. */ |
---|
1807 | fatal("Permission denied."); |
---|
1808 | /*NOTREACHED*/ |
---|
1809 | } |
---|