blob: 80e4aff4a34c66bca35c3ee9f597b3c8116cf068 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3sshconnect.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Sat Mar 18 22:15:47 1995 ylo
11
12Code to connect to a remote host, and to perform the client side of the
13login (authentication) dialog.
14
15*/
16
Damien Miller7f6ea021999-10-28 13:25:17 +100017#include "config.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100018#include "includes.h"
Damien Miller6d7b2cd1999-11-12 15:19:27 +110019RCSID("$Id: sshconnect.c,v 1.6 1999/11/12 04:19:27 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100020
Damien Miller7f6ea021999-10-28 13:25:17 +100021#ifdef HAVE_OPENSSL
Damien Millerd4a8b7e1999-10-27 13:42:43 +100022#include <openssl/bn.h>
Damien Miller7f6ea021999-10-28 13:25:17 +100023#include <openssl/md5.h>
24#endif
25#ifdef HAVE_SSL
26#include <ssl/bn.h>
27#include <ssl/md5.h>
28#endif
29
Damien Millerd4a8b7e1999-10-27 13:42:43 +100030#include "xmalloc.h"
31#include "rsa.h"
32#include "ssh.h"
33#include "packet.h"
34#include "authfd.h"
35#include "cipher.h"
36#include "mpaux.h"
37#include "uidswap.h"
38#include "compat.h"
Damien Miller6d7b2cd1999-11-12 15:19:27 +110039#include "readconf.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100040
41/* Session id for the current session. */
42unsigned char session_id[16];
43
44/* Connect to the given ssh server using a proxy command. */
45
46int
47ssh_proxy_connect(const char *host, int port, uid_t original_real_uid,
48 const char *proxy_command)
49{
50 Buffer command;
51 const char *cp;
52 char *command_string;
53 int pin[2], pout[2];
54 int pid;
55 char portstring[100];
56
57 /* Convert the port number into a string. */
58 snprintf(portstring, sizeof portstring, "%d", port);
59
60 /* Build the final command string in the buffer by making the appropriate
61 substitutions to the given proxy command. */
62 buffer_init(&command);
63 for (cp = proxy_command; *cp; cp++)
64 {
65 if (cp[0] == '%' && cp[1] == '%')
66 {
67 buffer_append(&command, "%", 1);
68 cp++;
69 continue;
70 }
71 if (cp[0] == '%' && cp[1] == 'h')
72 {
73 buffer_append(&command, host, strlen(host));
74 cp++;
75 continue;
76 }
77 if (cp[0] == '%' && cp[1] == 'p')
78 {
79 buffer_append(&command, portstring, strlen(portstring));
80 cp++;
81 continue;
82 }
83 buffer_append(&command, cp, 1);
84 }
85 buffer_append(&command, "\0", 1);
86
87 /* Get the final command string. */
88 command_string = buffer_ptr(&command);
89
90 /* Create pipes for communicating with the proxy. */
91 if (pipe(pin) < 0 || pipe(pout) < 0)
92 fatal("Could not create pipes to communicate with the proxy: %.100s",
93 strerror(errno));
94
95 debug("Executing proxy command: %.500s", command_string);
96
97 /* Fork and execute the proxy command. */
98 if ((pid = fork()) == 0)
99 {
100 char *argv[10];
101
102 /* Child. Permanently give up superuser privileges. */
103 permanently_set_uid(original_real_uid);
104
105 /* Redirect stdin and stdout. */
106 close(pin[1]);
107 if (pin[0] != 0)
108 {
109 if (dup2(pin[0], 0) < 0)
110 perror("dup2 stdin");
111 close(pin[0]);
112 }
113 close(pout[0]);
114 if (dup2(pout[1], 1) < 0)
115 perror("dup2 stdout");
116 close(pout[1]); /* Cannot be 1 because pin allocated two descriptors. */
117
118 /* Stderr is left as it is so that error messages get printed on
119 the user's terminal. */
120 argv[0] = "/bin/sh";
121 argv[1] = "-c";
122 argv[2] = command_string;
123 argv[3] = NULL;
124
125 /* Execute the proxy command. Note that we gave up any extra
126 privileges above. */
127 execv("/bin/sh", argv);
128 perror("/bin/sh");
129 exit(1);
130 }
131 /* Parent. */
132 if (pid < 0)
133 fatal("fork failed: %.100s", strerror(errno));
134
135 /* Close child side of the descriptors. */
136 close(pin[0]);
137 close(pout[1]);
138
139 /* Free the command name. */
140 buffer_free(&command);
141
142 /* Set the connection file descriptors. */
143 packet_set_connection(pout[0], pin[1]);
144
145 return 1;
146}
147
148/* Creates a (possibly privileged) socket for use as the ssh connection. */
149
150int ssh_create_socket(uid_t original_real_uid, int privileged)
151{
152 int sock;
153
154 /* If we are running as root and want to connect to a privileged port,
155 bind our own socket to a privileged port. */
156 if (privileged)
157 {
158 int p = IPPORT_RESERVED - 1;
159
160 sock = rresvport(&p);
161 if (sock < 0)
162 fatal("rresvport: %.100s", strerror(errno));
163 debug("Allocated local port %d.", p);
164 }
165 else
166 {
167 /* Just create an ordinary socket on arbitrary port. We use the
168 user's uid to create the socket. */
169 temporarily_use_uid(original_real_uid);
170 sock = socket(AF_INET, SOCK_STREAM, 0);
171 if (sock < 0)
172 fatal("socket: %.100s", strerror(errno));
173 restore_uid();
174 }
175 return sock;
176}
177
178/* Opens a TCP/IP connection to the remote server on the given host. If
179 port is 0, the default port will be used. If anonymous is zero,
180 a privileged port will be allocated to make the connection.
181 This requires super-user privileges if anonymous is false.
182 Connection_attempts specifies the maximum number of tries (one per
183 second). If proxy_command is non-NULL, it specifies the command (with %h
184 and %p substituted for host and port, respectively) to use to contact
185 the daemon. */
186
187int ssh_connect(const char *host, struct sockaddr_in *hostaddr,
188 int port, int connection_attempts,
189 int anonymous, uid_t original_real_uid,
190 const char *proxy_command)
191{
192 int sock = -1, attempt, i;
193 int on = 1;
194 struct servent *sp;
195 struct hostent *hp;
196 struct linger linger;
197
198 debug("ssh_connect: getuid %d geteuid %d anon %d",
199 (int)getuid(), (int)geteuid(), anonymous);
200
201 /* Get default port if port has not been set. */
202 if (port == 0)
203 {
204 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
205 if (sp)
206 port = ntohs(sp->s_port);
207 else
208 port = SSH_DEFAULT_PORT;
209 }
210
211 /* If a proxy command is given, connect using it. */
212 if (proxy_command != NULL)
213 return ssh_proxy_connect(host, port, original_real_uid, proxy_command);
214
215 /* No proxy command. */
216
217 /* No host lookup made yet. */
218 hp = NULL;
219
220 /* Try to connect several times. On some machines, the first time will
221 sometimes fail. In general socket code appears to behave quite
222 magically on many machines. */
223 for (attempt = 0; attempt < connection_attempts; attempt++)
224 {
225 if (attempt > 0)
226 debug("Trying again...");
227
228 /* Try to parse the host name as a numeric inet address. */
229 memset(hostaddr, 0, sizeof(hostaddr));
230 hostaddr->sin_family = AF_INET;
231 hostaddr->sin_port = htons(port);
232 hostaddr->sin_addr.s_addr = inet_addr(host);
233 if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff)
234 {
235 /* Valid numeric IP address */
236 debug("Connecting to %.100s port %d.",
237 inet_ntoa(hostaddr->sin_addr), port);
238
239 /* Create a socket. */
240 sock = ssh_create_socket(original_real_uid,
241 !anonymous && geteuid() == 0 &&
242 port < IPPORT_RESERVED);
243
244 /* Connect to the host. We use the user's uid in the hope that
245 it will help with the problems of tcp_wrappers showing the
246 remote uid as root. */
247 temporarily_use_uid(original_real_uid);
248 if (connect(sock, (struct sockaddr *)hostaddr, sizeof(*hostaddr))
249 >= 0)
250 {
251 /* Successful connect. */
252 restore_uid();
253 break;
254 }
255 debug("connect: %.100s", strerror(errno));
256 restore_uid();
257
258 /* Destroy the failed socket. */
259 shutdown(sock, SHUT_RDWR);
260 close(sock);
261 }
262 else
263 {
264 /* Not a valid numeric inet address. */
265 /* Map host name to an address. */
266 if (!hp)
267 hp = gethostbyname(host);
268 if (!hp)
269 fatal("Bad host name: %.100s", host);
270 if (!hp->h_addr_list[0])
271 fatal("Host does not have an IP address: %.100s", host);
272
273 /* Loop through addresses for this host, and try each one in
274 sequence until the connection succeeds. */
275 for (i = 0; hp->h_addr_list[i]; i++)
276 {
277 /* Set the address to connect to. */
278 hostaddr->sin_family = hp->h_addrtype;
279 memcpy(&hostaddr->sin_addr, hp->h_addr_list[i],
280 sizeof(hostaddr->sin_addr));
281
282 debug("Connecting to %.200s [%.100s] port %d.",
283 host, inet_ntoa(hostaddr->sin_addr), port);
284
285 /* Create a socket for connecting. */
286 sock = ssh_create_socket(original_real_uid,
287 !anonymous && geteuid() == 0 &&
288 port < IPPORT_RESERVED);
289
290 /* Connect to the host. We use the user's uid in the hope that
291 it will help with tcp_wrappers showing the remote uid as
292 root. */
293 temporarily_use_uid(original_real_uid);
294 if (connect(sock, (struct sockaddr *)hostaddr,
295 sizeof(*hostaddr)) >= 0)
296 {
297 /* Successful connection. */
298 restore_uid();
299 break;
300 }
301 debug("connect: %.100s", strerror(errno));
302 restore_uid();
303
304 /* Close the failed socket; there appear to be some problems
305 when reusing a socket for which connect() has already
306 returned an error. */
307 shutdown(sock, SHUT_RDWR);
308 close(sock);
309 }
310 if (hp->h_addr_list[i])
311 break; /* Successful connection. */
312 }
313
314 /* Sleep a moment before retrying. */
315 sleep(1);
316 }
317 /* Return failure if we didn't get a successful connection. */
318 if (attempt >= connection_attempts)
319 return 0;
320
321 debug("Connection established.");
322
323 /* Set socket options. We would like the socket to disappear as soon as
324 it has been closed for whatever reason. */
325 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
326 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on));
327 linger.l_onoff = 1;
328 linger.l_linger = 5;
329 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
330
331 /* Set the connection. */
332 packet_set_connection(sock, sock);
333
334 return 1;
335}
336
337/* Checks if the user has an authentication agent, and if so, tries to
338 authenticate using the agent. */
339
340int
341try_agent_authentication()
342{
343 int status, type, bits;
344 char *comment;
345 AuthenticationConnection *auth;
346 unsigned char response[16];
347 unsigned int i;
348 BIGNUM *e, *n, *challenge;
349
350 /* Get connection to the agent. */
351 auth = ssh_get_authentication_connection();
352 if (!auth)
353 return 0;
354
355 e = BN_new();
356 n = BN_new();
357 challenge = BN_new();
358
359 /* Loop through identities served by the agent. */
360 for (status = ssh_get_first_identity(auth, &bits, e, n, &comment);
361 status;
362 status = ssh_get_next_identity(auth, &bits, e, n, &comment))
363 {
364 int plen, clen;
365
366 /* Try this identity. */
367 debug("Trying RSA authentication via agent with '%.100s'", comment);
368 xfree(comment);
369
370 /* Tell the server that we are willing to authenticate using this key. */
371 packet_start(SSH_CMSG_AUTH_RSA);
372 packet_put_bignum(n);
373 packet_send();
374 packet_write_wait();
375
376 /* Wait for server's response. */
377 type = packet_read(&plen);
378
379 /* The server sends failure if it doesn\'t like our key or does not
380 support RSA authentication. */
381 if (type == SSH_SMSG_FAILURE)
382 {
383 debug("Server refused our key.");
384 continue;
385 }
386
387 /* Otherwise it should have sent a challenge. */
388 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
389 packet_disconnect("Protocol error during RSA authentication: %d",
390 type);
391
392 packet_get_bignum(challenge, &clen);
393
394 packet_integrity_check(plen, clen, type);
395
396 debug("Received RSA challenge from server.");
397
398 /* Ask the agent to decrypt the challenge. */
399 if (!ssh_decrypt_challenge(auth, bits, e, n, challenge,
400 session_id, 1, response))
401 {
402 /* The agent failed to authenticate this identifier although it
403 advertised it supports this. Just return a wrong value. */
404 log("Authentication agent failed to decrypt challenge.");
405 memset(response, 0, sizeof(response));
406 }
407
408 debug("Sending response to RSA challenge.");
409
410 /* Send the decrypted challenge back to the server. */
411 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
412 for (i = 0; i < 16; i++)
413 packet_put_char(response[i]);
414 packet_send();
415 packet_write_wait();
416
417 /* Wait for response from the server. */
418 type = packet_read(&plen);
419
420 /* The server returns success if it accepted the authentication. */
421 if (type == SSH_SMSG_SUCCESS)
422 {
423 debug("RSA authentication accepted by server.");
424 BN_clear_free(e);
425 BN_clear_free(n);
426 BN_clear_free(challenge);
427 return 1;
428 }
429
430 /* Otherwise it should return failure. */
431 if (type != SSH_SMSG_FAILURE)
432 packet_disconnect("Protocol error waiting RSA auth response: %d",
433 type);
434 }
435
436 BN_clear_free(e);
437 BN_clear_free(n);
438 BN_clear_free(challenge);
439
440 debug("RSA authentication using agent refused.");
441 return 0;
442}
443
444/* Computes the proper response to a RSA challenge, and sends the response to
445 the server. */
446
447void
448respond_to_rsa_challenge(BIGNUM *challenge, RSA *prv)
449{
450 unsigned char buf[32], response[16];
451 MD5_CTX md;
452 int i, len;
453
454 /* Decrypt the challenge using the private key. */
455 rsa_private_decrypt(challenge, challenge, prv);
456
457 /* Compute the response. */
458 /* The response is MD5 of decrypted challenge plus session id. */
459 len = BN_num_bytes(challenge);
Damien Millerfd7c9111999-11-08 16:15:55 +1100460 if (len <= 0 || len > sizeof(buf))
461 packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
462 len);
463
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000464 memset(buf, 0, sizeof(buf));
465 BN_bn2bin(challenge, buf + sizeof(buf) - len);
466 MD5_Init(&md);
467 MD5_Update(&md, buf, 32);
468 MD5_Update(&md, session_id, 16);
469 MD5_Final(response, &md);
470
471 debug("Sending response to host key RSA challenge.");
472
473 /* Send the response back to the server. */
474 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
475 for (i = 0; i < 16; i++)
476 packet_put_char(response[i]);
477 packet_send();
478 packet_write_wait();
479
480 memset(buf, 0, sizeof(buf));
481 memset(response, 0, sizeof(response));
482 memset(&md, 0, sizeof(md));
483}
484
485/* Checks if the user has authentication file, and if so, tries to authenticate
486 the user using it. */
487
488int
Damien Miller6d7b2cd1999-11-12 15:19:27 +1100489try_rsa_authentication(struct passwd *pw, const char *authfile)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000490{
Damien Miller6d7b2cd1999-11-12 15:19:27 +1100491 extern Options options;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000492 BIGNUM *challenge;
493 RSA *private_key;
494 RSA *public_key;
495 char *passphrase, *comment;
496 int type, i;
497 int plen, clen;
498
499 /* Try to load identification for the authentication key. */
500 public_key = RSA_new();
501 if (!load_public_key(authfile, public_key, &comment)) {
502 RSA_free(public_key);
503 return 0; /* Could not load it. Fail. */
504 }
505
506 debug("Trying RSA authentication with key '%.100s'", comment);
507
508 /* Tell the server that we are willing to authenticate using this key. */
509 packet_start(SSH_CMSG_AUTH_RSA);
510 packet_put_bignum(public_key->n);
511 packet_send();
512 packet_write_wait();
513
514 /* We no longer need the public key. */
515 RSA_free(public_key);
516
517 /* Wait for server's response. */
518 type = packet_read(&plen);
519
520 /* The server responds with failure if it doesn\'t like our key or doesn\'t
521 support RSA authentication. */
522 if (type == SSH_SMSG_FAILURE)
523 {
524 debug("Server refused our key.");
525 xfree(comment);
526 return 0; /* Server refuses to authenticate with this key. */
527 }
528
529 /* Otherwise, the server should respond with a challenge. */
530 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
531 packet_disconnect("Protocol error during RSA authentication: %d", type);
532
533 /* Get the challenge from the packet. */
534 challenge = BN_new();
535 packet_get_bignum(challenge, &clen);
536
537 packet_integrity_check(plen, clen, type);
538
539 debug("Received RSA challenge from server.");
540
541 private_key = RSA_new();
542 /* Load the private key. Try first with empty passphrase; if it fails,
543 ask for a passphrase. */
544 if (!load_private_key(authfile, "", private_key, NULL))
545 {
546 char buf[300];
547 /* Request passphrase from the user. We read from /dev/tty to make
548 this work even if stdin has been redirected. If running in
549 batch mode, we just use the empty passphrase, which will fail and
550 return. */
551 snprintf(buf, sizeof buf,
552 "Enter passphrase for RSA key '%.100s': ", comment);
Damien Miller6d7b2cd1999-11-12 15:19:27 +1100553 if (!options.batch_mode)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000554 passphrase = read_passphrase(buf, 0);
555 else
556 {
557 debug("Will not query passphrase for %.100s in batch mode.",
558 comment);
559 passphrase = xstrdup("");
560 }
561
562 /* Load the authentication file using the pasphrase. */
563 if (!load_private_key(authfile, passphrase, private_key, NULL))
564 {
565 memset(passphrase, 0, strlen(passphrase));
566 xfree(passphrase);
567 error("Bad passphrase.");
568
569 /* Send a dummy response packet to avoid protocol error. */
570 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
571 for (i = 0; i < 16; i++)
572 packet_put_char(0);
573 packet_send();
574 packet_write_wait();
575
576 /* Expect the server to reject it... */
577 packet_read_expect(&plen, SSH_SMSG_FAILURE);
578 xfree(comment);
579 return 0;
580 }
581
582 /* Destroy the passphrase. */
583 memset(passphrase, 0, strlen(passphrase));
584 xfree(passphrase);
585 }
586
587 /* We no longer need the comment. */
588 xfree(comment);
589
590 /* Compute and send a response to the challenge. */
591 respond_to_rsa_challenge(challenge, private_key);
592
593 /* Destroy the private key. */
594 RSA_free(private_key);
595
596 /* We no longer need the challenge. */
597 BN_clear_free(challenge);
598
599 /* Wait for response from the server. */
600 type = packet_read(&plen);
601 if (type == SSH_SMSG_SUCCESS)
602 {
603 debug("RSA authentication accepted by server.");
604 return 1;
605 }
606 if (type != SSH_SMSG_FAILURE)
607 packet_disconnect("Protocol error waiting RSA auth response: %d", type);
608 debug("RSA authentication refused.");
609 return 0;
610}
611
612/* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
613 authentication and RSA host authentication. */
614
615int
616try_rhosts_rsa_authentication(const char *local_user, RSA *host_key)
617{
618 int type;
619 BIGNUM *challenge;
620 int plen, clen;
621
622 debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
623
624 /* Tell the server that we are willing to authenticate using this key. */
625 packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
626 packet_put_string(local_user, strlen(local_user));
627 packet_put_int(BN_num_bits(host_key->n));
628 packet_put_bignum(host_key->e);
629 packet_put_bignum(host_key->n);
630 packet_send();
631 packet_write_wait();
632
633 /* Wait for server's response. */
634 type = packet_read(&plen);
635
636 /* The server responds with failure if it doesn't admit our .rhosts
637 authentication or doesn't know our host key. */
638 if (type == SSH_SMSG_FAILURE)
639 {
640 debug("Server refused our rhosts authentication or host key.");
641 return 0; /* Server refuses to authenticate us with this method. */
642 }
643
644 /* Otherwise, the server should respond with a challenge. */
645 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
646 packet_disconnect("Protocol error during RSA authentication: %d", type);
647
648 /* Get the challenge from the packet. */
649 challenge = BN_new();
650 packet_get_bignum(challenge, &clen);
651
652 packet_integrity_check(plen, clen, type);
653
654 debug("Received RSA challenge for host key from server.");
655
656 /* Compute a response to the challenge. */
657 respond_to_rsa_challenge(challenge, host_key);
658
659 /* We no longer need the challenge. */
660 BN_clear_free(challenge);
661
662 /* Wait for response from the server. */
663 type = packet_read(&plen);
664 if (type == SSH_SMSG_SUCCESS)
665 {
666 debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
667 return 1;
668 }
669 if (type != SSH_SMSG_FAILURE)
670 packet_disconnect("Protocol error waiting RSA auth response: %d", type);
671 debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
672 return 0;
673}
674
675#ifdef KRB4
676int try_kerberos_authentication()
677{
678 KTEXT_ST auth; /* Kerberos data */
679 char *reply;
680 char inst[INST_SZ];
681 char *realm;
682 CREDENTIALS cred;
683 int r, type, plen;
684 Key_schedule schedule;
685 u_long checksum, cksum;
686 MSG_DAT msg_data;
687 struct sockaddr_in local, foreign;
688 struct stat st;
689
690 /* Don't do anything if we don't have any tickets. */
691 if (stat(tkt_string(), &st) < 0) return 0;
692
693 strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
694
695 realm = (char *)krb_realmofhost(get_canonical_hostname());
696 if (!realm) {
697 debug("Kerberos V4: no realm for %s", get_canonical_hostname());
698 return 0;
699 }
700 /* This can really be anything. */
701 checksum = (u_long) getpid();
702
703 r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
704 if (r != KSUCCESS) {
705 debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
706 return 0;
707 }
708 /* Get session key to decrypt the server's reply with. */
709 r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
710 if (r != KSUCCESS) {
711 debug("get_cred failed: %s", krb_err_txt[r]);
712 return 0;
713 }
714 des_key_sched((des_cblock *)cred.session, schedule);
715
716 /* Send authentication info to server. */
717 packet_start(SSH_CMSG_AUTH_KERBEROS);
718 packet_put_string((char *)auth.dat, auth.length);
719 packet_send();
720 packet_write_wait();
721
722 /* Zero the buffer. */
723 (void) memset(auth.dat, 0, MAX_KTXT_LEN);
724
725 r = sizeof(local);
726 memset(&local, 0, sizeof(local));
727 if (getsockname(packet_get_connection_in(),
728 (struct sockaddr *) &local, &r) < 0)
729 debug("getsockname failed: %s", strerror(errno));
730
731 r = sizeof(foreign);
732 memset(&foreign, 0, sizeof(foreign));
733 if (getpeername(packet_get_connection_in(),
734 (struct sockaddr *)&foreign, &r) < 0)
735 debug("getpeername failed: %s", strerror(errno));
736
737 /* Get server reply. */
738 type = packet_read(&plen);
739 switch(type) {
740
741 case SSH_SMSG_FAILURE: /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
742 debug("Kerberos V4 authentication failed.");
743 return 0;
744 break;
745
746 case SSH_SMSG_AUTH_KERBEROS_RESPONSE: /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
747 debug("Kerberos V4 authentication accepted.");
748
749 /* Get server's response. */
750 reply = packet_get_string((unsigned int *)&auth.length);
751 memcpy(auth.dat, reply, auth.length);
752 xfree(reply);
753
754 packet_integrity_check(plen, 4 + auth.length, type);
755
756 /* If his response isn't properly encrypted with the session key,
757 and the decrypted checksum fails to match, he's bogus. Bail out. */
758 r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
759 &foreign, &local, &msg_data);
760 if (r != KSUCCESS) {
761 debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
762 packet_disconnect("Kerberos V4 challenge failed!");
763 }
764 /* Fetch the (incremented) checksum that we supplied in the request. */
765 (void)memcpy((char *)&cksum, (char *)msg_data.app_data, sizeof(cksum));
766 cksum = ntohl(cksum);
767
768 /* If it matches, we're golden. */
769 if (cksum == checksum + 1) {
770 debug("Kerberos V4 challenge successful.");
771 return 1;
772 }
773 else
774 packet_disconnect("Kerberos V4 challenge failed!");
775 break;
776
777 default:
778 packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
779 }
780 return 0;
781}
782#endif /* KRB4 */
783
784#ifdef AFS
785int send_kerberos_tgt()
786{
787 CREDENTIALS *creds;
788 char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
789 int r, type, plen;
790 unsigned char buffer[8192];
791 struct stat st;
792
793 /* Don't do anything if we don't have any tickets. */
794 if (stat(tkt_string(), &st) < 0) return 0;
795
796 creds = xmalloc(sizeof(*creds));
797
798 if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
799 debug("Kerberos V4 tf_fullname failed: %s",krb_err_txt[r]);
800 return 0;
801 }
802 if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
803 debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
804 return 0;
805 }
806 if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
807 debug("Kerberos V4 ticket expired: %s", TKT_FILE);
808 return 0;
809 }
810
811 creds_to_radix(creds, buffer);
812 xfree(creds);
813
814 packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
815 packet_put_string((char *)buffer, strlen(buffer));
816 packet_send();
817 packet_write_wait();
818
819 type = packet_read(&plen);
820
821 if (type == SSH_SMSG_FAILURE)
822 debug("Kerberos TGT for realm %s rejected.", prealm);
823 else if (type != SSH_SMSG_SUCCESS)
824 packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
825
826 return 1;
827}
828
829void send_afs_tokens(void)
830{
831 CREDENTIALS creds;
832 struct ViceIoctl parms;
833 struct ClearToken ct;
834 int i, type, len, plen;
835 char buf[2048], *p, *server_cell;
836 unsigned char buffer[8192];
837
838 /* Move over ktc_GetToken, here's something leaner. */
839 for (i = 0; i < 100; i++) { /* just in case */
840 parms.in = (char *)&i;
841 parms.in_size = sizeof(i);
842 parms.out = buf;
843 parms.out_size = sizeof(buf);
844 if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) break;
845 p = buf;
846
847 /* Get secret token. */
848 memcpy(&creds.ticket_st.length, p, sizeof(unsigned int));
849 if (creds.ticket_st.length > MAX_KTXT_LEN) break;
850 p += sizeof(unsigned int);
851 memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
852 p += creds.ticket_st.length;
853
854 /* Get clear token. */
855 memcpy(&len, p, sizeof(len));
856 if (len != sizeof(struct ClearToken)) break;
857 p += sizeof(len);
858 memcpy(&ct, p, len);
859 p += len;
860 p += sizeof(len); /* primary flag */
861 server_cell = p;
862
863 /* Flesh out our credentials. */
864 strlcpy(creds.service, "afs", sizeof creds.service);
865 creds.instance[0] = '\0';
866 strlcpy(creds.realm, server_cell, REALM_SZ);
867 memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
868 creds.issue_date = ct.BeginTimestamp;
869 creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
870 creds.kvno = ct.AuthHandle;
871 snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
872 creds.pinst[0] = '\0';
873
874 /* Encode token, ship it off. */
875 if (!creds_to_radix(&creds, buffer)) break;
876 packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
877 packet_put_string((char *)buffer, strlen(buffer));
878 packet_send();
879 packet_write_wait();
880
881 /* Roger, Roger. Clearance, Clarence. What's your vector, Victor? */
882 type = packet_read(&plen);
883
884 if (type == SSH_SMSG_FAILURE)
885 debug("AFS token for cell %s rejected.", server_cell);
886 else if (type != SSH_SMSG_SUCCESS)
887 packet_disconnect("Protocol error on AFS token response: %d", type);
888 }
889}
890#endif /* AFS */
891
892/* Waits for the server identification string, and sends our own identification
893 string. */
894
895void ssh_exchange_identification()
896{
897 char buf[256], remote_version[256]; /* must be same size! */
898 int remote_major, remote_minor, i;
899 int connection_in = packet_get_connection_in();
900 int connection_out = packet_get_connection_out();
901 extern Options options;
902
903 /* Read other side\'s version identification. */
904 for (i = 0; i < sizeof(buf) - 1; i++)
905 {
906 if (read(connection_in, &buf[i], 1) != 1)
907 fatal("read: %.100s", strerror(errno));
908 if (buf[i] == '\r')
909 {
910 buf[i] = '\n';
911 buf[i + 1] = 0;
912 break;
913 }
914 if (buf[i] == '\n')
915 {
916 buf[i + 1] = 0;
917 break;
918 }
919 }
920 buf[sizeof(buf) - 1] = 0;
921
922 /* Check that the versions match. In future this might accept several
923 versions and set appropriate flags to handle them. */
924 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
925 remote_version) != 3)
926 fatal("Bad remote protocol version identification: '%.100s'", buf);
927 debug("Remote protocol version %d.%d, remote software version %.100s",
928 remote_major, remote_minor, remote_version);
929
930 /* Check if the remote protocol version is too old. */
931 if (remote_major == 1 && remote_minor < 3)
932 fatal("Remote machine has too old SSH software version.");
933
934 /* We speak 1.3, too. */
935 if (remote_major == 1 && remote_minor == 3) {
936 enable_compat13();
937 if (options.forward_agent && strcmp(remote_version, SSH_VERSION) != 0) {
938 log("Agent forwarding disabled, remote version '%s' is not compatible.",
939 remote_version);
940 options.forward_agent = 0;
941 }
942 }
943#if 0
944 /* Removed for now, to permit compatibility with latter versions. The server
945 will reject our version and disconnect if it doesn't support it. */
946 if (remote_major != PROTOCOL_MAJOR)
947 fatal("Protocol major versions differ: %d vs. %d",
948 PROTOCOL_MAJOR, remote_major);
949#endif
950
951 /* Send our own protocol version identification. */
952 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
953 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
954 if (write(connection_out, buf, strlen(buf)) != strlen(buf))
955 fatal("write: %.100s", strerror(errno));
956}
957
958int ssh_cipher_default = SSH_CIPHER_3DES;
959
960int read_yes_or_no(const char *prompt, int defval)
961{
962 char buf[1024];
963 FILE *f;
964 int retval = -1;
965
966 if (isatty(0))
967 f = stdin;
968 else
969 f = fopen("/dev/tty", "rw");
970
971 if (f == NULL)
972 return 0;
973
974 fflush(stdout);
975
976 while (1)
977 {
978 fprintf(stderr, "%s", prompt);
979 if (fgets(buf, sizeof(buf), f) == NULL)
980 {
981 /* Print a newline (the prompt probably didn\'t have one). */
982 fprintf(stderr, "\n");
983 strlcpy(buf, "no", sizeof buf);
984 }
985 /* Remove newline from response. */
986 if (strchr(buf, '\n'))
987 *strchr(buf, '\n') = 0;
988
989 if (buf[0] == 0)
990 retval = defval;
991 if (strcmp(buf, "yes") == 0)
992 retval = 1;
993 if (strcmp(buf, "no") == 0)
994 retval = 0;
995
996 if (retval != -1)
997 {
998 if (f != stdin)
999 fclose(f);
1000 return retval;
1001 }
1002 }
1003}
1004
1005/* Starts a dialog with the server, and authenticates the current user on the
1006 server. This does not need any extra privileges. The basic connection
1007 to the server must already have been established before this is called.
1008 User is the remote user; if it is NULL, the current local user name will
1009 be used. Anonymous indicates that no rhosts authentication will be used.
1010 If login fails, this function prints an error and never returns.
1011 This function does not require super-user privileges. */
1012
1013void ssh_login(int host_key_valid,
1014 RSA *own_host_key,
1015 const char *orighost,
1016 struct sockaddr_in *hostaddr,
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001017 uid_t original_real_uid)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001018{
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001019 extern Options options;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001020 int i, type;
1021 char *password;
1022 struct passwd *pw;
1023 BIGNUM *key;
1024 RSA *host_key, *file_key;
1025 RSA *public_key;
Damien Millerda217a01999-11-09 10:35:52 +11001026 int bits, rbits;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001027 unsigned char session_key[SSH_SESSION_KEY_LENGTH];
1028 const char *server_user, *local_user;
1029 char *cp, *host, *ip = NULL;
1030 unsigned char check_bytes[8];
1031 unsigned int supported_ciphers, supported_authentications, protocol_flags;
1032 HostStatus host_status;
1033 HostStatus ip_status;
1034 int host_ip_differ = 0;
1035 int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
1036 int payload_len, clen, sum_len = 0;
1037 u_int32_t rand = 0;
1038
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001039 if (options.check_host_ip)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001040 ip = xstrdup(inet_ntoa(hostaddr->sin_addr));
1041
1042 /* Convert the user-supplied hostname into all lowercase. */
1043 host = xstrdup(orighost);
1044 for (cp = host; *cp; cp++)
1045 if (isupper(*cp))
1046 *cp = tolower(*cp);
1047
1048 /* Exchange protocol version identification strings with the server. */
1049 ssh_exchange_identification();
1050
1051 /* Put the connection into non-blocking mode. */
1052 packet_set_nonblocking();
1053
1054 /* Get local user name. Use it as server user if no user name
1055 was given. */
1056 pw = getpwuid(original_real_uid);
1057 if (!pw)
1058 fatal("User id %d not found from user database.", original_real_uid);
1059 local_user = xstrdup(pw->pw_name);
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001060 server_user = options.user ? options.user : local_user;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001061
1062 debug("Waiting for server public key.");
1063
1064 /* Wait for a public key packet from the server. */
1065 packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
1066
1067 /* Get check bytes from the packet. */
1068 for (i = 0; i < 8; i++)
1069 check_bytes[i] = packet_get_char();
1070
1071 /* Get the public key. */
1072 public_key = RSA_new();
Damien Millerda217a01999-11-09 10:35:52 +11001073 bits = packet_get_int(); /* bits */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001074 public_key->e = BN_new();
1075 packet_get_bignum(public_key->e, &clen);
1076 sum_len += clen;
1077 public_key->n = BN_new();
1078 packet_get_bignum(public_key->n, &clen);
1079 sum_len += clen;
1080
Damien Millerda217a01999-11-09 10:35:52 +11001081 rbits = BN_num_bits(public_key->n);
1082 if (bits != rbits) {
1083 log("Warning: Server lies about size of server public key,");
1084 log("Warning: this may be due to an old implementation of ssh.");
1085 log("Warning: (actual size %d bits, announced size %d bits)", rbits, bits);
1086 }
1087
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001088 /* Get the host key. */
1089 host_key = RSA_new();
Damien Millerda217a01999-11-09 10:35:52 +11001090 bits = packet_get_int(); /* bits */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001091 host_key->e = BN_new();
1092 packet_get_bignum(host_key->e, &clen);
1093 sum_len += clen;
1094 host_key->n = BN_new();
1095 packet_get_bignum(host_key->n, &clen);
1096 sum_len += clen;
1097
Damien Millerda217a01999-11-09 10:35:52 +11001098 rbits = BN_num_bits(host_key->n);
1099 if (bits != rbits) {
1100 log("Warning: Server lies about size of server host key,");
1101 log("Warning: this may be due to an old implementation of ssh.");
1102 log("Warning: (actual size %d bits, announced size %d bits)", rbits, bits);
1103 }
1104
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001105 /* Store the host key from the known host file in here
1106 * so that we can compare it with the key for the IP
1107 * address. */
1108 file_key = RSA_new();
1109 file_key->n = BN_new();
1110 file_key->e = BN_new();
1111
1112 /* Get protocol flags. */
1113 protocol_flags = packet_get_int();
1114 packet_set_protocol_flags(protocol_flags);
1115
1116 /* Get supported cipher types. */
1117 supported_ciphers = packet_get_int();
1118
1119 /* Get supported authentication types. */
1120 supported_authentications = packet_get_int();
1121
1122 debug("Received server public key (%d bits) and host key (%d bits).",
1123 BN_num_bits(public_key->n), BN_num_bits(host_key->n));
1124
1125 packet_integrity_check(payload_len,
1126 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
1127 SSH_SMSG_PUBLIC_KEY);
1128
1129 /* Compute the session id. */
1130 compute_session_id(session_id, check_bytes,
1131 BN_num_bits(host_key->n), host_key->n,
1132 BN_num_bits(public_key->n), public_key->n);
1133
1134 /* Check if the host key is present in the user\'s list of known hosts
1135 or in the systemwide list. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001136 host_status = check_host_in_hostfile(options.user_hostfile,
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001137 host, BN_num_bits(host_key->n),
1138 host_key->e, host_key->n,
1139 file_key->e, file_key->n);
1140 if (host_status == HOST_NEW)
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001141 host_status = check_host_in_hostfile(options.system_hostfile, host,
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001142 BN_num_bits(host_key->n),
1143 host_key->e, host_key->n,
1144 file_key->e, file_key->n);
1145 /* Force accepting of the host key for localhost and 127.0.0.1.
1146 The problem is that if the home directory is NFS-mounted to multiple
1147 machines, localhost will refer to a different machine in each of them,
1148 and the user will get bogus HOST_CHANGED warnings. This essentially
1149 disables host authentication for localhost; however, this is probably
1150 not a real problem. */
1151 if (local) {
1152 debug("Forcing accepting of host key for localhost.");
1153 host_status = HOST_OK;
1154 }
1155
1156 /* Also perform check for the ip address, skip the check if we are
1157 localhost or the hostname was an ip address to begin with */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001158 if (options.check_host_ip && !local && strcmp(host, ip)) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001159 RSA *ip_key = RSA_new();
1160 ip_key->n = BN_new();
1161 ip_key->e = BN_new();
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001162 ip_status = check_host_in_hostfile(options.user_hostfile, ip,
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001163 BN_num_bits(host_key->n),
1164 host_key->e, host_key->n,
1165 ip_key->e, ip_key->n);
1166
1167 if (ip_status == HOST_NEW)
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001168 ip_status = check_host_in_hostfile(options.system_hostfile, ip,
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001169 BN_num_bits(host_key->n),
1170 host_key->e, host_key->n,
1171 ip_key->e, ip_key->n);
1172 if (host_status == HOST_CHANGED &&
1173 (ip_status != HOST_CHANGED ||
1174 (BN_cmp(ip_key->e, file_key->e) || BN_cmp(ip_key->n, file_key->n))))
1175 host_ip_differ = 1;
1176
1177 RSA_free(ip_key);
1178 } else
1179 ip_status = host_status;
1180
1181 RSA_free(file_key);
1182
1183 switch (host_status) {
1184 case HOST_OK:
1185 /* The host is known and the key matches. */
1186 debug("Host '%.200s' is known and matches the host key.", host);
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001187 if (options.check_host_ip) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001188 if (ip_status == HOST_NEW) {
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001189 if (!add_host_to_hostfile(options.user_hostfile, ip,
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001190 BN_num_bits(host_key->n),
1191 host_key->e, host_key->n))
1192 log("Failed to add the host ip to the list of known hosts (%.30s).",
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001193 options.user_hostfile);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001194 else
1195 log("Warning: Permanently added host ip '%.30s' to the list of known hosts.", ip);
1196 } else if (ip_status != HOST_OK)
1197 log("Warning: the host key differ from the key of the ip address '%.30s' differs", ip);
1198 }
1199
1200 break;
1201 case HOST_NEW:
1202 {
1203 char hostline[1000], *hostp = hostline;
1204 /* The host is new. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001205 if (options.strict_host_key_checking == 1) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001206 /* User has requested strict host key checking. We will not
1207 add the host key automatically. The only alternative left
1208 is to abort. */
1209 fatal("No host key is known for %.200s and you have requested strict checking.", host);
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001210 } else if (options.strict_host_key_checking == 2) { /* The default */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001211 char prompt[1024];
1212 snprintf(prompt, sizeof(prompt),
1213 "The authenticity of host '%.200s' can't be established.\n"
1214 "Are you sure you want to continue connecting (yes/no)? ",
1215 host);
1216 if (!read_yes_or_no(prompt, -1))
1217 fatal("Aborted by user!\n");
1218 }
1219
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001220 if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip))
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001221 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
1222 else
1223 hostp = host;
1224
1225 /* If not in strict mode, add the key automatically to the local
1226 known_hosts file. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001227 if (!add_host_to_hostfile(options.user_hostfile, hostp,
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001228 BN_num_bits(host_key->n),
1229 host_key->e, host_key->n))
1230 log("Failed to add the host to the list of known hosts (%.500s).",
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001231 options.user_hostfile);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001232 else
1233 log("Warning: Permanently added '%.200s' to the list of known hosts.",
1234 hostp);
1235 break;
1236 }
1237 case HOST_CHANGED:
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001238 if (options.check_host_ip) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001239 if (host_ip_differ) {
1240 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1241 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
1242 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1243 error("The host key for %s has changed,", host);
1244 error("but the key for the according IP address %s has", ip);
1245 error("a different status. This could either mean that DNS");
1246 error("SPOOFING is happening or the IP address for the host");
1247 error("and its host key have changed at the same time");
1248 }
1249 }
1250
1251 /* The host key has changed. */
1252 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1253 error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @");
1254 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1255 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1256 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1257 error("It is also possible that the host key has just been changed.");
1258 error("Please contact your system administrator.");
1259 error("Add correct host key in %.100s to get rid of this message.",
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001260 options.user_hostfile);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001261
1262 /* If strict host key checking is in use, the user will have to edit
1263 the key manually and we can only abort. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001264 if (options.strict_host_key_checking)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001265 fatal("Host key for %.200s has changed and you have requested strict checking.", host);
1266
1267 /* If strict host key checking has not been requested, allow the
1268 connection but without password authentication or
1269 agent forwarding. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001270 if (options.password_authentication) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001271 error("Password authentication is disabled to avoid trojan horses.");
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001272 options.password_authentication = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001273 }
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001274 if (options.forward_agent) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001275 error("Agent forwarding is disabled to avoid trojan horses.");
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001276 options.forward_agent = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001277 }
1278 /* XXX Should permit the user to change to use the new id. This could
1279 be done by converting the host key to an identifying sentence, tell
1280 that the host identifies itself by that sentence, and ask the user
1281 if he/she whishes to accept the authentication. */
1282 break;
1283 }
1284
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001285 if (options.check_host_ip)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001286 xfree(ip);
1287
1288 /* Generate a session key. */
1289 arc4random_stir();
1290
1291 /* Generate an encryption key for the session. The key is a 256 bit
1292 random number, interpreted as a 32-byte key, with the least significant
1293 8 bits being the first byte of the key. */
1294 for (i = 0; i < 32; i++) {
1295 if (i % 4 == 0)
1296 rand = arc4random();
1297 session_key[i] = rand & 0xff;
1298 rand >>= 8;
1299 }
1300
1301 /* According to the protocol spec, the first byte of the session key is
1302 the highest byte of the integer. The session key is xored with the
1303 first 16 bytes of the session id. */
1304 key = BN_new();
1305 BN_set_word(key, 0);
1306 for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++)
1307 {
1308 BN_lshift(key, key, 8);
1309 if (i < 16)
1310 BN_add_word(key, session_key[i] ^ session_id[i]);
1311 else
1312 BN_add_word(key, session_key[i]);
1313 }
1314
1315 /* Encrypt the integer using the public key and host key of the server
1316 (key with smaller modulus first). */
1317 if (BN_cmp(public_key->n, host_key->n) < 0)
1318 {
1319 /* Public key has smaller modulus. */
Damien Millerfd7c9111999-11-08 16:15:55 +11001320 if (BN_num_bits(host_key->n) <
1321 BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
1322 fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
1323 "SSH_KEY_BITS_RESERVED %d",
1324 BN_num_bits(host_key->n),
1325 BN_num_bits(public_key->n),
1326 SSH_KEY_BITS_RESERVED);
1327 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001328
1329 rsa_public_encrypt(key, key, public_key);
1330 rsa_public_encrypt(key, key, host_key);
1331 }
1332 else
1333 {
1334 /* Host key has smaller modulus (or they are equal). */
Damien Millerfd7c9111999-11-08 16:15:55 +11001335 if (BN_num_bits(public_key->n) <
1336 BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
1337 fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
1338 "SSH_KEY_BITS_RESERVED %d",
1339 BN_num_bits(public_key->n),
1340 BN_num_bits(host_key->n),
1341 SSH_KEY_BITS_RESERVED);
1342 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001343
1344 rsa_public_encrypt(key, key, host_key);
1345 rsa_public_encrypt(key, key, public_key);
1346 }
1347
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001348 if (options.cipher == SSH_CIPHER_NOT_SET) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001349 if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default))
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001350 options.cipher = ssh_cipher_default;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001351 else {
1352 debug("Cipher %d not supported, using %.100s instead.",
1353 cipher_name(ssh_cipher_default),
1354 cipher_name(SSH_FALLBACK_CIPHER));
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001355 options.cipher = SSH_FALLBACK_CIPHER;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001356 }
1357 }
1358
1359 /* Check that the selected cipher is supported. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001360 if (!(supported_ciphers & (1 << options.cipher)))
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001361 fatal("Selected cipher type %.100s not supported by server.",
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001362 cipher_name(options.cipher));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001363
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001364 debug("Encryption type: %.100s", cipher_name(options.cipher));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001365
1366 /* Send the encrypted session key to the server. */
1367 packet_start(SSH_CMSG_SESSION_KEY);
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001368 packet_put_char(options.cipher);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001369
1370 /* Send the check bytes back to the server. */
1371 for (i = 0; i < 8; i++)
1372 packet_put_char(check_bytes[i]);
1373
1374 /* Send the encrypted encryption key. */
1375 packet_put_bignum(key);
1376
1377 /* Send protocol flags. */
1378 packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
1379
1380 /* Send the packet now. */
1381 packet_send();
1382 packet_write_wait();
1383
1384 /* Destroy the session key integer and the public keys since we no longer
1385 need them. */
1386 BN_clear_free(key);
1387 RSA_free(public_key);
1388 RSA_free(host_key);
1389
1390 debug("Sent encrypted session key.");
1391
1392 /* Set the encryption key. */
1393 packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH,
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001394 options.cipher, 1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001395
1396 /* We will no longer need the session key here. Destroy any extra copies. */
1397 memset(session_key, 0, sizeof(session_key));
1398
1399 /* Expect a success message from the server. Note that this message will
1400 be received in encrypted form. */
1401 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
1402
1403 debug("Received encrypted confirmation.");
1404
1405 /* Send the name of the user to log in as on the server. */
1406 packet_start(SSH_CMSG_USER);
1407 packet_put_string(server_user, strlen(server_user));
1408 packet_send();
1409 packet_write_wait();
1410
1411 /* The server should respond with success if no authentication is needed
1412 (the user has no password). Otherwise the server responds with
1413 failure. */
1414 type = packet_read(&payload_len);
1415 if (type == SSH_SMSG_SUCCESS)
1416 return; /* Connection was accepted without authentication. */
1417 if (type != SSH_SMSG_FAILURE)
1418 packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
1419 type);
1420
1421#ifdef AFS
1422 /* Try Kerberos tgt passing if the server supports it. */
1423 if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001424 options.kerberos_tgt_passing)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001425 {
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001426 if (options.cipher == SSH_CIPHER_NONE)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001427 log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
1428 (void)send_kerberos_tgt();
1429 }
1430
1431 /* Try AFS token passing if the server supports it. */
1432 if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001433 options.afs_token_passing && k_hasafs()) {
1434 if (options.cipher == SSH_CIPHER_NONE)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001435 log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
1436 send_afs_tokens();
1437 }
1438#endif /* AFS */
1439
1440#ifdef KRB4
1441 if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001442 options.kerberos_authentication)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001443 {
1444 debug("Trying Kerberos authentication.");
1445 if (try_kerberos_authentication()) {
1446 /* The server should respond with success or failure. */
1447 type = packet_read(&payload_len);
1448 if (type == SSH_SMSG_SUCCESS)
1449 return; /* Successful connection. */
1450 if (type != SSH_SMSG_FAILURE)
1451 packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
1452 }
1453 }
1454#endif /* KRB4 */
1455
1456 /* Use rhosts authentication if running in privileged socket and we do not
1457 wish to remain anonymous. */
1458 if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001459 options.rhosts_authentication)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001460 {
1461 debug("Trying rhosts authentication.");
1462 packet_start(SSH_CMSG_AUTH_RHOSTS);
1463 packet_put_string(local_user, strlen(local_user));
1464 packet_send();
1465 packet_write_wait();
1466
1467 /* The server should respond with success or failure. */
1468 type = packet_read(&payload_len);
1469 if (type == SSH_SMSG_SUCCESS)
1470 return; /* Successful connection. */
1471 if (type != SSH_SMSG_FAILURE)
1472 packet_disconnect("Protocol error: got %d in response to rhosts auth",
1473 type);
1474 }
1475
1476 /* Try .rhosts or /etc/hosts.equiv authentication with RSA host
1477 authentication. */
1478 if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001479 options.rhosts_rsa_authentication && host_key_valid)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001480 {
1481 if (try_rhosts_rsa_authentication(local_user, own_host_key))
1482 return; /* Successful authentication. */
1483 }
1484
1485 /* Try RSA authentication if the server supports it. */
1486 if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001487 options.rsa_authentication)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001488 {
1489 /* Try RSA authentication using the authentication agent. The agent
1490 is tried first because no passphrase is needed for it, whereas
1491 identity files may require passphrases. */
1492 if (try_agent_authentication())
1493 return; /* Successful connection. */
1494
1495 /* Try RSA authentication for each identity. */
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001496 for (i = 0; i < options.num_identity_files; i++)
1497 if (try_rsa_authentication(pw, options.identity_files[i]))
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001498 return; /* Successful connection. */
1499 }
1500
1501 /* Try password authentication if the server supports it. */
1502 if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001503 options.password_authentication && !options.batch_mode)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001504 {
1505 char prompt[80];
1506 snprintf(prompt, sizeof(prompt), "%.30s@%.30s's password: ",
1507 server_user, host);
1508 debug("Doing password authentication.");
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001509 if (options.cipher == SSH_CIPHER_NONE)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001510 log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
Damien Miller6d7b2cd1999-11-12 15:19:27 +11001511 for (i = 0; i < options.number_of_password_prompts; i++) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001512 if (i != 0)
1513 error("Permission denied, please try again.");
1514 password = read_passphrase(prompt, 0);
1515 packet_start(SSH_CMSG_AUTH_PASSWORD);
1516 packet_put_string(password, strlen(password));
1517 memset(password, 0, strlen(password));
1518 xfree(password);
1519 packet_send();
1520 packet_write_wait();
1521
1522 type = packet_read(&payload_len);
1523 if (type == SSH_SMSG_SUCCESS)
1524 return; /* Successful connection. */
1525 if (type != SSH_SMSG_FAILURE)
1526 packet_disconnect("Protocol error: got %d in response to passwd auth", type);
1527 }
1528 }
1529
1530 /* All authentication methods have failed. Exit with an error message. */
1531 fatal("Permission denied.");
1532 /*NOTREACHED*/
1533}