- }
- buf[sizeof(buf) - 1] = 0;
-
- /* Check that the versions match. In future this might accept several
- versions and set appropriate flags to handle them. */
- if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
- remote_version) != 3)
- {
- const char *s = "Protocol mismatch.\n";
- (void) write(sock_out, s, strlen(s));
- close(sock_in);
- close(sock_out);
- fatal("Bad protocol version identification: %.100s", buf);
- }
- debug("Client protocol version %d.%d; client software version %.100s",
- remote_major, remote_minor, remote_version);
- if (remote_major != PROTOCOL_MAJOR)
- {
- const char *s = "Protocol major versions differ.\n";
- (void) write(sock_out, s, strlen(s));
- close(sock_in);
- close(sock_out);
- fatal("Protocol major versions differ: %d vs. %d",
- PROTOCOL_MAJOR, remote_major);
- }
-
- /* Check that the client has sufficiently high software version. */
- if (remote_major == 1 && remote_minor < 3)
- packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version.");
-
- if (remote_major == 1 && remote_minor == 3) {
- enable_compat13();
- if (strcmp(remote_version, "OpenSSH-1.1") != 0) {
- debug("Agent forwarding disabled, remote version is not compatible.");
- no_agent_forwarding_flag = 1;
- }
- }
-
- packet_set_nonblocking();
-
- /* Handle the connection. We pass as argument whether the connection
- came from a privileged port. */
- do_connection(get_remote_port() < IPPORT_RESERVED);
-
-#ifdef KRB4
- /* Cleanup user's ticket cache file. */
- if (options.kerberos_ticket_cleanup)
- (void) dest_tkt();
-#endif /* KRB4 */
-
- /* Cleanup user's local Xauthority file. */
- if (xauthfile) unlink(xauthfile);
-
- /* The connection has been terminated. */
- log("Closing connection to %.100s", inet_ntoa(sin.sin_addr));
-
-#ifdef HAVE_LIBPAM
- {
- int retval;
-
- if (pamh != NULL)
- {
- debug("Closing PAM session.");
- retval = pam_close_session((pam_handle_t *)pamh, 0);
-
- debug("Terminating PAM library.");
- if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
- log("Cannot release PAM authentication.");
-
- fatal_remove_cleanup(&pam_cleanup_proc, NULL);
- }
- }
-#endif /* HAVE_LIBPAM */
-
- packet_close();
-
- exit(0);
-}
-
-/* Process an incoming connection. Protocol version identifiers have already
- been exchanged. This sends server key and performs the key exchange.
- Server and host keys will no longer be needed after this functions. */
-
-void do_connection(int privileged_port)
-{
- int i, len;
- BIGNUM *session_key_int;
- unsigned char session_key[SSH_SESSION_KEY_LENGTH];
- unsigned char check_bytes[8];
- char *user;
- unsigned int cipher_type, auth_mask, protocol_flags;
- int plen, slen;
- u_int32_t rand = 0;
-
- /* Generate check bytes that the client must send back in the user packet
- in order for it to be accepted; this is used to defy ip spoofing
- attacks. Note that this only works against somebody doing IP spoofing
- from a remote machine; any machine on the local network can still see
- outgoing packets and catch the random cookie. This only affects
- rhosts authentication, and this is one of the reasons why it is
- inherently insecure. */
- for (i = 0; i < 8; i++) {
- if (i % 4 == 0)
- rand = arc4random();
- check_bytes[i] = rand & 0xff;
- rand >>= 8;
- }
-
- /* Send our public key. We include in the packet 64 bits of random
- data that must be matched in the reply in order to prevent IP spoofing. */
- packet_start(SSH_SMSG_PUBLIC_KEY);
- for (i = 0; i < 8; i++)
- packet_put_char(check_bytes[i]);
-
- /* Store our public server RSA key. */
- packet_put_int(BN_num_bits(public_key->n));
- packet_put_bignum(public_key->e);
- packet_put_bignum(public_key->n);
-
- /* Store our public host RSA key. */
- packet_put_int(BN_num_bits(sensitive_data.host_key->n));
- packet_put_bignum(sensitive_data.host_key->e);
- packet_put_bignum(sensitive_data.host_key->n);
-
- /* Put protocol flags. */
- packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
-
- /* Declare which ciphers we support. */
- packet_put_int(cipher_mask());
-
- /* Declare supported authentication types. */
- auth_mask = 0;
- if (options.rhosts_authentication)
- auth_mask |= 1 << SSH_AUTH_RHOSTS;
- if (options.rhosts_rsa_authentication)
- auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
- if (options.rsa_authentication)
- auth_mask |= 1 << SSH_AUTH_RSA;
-#ifdef KRB4
- if (options.kerberos_authentication)
- auth_mask |= 1 << SSH_AUTH_KERBEROS;
-#endif
-#ifdef AFS
- if (options.kerberos_tgt_passing)
- auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
- if (options.afs_token_passing)
- auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
-#endif
- if (options.password_authentication)
- auth_mask |= 1 << SSH_AUTH_PASSWORD;
- packet_put_int(auth_mask);
-
- /* Send the packet and wait for it to be sent. */
- packet_send();
- packet_write_wait();
-
- debug("Sent %d bit public key and %d bit host key.",
- BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n));
-
- /* Read clients reply (cipher type and session key). */
- packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
-
- /* Get cipher type. */
- cipher_type = packet_get_char();
-
- /* Get check bytes from the packet. These must match those we sent earlier
- with the public key packet. */
- for (i = 0; i < 8; i++)
- if (check_bytes[i] != packet_get_char())
- packet_disconnect("IP Spoofing check bytes do not match.");
-
- debug("Encryption type: %.200s", cipher_name(cipher_type));
-
- /* Get the encrypted integer. */
- session_key_int = BN_new();
- packet_get_bignum(session_key_int, &slen);
-
- /* Get protocol flags. */
- protocol_flags = packet_get_int();
- packet_set_protocol_flags(protocol_flags);
-
- packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
-
- /* Decrypt it using our private server key and private host key (key with
- larger modulus first). */
- if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0)
- {
- /* Private key has bigger modulus. */
- if (BN_num_bits(sensitive_data.private_key->n) <
- BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
- fatal("do_connection: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
- BN_num_bits(sensitive_data.private_key->n),
- BN_num_bits(sensitive_data.host_key->n),
- SSH_KEY_BITS_RESERVED);
- }
-
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.private_key);
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.host_key);
- }
- else
- {
- /* Host key has bigger modulus (or they are equal). */
- if (BN_num_bits(sensitive_data.host_key->n) <
- BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) {
- fatal("do_connection: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d",
- BN_num_bits(sensitive_data.host_key->n),
- BN_num_bits(sensitive_data.private_key->n),
- SSH_KEY_BITS_RESERVED);
- }
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.host_key);
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.private_key);
- }
-
- /* Compute session id for this session. */
- compute_session_id(session_id, check_bytes,
- BN_num_bits(sensitive_data.host_key->n),
- sensitive_data.host_key->n,
- BN_num_bits(sensitive_data.private_key->n),
- sensitive_data.private_key->n);
-
- /* Extract session key from the decrypted integer. The key is in the
- least significant 256 bits of the integer; the first byte of the
- key is in the highest bits. */
- BN_mask_bits(session_key_int, sizeof(session_key) * 8);
- len = BN_num_bytes(session_key_int);
- if (len < 0 || len > sizeof(session_key))
- fatal("do_connection: bad len: session_key_int %d > sizeof(session_key) %d",
- len, sizeof(session_key));
- memset(session_key, 0, sizeof(session_key));
- BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
-
- /* Xor the first 16 bytes of the session key with the session id. */
- for (i = 0; i < 16; i++)
- session_key[i] ^= session_id[i];
-
- /* Destroy the decrypted integer. It is no longer needed. */
- BN_clear_free(session_key_int);
-
- /* Set the session key. From this on all communications will be
- encrypted. */
- packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH,
- cipher_type, 0);
-
- /* Destroy our copy of the session key. It is no longer needed. */
- memset(session_key, 0, sizeof(session_key));
-
- debug("Received session key; encryption turned on.");
-
- /* Send an acknowledgement packet. Note that this packet is sent
- encrypted. */
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-
- /* Get the name of the user that we wish to log in as. */
- packet_read_expect(&plen, SSH_CMSG_USER);
-
- /* Get the user name. */
- {
- int ulen;
- user = packet_get_string(&ulen);
- packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
- }
-
- /* Destroy the private and public keys. They will no longer be needed. */
- RSA_free(public_key);
- RSA_free(sensitive_data.private_key);
- RSA_free(sensitive_data.host_key);
-
- setproctitle("%s", user);
- /* Do the authentication. */
- do_authentication(user, privileged_port);
-}
-
-/* Check if the user is allowed to log in via ssh. If user is listed in
- DenyUsers or user's primary group is listed in DenyGroups, false will
- be returned. If AllowUsers isn't empty and user isn't listed there, or
- if AllowGroups isn't empty and user isn't listed there, false will be
- returned. Otherwise true is returned.
- XXX This function should also check if user has a valid shell */
-
-static int
-allowed_user(struct passwd *pw)
-{
- struct group *grp;
- int i;
-
- /* Shouldn't be called if pw is NULL, but better safe than sorry... */
- if (!pw)
- return 0;
-
- /* XXX Should check for valid login shell */
-
- /* Return false if user is listed in DenyUsers */
- if (options.num_deny_users > 0)
- {
- if (!pw->pw_name)
- return 0;
- for (i = 0; i < options.num_deny_users; i++)
- if (match_pattern(pw->pw_name, options.deny_users[i]))
- return 0;
- }
-
- /* Return false if AllowUsers isn't empty and user isn't listed there */
- if (options.num_allow_users > 0)
- {
- if (!pw->pw_name)
- return 0;
- for (i = 0; i < options.num_allow_users; i++)
- if (match_pattern(pw->pw_name, options.allow_users[i]))
- break;
- /* i < options.num_allow_users iff we break for loop */
- if (i >= options.num_allow_users)
- return 0;
- }
-
- /* Get the primary group name if we need it. Return false if it fails */
- if (options.num_deny_groups > 0 || options.num_allow_groups > 0 )
- {
- grp = getgrgid(pw->pw_gid);
- if (!grp)
- return 0;
-
- /* Return false if user's group is listed in DenyGroups */
- if (options.num_deny_groups > 0)
- {
- if (!grp->gr_name)
- return 0;
- for (i = 0; i < options.num_deny_groups; i++)
- if (match_pattern(grp->gr_name, options.deny_groups[i]))
- return 0;
- }
-
- /* Return false if AllowGroups isn't empty and user's group isn't
- listed there */
- if (options.num_allow_groups > 0)
- {
- if (!grp->gr_name)
- return 0;
- for (i = 0; i < options.num_allow_groups; i++)
- if (match_pattern(grp->gr_name, options.allow_groups[i]))
- break;
- /* i < options.num_allow_groups iff we break for loop */
- if (i >= options.num_allow_groups)
- return 0;
- }
- }
-
- /* We found no reason not to let this user try to log on... */
- return 1;
-}
-
-/* Performs authentication of an incoming connection. Session key has already
- been exchanged and encryption is enabled. User is the user name to log
- in as (received from the clinet). Privileged_port is true if the
- connection comes from a privileged port (used for .rhosts authentication).*/
-
-#define MAX_AUTH_FAILURES 5
-
-void
-do_authentication(char *user, int privileged_port)
-{
- int type;
- int authenticated = 0;
- int authentication_failures = 0;
- char *password = NULL;
- struct passwd *pw, pwcopy;
- char *client_user = NULL;
- unsigned int client_host_key_bits;
- BIGNUM *client_host_key_e, *client_host_key_n;
-#ifdef HAVE_LIBPAM
- int pam_retval;
-#endif /* HAVE_LIBPAM */
-
-#ifdef AFS
- /* If machine has AFS, set process authentication group. */
- if (k_hasafs()) {
- k_setpag();
- k_unlog();
- }
-#endif /* AFS */
-
- /* Verify that the user is a valid user. */
- pw = getpwnam(user);
- if (!pw || !allowed_user(pw))
- eat_packets_and_disconnect(user);
-
- /* Take a copy of the returned structure. */
- memset(&pwcopy, 0, sizeof(pwcopy));
- pwcopy.pw_name = xstrdup(pw->pw_name);
- pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
- pwcopy.pw_uid = pw->pw_uid;
- pwcopy.pw_gid = pw->pw_gid;
- pwcopy.pw_dir = xstrdup(pw->pw_dir);
- pwcopy.pw_shell = xstrdup(pw->pw_shell);
- pw = &pwcopy;
-
-#ifdef HAVE_LIBPAM
- debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
- pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
- if (pam_retval != PAM_SUCCESS)
- {
- log("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
- eat_packets_and_disconnect(user);
- }
- fatal_add_cleanup(&pam_cleanup_proc, NULL);
-#endif
-
- /* If we are not running as root, the user must have the same uid as the
- server. */
- if (getuid() != 0 && pw->pw_uid != getuid())
- packet_disconnect("Cannot change user when server not running as root.");
-
- debug("Attempting authentication for %.100s.", user);
-
- /* If the user has no password, accept authentication immediately. */
- if (options.password_authentication &&
-#ifdef KRB4
- (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
-#endif /* KRB4 */
- auth_password(pw, ""))
- {
- /* Authentication with empty password succeeded. */
- debug("Login for user %.100s accepted without authentication.", user);
- /* authentication_type = SSH_AUTH_PASSWORD; */
- authenticated = 1;
- /* Success packet will be sent after loop below. */
- }
- else
- {
- /* Indicate that authentication is needed. */
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- }
-
- /* Loop until the user has been authenticated or the connection is closed. */
- while (!authenticated)
- {
- int plen;
- /* Get a packet from the client. */
- type = packet_read(&plen);
-
- /* Process the packet. */
- switch (type)
- {
-
-#ifdef AFS
- case SSH_CMSG_HAVE_KERBEROS_TGT:
- if (!options.kerberos_tgt_passing)
- {
- /* packet_get_all(); */
- log("Kerberos tgt passing disabled.");
- break;
- }
- else {
- /* Accept Kerberos tgt. */
- int dlen;
- char *tgt = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- if (!auth_kerberos_tgt(pw, tgt))
- debug("Kerberos tgt REFUSED for %s", user);
- xfree(tgt);
- }
- continue;
-
- case SSH_CMSG_HAVE_AFS_TOKEN:
- if (!options.afs_token_passing || !k_hasafs()) {
- /* packet_get_all(); */
- log("AFS token passing disabled.");
- break;
- }
- else {
- /* Accept AFS token. */
- int dlen;
- char *token_string = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- if (!auth_afs_token(pw, token_string))
- debug("AFS token REFUSED for %s", user);
- xfree(token_string);
- continue;
- }
-#endif /* AFS */
-
-#ifdef KRB4
- case SSH_CMSG_AUTH_KERBEROS:
- if (!options.kerberos_authentication)
- {
- /* packet_get_all(); */
- log("Kerberos authentication disabled.");
- break;
- }
- else {
- /* Try Kerberos v4 authentication. */
- KTEXT_ST auth;
- char *tkt_user = NULL;
- char *kdata = packet_get_string((unsigned int *)&auth.length);
- packet_integrity_check(plen, 4 + auth.length, type);
-
- if (auth.length < MAX_KTXT_LEN)
- memcpy(auth.dat, kdata, auth.length);
- xfree(kdata);
-
- if (auth_krb4(user, &auth, &tkt_user)) {
- /* Client has successfully authenticated to us. */
- log("Kerberos authentication accepted %s for account "
- "%s from %s", tkt_user, user, get_canonical_hostname());
- /* authentication_type = SSH_AUTH_KERBEROS; */
- authenticated = 1;
- xfree(tkt_user);
- }
- else {
- log("Kerberos authentication failed for account "
- "%s from %s", user, get_canonical_hostname());
- }
- }
- break;
-#endif /* KRB4 */
-
- case SSH_CMSG_AUTH_RHOSTS:
- if (!options.rhosts_authentication)
- {
- log("Rhosts authentication disabled.");
- break;
- }
-
- /* Rhosts authentication (also uses /etc/hosts.equiv). */
- if (!privileged_port)
- {
- log("Rhosts authentication not available for connections from unprivileged port.");
- break;
- }
-
- /* Get client user name. Note that we just have to trust the client;
- this is one reason why rhosts authentication is insecure.
- (Another is IP-spoofing on a local network.) */
- {
- int dlen;
- client_user = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- }
-
- /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
- if (auth_rhosts(pw, client_user))
- {
- /* Authentication accepted. */
- log("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.",
- user, client_user, get_canonical_hostname());
- authenticated = 1;
-#ifndef HAVE_LIBPAM
- xfree(client_user);
-#endif /* HAVE_LIBPAM */
- break;
- }
- log("Rhosts authentication failed for %.100s, remote %.100s.",
- user, client_user);
-#ifndef HAVE_LIBPAM
- xfree(client_user);
-#endif /* HAVE_LIBPAM */
- break;
-
- case SSH_CMSG_AUTH_RHOSTS_RSA:
- if (!options.rhosts_rsa_authentication)
- {
- log("Rhosts with RSA authentication disabled.");
- break;
- }
-
- /* Rhosts authentication (also uses /etc/hosts.equiv) with RSA
- host authentication. */
- if (!privileged_port)
- {
- log("Rhosts authentication not available for connections from unprivileged port.");
- break;
- }
-
- {
- int ulen, elen, nlen;
- /* Get client user name. Note that we just have to trust
- the client; root on the client machine can claim to be
- any user. */
- client_user = packet_get_string(&ulen);
-
- /* Get the client host key. */
- client_host_key_e = BN_new();
- client_host_key_n = BN_new();
- client_host_key_bits = packet_get_int();
- packet_get_bignum(client_host_key_e, &elen);
- packet_get_bignum(client_host_key_n, &nlen);
-
- packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
- }
-
- if (auth_rhosts_rsa(pw, client_user,
- client_host_key_bits, client_host_key_e, client_host_key_n))
- {
- /* Authentication accepted. */
- authenticated = 1;
-#ifndef HAVE_LIBPAM
- xfree(client_user);
-#endif /* HAVE_LIBPAM */
- BN_clear_free(client_host_key_e);
- BN_clear_free(client_host_key_n);
- break;
- }
- log("Rhosts authentication failed for %.100s, remote %.100s.",
- user, client_user);
-#ifndef HAVE_LIBPAM
- xfree(client_user);
-#endif /* HAVE_LIBPAM */
- BN_clear_free(client_host_key_e);
- BN_clear_free(client_host_key_n);
- break;
-
- case SSH_CMSG_AUTH_RSA:
- if (!options.rsa_authentication)
- {
- log("RSA authentication disabled.");
- break;
- }
-
- /* RSA authentication requested. */
- {
- int nlen;
- BIGNUM *n;
- n = BN_new();
- packet_get_bignum(n, &nlen);
-
- packet_integrity_check(plen, nlen, type);
-
- if (auth_rsa(pw, n))
- {
- /* Successful authentication. */
- BN_clear_free(n);
- log("RSA authentication for %.100s accepted.", user);
- authenticated = 1;