diff options
author | des <des@FreeBSD.org> | 2002-06-23 16:09:08 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2002-06-23 16:09:08 +0000 |
commit | fa8aa6dfe7e9aaab9f8fa1e3290e7242fc12d83d (patch) | |
tree | cc93abce4a81ab84afa26d861b756d5c77818afa | |
parent | e9f3540c66a76052e51a348bdd05a068d0855d3d (diff) | |
download | FreeBSD-src-fa8aa6dfe7e9aaab9f8fa1e3290e7242fc12d83d.zip FreeBSD-src-fa8aa6dfe7e9aaab9f8fa1e3290e7242fc12d83d.tar.gz |
Resolve conflicts. Known issues:
- sshd fails to set TERM correctly.
- privilege separation may break PAM and is currently turned off.
- man pages have not yet been updated
I will have these issues resolved, and privilege separation turned on by
default, in time for DP2.
Sponsored by: DARPA, NAI Labs
45 files changed, 2059 insertions, 1424 deletions
diff --git a/crypto/openssh/LICENCE b/crypto/openssh/LICENCE index c347446..0e4f977 100644 --- a/crypto/openssh/LICENCE +++ b/crypto/openssh/LICENCE @@ -190,6 +190,8 @@ OpenSSH contains no GPL code. Aaron Campbell Damien Miller Kevin Steves + Daniel Kouril + Per Allansson * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -253,3 +255,4 @@ OpenSSH contains no GPL code. * SUCH DAMAGE. $FreeBSD$ + diff --git a/crypto/openssh/auth-krb4.c b/crypto/openssh/auth-krb4.c index 745b9c5..97d2908 100644 --- a/crypto/openssh/auth-krb4.c +++ b/crypto/openssh/auth-krb4.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-krb4.c,v 1.25 2001/12/19 07:18:56 deraadt Exp $"); +RCSID("$OpenBSD: auth-krb4.c,v 1.27 2002/06/11 05:46:20 mpech Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" @@ -58,8 +58,8 @@ krb4_init(void *context) if (lstat("/ticket", &st) != -1) tkt_root = "/ticket/"; #endif /* AFS */ - snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%d", - tkt_root, authctxt->pw->pw_uid, getpid()); + snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%ld", + tkt_root, authctxt->pw->pw_uid, (long)getpid()); krb_set_tkt_string(authctxt->krb4_ticket_file); } /* Register ticket cleanup in case of fatal error. */ @@ -254,6 +254,7 @@ auth_krb4(Authctxt *authctxt, KTEXT auth, char **client) log("Kerberos v4 .klogin authorization failed for %s to " "account %s", *client, authctxt->user); xfree(*client); + *client = NULL; return (0); } /* Increment the checksum, and return it encrypted with the diff --git a/crypto/openssh/auth-krb5.c b/crypto/openssh/auth-krb5.c index ff23c98..94344a6 100644 --- a/crypto/openssh/auth-krb5.c +++ b/crypto/openssh/auth-krb5.c @@ -1,9 +1,34 @@ /* * Kerberos v5 authentication and ticket-passing routines. + * + * $FreeBSD$ + */ +/* + * Copyright (c) 2002 Daniel Kouril. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: auth-krb5.c,v 1.6 2002/03/04 17:27:39 stevesk Exp $"); +RCSID("$OpenBSD: auth-krb5.c,v 1.8 2002/03/19 10:49:35 markus Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" diff --git a/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c index ab7447f..ec1b096 100644 --- a/crypto/openssh/auth-passwd.c +++ b/crypto/openssh/auth-passwd.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-passwd.c,v 1.24 2002/03/04 12:43:06 markus Exp $"); +RCSID("$OpenBSD: auth-passwd.c,v 1.27 2002/05/24 16:45:16 stevesk Exp $"); RCSID("$FreeBSD$"); #include "packet.h" @@ -55,7 +55,6 @@ int auth_password(Authctxt *authctxt, const char *password) { struct passwd * pw = authctxt->pw; - char *encrypted_password; /* deny if no user. */ if (pw == NULL) @@ -86,14 +85,20 @@ auth_password(Authctxt *authctxt, const char *password) return 0; else return 1; -#endif +#else /* Check for users with no password. */ if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) return 1; - /* Encrypt the candidate password using the proper salt. */ - encrypted_password = crypt(password, - (pw->pw_passwd[0] && pw->pw_passwd[1]) ? pw->pw_passwd : "xx"); - - /* Authentication is accepted if the encrypted passwords are identical. */ - return (strcmp(encrypted_password, pw->pw_passwd) == 0); + else { + /* Encrypt the candidate password using the proper salt. */ + char *encrypted_password = crypt(password, + (pw->pw_passwd[0] && pw->pw_passwd[1]) ? + pw->pw_passwd : "xx"); + /* + * Authentication is accepted if the encrypted passwords + * are identical. + */ + return (strcmp(encrypted_password, pw->pw_passwd) == 0); + } +#endif } diff --git a/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c index e985219..e74ef3d 100644 --- a/crypto/openssh/auth-rh-rsa.c +++ b/crypto/openssh/auth-rh-rsa.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rh-rsa.c,v 1.29 2002/03/04 12:43:06 markus Exp $"); +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.34 2002/03/25 09:25:06 markus Exp $"); RCSID("$FreeBSD$"); #include "packet.h" @@ -26,37 +26,48 @@ RCSID("$FreeBSD$"); #include "auth.h" #include "canohost.h" -/* - * Tries to authenticate the user using the .rhosts file and the host using - * its host key. Returns true if authentication succeeds. - */ +#include "monitor_wrap.h" + +/* import */ +extern ServerOptions options; int -auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key) +auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, + Key *client_host_key) { - extern ServerOptions options; - const char *canonical_hostname; HostStatus host_status; - debug("Trying rhosts with RSA host authentication for client user %.100s", client_user); - - if (pw == NULL || client_host_key == NULL || client_host_key->rsa == NULL) - return 0; - /* Check if we would accept it using rhosts authentication. */ - if (!auth_rhosts(pw, client_user)) + if (!auth_rhosts(pw, cuser)) return 0; - canonical_hostname = get_canonical_hostname( - options.verify_reverse_mapping); - - debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); - host_status = check_key_in_hostfiles(pw, client_host_key, - canonical_hostname, _PATH_SSH_SYSTEM_HOSTFILE, + chost, _PATH_SSH_SYSTEM_HOSTFILE, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); - if (host_status != HOST_OK) { + return (host_status == HOST_OK); +} + +/* + * Tries to authenticate the user using the .rhosts file and the host using + * its host key. Returns true if authentication succeeds. + */ +int +auth_rhosts_rsa(struct passwd *pw, char *cuser, Key *client_host_key) +{ + char *chost; + + debug("Trying rhosts with RSA host authentication for client user %.100s", + cuser); + + if (pw == NULL || client_host_key == NULL || + client_host_key->rsa == NULL) + return 0; + + chost = (char *)get_canonical_hostname(options.verify_reverse_mapping); + debug("Rhosts RSA authentication: canonical host %.900s", chost); + + if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) { debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); return 0; @@ -64,9 +75,9 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key /* A matching host key was found and is known. */ /* Perform the challenge-response dialog with the client for the host key. */ - if (!auth_rsa_challenge_dialog(client_host_key->rsa)) { + if (!auth_rsa_challenge_dialog(client_host_key)) { log("Client on %.800s failed to respond correctly to host authentication.", - canonical_hostname); + chost); return 0; } /* @@ -75,7 +86,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key */ verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", - pw->pw_name, client_user, canonical_hostname); + pw->pw_name, cuser, chost); packet_send_debug("Rhosts with RSA host authentication accepted."); return 1; } diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c index 77ea57b..17d7ae9 100644 --- a/crypto/openssh/auth-rsa.c +++ b/crypto/openssh/auth-rsa.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rsa.c,v 1.50 2001/12/28 14:50:54 markus Exp $"); +RCSID("$OpenBSD: auth-rsa.c,v 1.56 2002/06/10 16:53:06 stevesk Exp $"); RCSID("$FreeBSD$"); #include <openssl/rsa.h> @@ -33,6 +33,8 @@ RCSID("$FreeBSD$"); #include "servconf.h" #include "auth.h" #include "hostfile.h" +#include "monitor_wrap.h" +#include "ssh.h" /* import */ extern ServerOptions options; @@ -53,6 +55,58 @@ extern u_char session_id[16]; * description of the options. */ +BIGNUM * +auth_rsa_generate_challenge(Key *key) +{ + BIGNUM *challenge; + BN_CTX *ctx; + + if ((challenge = BN_new()) == NULL) + fatal("auth_rsa_generate_challenge: BN_new() failed"); + /* Generate a random challenge. */ + BN_rand(challenge, 256, 0, 0); + if ((ctx = BN_CTX_new()) == NULL) + fatal("auth_rsa_generate_challenge: BN_CTX_new() failed"); + BN_mod(challenge, challenge, key->rsa->n, ctx); + BN_CTX_free(ctx); + + return challenge; +} + +int +auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) +{ + u_char buf[32], mdbuf[16]; + MD5_CTX md; + int len; + + /* don't allow short keys */ + if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", + BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); + return (0); + } + + /* The response is MD5 of decrypted challenge plus session id. */ + len = BN_num_bytes(challenge); + if (len <= 0 || len > 32) + fatal("auth_rsa_verify_response: bad challenge length %d", len); + memset(buf, 0, 32); + BN_bn2bin(challenge, buf + 32 - len); + MD5_Init(&md); + MD5_Update(&md, buf, 32); + MD5_Update(&md, session_id, 16); + MD5_Final(mdbuf, &md); + + /* Verify that the response is the original challenge. */ + if (memcmp(response, mdbuf, 16) != 0) { + /* Wrong answer. */ + return (0); + } + /* Correct answer. */ + return (1); +} + /* * Performs the RSA authentication challenge-response dialog with the client, * and returns true (non-zero) if the client gave the correct answer to @@ -60,29 +114,19 @@ extern u_char session_id[16]; */ int -auth_rsa_challenge_dialog(RSA *pk) +auth_rsa_challenge_dialog(Key *key) { BIGNUM *challenge, *encrypted_challenge; - BN_CTX *ctx; - u_char buf[32], mdbuf[16], response[16]; - MD5_CTX md; - u_int i; - int len; + u_char response[16]; + int i, success; if ((encrypted_challenge = BN_new()) == NULL) fatal("auth_rsa_challenge_dialog: BN_new() failed"); - if ((challenge = BN_new()) == NULL) - fatal("auth_rsa_challenge_dialog: BN_new() failed"); - /* Generate a random challenge. */ - BN_rand(challenge, 256, 0, 0); - if ((ctx = BN_CTX_new()) == NULL) - fatal("auth_rsa_challenge_dialog: BN_CTX_new() failed"); - BN_mod(challenge, challenge, pk->n, ctx); - BN_CTX_free(ctx); + challenge = PRIVSEP(auth_rsa_generate_challenge(key)); /* Encrypt the challenge with the public key. */ - rsa_public_encrypt(encrypted_challenge, challenge, pk); + rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); /* Send the encrypted challenge to the client. */ packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); @@ -97,48 +141,26 @@ auth_rsa_challenge_dialog(RSA *pk) response[i] = packet_get_char(); packet_check_eom(); - /* The response is MD5 of decrypted challenge plus session id. */ - len = BN_num_bytes(challenge); - if (len <= 0 || len > 32) - fatal("auth_rsa_challenge_dialog: bad challenge length %d", len); - memset(buf, 0, 32); - BN_bn2bin(challenge, buf + 32 - len); - MD5_Init(&md); - MD5_Update(&md, buf, 32); - MD5_Update(&md, session_id, 16); - MD5_Final(mdbuf, &md); + success = PRIVSEP(auth_rsa_verify_response(key, challenge, response)); BN_clear_free(challenge); - - /* Verify that the response is the original challenge. */ - if (memcmp(response, mdbuf, 16) != 0) { - /* Wrong answer. */ - return 0; - } - /* Correct answer. */ - return 1; + return (success); } /* - * Performs the RSA authentication dialog with the client. This returns - * 0 if the client could not be authenticated, and 1 if authentication was - * successful. This may exit if there is a serious protocol violation. + * check if there's user key matching client_n, + * return key if login is allowed, NULL otherwise */ int -auth_rsa(struct passwd *pw, BIGNUM *client_n) +auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { char line[8192], *file; - int authenticated; + int allowed = 0; u_int bits; FILE *f; u_long linenum = 0; struct stat st; Key *key; - char *fp; - - /* no user given */ - if (pw == NULL) - return 0; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); @@ -152,29 +174,27 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) /* Restore the privileged uid. */ restore_uid(); xfree(file); - return 0; + return (0); } /* Open the file containing the authorized keys. */ f = fopen(file, "r"); if (!f) { /* Restore the privileged uid. */ restore_uid(); - packet_send_debug("Could not open %.900s for reading.", file); - packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); xfree(file); - return 0; + return (0); } if (options.strict_modes && secure_filename(f, file, pw, line, sizeof(line)) != 0) { xfree(file); fclose(f); log("Authentication refused: %s", line); - packet_send_debug("Authentication refused: %s", line); restore_uid(); - return 0; + return (0); } - /* Flag indicating whether authentication has succeeded. */ - authenticated = 0; + + /* Flag indicating whether the key is allowed. */ + allowed = 0; key = key_new(KEY_RSA1); @@ -239,32 +259,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) if (!auth_parse_options(pw, options, file, linenum)) continue; - /* Perform the challenge-response dialog for this key. */ - if (!auth_rsa_challenge_dialog(key->rsa)) { - /* Wrong response. */ - verbose("Wrong response to RSA authentication challenge."); - packet_send_debug("Wrong response to RSA authentication challenge."); - /* - * Break out of the loop. Otherwise we might send - * another challenge and break the protocol. - */ - break; - } - /* - * Correct response. The client has been successfully - * authenticated. Note that we have not yet processed the - * options; this will be reset if the options cause the - * authentication to be rejected. - * Break out of the loop if authentication was successful; - * otherwise continue searching. - */ - authenticated = 1; - - fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); - verbose("Found matching %s key: %s", - key_type(key), fp); - xfree(fp); - + /* break out, this key is allowed */ + allowed = 1; break; } @@ -275,13 +271,58 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) xfree(file); fclose(f); - key_free(key); - - if (authenticated) - packet_send_debug("RSA authentication accepted."); + /* return key if allowed */ + if (allowed && rkey != NULL) + *rkey = key; else + key_free(key); + return (allowed); +} + +/* + * Performs the RSA authentication dialog with the client. This returns + * 0 if the client could not be authenticated, and 1 if authentication was + * successful. This may exit if there is a serious protocol violation. + */ +int +auth_rsa(struct passwd *pw, BIGNUM *client_n) +{ + Key *key; + char *fp; + + /* no user given */ + if (pw == NULL) + return 0; + + if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { auth_clear_options(); + return (0); + } + + /* Perform the challenge-response dialog for this key. */ + if (!auth_rsa_challenge_dialog(key)) { + /* Wrong response. */ + verbose("Wrong response to RSA authentication challenge."); + packet_send_debug("Wrong response to RSA authentication challenge."); + /* + * Break out of the loop. Otherwise we might send + * another challenge and break the protocol. + */ + key_free(key); + return (0); + } + /* + * Correct response. The client has been successfully + * authenticated. Note that we have not yet processed the + * options; this will be reset if the options cause the + * authentication to be rejected. + */ + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + verbose("Found matching %s key: %s", + key_type(key), fp); + xfree(fp); + key_free(key); - /* Return authentication result. */ - return authenticated; + packet_send_debug("RSA authentication accepted."); + return (1); } diff --git a/crypto/openssh/auth-skey.c b/crypto/openssh/auth-skey.c index b538b39..18243ee 100644 --- a/crypto/openssh/auth-skey.c +++ b/crypto/openssh/auth-skey.c @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: auth-skey.c,v 1.16 2002/01/12 13:10:29 markus Exp $"); +RCSID("$OpenBSD: auth-skey.c,v 1.19 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #ifdef SKEY @@ -31,6 +31,7 @@ RCSID("$FreeBSD$"); #include "xmalloc.h" #include "auth.h" +#include "monitor_wrap.h" static void * skey_init_ctx(Authctxt *authctxt) @@ -38,9 +39,7 @@ skey_init_ctx(Authctxt *authctxt) return authctxt; } -#define PROMPT "\nOPIE Password: " - -static int +int skey_query(void *ctx, char **name, char **infotxt, u_int* numprompts, char ***prompts, u_int **echo_on) { @@ -54,23 +53,23 @@ skey_query(void *ctx, char **name, char **infotxt, if (opiechallenge(&opie, authctxt->user, challenge) == -1) return -1; - *name = xstrdup(""); - *infotxt = xstrdup(""); + *name = xstrdup(""); + *infotxt = xstrdup(""); *numprompts = 1; *prompts = xmalloc(*numprompts * sizeof(char*)); *echo_on = xmalloc(*numprompts * sizeof(u_int)); (*echo_on)[0] = 0; - len = strlen(challenge) + strlen(PROMPT) + 1; + len = strlen(challenge) + strlen(SKEY_PROMPT) + 1; p = xmalloc(len); strlcpy(p, challenge, len); - strlcat(p, PROMPT, len); + strlcat(p, SKEY_PROMPT, len); (*prompts)[0] = p; return 0; } -static int +int skey_respond(void *ctx, u_int numresponses, char **responses) { Authctxt *authctxt = ctx; @@ -96,4 +95,12 @@ KbdintDevice skey_device = { skey_respond, skey_free_ctx }; + +KbdintDevice mm_skey_device = { + "skey", + skey_init_ctx, + mm_skey_query, + mm_skey_respond, + skey_free_ctx +}; #endif /* SKEY */ diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c index 79332a8..fbd1361 100644 --- a/crypto/openssh/auth.c +++ b/crypto/openssh/auth.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth.c,v 1.35 2002/03/01 13:12:10 markus Exp $"); +RCSID("$OpenBSD: auth.c,v 1.43 2002/05/17 14:27:55 millert Exp $"); RCSID("$FreeBSD$"); #include <libgen.h> @@ -40,10 +40,17 @@ RCSID("$FreeBSD$"); #include "bufaux.h" #include "uidswap.h" #include "tildexpand.h" +#include "misc.h" +#include "bufaux.h" +#include "packet.h" /* import */ extern ServerOptions options; +/* Debugging messages */ +Buffer auth_debug; +int auth_debug_init; + /* * Check if the user is allowed to log in via ssh. If user is listed * in DenyUsers or one of user's groups is listed in DenyGroups, false @@ -77,7 +84,8 @@ allowed_user(struct passwd * pw) pw->pw_name, shell); return 0; } - if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) { + if (S_ISREG(st.st_mode) == 0 || + (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { log("User %.100s not allowed because shell %.100s is not executable", pw->pw_name, shell); return 0; @@ -91,17 +99,17 @@ allowed_user(struct passwd * pw) /* Return false if user is listed in DenyUsers */ if (options.num_deny_users > 0) { for (i = 0; i < options.num_deny_users; i++) - if (match_user(pw->pw_name, hostname, ipaddr, + if (match_user(pw->pw_name, hostname, ipaddr, options.deny_users[i])) { - log("User %.100s not allowed because listed in DenyUsers", - pw->pw_name); + log("User %.100s not allowed because listed in DenyUsers", + pw->pw_name); return 0; } } /* Return false if AllowUsers isn't empty and user isn't listed there */ if (options.num_allow_users > 0) { for (i = 0; i < options.num_allow_users; i++) - if (match_user(pw->pw_name, hostname, ipaddr, + if (match_user(pw->pw_name, hostname, ipaddr, options.allow_users[i])) break; /* i < options.num_allow_users iff we break for loop */ @@ -387,3 +395,77 @@ secure_filename(FILE *f, const char *file, struct passwd *pw, } return 0; } + +struct passwd * +getpwnamallow(const char *user) +{ +#ifdef HAVE_LOGIN_CAP + extern login_cap_t *lc; +#ifdef BSD_AUTH + auth_session_t *as; +#endif +#endif + struct passwd *pw; + + pw = getpwnam(user); + if (pw == NULL || !allowed_user(pw)) + return (NULL); +#ifdef HAVE_LOGIN_CAP + if ((lc = login_getclass(pw->pw_class)) == NULL) { + debug("unable to get login class: %s", user); + return (NULL); + } +#ifdef BSD_AUTH + if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || + auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { + debug("Approval failure for %s", user); + pw = NULL; + } + if (as != NULL) + auth_close(as); +#endif +#endif + if (pw != NULL) + return (pwcopy(pw)); + return (NULL); +} + +void +auth_debug_add(const char *fmt,...) +{ + char buf[1024]; + va_list args; + + if (!auth_debug_init) + return; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + buffer_put_cstring(&auth_debug, buf); +} + +void +auth_debug_send(void) +{ + char *msg; + + if (!auth_debug_init) + return; + while (buffer_len(&auth_debug)) { + msg = buffer_get_string(&auth_debug, NULL); + packet_send_debug("%s", msg); + xfree(msg); + } +} + +void +auth_debug_reset(void) +{ + if (auth_debug_init) + buffer_clear(&auth_debug); + else { + buffer_init(&auth_debug); + auth_debug_init = 1; + } +} diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index a6265f3..3fc7954 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.29 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: auth.h,v 1.39 2002/05/31 11:35:15 markus Exp $ */ /* $FreeBSD$ */ /* @@ -44,6 +44,7 @@ #endif typedef struct Authctxt Authctxt; +typedef struct Authmethod Authmethod; typedef struct KbdintDevice KbdintDevice; struct Authctxt { @@ -72,6 +73,12 @@ struct Authctxt { #endif }; +struct Authmethod { + char *name; + int (*userauth)(Authctxt *authctxt); + int *enabled; +}; + /* * Keyboard interactive device: * init_ctx returns: non NULL upon success @@ -89,14 +96,21 @@ struct KbdintDevice void (*free_ctx)(void *ctx); }; -int auth_rhosts(struct passwd *, const char *); +int auth_rhosts(struct passwd *, const char *); int auth_rhosts2(struct passwd *, const char *, const char *, const char *); -int auth_rhosts_rsa(struct passwd *, const char *, Key *); +int auth_rhosts_rsa(struct passwd *, char *, Key *); int auth_password(Authctxt *, const char *); int auth_rsa(struct passwd *, BIGNUM *); -int auth_rsa_challenge_dialog(RSA *); +int auth_rsa_challenge_dialog(Key *); +BIGNUM *auth_rsa_generate_challenge(Key *); +int auth_rsa_verify_response(Key *, BIGNUM *, u_char[]); +int auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); + +int auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); +int user_key_allowed(struct passwd *, Key *); #ifdef KRB4 #include <krb.h> @@ -119,18 +133,27 @@ int auth_krb5_password(Authctxt *authctxt, const char *password); void krb5_cleanup_proc(void *authctxt); #endif /* KRB5 */ -void do_authentication(void); -void do_authentication2(void); +Authctxt *do_authentication(void); +Authctxt *do_authentication2(void); Authctxt *authctxt_new(void); void auth_log(Authctxt *, int, char *, char *); void userauth_finish(Authctxt *, int, char *); int auth_root_allowed(char *); +char *auth2_read_banner(void); + +void privsep_challenge_enable(void); + int auth2_challenge(Authctxt *, char *); void auth2_challenge_stop(Authctxt *); +int bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); +int bsdauth_respond(void *, u_int, char **); +int skey_query(void *, char **, char **, u_int *, char ***, u_int **); +int skey_respond(void *, u_int, char **); int allowed_user(struct passwd *); +struct passwd * getpwnamallow(const char *user); char *get_challenge(Authctxt *); int verify_response(Authctxt *, const char *); @@ -148,8 +171,20 @@ HostStatus check_key_in_hostfiles(struct passwd *, Key *, const char *, const char *, const char *); +/* hostkey handling */ +Key *get_hostkey_by_index(int); +Key *get_hostkey_by_type(int); +int get_hostkey_index(Key *); +int ssh1_session_key(BIGNUM *); + +/* debug messages during authentication */ +void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void auth_debug_send(void); +void auth_debug_reset(void); + #define AUTH_FAIL_MAX 6 #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" +#define SKEY_PROMPT "\nOPIE Password: " #endif diff --git a/crypto/openssh/auth1.c b/crypto/openssh/auth1.c index 9611c6d..8d8b5ce 100644 --- a/crypto/openssh/auth1.c +++ b/crypto/openssh/auth1.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth1.c,v 1.35 2002/02/03 17:53:25 markus Exp $"); +RCSID("$OpenBSD: auth1.c,v 1.41 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include "xmalloc.h" @@ -26,8 +26,8 @@ RCSID("$FreeBSD$"); #include "channels.h" #include "session.h" #include "canohost.h" -#include "misc.h" #include "uidswap.h" +#include "monitor_wrap.h" #include <login_cap.h> #include "auth-pam.h" @@ -104,9 +104,9 @@ do_authloop(Authctxt *authctxt) (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif #ifdef USE_PAM - auth_pam_password(authctxt, "")) { + /* XXX PRIVSEP */ auth_pam_password(authctxt, "")) { #else - auth_password(authctxt, "")) { + PRIVSEP(auth_password(authctxt, ""))) { #endif auth_log(authctxt, 1, "without authentication", ""); return; @@ -228,7 +228,7 @@ do_authloop(Authctxt *authctxt) if (bits != BN_num_bits(client_host_key->rsa->n)) verbose("Warning: keysize mismatch for client_host_key: " "actual %d, announced %d", - BN_num_bits(client_host_key->rsa->n), bits); + BN_num_bits(client_host_key->rsa->n), bits); packet_check_eom(); authenticated = auth_rhosts_rsa(pw, client_user, @@ -267,10 +267,10 @@ do_authloop(Authctxt *authctxt) #ifdef USE_PAM /* Do PAM auth with password */ - authenticated = auth_pam_password(authctxt, password); + authenticated = /* XXX PRIVSEP */ auth_pam_password(authctxt, password); #else /* !USE_PAM */ /* Try authentication with the password. */ - authenticated = auth_password(authctxt, password); + authenticated = PRIVSEP(auth_password(authctxt, password)); #endif /* USE_PAM */ memset(password, 0, strlen(password)); @@ -418,13 +418,12 @@ do_authloop(Authctxt *authctxt) * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ -void +Authctxt * do_authentication(void) { Authctxt *authctxt; - struct passwd *pw; u_int ulen; - char *p, *user, *style = NULL; + char *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ packet_read_expect(SSH_CMSG_USER); @@ -436,36 +435,39 @@ do_authentication(void) if ((style = strchr(user, ':')) != NULL) *style++ = '\0'; +#ifdef KRB5 /* XXX - SSH.com Kerberos v5 braindeath. */ - if ((p = strchr(user, '@')) != NULL) - *p = '\0'; + if ((datafellows & SSH_BUG_K5USER) && + options.kerberos_authentication) { + char *p; + if ((p = strchr(user, '@')) != NULL) + *p = '\0'; + } +#endif authctxt = authctxt_new(); authctxt->user = user; authctxt->style = style; /* Verify that the user is a valid user. */ - pw = getpwnam(user); - if (pw && allowed_user(pw)) { + if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) authctxt->valid = 1; - pw = pwcopy(pw); - } else { + else debug("do_authentication: illegal user %s", user); - pw = NULL; - } - authctxt->pw = pw; #ifdef USE_PAM - if (pw != NULL) - start_pam(pw); + if (authctxt->pw != NULL) + start_pam(authctxt->pw); #endif - setproctitle("%s", pw ? user : "unknown"); + setproctitle("%s%s", authctxt->pw ? user : "unknown", + use_privsep ? " [net]" : ""); /* * If we are not running as root, the user must have the same uid as * the server. */ - if (getuid() != 0 && pw && pw->pw_uid != getuid()) + if (!use_privsep && getuid() != 0 && authctxt->pw && + authctxt->pw->pw_uid != getuid()) packet_disconnect("Cannot change user when server not running as root."); /* @@ -479,6 +481,5 @@ do_authentication(void) packet_send(); packet_write_wait(); - /* Perform session preparation. */ - do_authenticated(authctxt); + return (authctxt); } diff --git a/crypto/openssh/auth2-chall.c b/crypto/openssh/auth2-chall.c index 34fc8f3..1db7a81 100644 --- a/crypto/openssh/auth2-chall.c +++ b/crypto/openssh/auth2-chall.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: auth2-chall.c,v 1.16 2002/01/13 17:57:37 markus Exp $"); +RCSID("$OpenBSD: auth2-chall.c,v 1.18 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include "ssh2.h" @@ -220,7 +220,7 @@ send_userauth_info_request(Authctxt *authctxt) packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); packet_put_cstring(name); packet_put_cstring(instr); - packet_put_cstring(""); /* language not used */ + packet_put_cstring(""); /* language not used */ packet_put_int(numprompts); for (i = 0; i < numprompts; i++) { packet_put_cstring(prompts[i]); @@ -311,3 +311,22 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt) userauth_finish(authctxt, authenticated, method); xfree(method); } + +void +privsep_challenge_enable(void) +{ +#ifdef BSD_AUTH + extern KbdintDevice mm_bsdauth_device; +#endif +#ifdef SKEY + extern KbdintDevice mm_skey_device; +#endif + /* As long as SSHv1 has devices[0] hard coded this is fine */ +#ifdef BSD_AUTH + devices[0] = &mm_bsdauth_device; +#else +#ifdef SKEY + devices[0] = &mm_skey_device; +#endif +#endif +} diff --git a/crypto/openssh/auth2.c b/crypto/openssh/auth2.c index 117415d..72fad08 100644 --- a/crypto/openssh/auth2.c +++ b/crypto/openssh/auth2.c @@ -23,35 +23,20 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.93 2002/05/31 11:35:15 markus Exp $"); RCSID("$FreeBSD$"); -#include <openssl/evp.h> - #include "ssh2.h" #include "xmalloc.h" -#include "rsa.h" -#include "sshpty.h" #include "packet.h" -#include "buffer.h" #include "log.h" #include "servconf.h" #include "compat.h" -#include "channels.h" -#include "bufaux.h" #include "auth.h" -#include "session.h" #include "dispatch.h" -#include "key.h" -#include "cipher.h" -#include "kex.h" #include "pathnames.h" -#include "uidswap.h" -#include "auth-options.h" -#include "misc.h" -#include "hostfile.h" #include "canohost.h" -#include "match.h" +#include "monitor_wrap.h" #ifdef HAVE_LOGIN_CAP #include <login_cap.h> @@ -62,14 +47,23 @@ extern ServerOptions options; extern u_char *session_id2; extern int session_id2_len; -static Authctxt *x_authctxt = NULL; -static int one = 1; +Authctxt *x_authctxt = NULL; + +/* methods */ -typedef struct Authmethod Authmethod; -struct Authmethod { - char *name; - int (*userauth)(Authctxt *authctxt); - int *enabled; +extern Authmethod method_none; +extern Authmethod method_pubkey; +extern Authmethod method_passwd; +extern Authmethod method_kbdint; +extern Authmethod method_hostbased; + +Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + &method_passwd, + &method_kbdint, + &method_hostbased, + NULL }; /* protocol */ @@ -80,41 +74,14 @@ static void input_userauth_request(int, u_int32_t, void *); /* helper */ static Authmethod *authmethod_lookup(const char *); static char *authmethods_get(void); -static int user_key_allowed(struct passwd *, Key *); -static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); - -/* auth */ -static void userauth_banner(void); -static int userauth_none(Authctxt *); -static int userauth_passwd(Authctxt *); -static int userauth_pubkey(Authctxt *); -static int userauth_hostbased(Authctxt *); -static int userauth_kbdint(Authctxt *); - -Authmethod authmethods[] = { - {"none", - userauth_none, - &one}, - {"publickey", - userauth_pubkey, - &options.pubkey_authentication}, - {"password", - userauth_passwd, - &options.password_authentication}, - {"keyboard-interactive", - userauth_kbdint, - &options.kbd_interactive_authentication}, - {"hostbased", - userauth_hostbased, - &options.hostbased_authentication}, - {NULL, NULL, NULL} -}; +int user_key_allowed(struct passwd *, Key *); +int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); /* * loop until authctxt->success == TRUE */ -void +Authctxt * do_authentication2(void) { Authctxt *authctxt = authctxt_new(); @@ -128,7 +95,8 @@ do_authentication2(void) dispatch_init(&dispatch_protocol_error); dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); - do_authenticated(authctxt); + + return (authctxt); } static void @@ -195,23 +163,24 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) if (authctxt->attempt++ == 0) { /* setup auth context */ - struct passwd *pw = NULL; - pw = getpwnam(user); - if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { - authctxt->pw = pwcopy(pw); + authctxt->pw = PRIVSEP(getpwnamallow(user)); + if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); #ifdef USE_PAM - start_pam(pw); + start_pam(authctxt->pw); #endif } else { log("input_userauth_request: illegal user %s", user); authctxt->pw = NULL; } - setproctitle("%s", pw ? user : "unknown"); + setproctitle("%s%s", authctxt->pw ? user : "unknown", + use_privsep ? " [net]" : ""); authctxt->user = xstrdup(user); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; + if (use_privsep) + mm_inform_authserv(service, style); } else if (strcmp(user, authctxt->user) != 0 || strcmp(service, authctxt->service) != 0) { packet_disconnect("Change of username or service not allowed: " @@ -301,289 +270,6 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) } } -static void -userauth_banner(void) -{ - struct stat st; - char *banner = NULL; - off_t len, n; - int fd; - - if (options.banner == NULL || (datafellows & SSH_BUG_BANNER)) - return; - if ((fd = open(options.banner, O_RDONLY)) < 0) - return; - if (fstat(fd, &st) < 0) - goto done; - len = st.st_size; - banner = xmalloc(len + 1); - if ((n = read(fd, banner, len)) < 0) - goto done; - banner[n] = '\0'; - packet_start(SSH2_MSG_USERAUTH_BANNER); - packet_put_cstring(banner); - packet_put_cstring(""); /* language, unused */ - packet_send(); - debug("userauth_banner: sent"); -done: - if (banner) - xfree(banner); - close(fd); - return; -} - -static int -userauth_none(Authctxt *authctxt) -{ - /* disable method "none", only allowed one time */ - Authmethod *m = authmethod_lookup("none"); - if (m != NULL) - m->enabled = NULL; - packet_check_eom(); - userauth_banner(); -#ifdef USE_PAM - return authctxt->valid ? auth_pam_password(authctxt, "") : 0; -#else /* !USE_PAM */ - return authctxt->valid ? auth_password(authctxt, "") : 0; -#endif /* USE_PAM */ -} - -static int -userauth_passwd(Authctxt *authctxt) -{ - char *password; - int authenticated = 0; - int change; - u_int len; - change = packet_get_char(); - if (change) - log("password change not supported"); - password = packet_get_string(&len); - packet_check_eom(); - if (authctxt->valid && -#ifdef USE_PAM - auth_password(authctxt, password) == 1) -#else - auth_password(authctxt, password) == 1) -#endif - authenticated = 1; - memset(password, 0, len); - xfree(password); - return authenticated; -} - -static int -userauth_kbdint(Authctxt *authctxt) -{ - int authenticated = 0; - char *lang, *devs; - - lang = packet_get_string(NULL); - devs = packet_get_string(NULL); - packet_check_eom(); - - debug("keyboard-interactive devs %s", devs); - - if (options.challenge_response_authentication) - authenticated = auth2_challenge(authctxt, devs); - - xfree(devs); - xfree(lang); - return authenticated; -} - -static int -userauth_pubkey(Authctxt *authctxt) -{ - Buffer b; - Key *key = NULL; - char *pkalg; - u_char *pkblob, *sig; - u_int alen, blen, slen; - int have_sig, pktype; - int authenticated = 0; - - if (!authctxt->valid) { - debug2("userauth_pubkey: disabled because of invalid user"); - return 0; - } - have_sig = packet_get_char(); - if (datafellows & SSH_BUG_PKAUTH) { - debug2("userauth_pubkey: SSH_BUG_PKAUTH"); - /* no explicit pkalg given */ - pkblob = packet_get_string(&blen); - buffer_init(&b); - buffer_append(&b, pkblob, blen); - /* so we have to extract the pkalg from the pkblob */ - pkalg = buffer_get_string(&b, &alen); - buffer_free(&b); - } else { - pkalg = packet_get_string(&alen); - pkblob = packet_get_string(&blen); - } - pktype = key_type_from_name(pkalg); - if (pktype == KEY_UNSPEC) { - /* this is perfectly legal */ - log("userauth_pubkey: unsupported public key algorithm: %s", - pkalg); - goto done; - } - key = key_from_blob(pkblob, blen); - if (key == NULL) { - error("userauth_pubkey: cannot decode key: %s", pkalg); - goto done; - } - if (key->type != pktype) { - error("userauth_pubkey: type mismatch for decoded key " - "(received %d, expected %d)", key->type, pktype); - goto done; - } - if (have_sig) { - sig = packet_get_string(&slen); - packet_check_eom(); - buffer_init(&b); - if (datafellows & SSH_OLD_SESSIONID) { - buffer_append(&b, session_id2, session_id2_len); - } else { - buffer_put_string(&b, session_id2, session_id2_len); - } - /* reconstruct packet */ - buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); - buffer_put_cstring(&b, authctxt->user); - buffer_put_cstring(&b, - datafellows & SSH_BUG_PKSERVICE ? - "ssh-userauth" : - authctxt->service); - if (datafellows & SSH_BUG_PKAUTH) { - buffer_put_char(&b, have_sig); - } else { - buffer_put_cstring(&b, "publickey"); - buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, pkalg); - } - buffer_put_string(&b, pkblob, blen); -#ifdef DEBUG_PK - buffer_dump(&b); -#endif - /* test for correct signature */ - if (user_key_allowed(authctxt->pw, key) && - key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) - authenticated = 1; - buffer_clear(&b); - xfree(sig); - } else { - debug("test whether pkalg/pkblob are acceptable"); - packet_check_eom(); - - /* XXX fake reply and always send PK_OK ? */ - /* - * XXX this allows testing whether a user is allowed - * to login: if you happen to have a valid pubkey this - * message is sent. the message is NEVER sent at all - * if a user is not allowed to login. is this an - * issue? -markus - */ - if (user_key_allowed(authctxt->pw, key)) { - packet_start(SSH2_MSG_USERAUTH_PK_OK); - packet_put_string(pkalg, alen); - packet_put_string(pkblob, blen); - packet_send(); - packet_write_wait(); - authctxt->postponed = 1; - } - } - if (authenticated != 1) - auth_clear_options(); -done: - debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); - if (key != NULL) - key_free(key); - xfree(pkalg); - xfree(pkblob); - return authenticated; -} - -static int -userauth_hostbased(Authctxt *authctxt) -{ - Buffer b; - Key *key = NULL; - char *pkalg, *cuser, *chost, *service; - u_char *pkblob, *sig; - u_int alen, blen, slen; - int pktype; - int authenticated = 0; - - if (!authctxt->valid) { - debug2("userauth_hostbased: disabled because of invalid user"); - return 0; - } - pkalg = packet_get_string(&alen); - pkblob = packet_get_string(&blen); - chost = packet_get_string(NULL); - cuser = packet_get_string(NULL); - sig = packet_get_string(&slen); - - debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d", - cuser, chost, pkalg, slen); -#ifdef DEBUG_PK - debug("signature:"); - buffer_init(&b); - buffer_append(&b, sig, slen); - buffer_dump(&b); - buffer_free(&b); -#endif - pktype = key_type_from_name(pkalg); - if (pktype == KEY_UNSPEC) { - /* this is perfectly legal */ - log("userauth_hostbased: unsupported " - "public key algorithm: %s", pkalg); - goto done; - } - key = key_from_blob(pkblob, blen); - if (key == NULL) { - error("userauth_hostbased: cannot decode key: %s", pkalg); - goto done; - } - if (key->type != pktype) { - error("userauth_hostbased: type mismatch for decoded key " - "(received %d, expected %d)", key->type, pktype); - goto done; - } - service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : - authctxt->service; - buffer_init(&b); - buffer_put_string(&b, session_id2, session_id2_len); - /* reconstruct packet */ - buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); - buffer_put_cstring(&b, authctxt->user); - buffer_put_cstring(&b, service); - buffer_put_cstring(&b, "hostbased"); - buffer_put_string(&b, pkalg, alen); - buffer_put_string(&b, pkblob, blen); - buffer_put_cstring(&b, chost); - buffer_put_cstring(&b, cuser); -#ifdef DEBUG_PK - buffer_dump(&b); -#endif - /* test for allowed key and correct signature */ - if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) && - key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) - authenticated = 1; - - buffer_clear(&b); -done: - debug2("userauth_hostbased: authenticated %d", authenticated); - if (key != NULL) - key_free(key); - xfree(pkalg); - xfree(pkblob); - xfree(cuser); - xfree(chost); - xfree(sig); - return authenticated; -} - /* get current user */ struct passwd* @@ -597,18 +283,20 @@ auth_get_user(void) static char * authmethods_get(void) { - Authmethod *method = NULL; Buffer b; char *list; + int i; buffer_init(&b); - for (method = authmethods; method->name != NULL; method++) { - if (strcmp(method->name, "none") == 0) + for (i = 0; authmethods[i] != NULL; i++) { + if (strcmp(authmethods[i]->name, "none") == 0) continue; - if (method->enabled != NULL && *(method->enabled) != 0) { + if (authmethods[i]->enabled != NULL && + *(authmethods[i]->enabled) != 0) { if (buffer_len(&b) > 0) buffer_append(&b, ",", 1); - buffer_append(&b, method->name, strlen(method->name)); + buffer_append(&b, authmethods[i]->name, + strlen(authmethods[i]->name)); } } buffer_append(&b, "\0", 1); @@ -620,174 +308,15 @@ authmethods_get(void) static Authmethod * authmethod_lookup(const char *name) { - Authmethod *method = NULL; + int i; + if (name != NULL) - for (method = authmethods; method->name != NULL; method++) - if (method->enabled != NULL && - *(method->enabled) != 0 && - strcmp(name, method->name) == 0) - return method; - debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); + for (i = 0; authmethods[i] != NULL; i++) + if (authmethods[i]->enabled != NULL && + *(authmethods[i]->enabled) != 0 && + strcmp(name, authmethods[i]->name) == 0) + return authmethods[i]; + debug2("Unrecognized authentication method name: %s", + name ? name : "NULL"); return NULL; } - -/* return 1 if user allows given key */ -static int -user_key_allowed2(struct passwd *pw, Key *key, char *file) -{ - char line[8192]; - int found_key = 0; - FILE *f; - u_long linenum = 0; - struct stat st; - Key *found; - char *fp; - - if (pw == NULL) - return 0; - - /* Temporarily use the user's uid. */ - temporarily_use_uid(pw); - - debug("trying public key file %s", file); - - /* Fail quietly if file does not exist */ - if (stat(file, &st) < 0) { - /* Restore the privileged uid. */ - restore_uid(); - return 0; - } - /* Open the file containing the authorized keys. */ - f = fopen(file, "r"); - if (!f) { - /* Restore the privileged uid. */ - restore_uid(); - return 0; - } - if (options.strict_modes && - secure_filename(f, file, pw, line, sizeof(line)) != 0) { - fclose(f); - log("Authentication refused: %s", line); - restore_uid(); - return 0; - } - - found_key = 0; - found = key_new(key->type); - - while (fgets(line, sizeof(line), f)) { - char *cp, *options = NULL; - linenum++; - /* Skip leading whitespace, empty and comment lines. */ - for (cp = line; *cp == ' ' || *cp == '\t'; cp++) - ; - if (!*cp || *cp == '\n' || *cp == '#') - continue; - - if (key_read(found, &cp) != 1) { - /* no key? check if there are options for this key */ - int quoted = 0; - debug2("user_key_allowed: check options: '%s'", cp); - options = cp; - for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { - if (*cp == '\\' && cp[1] == '"') - cp++; /* Skip both */ - else if (*cp == '"') - quoted = !quoted; - } - /* Skip remaining whitespace. */ - for (; *cp == ' ' || *cp == '\t'; cp++) - ; - if (key_read(found, &cp) != 1) { - debug2("user_key_allowed: advance: '%s'", cp); - /* still no key? advance to next line*/ - continue; - } - } - if (key_equal(found, key) && - auth_parse_options(pw, options, file, linenum) == 1) { - found_key = 1; - debug("matching key found: file %s, line %lu", - file, linenum); - fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); - verbose("Found matching %s key: %s", - key_type(found), fp); - xfree(fp); - break; - } - } - restore_uid(); - fclose(f); - key_free(found); - if (!found_key) - debug2("key not found"); - return found_key; -} - -/* check whether given key is in .ssh/authorized_keys* */ -static int -user_key_allowed(struct passwd *pw, Key *key) -{ - int success; - char *file; - - file = authorized_keys_file(pw); - success = user_key_allowed2(pw, key, file); - xfree(file); - if (success) - return success; - - /* try suffix "2" for backward compat, too */ - file = authorized_keys_file2(pw); - success = user_key_allowed2(pw, key, file); - xfree(file); - return success; -} - -/* return 1 if given hostkey is allowed */ -static int -hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, - Key *key) -{ - const char *resolvedname, *ipaddr, *lookup; - HostStatus host_status; - int len; - - resolvedname = get_canonical_hostname(options.verify_reverse_mapping); - ipaddr = get_remote_ipaddr(); - - debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s", - chost, resolvedname, ipaddr); - - if (options.hostbased_uses_name_from_packet_only) { - if (auth_rhosts2(pw, cuser, chost, chost) == 0) - return 0; - lookup = chost; - } else { - if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') { - debug2("stripping trailing dot from chost %s", chost); - chost[len - 1] = '\0'; - } - if (strcasecmp(resolvedname, chost) != 0) - log("userauth_hostbased mismatch: " - "client sends %s, but we resolve %s to %s", - chost, ipaddr, resolvedname); - if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) - return 0; - lookup = resolvedname; - } - debug2("userauth_hostbased: access allowed by auth_rhosts2"); - - host_status = check_key_in_hostfiles(pw, key, lookup, - _PATH_SSH_SYSTEM_HOSTFILE, - options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); - - /* backward compat if no key has been found. */ - if (host_status == HOST_NEW) - host_status = check_key_in_hostfiles(pw, key, lookup, - _PATH_SSH_SYSTEM_HOSTFILE2, - options.ignore_user_known_hosts ? NULL : - _PATH_SSH_USER_HOSTFILE2); - - return (host_status == HOST_OK); -} diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c index 35a6a3f..69fa660 100644 --- a/crypto/openssh/authfd.c +++ b/crypto/openssh/authfd.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.48 2002/02/24 19:14:59 markus Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.55 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include <openssl/evp.h> @@ -60,7 +60,7 @@ int decode_reply(int type); /* macro to check for "agent failure" message */ #define agent_failed(x) \ ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \ - (x == SSH2_AGENT_FAILURE)) + (x == SSH2_AGENT_FAILURE)) /* Returns the number of the authentication fd, or -1 if there is none. */ @@ -208,6 +208,26 @@ ssh_close_authentication_connection(AuthenticationConnection *auth) xfree(auth); } +/* Lock/unlock agent */ +int +ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password) +{ + int type; + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK); + buffer_put_cstring(&msg, password); + + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return 0; + } + type = buffer_get_char(&msg); + buffer_free(&msg); + return decode_reply(type); +} + /* * Returns the first authentication identity held by the agent. */ @@ -420,8 +440,6 @@ ssh_agent_sign(AuthenticationConnection *auth, static void ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) { - buffer_clear(b); - buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY); buffer_put_int(b, BN_num_bits(key->n)); buffer_put_bignum(b, key->n); buffer_put_bignum(b, key->e); @@ -436,8 +454,6 @@ ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) static void ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) { - buffer_clear(b); - buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY); buffer_put_cstring(b, key_ssh_name(key)); switch (key->type) { case KEY_RSA: @@ -465,19 +481,28 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) */ int -ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) +ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, + const char *comment, u_int life) { Buffer msg; - int type; + int type, constrained = (life != 0); buffer_init(&msg); switch (key->type) { case KEY_RSA1: + type = constrained ? + SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : + SSH_AGENTC_ADD_RSA_IDENTITY; + buffer_put_char(&msg, type); ssh_encode_identity_rsa1(&msg, key->rsa, comment); break; case KEY_RSA: case KEY_DSA: + type = constrained ? + SSH2_AGENTC_ADD_ID_CONSTRAINED : + SSH2_AGENTC_ADD_IDENTITY; + buffer_put_char(&msg, type); ssh_encode_identity_ssh2(&msg, key, comment); break; default: @@ -485,6 +510,12 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) return 0; break; } + if (constrained) { + if (life != 0) { + buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); + buffer_put_int(&msg, life); + } + } if (ssh_request_reply(auth, &msg, &msg) == 0) { buffer_free(&msg); return 0; @@ -494,6 +525,12 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) return decode_reply(type); } +int +ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) +{ + return ssh_add_identity_constrained(auth, key, comment, 0); +} + /* * Removes an identity from the authentication server. This call is not * meant to be used by normal applications. @@ -533,7 +570,7 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key) } int -ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id) +ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id, const char *pin) { Buffer msg; int type; @@ -542,6 +579,7 @@ ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id) buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY : SSH_AGENTC_REMOVE_SMARTCARD_KEY); buffer_put_cstring(&msg, reader_id); + buffer_put_cstring(&msg, pin); if (ssh_request_reply(auth, &msg, &msg) == 0) { buffer_free(&msg); return 0; diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c index 80b2fc5..6b63229 100644 --- a/crypto/openssh/authfile.c +++ b/crypto/openssh/authfile.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfile.c,v 1.48 2002/02/28 15:46:33 markus Exp $"); +RCSID("$OpenBSD: authfile.c,v 1.49 2002/05/23 19:24:30 markus Exp $"); RCSID("$FreeBSD$"); #include <openssl/err.h> @@ -422,7 +422,7 @@ fail: return NULL; } -static Key * +Key * key_load_private_pem(int fd, int type, const char *passphrase, char **commentp) { diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c index b7f99090..17f0855 100644 --- a/crypto/openssh/bufaux.c +++ b/crypto/openssh/bufaux.c @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: bufaux.c,v 1.22 2002/01/18 18:14:17 stevesk Exp $"); +RCSID("$OpenBSD: bufaux.c,v 1.25 2002/04/20 09:14:58 markus Exp $"); RCSID("$FreeBSD$"); #include <openssl/bn.h> @@ -138,10 +138,18 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value) BN_bin2bn(bin, len, value); xfree(bin); } - /* - * Returns an integer from the buffer (4 bytes, msb first). + * Returns integers from the buffer (msb first). */ + +u_short +buffer_get_short(Buffer *buffer) +{ + u_char buf[2]; + buffer_get(buffer, (char *) buf, 2); + return GET_16BIT(buf); +} + u_int buffer_get_int(Buffer *buffer) { @@ -159,9 +167,17 @@ buffer_get_int64(Buffer *buffer) } /* - * Stores an integer in the buffer in 4 bytes, msb first. + * Stores integers in the buffer, msb first. */ void +buffer_put_short(Buffer *buffer, u_short value) +{ + char buf[2]; + PUT_16BIT(buf, value); + buffer_append(buffer, buf, 2); +} + +void buffer_put_int(Buffer *buffer, u_int value) { char buf[4]; @@ -193,7 +209,7 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr) /* Get the length. */ len = buffer_get_int(buffer); if (len > 256 * 1024) - fatal("Received packet with bad string length %d", len); + fatal("buffer_get_string: bad string length %d", len); /* Allocate space for the string. Add one byte for a null character. */ value = xmalloc(len + 1); /* Get the string. */ @@ -218,6 +234,8 @@ buffer_put_string(Buffer *buffer, const void *buf, u_int len) void buffer_put_cstring(Buffer *buffer, const char *s) { + if (s == NULL) + fatal("buffer_put_cstring: s == NULL"); buffer_put_string(buffer, s, strlen(s)); } diff --git a/crypto/openssh/canohost.c b/crypto/openssh/canohost.c index 2892aaa..b0a0eb6 100644 --- a/crypto/openssh/canohost.c +++ b/crypto/openssh/canohost.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: canohost.c,v 1.31 2002/02/27 21:23:13 stevesk Exp $"); +RCSID("$OpenBSD: canohost.c,v 1.32 2002/06/11 08:11:45 itojun Exp $"); RCSID("$FreeBSD$"); #include "packet.h" @@ -43,13 +43,14 @@ get_remote_hostname(int socket, int verify_reverse_mapping) debug("getpeername failed: %.100s", strerror(errno)); fatal_cleanup(); } - if (from.ss_family == AF_INET) - check_ip_options(socket, ntop); if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); + if (from.ss_family == AF_INET) + check_ip_options(socket, ntop); + debug3("Trying to reverse map address %.100s.", ntop); /* Map the IP address to a host name. */ if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index 9fea660..00cf29d 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.171 2002/03/04 19:37:58 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.175 2002/06/10 22:28:41 markus Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" @@ -47,7 +47,6 @@ RCSID("$FreeBSD$"); #include "ssh2.h" #include "packet.h" #include "xmalloc.h" -#include "uidswap.h" #include "log.h" #include "misc.h" #include "channels.h" @@ -130,10 +129,6 @@ static u_int x11_fake_data_len; #define NUM_SOCKS 10 -/* Name and directory of socket for authentication agent forwarding. */ -static char *auth_sock_name = NULL; -static char *auth_sock_dir = NULL; - /* AF_UNSPEC or AF_INET or AF_INET6 */ int IPv4or6 = AF_UNSPEC; @@ -707,7 +702,11 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) if (buffer_len(&c->output) > 0) { FD_SET(c->wfd, writeset); } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { - chan_obuf_empty(c); + if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) + debug2("channel %d: obuf_empty delayed efd %d/(%d)", + c->self, c->efd, buffer_len(&c->extended)); + else + chan_obuf_empty(c); } } /** XXX check close conditions, too */ @@ -715,7 +714,8 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) if (c->extended_usage == CHAN_EXTENDED_WRITE && buffer_len(&c->extended) > 0) FD_SET(c->efd, writeset); - else if (c->extended_usage == CHAN_EXTENDED_READ && + else if (!(c->flags & CHAN_EOF_SENT) && + c->extended_usage == CHAN_EXTENDED_READ && buffer_len(&c->extended) < c->remote_window) FD_SET(c->efd, readset); } @@ -1633,12 +1633,18 @@ channel_output_poll(void) fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); /* * input-buffer is empty and read-socket shutdown: - * tell peer, that we will not send more data: send IEOF + * tell peer, that we will not send more data: send IEOF. + * hack for extended data: delay EOF if EFD still in use. */ - chan_ibuf_empty(c); + if (CHANNEL_EFD_INPUT_ACTIVE(c)) + debug2("channel %d: ibuf_empty delayed efd %d/(%d)", + c->self, c->efd, buffer_len(&c->extended)); + else + chan_ibuf_empty(c); } /* Send extended data, i.e. stderr */ if (compat20 && + !(c->flags & CHAN_EOF_SENT) && c->remote_window > 0 && (len = buffer_len(&c->extended)) > 0 && c->extended_usage == CHAN_EXTENDED_READ) { @@ -1727,6 +1733,13 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt) log("channel %d: ext data for non open", id); return; } + if (c->flags & CHAN_EOF_RCVD) { + if (datafellows & SSH_BUG_EXTEOF) + debug("channel %d: accepting ext data after eof", id); + else + packet_disconnect("Received extended_data after EOF " + "on channel %d.", id); + } tcode = packet_get_int(); if (c->efd == -1 || c->extended_usage != CHAN_EXTENDED_WRITE || @@ -2109,7 +2122,7 @@ channel_request_remote_forwarding(u_short listen_port, const char *address_to_bind = "0.0.0.0"; packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("tcpip-forward"); - packet_put_char(0); /* boolean: want reply */ + packet_put_char(1); /* boolean: want reply */ packet_put_cstring(address_to_bind); packet_put_int(listen_port); packet_send(); @@ -2655,105 +2668,6 @@ auth_request_forwarding(void) packet_write_wait(); } -/* - * Returns the name of the forwarded authentication socket. Returns NULL if - * there is no forwarded authentication socket. The returned value points to - * a static buffer. - */ - -char * -auth_get_socket_name(void) -{ - return auth_sock_name; -} - -/* removes the agent forwarding socket */ - -void -auth_sock_cleanup_proc(void *_pw) -{ - struct passwd *pw = _pw; - - if (auth_sock_name) { - temporarily_use_uid(pw); - unlink(auth_sock_name); - rmdir(auth_sock_dir); - auth_sock_name = NULL; - restore_uid(); - } -} - -/* - * This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. - * This starts forwarding authentication requests. - */ - -int -auth_input_request_forwarding(struct passwd * pw) -{ - Channel *nc; - int sock; - struct sockaddr_un sunaddr; - - if (auth_get_socket_name() != NULL) { - error("authentication forwarding requested twice."); - return 0; - } - - /* Temporarily drop privileged uid for mkdir/bind. */ - temporarily_use_uid(pw); - - /* Allocate a buffer for the socket name, and format the name. */ - auth_sock_name = xmalloc(MAXPATHLEN); - auth_sock_dir = xmalloc(MAXPATHLEN); - strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); - - /* Create private directory for socket */ - if (mkdtemp(auth_sock_dir) == NULL) { - packet_send_debug("Agent forwarding disabled: " - "mkdtemp() failed: %.100s", strerror(errno)); - restore_uid(); - xfree(auth_sock_name); - xfree(auth_sock_dir); - auth_sock_name = NULL; - auth_sock_dir = NULL; - return 0; - } - snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%d", - auth_sock_dir, (int) getpid()); - - /* delete agent socket on fatal() */ - fatal_add_cleanup(auth_sock_cleanup_proc, pw); - - /* Create the socket. */ - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - packet_disconnect("socket: %.100s", strerror(errno)); - - /* Bind it to the name. */ - memset(&sunaddr, 0, sizeof(sunaddr)); - sunaddr.sun_family = AF_UNIX; - strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); - - if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) - packet_disconnect("bind: %.100s", strerror(errno)); - - /* Restore the privileged uid. */ - restore_uid(); - - /* Start listening on the socket. */ - if (listen(sock, 5) < 0) - packet_disconnect("listen: %.100s", strerror(errno)); - - /* Allocate a channel for the authentication agent socket. */ - nc = channel_new("auth socket", - SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, - CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, - 0, xstrdup("auth socket"), 1); - strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); - return 1; -} - /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ void diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index 9425739..12876d3 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.65 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: channels.h,v 1.68 2002/06/10 22:28:41 markus Exp $ */ /* $FreeBSD$ */ /* @@ -136,6 +136,18 @@ struct Channel { #define CHAN_CLOSE_SENT 0x01 #define CHAN_CLOSE_RCVD 0x02 +#define CHAN_EOF_SENT 0x04 +#define CHAN_EOF_RCVD 0x08 + +/* check whether 'efd' is still in use */ +#define CHANNEL_EFD_INPUT_ACTIVE(c) \ + (compat20 && c->extended_usage == CHAN_EXTENDED_READ && \ + (c->efd != -1 || \ + buffer_len(&c->extended) > 0)) +#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \ + (compat20 && c->extended_usage == CHAN_EXTENDED_WRITE && \ + ((c->efd != -1 && !(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD))) || \ + buffer_len(&c->extended) > 0)) /* channel management */ @@ -202,8 +214,6 @@ void deny_input_open(int, u_int32_t, void *); /* agent forwarding */ void auth_request_forwarding(void); -char *auth_get_socket_name(void); -int auth_input_request_forwarding(struct passwd *); void auth_input_open_request(int, u_int32_t, void *); /* channel close */ diff --git a/crypto/openssh/cipher.c b/crypto/openssh/cipher.c index 806c5c1..0892423 100644 --- a/crypto/openssh/cipher.c +++ b/crypto/openssh/cipher.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: cipher.c,v 1.52 2002/02/18 13:05:32 markus Exp $"); +RCSID("$OpenBSD: cipher.c,v 1.59 2002/06/19 18:01:00 markus Exp $"); RCSID("$FreeBSD$"); #include "xmalloc.h" @@ -43,18 +43,20 @@ RCSID("$FreeBSD$"); #include "cipher.h" #include <openssl/md5.h> -#include "rijndael.h" -static EVP_CIPHER *evp_ssh1_3des(void); -static EVP_CIPHER *evp_ssh1_bf(void); -static EVP_CIPHER *evp_rijndael(void); +#if OPENSSL_VERSION_NUMBER < 0x00907000L +#include "rijndael.h" +static const EVP_CIPHER *evp_rijndael(void); +#endif +static const EVP_CIPHER *evp_ssh1_3des(void); +static const EVP_CIPHER *evp_ssh1_bf(void); struct Cipher { char *name; int number; /* for ssh1 only */ u_int block_size; u_int key_len; - EVP_CIPHER *(*evptype)(void); + const EVP_CIPHER *(*evptype)(void); } ciphers[] = { { "none", SSH_CIPHER_NONE, 8, 0, EVP_enc_null }, { "des", SSH_CIPHER_DES, 8, 8, EVP_des_cbc }, @@ -65,25 +67,40 @@ struct Cipher { { "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc }, { "cast128-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_cast5_cbc }, { "arcfour", SSH_CIPHER_SSH2, 8, 16, EVP_rc4 }, +#if OPENSSL_VERSION_NUMBER < 0x00907000L { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, evp_rijndael }, { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, evp_rijndael }, { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, evp_rijndael }, + { "rijndael-cbc@lysator.liu.se", + SSH_CIPHER_SSH2, 16, 32, evp_rijndael }, +#else + { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, EVP_aes_128_cbc }, + { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, EVP_aes_192_cbc }, + { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, EVP_aes_256_cbc }, + { "rijndael-cbc@lysator.liu.se", + SSH_CIPHER_SSH2, 16, 32, EVP_aes_256_cbc }, +#endif { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL } }; /*--*/ -u_int +u_int cipher_blocksize(Cipher *c) { return (c->block_size); } -u_int +u_int cipher_keylen(Cipher *c) { return (c->key_len); } +u_int +cipher_get_number(Cipher *c) +{ + return (c->number); +} u_int cipher_mask_ssh1(int client) @@ -334,7 +351,7 @@ ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx) } return (1); } -static EVP_CIPHER * +static const EVP_CIPHER * evp_ssh1_3des(void) { static EVP_CIPHER ssh1_3des; @@ -384,7 +401,7 @@ bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in, u_int len) swap_bytes(out, out, len); return (ret); } -static EVP_CIPHER * +static const EVP_CIPHER * evp_ssh1_bf(void) { static EVP_CIPHER ssh1_bf; @@ -397,6 +414,7 @@ evp_ssh1_bf(void) return (&ssh1_bf); } +#if OPENSSL_VERSION_NUMBER < 0x00907000L /* RIJNDAEL */ #define RIJNDAEL_BLOCKSIZE 16 struct ssh_rijndael_ctx @@ -482,7 +500,7 @@ ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx) } return (1); } -static EVP_CIPHER * +static const EVP_CIPHER * evp_rijndael(void) { static EVP_CIPHER rijndal_cbc; @@ -499,3 +517,155 @@ evp_rijndael(void) EVP_CIPH_ALWAYS_CALL_INIT; return (&rijndal_cbc); } +#endif + +/* + * Exports an IV from the CipherContext required to export the key + * state back from the unprivileged child to the privileged parent + * process. + */ + +int +cipher_get_keyiv_len(CipherContext *cc) +{ + Cipher *c = cc->cipher; + int ivlen; + + if (c->number == SSH_CIPHER_3DES) + ivlen = 24; + else + ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); + return (ivlen); +} + +void +cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) +{ + Cipher *c = cc->cipher; + u_char *civ = NULL; + int evplen; + + switch (c->number) { + case SSH_CIPHER_SSH2: + case SSH_CIPHER_DES: + case SSH_CIPHER_BLOWFISH: + evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); + if (evplen == 0) + return; + if (evplen != len) + fatal("%s: wrong iv length %d != %d", __func__, + evplen, len); + +#if OPENSSL_VERSION_NUMBER < 0x00907000L + if (c->evptype == evp_rijndael) { + struct ssh_rijndael_ctx *aesc; + + aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp); + if (aesc == NULL) + fatal("%s: no rijndael context", __func__); + civ = aesc->r_iv; + } else +#endif + { + civ = cc->evp.iv; + } + break; + case SSH_CIPHER_3DES: { + struct ssh1_3des_ctx *desc; + if (len != 24) + fatal("%s: bad 3des iv length: %d", __func__, len); + desc = EVP_CIPHER_CTX_get_app_data(&cc->evp); + if (desc == NULL) + fatal("%s: no 3des context", __func__); + debug3("%s: Copying 3DES IV", __func__); + memcpy(iv, desc->k1.iv, 8); + memcpy(iv + 8, desc->k2.iv, 8); + memcpy(iv + 16, desc->k3.iv, 8); + return; + } + default: + fatal("%s: bad cipher %d", __func__, c->number); + } + memcpy(iv, civ, len); +} + +void +cipher_set_keyiv(CipherContext *cc, u_char *iv) +{ + Cipher *c = cc->cipher; + u_char *div = NULL; + int evplen = 0; + + switch (c->number) { + case SSH_CIPHER_SSH2: + case SSH_CIPHER_DES: + case SSH_CIPHER_BLOWFISH: + evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); + if (evplen == 0) + return; + +#if OPENSSL_VERSION_NUMBER < 0x00907000L + if (c->evptype == evp_rijndael) { + struct ssh_rijndael_ctx *aesc; + + aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp); + if (aesc == NULL) + fatal("%s: no rijndael context", __func__); + div = aesc->r_iv; + } else +#endif + { + div = cc->evp.iv; + } + break; + case SSH_CIPHER_3DES: { + struct ssh1_3des_ctx *desc; + desc = EVP_CIPHER_CTX_get_app_data(&cc->evp); + if (desc == NULL) + fatal("%s: no 3des context", __func__); + debug3("%s: Installed 3DES IV", __func__); + memcpy(desc->k1.iv, iv, 8); + memcpy(desc->k2.iv, iv + 8, 8); + memcpy(desc->k3.iv, iv + 16, 8); + return; + } + default: + fatal("%s: bad cipher %d", __func__, c->number); + } + memcpy(div, iv, evplen); +} + +#if OPENSSL_VERSION_NUMBER < 0x00907000L +#define EVP_X_STATE(evp) &(evp).c +#define EVP_X_STATE_LEN(evp) sizeof((evp).c) +#else +#define EVP_X_STATE(evp) (evp).cipher_data +#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size +#endif + +int +cipher_get_keycontext(CipherContext *cc, u_char *dat) +{ + Cipher *c = cc->cipher; + int plen = 0; + + if (c->evptype == EVP_rc4) { + plen = EVP_X_STATE_LEN(cc->evp); + if (dat == NULL) + return (plen); + memcpy(dat, EVP_X_STATE(cc->evp), plen); + } + return (plen); +} + +void +cipher_set_keycontext(CipherContext *cc, u_char *dat) +{ + Cipher *c = cc->cipher; + int plen; + + if (c->evptype == EVP_rc4) { + plen = EVP_X_STATE_LEN(cc->evp); + memcpy(EVP_X_STATE(cc->evp), dat, plen); + } +} diff --git a/crypto/openssh/cipher.h b/crypto/openssh/cipher.h index 8aa5982..3847bda 100644 --- a/crypto/openssh/cipher.h +++ b/crypto/openssh/cipher.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cipher.h,v 1.32 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: cipher.h,v 1.33 2002/03/18 17:13:15 markus Exp $ */ /* $FreeBSD$ */ /* @@ -82,4 +82,11 @@ void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); u_int cipher_blocksize(Cipher *); u_int cipher_keylen(Cipher *); + +u_int cipher_get_number(Cipher *); +void cipher_get_keyiv(CipherContext *, u_char *, u_int); +void cipher_set_keyiv(CipherContext *, u_char *); +int cipher_get_keyiv_len(CipherContext *); +int cipher_get_keycontext(CipherContext *, u_char *); +void cipher_set_keycontext(CipherContext *, u_char *); #endif /* CIPHER_H */ diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c index 57694327..3344dd6 100644 --- a/crypto/openssh/compat.c +++ b/crypto/openssh/compat.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: compat.c,v 1.61 2002/03/06 00:24:39 markus Exp $"); +RCSID("$OpenBSD: compat.c,v 1.63 2002/04/10 08:21:47 markus Exp $"); RCSID("$FreeBSD$"); #include "buffer.h" @@ -62,20 +62,26 @@ compat_datafellows(const char *version) "OpenSSH-2.1*," "OpenSSH_2.1*," "OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER| - SSH_OLD_DHGEX|SSH_BUG_NOREKEY }, + SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, { "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES| - SSH_OLD_DHGEX|SSH_BUG_NOREKEY}, + SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, { "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| - SSH_BUG_NOREKEY}, + SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH_2.5.0p1*," "OpenSSH_2.5.1p1*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| - SSH_BUG_NOREKEY }, + SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH_2.5.0*," "OpenSSH_2.5.1*," - "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY }, - { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY }, - { "Sun_SSH_1.0*", SSH_BUG_NOREKEY }, + "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, + { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH_2.*," + "OpenSSH_3.0*," + "OpenSSH_3.1*", SSH_BUG_EXTEOF}, + { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH*", 0 }, { "*MindTerm*", 0 }, { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| @@ -122,8 +128,12 @@ compat_datafellows(const char *version) "1.2.19*," "1.2.20*," "1.2.21*," - "1.2.22*", SSH_BUG_IGNOREMSG }, - { "1.3.2*", SSH_BUG_IGNOREMSG }, /* f-secure */ + "1.2.22*", SSH_BUG_IGNOREMSG|SSH_BUG_K5USER }, + { "1.3.2*", /* F-Secure */ + SSH_BUG_IGNOREMSG|SSH_BUG_K5USER }, + { "1.2.1*," + "1.2.2*," + "1.2.3*", SSH_BUG_K5USER }, { "*SSH Compatible Server*", /* Netscreen */ SSH_BUG_PASSWORDPAD }, { "*OSU_0*," diff --git a/crypto/openssh/compat.h b/crypto/openssh/compat.h index 82acc5b..a0d2534 100644 --- a/crypto/openssh/compat.h +++ b/crypto/openssh/compat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: compat.h,v 1.30 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: compat.h,v 1.32 2002/04/10 08:21:47 markus Exp $ */ /* $FreeBSD$ */ /* @@ -53,6 +53,8 @@ #define SSH_BUG_OPENFAILURE 0x00020000 #define SSH_BUG_DERIVEKEY 0x00040000 #define SSH_BUG_DUMMYCHAN 0x00100000 +#define SSH_BUG_EXTEOF 0x00200000 +#define SSH_BUG_K5USER 0x00400000 void enable_compat13(void); void enable_compat20(void); diff --git a/crypto/openssh/key.c b/crypto/openssh/key.c index 05780ab..610ce4a 100644 --- a/crypto/openssh/key.c +++ b/crypto/openssh/key.c @@ -32,7 +32,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: key.c,v 1.41 2002/02/28 15:46:33 markus Exp $"); +RCSID("$OpenBSD: key.c,v 1.44 2002/05/31 13:16:48 markus Exp $"); RCSID("$FreeBSD$"); #include <openssl/evp.h> @@ -780,6 +780,10 @@ key_sign( } } +/* + * key_verify returns 1 for a correct signature, 0 for an incorrect signature + * and -1 on error. + */ int key_verify( Key *key, @@ -802,3 +806,46 @@ key_verify( break; } } + +/* Converts a private to a public key */ + +Key * +key_demote(Key *k) +{ + Key *pk; + + pk = xmalloc(sizeof(*pk)); + pk->type = k->type; + pk->flags = k->flags; + pk->dsa = NULL; + pk->rsa = NULL; + + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((pk->rsa = RSA_new()) == NULL) + fatal("key_demote: RSA_new failed"); + if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + case KEY_DSA: + if ((pk->dsa = DSA_new()) == NULL) + fatal("key_demote: DSA_new failed"); + if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + + return (pk); +} diff --git a/crypto/openssh/monitor.c b/crypto/openssh/monitor.c index 4957be9..c37da19 100644 --- a/crypto/openssh/monitor.c +++ b/crypto/openssh/monitor.c @@ -26,11 +26,12 @@ #include "includes.h" RCSID("$OpenBSD: monitor.c,v 1.16 2002/06/21 05:50:51 djm Exp $"); +RCSID("$FreeBSD$"); #include <openssl/dh.h> #ifdef SKEY -#include <skey.h> +#include <opie.h> #endif #include "ssh.h" @@ -656,11 +657,11 @@ mm_answer_bsdauthrespond(int socket, Buffer *m) int mm_answer_skeyquery(int socket, Buffer *m) { - struct skey skey; + struct opie opie; char challenge[1024]; int res; - res = skeychallenge(&skey, authctxt->user, challenge); + res = opiechallenge(&opie, authctxt->user, challenge); buffer_clear(m); buffer_put_int(m, res); @@ -683,8 +684,8 @@ mm_answer_skeyrespond(int socket, Buffer *m) authok = (options.challenge_response_authentication && authctxt->valid && - skey_haskey(authctxt->pw->pw_name) == 0 && - skey_passcheck(authctxt->pw->pw_name, response) != -1); + opie_haskey(authctxt->pw->pw_name) == 0 && + opie_passverify(authctxt->pw->pw_name, response) != -1); xfree(response); diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index ca2c259..372ac7e 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.13 2002/01/21 22:30:12 markus Exp $ */ +/* $OpenBSD: myproposal.h,v 1.14 2002/04/03 09:26:11 markus Exp $ */ /* $FreeBSD$ */ /* @@ -28,7 +28,7 @@ #define KEX_DEFAULT_PK_ALG "ssh-dss,ssh-rsa" #define KEX_DEFAULT_ENCRYPT \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ - "aes192-cbc,aes256-cbc" + "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" #define KEX_DEFAULT_MAC \ "hmac-md5,hmac-sha1,hmac-ripemd160," \ "hmac-ripemd160@openssh.com," \ diff --git a/crypto/openssh/packet.h b/crypto/openssh/packet.h index deaf81c..a97d082 100644 --- a/crypto/openssh/packet.h +++ b/crypto/openssh/packet.h @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.h,v 1.33 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: packet.h,v 1.35 2002/06/19 18:01:00 markus Exp $ */ /* $FreeBSD$ */ /* @@ -25,6 +25,7 @@ int packet_get_connection_in(void); int packet_get_connection_out(void); void packet_close(void); void packet_set_encryption_key(const u_char *, u_int, int); +u_int packet_get_encryption_key(u_char *); void packet_set_protocol_flags(u_int); u_int packet_get_protocol_flags(void); void packet_start_compression(int); @@ -57,6 +58,16 @@ void *packet_get_string(u_int *length_ptr); void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2))); void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void set_newkeys(int mode); +int packet_get_keyiv_len(int); +void packet_get_keyiv(int, u_char *, u_int); +int packet_get_keycontext(int, u_char *); +void packet_set_keycontext(int, u_char *); +u_int32_t packet_get_seqnr(int); +void packet_set_seqnr(int, u_int32_t); +int packet_get_ssh1_cipher(void); +void packet_set_iv(int, u_char *); + void packet_write_poll(void); void packet_write_wait(void); int packet_have_data_to_write(void); diff --git a/crypto/openssh/pathnames.h b/crypto/openssh/pathnames.h index 6f4dfc1..2c3989c 100644 --- a/crypto/openssh/pathnames.h +++ b/crypto/openssh/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.11 2002/02/09 17:37:34 deraadt Exp $ */ +/* $OpenBSD: pathnames.h,v 1.13 2002/05/23 19:24:30 markus Exp $ */ /* $FreeBSD$ */ /* @@ -111,6 +111,9 @@ */ #define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass" +/* Location of ssh-keysign for hostbased authentication */ +#define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign" + /* xauth for X11 forwarding */ #define _PATH_XAUTH "/usr/X11R6/bin/xauth" @@ -120,3 +123,6 @@ /* for sftp */ #define _PATH_SFTP_SERVER "/usr/libexec/sftp-server" #define _PATH_LS "ls" + +/* chroot directory for unprivileged user when UsePrivilegeSeparation=yes */ +#define _PATH_PRIVSEP_CHROOT_DIR "/var/empty" diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index e1eb469..ca5b27f 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.95 2002/02/04 12:15:25 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" @@ -42,7 +42,7 @@ RCSID("$FreeBSD$"); # that they are given in. Host *.ngs.fi ngs.fi - FallBackToRsh no + User foo Host fake.com HostName another.host.name.real.org @@ -66,7 +66,7 @@ RCSID("$FreeBSD$"); ProxyCommand ssh-proxy %h %p Host *.fr - UseRsh yes + PublicKeyAuthentication no Host *.su Cipher none @@ -80,8 +80,6 @@ RCSID("$FreeBSD$"); PasswordAuthentication yes RSAAuthentication yes RhostsRSAAuthentication yes - FallBackToRsh no - UseRsh no StrictHostKeyChecking yes KeepAlives no IdentityFile ~/.ssh/identity @@ -95,7 +93,7 @@ RCSID("$FreeBSD$"); typedef enum { oBadOption, oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication, - oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, + oPasswordAuthentication, oRSAAuthentication, oChallengeResponseAuthentication, oXAuthLocation, #if defined(KRB4) || defined(KRB5) oKerberosAuthentication, @@ -117,7 +115,8 @@ typedef enum { oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, oClearAllForwardings, oNoHostAuthenticationForLocalhost, - oVersionAddendum + oVersionAddendum, + oDeprecated } OpCodes; /* Textual representations of the tokens. */ @@ -152,8 +151,8 @@ static struct { #ifdef AFS { "afstokenpassing", oAFSTokenPassing }, #endif - { "fallbacktorsh", oFallBackToRsh }, - { "usersh", oUseRsh }, + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, { "identityfile", oIdentityFile }, { "identityfile2", oIdentityFile }, /* alias */ { "hostname", oHostName }, @@ -374,14 +373,6 @@ parse_flag: intptr = &options->afs_token_passing; goto parse_flag; #endif - case oFallBackToRsh: - intptr = &options->fallback_to_rsh; - goto parse_flag; - - case oUseRsh: - intptr = &options->use_rsh; - goto parse_flag; - case oBatchMode: intptr = &options->batch_mode; goto parse_flag; @@ -686,6 +677,11 @@ parse_int: } while (arg != NULL && *arg != '\0'); break; + case oDeprecated: + debug("%s line %d: Deprecated option \"%s\"", + filename, linenum, keyword); + return 0; + default: fatal("process_config_line: Unimplemented opcode %d", opcode); } @@ -773,8 +769,6 @@ initialize_options(Options * options) options->kbd_interactive_devices = NULL; options->rhosts_rsa_authentication = -1; options->hostbased_authentication = -1; - options->fallback_to_rsh = -1; - options->use_rsh = -1; options->batch_mode = -1; options->check_host_ip = -1; options->strict_host_key_checking = -1; @@ -830,7 +824,7 @@ fill_default_options(Options * options) if (options->use_privileged_port == -1) options->use_privileged_port = 0; if (options->rhosts_authentication == -1) - options->rhosts_authentication = 1; + options->rhosts_authentication = 0; if (options->rsa_authentication == -1) options->rsa_authentication = 1; if (options->pubkey_authentication == -1) @@ -854,13 +848,9 @@ fill_default_options(Options * options) if (options->kbd_interactive_authentication == -1) options->kbd_interactive_authentication = 1; if (options->rhosts_rsa_authentication == -1) - options->rhosts_rsa_authentication = 1; + options->rhosts_rsa_authentication = 0; if (options->hostbased_authentication == -1) options->hostbased_authentication = 0; - if (options->fallback_to_rsh == -1) - options->fallback_to_rsh = 0; - if (options->use_rsh == -1) - options->use_rsh = 0; if (options->batch_mode == -1) options->batch_mode = 0; if (options->check_host_ip == -1) diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index c310137..9d32622 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.42 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: readconf.h,v 1.43 2002/06/08 05:17:01 markus Exp $ */ /* $FreeBSD$ */ /* @@ -55,8 +55,6 @@ typedef struct { * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */ - int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */ - int use_rsh; /* Always use rsh (don\'t try ssh). */ int batch_mode; /* Batch mode: do not ask for passwords. */ int check_host_ip; /* Also keep track of keys for IP address */ int strict_host_key_checking; /* Strict host key checking. */ diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index 1cf7f9d..415ecca 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.101 2002/02/04 12:15:25 markus Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.111 2002/06/20 23:05:55 markus Exp $"); RCSID("$FreeBSD$"); #if defined(KRB4) @@ -40,6 +40,8 @@ static void add_one_listen_addr(ServerOptions *, char *, u_short); /* AF_UNSPEC or AF_INET or AF_INET6 */ extern int IPv4or6; +/* Use of privilege separation or not */ +extern int use_privsep; /* Initializes the server options to their default values. */ @@ -90,6 +92,7 @@ initialize_server_options(ServerOptions *options) options->challenge_response_authentication = -1; options->permit_empty_passwd = -1; options->use_login = -1; + options->compression = -1; options->allow_tcp_forwarding = -1; options->num_allow_users = 0; options->num_deny_users = 0; @@ -111,6 +114,9 @@ initialize_server_options(ServerOptions *options) options->authorized_keys_file = NULL; options->authorized_keys_file2 = NULL; options->check_mail = -1; + + /* Needs to be accessable in many places */ + use_privsep = -1; } void @@ -205,7 +211,7 @@ fill_default_server_options(ServerOptions *options) #endif #ifdef AFS if (options->afs_token_passing == -1) - options->afs_token_passing = k_hasafs(); + options->afs_token_passing = 0; #endif if (options->password_authentication == -1) options->password_authentication = 1; @@ -217,6 +223,8 @@ fill_default_server_options(ServerOptions *options) options->permit_empty_passwd = 0; if (options->use_login == -1) options->use_login = 0; + if (options->compression == -1) + options->compression = 1; if (options->allow_tcp_forwarding == -1) options->allow_tcp_forwarding = 1; if (options->gateway_ports == -1) @@ -242,6 +250,10 @@ fill_default_server_options(ServerOptions *options) } if (options->authorized_keys_file == NULL) options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; + + /* Turn privilege separation off by default */ + if (use_privsep == -1) + use_privsep = 0; } /* Keyword tokens. */ @@ -264,13 +276,14 @@ typedef enum { sPrintMotd, sPrintLastLog, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, sStrictModes, sEmptyPasswd, sKeepAlives, - sUseLogin, sAllowTcpForwarding, + sUseLogin, sAllowTcpForwarding, sCompression, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, sBanner, sVerifyReverseMapping, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, + sUsePrivilegeSeparation, sCheckMail, sVersionAddendum, sDeprecated } ServerOpCodes; @@ -324,6 +337,7 @@ static struct { { "strictmodes", sStrictModes }, { "permitemptypasswords", sEmptyPasswd }, { "uselogin", sUseLogin }, + { "compression", sCompression }, { "keepalive", sKeepAlives }, { "allowtcpforwarding", sAllowTcpForwarding }, { "allowusers", sAllowUsers }, @@ -343,6 +357,7 @@ static struct { { "clientalivecountmax", sClientAliveCountMax }, { "authorizedkeysfile", sAuthorizedKeysFile }, { "authorizedkeysfile2", sAuthorizedKeysFile2 }, + { "useprivilegeseparation", sUsePrivilegeSeparation}, { "checkmail", sCheckMail }, { "versionaddendum", sVersionAddendum }, { NULL, sBadOption } @@ -681,6 +696,10 @@ parse_flag: intptr = &options->use_login; goto parse_flag; + case sCompression: + intptr = &options->compression; + goto parse_flag; + case sGatewayPorts: intptr = &options->gateway_ports; goto parse_flag; @@ -715,6 +734,10 @@ parse_flag: intptr = &options->allow_tcp_forwarding; goto parse_flag; + case sUsePrivilegeSeparation: + intptr = &use_privsep; + goto parse_flag; + case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index d5bf6be..862832a 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.54 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: servconf.h,v 1.58 2002/06/20 23:05:55 markus Exp $ */ /* $FreeBSD$ */ /* @@ -100,6 +100,7 @@ typedef struct { int permit_empty_passwd; /* If false, do not permit empty * passwords. */ int use_login; /* If true, login(1) is used */ + int compression; /* If true, compression is allowed */ int allow_tcp_forwarding; u_int num_allow_users; char *allow_users[MAX_ALLOW_USERS]; @@ -132,7 +133,6 @@ typedef struct { char *authorized_keys_file; /* File containing public keys */ char *authorized_keys_file2; - } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c index c5731d4..9210050 100644 --- a/crypto/openssh/serverloop.c +++ b/crypto/openssh/serverloop.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: serverloop.c,v 1.98 2002/02/06 14:55:16 markus Exp $"); +RCSID("$OpenBSD: serverloop.c,v 1.102 2002/06/11 05:46:20 mpech Exp $"); RCSID("$FreeBSD$"); #include "xmalloc.h" @@ -319,9 +319,6 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, tv.tv_usec = 1000 * (max_time_milliseconds % 1000); tvp = &tv; } - if (tvp!=NULL) - debug3("tvp!=NULL kid %d mili %d", (int) child_terminated, - max_time_milliseconds); /* Wait for something to happen, or the timeout to expire. */ ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); @@ -674,12 +671,12 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) /* We no longer want our SIGCHLD handler to be called. */ signal(SIGCHLD, SIG_DFL); - wait_pid = waitpid(-1, &wait_status, 0); - if (wait_pid == -1) - packet_disconnect("wait: %.100s", strerror(errno)); - else if (wait_pid != pid) - error("Strange, wait returned pid %d, expected %d", - wait_pid, pid); + while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) + if (errno != EINTR) + packet_disconnect("wait: %.100s", strerror(errno)); + if (wait_pid != pid) + error("Strange, wait returned pid %ld, expected %ld", + (long)wait_pid, (long)pid); /* Check if it exited normally. */ if (WIFEXITED(wait_status)) { @@ -727,8 +724,10 @@ collect_children(void) sigaddset(&nset, SIGCHLD); sigprocmask(SIG_BLOCK, &nset, &oset); if (child_terminated) { - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - session_close_by_pid(pid, status); + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) + if (pid > 0) + session_close_by_pid(pid, status); child_terminated = 0; } sigprocmask(SIG_SETMASK, &oset, NULL); @@ -785,7 +784,7 @@ server_loop2(Authctxt *authctxt) channel_free_all(); /* free remaining sessions, e.g. remove wtmp entries */ - session_destroy_all(); + session_destroy_all(NULL); } static void diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index eddcf6c..2992794 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.128 2002/02/16 00:51:44 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.138 2002/06/20 23:05:55 markus Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" @@ -57,6 +57,7 @@ RCSID("$FreeBSD$"); #include "serverloop.h" #include "canohost.h" #include "session.h" +#include "monitor_wrap.h" #ifdef __FreeBSD__ #define _PATH_CHPASS "/usr/bin/passwd" @@ -69,39 +70,11 @@ RCSID("$FreeBSD$"); #include <login_cap.h> #endif -/* types */ - -#define TTYSZ 64 -typedef struct Session Session; -struct Session { - int used; - int self; - struct passwd *pw; - Authctxt *authctxt; - pid_t pid; - /* tty */ - char *term; - int ptyfd, ttyfd, ptymaster; - int row, col, xpixel, ypixel; - char tty[TTYSZ]; - /* X11 */ - int display_number; - char *display; - int screen; - char *auth_display; - char *auth_proto; - char *auth_data; - int single_connection; - /* proto 2 */ - int chanid; - int is_subsystem; -}; - /* func */ Session *session_new(void); void session_set_fds(Session *, int, int, int); -static void session_pty_cleanup(void *); +void session_pty_cleanup(void *); void session_proctitle(Session *); int session_setup_x11fwd(Session *); void do_exec_pty(Session *, const char *); @@ -115,7 +88,6 @@ int check_quietlogin(Session *, const char *); static void do_authenticated1(Authctxt *); static void do_authenticated2(Authctxt *); -static void session_close(Session *); static int session_pty_req(Session *); /* import */ @@ -135,9 +107,96 @@ const char *original_command = NULL; Session sessions[MAX_SESSIONS]; #ifdef HAVE_LOGIN_CAP -static login_cap_t *lc; +login_cap_t *lc; #endif +/* Name and directory of socket for authentication agent forwarding. */ +static char *auth_sock_name = NULL; +static char *auth_sock_dir = NULL; + +/* removes the agent forwarding socket */ + +static void +auth_sock_cleanup_proc(void *_pw) +{ + struct passwd *pw = _pw; + + if (auth_sock_name != NULL) { + temporarily_use_uid(pw); + unlink(auth_sock_name); + rmdir(auth_sock_dir); + auth_sock_name = NULL; + restore_uid(); + } +} + +static int +auth_input_request_forwarding(struct passwd * pw) +{ + Channel *nc; + int sock; + struct sockaddr_un sunaddr; + + if (auth_sock_name != NULL) { + error("authentication forwarding requested twice."); + return 0; + } + + /* Temporarily drop privileged uid for mkdir/bind. */ + temporarily_use_uid(pw); + + /* Allocate a buffer for the socket name, and format the name. */ + auth_sock_name = xmalloc(MAXPATHLEN); + auth_sock_dir = xmalloc(MAXPATHLEN); + strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); + + /* Create private directory for socket */ + if (mkdtemp(auth_sock_dir) == NULL) { + packet_send_debug("Agent forwarding disabled: " + "mkdtemp() failed: %.100s", strerror(errno)); + restore_uid(); + xfree(auth_sock_name); + xfree(auth_sock_dir); + auth_sock_name = NULL; + auth_sock_dir = NULL; + return 0; + } + snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", + auth_sock_dir, (long) getpid()); + + /* delete agent socket on fatal() */ + fatal_add_cleanup(auth_sock_cleanup_proc, pw); + + /* Create the socket. */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + packet_disconnect("socket: %.100s", strerror(errno)); + + /* Bind it to the name. */ + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); + + if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) + packet_disconnect("bind: %.100s", strerror(errno)); + + /* Restore the privileged uid. */ + restore_uid(); + + /* Start listening on the socket. */ + if (listen(sock, 5) < 0) + packet_disconnect("listen: %.100s", strerror(errno)); + + /* Allocate a channel for the authentication agent socket. */ + nc = channel_new("auth socket", + SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, xstrdup("auth socket"), 1); + strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); + return 1; +} + + void do_authenticated(Authctxt *authctxt) { @@ -150,18 +209,6 @@ do_authenticated(Authctxt *authctxt) close(startup_pipe); startup_pipe = -1; } -#ifdef HAVE_LOGIN_CAP - if ((lc = login_getpwclass(authctxt->pw)) == NULL) { - error("unable to get login class"); - return; - } -#ifdef BSD_AUTH - if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) { - packet_disconnect("Approval failure for %s", - authctxt->pw->pw_name); - } -#endif -#endif /* setup the channel layer */ if (!no_port_forwarding_flag && options.allow_tcp_forwarding) channel_permit_all_opens(); @@ -172,7 +219,7 @@ do_authenticated(Authctxt *authctxt) do_authenticated1(authctxt); /* remove agent socket */ - if (auth_get_socket_name()) + if (auth_sock_name != NULL) auth_sock_cleanup_proc(authctxt->pw); #ifdef KRB4 if (options.kerberos_ticket_cleanup) @@ -223,6 +270,10 @@ do_authenticated1(Authctxt *authctxt) compression_level); break; } + if (!options.compression) { + debug2("compression disabled"); + break; + } /* Enable compression after we have responded with SUCCESS. */ enable_compression_after_reply = 1; success = 1; @@ -379,7 +430,7 @@ do_authenticated1(Authctxt *authctxt) void do_exec_no_pty(Session *s, const char *command) { - int pid; + pid_t pid; #ifdef USE_PIPES int pin[2], pout[2], perr[2]; @@ -603,22 +654,13 @@ do_exec(Session *s, const char *command) void do_login(Session *s, const char *command) { - FILE *f; #ifndef USE_PAM char *time_string; - char *newcommand = NULL; #endif - char buf[256]; -#ifndef USE_PAM - char hostname[MAXHOSTNAMELEN]; socklen_t fromlen; struct sockaddr_storage from; - time_t last_login_time; -#endif struct passwd * pw = s->pw; -#ifndef USE_PAM pid_t pid = getpid(); -#endif #ifdef __FreeBSD__ #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ struct timeval tv; @@ -644,20 +686,6 @@ do_login(Session *s, const char *command) } #endif -#ifndef USE_PAM - /* Get the time and hostname when the user last logged in. */ - if (options.print_lastlog) { - hostname[0] = '\0'; - last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, - hostname, sizeof(hostname)); - } - - /* Record that there was a login on that tty from the remote host. */ - record_login(pid, s->tty, pw->pw_name, pw->pw_uid, - get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), - (struct sockaddr *)&from); -#endif - #ifdef USE_PAM /* * If password change is needed, do it now. @@ -729,6 +757,13 @@ do_login(Session *s, const char *command) } #endif /* HAVE_LOGIN_CAP */ + /* Record that there was a login on that tty from the remote host. */ + if (!use_privsep) + record_login(pid, s->tty, pw->pw_name, pw->pw_uid, + get_remote_name_or_ip(utmp_len, + options.verify_reverse_mapping), + (struct sockaddr *)&from); + #ifdef USE_PAM if (command == NULL && options.print_lastlog && !check_quietlogin(s, command) && @@ -745,22 +780,27 @@ do_login(Session *s, const char *command) */ if (command == NULL && options.print_lastlog && - last_login_time != 0 && !check_quietlogin(s, command) && + s->last_login_time != 0 && !check_quietlogin(s, command) && !options.use_login) { - time_string = ctime(&last_login_time); + time_string = ctime(&s->last_login_time); if (strchr(time_string, '\n')) *strchr(time_string, '\n') = 0; - if (strcmp(hostname, "") == 0) + if (strcmp(s->hostname, "") == 0) printf("Last login: %s\r\n", time_string); else - printf("Last login: %s from %s\r\n", time_string, hostname); + printf("Last login: %s from %s\r\n", time_string, + s->hostname); } #endif /* !USE_PAM */ if (command == NULL && !check_quietlogin(s, command) && !options.use_login) { #ifdef HAVE_LOGIN_CAP - const char *fname = login_getcapstr(lc, "copyright", NULL, NULL); + const char *fname; + char buf[256]; + FILE *f; + + fname = login_getcapstr(lc, "copyright", NULL, NULL); if (fname != NULL && (f = fopen(fname, "r")) != NULL) { while (fgets(buf, sizeof(buf), f) != NULL) fputs(buf, stdout); @@ -1033,9 +1073,9 @@ do_setup_env(char **env, Session *s, const char *shell) do_pam_environment(&env, &envsize); #endif /* USE_PAM */ - if (auth_get_socket_name() != NULL) + if (auth_sock_name != NULL) child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, - auth_get_socket_name()); + auth_sock_name); /* read $HOME/.ssh/environment. */ if (!options.use_login) { @@ -1099,7 +1139,7 @@ do_rc_files(Session *s, const char *shell) /* Add authority data to .Xauthority if appropriate. */ if (debug_flag) { fprintf(stderr, - "Running %.100s add " + "Running %.500s add " "%.100s %.100s %.100s\n", options.xauth_location, s->auth_display, s->auth_proto, s->auth_data); @@ -1143,11 +1183,10 @@ do_nologin(struct passwd *pw) } /* Set login name, uid, gid, and groups. */ -static char ** -do_setusercontext(Session *s) +void +do_setusercontext(struct passwd *pw) { char **env = NULL; - struct passwd *pw = s->pw; #ifdef HAVE_LOGIN_CAP char buf[256]; char **tmpenv; @@ -1170,9 +1209,6 @@ do_setusercontext(Session *s) if (getenv("TZ")) child_set_env(&env, &envsize, "TZ", getenv("TZ")); - if (s->term) - child_set_env(&env, &envsize, "TERM", s->term); - /* Save parent environment */ tmpenv = environ; /* Switch to env */ @@ -1207,7 +1243,21 @@ do_setusercontext(Session *s) if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); #endif /* HAVE_LOGIN_CAP */ - return env; + return; +} + +static void +launch_login(struct passwd *pw, const char *hostname) +{ + /* Launch login(1). */ + + execl("/usr/bin/login", "login", "-h", hostname, + "-p", "-f", "--", pw->pw_name, (char *)NULL); + + /* Login couldn't be executed, die. */ + + perror("login"); + exit(1); } /* @@ -1242,7 +1292,7 @@ do_child(Session *s, const char *command) */ if (!options.use_login) { do_nologin(pw); - env = do_setusercontext(s); + do_setusercontext(pw); } /* @@ -1336,15 +1386,8 @@ do_child(Session *s, const char *command) signal(SIGPIPE, SIG_DFL); if (options.use_login) { - /* Launch login(1). */ - - execl("/usr/bin/login", "login", "-h", hostname, - "-p", "-f", "--", pw->pw_name, (char *)NULL); - - /* Login couldn't be executed, die. */ - - perror("login"); - exit(1); + launch_login(pw, hostname); + /* NEVERREACHED */ } /* Get the last component of the shell name. */ @@ -1450,12 +1493,12 @@ session_dump(void) int i; for (i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; - debug("dump: used %d session %d %p channel %d pid %d", + debug("dump: used %d session %d %p channel %d pid %ld", s->used, s->self, s, s->chanid, - s->pid); + (long)s->pid); } } @@ -1477,6 +1520,22 @@ session_open(Authctxt *authctxt, int chanid) return 1; } +Session * +session_by_tty(char *tty) +{ + int i; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { + debug("session_by_tty: session %d tty %s", i, tty); + return s; + } + } + debug("session_by_tty: unknown tty %.100s", tty); + session_dump(); + return NULL; +} + static Session * session_by_channel(int id) { @@ -1497,13 +1556,13 @@ static Session * session_by_pid(pid_t pid) { int i; - debug("session_by_pid: pid %d", pid); + debug("session_by_pid: pid %ld", (long)pid); for (i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; if (s->used && s->pid == pid) return s; } - error("session_by_pid: unknown pid %d", pid); + error("session_by_pid: unknown pid %ld", (long)pid); session_dump(); return NULL; } @@ -1534,6 +1593,12 @@ session_pty_req(Session *s) packet_disconnect("Protocol error: you already have a pty."); return 0; } + /* Get the time and hostname when the user last logged in. */ + if (options.print_lastlog) { + s->hostname[0] = '\0'; + s->last_login_time = get_last_login_time(s->pw->pw_uid, + s->pw->pw_name, s->hostname, sizeof(s->hostname)); + } s->term = packet_get_string(&len); @@ -1554,7 +1619,7 @@ session_pty_req(Session *s) /* Allocate a pty and open it. */ debug("Allocating pty."); - if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) { + if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { if (s->term) xfree(s->term); s->term = NULL; @@ -1575,7 +1640,8 @@ session_pty_req(Session *s) * time in case we call fatal() (e.g., the connection gets closed). */ fatal_add_cleanup(session_pty_cleanup, (void *)s); - pty_setowner(s->pw, s->tty); + if (!use_privsep) + pty_setowner(s->pw, s->tty); /* Set window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); @@ -1738,8 +1804,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) * Function to perform pty cleanup. Also called if we get aborted abnormally * (e.g., due to a dropped connection). */ -static void -session_pty_cleanup(void *session) +void +session_pty_cleanup2(void *session) { Session *s = session; @@ -1757,7 +1823,8 @@ session_pty_cleanup(void *session) record_logout(s->pid, s->tty); /* Release the pseudo-tty. */ - pty_release(s->tty); + if (getuid() == 0) + pty_release(s->tty); /* * Close the server side of the socket pairs. We must do this after @@ -1765,12 +1832,18 @@ session_pty_cleanup(void *session) * while we're still cleaning up. */ if (close(s->ptymaster) < 0) - error("close(s->ptymaster): %s", strerror(errno)); + error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); /* unlink pty from session */ s->ttyfd = -1; } +void +session_pty_cleanup(void *session) +{ + PRIVSEP(session_pty_cleanup2(session)); +} + static void session_exit_message(Session *s, int status) { @@ -1779,8 +1852,8 @@ session_exit_message(Session *s, int status) if ((c = channel_lookup(s->chanid)) == NULL) fatal("session_exit_message: session %d: no channel %d", s->self, s->chanid); - debug("session_exit_message: session %d channel %d pid %d", - s->self, s->chanid, s->pid); + debug("session_exit_message: session %d channel %d pid %ld", + s->self, s->chanid, (long)s->pid); if (WIFEXITED(status)) { channel_request_start(s->chanid, "exit-status", 0); @@ -1812,10 +1885,10 @@ session_exit_message(Session *s, int status) s->chanid = -1; } -static void +void session_close(Session *s) { - debug("session_close: session %d pid %d", s->self, s->pid); + debug("session_close: session %d pid %ld", s->self, (long)s->pid); if (s->ttyfd != -1) { fatal_remove_cleanup(session_pty_cleanup, (void *)s); session_pty_cleanup(s); @@ -1839,7 +1912,8 @@ session_close_by_pid(pid_t pid, int status) { Session *s = session_by_pid(pid); if (s == NULL) { - debug("session_close_by_pid: no session for pid %d", pid); + debug("session_close_by_pid: no session for pid %ld", + (long)pid); return; } if (s->chanid != -1) @@ -1859,7 +1933,8 @@ session_close_by_channel(int id, void *arg) debug("session_close_by_channel: no session for id %d", id); return; } - debug("session_close_by_channel: channel %d child %d", id, s->pid); + debug("session_close_by_channel: channel %d child %ld", + id, (long)s->pid); if (s->pid != 0) { debug("session_close_by_channel: channel %d: has child", id); /* @@ -1879,13 +1954,17 @@ session_close_by_channel(int id, void *arg) } void -session_destroy_all(void) +session_destroy_all(void (*closefunc)(Session *)) { int i; for (i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; - if (s->used) - session_close(s); + if (s->used) { + if (closefunc != NULL) + closefunc(s); + else + session_close(s); + } } } diff --git a/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c index 526a187..3680c06 100644 --- a/crypto/openssh/ssh-add.c +++ b/crypto/openssh/ssh-add.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-add.c,v 1.50 2002/01/29 14:27:57 markus Exp $"); +RCSID("$OpenBSD: ssh-add.c,v 1.61 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include <openssl/evp.h> @@ -49,6 +49,7 @@ RCSID("$FreeBSD$"); #include "authfile.h" #include "pathnames.h" #include "readpass.h" +#include "misc.h" /* argv0 */ extern char *__progname; @@ -57,10 +58,12 @@ extern char *__progname; static char *default_files[] = { _PATH_SSH_CLIENT_ID_RSA, _PATH_SSH_CLIENT_ID_DSA, - _PATH_SSH_CLIENT_IDENTITY, + _PATH_SSH_CLIENT_IDENTITY, NULL }; +/* Default lifetime (0 == forever) */ +static int lifetime = 0; /* we keep a cache of one passphrases */ static char *pass = NULL; @@ -156,11 +159,19 @@ add_file(AuthenticationConnection *ac, const char *filename) strlcpy(msg, "Bad passphrase, try again: ", sizeof msg); } } - if (ssh_add_identity(ac, private, comment)) { + + if (ssh_add_identity_constrained(ac, private, comment, lifetime)) { fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); ret = 0; - } else + if (lifetime != 0) + fprintf(stderr, + "Lifetime set to %d seconds\n", lifetime); + } else if (ssh_add_identity(ac, private, comment)) { + fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); + ret = 0; + } else { fprintf(stderr, "Could not add identity: %s\n", filename); + } xfree(comment); key_free(private); @@ -171,7 +182,13 @@ add_file(AuthenticationConnection *ac, const char *filename) static int update_card(AuthenticationConnection *ac, int add, const char *id) { - if (ssh_update_card(ac, add, id)) { + char *pin; + + pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); + if (pin == NULL) + return -1; + + if (ssh_update_card(ac, add, id, pin)) { fprintf(stderr, "Card %s: %s\n", add ? "added" : "removed", id); return 0; @@ -218,6 +235,34 @@ list_identities(AuthenticationConnection *ac, int do_fp) } static int +lock_agent(AuthenticationConnection *ac, int lock) +{ + char prompt[100], *p1, *p2; + int passok = 1, ret = -1; + + strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); + p1 = read_passphrase(prompt, RP_ALLOW_STDIN); + if (lock) { + strlcpy(prompt, "Again: ", sizeof prompt); + p2 = read_passphrase(prompt, RP_ALLOW_STDIN); + if (strcmp(p1, p2) != 0) { + fprintf(stderr, "Passwords do not match.\n"); + passok = 0; + } + memset(p2, 0, strlen(p2)); + xfree(p2); + } + if (passok && ssh_lock_agent(ac, lock, p1)) { + fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); + ret = 0; + } else + fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un"); + memset(p1, 0, strlen(p1)); + xfree(p1); + return -1; +} + +static int do_file(AuthenticationConnection *ac, int deleting, char *file) { if (deleting) { @@ -239,6 +284,9 @@ usage(void) fprintf(stderr, " -L List public key parameters of all identities.\n"); fprintf(stderr, " -d Delete identity.\n"); fprintf(stderr, " -D Delete all identities.\n"); + fprintf(stderr, " -x Lock agent.\n"); + fprintf(stderr, " -x Unlock agent.\n"); + fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); #ifdef SMARTCARD fprintf(stderr, " -s reader Add key in smartcard reader.\n"); fprintf(stderr, " -e reader Remove key in smartcard reader.\n"); @@ -262,7 +310,7 @@ main(int argc, char **argv) fprintf(stderr, "Could not open a connection to your authentication agent.\n"); exit(2); } - while ((ch = getopt(argc, argv, "lLdDe:s:")) != -1) { + while ((ch = getopt(argc, argv, "lLdDxXe:s:t:")) != -1) { switch (ch) { case 'l': case 'L': @@ -270,6 +318,12 @@ main(int argc, char **argv) ret = 1; goto done; break; + case 'x': + case 'X': + if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1) + ret = 1; + goto done; + break; case 'd': deleting = 1; break; @@ -285,6 +339,13 @@ main(int argc, char **argv) deleting = 1; sc_reader_id = optarg; break; + case 't': + if ((lifetime = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid lifetime\n"); + ret = 1; + goto done; + } + break; default: usage(); ret = 1; @@ -301,6 +362,8 @@ main(int argc, char **argv) if (argc == 0) { char buf[MAXPATHLEN]; struct passwd *pw; + struct stat st; + int count = 0; if ((pw = getpwuid(getuid())) == NULL) { fprintf(stderr, "No user found with uid %u\n", @@ -310,11 +373,17 @@ main(int argc, char **argv) } for(i = 0; default_files[i]; i++) { - snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, + snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, default_files[i]); + if (stat(buf, &st) < 0) + continue; if (do_file(ac, deleting, buf) == -1) ret = 1; + else + count++; } + if (count == 0) + ret = 1; } else { for(i = 0; i < argc; i++) { if (do_file(ac, deleting, argv[i]) == -1) diff --git a/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c index 07df747..4fc0f23 100644 --- a/crypto/openssh/ssh-agent.c +++ b/crypto/openssh/ssh-agent.c @@ -35,7 +35,7 @@ #include "includes.h" #include <sys/queue.h> -RCSID("$OpenBSD: ssh-agent.c,v 1.82 2002/03/04 17:27:39 stevesk Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.95 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include <openssl/evp.h> @@ -53,7 +53,6 @@ RCSID("$FreeBSD$"); #include "log.h" #ifdef SMARTCARD -#include <openssl/engine.h> #include "scard.h" #endif @@ -68,6 +67,7 @@ typedef struct { sock_type type; Buffer input; Buffer output; + Buffer request; } SocketEntry; u_int sockets_alloc = 0; @@ -77,6 +77,7 @@ typedef struct identity { TAILQ_ENTRY(identity) next; Key *key; char *comment; + u_int death; } Identity; typedef struct { @@ -96,6 +97,10 @@ pid_t parent_pid = -1; char socket_name[1024]; char socket_dir[1024]; +/* locking */ +int locked = 0; +char *lock_passwd = NULL; + extern char *__progname; static void @@ -117,6 +122,14 @@ idtab_lookup(int version) return &idtable[version]; } +static void +free_identity(Identity *id) +{ + key_free(id->key); + xfree(id->comment); + xfree(id); +} + /* return matching private key for given public key */ static Identity * lookup_identity(Key *key, int version) @@ -131,14 +144,6 @@ lookup_identity(Key *key, int version) return (NULL); } -static void -free_identity(Identity *id) -{ - key_free(id->key); - xfree(id->comment); - xfree(id); -} - /* send list of supported public keys to 'client' */ static void process_request_identities(SocketEntry *e, int version) @@ -188,16 +193,16 @@ process_authentication_challenge1(SocketEntry *e) if ((challenge = BN_new()) == NULL) fatal("process_authentication_challenge1: BN_new failed"); - buffer_get_int(&e->input); /* ignored */ - buffer_get_bignum(&e->input, key->rsa->e); - buffer_get_bignum(&e->input, key->rsa->n); - buffer_get_bignum(&e->input, challenge); + buffer_get_int(&e->request); /* ignored */ + buffer_get_bignum(&e->request, key->rsa->e); + buffer_get_bignum(&e->request, key->rsa->n); + buffer_get_bignum(&e->request, challenge); /* Only protocol 1.1 is supported */ - if (buffer_len(&e->input) == 0) + if (buffer_len(&e->request) == 0) goto failure; - buffer_get(&e->input, session_id, 16); - response_type = buffer_get_int(&e->input); + buffer_get(&e->request, session_id, 16); + response_type = buffer_get_int(&e->request); if (response_type != 1) goto failure; @@ -253,10 +258,10 @@ process_sign_request2(SocketEntry *e) datafellows = 0; - blob = buffer_get_string(&e->input, &blen); - data = buffer_get_string(&e->input, &dlen); + blob = buffer_get_string(&e->request, &blen); + data = buffer_get_string(&e->request, &dlen); - flags = buffer_get_int(&e->input); + flags = buffer_get_int(&e->request); if (flags & SSH_AGENT_OLD_SIGNATURE) datafellows = SSH_BUG_SIGBLOB; @@ -297,16 +302,16 @@ process_remove_identity(SocketEntry *e, int version) switch (version) { case 1: key = key_new(KEY_RSA1); - bits = buffer_get_int(&e->input); - buffer_get_bignum(&e->input, key->rsa->e); - buffer_get_bignum(&e->input, key->rsa->n); + bits = buffer_get_int(&e->request); + buffer_get_bignum(&e->request, key->rsa->e); + buffer_get_bignum(&e->request, key->rsa->n); if (bits != key_size(key)) log("Warning: identity keysize mismatch: actual %d, announced %d", key_size(key), bits); break; case 2: - blob = buffer_get_string(&e->input, &blen); + blob = buffer_get_string(&e->request, &blen); key = key_from_blob(blob, blen); xfree(blob); break; @@ -357,7 +362,27 @@ process_remove_all_identities(SocketEntry *e, int version) /* Send success. */ buffer_put_int(&e->output, 1); buffer_put_char(&e->output, SSH_AGENT_SUCCESS); - return; +} + +static void +reaper(void) +{ + Idtab *tab; + Identity *id, *nxt; + int version; + u_int now = time(NULL); + + for (version = 1; version < 3; version++) { + tab = idtab_lookup(version); + for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { + nxt = TAILQ_NEXT(id, next); + if (id->death != 0 && now >= id->death) { + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); + tab->nentries--; + } + } + } } static void @@ -366,66 +391,76 @@ process_add_identity(SocketEntry *e, int version) Key *k = NULL; char *type_name; char *comment; - int type, success = 0; + int type, success = 0, death = 0; Idtab *tab = idtab_lookup(version); switch (version) { case 1: k = key_new_private(KEY_RSA1); - buffer_get_int(&e->input); /* ignored */ - buffer_get_bignum(&e->input, k->rsa->n); - buffer_get_bignum(&e->input, k->rsa->e); - buffer_get_bignum(&e->input, k->rsa->d); - buffer_get_bignum(&e->input, k->rsa->iqmp); + buffer_get_int(&e->request); /* ignored */ + buffer_get_bignum(&e->request, k->rsa->n); + buffer_get_bignum(&e->request, k->rsa->e); + buffer_get_bignum(&e->request, k->rsa->d); + buffer_get_bignum(&e->request, k->rsa->iqmp); /* SSH and SSL have p and q swapped */ - buffer_get_bignum(&e->input, k->rsa->q); /* p */ - buffer_get_bignum(&e->input, k->rsa->p); /* q */ + buffer_get_bignum(&e->request, k->rsa->q); /* p */ + buffer_get_bignum(&e->request, k->rsa->p); /* q */ /* Generate additional parameters */ rsa_generate_additional_parameters(k->rsa); break; case 2: - type_name = buffer_get_string(&e->input, NULL); + type_name = buffer_get_string(&e->request, NULL); type = key_type_from_name(type_name); xfree(type_name); switch (type) { case KEY_DSA: k = key_new_private(type); - buffer_get_bignum2(&e->input, k->dsa->p); - buffer_get_bignum2(&e->input, k->dsa->q); - buffer_get_bignum2(&e->input, k->dsa->g); - buffer_get_bignum2(&e->input, k->dsa->pub_key); - buffer_get_bignum2(&e->input, k->dsa->priv_key); + buffer_get_bignum2(&e->request, k->dsa->p); + buffer_get_bignum2(&e->request, k->dsa->q); + buffer_get_bignum2(&e->request, k->dsa->g); + buffer_get_bignum2(&e->request, k->dsa->pub_key); + buffer_get_bignum2(&e->request, k->dsa->priv_key); break; case KEY_RSA: k = key_new_private(type); - buffer_get_bignum2(&e->input, k->rsa->n); - buffer_get_bignum2(&e->input, k->rsa->e); - buffer_get_bignum2(&e->input, k->rsa->d); - buffer_get_bignum2(&e->input, k->rsa->iqmp); - buffer_get_bignum2(&e->input, k->rsa->p); - buffer_get_bignum2(&e->input, k->rsa->q); + buffer_get_bignum2(&e->request, k->rsa->n); + buffer_get_bignum2(&e->request, k->rsa->e); + buffer_get_bignum2(&e->request, k->rsa->d); + buffer_get_bignum2(&e->request, k->rsa->iqmp); + buffer_get_bignum2(&e->request, k->rsa->p); + buffer_get_bignum2(&e->request, k->rsa->q); /* Generate additional parameters */ rsa_generate_additional_parameters(k->rsa); break; default: - buffer_clear(&e->input); + buffer_clear(&e->request); goto send; } break; } - comment = buffer_get_string(&e->input, NULL); + comment = buffer_get_string(&e->request, NULL); if (k == NULL) { xfree(comment); goto send; } success = 1; + while (buffer_len(&e->request)) { + switch (buffer_get_char(&e->request)) { + case SSH_AGENT_CONSTRAIN_LIFETIME: + death = time(NULL) + buffer_get_int(&e->request); + break; + default: + break; + } + } if (lookup_identity(k, version) == NULL) { Identity *id = xmalloc(sizeof(Identity)); id->key = k; id->comment = comment; + id->death = death; TAILQ_INSERT_TAIL(&tab->idlist, id, next); /* Increment the number of identities. */ tab->nentries++; @@ -439,53 +474,86 @@ send: success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); } +/* XXX todo: encrypt sensitive data with passphrase */ +static void +process_lock_agent(SocketEntry *e, int lock) +{ + char *passwd; + int success = 0; + + passwd = buffer_get_string(&e->request, NULL); + if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { + locked = 0; + memset(lock_passwd, 0, strlen(lock_passwd)); + xfree(lock_passwd); + lock_passwd = NULL; + success = 1; + } else if (!locked && lock) { + locked = 1; + lock_passwd = xstrdup(passwd); + success = 1; + } + memset(passwd, 0, strlen(passwd)); + xfree(passwd); + + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} + +static void +no_identities(SocketEntry *e, u_int type) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, + (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ? + SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); + buffer_put_int(&msg, 0); + buffer_put_int(&e->output, buffer_len(&msg)); + buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); + buffer_free(&msg); +} #ifdef SMARTCARD static void process_add_smartcard_key (SocketEntry *e) { + Identity *id; Idtab *tab; - Key *n = NULL, *k = NULL; - char *sc_reader_id = NULL; - int success = 0; + Key **keys, *k; + char *sc_reader_id = NULL, *pin; + int i, version, success = 0; - sc_reader_id = buffer_get_string(&e->input, NULL); - k = sc_get_key(sc_reader_id); + sc_reader_id = buffer_get_string(&e->request, NULL); + pin = buffer_get_string(&e->request, NULL); + keys = sc_get_keys(sc_reader_id, pin); xfree(sc_reader_id); + xfree(pin); - if (k == NULL) { - error("sc_get_pubkey failed"); + if (keys == NULL || keys[0] == NULL) { + error("sc_get_keys failed"); goto send; } - success = 1; - - tab = idtab_lookup(1); - k->type = KEY_RSA1; - if (lookup_identity(k, 1) == NULL) { - Identity *id = xmalloc(sizeof(Identity)); - n = key_new(KEY_RSA1); - BN_copy(n->rsa->n, k->rsa->n); - BN_copy(n->rsa->e, k->rsa->e); - RSA_set_method(n->rsa, sc_get_engine()); - id->key = n; - id->comment = xstrdup("rsa1 smartcard"); - TAILQ_INSERT_TAIL(&tab->idlist, id, next); - tab->nentries++; - } - k->type = KEY_RSA; - tab = idtab_lookup(2); - if (lookup_identity(k, 2) == NULL) { - Identity *id = xmalloc(sizeof(Identity)); - n = key_new(KEY_RSA); - BN_copy(n->rsa->n, k->rsa->n); - BN_copy(n->rsa->e, k->rsa->e); - RSA_set_method(n->rsa, sc_get_engine()); - id->key = n; - id->comment = xstrdup("rsa smartcard"); - TAILQ_INSERT_TAIL(&tab->idlist, id, next); - tab->nentries++; + for (i = 0; keys[i] != NULL; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + tab = idtab_lookup(version); + if (lookup_identity(k, version) == NULL) { + id = xmalloc(sizeof(Identity)); + id->key = k; + id->comment = xstrdup("smartcard key"); + id->death = 0; + TAILQ_INSERT_TAIL(&tab->idlist, id, next); + tab->nentries++; + success = 1; + } else { + key_free(k); + } + keys[i] = NULL; } - key_free(k); + xfree(keys); send: buffer_put_int(&e->output, 1); buffer_put_char(&e->output, @@ -495,39 +563,37 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { - Key *k = NULL; - int success = 0; - char *sc_reader_id = NULL; + Identity *id; + Idtab *tab; + Key **keys, *k = NULL; + char *sc_reader_id = NULL, *pin; + int i, version, success = 0; - sc_reader_id = buffer_get_string(&e->input, NULL); - k = sc_get_key(sc_reader_id); + sc_reader_id = buffer_get_string(&e->request, NULL); + pin = buffer_get_string(&e->request, NULL); + keys = sc_get_keys(sc_reader_id, pin); xfree(sc_reader_id); + xfree(pin); - if (k == NULL) { - error("sc_get_pubkey failed"); - } else { - Identity *id; - k->type = KEY_RSA1; - id = lookup_identity(k, 1); - if (id != NULL) { - Idtab *tab = idtab_lookup(1); + if (keys == NULL || keys[0] == NULL) { + error("sc_get_keys failed"); + goto send; + } + for (i = 0; keys[i] != NULL; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + if ((id = lookup_identity(k, version)) != NULL) { + tab = idtab_lookup(version); TAILQ_REMOVE(&tab->idlist, id, next); - free_identity(id); tab->nentries--; - success = 1; - } - k->type = KEY_RSA; - id = lookup_identity(k, 2); - if (id != NULL) { - Idtab *tab = idtab_lookup(2); - TAILQ_REMOVE(&tab->idlist, id, next); free_identity(id); - tab->nentries--; success = 1; } key_free(k); + keys[i] = NULL; } - + xfree(keys); +send: buffer_put_int(&e->output, 1); buffer_put_char(&e->output, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); @@ -542,6 +608,10 @@ process_message(SocketEntry *e) u_int msg_len; u_int type; u_char *cp; + + /* kill dead keys */ + reaper(); + if (buffer_len(&e->input) < 5) return; /* Incomplete message. */ cp = buffer_ptr(&e->input); @@ -550,15 +620,44 @@ process_message(SocketEntry *e) shutdown(e->fd, SHUT_RDWR); close(e->fd); e->type = AUTH_UNUSED; + buffer_free(&e->input); + buffer_free(&e->output); + buffer_free(&e->request); return; } if (buffer_len(&e->input) < msg_len + 4) return; + + /* move the current input to e->request */ buffer_consume(&e->input, 4); - type = buffer_get_char(&e->input); + buffer_clear(&e->request); + buffer_append(&e->request, buffer_ptr(&e->input), msg_len); + buffer_consume(&e->input, msg_len); + type = buffer_get_char(&e->request); + + /* check wheter agent is locked */ + if (locked && type != SSH_AGENTC_UNLOCK) { + buffer_clear(&e->request); + switch (type) { + case SSH_AGENTC_REQUEST_RSA_IDENTITIES: + case SSH2_AGENTC_REQUEST_IDENTITIES: + /* send empty lists */ + no_identities(e, type); + break; + default: + /* send a fail message for all other request types */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_FAILURE); + } + return; + } debug("type %d", type); switch (type) { + case SSH_AGENTC_LOCK: + case SSH_AGENTC_UNLOCK: + process_lock_agent(e, type == SSH_AGENTC_LOCK); + break; /* ssh1 */ case SSH_AGENTC_RSA_CHALLENGE: process_authentication_challenge1(e); @@ -567,6 +666,7 @@ process_message(SocketEntry *e) process_request_identities(e, 1); break; case SSH_AGENTC_ADD_RSA_IDENTITY: + case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED: process_add_identity(e, 1); break; case SSH_AGENTC_REMOVE_RSA_IDENTITY: @@ -583,6 +683,7 @@ process_message(SocketEntry *e) process_request_identities(e, 2); break; case SSH2_AGENTC_ADD_IDENTITY: + case SSH2_AGENTC_ADD_ID_CONSTRAINED: process_add_identity(e, 2); break; case SSH2_AGENTC_REMOVE_IDENTITY: @@ -602,7 +703,7 @@ process_message(SocketEntry *e) default: /* Unknown message. Respond with failure. */ error("Unknown message %d", type); - buffer_clear(&e->input); + buffer_clear(&e->request); buffer_put_int(&e->output, 1); buffer_put_char(&e->output, SSH_AGENT_FAILURE); break; @@ -625,6 +726,7 @@ new_socket(sock_type type, int fd) sockets[i].type = type; buffer_init(&sockets[i].input); buffer_init(&sockets[i].output); + buffer_init(&sockets[i].request); return; } old_alloc = sockets_alloc; @@ -639,6 +741,7 @@ new_socket(sock_type type, int fd) sockets[old_alloc].fd = fd; buffer_init(&sockets[old_alloc].input); buffer_init(&sockets[old_alloc].output); + buffer_init(&sockets[old_alloc].request); } static int @@ -736,6 +839,7 @@ after_select(fd_set *readset, fd_set *writeset) sockets[i].type = AUTH_UNUSED; buffer_free(&sockets[i].input); buffer_free(&sockets[i].output); + buffer_free(&sockets[i].request); break; } buffer_consume(&sockets[i].output, len); @@ -754,6 +858,7 @@ after_select(fd_set *readset, fd_set *writeset) sockets[i].type = AUTH_UNUSED; buffer_free(&sockets[i].input); buffer_free(&sockets[i].output); + buffer_free(&sockets[i].request); break; } buffer_append(&sockets[i].input, buf, len); @@ -812,6 +917,7 @@ usage(void) fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n"); fprintf(stderr, " -k Kill the current agent.\n"); fprintf(stderr, " -d Debug mode.\n"); + fprintf(stderr, " -a socket Bind agent socket to given name.\n"); exit(1); } @@ -823,12 +929,13 @@ main(int ac, char **av) struct rlimit rlim; pid_t pid; char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; + char *agentsocket = NULL; extern int optind; fd_set *readsetp = NULL, *writesetp = NULL; SSLeay_add_all_algorithms(); - while ((ch = getopt(ac, av, "cdks")) != -1) { + while ((ch = getopt(ac, av, "cdksa:")) != -1) { switch (ch) { case 'c': if (s_flag) @@ -848,6 +955,9 @@ main(int ac, char **av) usage(); d_flag++; break; + case 'a': + agentsocket = optarg; + break; default: usage(); } @@ -858,7 +968,7 @@ main(int ac, char **av) if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) usage(); - if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) { + if (ac == 0 && !c_flag && !s_flag) { shell = getenv("SHELL"); if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) c_flag = 1; @@ -883,19 +993,25 @@ main(int ac, char **av) format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; printf(format, SSH_AUTHSOCKET_ENV_NAME); printf(format, SSH_AGENTPID_ENV_NAME); - printf("echo Agent pid %d killed;\n", pid); + printf("echo Agent pid %ld killed;\n", (long)pid); exit(0); } parent_pid = getpid(); - /* Create private directory for agent socket */ - strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir); - if (mkdtemp(socket_dir) == NULL) { - perror("mkdtemp: private socket dir"); - exit(1); + if (agentsocket == NULL) { + /* Create private directory for agent socket */ + strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir); + if (mkdtemp(socket_dir) == NULL) { + perror("mkdtemp: private socket dir"); + exit(1); + } + snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir, + (long)parent_pid); + } else { + /* Try to use specified agent socket */ + socket_dir[0] = '\0'; + strlcpy(socket_name, agentsocket, sizeof socket_name); } - snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, - parent_pid); /* * Create socket early so it will exist before command gets run from @@ -928,7 +1044,7 @@ main(int ac, char **av) format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, SSH_AUTHSOCKET_ENV_NAME); - printf("echo Agent pid %d;\n", parent_pid); + printf("echo Agent pid %ld;\n", (long)parent_pid); goto skip; } pid = fork(); @@ -938,14 +1054,14 @@ main(int ac, char **av) } if (pid != 0) { /* Parent - execute the given command. */ close(sock); - snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid); + snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid); if (ac == 0) { format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, SSH_AUTHSOCKET_ENV_NAME); printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, SSH_AGENTPID_ENV_NAME); - printf("echo Agent pid %d;\n", pid); + printf("echo Agent pid %ld;\n", (long)pid); exit(0); } if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 || diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index e991920..cf01550 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -13,6 +13,7 @@ * called by a name other than "ssh" or "Secure Shell". * * Copyright (c) 1999 Niels Provos. All rights reserved. + * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * * Modified to work with SSL by Niels Provos <provos@citi.umich.edu> * in Canada (German citizen). @@ -39,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.164 2002/02/14 23:28:00 markus Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.179 2002/06/12 01:09:52 markus Exp $"); RCSID("$FreeBSD$"); #include <openssl/evp.h> @@ -53,7 +54,6 @@ RCSID("$FreeBSD$"); #include "xmalloc.h" #include "packet.h" #include "buffer.h" -#include "uidswap.h" #include "channels.h" #include "key.h" #include "authfd.h" @@ -71,7 +71,6 @@ RCSID("$FreeBSD$"); #include "sshtty.h" #ifdef SMARTCARD -#include <openssl/engine.h> #include "scard.h" #endif @@ -100,7 +99,7 @@ int stdin_null_flag = 0; /* * Flag indicating that ssh should fork after authentication. This is useful - * so that the pasphrase can be entered manually, and then ssh goes to the + * so that the passphrase can be entered manually, and then ssh goes to the * background. */ int fork_after_authentication_flag = 0; @@ -125,13 +124,11 @@ char *host; struct sockaddr_storage hostaddr; /* Private host keys. */ -struct { - Key **keys; - int nkeys; -} sensitive_data; +Sensitive sensitive_data; /* Original real UID. */ uid_t original_real_uid; +uid_t original_effective_uid; /* command to be executed */ Buffer command; @@ -139,6 +136,9 @@ Buffer command; /* Should we execute a command or invoke a subsystem? */ int subsystem_flag = 0; +/* # of replies received for global requests */ +static int client_global_request_id = 0; + /* Prints a help message to the user. This function never returns. */ static void @@ -193,47 +193,6 @@ usage(void) exit(1); } -/* - * Connects to the given host using rsh (or prints an error message and exits - * if rsh is not available). This function never returns. - */ -static void -rsh_connect(char *host, char *user, Buffer * command) -{ - char *args[10]; - int i; - - log("Using rsh. WARNING: Connection will not be encrypted."); - /* Build argument list for rsh. */ - i = 0; -#ifndef _PATH_RSH -#define _PATH_RSH "/usr/bin/rsh" -#endif - args[i++] = _PATH_RSH; - /* host may have to come after user on some systems */ - args[i++] = host; - if (user) { - args[i++] = "-l"; - args[i++] = user; - } - if (buffer_len(command) > 0) { - buffer_append(command, "\0", 1); - args[i++] = buffer_ptr(command); - } - args[i++] = NULL; - if (debug_flag) { - for (i = 0; args[i]; i++) { - if (i != 0) - fprintf(stderr, " "); - fprintf(stderr, "%s", args[i]); - } - fprintf(stderr, "\n"); - } - execv(_PATH_RSH, args); - perror(_PATH_RSH); - exit(1); -} - static int ssh_session(void); static int ssh_session2(void); static void load_public_identity_files(void); @@ -244,14 +203,13 @@ static void load_public_identity_files(void); int main(int ac, char **av) { - int i, opt, exit_status, cerr; + int i, opt, exit_status; u_short fwd_port, fwd_host_port; char sfwd_port[6], sfwd_host_port[6]; char *p, *cp, buf[256]; struct stat st; struct passwd *pw; int dummy; - uid_t original_effective_uid; extern int optind, optreset; extern char *optarg; @@ -285,7 +243,7 @@ main(int ac, char **av) * them when the port has been created (actually, when the connection * has been made, as we may need to create the port several times). */ - temporarily_use_uid(pw); + PRIV_END; /* * Set our umask to something reasonable, as some files are created @@ -466,7 +424,7 @@ again: /* NOTREACHED */ } if ((fwd_port = a2port(sfwd_port)) == 0 || - (fwd_host_port = a2port(sfwd_host_port)) == 0) { + (fwd_host_port = a2port(sfwd_host_port)) == 0) { fprintf(stderr, "Bad forwarding port(s) '%s'\n", optarg); exit(1); @@ -650,52 +608,48 @@ again: "originating port will not be trusted."); options.rhosts_authentication = 0; } - /* - * If using rsh has been selected, exec it now (without trying - * anything else). Note that we must release privileges first. - */ - if (options.use_rsh) { - /* - * Restore our superuser privileges. This must be done - * before permanently setting the uid. - */ - restore_uid(); - - /* Switch to the original uid permanently. */ - permanently_set_uid(pw); - - /* Execute rsh. */ - rsh_connect(host, options.user, &command); - fatal("rsh_connect returned"); - } - /* Restore our superuser privileges. */ - restore_uid(); - /* Open a connection to the remote host. */ - cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6, + if (ssh_connect(host, &hostaddr, options.port, IPv4or6, options.connection_attempts, - original_effective_uid != 0 || !options.use_privileged_port, - pw, options.proxy_command); + original_effective_uid == 0 && options.use_privileged_port, + options.proxy_command) != 0) + exit(1); /* * If we successfully made the connection, load the host private key * in case we will need it later for combined rsa-rhosts * authentication. This must be done before releasing extra * privileges, because the file is only readable by root. + * If we cannot access the private keys, load the public keys + * instead and try to execute the ssh-keysign helper instead. */ sensitive_data.nkeys = 0; sensitive_data.keys = NULL; - if (!cerr && (options.rhosts_rsa_authentication || - options.hostbased_authentication)) { + sensitive_data.external_keysign = 0; + if (options.rhosts_rsa_authentication || + options.hostbased_authentication) { sensitive_data.nkeys = 3; sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key)); + + PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL); sensitive_data.keys[1] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL); sensitive_data.keys[2] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); + PRIV_END; + + if (sensitive_data.keys[0] == NULL && + sensitive_data.keys[1] == NULL && + sensitive_data.keys[2] == NULL) { + sensitive_data.keys[1] = key_load_public( + _PATH_HOST_DSA_KEY_FILE, NULL); + sensitive_data.keys[2] = key_load_public( + _PATH_HOST_RSA_KEY_FILE, NULL); + sensitive_data.external_keysign = 1; + } } /* * Get rid of any extra privileges that we may have. We will no @@ -704,15 +658,8 @@ again: * user's home directory if it happens to be on a NFS volume where * root is mapped to nobody. */ - - /* - * Note that some legacy systems need to postpone the following call - * to permanently_set_uid() until the private hostkey is destroyed - * with RSA_free(). Otherwise the calling user could ptrace() the - * process, read the private hostkey and impersonate the host. - * OpenBSD does not allow ptracing of setuid processes. - */ - permanently_set_uid(pw); + seteuid(original_real_uid); + setuid(original_real_uid); /* * Now that we are back to our own permissions, create ~/.ssh @@ -723,21 +670,6 @@ again: if (mkdir(buf, 0700) < 0) error("Could not create directory '%.200s'.", buf); - /* Check if the connection failed, and try "rsh" if appropriate. */ - if (cerr) { - if (!options.fallback_to_rsh) - exit(1); - if (options.port != 0) - log("Secure connection to %.100s on port %hu refused; " - "reverting to insecure method", - host, options.port); - else - log("Secure connection to %.100s refused; " - "reverting to insecure method.", host); - - rsh_connect(host, options.user, &command); - fatal("rsh_connect returned"); - } /* load options.identity_files */ load_public_identity_files(); @@ -755,8 +687,7 @@ again: signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ /* Log into the remote system. This never returns if the login fails. */ - ssh_login(sensitive_data.keys, sensitive_data.nkeys, - host, (struct sockaddr *)&hostaddr, pw); + ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); /* We no longer need the private host keys. Clear them now. */ if (sensitive_data.nkeys != 0) { @@ -808,10 +739,10 @@ x11_get_proto(char **_proto, char **_data) * XXX: "localhost" match to determine FamilyLocal * is not perfect. */ - snprintf(line, sizeof line, "%.100s list unix:%s 2>" + snprintf(line, sizeof line, "%s list unix:%s 2>" _PATH_DEVNULL, options.xauth_location, display+10); else - snprintf(line, sizeof line, "%.100s list %.200s 2>" + snprintf(line, sizeof line, "%s list %.200s 2>" _PATH_DEVNULL, options.xauth_location, display); debug2("x11_get_proto %s", line); f = popen(line, "r"); @@ -1041,6 +972,27 @@ client_subsystem_reply(int type, u_int32_t seq, void *ctxt) len, (u_char *)buffer_ptr(&command), id); } +void +client_global_request_reply(int type, u_int32_t seq, void *ctxt) +{ + int i; + + i = client_global_request_id++; + if (i >= options.num_remote_forwards) { + debug("client_global_request_reply: too many replies %d > %d", + i, options.num_remote_forwards); + return; + } + debug("remote forward %s for: listen %d, connect %s:%d", + type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", + options.remote_forwards[i].port, + options.remote_forwards[i].host, + options.remote_forwards[i].host_port); + if (type == SSH2_MSG_REQUEST_FAILURE) + log("Warning: remote port forwarding failed for listen port %d", + options.remote_forwards[i].port); +} + /* request pty/x11/agent/tcpfwd/shell for channel */ static void ssh_session2_setup(int id, void *arg) @@ -1100,7 +1052,7 @@ ssh_session2_setup(int id, void *arg) debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command)); channel_request_start(id, "subsystem", /*want reply*/ 1); /* register callback for reply */ - /* XXX we asume that client_loop has already been called */ + /* XXX we assume that client_loop has already been called */ dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply); dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply); } else { @@ -1187,40 +1139,29 @@ static void load_public_identity_files(void) { char *filename; - Key *public; int i = 0; - + Key *public; #ifdef SMARTCARD + Key **keys; + if (options.smartcard_device != NULL && - options.num_identity_files + 1 < SSH_MAX_IDENTITY_FILES && - (public = sc_get_key(options.smartcard_device)) != NULL ) { - Key *new; - - if (options.num_identity_files + 2 > SSH_MAX_IDENTITY_FILES) - options.num_identity_files = SSH_MAX_IDENTITY_FILES - 2; - memmove(&options.identity_files[2], &options.identity_files[0], - sizeof(char *) * options.num_identity_files); - options.num_identity_files += 2; - i = 2; - - /* XXX ssh1 vs ssh2 */ - new = key_new(KEY_RSA); - new->flags = KEY_FLAG_EXT; - BN_copy(new->rsa->n, public->rsa->n); - BN_copy(new->rsa->e, public->rsa->e); - RSA_set_method(new->rsa, sc_get_engine()); - options.identity_keys[0] = new; - options.identity_files[0] = xstrdup("smartcard rsa key");; - - new = key_new(KEY_RSA1); - new->flags = KEY_FLAG_EXT; - BN_copy(new->rsa->n, public->rsa->n); - BN_copy(new->rsa->e, public->rsa->e); - RSA_set_method(new->rsa, sc_get_engine()); - options.identity_keys[1] = new; - options.identity_files[1] = xstrdup("smartcard rsa1 key"); - - key_free(public); + options.num_identity_files < SSH_MAX_IDENTITY_FILES && + (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) { + int count = 0; + for (i = 0; keys[i] != NULL; i++) { + count++; + memmove(&options.identity_files[1], &options.identity_files[0], + sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); + memmove(&options.identity_keys[1], &options.identity_keys[0], + sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); + options.num_identity_files++; + options.identity_keys[0] = keys[i]; + options.identity_files[0] = xstrdup("smartcard key");; + } + if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) + options.num_identity_files = SSH_MAX_IDENTITY_FILES; + i = count; + xfree(keys); } #endif /* SMARTCARD */ for (; i < options.num_identity_files; i++) { diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h index 6848e1e..fd9fd50 100644 --- a/crypto/openssh/ssh.h +++ b/crypto/openssh/ssh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.h,v 1.64 2002/03/04 17:27:39 stevesk Exp $ */ +/* $OpenBSD: ssh.h,v 1.70 2002/06/03 12:04:07 deraadt Exp $ */ /* $FreeBSD$ */ /* @@ -32,7 +32,7 @@ #define SSH_MAX_IDENTITY_FILES 100 /* - * Major protocol version. Different version indicates major incompatiblity + * Major protocol version. Different version indicates major incompatibility * that prevents communication. * * Minor protocol version. Different version indicates minor incompatibility @@ -86,6 +86,16 @@ /* Used to identify ``EscapeChar none'' */ #define SSH_ESCAPECHAR_NONE -2 +/* + * unprivileged user when UsePrivilegeSeparation=yes; + * sshd will change its privileges to this user and its + * primary group. + */ +#define SSH_PRIVSEP_USER "sshd" + +/* Minimum modulus size (n) for RSA keys. */ +#define SSH_RSA_MINIMUM_MODULUS_SIZE 768 + #ifdef USE_PAM #include "auth-pam.h" #endif /* USE_PAM */ diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config index 07814b6..ab6206e 100644 --- a/crypto/openssh/ssh_config +++ b/crypto/openssh/ssh_config @@ -1,10 +1,10 @@ -# $OpenBSD: ssh_config,v 1.12 2002/01/16 17:55:33 stevesk Exp $ -# $FreeBSD$ +# $OpenBSD: ssh_config,v 1.15 2002/06/20 20:03:34 stevesk Exp $ +# $FreeBSD$ -# This is the ssh client system-wide configuration file. See ssh(1) -# for more information. This file provides defaults for users, and -# the values can be changed in per-user configuration files or on the -# command line. +# This is the ssh client system-wide configuration file. See +# ssh_config(5) for more information. This file provides defaults for +# users, and the values can be changed in per-user configuration files +# or on the command line. # Configuration data is parsed as follows: # 1. command line options @@ -19,12 +19,10 @@ # Host * # ForwardAgent no # ForwardX11 no -# RhostsAuthentication yes -# RhostsRSAAuthentication yes +# RhostsAuthentication no +# RhostsRSAAuthentication no # RSAAuthentication yes # PasswordAuthentication yes -# FallBackToRsh no -# UseRsh no # BatchMode no # CheckHostIP yes # StrictHostKeyChecking ask diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c index 1a6f8e4..707a9c0 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.119 2002/01/21 15:13:51 markus Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.125 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include <openssl/bn.h> @@ -37,27 +37,20 @@ RCSID("$FreeBSD$"); char *client_version_string = NULL; char *server_version_string = NULL; +/* import */ extern Options options; extern char *__progname; +extern uid_t original_real_uid; +extern uid_t original_effective_uid; static const char * -sockaddr_ntop(struct sockaddr *sa) +sockaddr_ntop(struct sockaddr *sa, socklen_t salen) { - void *addr; - static char addrbuf[INET6_ADDRSTRLEN]; + static char addrbuf[NI_MAXHOST]; - switch (sa->sa_family) { - case AF_INET: - addr = &((struct sockaddr_in *)sa)->sin_addr; - break; - case AF_INET6: - addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - break; - default: - /* This case should be protected against elsewhere */ - abort(); /* XXX abort is bad -- do something else */ - } - inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf)); + if (getnameinfo(sa, salen, addrbuf, sizeof(addrbuf), NULL, 0, + NI_NUMERICHOST) != 0) + fatal("sockaddr_ntop: getnameinfo NI_NUMERICHOST failed"); return addrbuf; } @@ -65,8 +58,7 @@ sockaddr_ntop(struct sockaddr *sa) * Connect to the given ssh server using a proxy command. */ static int -ssh_proxy_connect(const char *host, u_short port, struct passwd *pw, - const char *proxy_command) +ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) { Buffer command; const char *cp; @@ -116,7 +108,8 @@ ssh_proxy_connect(const char *host, u_short port, struct passwd *pw, char *argv[10]; /* Child. Permanently give up superuser privileges. */ - permanently_set_uid(pw); + seteuid(original_real_uid); + setuid(original_real_uid); /* Redirect stdin and stdout. */ close(pin[1]); @@ -166,7 +159,7 @@ ssh_proxy_connect(const char *host, u_short port, struct passwd *pw, * Creates a (possibly privileged) socket for use as the ssh connection. */ static int -ssh_create_socket(struct passwd *pw, int privileged, int family) +ssh_create_socket(int privileged, int family) { int sock, gaierr; struct addrinfo hints, *res; @@ -177,22 +170,18 @@ ssh_create_socket(struct passwd *pw, int privileged, int family) */ if (privileged) { int p = IPPORT_RESERVED - 1; + PRIV_START; sock = rresvport_af(&p, family); + PRIV_END; if (sock < 0) error("rresvport: af=%d %.100s", family, strerror(errno)); else debug("Allocated local port %d.", p); return sock; } - /* - * Just create an ordinary socket on arbitrary port. We use - * the user's uid to create the socket. - */ - temporarily_use_uid(pw); sock = socket(family, SOCK_STREAM, 0); if (sock < 0) error("socket: %.100s", strerror(errno)); - restore_uid(); /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL) @@ -222,9 +211,9 @@ ssh_create_socket(struct passwd *pw, int privileged, int family) /* * Opens a TCP/IP connection to the remote server on the given host. * The address of the remote host will be returned in hostaddr. - * If port is 0, the default port will be used. If anonymous is zero, + * If port is 0, the default port will be used. If needpriv is true, * a privileged port will be allocated to make the connection. - * This requires super-user privileges if anonymous is false. + * This requires super-user privileges if needpriv is true. * Connection_attempts specifies the maximum number of tries (one per * second). If proxy_command is non-NULL, it specifies the command (with %h * and %p substituted for host and port, respectively) to use to contact @@ -239,7 +228,7 @@ ssh_create_socket(struct passwd *pw, int privileged, int family) int ssh_connect(const char *host, struct sockaddr_storage * hostaddr, u_short port, int family, int connection_attempts, - int anonymous, struct passwd *pw, const char *proxy_command) + int needpriv, const char *proxy_command) { int gaierr; int on = 1; @@ -255,8 +244,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, */ int full_failure = 1; - debug("ssh_connect: getuid %u geteuid %u anon %d", - (u_int) getuid(), (u_int) geteuid(), anonymous); + debug("ssh_connect: needpriv %d", needpriv); /* Get default port if port has not been set. */ if (port == 0) { @@ -268,7 +256,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, } /* If a proxy command is given, connect using it. */ if (proxy_command != NULL) - return ssh_proxy_connect(host, port, pw, proxy_command); + return ssh_proxy_connect(host, port, proxy_command); /* No proxy command. */ @@ -304,30 +292,21 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, host, ntop, strport); /* Create a socket for connecting. */ - sock = ssh_create_socket(pw, - !anonymous && geteuid() == 0, - ai->ai_family); + sock = ssh_create_socket(needpriv, ai->ai_family); if (sock < 0) /* Any error is already output */ continue; - /* Connect to the host. We use the user's uid in the - * hope that it will help with tcp_wrappers showing - * the remote uid as root. - */ - temporarily_use_uid(pw); if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { /* Successful connection. */ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); - restore_uid(); break; } else { if (errno == ECONNREFUSED) full_failure = 0; log("ssh: connect to address %s port %s: %s", - sockaddr_ntop(ai->ai_addr), strport, - strerror(errno)); - restore_uid(); + sockaddr_ntop(ai->ai_addr, ai->ai_addrlen), + strport, strerror(errno)); /* * Close the failed socket; there appear to * be some problems when reusing a socket for @@ -785,7 +764,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, len = strlen(msg); snprintf(msg + len, sizeof(msg) - len, "\nMatching host key in %s:%d", - host_file, host_line); + host_file, host_line); } if (options.strict_host_key_checking == 1) { log(msg); @@ -833,7 +812,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) * This function does not require super-user privileges. */ void -ssh_login(Key **keys, int nkeys, const char *orighost, +ssh_login(Sensitive *sensitive, const char *orighost, struct sockaddr *hostaddr, struct passwd *pw) { char *host, *cp; @@ -858,10 +837,10 @@ ssh_login(Key **keys, int nkeys, const char *orighost, /* authenticate user */ if (compat20) { ssh_kex2(host, hostaddr); - ssh_userauth2(local_user, server_user, host, keys, nkeys); + ssh_userauth2(local_user, server_user, host, sensitive); } else { ssh_kex(host, hostaddr); - ssh_userauth1(local_user, server_user, host, keys, nkeys); + ssh_userauth1(local_user, server_user, host, sensitive); } } diff --git a/crypto/openssh/sshconnect.h b/crypto/openssh/sshconnect.h index 5c1d326..47bbfd5 100644 --- a/crypto/openssh/sshconnect.h +++ b/crypto/openssh/sshconnect.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.h,v 1.13 2001/10/08 19:05:05 markus Exp $ */ +/* $OpenBSD: sshconnect.h,v 1.17 2002/06/19 00:27:55 deraadt Exp $ */ /* $FreeBSD$ */ /* @@ -27,21 +27,44 @@ #ifndef SSHCONNECT_H #define SSHCONNECT_H +typedef struct Sensitive Sensitive; +struct Sensitive { + Key **keys; + int nkeys; + int external_keysign; +}; + int ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, - int, struct passwd *, const char *); + int, const char *); void -ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *); +ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *); int verify_host_key(char *, struct sockaddr *, Key *); void ssh_kex(char *, struct sockaddr *); void ssh_kex2(char *, struct sockaddr *); -void ssh_userauth1(const char *, const char *, char *, Key **, int); -void ssh_userauth2(const char *, const char *, char *, Key **, int); +void ssh_userauth1(const char *, const char *, char *, Sensitive *); +void ssh_userauth2(const char *, const char *, char *, Sensitive *); void ssh_put_password(char *); + +/* + * Macros to raise/lower permissions. + */ +#define PRIV_START do { \ + int save_errno = errno; \ + (void)seteuid(original_effective_uid); \ + errno = save_errno; \ +} while (0) + +#define PRIV_END do { \ + int save_errno = errno; \ + (void)seteuid(original_real_uid); \ + errno = save_errno; \ +} while (0) + #endif diff --git a/crypto/openssh/sshconnect1.c b/crypto/openssh/sshconnect1.c index f021bec..3cb2d18 100644 --- a/crypto/openssh/sshconnect1.c +++ b/crypto/openssh/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.48 2002/02/11 16:15:46 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.51 2002/05/23 19:24:30 markus Exp $"); RCSID("$FreeBSD$"); #include <openssl/bn.h> @@ -460,6 +460,8 @@ try_krb4_authentication(void) /* Get server's response. */ reply = packet_get_string((u_int *) &auth.length); + if (auth.length >= MAX_KTXT_LEN) + fatal("Kerberos v4: Malformed response from server"); memcpy(auth.dat, reply, auth.length); xfree(reply); @@ -844,7 +846,7 @@ try_challenge_response_authentication(void) error("Permission denied, please try again."); if (options.cipher == SSH_CIPHER_NONE) log("WARNING: Encryption is disabled! " - "Reponse will be transmitted in clear text."); + "Response will be transmitted in clear text."); response = read_passphrase(prompt, 0); if (strcmp(response, "") == 0) { xfree(response); @@ -1091,7 +1093,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr) */ void ssh_userauth1(const char *local_user, const char *server_user, char *host, - Key **keys, int nkeys) + Sensitive *sensitive) { #ifdef KRB5 krb5_context context = NULL; @@ -1177,9 +1179,11 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, */ if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && options.rhosts_rsa_authentication) { - for (i = 0; i < nkeys; i++) { - if (keys[i] != NULL && keys[i]->type == KEY_RSA1 && - try_rhosts_rsa_authentication(local_user, keys[i])) + for (i = 0; i < sensitive->nkeys; i++) { + if (sensitive->keys[i] != NULL && + sensitive->keys[i]->type == KEY_RSA1 && + try_rhosts_rsa_authentication(local_user, + sensitive->keys[i])) goto success; } } diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c index 283b8d2..7ecbe74 100644 --- a/crypto/openssh/sshconnect2.c +++ b/crypto/openssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.97 2002/02/25 16:33:27 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.104 2002/06/19 00:27:55 deraadt Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" @@ -46,6 +46,8 @@ RCSID("$FreeBSD$"); #include "match.h" #include "dispatch.h" #include "canohost.h" +#include "msg.h" +#include "pathnames.h" /* import */ extern char *client_version_string; @@ -155,8 +157,7 @@ struct Authctxt { int last_key_hint; AuthenticationConnection *agent; /* hostbased */ - Key **keys; - int nkeys; + Sensitive *sensitive; /* kbd-interactive */ int info_req_seen; }; @@ -173,6 +174,7 @@ void input_userauth_banner(int, u_int32_t, void *); void input_userauth_error(int, u_int32_t, void *); void input_userauth_info_req(int, u_int32_t, void *); void input_userauth_pk_ok(int, u_int32_t, void *); +void input_userauth_passwd_changereq(int, u_int32_t, void *); int userauth_none(Authctxt *); int userauth_pubkey(Authctxt *); @@ -215,7 +217,7 @@ Authmethod authmethods[] = { void ssh_userauth2(const char *local_user, const char *server_user, char *host, - Key **keys, int nkeys) + Sensitive *sensitive) { Authctxt authctxt; int type; @@ -255,8 +257,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, authctxt.success = 0; authctxt.method = authmethod_lookup("none"); authctxt.authlist = NULL; - authctxt.keys = keys; - authctxt.nkeys = nkeys; + authctxt.sensitive = sensitive; authctxt.info_req_seen = 0; if (authctxt.method == NULL) fatal("ssh_userauth2: internal error: cannot send userauth none request"); @@ -392,10 +393,10 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) debug("no key from blob. pkalg %s", pkalg); break; } - if (key->type != pktype) { + if (key->type != pktype) { error("input_userauth_pk_ok: type mismatch " "for decoded key (received %d, expected %d)", - key->type, pktype); + key->type, pktype); break; } fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); @@ -440,7 +441,7 @@ int userauth_passwd(Authctxt *authctxt) { static int attempt = 0; - char prompt[80]; + char prompt[150]; char *password; if (attempt++ >= options.number_of_password_prompts) @@ -462,13 +463,85 @@ userauth_passwd(Authctxt *authctxt) xfree(password); packet_add_padding(64); packet_send(); + + dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, + &input_userauth_passwd_changereq); + return 1; } +/* + * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST + */ +void +input_userauth_passwd_changereq(int type, uint32_t seqnr, void *ctxt) +{ + Authctxt *authctxt = ctxt; + char *info, *lang, *password = NULL, *retype = NULL; + char prompt[150]; + + debug2("input_userauth_passwd_changereq"); + + if (authctxt == NULL) + fatal("input_userauth_passwd_changereq: " + "no authentication context"); + + info = packet_get_string(NULL); + lang = packet_get_string(NULL); + if (strlen(info) > 0) + log("%s", info); + xfree(info); + xfree(lang); + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_char(1); /* additional info */ + snprintf(prompt, sizeof(prompt), + "Enter %.30s@%.128s's old password: ", + authctxt->server_user, authctxt->host); + password = read_passphrase(prompt, 0); + packet_put_cstring(password); + memset(password, 0, strlen(password)); + xfree(password); + password = NULL; + while (password == NULL) { + snprintf(prompt, sizeof(prompt), + "Enter %.30s@%.128s's new password: ", + authctxt->server_user, authctxt->host); + password = read_passphrase(prompt, RP_ALLOW_EOF); + if (password == NULL) { + /* bail out */ + return; + } + snprintf(prompt, sizeof(prompt), + "Retype %.30s@%.128s's new password: ", + authctxt->server_user, authctxt->host); + retype = read_passphrase(prompt, 0); + if (strcmp(password, retype) != 0) { + memset(password, 0, strlen(password)); + xfree(password); + log("Mismatch; try again, EOF to quit."); + password = NULL; + } + memset(retype, 0, strlen(retype)); + xfree(retype); + } + packet_put_cstring(password); + memset(password, 0, strlen(password)); + xfree(password); + packet_add_padding(64); + packet_send(); + + dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, + &input_userauth_passwd_changereq); +} static void clear_auth_state(Authctxt *authctxt) { /* XXX clear authentication state */ + dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL); + if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) { debug3("clear_auth_state: key_free %p", authctxt->last_key); key_free(authctxt->last_key); @@ -821,14 +894,88 @@ input_userauth_info_req(int type, u_int32_t seq, void *ctxt) packet_send(); } -/* - * this will be move to an external program (ssh-keysign) ASAP. ssh-keysign - * will be setuid-root and the sbit can be removed from /usr/bin/ssh. - */ +static int +ssh_keysign( + Key *key, + u_char **sigp, u_int *lenp, + u_char *data, u_int datalen) +{ + Buffer b; + struct stat st; + pid_t pid; + int to[2], from[2], status, version = 2; + + debug("ssh_keysign called"); + + if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { + error("ssh_keysign: no installed: %s", strerror(errno)); + return -1; + } + if (fflush(stdout) != 0) + error("ssh_keysign: fflush: %s", strerror(errno)); + if (pipe(to) < 0) { + error("ssh_keysign: pipe: %s", strerror(errno)); + return -1; + } + if (pipe(from) < 0) { + error("ssh_keysign: pipe: %s", strerror(errno)); + return -1; + } + if ((pid = fork()) < 0) { + error("ssh_keysign: fork: %s", strerror(errno)); + return -1; + } + if (pid == 0) { + seteuid(getuid()); + setuid(getuid()); + close(from[0]); + if (dup2(from[1], STDOUT_FILENO) < 0) + fatal("ssh_keysign: dup2: %s", strerror(errno)); + close(to[1]); + if (dup2(to[0], STDIN_FILENO) < 0) + fatal("ssh_keysign: dup2: %s", strerror(errno)); + close(from[1]); + close(to[0]); + execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); + fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN, + strerror(errno)); + } + close(from[1]); + close(to[0]); + + buffer_init(&b); + buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ + buffer_put_string(&b, data, datalen); + msg_send(to[1], version, &b); + + if (msg_recv(from[0], &b) < 0) { + error("ssh_keysign: no reply"); + buffer_clear(&b); + return -1; + } + close(from[0]); + close(to[1]); + + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + + if (buffer_get_char(&b) != version) { + error("ssh_keysign: bad version"); + buffer_clear(&b); + return -1; + } + *sigp = buffer_get_string(&b, lenp); + buffer_clear(&b); + + return 0; +} + int userauth_hostbased(Authctxt *authctxt) { Key *private = NULL; + Sensitive *sensitive = authctxt->sensitive; Buffer b; u_char *signature, *blob; char *chost, *pkalg, *p; @@ -837,12 +984,12 @@ userauth_hostbased(Authctxt *authctxt) int ok, i, len, found = 0; /* check for a useful key */ - for (i = 0; i < authctxt->nkeys; i++) { - private = authctxt->keys[i]; + for (i = 0; i < sensitive->nkeys; i++) { + private = sensitive->keys[i]; if (private && private->type != KEY_RSA1) { found = 1; /* we take and free the key */ - authctxt->keys[i] = NULL; + sensitive->keys[i] = NULL; break; } } @@ -884,7 +1031,12 @@ userauth_hostbased(Authctxt *authctxt) #ifdef DEBUG_PK buffer_dump(&b); #endif - ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); + if (sensitive->external_keysign) + ok = ssh_keysign(private, &signature, &slen, + buffer_ptr(&b), buffer_len(&b)); + else + ok = key_sign(private, &signature, &slen, + buffer_ptr(&b), buffer_len(&b)); key_free(private); buffer_free(&b); if (ok != 0) { diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index a48fa8c..fb6cf98 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -15,8 +15,10 @@ * called by a name other than "ssh" or "Secure Shell". * * SSH2 implementation: + * Privilege Separation: * - * Copyright (c) 2000 Markus Friedl. All rights reserved. + * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. + * Copyright (c) 2002 Niels Provos. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,12 +42,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.228 2002/02/27 21:23:13 stevesk Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.246 2002/06/20 23:05:56 markus Exp $"); RCSID("$FreeBSD$"); #include <openssl/dh.h> #include <openssl/bn.h> #include <openssl/md5.h> +#include <openssl/rand.h> #include "ssh.h" #include "ssh1.h" @@ -76,6 +79,11 @@ RCSID("$FreeBSD$"); #include "misc.h" #include "dispatch.h" #include "channels.h" +#include "session.h" +#include "monitor_mm.h" +#include "monitor.h" +#include "monitor_wrap.h" +#include "monitor_fdpass.h" #ifdef LIBWRAP #include <tcpd.h> @@ -184,8 +192,13 @@ u_int utmp_len = MAXHOSTNAMELEN; int *startup_pipes = NULL; int startup_pipe; /* in child */ +/* variables used for privilege separation */ +extern struct monitor *pmonitor; +extern int use_privsep; + /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); +void demote_sensitive_data(void); static void do_ssh1_kex(void); static void do_ssh2_kex(void); @@ -258,10 +271,12 @@ sigterm_handler(int sig) static void main_sigchld_handler(int sig) { + pid_t pid; int save_errno = errno; int status; - while (waitpid(-1, &status, WNOHANG) > 0) + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) ; signal(SIGCHLD, main_sigchld_handler); @@ -354,7 +369,7 @@ sshd_exchange_identification(int sock_in, int sock_out) fatal_cleanup(); } - /* Read other side's version identification. */ + /* Read other sides version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { @@ -472,6 +487,160 @@ destroy_sensitive_data(void) memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); } +/* Demote private to public keys for network child */ +void +demote_sensitive_data(void) +{ + Key *tmp; + int i; + + if (sensitive_data.server_key) { + tmp = key_demote(sensitive_data.server_key); + key_free(sensitive_data.server_key); + sensitive_data.server_key = tmp; + } + + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { + tmp = key_demote(sensitive_data.host_keys[i]); + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = tmp; + if (tmp->type == KEY_RSA1) + sensitive_data.ssh1_host_key = tmp; + } + } + + /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ +} + +static void +privsep_preauth_child(void) +{ + u_int32_t rand[256]; + int i; + struct passwd *pw; + + /* Enable challenge-response authentication for privilege separation */ + privsep_challenge_enable(); + + for (i = 0; i < 256; i++) + rand[i] = arc4random(); + RAND_seed(rand, sizeof(rand)); + + /* Demote the private keys to public keys. */ + demote_sensitive_data(); + + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + endpwent(); + + /* Change our root directory*/ + if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) + fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, + strerror(errno)); + if (chdir("/") == -1) + fatal("chdir(\"/\"): %s", strerror(errno)); + + /* Drop our privileges */ + debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, + (u_int)pw->pw_gid); + do_setusercontext(pw); +} + +static Authctxt* +privsep_preauth(void) +{ + Authctxt *authctxt = NULL; + int status; + pid_t pid; + + /* Set up unprivileged child process to deal with network data */ + pmonitor = monitor_init(); + /* Store a pointer to the kex for later rekeying */ + pmonitor->m_pkex = &xxx_kex; + + pid = fork(); + if (pid == -1) { + fatal("fork of unprivileged child failed"); + } else if (pid != 0) { + debug2("Network child is on pid %ld", (long)pid); + + close(pmonitor->m_recvfd); + authctxt = monitor_child_preauth(pmonitor); + close(pmonitor->m_sendfd); + + /* Sync memory */ + monitor_sync(pmonitor); + + /* Wait for the child's exit status */ + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + return (authctxt); + } else { + /* child */ + + close(pmonitor->m_sendfd); + + /* Demote the child */ + if (getuid() == 0 || geteuid() == 0) + privsep_preauth_child(); + setproctitle("%s", "[net]"); + } + return (NULL); +} + +static void +privsep_postauth(Authctxt *authctxt) +{ + extern Authctxt *x_authctxt; + + /* XXX - Remote port forwarding */ + x_authctxt = authctxt; + + if (authctxt->pw->pw_uid == 0 || options.use_login) { + /* File descriptor passing is broken or root login */ + monitor_apply_keystate(pmonitor); + use_privsep = 0; + return; + } + + /* Authentication complete */ + alarm(0); + if (startup_pipe != -1) { + close(startup_pipe); + startup_pipe = -1; + } + + /* New socket pair */ + monitor_reinit(pmonitor); + + pmonitor->m_pid = fork(); + if (pmonitor->m_pid == -1) + fatal("fork of unprivileged child failed"); + else if (pmonitor->m_pid != 0) { + debug2("User child is on pid %ld", (long)pmonitor->m_pid); + close(pmonitor->m_recvfd); + monitor_child_postauth(pmonitor); + + /* NEVERREACHED */ + exit(0); + } + + close(pmonitor->m_sendfd); + + /* Demote the private keys to public keys. */ + demote_sensitive_data(); + + /* Drop privileges */ + do_setusercontext(authctxt->pw); + + /* It is safe now to apply the key state */ + monitor_apply_keystate(pmonitor); +} + static char * list_hostkey_types(void) { @@ -501,7 +670,7 @@ list_hostkey_types(void) return p; } -static Key * +Key * get_hostkey_by_type(int type) { int i; @@ -513,6 +682,25 @@ get_hostkey_by_type(int type) return NULL; } +Key * +get_hostkey_by_index(int ind) +{ + if (ind < 0 || ind >= options.num_host_key_files) + return (NULL); + return (sensitive_data.host_keys[ind]); +} + +int +get_hostkey_index(Key *key) +{ + int i; + for (i = 0; i < options.num_host_key_files; i++) { + if (key == sensitive_data.host_keys[i]) + return (i); + } + return (-1); +} + /* * returns 1 if connection should be dropped, 0 otherwise. * dropping starts at connection #max_startups_begin with a probability @@ -589,6 +777,7 @@ main(int ac, char **av) int listen_sock, maxfd; int startup_p[2]; int startups = 0; + Authctxt *authctxt; Key *key; int ret, key_used = 0; @@ -787,6 +976,19 @@ main(int ac, char **av) } } + if (use_privsep) { + struct passwd *pw; + struct stat st; + + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || + (S_ISDIR(st.st_mode) == 0)) + fatal("Missing privilege separation directory: %s", + _PATH_PRIVSEP_CHROOT_DIR); + } + /* Configuration looks good, so exit if in test mode. */ if (test_flag) exit(0); @@ -933,7 +1135,7 @@ main(int ac, char **av) */ f = fopen(options.pid_file, "w"); if (f) { - fprintf(f, "%u\n", (u_int) getpid()); + fprintf(f, "%ld\n", (long) getpid()); fclose(f); } } @@ -1080,7 +1282,7 @@ main(int ac, char **av) if (pid < 0) error("fork: %.100s", strerror(errno)); else - debug("Forked child %d.", pid); + debug("Forked child %ld.", (long)pid); close(startup_p[1]); @@ -1107,6 +1309,14 @@ main(int ac, char **av) /* This is the child processing a new connection. */ /* + * Create a new session and process group since the 4.4BSD + * setlogin() affects the entire process group. We don't + * want the child to be able to affect the parent. + */ + if (setsid() < 0) + error("setsid: %.100s", strerror(errno)); + + /* * Disable the key regeneration alarm. We will not regenerate the * key since we are no longer in a position to give it to anyone. We * will not restart on SIGHUP since it no longer makes sense. @@ -1179,7 +1389,7 @@ main(int ac, char **av) sshd_exchange_identification(sock_in, sock_out); /* * Check that the connection comes from a privileged port. - * Rhosts-Authentication only makes sense from priviledged + * Rhosts-Authentication only makes sense from privileged * programs. Of course, if the intruder has root access on his local * machine, he can connect from any port. So do not use these * authentication methods from machines that you do not trust. @@ -1208,15 +1418,43 @@ main(int ac, char **av) packet_set_nonblocking(); + if (use_privsep) + if ((authctxt = privsep_preauth()) != NULL) + goto authenticated; + /* perform the key exchange */ /* authenticate user and start session */ if (compat20) { do_ssh2_kex(); - do_authentication2(); + authctxt = do_authentication2(); } else { do_ssh1_kex(); - do_authentication(); + authctxt = do_authentication(); + } + /* + * If we use privilege separation, the unprivileged child transfers + * the current keystate and exits + */ + if (use_privsep) { + mm_send_keystate(pmonitor); + exit(0); + } + + authenticated: + /* + * In privilege separation, we fork another child and prepare + * file descriptor passing. + */ + if (use_privsep) { + privsep_postauth(authctxt); + /* the monitor process [priv] will not return */ + if (!compat20) + destroy_sensitive_data(); } + + /* Perform session preparation. */ + do_authenticated(authctxt); + /* The connection has been terminated. */ verbose("Closing connection to %.100s", remote_ip); @@ -1225,10 +1463,58 @@ main(int ac, char **av) #endif /* USE_PAM */ packet_close(); + + if (use_privsep) + mm_terminate(); + exit(0); } /* + * Decrypt session_key_int using our private server key and private host key + * (key with larger modulus first). + */ +int +ssh1_session_key(BIGNUM *session_key_int) +{ + int rsafail = 0; + + if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { + /* Server key has bigger modulus. */ + if (BN_num_bits(sensitive_data.server_key->rsa->n) < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + SSH_KEY_BITS_RESERVED); + } + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.server_key->rsa) <= 0) + rsafail++; + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.ssh1_host_key->rsa) <= 0) + rsafail++; + } else { + /* Host key has bigger modulus (or they are equal). */ + if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < + BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + BN_num_bits(sensitive_data.server_key->rsa->n), + SSH_KEY_BITS_RESERVED); + } + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.ssh1_host_key->rsa) < 0) + rsafail++; + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.server_key->rsa) < 0) + rsafail++; + } + return (rsafail); +} +/* * SSH1 key exchange */ static void @@ -1343,43 +1629,9 @@ do_ssh1_kex(void) packet_set_protocol_flags(protocol_flags); packet_check_eom(); - /* - * Decrypt it using our private server key and private host key (key - * with larger modulus first). - */ - if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { - /* Server key has bigger modulus. */ - if (BN_num_bits(sensitive_data.server_key->rsa->n) < - BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.server_key->rsa->n), - BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), - SSH_KEY_BITS_RESERVED); - } - if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.server_key->rsa) <= 0) - rsafail++; - if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.ssh1_host_key->rsa) <= 0) - rsafail++; - } else { - /* Host key has bigger modulus (or they are equal). */ - if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < - BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), - BN_num_bits(sensitive_data.server_key->rsa->n), - SSH_KEY_BITS_RESERVED); - } - if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.ssh1_host_key->rsa) < 0) - rsafail++; - if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.server_key->rsa) < 0) - rsafail++; - } + /* Decrypt session_key_int using host/server keys */ + rsafail = PRIVSEP(ssh1_session_key(session_key_int)); + /* * Extract session key from the decrypted integer. The key is in the * least significant 256 bits of the integer; the first byte of the @@ -1430,9 +1682,12 @@ do_ssh1_kex(void) for (i = 0; i < 16; i++) session_id[i] = session_key[i] ^ session_key[i + 16]; } - /* Destroy the private and public keys. They will no longer be needed. */ + /* Destroy the private and public keys. No longer. */ destroy_sensitive_data(); + if (use_privsep) + mm_ssh1_session_id(session_id); + /* Destroy the decrypted integer. It is no longer needed. */ BN_clear_free(session_key_int); @@ -1444,7 +1699,7 @@ do_ssh1_kex(void) debug("Received session key; encryption turned on."); - /* Send an acknowledgement packet. Note that this packet is sent encrypted. */ + /* Send an acknowledgment packet. Note that this packet is sent encrypted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); @@ -1471,6 +1726,10 @@ do_ssh2_kex(void) myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } + if (!options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; + } myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); /* start key exchange */ @@ -1479,6 +1738,7 @@ do_ssh2_kex(void) kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->load_host_key=&get_hostkey_by_type; + kex->host_key_index=&get_hostkey_index; xxx_kex = kex; diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index 9bd2d19..3f39deb 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -1,8 +1,8 @@ -# $OpenBSD: src/usr.bin/ssh/sshd_config,v 1.48 2002/02/19 02:50:59 deraadt Exp $ -# $FreeBSD$ +# $OpenBSD: sshd_config,v 1.56 2002/06/20 23:37:12 markus Exp $ +# $FreeBSD$ -# This is the sshd server system-wide configuration file. See sshd(8) -# for more information. +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. # The strategy used for options in the default sshd_config shipped with # OpenSSH is to specify options with their default value where @@ -64,13 +64,11 @@ #ChallengeResponseAuthentication yes # Kerberos options -# KerberosAuthentication automatically enabled if keyfile exists -#KerberosAuthentication yes +#KerberosAuthentication no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes -# AFSTokenPassing automatically enabled if k_hasafs() is true -#AFSTokenPassing yes +#AFSTokenPassing no # Kerberos TGT Passing only works with the AFS kaserver #KerberosTgtPassing no @@ -83,6 +81,8 @@ #KeepAlive yes #UseLogin no #CheckMail yes +#UsePrivilegeSeparation no +#Compression yes #MaxStartups 10 # no default banner path diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index 084dd22..93b15ff 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -1,11 +1,11 @@ -/* $OpenBSD: version.h,v 1.28 2002/03/06 00:25:55 markus Exp $ */ +/* $OpenBSD: version.h,v 1.33 2002/06/21 15:41:20 markus Exp $ */ /* $FreeBSD$ */ #ifndef SSH_VERSION #define SSH_VERSION (ssh_version_get()) -#define SSH_VERSION_BASE "OpenSSH_3.1" -#define SSH_VERSION_ADDENDUM "FreeBSD-20020402" +#define SSH_VERSION_BASE "OpenSSH_3.3" +#define SSH_VERSION_ADDENDUM "FreeBSD-20020623" const char *ssh_version_get(void); void ssh_version_set_addendum(const char *add); |