1511b41d2SMark Murray /* 2511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 3511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4511b41d2SMark Murray * All rights reserved 5511b41d2SMark Murray * Created: Sat Mar 18 22:15:47 1995 ylo 6511b41d2SMark Murray * Code to connect to a remote host, and to perform the client side of the 7511b41d2SMark Murray * login (authentication) dialog. 842f71286SMark Murray * 942f71286SMark Murray * $FreeBSD$ 10511b41d2SMark Murray */ 11511b41d2SMark Murray 12511b41d2SMark Murray #include "includes.h" 13511b41d2SMark Murray RCSID("$OpenBSD: sshconnect.c,v 1.56 2000/02/18 08:50:33 markus Exp $"); 14511b41d2SMark Murray 15511b41d2SMark Murray #include <ssl/bn.h> 16511b41d2SMark Murray #include "xmalloc.h" 17511b41d2SMark Murray #include "rsa.h" 18511b41d2SMark Murray #include "ssh.h" 19511b41d2SMark Murray #include "packet.h" 20511b41d2SMark Murray #include "authfd.h" 21511b41d2SMark Murray #include "cipher.h" 22511b41d2SMark Murray #include "mpaux.h" 23511b41d2SMark Murray #include "uidswap.h" 24511b41d2SMark Murray #include "compat.h" 25511b41d2SMark Murray #include "readconf.h" 26511b41d2SMark Murray #include "fingerprint.h" 27511b41d2SMark Murray 28511b41d2SMark Murray #include <ssl/md5.h> 29511b41d2SMark Murray 30511b41d2SMark Murray /* Session id for the current session. */ 31511b41d2SMark Murray unsigned char session_id[16]; 32511b41d2SMark Murray 33511b41d2SMark Murray /* authentications supported by server */ 34511b41d2SMark Murray unsigned int supported_authentications; 35511b41d2SMark Murray 36511b41d2SMark Murray extern Options options; 37511b41d2SMark Murray extern char *__progname; 38511b41d2SMark Murray 39511b41d2SMark Murray /* 40511b41d2SMark Murray * Connect to the given ssh server using a proxy command. 41511b41d2SMark Murray */ 42511b41d2SMark Murray int 43511b41d2SMark Murray ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid, 44511b41d2SMark Murray const char *proxy_command) 45511b41d2SMark Murray { 46511b41d2SMark Murray Buffer command; 47511b41d2SMark Murray const char *cp; 48511b41d2SMark Murray char *command_string; 49511b41d2SMark Murray int pin[2], pout[2]; 50511b41d2SMark Murray int pid; 51511b41d2SMark Murray char strport[NI_MAXSERV]; 52511b41d2SMark Murray 53511b41d2SMark Murray /* Convert the port number into a string. */ 54511b41d2SMark Murray snprintf(strport, sizeof strport, "%hu", port); 55511b41d2SMark Murray 56511b41d2SMark Murray /* Build the final command string in the buffer by making the 57511b41d2SMark Murray appropriate substitutions to the given proxy command. */ 58511b41d2SMark Murray buffer_init(&command); 59511b41d2SMark Murray for (cp = proxy_command; *cp; cp++) { 60511b41d2SMark Murray if (cp[0] == '%' && cp[1] == '%') { 61511b41d2SMark Murray buffer_append(&command, "%", 1); 62511b41d2SMark Murray cp++; 63511b41d2SMark Murray continue; 64511b41d2SMark Murray } 65511b41d2SMark Murray if (cp[0] == '%' && cp[1] == 'h') { 66511b41d2SMark Murray buffer_append(&command, host, strlen(host)); 67511b41d2SMark Murray cp++; 68511b41d2SMark Murray continue; 69511b41d2SMark Murray } 70511b41d2SMark Murray if (cp[0] == '%' && cp[1] == 'p') { 71511b41d2SMark Murray buffer_append(&command, strport, strlen(strport)); 72511b41d2SMark Murray cp++; 73511b41d2SMark Murray continue; 74511b41d2SMark Murray } 75511b41d2SMark Murray buffer_append(&command, cp, 1); 76511b41d2SMark Murray } 77511b41d2SMark Murray buffer_append(&command, "\0", 1); 78511b41d2SMark Murray 79511b41d2SMark Murray /* Get the final command string. */ 80511b41d2SMark Murray command_string = buffer_ptr(&command); 81511b41d2SMark Murray 82511b41d2SMark Murray /* Create pipes for communicating with the proxy. */ 83511b41d2SMark Murray if (pipe(pin) < 0 || pipe(pout) < 0) 84511b41d2SMark Murray fatal("Could not create pipes to communicate with the proxy: %.100s", 85511b41d2SMark Murray strerror(errno)); 86511b41d2SMark Murray 87511b41d2SMark Murray debug("Executing proxy command: %.500s", command_string); 88511b41d2SMark Murray 89511b41d2SMark Murray /* Fork and execute the proxy command. */ 90511b41d2SMark Murray if ((pid = fork()) == 0) { 91511b41d2SMark Murray char *argv[10]; 92511b41d2SMark Murray 93511b41d2SMark Murray /* Child. Permanently give up superuser privileges. */ 94511b41d2SMark Murray permanently_set_uid(original_real_uid); 95511b41d2SMark Murray 96511b41d2SMark Murray /* Redirect stdin and stdout. */ 97511b41d2SMark Murray close(pin[1]); 98511b41d2SMark Murray if (pin[0] != 0) { 99511b41d2SMark Murray if (dup2(pin[0], 0) < 0) 100511b41d2SMark Murray perror("dup2 stdin"); 101511b41d2SMark Murray close(pin[0]); 102511b41d2SMark Murray } 103511b41d2SMark Murray close(pout[0]); 104511b41d2SMark Murray if (dup2(pout[1], 1) < 0) 105511b41d2SMark Murray perror("dup2 stdout"); 106511b41d2SMark Murray /* Cannot be 1 because pin allocated two descriptors. */ 107511b41d2SMark Murray close(pout[1]); 108511b41d2SMark Murray 109511b41d2SMark Murray /* Stderr is left as it is so that error messages get 110511b41d2SMark Murray printed on the user's terminal. */ 111511b41d2SMark Murray argv[0] = "/bin/sh"; 112511b41d2SMark Murray argv[1] = "-c"; 113511b41d2SMark Murray argv[2] = command_string; 114511b41d2SMark Murray argv[3] = NULL; 115511b41d2SMark Murray 116511b41d2SMark Murray /* Execute the proxy command. Note that we gave up any 117511b41d2SMark Murray extra privileges above. */ 118511b41d2SMark Murray execv("/bin/sh", argv); 119511b41d2SMark Murray perror("/bin/sh"); 120511b41d2SMark Murray exit(1); 121511b41d2SMark Murray } 122511b41d2SMark Murray /* Parent. */ 123511b41d2SMark Murray if (pid < 0) 124511b41d2SMark Murray fatal("fork failed: %.100s", strerror(errno)); 125511b41d2SMark Murray 126511b41d2SMark Murray /* Close child side of the descriptors. */ 127511b41d2SMark Murray close(pin[0]); 128511b41d2SMark Murray close(pout[1]); 129511b41d2SMark Murray 130511b41d2SMark Murray /* Free the command name. */ 131511b41d2SMark Murray buffer_free(&command); 132511b41d2SMark Murray 133511b41d2SMark Murray /* Set the connection file descriptors. */ 134511b41d2SMark Murray packet_set_connection(pout[0], pin[1]); 135511b41d2SMark Murray 136511b41d2SMark Murray return 1; 137511b41d2SMark Murray } 138511b41d2SMark Murray 139511b41d2SMark Murray /* 140511b41d2SMark Murray * Creates a (possibly privileged) socket for use as the ssh connection. 141511b41d2SMark Murray */ 142511b41d2SMark Murray int 143511b41d2SMark Murray ssh_create_socket(uid_t original_real_uid, int privileged, int family) 144511b41d2SMark Murray { 145511b41d2SMark Murray int sock; 146511b41d2SMark Murray 147511b41d2SMark Murray /* 148511b41d2SMark Murray * If we are running as root and want to connect to a privileged 149511b41d2SMark Murray * port, bind our own socket to a privileged port. 150511b41d2SMark Murray */ 151511b41d2SMark Murray if (privileged) { 152511b41d2SMark Murray int p = IPPORT_RESERVED - 1; 153511b41d2SMark Murray sock = rresvport_af(&p, family); 154511b41d2SMark Murray if (sock < 0) 155511b41d2SMark Murray error("rresvport: af=%d %.100s", family, strerror(errno)); 156511b41d2SMark Murray else 157511b41d2SMark Murray debug("Allocated local port %d.", p); 158511b41d2SMark Murray } else { 159511b41d2SMark Murray /* 160511b41d2SMark Murray * Just create an ordinary socket on arbitrary port. We use 161511b41d2SMark Murray * the user's uid to create the socket. 162511b41d2SMark Murray */ 163511b41d2SMark Murray temporarily_use_uid(original_real_uid); 164511b41d2SMark Murray sock = socket(family, SOCK_STREAM, 0); 165511b41d2SMark Murray if (sock < 0) 166511b41d2SMark Murray error("socket: %.100s", strerror(errno)); 167511b41d2SMark Murray restore_uid(); 168511b41d2SMark Murray } 169511b41d2SMark Murray return sock; 170511b41d2SMark Murray } 171511b41d2SMark Murray 172511b41d2SMark Murray /* 173511b41d2SMark Murray * Opens a TCP/IP connection to the remote server on the given host. 174511b41d2SMark Murray * The address of the remote host will be returned in hostaddr. 175511b41d2SMark Murray * If port is 0, the default port will be used. If anonymous is zero, 176511b41d2SMark Murray * a privileged port will be allocated to make the connection. 177511b41d2SMark Murray * This requires super-user privileges if anonymous is false. 178511b41d2SMark Murray * Connection_attempts specifies the maximum number of tries (one per 179511b41d2SMark Murray * second). If proxy_command is non-NULL, it specifies the command (with %h 180511b41d2SMark Murray * and %p substituted for host and port, respectively) to use to contact 181511b41d2SMark Murray * the daemon. 182511b41d2SMark Murray */ 183511b41d2SMark Murray int 184511b41d2SMark Murray ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 185511b41d2SMark Murray u_short port, int connection_attempts, 186511b41d2SMark Murray int anonymous, uid_t original_real_uid, 187511b41d2SMark Murray const char *proxy_command) 188511b41d2SMark Murray { 189511b41d2SMark Murray int sock = -1, attempt; 190511b41d2SMark Murray struct servent *sp; 191511b41d2SMark Murray struct addrinfo hints, *ai, *aitop; 192511b41d2SMark Murray char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 193511b41d2SMark Murray int gaierr; 194511b41d2SMark Murray struct linger linger; 195511b41d2SMark Murray 196511b41d2SMark Murray debug("ssh_connect: getuid %d geteuid %d anon %d", 197511b41d2SMark Murray (int) getuid(), (int) geteuid(), anonymous); 198511b41d2SMark Murray 199511b41d2SMark Murray /* Get default port if port has not been set. */ 200511b41d2SMark Murray if (port == 0) { 201511b41d2SMark Murray sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 202511b41d2SMark Murray if (sp) 203511b41d2SMark Murray port = ntohs(sp->s_port); 204511b41d2SMark Murray else 205511b41d2SMark Murray port = SSH_DEFAULT_PORT; 206511b41d2SMark Murray } 207511b41d2SMark Murray /* If a proxy command is given, connect using it. */ 208511b41d2SMark Murray if (proxy_command != NULL) 209511b41d2SMark Murray return ssh_proxy_connect(host, port, original_real_uid, proxy_command); 210511b41d2SMark Murray 211511b41d2SMark Murray /* No proxy command. */ 212511b41d2SMark Murray 213511b41d2SMark Murray memset(&hints, 0, sizeof(hints)); 214511b41d2SMark Murray hints.ai_family = IPv4or6; 215511b41d2SMark Murray hints.ai_socktype = SOCK_STREAM; 216511b41d2SMark Murray snprintf(strport, sizeof strport, "%d", port); 217511b41d2SMark Murray if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 218511b41d2SMark Murray fatal("%s: %.100s: %s", __progname, host, 219511b41d2SMark Murray gai_strerror(gaierr)); 220511b41d2SMark Murray 221511b41d2SMark Murray /* 222511b41d2SMark Murray * Try to connect several times. On some machines, the first time 223511b41d2SMark Murray * will sometimes fail. In general socket code appears to behave 224511b41d2SMark Murray * quite magically on many machines. 225511b41d2SMark Murray */ 226511b41d2SMark Murray for (attempt = 0; attempt < connection_attempts; attempt++) { 227511b41d2SMark Murray if (attempt > 0) 228511b41d2SMark Murray debug("Trying again..."); 229511b41d2SMark Murray 230511b41d2SMark Murray /* Loop through addresses for this host, and try each one in 231511b41d2SMark Murray sequence until the connection succeeds. */ 232511b41d2SMark Murray for (ai = aitop; ai; ai = ai->ai_next) { 233511b41d2SMark Murray if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 234511b41d2SMark Murray continue; 235511b41d2SMark Murray if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 236511b41d2SMark Murray ntop, sizeof(ntop), strport, sizeof(strport), 237511b41d2SMark Murray NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 238511b41d2SMark Murray error("ssh_connect: getnameinfo failed"); 239511b41d2SMark Murray continue; 240511b41d2SMark Murray } 241511b41d2SMark Murray debug("Connecting to %.200s [%.100s] port %s.", 242511b41d2SMark Murray host, ntop, strport); 243511b41d2SMark Murray 244511b41d2SMark Murray /* Create a socket for connecting. */ 245511b41d2SMark Murray sock = ssh_create_socket(original_real_uid, 246511b41d2SMark Murray !anonymous && geteuid() == 0 && port < IPPORT_RESERVED, 247511b41d2SMark Murray ai->ai_family); 248511b41d2SMark Murray if (sock < 0) 249511b41d2SMark Murray continue; 250511b41d2SMark Murray 251511b41d2SMark Murray /* Connect to the host. We use the user's uid in the 252511b41d2SMark Murray * hope that it will help with tcp_wrappers showing 253511b41d2SMark Murray * the remote uid as root. 254511b41d2SMark Murray */ 255511b41d2SMark Murray temporarily_use_uid(original_real_uid); 256511b41d2SMark Murray if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { 257511b41d2SMark Murray /* Successful connection. */ 258511b41d2SMark Murray memcpy(hostaddr, ai->ai_addr, sizeof(*hostaddr)); 259511b41d2SMark Murray restore_uid(); 260511b41d2SMark Murray break; 261511b41d2SMark Murray } else { 262511b41d2SMark Murray debug("connect: %.100s", strerror(errno)); 263511b41d2SMark Murray restore_uid(); 264511b41d2SMark Murray /* 265511b41d2SMark Murray * Close the failed socket; there appear to 266511b41d2SMark Murray * be some problems when reusing a socket for 267511b41d2SMark Murray * which connect() has already returned an 268511b41d2SMark Murray * error. 269511b41d2SMark Murray */ 270511b41d2SMark Murray shutdown(sock, SHUT_RDWR); 271511b41d2SMark Murray close(sock); 272511b41d2SMark Murray } 273511b41d2SMark Murray } 274511b41d2SMark Murray if (ai) 275511b41d2SMark Murray break; /* Successful connection. */ 276511b41d2SMark Murray 277511b41d2SMark Murray /* Sleep a moment before retrying. */ 278511b41d2SMark Murray sleep(1); 279511b41d2SMark Murray } 280511b41d2SMark Murray 281511b41d2SMark Murray freeaddrinfo(aitop); 282511b41d2SMark Murray 283511b41d2SMark Murray /* Return failure if we didn't get a successful connection. */ 284511b41d2SMark Murray if (attempt >= connection_attempts) 285511b41d2SMark Murray return 0; 286511b41d2SMark Murray 287511b41d2SMark Murray debug("Connection established."); 288511b41d2SMark Murray 289511b41d2SMark Murray /* 290511b41d2SMark Murray * Set socket options. We would like the socket to disappear as soon 291511b41d2SMark Murray * as it has been closed for whatever reason. 292511b41d2SMark Murray */ 293511b41d2SMark Murray /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ 294511b41d2SMark Murray linger.l_onoff = 1; 295511b41d2SMark Murray linger.l_linger = 5; 296511b41d2SMark Murray setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); 297511b41d2SMark Murray 298511b41d2SMark Murray /* Set the connection. */ 299511b41d2SMark Murray packet_set_connection(sock, sock); 300511b41d2SMark Murray 301511b41d2SMark Murray return 1; 302511b41d2SMark Murray } 303511b41d2SMark Murray 304511b41d2SMark Murray /* 305511b41d2SMark Murray * Checks if the user has an authentication agent, and if so, tries to 306511b41d2SMark Murray * authenticate using the agent. 307511b41d2SMark Murray */ 308511b41d2SMark Murray int 309511b41d2SMark Murray try_agent_authentication() 310511b41d2SMark Murray { 311511b41d2SMark Murray int status, type; 312511b41d2SMark Murray char *comment; 313511b41d2SMark Murray AuthenticationConnection *auth; 314511b41d2SMark Murray unsigned char response[16]; 315511b41d2SMark Murray unsigned int i; 316511b41d2SMark Murray BIGNUM *e, *n, *challenge; 317511b41d2SMark Murray 318511b41d2SMark Murray /* Get connection to the agent. */ 319511b41d2SMark Murray auth = ssh_get_authentication_connection(); 320511b41d2SMark Murray if (!auth) 321511b41d2SMark Murray return 0; 322511b41d2SMark Murray 323511b41d2SMark Murray e = BN_new(); 324511b41d2SMark Murray n = BN_new(); 325511b41d2SMark Murray challenge = BN_new(); 326511b41d2SMark Murray 327511b41d2SMark Murray /* Loop through identities served by the agent. */ 328511b41d2SMark Murray for (status = ssh_get_first_identity(auth, e, n, &comment); 329511b41d2SMark Murray status; 330511b41d2SMark Murray status = ssh_get_next_identity(auth, e, n, &comment)) { 331511b41d2SMark Murray int plen, clen; 332511b41d2SMark Murray 333511b41d2SMark Murray /* Try this identity. */ 334511b41d2SMark Murray debug("Trying RSA authentication via agent with '%.100s'", comment); 335511b41d2SMark Murray xfree(comment); 336511b41d2SMark Murray 337511b41d2SMark Murray /* Tell the server that we are willing to authenticate using this key. */ 338511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RSA); 339511b41d2SMark Murray packet_put_bignum(n); 340511b41d2SMark Murray packet_send(); 341511b41d2SMark Murray packet_write_wait(); 342511b41d2SMark Murray 343511b41d2SMark Murray /* Wait for server's response. */ 344511b41d2SMark Murray type = packet_read(&plen); 345511b41d2SMark Murray 346511b41d2SMark Murray /* The server sends failure if it doesn\'t like our key or 347511b41d2SMark Murray does not support RSA authentication. */ 348511b41d2SMark Murray if (type == SSH_SMSG_FAILURE) { 349511b41d2SMark Murray debug("Server refused our key."); 350511b41d2SMark Murray continue; 351511b41d2SMark Murray } 352511b41d2SMark Murray /* Otherwise it should have sent a challenge. */ 353511b41d2SMark Murray if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) 354511b41d2SMark Murray packet_disconnect("Protocol error during RSA authentication: %d", 355511b41d2SMark Murray type); 356511b41d2SMark Murray 357511b41d2SMark Murray packet_get_bignum(challenge, &clen); 358511b41d2SMark Murray 359511b41d2SMark Murray packet_integrity_check(plen, clen, type); 360511b41d2SMark Murray 361511b41d2SMark Murray debug("Received RSA challenge from server."); 362511b41d2SMark Murray 363511b41d2SMark Murray /* Ask the agent to decrypt the challenge. */ 364511b41d2SMark Murray if (!ssh_decrypt_challenge(auth, e, n, challenge, 365511b41d2SMark Murray session_id, 1, response)) { 366511b41d2SMark Murray /* The agent failed to authenticate this identifier although it 367511b41d2SMark Murray advertised it supports this. Just return a wrong value. */ 368511b41d2SMark Murray log("Authentication agent failed to decrypt challenge."); 369511b41d2SMark Murray memset(response, 0, sizeof(response)); 370511b41d2SMark Murray } 371511b41d2SMark Murray debug("Sending response to RSA challenge."); 372511b41d2SMark Murray 373511b41d2SMark Murray /* Send the decrypted challenge back to the server. */ 374511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); 375511b41d2SMark Murray for (i = 0; i < 16; i++) 376511b41d2SMark Murray packet_put_char(response[i]); 377511b41d2SMark Murray packet_send(); 378511b41d2SMark Murray packet_write_wait(); 379511b41d2SMark Murray 380511b41d2SMark Murray /* Wait for response from the server. */ 381511b41d2SMark Murray type = packet_read(&plen); 382511b41d2SMark Murray 383511b41d2SMark Murray /* The server returns success if it accepted the authentication. */ 384511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) { 385511b41d2SMark Murray debug("RSA authentication accepted by server."); 386511b41d2SMark Murray BN_clear_free(e); 387511b41d2SMark Murray BN_clear_free(n); 388511b41d2SMark Murray BN_clear_free(challenge); 389511b41d2SMark Murray return 1; 390511b41d2SMark Murray } 391511b41d2SMark Murray /* Otherwise it should return failure. */ 392511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 393511b41d2SMark Murray packet_disconnect("Protocol error waiting RSA auth response: %d", 394511b41d2SMark Murray type); 395511b41d2SMark Murray } 396511b41d2SMark Murray 397511b41d2SMark Murray BN_clear_free(e); 398511b41d2SMark Murray BN_clear_free(n); 399511b41d2SMark Murray BN_clear_free(challenge); 400511b41d2SMark Murray 401511b41d2SMark Murray debug("RSA authentication using agent refused."); 402511b41d2SMark Murray return 0; 403511b41d2SMark Murray } 404511b41d2SMark Murray 405511b41d2SMark Murray /* 406511b41d2SMark Murray * Computes the proper response to a RSA challenge, and sends the response to 407511b41d2SMark Murray * the server. 408511b41d2SMark Murray */ 409511b41d2SMark Murray void 410511b41d2SMark Murray respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) 411511b41d2SMark Murray { 412511b41d2SMark Murray unsigned char buf[32], response[16]; 413511b41d2SMark Murray MD5_CTX md; 414511b41d2SMark Murray int i, len; 415511b41d2SMark Murray 416511b41d2SMark Murray /* Decrypt the challenge using the private key. */ 417511b41d2SMark Murray rsa_private_decrypt(challenge, challenge, prv); 418511b41d2SMark Murray 419511b41d2SMark Murray /* Compute the response. */ 420511b41d2SMark Murray /* The response is MD5 of decrypted challenge plus session id. */ 421511b41d2SMark Murray len = BN_num_bytes(challenge); 422511b41d2SMark Murray if (len <= 0 || len > sizeof(buf)) 423511b41d2SMark Murray packet_disconnect("respond_to_rsa_challenge: bad challenge length %d", 424511b41d2SMark Murray len); 425511b41d2SMark Murray 426511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 427511b41d2SMark Murray BN_bn2bin(challenge, buf + sizeof(buf) - len); 428511b41d2SMark Murray MD5_Init(&md); 429511b41d2SMark Murray MD5_Update(&md, buf, 32); 430511b41d2SMark Murray MD5_Update(&md, session_id, 16); 431511b41d2SMark Murray MD5_Final(response, &md); 432511b41d2SMark Murray 433511b41d2SMark Murray debug("Sending response to host key RSA challenge."); 434511b41d2SMark Murray 435511b41d2SMark Murray /* Send the response back to the server. */ 436511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); 437511b41d2SMark Murray for (i = 0; i < 16; i++) 438511b41d2SMark Murray packet_put_char(response[i]); 439511b41d2SMark Murray packet_send(); 440511b41d2SMark Murray packet_write_wait(); 441511b41d2SMark Murray 442511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 443511b41d2SMark Murray memset(response, 0, sizeof(response)); 444511b41d2SMark Murray memset(&md, 0, sizeof(md)); 445511b41d2SMark Murray } 446511b41d2SMark Murray 447511b41d2SMark Murray /* 448511b41d2SMark Murray * Checks if the user has authentication file, and if so, tries to authenticate 449511b41d2SMark Murray * the user using it. 450511b41d2SMark Murray */ 451511b41d2SMark Murray int 452511b41d2SMark Murray try_rsa_authentication(const char *authfile) 453511b41d2SMark Murray { 454511b41d2SMark Murray BIGNUM *challenge; 455511b41d2SMark Murray RSA *private_key; 456511b41d2SMark Murray RSA *public_key; 457511b41d2SMark Murray char *passphrase, *comment; 458511b41d2SMark Murray int type, i; 459511b41d2SMark Murray int plen, clen; 460511b41d2SMark Murray 461511b41d2SMark Murray /* Try to load identification for the authentication key. */ 462511b41d2SMark Murray public_key = RSA_new(); 463511b41d2SMark Murray if (!load_public_key(authfile, public_key, &comment)) { 464511b41d2SMark Murray RSA_free(public_key); 465511b41d2SMark Murray /* Could not load it. Fail. */ 466511b41d2SMark Murray return 0; 467511b41d2SMark Murray } 468511b41d2SMark Murray debug("Trying RSA authentication with key '%.100s'", comment); 469511b41d2SMark Murray 470511b41d2SMark Murray /* Tell the server that we are willing to authenticate using this key. */ 471511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RSA); 472511b41d2SMark Murray packet_put_bignum(public_key->n); 473511b41d2SMark Murray packet_send(); 474511b41d2SMark Murray packet_write_wait(); 475511b41d2SMark Murray 476511b41d2SMark Murray /* We no longer need the public key. */ 477511b41d2SMark Murray RSA_free(public_key); 478511b41d2SMark Murray 479511b41d2SMark Murray /* Wait for server's response. */ 480511b41d2SMark Murray type = packet_read(&plen); 481511b41d2SMark Murray 482511b41d2SMark Murray /* 483511b41d2SMark Murray * The server responds with failure if it doesn\'t like our key or 484511b41d2SMark Murray * doesn\'t support RSA authentication. 485511b41d2SMark Murray */ 486511b41d2SMark Murray if (type == SSH_SMSG_FAILURE) { 487511b41d2SMark Murray debug("Server refused our key."); 488511b41d2SMark Murray xfree(comment); 489511b41d2SMark Murray return 0; 490511b41d2SMark Murray } 491511b41d2SMark Murray /* Otherwise, the server should respond with a challenge. */ 492511b41d2SMark Murray if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) 493511b41d2SMark Murray packet_disconnect("Protocol error during RSA authentication: %d", type); 494511b41d2SMark Murray 495511b41d2SMark Murray /* Get the challenge from the packet. */ 496511b41d2SMark Murray challenge = BN_new(); 497511b41d2SMark Murray packet_get_bignum(challenge, &clen); 498511b41d2SMark Murray 499511b41d2SMark Murray packet_integrity_check(plen, clen, type); 500511b41d2SMark Murray 501511b41d2SMark Murray debug("Received RSA challenge from server."); 502511b41d2SMark Murray 503511b41d2SMark Murray private_key = RSA_new(); 504511b41d2SMark Murray /* 505511b41d2SMark Murray * Load the private key. Try first with empty passphrase; if it 506511b41d2SMark Murray * fails, ask for a passphrase. 507511b41d2SMark Murray */ 508511b41d2SMark Murray if (!load_private_key(authfile, "", private_key, NULL)) { 509511b41d2SMark Murray char buf[300]; 510511b41d2SMark Murray snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", 511511b41d2SMark Murray comment); 512511b41d2SMark Murray if (!options.batch_mode) 513511b41d2SMark Murray passphrase = read_passphrase(buf, 0); 514511b41d2SMark Murray else { 515511b41d2SMark Murray debug("Will not query passphrase for %.100s in batch mode.", 516511b41d2SMark Murray comment); 517511b41d2SMark Murray passphrase = xstrdup(""); 518511b41d2SMark Murray } 519511b41d2SMark Murray 520511b41d2SMark Murray /* Load the authentication file using the pasphrase. */ 521511b41d2SMark Murray if (!load_private_key(authfile, passphrase, private_key, NULL)) { 522511b41d2SMark Murray memset(passphrase, 0, strlen(passphrase)); 523511b41d2SMark Murray xfree(passphrase); 524511b41d2SMark Murray error("Bad passphrase."); 525511b41d2SMark Murray 526511b41d2SMark Murray /* Send a dummy response packet to avoid protocol error. */ 527511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); 528511b41d2SMark Murray for (i = 0; i < 16; i++) 529511b41d2SMark Murray packet_put_char(0); 530511b41d2SMark Murray packet_send(); 531511b41d2SMark Murray packet_write_wait(); 532511b41d2SMark Murray 533511b41d2SMark Murray /* Expect the server to reject it... */ 534511b41d2SMark Murray packet_read_expect(&plen, SSH_SMSG_FAILURE); 535511b41d2SMark Murray xfree(comment); 536511b41d2SMark Murray return 0; 537511b41d2SMark Murray } 538511b41d2SMark Murray /* Destroy the passphrase. */ 539511b41d2SMark Murray memset(passphrase, 0, strlen(passphrase)); 540511b41d2SMark Murray xfree(passphrase); 541511b41d2SMark Murray } 542511b41d2SMark Murray /* We no longer need the comment. */ 543511b41d2SMark Murray xfree(comment); 544511b41d2SMark Murray 545511b41d2SMark Murray /* Compute and send a response to the challenge. */ 546511b41d2SMark Murray respond_to_rsa_challenge(challenge, private_key); 547511b41d2SMark Murray 548511b41d2SMark Murray /* Destroy the private key. */ 549511b41d2SMark Murray RSA_free(private_key); 550511b41d2SMark Murray 551511b41d2SMark Murray /* We no longer need the challenge. */ 552511b41d2SMark Murray BN_clear_free(challenge); 553511b41d2SMark Murray 554511b41d2SMark Murray /* Wait for response from the server. */ 555511b41d2SMark Murray type = packet_read(&plen); 556511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) { 557511b41d2SMark Murray debug("RSA authentication accepted by server."); 558511b41d2SMark Murray return 1; 559511b41d2SMark Murray } 560511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 561511b41d2SMark Murray packet_disconnect("Protocol error waiting RSA auth response: %d", type); 562511b41d2SMark Murray debug("RSA authentication refused."); 563511b41d2SMark Murray return 0; 564511b41d2SMark Murray } 565511b41d2SMark Murray 566511b41d2SMark Murray /* 567511b41d2SMark Murray * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv 568511b41d2SMark Murray * authentication and RSA host authentication. 569511b41d2SMark Murray */ 570511b41d2SMark Murray int 571511b41d2SMark Murray try_rhosts_rsa_authentication(const char *local_user, RSA * host_key) 572511b41d2SMark Murray { 573511b41d2SMark Murray int type; 574511b41d2SMark Murray BIGNUM *challenge; 575511b41d2SMark Murray int plen, clen; 576511b41d2SMark Murray 577511b41d2SMark Murray debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication."); 578511b41d2SMark Murray 579511b41d2SMark Murray /* Tell the server that we are willing to authenticate using this key. */ 580511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); 581511b41d2SMark Murray packet_put_string(local_user, strlen(local_user)); 582511b41d2SMark Murray packet_put_int(BN_num_bits(host_key->n)); 583511b41d2SMark Murray packet_put_bignum(host_key->e); 584511b41d2SMark Murray packet_put_bignum(host_key->n); 585511b41d2SMark Murray packet_send(); 586511b41d2SMark Murray packet_write_wait(); 587511b41d2SMark Murray 588511b41d2SMark Murray /* Wait for server's response. */ 589511b41d2SMark Murray type = packet_read(&plen); 590511b41d2SMark Murray 591511b41d2SMark Murray /* The server responds with failure if it doesn't admit our 592511b41d2SMark Murray .rhosts authentication or doesn't know our host key. */ 593511b41d2SMark Murray if (type == SSH_SMSG_FAILURE) { 594511b41d2SMark Murray debug("Server refused our rhosts authentication or host key."); 595511b41d2SMark Murray return 0; 596511b41d2SMark Murray } 597511b41d2SMark Murray /* Otherwise, the server should respond with a challenge. */ 598511b41d2SMark Murray if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) 599511b41d2SMark Murray packet_disconnect("Protocol error during RSA authentication: %d", type); 600511b41d2SMark Murray 601511b41d2SMark Murray /* Get the challenge from the packet. */ 602511b41d2SMark Murray challenge = BN_new(); 603511b41d2SMark Murray packet_get_bignum(challenge, &clen); 604511b41d2SMark Murray 605511b41d2SMark Murray packet_integrity_check(plen, clen, type); 606511b41d2SMark Murray 607511b41d2SMark Murray debug("Received RSA challenge for host key from server."); 608511b41d2SMark Murray 609511b41d2SMark Murray /* Compute a response to the challenge. */ 610511b41d2SMark Murray respond_to_rsa_challenge(challenge, host_key); 611511b41d2SMark Murray 612511b41d2SMark Murray /* We no longer need the challenge. */ 613511b41d2SMark Murray BN_clear_free(challenge); 614511b41d2SMark Murray 615511b41d2SMark Murray /* Wait for response from the server. */ 616511b41d2SMark Murray type = packet_read(&plen); 617511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) { 618511b41d2SMark Murray debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server."); 619511b41d2SMark Murray return 1; 620511b41d2SMark Murray } 621511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 622511b41d2SMark Murray packet_disconnect("Protocol error waiting RSA auth response: %d", type); 623511b41d2SMark Murray debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused."); 624511b41d2SMark Murray return 0; 625511b41d2SMark Murray } 626511b41d2SMark Murray 627511b41d2SMark Murray #ifdef KRB4 628511b41d2SMark Murray int 629511b41d2SMark Murray try_kerberos_authentication() 630511b41d2SMark Murray { 631511b41d2SMark Murray KTEXT_ST auth; /* Kerberos data */ 632511b41d2SMark Murray char *reply; 633511b41d2SMark Murray char inst[INST_SZ]; 634511b41d2SMark Murray char *realm; 635511b41d2SMark Murray CREDENTIALS cred; 636511b41d2SMark Murray int r, type, plen; 637511b41d2SMark Murray Key_schedule schedule; 638511b41d2SMark Murray u_long checksum, cksum; 639511b41d2SMark Murray MSG_DAT msg_data; 640511b41d2SMark Murray struct sockaddr_in local, foreign; 641511b41d2SMark Murray struct stat st; 642511b41d2SMark Murray 643511b41d2SMark Murray /* Don't do anything if we don't have any tickets. */ 644511b41d2SMark Murray if (stat(tkt_string(), &st) < 0) 645511b41d2SMark Murray return 0; 646511b41d2SMark Murray 647511b41d2SMark Murray strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ); 648511b41d2SMark Murray 649511b41d2SMark Murray realm = (char *) krb_realmofhost(get_canonical_hostname()); 650511b41d2SMark Murray if (!realm) { 651511b41d2SMark Murray debug("Kerberos V4: no realm for %s", get_canonical_hostname()); 652511b41d2SMark Murray return 0; 653511b41d2SMark Murray } 654511b41d2SMark Murray /* This can really be anything. */ 655511b41d2SMark Murray checksum = (u_long) getpid(); 656511b41d2SMark Murray 657511b41d2SMark Murray r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); 658511b41d2SMark Murray if (r != KSUCCESS) { 659511b41d2SMark Murray debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]); 660511b41d2SMark Murray return 0; 661511b41d2SMark Murray } 662511b41d2SMark Murray /* Get session key to decrypt the server's reply with. */ 663511b41d2SMark Murray r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred); 664511b41d2SMark Murray if (r != KSUCCESS) { 665511b41d2SMark Murray debug("get_cred failed: %s", krb_err_txt[r]); 666511b41d2SMark Murray return 0; 667511b41d2SMark Murray } 668511b41d2SMark Murray des_key_sched((des_cblock *) cred.session, schedule); 669511b41d2SMark Murray 670511b41d2SMark Murray /* Send authentication info to server. */ 671511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_KERBEROS); 672511b41d2SMark Murray packet_put_string((char *) auth.dat, auth.length); 673511b41d2SMark Murray packet_send(); 674511b41d2SMark Murray packet_write_wait(); 675511b41d2SMark Murray 676511b41d2SMark Murray /* Zero the buffer. */ 677511b41d2SMark Murray (void) memset(auth.dat, 0, MAX_KTXT_LEN); 678511b41d2SMark Murray 679511b41d2SMark Murray r = sizeof(local); 680511b41d2SMark Murray memset(&local, 0, sizeof(local)); 681511b41d2SMark Murray if (getsockname(packet_get_connection_in(), 682511b41d2SMark Murray (struct sockaddr *) & local, &r) < 0) 683511b41d2SMark Murray debug("getsockname failed: %s", strerror(errno)); 684511b41d2SMark Murray 685511b41d2SMark Murray r = sizeof(foreign); 686511b41d2SMark Murray memset(&foreign, 0, sizeof(foreign)); 687511b41d2SMark Murray if (getpeername(packet_get_connection_in(), 688511b41d2SMark Murray (struct sockaddr *) & foreign, &r) < 0) { 689511b41d2SMark Murray debug("getpeername failed: %s", strerror(errno)); 690511b41d2SMark Murray fatal_cleanup(); 691511b41d2SMark Murray } 692511b41d2SMark Murray /* Get server reply. */ 693511b41d2SMark Murray type = packet_read(&plen); 694511b41d2SMark Murray switch (type) { 695511b41d2SMark Murray case SSH_SMSG_FAILURE: 696511b41d2SMark Murray /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ 697511b41d2SMark Murray debug("Kerberos V4 authentication failed."); 698511b41d2SMark Murray return 0; 699511b41d2SMark Murray break; 700511b41d2SMark Murray 701511b41d2SMark Murray case SSH_SMSG_AUTH_KERBEROS_RESPONSE: 702511b41d2SMark Murray /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ 703511b41d2SMark Murray debug("Kerberos V4 authentication accepted."); 704511b41d2SMark Murray 705511b41d2SMark Murray /* Get server's response. */ 706511b41d2SMark Murray reply = packet_get_string((unsigned int *) &auth.length); 707511b41d2SMark Murray memcpy(auth.dat, reply, auth.length); 708511b41d2SMark Murray xfree(reply); 709511b41d2SMark Murray 710511b41d2SMark Murray packet_integrity_check(plen, 4 + auth.length, type); 711511b41d2SMark Murray 712511b41d2SMark Murray /* 713511b41d2SMark Murray * If his response isn't properly encrypted with the session 714511b41d2SMark Murray * key, and the decrypted checksum fails to match, he's 715511b41d2SMark Murray * bogus. Bail out. 716511b41d2SMark Murray */ 717511b41d2SMark Murray r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, 718511b41d2SMark Murray &foreign, &local, &msg_data); 719511b41d2SMark Murray if (r != KSUCCESS) { 720511b41d2SMark Murray debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]); 721511b41d2SMark Murray packet_disconnect("Kerberos V4 challenge failed!"); 722511b41d2SMark Murray } 723511b41d2SMark Murray /* Fetch the (incremented) checksum that we supplied in the request. */ 724511b41d2SMark Murray (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum)); 725511b41d2SMark Murray cksum = ntohl(cksum); 726511b41d2SMark Murray 727511b41d2SMark Murray /* If it matches, we're golden. */ 728511b41d2SMark Murray if (cksum == checksum + 1) { 729511b41d2SMark Murray debug("Kerberos V4 challenge successful."); 730511b41d2SMark Murray return 1; 731511b41d2SMark Murray } else 732511b41d2SMark Murray packet_disconnect("Kerberos V4 challenge failed!"); 733511b41d2SMark Murray break; 734511b41d2SMark Murray 735511b41d2SMark Murray default: 736511b41d2SMark Murray packet_disconnect("Protocol error on Kerberos V4 response: %d", type); 737511b41d2SMark Murray } 738511b41d2SMark Murray return 0; 739511b41d2SMark Murray } 740511b41d2SMark Murray 741511b41d2SMark Murray #endif /* KRB4 */ 742511b41d2SMark Murray 743511b41d2SMark Murray #ifdef AFS 744511b41d2SMark Murray int 745511b41d2SMark Murray send_kerberos_tgt() 746511b41d2SMark Murray { 747511b41d2SMark Murray CREDENTIALS *creds; 748511b41d2SMark Murray char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; 749511b41d2SMark Murray int r, type, plen; 750511b41d2SMark Murray unsigned char buffer[8192]; 751511b41d2SMark Murray struct stat st; 752511b41d2SMark Murray 753511b41d2SMark Murray /* Don't do anything if we don't have any tickets. */ 754511b41d2SMark Murray if (stat(tkt_string(), &st) < 0) 755511b41d2SMark Murray return 0; 756511b41d2SMark Murray 757511b41d2SMark Murray creds = xmalloc(sizeof(*creds)); 758511b41d2SMark Murray 759511b41d2SMark Murray if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) { 760511b41d2SMark Murray debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]); 761511b41d2SMark Murray return 0; 762511b41d2SMark Murray } 763511b41d2SMark Murray if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) { 764511b41d2SMark Murray debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]); 765511b41d2SMark Murray return 0; 766511b41d2SMark Murray } 767511b41d2SMark Murray if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { 768511b41d2SMark Murray debug("Kerberos V4 ticket expired: %s", TKT_FILE); 769511b41d2SMark Murray return 0; 770511b41d2SMark Murray } 771511b41d2SMark Murray creds_to_radix(creds, buffer); 772511b41d2SMark Murray xfree(creds); 773511b41d2SMark Murray 774511b41d2SMark Murray packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); 775511b41d2SMark Murray packet_put_string((char *) buffer, strlen(buffer)); 776511b41d2SMark Murray packet_send(); 777511b41d2SMark Murray packet_write_wait(); 778511b41d2SMark Murray 779511b41d2SMark Murray type = packet_read(&plen); 780511b41d2SMark Murray 781511b41d2SMark Murray if (type == SSH_SMSG_FAILURE) 782511b41d2SMark Murray debug("Kerberos TGT for realm %s rejected.", prealm); 783511b41d2SMark Murray else if (type != SSH_SMSG_SUCCESS) 784511b41d2SMark Murray packet_disconnect("Protocol error on Kerberos TGT response: %d", type); 785511b41d2SMark Murray 786511b41d2SMark Murray return 1; 787511b41d2SMark Murray } 788511b41d2SMark Murray 789511b41d2SMark Murray void 790511b41d2SMark Murray send_afs_tokens(void) 791511b41d2SMark Murray { 792511b41d2SMark Murray CREDENTIALS creds; 793511b41d2SMark Murray struct ViceIoctl parms; 794511b41d2SMark Murray struct ClearToken ct; 795511b41d2SMark Murray int i, type, len, plen; 796511b41d2SMark Murray char buf[2048], *p, *server_cell; 797511b41d2SMark Murray unsigned char buffer[8192]; 798511b41d2SMark Murray 799511b41d2SMark Murray /* Move over ktc_GetToken, here's something leaner. */ 800511b41d2SMark Murray for (i = 0; i < 100; i++) { /* just in case */ 801511b41d2SMark Murray parms.in = (char *) &i; 802511b41d2SMark Murray parms.in_size = sizeof(i); 803511b41d2SMark Murray parms.out = buf; 804511b41d2SMark Murray parms.out_size = sizeof(buf); 805511b41d2SMark Murray if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) 806511b41d2SMark Murray break; 807511b41d2SMark Murray p = buf; 808511b41d2SMark Murray 809511b41d2SMark Murray /* Get secret token. */ 810511b41d2SMark Murray memcpy(&creds.ticket_st.length, p, sizeof(unsigned int)); 811511b41d2SMark Murray if (creds.ticket_st.length > MAX_KTXT_LEN) 812511b41d2SMark Murray break; 813511b41d2SMark Murray p += sizeof(unsigned int); 814511b41d2SMark Murray memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); 815511b41d2SMark Murray p += creds.ticket_st.length; 816511b41d2SMark Murray 817511b41d2SMark Murray /* Get clear token. */ 818511b41d2SMark Murray memcpy(&len, p, sizeof(len)); 819511b41d2SMark Murray if (len != sizeof(struct ClearToken)) 820511b41d2SMark Murray break; 821511b41d2SMark Murray p += sizeof(len); 822511b41d2SMark Murray memcpy(&ct, p, len); 823511b41d2SMark Murray p += len; 824511b41d2SMark Murray p += sizeof(len); /* primary flag */ 825511b41d2SMark Murray server_cell = p; 826511b41d2SMark Murray 827511b41d2SMark Murray /* Flesh out our credentials. */ 828511b41d2SMark Murray strlcpy(creds.service, "afs", sizeof creds.service); 829511b41d2SMark Murray creds.instance[0] = '\0'; 830511b41d2SMark Murray strlcpy(creds.realm, server_cell, REALM_SZ); 831511b41d2SMark Murray memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); 832511b41d2SMark Murray creds.issue_date = ct.BeginTimestamp; 833511b41d2SMark Murray creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp); 834511b41d2SMark Murray creds.kvno = ct.AuthHandle; 835511b41d2SMark Murray snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId); 836511b41d2SMark Murray creds.pinst[0] = '\0'; 837511b41d2SMark Murray 838511b41d2SMark Murray /* Encode token, ship it off. */ 839511b41d2SMark Murray if (!creds_to_radix(&creds, buffer)) 840511b41d2SMark Murray break; 841511b41d2SMark Murray packet_start(SSH_CMSG_HAVE_AFS_TOKEN); 842511b41d2SMark Murray packet_put_string((char *) buffer, strlen(buffer)); 843511b41d2SMark Murray packet_send(); 844511b41d2SMark Murray packet_write_wait(); 845511b41d2SMark Murray 846511b41d2SMark Murray /* Roger, Roger. Clearance, Clarence. What's your vector, 847511b41d2SMark Murray Victor? */ 848511b41d2SMark Murray type = packet_read(&plen); 849511b41d2SMark Murray 850511b41d2SMark Murray if (type == SSH_SMSG_FAILURE) 851511b41d2SMark Murray debug("AFS token for cell %s rejected.", server_cell); 852511b41d2SMark Murray else if (type != SSH_SMSG_SUCCESS) 853511b41d2SMark Murray packet_disconnect("Protocol error on AFS token response: %d", type); 854511b41d2SMark Murray } 855511b41d2SMark Murray } 856511b41d2SMark Murray 857511b41d2SMark Murray #endif /* AFS */ 858511b41d2SMark Murray 859511b41d2SMark Murray /* 860511b41d2SMark Murray * Tries to authenticate with any string-based challenge/response system. 861511b41d2SMark Murray * Note that the client code is not tied to s/key or TIS. 862511b41d2SMark Murray */ 863511b41d2SMark Murray int 864511b41d2SMark Murray try_skey_authentication() 865511b41d2SMark Murray { 866511b41d2SMark Murray int type, i, payload_len; 867511b41d2SMark Murray char *challenge, *response; 868511b41d2SMark Murray 869511b41d2SMark Murray debug("Doing skey authentication."); 870511b41d2SMark Murray 871511b41d2SMark Murray /* request a challenge */ 872511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_TIS); 873511b41d2SMark Murray packet_send(); 874511b41d2SMark Murray packet_write_wait(); 875511b41d2SMark Murray 876511b41d2SMark Murray type = packet_read(&payload_len); 877511b41d2SMark Murray if (type != SSH_SMSG_FAILURE && 878511b41d2SMark Murray type != SSH_SMSG_AUTH_TIS_CHALLENGE) { 879511b41d2SMark Murray packet_disconnect("Protocol error: got %d in response " 880511b41d2SMark Murray "to skey-auth", type); 881511b41d2SMark Murray } 882511b41d2SMark Murray if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) { 883511b41d2SMark Murray debug("No challenge for skey authentication."); 884511b41d2SMark Murray return 0; 885511b41d2SMark Murray } 886511b41d2SMark Murray challenge = packet_get_string(&payload_len); 887511b41d2SMark Murray if (options.cipher == SSH_CIPHER_NONE) 888511b41d2SMark Murray log("WARNING: Encryption is disabled! " 889511b41d2SMark Murray "Reponse will be transmitted in clear text."); 890511b41d2SMark Murray fprintf(stderr, "%s\n", challenge); 891511b41d2SMark Murray xfree(challenge); 892511b41d2SMark Murray fflush(stderr); 893511b41d2SMark Murray for (i = 0; i < options.number_of_password_prompts; i++) { 894511b41d2SMark Murray if (i != 0) 895511b41d2SMark Murray error("Permission denied, please try again."); 896511b41d2SMark Murray response = read_passphrase("Response: ", 0); 897511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_TIS_RESPONSE); 898511b41d2SMark Murray packet_put_string(response, strlen(response)); 899511b41d2SMark Murray memset(response, 0, strlen(response)); 900511b41d2SMark Murray xfree(response); 901511b41d2SMark Murray packet_send(); 902511b41d2SMark Murray packet_write_wait(); 903511b41d2SMark Murray type = packet_read(&payload_len); 904511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) 905511b41d2SMark Murray return 1; 906511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 907511b41d2SMark Murray packet_disconnect("Protocol error: got %d in response " 908511b41d2SMark Murray "to skey-auth-reponse", type); 909511b41d2SMark Murray } 910511b41d2SMark Murray /* failure */ 911511b41d2SMark Murray return 0; 912511b41d2SMark Murray } 913511b41d2SMark Murray 914511b41d2SMark Murray /* 915511b41d2SMark Murray * Tries to authenticate with plain passwd authentication. 916511b41d2SMark Murray */ 917511b41d2SMark Murray int 918511b41d2SMark Murray try_password_authentication(char *prompt) 919511b41d2SMark Murray { 920511b41d2SMark Murray int type, i, payload_len; 921511b41d2SMark Murray char *password; 922511b41d2SMark Murray 923511b41d2SMark Murray debug("Doing password authentication."); 924511b41d2SMark Murray if (options.cipher == SSH_CIPHER_NONE) 925511b41d2SMark Murray log("WARNING: Encryption is disabled! Password will be transmitted in clear text."); 926511b41d2SMark Murray for (i = 0; i < options.number_of_password_prompts; i++) { 927511b41d2SMark Murray if (i != 0) 928511b41d2SMark Murray error("Permission denied, please try again."); 929511b41d2SMark Murray password = read_passphrase(prompt, 0); 930511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_PASSWORD); 931511b41d2SMark Murray packet_put_string(password, strlen(password)); 932511b41d2SMark Murray memset(password, 0, strlen(password)); 933511b41d2SMark Murray xfree(password); 934511b41d2SMark Murray packet_send(); 935511b41d2SMark Murray packet_write_wait(); 936511b41d2SMark Murray 937511b41d2SMark Murray type = packet_read(&payload_len); 938511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) 939511b41d2SMark Murray return 1; 940511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 941511b41d2SMark Murray packet_disconnect("Protocol error: got %d in response to passwd auth", type); 942511b41d2SMark Murray } 943511b41d2SMark Murray /* failure */ 944511b41d2SMark Murray return 0; 945511b41d2SMark Murray } 946511b41d2SMark Murray 947511b41d2SMark Murray /* 948511b41d2SMark Murray * Waits for the server identification string, and sends our own 949511b41d2SMark Murray * identification string. 950511b41d2SMark Murray */ 951511b41d2SMark Murray void 952511b41d2SMark Murray ssh_exchange_identification() 953511b41d2SMark Murray { 954511b41d2SMark Murray char buf[256], remote_version[256]; /* must be same size! */ 955511b41d2SMark Murray int remote_major, remote_minor, i; 956511b41d2SMark Murray int connection_in = packet_get_connection_in(); 957511b41d2SMark Murray int connection_out = packet_get_connection_out(); 958511b41d2SMark Murray 959511b41d2SMark Murray /* Read other side\'s version identification. */ 960511b41d2SMark Murray for (i = 0; i < sizeof(buf) - 1; i++) { 961511b41d2SMark Murray int len = read(connection_in, &buf[i], 1); 962511b41d2SMark Murray if (len < 0) 963511b41d2SMark Murray fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); 964511b41d2SMark Murray if (len != 1) 965511b41d2SMark Murray fatal("ssh_exchange_identification: Connection closed by remote host"); 966511b41d2SMark Murray if (buf[i] == '\r') { 967511b41d2SMark Murray buf[i] = '\n'; 968511b41d2SMark Murray buf[i + 1] = 0; 969511b41d2SMark Murray break; 970511b41d2SMark Murray } 971511b41d2SMark Murray if (buf[i] == '\n') { 972511b41d2SMark Murray buf[i + 1] = 0; 973511b41d2SMark Murray break; 974511b41d2SMark Murray } 975511b41d2SMark Murray } 976511b41d2SMark Murray buf[sizeof(buf) - 1] = 0; 977511b41d2SMark Murray 978511b41d2SMark Murray /* 979511b41d2SMark Murray * Check that the versions match. In future this might accept 980511b41d2SMark Murray * several versions and set appropriate flags to handle them. 981511b41d2SMark Murray */ 982511b41d2SMark Murray if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, 983511b41d2SMark Murray remote_version) != 3) 984511b41d2SMark Murray fatal("Bad remote protocol version identification: '%.100s'", buf); 985511b41d2SMark Murray debug("Remote protocol version %d.%d, remote software version %.100s", 986511b41d2SMark Murray remote_major, remote_minor, remote_version); 987511b41d2SMark Murray 988511b41d2SMark Murray /* Check if the remote protocol version is too old. */ 989511b41d2SMark Murray if (remote_major == 1 && remote_minor < 3) 990511b41d2SMark Murray fatal("Remote machine has too old SSH software version."); 991511b41d2SMark Murray 992511b41d2SMark Murray /* We speak 1.3, too. */ 993511b41d2SMark Murray if (remote_major == 1 && remote_minor == 3) { 994511b41d2SMark Murray enable_compat13(); 995511b41d2SMark Murray if (options.forward_agent) { 996511b41d2SMark Murray log("Agent forwarding disabled for protocol 1.3"); 997511b41d2SMark Murray options.forward_agent = 0; 998511b41d2SMark Murray } 999511b41d2SMark Murray } 1000511b41d2SMark Murray #if 0 1001511b41d2SMark Murray /* 1002511b41d2SMark Murray * Removed for now, to permit compatibility with latter versions. The 1003511b41d2SMark Murray * server will reject our version and disconnect if it doesn't 1004511b41d2SMark Murray * support it. 1005511b41d2SMark Murray */ 1006511b41d2SMark Murray if (remote_major != PROTOCOL_MAJOR) 1007511b41d2SMark Murray fatal("Protocol major versions differ: %d vs. %d", 1008511b41d2SMark Murray PROTOCOL_MAJOR, remote_major); 1009511b41d2SMark Murray #endif 1010511b41d2SMark Murray 1011511b41d2SMark Murray /* Send our own protocol version identification. */ 1012511b41d2SMark Murray snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 1013511b41d2SMark Murray PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); 1014511b41d2SMark Murray if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) 1015511b41d2SMark Murray fatal("write: %.100s", strerror(errno)); 1016511b41d2SMark Murray } 1017511b41d2SMark Murray 1018511b41d2SMark Murray int ssh_cipher_default = SSH_CIPHER_3DES; 1019511b41d2SMark Murray 1020511b41d2SMark Murray int 1021511b41d2SMark Murray read_yes_or_no(const char *prompt, int defval) 1022511b41d2SMark Murray { 1023511b41d2SMark Murray char buf[1024]; 1024511b41d2SMark Murray FILE *f; 1025511b41d2SMark Murray int retval = -1; 1026511b41d2SMark Murray 1027511b41d2SMark Murray if (isatty(0)) 1028511b41d2SMark Murray f = stdin; 1029511b41d2SMark Murray else 1030511b41d2SMark Murray f = fopen("/dev/tty", "rw"); 1031511b41d2SMark Murray 1032511b41d2SMark Murray if (f == NULL) 1033511b41d2SMark Murray return 0; 1034511b41d2SMark Murray 1035511b41d2SMark Murray fflush(stdout); 1036511b41d2SMark Murray 1037511b41d2SMark Murray while (1) { 1038511b41d2SMark Murray fprintf(stderr, "%s", prompt); 1039511b41d2SMark Murray if (fgets(buf, sizeof(buf), f) == NULL) { 1040511b41d2SMark Murray /* Print a newline (the prompt probably didn\'t have one). */ 1041511b41d2SMark Murray fprintf(stderr, "\n"); 1042511b41d2SMark Murray strlcpy(buf, "no", sizeof buf); 1043511b41d2SMark Murray } 1044511b41d2SMark Murray /* Remove newline from response. */ 1045511b41d2SMark Murray if (strchr(buf, '\n')) 1046511b41d2SMark Murray *strchr(buf, '\n') = 0; 1047511b41d2SMark Murray 1048511b41d2SMark Murray if (buf[0] == 0) 1049511b41d2SMark Murray retval = defval; 1050511b41d2SMark Murray if (strcmp(buf, "yes") == 0) 1051511b41d2SMark Murray retval = 1; 1052511b41d2SMark Murray if (strcmp(buf, "no") == 0) 1053511b41d2SMark Murray retval = 0; 1054511b41d2SMark Murray 1055511b41d2SMark Murray if (retval != -1) { 1056511b41d2SMark Murray if (f != stdin) 1057511b41d2SMark Murray fclose(f); 1058511b41d2SMark Murray return retval; 1059511b41d2SMark Murray } 1060511b41d2SMark Murray } 1061511b41d2SMark Murray } 1062511b41d2SMark Murray 1063511b41d2SMark Murray /* 1064511b41d2SMark Murray * check whether the supplied host key is valid, return only if ok. 1065511b41d2SMark Murray */ 1066511b41d2SMark Murray 1067511b41d2SMark Murray void 1068511b41d2SMark Murray check_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key) 1069511b41d2SMark Murray { 1070511b41d2SMark Murray RSA *file_key; 1071511b41d2SMark Murray char *ip = NULL; 1072511b41d2SMark Murray char hostline[1000], *hostp; 1073511b41d2SMark Murray HostStatus host_status; 1074511b41d2SMark Murray HostStatus ip_status; 1075511b41d2SMark Murray int local = 0, host_ip_differ = 0; 1076511b41d2SMark Murray char ntop[NI_MAXHOST]; 1077511b41d2SMark Murray 1078511b41d2SMark Murray /* 1079511b41d2SMark Murray * Force accepting of the host key for loopback/localhost. The 1080511b41d2SMark Murray * problem is that if the home directory is NFS-mounted to multiple 1081511b41d2SMark Murray * machines, localhost will refer to a different machine in each of 1082511b41d2SMark Murray * them, and the user will get bogus HOST_CHANGED warnings. This 1083511b41d2SMark Murray * essentially disables host authentication for localhost; however, 1084511b41d2SMark Murray * this is probably not a real problem. 1085511b41d2SMark Murray */ 1086511b41d2SMark Murray switch (hostaddr->sa_family) { 1087511b41d2SMark Murray case AF_INET: 1088511b41d2SMark Murray local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 1089511b41d2SMark Murray break; 109042f71286SMark Murray #ifdef INET6 1091511b41d2SMark Murray case AF_INET6: 1092511b41d2SMark Murray local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); 1093511b41d2SMark Murray break; 109442f71286SMark Murray #endif 1095511b41d2SMark Murray default: 1096511b41d2SMark Murray local = 0; 1097511b41d2SMark Murray break; 1098511b41d2SMark Murray } 1099511b41d2SMark Murray if (local) { 1100511b41d2SMark Murray debug("Forcing accepting of host key for loopback/localhost."); 1101511b41d2SMark Murray return; 1102511b41d2SMark Murray } 1103511b41d2SMark Murray 1104511b41d2SMark Murray /* 1105511b41d2SMark Murray * Turn off check_host_ip for proxy connects, since 1106511b41d2SMark Murray * we don't have the remote ip-address 1107511b41d2SMark Murray */ 1108511b41d2SMark Murray if (options.proxy_command != NULL && options.check_host_ip) 1109511b41d2SMark Murray options.check_host_ip = 0; 1110511b41d2SMark Murray 1111511b41d2SMark Murray if (options.check_host_ip) { 1112511b41d2SMark Murray if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop), 1113511b41d2SMark Murray NULL, 0, NI_NUMERICHOST) != 0) 1114511b41d2SMark Murray fatal("check_host_key: getnameinfo failed"); 1115511b41d2SMark Murray ip = xstrdup(ntop); 1116511b41d2SMark Murray } 1117511b41d2SMark Murray 1118511b41d2SMark Murray /* 1119511b41d2SMark Murray * Store the host key from the known host file in here so that we can 1120511b41d2SMark Murray * compare it with the key for the IP address. 1121511b41d2SMark Murray */ 1122511b41d2SMark Murray file_key = RSA_new(); 1123511b41d2SMark Murray file_key->n = BN_new(); 1124511b41d2SMark Murray file_key->e = BN_new(); 1125511b41d2SMark Murray 1126511b41d2SMark Murray /* 1127511b41d2SMark Murray * Check if the host key is present in the user\'s list of known 1128511b41d2SMark Murray * hosts or in the systemwide list. 1129511b41d2SMark Murray */ 1130511b41d2SMark Murray host_status = check_host_in_hostfile(options.user_hostfile, host, 1131511b41d2SMark Murray host_key->e, host_key->n, 1132511b41d2SMark Murray file_key->e, file_key->n); 1133511b41d2SMark Murray if (host_status == HOST_NEW) 1134511b41d2SMark Murray host_status = check_host_in_hostfile(options.system_hostfile, host, 1135511b41d2SMark Murray host_key->e, host_key->n, 1136511b41d2SMark Murray file_key->e, file_key->n); 1137511b41d2SMark Murray /* 1138511b41d2SMark Murray * Also perform check for the ip address, skip the check if we are 1139511b41d2SMark Murray * localhost or the hostname was an ip address to begin with 1140511b41d2SMark Murray */ 1141511b41d2SMark Murray if (options.check_host_ip && !local && strcmp(host, ip)) { 1142511b41d2SMark Murray RSA *ip_key = RSA_new(); 1143511b41d2SMark Murray ip_key->n = BN_new(); 1144511b41d2SMark Murray ip_key->e = BN_new(); 1145511b41d2SMark Murray ip_status = check_host_in_hostfile(options.user_hostfile, ip, 1146511b41d2SMark Murray host_key->e, host_key->n, 1147511b41d2SMark Murray ip_key->e, ip_key->n); 1148511b41d2SMark Murray 1149511b41d2SMark Murray if (ip_status == HOST_NEW) 1150511b41d2SMark Murray ip_status = check_host_in_hostfile(options.system_hostfile, ip, 1151511b41d2SMark Murray host_key->e, host_key->n, 1152511b41d2SMark Murray ip_key->e, ip_key->n); 1153511b41d2SMark Murray if (host_status == HOST_CHANGED && 1154511b41d2SMark Murray (ip_status != HOST_CHANGED || 1155511b41d2SMark Murray (BN_cmp(ip_key->e, file_key->e) || BN_cmp(ip_key->n, file_key->n)))) 1156511b41d2SMark Murray host_ip_differ = 1; 1157511b41d2SMark Murray 1158511b41d2SMark Murray RSA_free(ip_key); 1159511b41d2SMark Murray } else 1160511b41d2SMark Murray ip_status = host_status; 1161511b41d2SMark Murray 1162511b41d2SMark Murray RSA_free(file_key); 1163511b41d2SMark Murray 1164511b41d2SMark Murray switch (host_status) { 1165511b41d2SMark Murray case HOST_OK: 1166511b41d2SMark Murray /* The host is known and the key matches. */ 1167511b41d2SMark Murray debug("Host '%.200s' is known and matches the host key.", host); 1168511b41d2SMark Murray if (options.check_host_ip) { 1169511b41d2SMark Murray if (ip_status == HOST_NEW) { 1170511b41d2SMark Murray if (!add_host_to_hostfile(options.user_hostfile, ip, 1171511b41d2SMark Murray host_key->e, host_key->n)) 1172511b41d2SMark Murray log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).", 1173511b41d2SMark Murray ip, options.user_hostfile); 1174511b41d2SMark Murray else 1175511b41d2SMark Murray log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.", 1176511b41d2SMark Murray ip); 1177511b41d2SMark Murray } else if (ip_status != HOST_OK) 1178511b41d2SMark Murray log("Warning: the host key for '%.200s' differs from the key for the IP address '%.30s'", 1179511b41d2SMark Murray host, ip); 1180511b41d2SMark Murray } 1181511b41d2SMark Murray break; 1182511b41d2SMark Murray case HOST_NEW: 1183511b41d2SMark Murray /* The host is new. */ 1184511b41d2SMark Murray if (options.strict_host_key_checking == 1) { 1185511b41d2SMark Murray /* User has requested strict host key checking. We will not add the host key 1186511b41d2SMark Murray automatically. The only alternative left is to abort. */ 1187511b41d2SMark Murray fatal("No host key is known for %.200s and you have requested strict checking.", host); 1188511b41d2SMark Murray } else if (options.strict_host_key_checking == 2) { 1189511b41d2SMark Murray /* The default */ 1190511b41d2SMark Murray char prompt[1024]; 1191511b41d2SMark Murray char *fp = fingerprint(host_key->e, host_key->n); 1192511b41d2SMark Murray snprintf(prompt, sizeof(prompt), 1193511b41d2SMark Murray "The authenticity of host '%.200s' can't be established.\n" 1194511b41d2SMark Murray "Key fingerprint is %d %s.\n" 1195511b41d2SMark Murray "Are you sure you want to continue connecting (yes/no)? ", 1196511b41d2SMark Murray host, BN_num_bits(host_key->n), fp); 1197511b41d2SMark Murray if (!read_yes_or_no(prompt, -1)) 1198511b41d2SMark Murray fatal("Aborted by user!\n"); 1199511b41d2SMark Murray } 1200511b41d2SMark Murray if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) { 1201511b41d2SMark Murray snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 1202511b41d2SMark Murray hostp = hostline; 1203511b41d2SMark Murray } else 1204511b41d2SMark Murray hostp = host; 1205511b41d2SMark Murray 1206511b41d2SMark Murray /* If not in strict mode, add the key automatically to the local known_hosts file. */ 1207511b41d2SMark Murray if (!add_host_to_hostfile(options.user_hostfile, hostp, 1208511b41d2SMark Murray host_key->e, host_key->n)) 1209511b41d2SMark Murray log("Failed to add the host to the list of known hosts (%.500s).", 1210511b41d2SMark Murray options.user_hostfile); 1211511b41d2SMark Murray else 1212511b41d2SMark Murray log("Warning: Permanently added '%.200s' to the list of known hosts.", 1213511b41d2SMark Murray hostp); 1214511b41d2SMark Murray break; 1215511b41d2SMark Murray case HOST_CHANGED: 1216511b41d2SMark Murray if (options.check_host_ip && host_ip_differ) { 1217511b41d2SMark Murray char *msg; 1218511b41d2SMark Murray if (ip_status == HOST_NEW) 1219511b41d2SMark Murray msg = "is unknown"; 1220511b41d2SMark Murray else if (ip_status == HOST_OK) 1221511b41d2SMark Murray msg = "is unchanged"; 1222511b41d2SMark Murray else 1223511b41d2SMark Murray msg = "has a different value"; 1224511b41d2SMark Murray error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1225511b41d2SMark Murray error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 1226511b41d2SMark Murray error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1227511b41d2SMark Murray error("The host key for %s has changed,", host); 1228511b41d2SMark Murray error("and the key for the according IP address %s", ip); 1229511b41d2SMark Murray error("%s. This could either mean that", msg); 1230511b41d2SMark Murray error("DNS SPOOFING is happening or the IP address for the host"); 1231511b41d2SMark Murray error("and its host key have changed at the same time"); 1232511b41d2SMark Murray } 1233511b41d2SMark Murray /* The host key has changed. */ 1234511b41d2SMark Murray error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1235511b41d2SMark Murray error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 1236511b41d2SMark Murray error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1237511b41d2SMark Murray error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1238511b41d2SMark Murray error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1239511b41d2SMark Murray error("It is also possible that the host key has just been changed."); 1240511b41d2SMark Murray error("Please contact your system administrator."); 1241511b41d2SMark Murray error("Add correct host key in %.100s to get rid of this message.", 1242511b41d2SMark Murray options.user_hostfile); 1243511b41d2SMark Murray 1244511b41d2SMark Murray /* 1245511b41d2SMark Murray * If strict host key checking is in use, the user will have 1246511b41d2SMark Murray * to edit the key manually and we can only abort. 1247511b41d2SMark Murray */ 1248511b41d2SMark Murray if (options.strict_host_key_checking) 1249511b41d2SMark Murray fatal("Host key for %.200s has changed and you have requested strict checking.", host); 1250511b41d2SMark Murray 1251511b41d2SMark Murray /* 1252511b41d2SMark Murray * If strict host key checking has not been requested, allow 1253511b41d2SMark Murray * the connection but without password authentication or 1254511b41d2SMark Murray * agent forwarding. 1255511b41d2SMark Murray */ 1256511b41d2SMark Murray if (options.password_authentication) { 1257511b41d2SMark Murray error("Password authentication is disabled to avoid trojan horses."); 1258511b41d2SMark Murray options.password_authentication = 0; 1259511b41d2SMark Murray } 1260511b41d2SMark Murray if (options.forward_agent) { 1261511b41d2SMark Murray error("Agent forwarding is disabled to avoid trojan horses."); 1262511b41d2SMark Murray options.forward_agent = 0; 1263511b41d2SMark Murray } 1264511b41d2SMark Murray /* 1265511b41d2SMark Murray * XXX Should permit the user to change to use the new id. 1266511b41d2SMark Murray * This could be done by converting the host key to an 1267511b41d2SMark Murray * identifying sentence, tell that the host identifies itself 1268511b41d2SMark Murray * by that sentence, and ask the user if he/she whishes to 1269511b41d2SMark Murray * accept the authentication. 1270511b41d2SMark Murray */ 1271511b41d2SMark Murray break; 1272511b41d2SMark Murray } 1273511b41d2SMark Murray if (options.check_host_ip) 1274511b41d2SMark Murray xfree(ip); 1275511b41d2SMark Murray } 1276511b41d2SMark Murray 1277511b41d2SMark Murray /* 1278511b41d2SMark Murray * SSH1 key exchange 1279511b41d2SMark Murray */ 1280511b41d2SMark Murray void 1281511b41d2SMark Murray ssh_kex(char *host, struct sockaddr *hostaddr) 1282511b41d2SMark Murray { 1283511b41d2SMark Murray int i; 1284511b41d2SMark Murray BIGNUM *key; 1285511b41d2SMark Murray RSA *host_key; 1286511b41d2SMark Murray RSA *public_key; 1287511b41d2SMark Murray int bits, rbits; 1288511b41d2SMark Murray unsigned char session_key[SSH_SESSION_KEY_LENGTH]; 1289511b41d2SMark Murray unsigned char cookie[8]; 1290511b41d2SMark Murray unsigned int supported_ciphers; 1291511b41d2SMark Murray unsigned int server_flags, client_flags; 1292511b41d2SMark Murray int payload_len, clen, sum_len = 0; 1293511b41d2SMark Murray u_int32_t rand = 0; 1294511b41d2SMark Murray 1295511b41d2SMark Murray debug("Waiting for server public key."); 1296511b41d2SMark Murray 1297511b41d2SMark Murray /* Wait for a public key packet from the server. */ 1298511b41d2SMark Murray packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); 1299511b41d2SMark Murray 1300511b41d2SMark Murray /* Get cookie from the packet. */ 1301511b41d2SMark Murray for (i = 0; i < 8; i++) 1302511b41d2SMark Murray cookie[i] = packet_get_char(); 1303511b41d2SMark Murray 1304511b41d2SMark Murray /* Get the public key. */ 1305511b41d2SMark Murray public_key = RSA_new(); 1306511b41d2SMark Murray bits = packet_get_int();/* bits */ 1307511b41d2SMark Murray public_key->e = BN_new(); 1308511b41d2SMark Murray packet_get_bignum(public_key->e, &clen); 1309511b41d2SMark Murray sum_len += clen; 1310511b41d2SMark Murray public_key->n = BN_new(); 1311511b41d2SMark Murray packet_get_bignum(public_key->n, &clen); 1312511b41d2SMark Murray sum_len += clen; 1313511b41d2SMark Murray 1314511b41d2SMark Murray rbits = BN_num_bits(public_key->n); 1315511b41d2SMark Murray if (bits != rbits) { 1316511b41d2SMark Murray log("Warning: Server lies about size of server public key: " 1317511b41d2SMark Murray "actual size is %d bits vs. announced %d.", rbits, bits); 1318511b41d2SMark Murray log("Warning: This may be due to an old implementation of ssh."); 1319511b41d2SMark Murray } 1320511b41d2SMark Murray /* Get the host key. */ 1321511b41d2SMark Murray host_key = RSA_new(); 1322511b41d2SMark Murray bits = packet_get_int();/* bits */ 1323511b41d2SMark Murray host_key->e = BN_new(); 1324511b41d2SMark Murray packet_get_bignum(host_key->e, &clen); 1325511b41d2SMark Murray sum_len += clen; 1326511b41d2SMark Murray host_key->n = BN_new(); 1327511b41d2SMark Murray packet_get_bignum(host_key->n, &clen); 1328511b41d2SMark Murray sum_len += clen; 1329511b41d2SMark Murray 1330511b41d2SMark Murray rbits = BN_num_bits(host_key->n); 1331511b41d2SMark Murray if (bits != rbits) { 1332511b41d2SMark Murray log("Warning: Server lies about size of server host key: " 1333511b41d2SMark Murray "actual size is %d bits vs. announced %d.", rbits, bits); 1334511b41d2SMark Murray log("Warning: This may be due to an old implementation of ssh."); 1335511b41d2SMark Murray } 1336511b41d2SMark Murray 1337511b41d2SMark Murray /* Get protocol flags. */ 1338511b41d2SMark Murray server_flags = packet_get_int(); 1339511b41d2SMark Murray packet_set_protocol_flags(server_flags); 1340511b41d2SMark Murray 1341511b41d2SMark Murray supported_ciphers = packet_get_int(); 1342511b41d2SMark Murray supported_authentications = packet_get_int(); 1343511b41d2SMark Murray 1344511b41d2SMark Murray debug("Received server public key (%d bits) and host key (%d bits).", 1345511b41d2SMark Murray BN_num_bits(public_key->n), BN_num_bits(host_key->n)); 1346511b41d2SMark Murray 1347511b41d2SMark Murray packet_integrity_check(payload_len, 1348511b41d2SMark Murray 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, 1349511b41d2SMark Murray SSH_SMSG_PUBLIC_KEY); 1350511b41d2SMark Murray 1351511b41d2SMark Murray check_host_key(host, hostaddr, host_key); 1352511b41d2SMark Murray 1353511b41d2SMark Murray client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN; 1354511b41d2SMark Murray 1355511b41d2SMark Murray compute_session_id(session_id, cookie, host_key->n, public_key->n); 1356511b41d2SMark Murray 1357511b41d2SMark Murray /* Generate a session key. */ 1358511b41d2SMark Murray arc4random_stir(); 1359511b41d2SMark Murray 1360511b41d2SMark Murray /* 1361511b41d2SMark Murray * Generate an encryption key for the session. The key is a 256 bit 1362511b41d2SMark Murray * random number, interpreted as a 32-byte key, with the least 1363511b41d2SMark Murray * significant 8 bits being the first byte of the key. 1364511b41d2SMark Murray */ 1365511b41d2SMark Murray for (i = 0; i < 32; i++) { 1366511b41d2SMark Murray if (i % 4 == 0) 1367511b41d2SMark Murray rand = arc4random(); 1368511b41d2SMark Murray session_key[i] = rand & 0xff; 1369511b41d2SMark Murray rand >>= 8; 1370511b41d2SMark Murray } 1371511b41d2SMark Murray 1372511b41d2SMark Murray /* 1373511b41d2SMark Murray * According to the protocol spec, the first byte of the session key 1374511b41d2SMark Murray * is the highest byte of the integer. The session key is xored with 1375511b41d2SMark Murray * the first 16 bytes of the session id. 1376511b41d2SMark Murray */ 1377511b41d2SMark Murray key = BN_new(); 1378511b41d2SMark Murray BN_set_word(key, 0); 1379511b41d2SMark Murray for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { 1380511b41d2SMark Murray BN_lshift(key, key, 8); 1381511b41d2SMark Murray if (i < 16) 1382511b41d2SMark Murray BN_add_word(key, session_key[i] ^ session_id[i]); 1383511b41d2SMark Murray else 1384511b41d2SMark Murray BN_add_word(key, session_key[i]); 1385511b41d2SMark Murray } 1386511b41d2SMark Murray 1387511b41d2SMark Murray /* 1388511b41d2SMark Murray * Encrypt the integer using the public key and host key of the 1389511b41d2SMark Murray * server (key with smaller modulus first). 1390511b41d2SMark Murray */ 1391511b41d2SMark Murray if (BN_cmp(public_key->n, host_key->n) < 0) { 1392511b41d2SMark Murray /* Public key has smaller modulus. */ 1393511b41d2SMark Murray if (BN_num_bits(host_key->n) < 1394511b41d2SMark Murray BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) { 1395511b41d2SMark Murray fatal("respond_to_rsa_challenge: host_key %d < public_key %d + " 1396511b41d2SMark Murray "SSH_KEY_BITS_RESERVED %d", 1397511b41d2SMark Murray BN_num_bits(host_key->n), 1398511b41d2SMark Murray BN_num_bits(public_key->n), 1399511b41d2SMark Murray SSH_KEY_BITS_RESERVED); 1400511b41d2SMark Murray } 1401511b41d2SMark Murray rsa_public_encrypt(key, key, public_key); 1402511b41d2SMark Murray rsa_public_encrypt(key, key, host_key); 1403511b41d2SMark Murray } else { 1404511b41d2SMark Murray /* Host key has smaller modulus (or they are equal). */ 1405511b41d2SMark Murray if (BN_num_bits(public_key->n) < 1406511b41d2SMark Murray BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) { 1407511b41d2SMark Murray fatal("respond_to_rsa_challenge: public_key %d < host_key %d + " 1408511b41d2SMark Murray "SSH_KEY_BITS_RESERVED %d", 1409511b41d2SMark Murray BN_num_bits(public_key->n), 1410511b41d2SMark Murray BN_num_bits(host_key->n), 1411511b41d2SMark Murray SSH_KEY_BITS_RESERVED); 1412511b41d2SMark Murray } 1413511b41d2SMark Murray rsa_public_encrypt(key, key, host_key); 1414511b41d2SMark Murray rsa_public_encrypt(key, key, public_key); 1415511b41d2SMark Murray } 1416511b41d2SMark Murray 1417511b41d2SMark Murray /* Destroy the public keys since we no longer need them. */ 1418511b41d2SMark Murray RSA_free(public_key); 1419511b41d2SMark Murray RSA_free(host_key); 1420511b41d2SMark Murray 1421511b41d2SMark Murray if (options.cipher == SSH_CIPHER_NOT_SET) { 1422511b41d2SMark Murray if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default)) 1423511b41d2SMark Murray options.cipher = ssh_cipher_default; 1424511b41d2SMark Murray else { 1425511b41d2SMark Murray debug("Cipher %s not supported, using %.100s instead.", 1426511b41d2SMark Murray cipher_name(ssh_cipher_default), 1427511b41d2SMark Murray cipher_name(SSH_FALLBACK_CIPHER)); 1428511b41d2SMark Murray options.cipher = SSH_FALLBACK_CIPHER; 1429511b41d2SMark Murray } 1430511b41d2SMark Murray } 1431511b41d2SMark Murray /* Check that the selected cipher is supported. */ 1432511b41d2SMark Murray if (!(supported_ciphers & (1 << options.cipher))) 1433511b41d2SMark Murray fatal("Selected cipher type %.100s not supported by server.", 1434511b41d2SMark Murray cipher_name(options.cipher)); 1435511b41d2SMark Murray 1436511b41d2SMark Murray debug("Encryption type: %.100s", cipher_name(options.cipher)); 1437511b41d2SMark Murray 1438511b41d2SMark Murray /* Send the encrypted session key to the server. */ 1439511b41d2SMark Murray packet_start(SSH_CMSG_SESSION_KEY); 1440511b41d2SMark Murray packet_put_char(options.cipher); 1441511b41d2SMark Murray 1442511b41d2SMark Murray /* Send the cookie back to the server. */ 1443511b41d2SMark Murray for (i = 0; i < 8; i++) 1444511b41d2SMark Murray packet_put_char(cookie[i]); 1445511b41d2SMark Murray 1446511b41d2SMark Murray /* Send and destroy the encrypted encryption key integer. */ 1447511b41d2SMark Murray packet_put_bignum(key); 1448511b41d2SMark Murray BN_clear_free(key); 1449511b41d2SMark Murray 1450511b41d2SMark Murray /* Send protocol flags. */ 1451511b41d2SMark Murray packet_put_int(client_flags); 1452511b41d2SMark Murray 1453511b41d2SMark Murray /* Send the packet now. */ 1454511b41d2SMark Murray packet_send(); 1455511b41d2SMark Murray packet_write_wait(); 1456511b41d2SMark Murray 1457511b41d2SMark Murray debug("Sent encrypted session key."); 1458511b41d2SMark Murray 1459511b41d2SMark Murray /* Set the encryption key. */ 1460511b41d2SMark Murray packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher); 1461511b41d2SMark Murray 1462511b41d2SMark Murray /* We will no longer need the session key here. Destroy any extra copies. */ 1463511b41d2SMark Murray memset(session_key, 0, sizeof(session_key)); 1464511b41d2SMark Murray 1465511b41d2SMark Murray /* 1466511b41d2SMark Murray * Expect a success message from the server. Note that this message 1467511b41d2SMark Murray * will be received in encrypted form. 1468511b41d2SMark Murray */ 1469511b41d2SMark Murray packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); 1470511b41d2SMark Murray 1471511b41d2SMark Murray debug("Received encrypted confirmation."); 1472511b41d2SMark Murray } 1473511b41d2SMark Murray 1474511b41d2SMark Murray /* 1475511b41d2SMark Murray * Authenticate user 1476511b41d2SMark Murray */ 1477511b41d2SMark Murray void 1478511b41d2SMark Murray ssh_userauth(int host_key_valid, RSA *own_host_key, 1479511b41d2SMark Murray uid_t original_real_uid, char *host) 1480511b41d2SMark Murray { 1481511b41d2SMark Murray int i, type; 1482511b41d2SMark Murray int payload_len; 1483511b41d2SMark Murray struct passwd *pw; 1484511b41d2SMark Murray const char *server_user, *local_user; 1485511b41d2SMark Murray 1486511b41d2SMark Murray /* Get local user name. Use it as server user if no user name was given. */ 1487511b41d2SMark Murray pw = getpwuid(original_real_uid); 1488511b41d2SMark Murray if (!pw) 1489511b41d2SMark Murray fatal("User id %d not found from user database.", original_real_uid); 1490511b41d2SMark Murray local_user = xstrdup(pw->pw_name); 1491511b41d2SMark Murray server_user = options.user ? options.user : local_user; 1492511b41d2SMark Murray 1493511b41d2SMark Murray /* Send the name of the user to log in as on the server. */ 1494511b41d2SMark Murray packet_start(SSH_CMSG_USER); 1495511b41d2SMark Murray packet_put_string(server_user, strlen(server_user)); 1496511b41d2SMark Murray packet_send(); 1497511b41d2SMark Murray packet_write_wait(); 1498511b41d2SMark Murray 1499511b41d2SMark Murray /* 1500511b41d2SMark Murray * The server should respond with success if no authentication is 1501511b41d2SMark Murray * needed (the user has no password). Otherwise the server responds 1502511b41d2SMark Murray * with failure. 1503511b41d2SMark Murray */ 1504511b41d2SMark Murray type = packet_read(&payload_len); 1505511b41d2SMark Murray 1506511b41d2SMark Murray /* check whether the connection was accepted without authentication. */ 1507511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) 1508511b41d2SMark Murray return; 1509511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 1510511b41d2SMark Murray packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", 1511511b41d2SMark Murray type); 1512511b41d2SMark Murray 1513511b41d2SMark Murray #ifdef AFS 1514511b41d2SMark Murray /* Try Kerberos tgt passing if the server supports it. */ 1515511b41d2SMark Murray if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && 1516511b41d2SMark Murray options.kerberos_tgt_passing) { 1517511b41d2SMark Murray if (options.cipher == SSH_CIPHER_NONE) 1518511b41d2SMark Murray log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); 1519511b41d2SMark Murray (void) send_kerberos_tgt(); 1520511b41d2SMark Murray } 1521511b41d2SMark Murray /* Try AFS token passing if the server supports it. */ 1522511b41d2SMark Murray if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && 1523511b41d2SMark Murray options.afs_token_passing && k_hasafs()) { 1524511b41d2SMark Murray if (options.cipher == SSH_CIPHER_NONE) 1525511b41d2SMark Murray log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); 1526511b41d2SMark Murray send_afs_tokens(); 1527511b41d2SMark Murray } 1528511b41d2SMark Murray #endif /* AFS */ 1529511b41d2SMark Murray 1530511b41d2SMark Murray #ifdef KRB4 1531511b41d2SMark Murray if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && 1532511b41d2SMark Murray options.kerberos_authentication) { 1533511b41d2SMark Murray debug("Trying Kerberos authentication."); 1534511b41d2SMark Murray if (try_kerberos_authentication()) { 1535511b41d2SMark Murray /* The server should respond with success or failure. */ 1536511b41d2SMark Murray type = packet_read(&payload_len); 1537511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) 1538511b41d2SMark Murray return; 1539511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 1540511b41d2SMark Murray packet_disconnect("Protocol error: got %d in response to Kerberos auth", type); 1541511b41d2SMark Murray } 1542511b41d2SMark Murray } 1543511b41d2SMark Murray #endif /* KRB4 */ 1544511b41d2SMark Murray 1545511b41d2SMark Murray /* 1546511b41d2SMark Murray * Use rhosts authentication if running in privileged socket and we 1547511b41d2SMark Murray * do not wish to remain anonymous. 1548511b41d2SMark Murray */ 1549511b41d2SMark Murray if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && 1550511b41d2SMark Murray options.rhosts_authentication) { 1551511b41d2SMark Murray debug("Trying rhosts authentication."); 1552511b41d2SMark Murray packet_start(SSH_CMSG_AUTH_RHOSTS); 1553511b41d2SMark Murray packet_put_string(local_user, strlen(local_user)); 1554511b41d2SMark Murray packet_send(); 1555511b41d2SMark Murray packet_write_wait(); 1556511b41d2SMark Murray 1557511b41d2SMark Murray /* The server should respond with success or failure. */ 1558511b41d2SMark Murray type = packet_read(&payload_len); 1559511b41d2SMark Murray if (type == SSH_SMSG_SUCCESS) 1560511b41d2SMark Murray return; 1561511b41d2SMark Murray if (type != SSH_SMSG_FAILURE) 1562511b41d2SMark Murray packet_disconnect("Protocol error: got %d in response to rhosts auth", 1563511b41d2SMark Murray type); 1564511b41d2SMark Murray } 1565511b41d2SMark Murray /* 1566511b41d2SMark Murray * Try .rhosts or /etc/hosts.equiv authentication with RSA host 1567511b41d2SMark Murray * authentication. 1568511b41d2SMark Murray */ 1569511b41d2SMark Murray if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && 1570511b41d2SMark Murray options.rhosts_rsa_authentication && host_key_valid) { 1571511b41d2SMark Murray if (try_rhosts_rsa_authentication(local_user, own_host_key)) 1572511b41d2SMark Murray return; 1573511b41d2SMark Murray } 1574511b41d2SMark Murray /* Try RSA authentication if the server supports it. */ 1575511b41d2SMark Murray if ((supported_authentications & (1 << SSH_AUTH_RSA)) && 1576511b41d2SMark Murray options.rsa_authentication) { 1577511b41d2SMark Murray /* 1578511b41d2SMark Murray * Try RSA authentication using the authentication agent. The 1579511b41d2SMark Murray * agent is tried first because no passphrase is needed for 1580511b41d2SMark Murray * it, whereas identity files may require passphrases. 1581511b41d2SMark Murray */ 1582511b41d2SMark Murray if (try_agent_authentication()) 1583511b41d2SMark Murray return; 1584511b41d2SMark Murray 1585511b41d2SMark Murray /* Try RSA authentication for each identity. */ 1586511b41d2SMark Murray for (i = 0; i < options.num_identity_files; i++) 1587511b41d2SMark Murray if (try_rsa_authentication(options.identity_files[i])) 1588511b41d2SMark Murray return; 1589511b41d2SMark Murray } 1590511b41d2SMark Murray /* Try skey authentication if the server supports it. */ 1591511b41d2SMark Murray if ((supported_authentications & (1 << SSH_AUTH_TIS)) && 1592511b41d2SMark Murray options.skey_authentication && !options.batch_mode) { 1593511b41d2SMark Murray if (try_skey_authentication()) 1594511b41d2SMark Murray return; 1595511b41d2SMark Murray } 1596511b41d2SMark Murray /* Try password authentication if the server supports it. */ 1597511b41d2SMark Murray if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && 1598511b41d2SMark Murray options.password_authentication && !options.batch_mode) { 1599511b41d2SMark Murray char prompt[80]; 1600511b41d2SMark Murray 1601511b41d2SMark Murray snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", 1602511b41d2SMark Murray server_user, host); 1603511b41d2SMark Murray if (try_password_authentication(prompt)) 1604511b41d2SMark Murray return; 1605511b41d2SMark Murray } 1606511b41d2SMark Murray /* All authentication methods have failed. Exit with an error message. */ 1607511b41d2SMark Murray fatal("Permission denied."); 1608511b41d2SMark Murray /* NOTREACHED */ 1609511b41d2SMark Murray } 1610511b41d2SMark Murray 1611511b41d2SMark Murray /* 1612511b41d2SMark Murray * Starts a dialog with the server, and authenticates the current user on the 1613511b41d2SMark Murray * server. This does not need any extra privileges. The basic connection 1614511b41d2SMark Murray * to the server must already have been established before this is called. 1615511b41d2SMark Murray * If login fails, this function prints an error and never returns. 1616511b41d2SMark Murray * This function does not require super-user privileges. 1617511b41d2SMark Murray */ 1618511b41d2SMark Murray void 1619511b41d2SMark Murray ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost, 1620511b41d2SMark Murray struct sockaddr *hostaddr, uid_t original_real_uid) 1621511b41d2SMark Murray { 1622511b41d2SMark Murray char *host, *cp; 1623511b41d2SMark Murray 1624511b41d2SMark Murray /* Convert the user-supplied hostname into all lowercase. */ 1625511b41d2SMark Murray host = xstrdup(orighost); 1626511b41d2SMark Murray for (cp = host; *cp; cp++) 1627511b41d2SMark Murray if (isupper(*cp)) 1628511b41d2SMark Murray *cp = tolower(*cp); 1629511b41d2SMark Murray 1630511b41d2SMark Murray /* Exchange protocol version identification strings with the server. */ 1631511b41d2SMark Murray ssh_exchange_identification(); 1632511b41d2SMark Murray 1633511b41d2SMark Murray /* Put the connection into non-blocking mode. */ 1634511b41d2SMark Murray packet_set_nonblocking(); 1635511b41d2SMark Murray 1636511b41d2SMark Murray supported_authentications = 0; 1637511b41d2SMark Murray /* key exchange */ 1638511b41d2SMark Murray ssh_kex(host, hostaddr); 1639511b41d2SMark Murray if (supported_authentications == 0) 1640511b41d2SMark Murray fatal("supported_authentications == 0."); 1641511b41d2SMark Murray /* authenticate user */ 1642511b41d2SMark Murray ssh_userauth(host_key_valid, own_host_key, original_real_uid, host); 1643511b41d2SMark Murray } 1644