sshconnect.c revision 76262
1/* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 5 * Code to connect to a remote host, and to perform the client side of the 6 * login (authentication) dialog. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 */ 14 15#include "includes.h" 16RCSID("$OpenBSD: sshconnect.c,v 1.104 2001/04/12 19:15:25 markus Exp $"); 17RCSID("$FreeBSD: head/crypto/openssh/sshconnect.c 76262 2001-05-04 04:14:23Z green $"); 18 19#include <openssl/bn.h> 20 21#include "ssh.h" 22#include "xmalloc.h" 23#include "rsa.h" 24#include "buffer.h" 25#include "packet.h" 26#include "uidswap.h" 27#include "compat.h" 28#include "key.h" 29#include "sshconnect.h" 30#include "hostfile.h" 31#include "log.h" 32#include "readconf.h" 33#include "atomicio.h" 34#include "misc.h" 35 36char *client_version_string = NULL; 37char *server_version_string = NULL; 38 39extern Options options; 40extern char *__progname; 41 42/* AF_UNSPEC or AF_INET or AF_INET6 */ 43extern int IPv4or6; 44 45/* 46 * Connect to the given ssh server using a proxy command. 47 */ 48int 49ssh_proxy_connect(const char *host, u_short port, struct passwd *pw, 50 const char *proxy_command) 51{ 52 Buffer command; 53 const char *cp; 54 char *command_string; 55 int pin[2], pout[2]; 56 pid_t pid; 57 char strport[NI_MAXSERV]; 58 59 /* Convert the port number into a string. */ 60 snprintf(strport, sizeof strport, "%hu", port); 61 62 /* Build the final command string in the buffer by making the 63 appropriate substitutions to the given proxy command. */ 64 buffer_init(&command); 65 for (cp = proxy_command; *cp; cp++) { 66 if (cp[0] == '%' && cp[1] == '%') { 67 buffer_append(&command, "%", 1); 68 cp++; 69 continue; 70 } 71 if (cp[0] == '%' && cp[1] == 'h') { 72 buffer_append(&command, host, strlen(host)); 73 cp++; 74 continue; 75 } 76 if (cp[0] == '%' && cp[1] == 'p') { 77 buffer_append(&command, strport, strlen(strport)); 78 cp++; 79 continue; 80 } 81 buffer_append(&command, cp, 1); 82 } 83 buffer_append(&command, "\0", 1); 84 85 /* Get the final command string. */ 86 command_string = buffer_ptr(&command); 87 88 /* Create pipes for communicating with the proxy. */ 89 if (pipe(pin) < 0 || pipe(pout) < 0) 90 fatal("Could not create pipes to communicate with the proxy: %.100s", 91 strerror(errno)); 92 93 debug("Executing proxy command: %.500s", command_string); 94 95 /* Fork and execute the proxy command. */ 96 if ((pid = fork()) == 0) { 97 char *argv[10]; 98 99 /* Child. Permanently give up superuser privileges. */ 100 permanently_set_uid(pw); 101 102 /* Redirect stdin and stdout. */ 103 close(pin[1]); 104 if (pin[0] != 0) { 105 if (dup2(pin[0], 0) < 0) 106 perror("dup2 stdin"); 107 close(pin[0]); 108 } 109 close(pout[0]); 110 if (dup2(pout[1], 1) < 0) 111 perror("dup2 stdout"); 112 /* Cannot be 1 because pin allocated two descriptors. */ 113 close(pout[1]); 114 115 /* Stderr is left as it is so that error messages get 116 printed on the user's terminal. */ 117 argv[0] = _PATH_BSHELL; 118 argv[1] = "-c"; 119 argv[2] = command_string; 120 argv[3] = NULL; 121 122 /* Execute the proxy command. Note that we gave up any 123 extra privileges above. */ 124 execv(argv[0], argv); 125 perror(argv[0]); 126 exit(1); 127 } 128 /* Parent. */ 129 if (pid < 0) 130 fatal("fork failed: %.100s", strerror(errno)); 131 132 /* Close child side of the descriptors. */ 133 close(pin[0]); 134 close(pout[1]); 135 136 /* Free the command name. */ 137 buffer_free(&command); 138 139 /* Set the connection file descriptors. */ 140 packet_set_connection(pout[0], pin[1]); 141 142 return 1; 143} 144 145/* 146 * Creates a (possibly privileged) socket for use as the ssh connection. 147 */ 148int 149ssh_create_socket(struct passwd *pw, int privileged, int family) 150{ 151 int sock; 152 153 /* 154 * If we are running as root and want to connect to a privileged 155 * port, bind our own socket to a privileged port. 156 */ 157 if (privileged) { 158 int p = IPPORT_RESERVED - 1; 159 sock = rresvport_af(&p, family); 160 if (sock < 0) 161 error("rresvport: af=%d %.100s", family, strerror(errno)); 162 else 163 debug("Allocated local port %d.", p); 164 } else { 165 /* 166 * Just create an ordinary socket on arbitrary port. We use 167 * the user's uid to create the socket. 168 */ 169 temporarily_use_uid(pw); 170 sock = socket(family, SOCK_STREAM, 0); 171 if (sock < 0) 172 error("socket: %.100s", strerror(errno)); 173 restore_uid(); 174 } 175 return sock; 176} 177 178/* 179 * Opens a TCP/IP connection to the remote server on the given host. 180 * The address of the remote host will be returned in hostaddr. 181 * If port is 0, the default port will be used. If anonymous is zero, 182 * a privileged port will be allocated to make the connection. 183 * This requires super-user privileges if anonymous is false. 184 * Connection_attempts specifies the maximum number of tries (one per 185 * second). If proxy_command is non-NULL, it specifies the command (with %h 186 * and %p substituted for host and port, respectively) to use to contact 187 * the daemon. 188 */ 189int 190ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 191 u_short port, int connection_attempts, 192 int anonymous, struct passwd *pw, 193 const char *proxy_command) 194{ 195 int gaierr; 196 int on = 1; 197 int sock = -1, attempt; 198 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 199 struct addrinfo hints, *ai, *aitop; 200 struct linger linger; 201 struct servent *sp; 202 203 debug("ssh_connect: getuid %u geteuid %u anon %d", 204 (u_int) getuid(), (u_int) geteuid(), anonymous); 205 206 /* Get default port if port has not been set. */ 207 if (port == 0) { 208 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 209 if (sp) 210 port = ntohs(sp->s_port); 211 else 212 port = SSH_DEFAULT_PORT; 213 } 214 /* If a proxy command is given, connect using it. */ 215 if (proxy_command != NULL) 216 return ssh_proxy_connect(host, port, pw, proxy_command); 217 218 /* No proxy command. */ 219 220 memset(&hints, 0, sizeof(hints)); 221 hints.ai_family = IPv4or6; 222 hints.ai_socktype = SOCK_STREAM; 223 snprintf(strport, sizeof strport, "%d", port); 224 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 225 fatal("%s: %.100s: %s", __progname, host, 226 gai_strerror(gaierr)); 227 228 /* 229 * Try to connect several times. On some machines, the first time 230 * will sometimes fail. In general socket code appears to behave 231 * quite magically on many machines. 232 */ 233 for (attempt = 0; attempt < connection_attempts; attempt++) { 234 if (attempt > 0) 235 debug("Trying again..."); 236 237 /* Loop through addresses for this host, and try each one in 238 sequence until the connection succeeds. */ 239 for (ai = aitop; ai; ai = ai->ai_next) { 240 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 241 continue; 242 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 243 ntop, sizeof(ntop), strport, sizeof(strport), 244 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 245 error("ssh_connect: getnameinfo failed"); 246 continue; 247 } 248 debug("Connecting to %.200s [%.100s] port %s.", 249 host, ntop, strport); 250 251 /* Create a socket for connecting. */ 252 sock = ssh_create_socket(pw, 253 !anonymous && geteuid() == 0, 254 ai->ai_family); 255 if (sock < 0) 256 continue; 257 258 /* Connect to the host. We use the user's uid in the 259 * hope that it will help with tcp_wrappers showing 260 * the remote uid as root. 261 */ 262 temporarily_use_uid(pw); 263 if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { 264 /* Successful connection. */ 265 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 266 restore_uid(); 267 break; 268 } else { 269 debug("connect: %.100s", strerror(errno)); 270 restore_uid(); 271 /* 272 * Close the failed socket; there appear to 273 * be some problems when reusing a socket for 274 * which connect() has already returned an 275 * error. 276 */ 277 shutdown(sock, SHUT_RDWR); 278 close(sock); 279 } 280 } 281 if (ai) 282 break; /* Successful connection. */ 283 284 /* Sleep a moment before retrying. */ 285 sleep(1); 286 } 287 288 freeaddrinfo(aitop); 289 290 /* Return failure if we didn't get a successful connection. */ 291 if (attempt >= connection_attempts) 292 return 0; 293 294 debug("Connection established."); 295 296 /* 297 * Set socket options. We would like the socket to disappear as soon 298 * as it has been closed for whatever reason. 299 */ 300 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ 301 linger.l_onoff = 1; 302 linger.l_linger = 5; 303 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); 304 305 /* Set keepalives if requested. */ 306 if (options.keepalives && 307 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 308 sizeof(on)) < 0) 309 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 310 311 /* Set the connection. */ 312 packet_set_connection(sock, sock); 313 314 return 1; 315} 316 317/* 318 * Waits for the server identification string, and sends our own 319 * identification string. 320 */ 321void 322ssh_exchange_identification(void) 323{ 324 char buf[256], remote_version[256]; /* must be same size! */ 325 int remote_major, remote_minor, i, mismatch; 326 int connection_in = packet_get_connection_in(); 327 int connection_out = packet_get_connection_out(); 328 int minor1 = PROTOCOL_MINOR_1; 329 330 /* Read other side\'s version identification. */ 331 for (;;) { 332 for (i = 0; i < sizeof(buf) - 1; i++) { 333 int len = atomicio(read, connection_in, &buf[i], 1); 334 if (len < 0) 335 fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); 336 if (len != 1) 337 fatal("ssh_exchange_identification: Connection closed by remote host"); 338 if (buf[i] == '\r') { 339 buf[i] = '\n'; 340 buf[i + 1] = 0; 341 continue; /**XXX wait for \n */ 342 } 343 if (buf[i] == '\n') { 344 buf[i + 1] = 0; 345 break; 346 } 347 } 348 buf[sizeof(buf) - 1] = 0; 349 if (strncmp(buf, "SSH-", 4) == 0) 350 break; 351 debug("ssh_exchange_identification: %s", buf); 352 } 353 server_version_string = xstrdup(buf); 354 355 /* 356 * Check that the versions match. In future this might accept 357 * several versions and set appropriate flags to handle them. 358 */ 359 if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n", 360 &remote_major, &remote_minor, remote_version) != 3) 361 fatal("Bad remote protocol version identification: '%.100s'", buf); 362 debug("Remote protocol version %d.%d, remote software version %.100s", 363 remote_major, remote_minor, remote_version); 364 365 compat_datafellows(remote_version); 366 mismatch = 0; 367 368 switch(remote_major) { 369 case 1: 370 if (remote_minor == 99 && 371 (options.protocol & SSH_PROTO_2) && 372 !(options.protocol & SSH_PROTO_1_PREFERRED)) { 373 enable_compat20(); 374 break; 375 } 376 if (!(options.protocol & SSH_PROTO_1)) { 377 mismatch = 1; 378 break; 379 } 380 if (remote_minor < 3) { 381 fatal("Remote machine has too old SSH software version."); 382 } else if (remote_minor == 3 || remote_minor == 4) { 383 /* We speak 1.3, too. */ 384 enable_compat13(); 385 minor1 = 3; 386 if (options.forward_agent) { 387 log("Agent forwarding disabled for protocol 1.3"); 388 options.forward_agent = 0; 389 } 390 } 391 break; 392 case 2: 393 if (options.protocol & SSH_PROTO_2) { 394 enable_compat20(); 395 break; 396 } 397 /* FALLTHROUGH */ 398 default: 399 mismatch = 1; 400 break; 401 } 402 if (mismatch) 403 fatal("Protocol major versions differ: %d vs. %d", 404 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 405 remote_major); 406 if (compat20) 407 packet_set_ssh2_format(); 408 /* Send our own protocol version identification. */ 409 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 410 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 411 compat20 ? PROTOCOL_MINOR_2 : minor1, 412 SSH_VERSION); 413 if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) 414 fatal("write: %.100s", strerror(errno)); 415 client_version_string = xstrdup(buf); 416 chop(client_version_string); 417 chop(server_version_string); 418 debug("Local version string %.100s", client_version_string); 419} 420 421/* defaults to 'no' */ 422int 423read_yes_or_no(const char *prompt, int defval) 424{ 425 char buf[1024]; 426 FILE *f; 427 int retval = -1; 428 429 if (options.batch_mode) 430 return 0; 431 432 if (isatty(STDIN_FILENO)) 433 f = stdin; 434 else 435 f = fopen(_PATH_TTY, "rw"); 436 437 if (f == NULL) 438 return 0; 439 440 fflush(stdout); 441 442 while (1) { 443 fprintf(stderr, "%s", prompt); 444 if (fgets(buf, sizeof(buf), f) == NULL) { 445 /* Print a newline (the prompt probably didn\'t have one). */ 446 fprintf(stderr, "\n"); 447 strlcpy(buf, "no", sizeof buf); 448 } 449 /* Remove newline from response. */ 450 if (strchr(buf, '\n')) 451 *strchr(buf, '\n') = 0; 452 453 if (buf[0] == 0) 454 retval = defval; 455 if (strcmp(buf, "yes") == 0) 456 retval = 1; 457 else if (strcmp(buf, "no") == 0) 458 retval = 0; 459 else 460 fprintf(stderr, "Please type 'yes' or 'no'.\n"); 461 462 if (retval != -1) { 463 if (f != stdin) 464 fclose(f); 465 return retval; 466 } 467 } 468} 469 470/* 471 * check whether the supplied host key is valid, return only if ok. 472 */ 473 474void 475check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, 476 const char *user_hostfile, const char *system_hostfile) 477{ 478 Key *file_key; 479 char *type = key_type(host_key); 480 char *ip = NULL; 481 char hostline[1000], *hostp, *fp; 482 HostStatus host_status; 483 HostStatus ip_status; 484 int local = 0, host_ip_differ = 0; 485 char ntop[NI_MAXHOST]; 486 int host_line, ip_line; 487 const char *host_file = NULL, *ip_file = NULL; 488 489 /* 490 * Force accepting of the host key for loopback/localhost. The 491 * problem is that if the home directory is NFS-mounted to multiple 492 * machines, localhost will refer to a different machine in each of 493 * them, and the user will get bogus HOST_CHANGED warnings. This 494 * essentially disables host authentication for localhost; however, 495 * this is probably not a real problem. 496 */ 497 /** hostaddr == 0! */ 498 switch (hostaddr->sa_family) { 499 case AF_INET: 500 local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 501 break; 502 case AF_INET6: 503 local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); 504 break; 505 default: 506 local = 0; 507 break; 508 } 509 if (local && options.host_key_alias == NULL) { 510 debug("Forcing accepting of host key for " 511 "loopback/localhost."); 512 return; 513 } 514 515 /* 516 * We don't have the remote ip-address for connections 517 * using a proxy command 518 */ 519 if (options.proxy_command == NULL) { 520 if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop), 521 NULL, 0, NI_NUMERICHOST) != 0) 522 fatal("check_host_key: getnameinfo failed"); 523 ip = xstrdup(ntop); 524 } else { 525 ip = xstrdup("<no hostip for proxy command>"); 526 } 527 /* 528 * Turn off check_host_ip if the connection is to localhost, via proxy 529 * command or if we don't have a hostname to compare with 530 */ 531 if (options.check_host_ip && 532 (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) 533 options.check_host_ip = 0; 534 535 /* 536 * Allow the user to record the key under a different name. This is 537 * useful for ssh tunneling over forwarded connections or if you run 538 * multiple sshd's on different ports on the same machine. 539 */ 540 if (options.host_key_alias != NULL) { 541 host = options.host_key_alias; 542 debug("using hostkeyalias: %s", host); 543 } 544 545 /* 546 * Store the host key from the known host file in here so that we can 547 * compare it with the key for the IP address. 548 */ 549 file_key = key_new(host_key->type); 550 551 /* 552 * Check if the host key is present in the user\'s list of known 553 * hosts or in the systemwide list. 554 */ 555 host_file = user_hostfile; 556 host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line); 557 if (host_status == HOST_NEW) { 558 host_file = system_hostfile; 559 host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line); 560 } 561 /* 562 * Also perform check for the ip address, skip the check if we are 563 * localhost or the hostname was an ip address to begin with 564 */ 565 if (options.check_host_ip) { 566 Key *ip_key = key_new(host_key->type); 567 568 ip_file = user_hostfile; 569 ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line); 570 if (ip_status == HOST_NEW) { 571 ip_file = system_hostfile; 572 ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line); 573 } 574 if (host_status == HOST_CHANGED && 575 (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) 576 host_ip_differ = 1; 577 578 key_free(ip_key); 579 } else 580 ip_status = host_status; 581 582 key_free(file_key); 583 584 switch (host_status) { 585 case HOST_OK: 586 /* The host is known and the key matches. */ 587 debug("Host '%.200s' is known and matches the %s host key.", 588 host, type); 589 debug("Found key in %s:%d", host_file, host_line); 590 if (options.check_host_ip && ip_status == HOST_NEW) { 591 if (!add_host_to_hostfile(user_hostfile, ip, host_key)) 592 log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).", 593 type, ip, user_hostfile); 594 else 595 log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.", 596 type, ip); 597 } 598 break; 599 case HOST_NEW: 600 /* The host is new. */ 601 if (options.strict_host_key_checking == 1) { 602 /* User has requested strict host key checking. We will not add the host key 603 automatically. The only alternative left is to abort. */ 604 fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host); 605 } else if (options.strict_host_key_checking == 2) { 606 /* The default */ 607 char prompt[1024]; 608 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 609 snprintf(prompt, sizeof(prompt), 610 "The authenticity of host '%.200s (%s)' can't be established.\n" 611 "%s key fingerprint is %s.\n" 612 "Are you sure you want to continue connecting (yes/no)? ", 613 host, ip, type, fp); 614 xfree(fp); 615 if (!read_yes_or_no(prompt, -1)) 616 fatal("Aborted by user!"); 617 } 618 if (options.check_host_ip && ip_status == HOST_NEW) { 619 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 620 hostp = hostline; 621 } else 622 hostp = host; 623 624 /* If not in strict mode, add the key automatically to the local known_hosts file. */ 625 if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) 626 log("Failed to add the host to the list of known hosts (%.500s).", 627 user_hostfile); 628 else 629 log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.", 630 hostp, type); 631 break; 632 case HOST_CHANGED: 633 if (options.check_host_ip && host_ip_differ) { 634 char *msg; 635 if (ip_status == HOST_NEW) 636 msg = "is unknown"; 637 else if (ip_status == HOST_OK) 638 msg = "is unchanged"; 639 else 640 msg = "has a different value"; 641 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 642 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 643 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 644 error("The %s host key for %s has changed,", type, host); 645 error("and the key for the according IP address %s", ip); 646 error("%s. This could either mean that", msg); 647 error("DNS SPOOFING is happening or the IP address for the host"); 648 error("and its host key have changed at the same time."); 649 if (ip_status != HOST_NEW) 650 error("Offending key for IP in %s:%d", ip_file, ip_line); 651 } 652 /* The host key has changed. */ 653 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 654 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 655 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 656 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 657 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 658 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 659 error("It is also possible that the %s host key has just been changed.", type); 660 error("The fingerprint for the %s key sent by the remote host is\n%s.", 661 type, fp); 662 error("Please contact your system administrator."); 663 error("Add correct host key in %.100s to get rid of this message.", 664 user_hostfile); 665 error("Offending key in %s:%d", host_file, host_line); 666 xfree(fp); 667 668 /* 669 * If strict host key checking is in use, the user will have 670 * to edit the key manually and we can only abort. 671 */ 672 if (options.strict_host_key_checking) 673 fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host); 674 675 /* 676 * If strict host key checking has not been requested, allow 677 * the connection but without password authentication or 678 * agent forwarding. 679 */ 680 if (options.password_authentication) { 681 error("Password authentication is disabled to avoid trojan horses."); 682 options.password_authentication = 0; 683 } 684 if (options.forward_agent) { 685 error("Agent forwarding is disabled to avoid trojan horses."); 686 options.forward_agent = 0; 687 } 688 if (options.forward_x11) { 689 error("X11 forwarding is disabled to avoid trojan horses."); 690 options.forward_x11 = 0; 691 } 692 if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) { 693 error("Port forwarding is disabled to avoid trojan horses."); 694 options.num_local_forwards = options.num_remote_forwards = 0; 695 } 696 /* 697 * XXX Should permit the user to change to use the new id. 698 * This could be done by converting the host key to an 699 * identifying sentence, tell that the host identifies itself 700 * by that sentence, and ask the user if he/she whishes to 701 * accept the authentication. 702 */ 703 break; 704 } 705 706 if (options.check_host_ip && host_status != HOST_CHANGED && 707 ip_status == HOST_CHANGED) { 708 log("Warning: the %s host key for '%.200s' " 709 "differs from the key for the IP address '%.128s'", 710 type, host, ip); 711 if (host_status == HOST_OK) 712 log("Matching host key in %s:%d", host_file, host_line); 713 log("Offending key for IP in %s:%d", ip_file, ip_line); 714 if (options.strict_host_key_checking == 1) { 715 fatal("Exiting, you have requested strict checking."); 716 } else if (options.strict_host_key_checking == 2) { 717 if (!read_yes_or_no("Are you sure you want " \ 718 "to continue connecting (yes/no)? ", -1)) 719 fatal("Aborted by user!"); 720 } 721 } 722 723 xfree(ip); 724} 725 726#ifdef KRB5 727int 728try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context) 729{ 730 krb5_error_code problem; 731 const char *tkfile; 732 struct stat buf; 733 krb5_ccache ccache = NULL; 734 const char *remotehost; 735 krb5_data ap; 736 int type, payload_len; 737 krb5_ap_rep_enc_part *reply = NULL; 738 int ret; 739 740 memset(&ap, 0, sizeof(ap)); 741 742 problem = krb5_init_context(context); 743 if (problem) { 744 ret = 0; 745 goto out; 746 } 747 748 tkfile = krb5_cc_default_name(*context); 749 if (strncmp(tkfile, "FILE:", 5) == 0) 750 tkfile += 5; 751 752 if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) { 753 debug("Kerberos V5: could not get default ccache (permission denied)."); 754 ret = 0; 755 goto out; 756 } 757 758 problem = krb5_cc_default(*context, &ccache); 759 if (problem) { 760 ret = 0; 761 goto out; 762 } 763 764 remotehost = get_canonical_hostname(); 765 766 problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED, 767 "host", remotehost, NULL, ccache, &ap); 768 if (problem) { 769 ret = 0; 770 goto out; 771 } 772 773 packet_start(SSH_CMSG_AUTH_KERBEROS); 774 packet_put_string((char *) ap.data, ap.length); 775 packet_send(); 776 packet_write_wait(); 777 778 xfree(ap.data); 779 ap.length = 0; 780 781 type = packet_read(&payload_len); 782 switch (type) { 783 case SSH_SMSG_FAILURE: 784 /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ 785 debug("Kerberos V5 authentication failed."); 786 ret = 0; 787 break; 788 789 case SSH_SMSG_AUTH_KERBEROS_RESPONSE: 790 /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ 791 debug("Kerberos V5 authentication accepted."); 792 793 /* Get server's response. */ 794 ap.data = packet_get_string((unsigned int *) &ap.length); 795 796 packet_integrity_check(payload_len, 4 + ap.length, type); 797 /* XXX je to dobre? */ 798 799 problem = krb5_rd_rep(*context, *auth_context, &ap, &reply); 800 if (problem) { 801 ret = 0; 802 } 803 ret = 1; 804 break; 805 806 default: 807 packet_disconnect("Protocol error on Kerberos V5 response: %d", type); 808 ret = 0; 809 break; 810 811 } 812 813out: 814 if (ccache != NULL) 815 krb5_cc_close(*context, ccache); 816 if (reply != NULL) 817 krb5_free_ap_rep_enc_part(*context, reply); 818 if (ap.length > 0) 819 krb5_data_free(&ap); 820 821 return ret; 822 823} 824 825void 826send_krb5_tgt(krb5_context context, krb5_auth_context auth_context) 827{ 828 int fd; 829 int type, payload_len; 830 krb5_error_code problem; 831 krb5_data outbuf; 832 krb5_ccache ccache = NULL; 833 krb5_creds creds; 834 krb5_kdc_flags flags; 835 const char* remotehost = get_canonical_hostname(); 836 837 memset(&creds, 0, sizeof(creds)); 838 memset(&outbuf, 0, sizeof(outbuf)); 839 840 fd = packet_get_connection_in(); 841 problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd); 842 if (problem) { 843 goto out; 844 } 845 846#if 0 847 tkfile = krb5_cc_default_name(context); 848 if (strncmp(tkfile, "FILE:", 5) == 0) 849 tkfile += 5; 850 851 if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) { 852 debug("Kerberos V5: could not get default ccache (permission denied)."); 853 goto out; 854 } 855#endif 856 857 problem = krb5_cc_default(context, &ccache); 858 if (problem) { 859 goto out; 860 } 861 862 problem = krb5_cc_get_principal(context, ccache, &creds.client); 863 if (problem) { 864 goto out; 865 } 866 867 problem = krb5_build_principal(context, &creds.server, 868 strlen(creds.client->realm), 869 creds.client->realm, 870 "krbtgt", 871 creds.client->realm, 872 NULL); 873 if (problem) { 874 goto out; 875 } 876 877 creds.times.endtime = 0; 878 879 flags.i = 0; 880 flags.b.forwarded = 1; 881 flags.b.forwardable = krb5_config_get_bool(context, NULL, 882 "libdefaults", "forwardable", NULL); 883 884 problem = krb5_get_forwarded_creds (context, 885 auth_context, 886 ccache, 887 flags.i, 888 remotehost, 889 &creds, 890 &outbuf); 891 if (problem) { 892 goto out; 893 } 894 895 packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); 896 packet_put_string((char *)outbuf.data, outbuf.length); 897 packet_send(); 898 packet_write_wait(); 899 900 type = packet_read(&payload_len); 901 switch (type) { 902 case SSH_SMSG_SUCCESS: 903 break; 904 case SSH_SMSG_FAILURE: 905 break; 906 default: 907 break; 908 } 909 910out: 911 if (creds.client) 912 krb5_free_principal(context, creds.client); 913 if (creds.server) 914 krb5_free_principal(context, creds.server); 915 if (ccache) 916 krb5_cc_close(context, ccache); 917 if (outbuf.data) 918 xfree(outbuf.data); 919 920 return; 921} 922#endif /* KRB5 */ 923 924/* 925 * Starts a dialog with the server, and authenticates the current user on the 926 * server. This does not need any extra privileges. The basic connection 927 * to the server must already have been established before this is called. 928 * If login fails, this function prints an error and never returns. 929 * This function does not require super-user privileges. 930 */ 931void 932ssh_login(Key **keys, int nkeys, const char *orighost, 933 struct sockaddr *hostaddr, struct passwd *pw) 934{ 935 char *host, *cp; 936 char *server_user, *local_user; 937 938 local_user = xstrdup(pw->pw_name); 939 server_user = options.user ? options.user : local_user; 940 941 /* Convert the user-supplied hostname into all lowercase. */ 942 host = xstrdup(orighost); 943 for (cp = host; *cp; cp++) 944 if (isupper(*cp)) 945 *cp = tolower(*cp); 946 947 /* Exchange protocol version identification strings with the server. */ 948 ssh_exchange_identification(); 949 950 /* Put the connection into non-blocking mode. */ 951 packet_set_nonblocking(); 952 953 /* key exchange */ 954 /* authenticate user */ 955 if (compat20) { 956 ssh_kex2(host, hostaddr); 957 ssh_userauth2(local_user, server_user, host, keys, nkeys); 958 } else { 959 ssh_kex(host, hostaddr); 960 ssh_userauth1(local_user, server_user, host, keys, nkeys); 961 } 962} 963 964void 965ssh_put_password(char *password) 966{ 967 int size; 968 char *padded; 969 970 if (datafellows & SSH_BUG_PASSWORDPAD) { 971 packet_put_string(password, strlen(password)); 972 return; 973 } 974 size = roundup(strlen(password) + 1, 32); 975 padded = xmalloc(size); 976 memset(padded, 0, size); 977 strlcpy(padded, password, size); 978 packet_put_string(padded, size); 979 memset(padded, 0, size); 980 xfree(padded); 981} 982