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