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
This commit is contained in:
parent
f191b6f96c
commit
80628bacb0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=98684
@ -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$
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
else {
|
||||
/* 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. */
|
||||
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
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
#include "monitor_wrap.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
|
||||
int
|
||||
auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
|
||||
Key *client_host_key)
|
||||
{
|
||||
HostStatus host_status;
|
||||
|
||||
/* Check if we would accept it using rhosts authentication. */
|
||||
if (!auth_rhosts(pw, cuser))
|
||||
return 0;
|
||||
|
||||
host_status = check_key_in_hostfiles(pw, client_host_key,
|
||||
chost, _PATH_SSH_SYSTEM_HOSTFILE,
|
||||
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
|
||||
|
||||
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, const char *client_user, Key *client_host_key)
|
||||
auth_rhosts_rsa(struct passwd *pw, char *cuser, Key *client_host_key)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
const char *canonical_hostname;
|
||||
HostStatus host_status;
|
||||
char *chost;
|
||||
|
||||
debug("Trying rhosts with RSA host authentication for client user %.100s", client_user);
|
||||
debug("Trying rhosts with RSA host authentication for client user %.100s",
|
||||
cuser);
|
||||
|
||||
if (pw == NULL || client_host_key == NULL || client_host_key->rsa == NULL)
|
||||
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))
|
||||
return 0;
|
||||
chost = (char *)get_canonical_hostname(options.verify_reverse_mapping);
|
||||
debug("Rhosts RSA authentication: canonical host %.900s", chost);
|
||||
|
||||
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,
|
||||
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
|
||||
|
||||
if (host_status != HOST_OK) {
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (authenticated)
|
||||
packet_send_debug("RSA authentication accepted.");
|
||||
else
|
||||
auth_clear_options();
|
||||
|
||||
/* Return authentication result. */
|
||||
return authenticated;
|
||||
return (1);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
@ -61,16 +60,16 @@ skey_query(void *ctx, char **name, char **infotxt,
|
||||
*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 */
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -93,10 +100,17 @@ 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
|
||||
|
@ -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;
|
||||
@ -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 ((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);
|
||||
}
|
||||
|
@ -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"
|
||||
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
typedef struct Authmethod Authmethod;
|
||||
struct Authmethod {
|
||||
char *name;
|
||||
int (*userauth)(Authctxt *authctxt);
|
||||
int *enabled;
|
||||
/* methods */
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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>
|
||||
@ -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;
|
||||
|
@ -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 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Key *
|
||||
Key *
|
||||
key_load_private_pem(int fd, int type, const char *passphrase,
|
||||
char **commentp)
|
||||
{
|
||||
|
@ -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,8 +167,16 @@ 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)
|
||||
{
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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,6 +702,10 @@ 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
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
|
||||
|
@ -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 */
|
||||
|
@ -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,9 +67,19 @@ 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 }
|
||||
};
|
||||
@ -84,6 +96,11 @@ 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);
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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*,"
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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," \
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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 @@ process_config_line(Options *options, const char *host,
|
||||
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 @@ process_config_line(Options *options, const char *host,
|
||||
} 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)
|
||||
|
@ -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. */
|
||||
|
@ -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 @@ process_server_config_line(ServerOptions *options, char *line,
|
||||
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 @@ process_server_config_line(ServerOptions *options, char *line,
|
||||
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)
|
||||
|
@ -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 *);
|
||||
|
@ -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)
|
||||
while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0)
|
||||
if (errno != EINTR)
|
||||
packet_disconnect("wait: %.100s", strerror(errno));
|
||||
else if (wait_pid != pid)
|
||||
error("Strange, wait returned pid %d, expected %d",
|
||||
wait_pid, pid);
|
||||
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,7 +724,9 @@ collect_children(void)
|
||||
sigaddset(&nset, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
if (child_terminated) {
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
|
||||
(pid < 0 && errno == EINTR))
|
||||
if (pid > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
child_terminated = 0;
|
||||
}
|
||||
@ -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
|
||||
|
@ -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,6 +1640,7 @@ 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);
|
||||
if (!use_privsep)
|
||||
pty_setowner(s->pw, s->tty);
|
||||
|
||||
/* Set window size from the packet. */
|
||||
@ -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,6 +1823,7 @@ session_pty_cleanup(void *session)
|
||||
record_logout(s->pid, s->tty);
|
||||
|
||||
/* Release the pseudo-tty. */
|
||||
if (getuid() == 0)
|
||||
pty_release(s->tty);
|
||||
|
||||
/*
|
||||
@ -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,14 +1954,18 @@ 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)
|
||||
if (s->used) {
|
||||
if (closefunc != NULL)
|
||||
closefunc(s);
|
||||
else
|
||||
session_close(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -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;
|
||||
@ -61,6 +62,8 @@ static char *default_files[] = {
|
||||
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;
|
||||
@ -217,6 +234,34 @@ list_identities(AuthenticationConnection *ac, int do_fp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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",
|
||||
@ -312,9 +375,15 @@ main(int argc, char **argv)
|
||||
for(i = 0; default_files[i]; i++) {
|
||||
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)
|
||||
|
@ -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 @@ process_add_identity(SocketEntry *e, int version)
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
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++;
|
||||
}
|
||||
} else {
|
||||
key_free(k);
|
||||
}
|
||||
keys[i] = NULL;
|
||||
}
|
||||
xfree(keys);
|
||||
send:
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output,
|
||||
@ -495,39 +563,37 @@ process_add_smartcard_key (SocketEntry *e)
|
||||
static void
|
||||
process_remove_smartcard_key(SocketEntry *e)
|
||||
{
|
||||
Key *k = NULL;
|
||||
int success = 0;
|
||||
char *sc_reader_id = NULL;
|
||||
|
||||
sc_reader_id = buffer_get_string(&e->input, NULL);
|
||||
k = sc_get_key(sc_reader_id);
|
||||
xfree(sc_reader_id);
|
||||
|
||||
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);
|
||||
TAILQ_REMOVE(&tab->idlist, id, next);
|
||||
free_identity(id);
|
||||
tab->nentries--;
|
||||
success = 1;
|
||||
Idtab *tab;
|
||||
Key **keys, *k = NULL;
|
||||
char *sc_reader_id = NULL, *pin;
|
||||
int i, version, success = 0;
|
||||
|
||||
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 (keys == NULL || keys[0] == NULL) {
|
||||
error("sc_get_keys failed");
|
||||
goto send;
|
||||
}
|
||||
k->type = KEY_RSA;
|
||||
id = lookup_identity(k, 2);
|
||||
if (id != NULL) {
|
||||
Idtab *tab = idtab_lookup(2);
|
||||
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--;
|
||||
free_identity(id);
|
||||
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();
|
||||
|
||||
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.%d", socket_dir,
|
||||
parent_pid);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ||
|
||||
|
@ -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
|
||||
@ -650,52 +608,48 @@ main(int ac, char **av)
|
||||
"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 @@ main(int ac, char **av)
|
||||
* 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 @@ main(int ac, char **av)
|
||||
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 @@ main(int ac, char **av)
|
||||
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++) {
|
||||
|
@ -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 */
|
||||
|
@ -1,10 +1,10 @@
|
||||
# $OpenBSD: ssh_config,v 1.12 2002/01/16 17:55:33 stevesk Exp $
|
||||
# $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
|
||||
|
@ -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
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
@ -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) {
|
||||
|
@ -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]);
|
||||
|
||||
@ -1106,6 +1308,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
|
||||
@ -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,9 +1463,57 @@ 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
|
||||
*/
|
||||
@ -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;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# $OpenBSD: src/usr.bin/ssh/sshd_config,v 1.48 2002/02/19 02:50:59 deraadt Exp $
|
||||
# $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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user