ALT Linux repos
S: | 9.4p1-alt1 |
5.0: | 5.2p1-alt1.1 |
4.1: | 5.0p1-alt3 |
4.0: | 5.0p1-alt3 |
+updates: | 4.7p1-alt1 |
3.0: | 3.6.1p2-alt6 |
Group :: Networking/Remote access
RPM: openssh
Main Changelog Spec Patches Sources Download Gear Bugs and FR Repocop
Patch: openssh-5.9p1-alt7.patch
Download
Download
Makefile.in | 6 +-
auth-options.c | 12 +-
auth-options.h | 2 +-
auth-pam.c | 41 +++---
auth.c | 12 +-
auth.h | 3 +-
auth1.c | 12 +-
auth2-pubkey.c | 12 +-
auth2.c | 8 +-
blacklist.c | 267 ++++++++++++++++++++++++++++++++++++++++
blacklist.h | 37 ++++++
channels.c | 6 +
configure.ac | 8 +-
entropy.c | 4 +-
key.c | 10 ++
log.c | 8 ++
monitor.c | 4 +-
monitor_mm.c | 1 +
monitor_wrap.c | 4 +-
monitor_wrap.h | 2 +-
mux.c | 18 +--
myproposal.h | 7 +-
openbsd-compat/Makefile.in | 2 +-
openbsd-compat/getopt.c | 2 +-
openbsd-compat/getpeerproc.c | 74 +++++++++++
openbsd-compat/openbsd-compat.h | 2 +
openbsd-compat/xmmap.c | 4 +-
packet.c | 2 +-
packet.h | 2 +-
pathnames.h | 4 +
progressmeter.c | 2 +-
readconf.c | 6 +-
schnorr.c | 8 +-
scp.c | 6 +-
servconf.c | 61 +++++++--
servconf.h | 1 +
session.c | 5 +-
sftp-glob.c | 2 +-
sftp-server.8 | 4 +-
sftp-server.c | 4 +
sftp.c | 6 +-
ssh-agent.1 | 9 +-
ssh-agent.c | 146 +++++++++++++++-------
ssh-keygen.1 | 4 +
ssh-keygen.c | 12 +-
ssh-keyscan.c | 6 +-
ssh.1 | 20 ++-
ssh.c | 34 +++--
ssh_config | 10 +-
ssh_config.5 | 12 +-
sshconnect.c | 5 +-
sshconnect1.c | 2 +-
sshconnect2.c | 4 +-
sshd.8 | 1 -
sshd.c | 21 +++-
sshd_config | 35 ++++--
sshd_config.5 | 73 ++++++++---
57 files changed, 860 insertions(+), 215 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 3be3aa6..c58c7a4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -61,7 +61,7 @@ MANFMT=@MANFMT@
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
-LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+LIBSSH_OBJS=acss.o authfd.o authfile.o blacklist.o bufaux.o bufbn.o buffer.o \
canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
@@ -273,9 +273,9 @@ install-files:
$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
$(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
-rm -f $(DESTDIR)$(bindir)/slogin
- ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
+ ln -s ssh$(git-EXEEXT) $(DESTDIR)$(bindir)/slogin
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
- ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+ ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
install-sysconf:
if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
diff --git a/auth-options.c b/auth-options.c
index eae45cf..cf292f6 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -92,7 +92,7 @@ auth_clear_options(void)
* side effect: sets key option flags
*/
int
-auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
+auth_parse_options(struct passwd *pw, char *opts, const char *file, u_long linenum)
{
const char *cp;
int i;
@@ -112,6 +112,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "no-port-forwarding";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ debug("Port forwarding disabled.");
auth_debug_add("Port forwarding disabled.");
no_port_forwarding_flag = 1;
opts += strlen(cp);
@@ -119,6 +120,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "no-agent-forwarding";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ debug("Agent forwarding disabled.");
auth_debug_add("Agent forwarding disabled.");
no_agent_forwarding_flag = 1;
opts += strlen(cp);
@@ -126,6 +128,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "no-X11-forwarding";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ debug("X11 forwarding disabled.");
auth_debug_add("X11 forwarding disabled.");
no_x11_forwarding_flag = 1;
opts += strlen(cp);
@@ -133,6 +136,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "no-pty";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ debug("Pty allocation disabled.");
auth_debug_add("Pty allocation disabled.");
no_pty_flag = 1;
opts += strlen(cp);
@@ -140,6 +144,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "no-user-rc";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ debug("User rc file execution disabled.");
auth_debug_add("User rc file execution disabled.");
no_user_rc = 1;
opts += strlen(cp);
@@ -172,6 +177,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
goto bad_option;
}
forced_command[i] = '\0';
+ debug("Forced command: %.900s", forced_command);
auth_debug_add("Forced command.");
opts++;
goto next_option;
@@ -203,6 +209,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
goto bad_option;
}
authorized_principals[i] = '\0';
+ debug("principals: %.900s", authorized_principals);
auth_debug_add("principals: %.900s",
authorized_principals);
opts++;
@@ -236,8 +243,8 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
goto bad_option;
}
s[i] = '\0';
- auth_debug_add("Adding to environment: %.900s", s);
debug("Adding to environment: %.900s", s);
+ auth_debug_add("Adding to environment: %.900s", s);
opts++;
new_envstring = xmalloc(sizeof(struct envstring));
new_envstring->s = s;
@@ -385,6 +392,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
forced_tun_device = -1;
goto bad_option;
}
+ debug("Forced tun device: %d", forced_tun_device);
auth_debug_add("Forced tun device: %d", forced_tun_device);
opts++;
goto next_option;
diff --git a/auth-options.h b/auth-options.h
index 7455c94..3243821 100644
--- a/auth-options.h
+++ b/auth-options.h
@@ -33,7 +33,7 @@ extern int forced_tun_device;
extern int key_is_cert_authority;
extern char *authorized_principals;
-int auth_parse_options(struct passwd *, char *, char *, u_long);
+int auth_parse_options(struct passwd *, char *, const char *, u_long);
void auth_clear_options(void);
int auth_cert_options(Key *, struct passwd *);
diff --git a/auth-pam.c b/auth-pam.c
index 675006e..37845a5 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -65,6 +65,8 @@
#include <pam/pam_appl.h>
#endif
+#include <security/pam_userpass.h>
+
/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
#ifdef PAM_SUN_CODEBASE
# define sshpam_const /* Solaris, HP-UX, AIX */
@@ -230,7 +232,7 @@ static int sshpam_cred_established = 0;
static int sshpam_account_status = -1;
static char **sshpam_env = NULL;
static Authctxt *sshpam_authctxt = NULL;
-static const char *sshpam_password = NULL;
+static pam_userpass_t sshpam_userpass;
static char badpw[] = "\b\n\r\177INCORRECT";
/* Some PAM implementations don't implement this */
@@ -602,11 +604,11 @@ sshpam_cleanup(void)
return;
debug("PAM: cleanup");
pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
- if (sshpam_session_open) {
+ if (getpid() == sshpam_session_open) {
debug("PAM: closing session");
pam_close_session(sshpam_handle, PAM_SILENT);
- sshpam_session_open = 0;
}
+ sshpam_session_open = 0;
if (sshpam_cred_established) {
debug("PAM: deleting credentials");
pam_setcred(sshpam_handle, PAM_DELETE_CRED);
@@ -794,8 +796,9 @@ sshpam_query(void *ctx, char **name, char **info,
return (0);
}
error("PAM: %s for %s%.100s from %.100s", msg,
- sshpam_authctxt->valid ? "" : "illegal user ",
- sshpam_authctxt->user,
+ !sshpam_authctxt->valid ? "UNKNOWN USER" :
+ (sshpam_authctxt->pw->pw_uid == 0 ? "ROOT USER " : ""),
+ sshpam_authctxt->valid ? sshpam_authctxt->user : "",
get_remote_name_or_ip(utmp_len, options.use_dns));
/* FALLTHROUGH */
default:
@@ -1047,7 +1050,7 @@ do_pam_session(void)
pam_strerror(sshpam_handle, sshpam_err));
sshpam_err = pam_open_session(sshpam_handle, 0);
if (sshpam_err == PAM_SUCCESS)
- sshpam_session_open = 1;
+ sshpam_session_open = getpid();
else {
sshpam_session_open = 0;
disable_forwarding();
@@ -1132,18 +1135,15 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
+ i = pam_userpass_conv(n, msg, resp, data);
+ if (i != PAM_CONV_ERR)
+ return i;
+
if ((reply = calloc(n, sizeof(*reply))) == NULL)
return (PAM_CONV_ERR);
for (i = 0; i < n; ++i) {
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
- case PAM_PROMPT_ECHO_OFF:
- if (sshpam_password == NULL)
- goto fail;
- if ((reply[i].resp = strdup(sshpam_password)) == NULL)
- goto fail;
- reply[i].resp_retcode = PAM_SUCCESS;
- break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
len = strlen(PAM_MSG_MEMBER(msg, i, msg));
@@ -1172,7 +1172,7 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
return (PAM_CONV_ERR);
}
-static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
+static struct pam_conv passwd_conv = { sshpam_passwd_conv, &sshpam_userpass };
/*
* Attempt password authentication via PAM
@@ -1187,9 +1187,6 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
fatal("PAM: %s called when PAM disabled or failed to "
"initialise.", __func__);
- sshpam_password = password;
- sshpam_authctxt = authctxt;
-
/*
* If the user logging in is invalid, or is root but is not permitted
* by PermitRootLogin, use an invalid password to prevent leaking
@@ -1197,7 +1194,11 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
*/
if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
options.permit_root_login != PERMIT_YES))
- sshpam_password = badpw;
+ password = badpw;
+
+ sshpam_userpass.user = authctxt->valid ? authctxt->user : "UNKNOWN USER";
+ sshpam_userpass.pass = password;
+ sshpam_authctxt = authctxt;
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&passwd_conv);
@@ -1206,14 +1207,14 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
pam_strerror(sshpam_handle, sshpam_err));
sshpam_err = pam_authenticate(sshpam_handle, flags);
- sshpam_password = NULL;
+ sshpam_userpass.user = sshpam_userpass.pass = NULL;
if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
debug("PAM: password authentication accepted for %.100s",
authctxt->user);
return 1;
} else {
debug("PAM: password authentication failed for %.100s: %s",
- authctxt->valid ? authctxt->user : "an illegal user",
+ authctxt->valid ? authctxt->user : "UNKNOWN USER",
pam_strerror(sshpam_handle, sshpam_err));
return 0;
}
diff --git a/auth.c b/auth.c
index cd95da9..f0f5209 100644
--- a/auth.c
+++ b/auth.c
@@ -71,6 +71,7 @@
#endif
#include "authfile.h"
#include "monitor_wrap.h"
+#include "blacklist.h"
/* import */
extern ServerOptions options;
@@ -274,8 +275,9 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
authlog("%s %s for %s%.100s from %.200s port %d%s",
authmsg,
method,
- authctxt->valid ? "" : "invalid user ",
- authctxt->user,
+ !authctxt->valid ? "UNKNOWN USER" :
+ (authctxt->pw->pw_uid == 0 ? "ROOT USER " : ""),
+ authctxt->valid ? authctxt->user : "",
get_remote_ipaddr(),
get_remote_port(),
info);
@@ -571,8 +573,7 @@ getpwnamallow(const char *user)
}
#endif
if (pw == NULL) {
- logit("Invalid user %.100s from %.100s",
- user, get_remote_ipaddr());
+ logit("UNKNOWN USER from %.100s", get_remote_ipaddr());
#ifdef CUSTOM_FAILED_LOGIN
record_failed_login(user,
get_canonical_hostname(options.use_dns), "ssh");
@@ -610,6 +611,9 @@ auth_key_is_revoked(Key *key)
{
char *key_fp;
+ if (blacklisted_key(key, 0))
+ return 1;
+
if (options.revoked_keys_file == NULL)
return 0;
diff --git a/auth.h b/auth.h
index 0d786c4..437fe33 100644
--- a/auth.h
+++ b/auth.h
@@ -61,6 +61,7 @@ struct Authctxt {
char *style;
void *kbdintctxt;
void *jpake_ctx;
+ char *key_fingerprint;
#ifdef BSD_AUTH
auth_session_t *as;
#endif
@@ -118,7 +119,7 @@ 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 *);
+int user_key_allowed(Authctxt *, Key *);
#ifdef KRB5
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
diff --git a/auth1.c b/auth1.c
index cc85aec..4fd55f1 100644
--- a/auth1.c
+++ b/auth1.c
@@ -241,7 +241,9 @@ do_authloop(Authctxt *authctxt)
const struct AuthMethod1 *meth;
debug("Attempting authentication for %s%.100s.",
- authctxt->valid ? "" : "invalid user ", authctxt->user);
+ !authctxt->valid ? "UNKNOWN USER" :
+ (authctxt->pw->pw_uid == 0 ? "ROOT USER " : ""),
+ authctxt->valid ? authctxt->user : "");
/* If the user has no password, accept authentication immediately. */
if (options.permit_empty_passwd && options.password_authentication &&
@@ -308,8 +310,7 @@ do_authloop(Authctxt *authctxt)
}
#endif
if (!authctxt->valid && authenticated)
- fatal("INTERNAL ERROR: authenticated invalid user %s",
- authctxt->user);
+ fatal("INTERNAL ERROR: authenticated UNKNOWN USER");
#ifdef _UNICOS
if (authenticated && cray_access_denied(authctxt->user)) {
@@ -402,11 +403,12 @@ do_authentication(Authctxt *authctxt)
if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
authctxt->valid = 1;
else {
- debug("do_authentication: invalid user %s", user);
+ debug("do_authentication: UNKNOWN USER");
authctxt->pw = fakepw();
+ authctxt->valid = 0;
}
- setproctitle("%s%s", authctxt->valid ? user : "unknown",
+ setproctitle("%s%s", authctxt->valid ? user : "UNKNOWN USER",
use_privsep ? " [net]" : "");
#ifdef USE_PAM
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 137887e..b444c18 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -139,7 +139,7 @@ userauth_pubkey(Authctxt *authctxt)
#endif
/* test for correct signature */
authenticated = 0;
- if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
+ if (PRIVSEP(user_key_allowed(authctxt, key)) &&
PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
buffer_len(&b))) == 1)
authenticated = 1;
@@ -157,7 +157,7 @@ userauth_pubkey(Authctxt *authctxt)
* if a user is not allowed to login. is this an
* issue? -markus
*/
- if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
+ if (PRIVSEP(user_key_allowed(authctxt, key))) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
@@ -434,11 +434,14 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
/* check whether given key is in .ssh/authorized_keys* */
int
-user_key_allowed(struct passwd *pw, Key *key)
+user_key_allowed(Authctxt *authctxt, Key *key)
{
u_int success, i;
char *file;
+ struct passwd *pw = authctxt->pw;
+ if (!pw)
+ return 0;
if (auth_key_is_revoked(key))
return 0;
if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
@@ -455,6 +458,9 @@ user_key_allowed(struct passwd *pw, Key *key)
xfree(file);
}
+ if (success)
+ authctxt->key_fingerprint =
+ key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
return success;
}
diff --git a/auth2.c b/auth2.c
index c06c95f..0aafa9e 100644
--- a/auth2.c
+++ b/auth2.c
@@ -238,8 +238,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
authctxt->valid = 1;
debug2("input_userauth_request: setting up authctxt for %s", user);
} else {
- logit("input_userauth_request: invalid user %s", user);
+ logit("input_userauth_request: UNKNOWN USER");
authctxt->pw = fakepw();
+ authctxt->valid = 0;
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(SSH_INVALID_USER));
#endif
@@ -248,7 +249,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
if (options.use_pam)
PRIVSEP(start_pam(authctxt));
#endif
- setproctitle("%s%s", authctxt->valid ? user : "unknown",
+ setproctitle("%s%s", authctxt->valid ? user : "UNKNOWN USER",
use_privsep ? " [net]" : "");
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL;
@@ -295,8 +296,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
char *methods;
if (!authctxt->valid && authenticated)
- fatal("INTERNAL ERROR: authenticated invalid user %s",
- authctxt->user);
+ fatal("INTERNAL ERROR: authenticated UNKNOWN USER");
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
diff --git a/blacklist.c b/blacklist.c
new file mode 100644
index 0000000..89eff83
--- /dev/null
+++ b/blacklist.c
@@ -0,0 +1,267 @@
+/*
+ * Support for RSA/DSA key blacklisting based on partial fingerprints,
+ * developed under Openwall Project for Owl - http://www.openwall.com/Owl/
+ *
+ * Copyright (c) 2008 Dmitry V. Levin <ldv at cvs.openwall.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * The blacklist encoding was designed by Solar Designer and Dmitry V. Levin.
+ * No intellectual property rights to the encoding scheme are claimed.
+ *
+ * This effort was supported by CivicActions - http://www.civicactions.com
+ *
+ * The file size to encode 294,903 of 48-bit fingerprints is just 1.3 MB,
+ * which corresponds to less than 4.5 bytes per fingerprint.
+ */
+
+#include "includes.h"
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "atomicio.h"
+#include "blacklist.h"
+#include "canohost.h"
+#include "log.h"
+#include "pathnames.h"
+#include "servconf.h"
+#include "xmalloc.h"
+
+extern ServerOptions options;
+
+typedef struct
+{
+ /* format version identifier */
+ char version[8];
+ /* index size, in bits */
+ uint8_t index_size;
+ /* offset size, in bits */
+ uint8_t offset_size;
+ /* record size, in bits */
+ uint8_t record_bits;
+ /* number of records */
+ uint8_t records[3];
+ /* offset shift */
+ uint8_t shift[2];
+
+} __attribute__((packed)) blacklist_header;
+
+static unsigned
+c2u(uint8_t c)
+{
+ return (c >= 'a') ? (c - 'a' + 10) : (c - '0');
+}
+
+static blacklist_error_t
+validate_blacklist(const char *fname, int fd, unsigned *bytes,
+ unsigned *records, unsigned *shift)
+{
+ unsigned expected;
+ struct stat st;
+ blacklist_header header;
+
+ if (fstat(fd, &st)) {
+ error("fstat for blacklist file %s failed: %m", fname);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+
+ if (atomicio(read, fd, &header, sizeof(header)) != sizeof(header)) {
+ error("read blacklist file %s header failed: %m", fname);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+
+ if (memcmp(header.version, "SSH-FP", 6)) {
+ error("blacklist file %s has unrecognized format", fname);
+ return BLACKLIST_ERROR_FORMAT;
+ }
+
+ if (header.index_size != 16 || header.offset_size != 16 ||
+ memcmp(header.version, "SSH-FP00", 8)) {
+ error("blacklist file %s has unsupported format", fname);
+ return BLACKLIST_ERROR_VERSION;
+ }
+
+ *bytes = (header.record_bits >> 3) - 2;
+ *records =
+ (((header.records[0] << 8) +
+ header.records[1]) << 8) + header.records[2];
+ *shift = (header.shift[0] << 8) + header.shift[1];
+
+ expected = sizeof(header) + 0x20000 + (*records) * (*bytes);
+ if (st.st_size != expected) {
+ error("blacklist file %s size mismatch: "
+ "expected size %u, found size %lu",
+ fname, expected, (unsigned long) st.st_size);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+
+ return BLACKLIST_ERROR_NONE;
+}
+
+static int
+expected_offset(uint16_t index, uint16_t shift, unsigned records)
+{
+ return ((index * (long long) records) >> 16) - shift;
+}
+
+static int
+xlseek(const char *fname, int fd, unsigned seek)
+{
+ if (lseek(fd, seek, SEEK_SET) != seek) {
+ error("lseek for blacklist file %s failed: %m", fname);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+ return BLACKLIST_ERROR_NONE;
+}
+
+static blacklist_error_t
+check(const char *fname, int fd, const char *s)
+{
+ unsigned bytes, records, shift;
+ unsigned num, i, j;
+ int off_start, off_end;
+ blacklist_error_t rc;
+ uint16_t index;
+ /* max number of bytes stored in record_bits, minus two bytes used for index */
+ uint8_t buf[(0xff >> 3) - 2];
+
+ if ((rc = validate_blacklist(fname, fd, &bytes, &records, &shift)))
+ return rc;
+
+ index = (((((c2u(s[0]) << 4) | c2u(s[1])) << 4) |
+ c2u(s[2])) << 4) | c2u(s[3]);
+ if (xlseek(fname, fd, sizeof(blacklist_header) + index * 2))
+ return BLACKLIST_ERROR_ACCESS;
+
+ if (atomicio(read, fd, buf, 4) != 4) {
+ error("read blacklist file %s offsets failed: %m", fname);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+
+ off_start = (buf[0] << 8) + buf[1] +
+ expected_offset(index, shift, records);
+ if (off_start < 0 || (unsigned) off_start > records) {
+ error("blacklist file %s off_start overflow [%d] for index %#x",
+ fname, off_start, index);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+ if (index < 0xffff) {
+ off_end = (buf[2] << 8) + buf[3] +
+ expected_offset(index + 1, shift, records);
+ if (off_end < off_start || (unsigned) off_end > records) {
+ error("blacklist file %s off_end overflow [%d] for index %#x",
+ fname, off_end, index);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+ } else
+ off_end = records;
+
+ if (xlseek(fname, fd,
+ sizeof(blacklist_header) + 0x20000 + off_start * bytes))
+ return BLACKLIST_ERROR_ACCESS;
+
+ num = off_end - off_start;
+ for (i = 0; i < num; ++i) {
+ if (atomicio(read, fd, buf, bytes) != bytes) {
+ error("read blacklist file %s fingerprints failed: %m",
+ fname);
+ return BLACKLIST_ERROR_ACCESS;
+ }
+
+ for (j = 0; j < bytes; ++j)
+ if (((c2u(s[4 + j * 2]) << 4) | c2u(s[5 + j * 2])) !=
+ buf[j])
+ break;
+ if (j >= bytes) {
+ debug("blacklisted fingerprint: %s offset=%u, number=%u",
+ s, off_start, i);
+ return BLACKLIST_ERROR_ALL;
+ }
+ }
+
+ debug("non-blacklisted fingerprint: %s offset=%u, number=%u",
+ s, off_start, num);
+ return BLACKLIST_ERROR_NONE;
+}
+
+static blacklist_error_t
+blacklisted_fingerprint(const char *hex)
+{
+ int fd = -1;
+ blacklist_error_t rc = BLACKLIST_ERROR_ACCESS;
+ const char *fname = _PATH_BLACKLIST;
+ char *s, *p;
+
+ debug("Checking fingerprint %s using blacklist file %s", hex, fname);
+
+ s = xstrdup(hex);
+ for (p = s; *hex; ++hex)
+ if (*hex != ':')
+ *p++ = *hex;
+ *p = '\0';
+
+ if (strlen(s) != 32 || strlen(s) != strspn(s, "0123456789abcdef")) {
+ error("%s: invalid fingerprint", s);
+ goto out;
+ }
+
+ if ((fd = open(fname, O_RDONLY)) < 0) {
+ if (ENOENT == errno) {
+ rc = BLACKLIST_ERROR_MISSING;
+ verbose("open blacklist file %s failed: %m", fname);
+ } else
+ logit("open blacklist file %s failed: %m", fname);
+ goto out;
+ }
+
+ rc = check(fname, fd, s);
+
+out:
+ close(fd);
+ xfree(s);
+ return rc;
+}
+
+int
+blacklisted_key(Key *key, int hostkey)
+{
+ int rc;
+ const char *text;
+ char *fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+
+ switch ((rc = blacklisted_fingerprint(fp))) {
+ case BLACKLIST_ERROR_NONE:
+ break;
+ case BLACKLIST_ERROR_ALL:
+ text = (options.ignore_blacklist_errors == rc) ?
+ "Permitted" : "Rejected";
+ if (hostkey)
+ logit("%s blacklisted host key %s", text, fp);
+ else
+ logit("%s blacklisted public key %s from %.100s",
+ text, fp, get_remote_ipaddr());
+ break;
+ default:
+ if (hostkey)
+ logit("Unable to check blacklist for host key %s",
+ fp);
+ else
+ logit("Unable to check blacklist for public key %s from %.100s",
+ fp, get_remote_ipaddr());
+ }
+
+ xfree(fp);
+ return (rc > options.ignore_blacklist_errors);
+}
diff --git a/blacklist.h b/blacklist.h
new file mode 100644
index 0000000..853ede1
--- /dev/null
+++ b/blacklist.h
@@ -0,0 +1,37 @@
+/*
+ * Support for RSA/DSA key blacklisting based on partial fingerprints,
+ * developed under Openwall Project for Owl - http://www.openwall.com/Owl/
+ *
+ * Copyright (c) 2008 Dmitry V. Levin <ldv at cvs.openwall.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BLACKLIST_H_
+#define BLACKLIST_H_
+
+#include "key.h"
+
+int blacklisted_key(Key *, int);
+
+typedef enum
+{
+ BLACKLIST_ERROR_NONE = 0,
+ BLACKLIST_ERROR_MISSING,
+ BLACKLIST_ERROR_VERSION,
+ BLACKLIST_ERROR_FORMAT,
+ BLACKLIST_ERROR_ACCESS,
+ BLACKLIST_ERROR_ALL
+} blacklist_error_t;
+
+#endif /* BLACKLIST_H_ */
diff --git a/channels.c b/channels.c
index 24d4a9f..088f17b 100644
--- a/channels.c
+++ b/channels.c
@@ -2879,6 +2879,8 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
packet_write_wait();
/* Assume that server accepts the request */
success = 1;
+ debug("Forward request from remote address %s:%u to local address %s:%u succeded.",
+ address_to_bind, listen_port, host_to_connect, port_to_connect);
} else {
packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
packet_put_int(listen_port);
@@ -2892,8 +2894,12 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
switch (type) {
case SSH_SMSG_SUCCESS:
success = 1;
+ debug("Forward request from remote port %u to local address %s:%u succeded.",
+ listen_port, host_to_connect, port_to_connect);
break;
case SSH_SMSG_FAILURE:
+ debug("Forward request from remote port %u to local address %s:%u failed.",
+ listen_port, host_to_connect, port_to_connect);
break;
default:
/* Unknown packet */
diff --git a/configure.ac b/configure.ac
index 7a91527..1f92a39 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2168,7 +2168,7 @@ AC_LINK_IFELSE(
]
)
-AC_CHECK_FUNCS([RSA_generate_key_ex DSA_generate_parameters_ex BN_is_prime_ex RSA_get_default_method])
+AC_CHECK_FUNCS([RSA_generate_key_ex DSA_generate_parameters_ex dsa_builtin_paramgen BN_is_prime_ex RSA_get_default_method])
AC_ARG_WITH([ssl-engine],
[ --with-ssl-engine Enable OpenSSL (hardware) ENGINE support ],
@@ -3379,7 +3379,7 @@ AC_ARG_WITH([kerberos5],
[ --with-kerberos5=PATH Enable Kerberos 5 support],
[ if test "x$withval" != "xno" ; then
if test "x$withval" = "xyes" ; then
- KRB5ROOT="/usr/local"
+ KRB5ROOT="/usr"
else
KRB5ROOT=${withval}
fi
@@ -3403,8 +3403,8 @@ AC_ARG_WITH([kerberos5],
AC_MSG_RESULT([no])
k5confopts=""
fi
- K5CFLAGS="`$KRB5CONF --cflags $k5confopts`"
- K5LIBS="`$KRB5CONF --libs $k5confopts`"
+ K5CFLAGS="`env -i $KRB5CONF --cflags $k5confopts`"
+ K5LIBS="`env -i $KRB5CONF --libs $k5confopts`"
CPPFLAGS="$CPPFLAGS $K5CFLAGS"
AC_MSG_CHECKING([whether we are using Heimdal])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <krb5.h>
diff --git a/entropy.c b/entropy.c
index 2d6d3ec..fe241a9 100644
--- a/entropy.c
+++ b/entropy.c
@@ -211,9 +211,9 @@ seed_rng(void)
#endif
/*
* OpenSSL version numbers: MNNFFPPS: major minor fix patch status
- * We match major, minor, fix and status (not patch)
+ * We match major and minor (but not fix, patch and status)
*/
- if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L)
+ if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xfffffL)
fatal("OpenSSL version mismatch. Built against %lx, you "
"have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
diff --git a/key.c b/key.c
index 498cf5a..73ea8e9 100644
--- a/key.c
+++ b/key.c
@@ -1035,9 +1035,19 @@ dsa_generate_private_key(u_int bits)
if (private == NULL)
fatal("%s: DSA_new failed", __func__);
+#ifdef HAVE_DSA_BUILTIN_PARAMGEN
+ extern int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits,
+ const EVP_MD *evpmd, const unsigned char *seed_in, size_t seed_len,
+ unsigned char *seed_out,
+ int *counter_ret, unsigned long *h_ret, BN_GENCB *cb);
+ if (!dsa_builtin_paramgen(private, bits, 160, EVP_sha1(),
+ NULL, 0, NULL, NULL, NULL, NULL))
+ fatal("%s: dsa_builtin_paramgen failed", __func__);
+#else
if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
NULL, NULL))
fatal("%s: DSA_generate_parameters failed", __func__);
+#endif
if (!DSA_generate_key(private))
fatal("%s: DSA_generate_key failed.", __func__);
return private;
diff --git a/log.c b/log.c
index ad5a10b..c2dad03 100644
--- a/log.c
+++ b/log.c
@@ -54,7 +54,11 @@
static LogLevel log_level = SYSLOG_LEVEL_INFO;
static int log_on_stderr = 1;
+#ifdef LOG_AUTHPRIV
+static int log_facility = LOG_AUTHPRIV;
+#else
static int log_facility = LOG_AUTH;
+#endif
static char *argv0;
static log_handler_fn *log_handler;
static void *log_handler_ctx;
@@ -368,11 +372,15 @@ do_log(LogLevel level, const char *fmt, va_list args)
case SYSLOG_LEVEL_FATAL:
if (!log_on_stderr)
txt = "fatal";
+ else
+ txt = __progname;
pri = LOG_CRIT;
break;
case SYSLOG_LEVEL_ERROR:
if (!log_on_stderr)
txt = "error";
+ else
+ txt = __progname;
pri = LOG_ERR;
break;
case SYSLOG_LEVEL_INFO:
diff --git a/monitor.c b/monitor.c
index a166fed..d51d16e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -742,7 +742,7 @@ mm_answer_pwnamallow(int sock, Buffer *m)
pwent = getpwnamallow(username);
authctxt->user = xstrdup(username);
- setproctitle("%s [priv]", pwent ? username : "unknown");
+ setproctitle("%s [priv]", pwent ? username : "UNKNOWN USER");
xfree(username);
buffer_clear(m);
@@ -1136,7 +1136,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
switch (type) {
case MM_USERKEY:
allowed = options.pubkey_authentication &&
- user_key_allowed(authctxt->pw, key);
+ user_key_allowed(authctxt, key);
auth_method = "publickey";
if (options.pubkey_authentication && allowed != 1)
auth_clear_options();
diff --git a/monitor_mm.c b/monitor_mm.c
index faf9f3d..1048011 100644
--- a/monitor_mm.c
+++ b/monitor_mm.c
@@ -139,6 +139,7 @@ mm_destroy(struct mm_master *mm)
mm_freelist(mm->mmalloc, &mm->rb_allocated);
#ifdef HAVE_MMAP
+ memset(mm->address, 0xd0, mm->size);
if (munmap(mm->address, mm->size) == -1)
fatal("munmap(%p, %lu): %s", mm->address, (u_long)mm->size,
strerror(errno));
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 1f60658..3962a04 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -362,7 +362,7 @@ mm_auth_password(Authctxt *authctxt, char *password)
}
int
-mm_user_key_allowed(struct passwd *pw, Key *key)
+mm_user_key_allowed(Authctxt *authctxt, Key *key)
{
return (mm_key_allowed(MM_USERKEY, NULL, NULL, key));
}
@@ -480,7 +480,7 @@ mm_newkeys_from_blob(u_char *blob, int blen)
buffer_init(&b);
buffer_append(&b, blob, blen);
- newkey = xmalloc(sizeof(*newkey));
+ newkey = xcalloc(1, sizeof(*newkey));
enc = &newkey->enc;
mac = &newkey->mac;
comp = &newkey->comp;
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 0c7f2e3..4672ca9 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -46,7 +46,7 @@ struct passwd *mm_getpwnamallow(const char *);
char *mm_auth2_read_banner(void);
int mm_auth_password(struct Authctxt *, char *);
int mm_key_allowed(enum mm_keytype, char *, char *, Key *);
-int mm_user_key_allowed(struct passwd *, Key *);
+int mm_user_key_allowed(struct Authctxt *, Key *);
int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *);
int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
diff --git a/mux.c b/mux.c
index add0e26..36cc1ba 100644
--- a/mux.c
+++ b/mux.c
@@ -420,7 +420,8 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
- if (!ask_permission("Allow shared connection to %s? ", host)) {
+ if (!ask_permission("Allow shared connection to %s,\n"
+ "requested by \"%s\"? ", host, getpeerproc(c->sock))) {
debug2("%s: session refused by user", __func__);
/* prepare reply */
buffer_put_int(r, MUX_S_PERMISSION_DENIED);
@@ -495,8 +496,8 @@ process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
- if (!ask_permission("Terminate shared connection to %s? ",
- host)) {
+ if (!ask_permission("Terminate shared connection to %s,\n"
+ "requested by \"%s\"? ", host, getpeerproc(c->sock))) {
debug2("%s: termination refused by user", __func__);
buffer_put_int(r, MUX_S_PERMISSION_DENIED);
buffer_put_int(r, rid);
@@ -720,7 +721,8 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
- if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
+ if (!ask_permission("Open %s on %s,\nrequested by \"%s\"? ",
+ fwd_desc, host, getpeerproc(c->sock))) {
debug2("%s: forwarding refused by user", __func__);
buffer_put_int(r, MUX_S_PERMISSION_DENIED);
buffer_put_int(r, rid);
@@ -882,8 +884,9 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
- if (!ask_permission("Allow forward to %s:%u? ",
- chost, cport)) {
+ if (!ask_permission("Allow forward to %s:%u,\n"
+ "requested by \"%s\"? ",
+ chost, cport, getpeerproc(c->sock))) {
debug2("%s: stdio fwd refused by user", __func__);
/* prepare reply */
buffer_put_int(r, MUX_S_PERMISSION_DENIED);
@@ -926,7 +929,8 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Disable further multiplexing on shared "
- "connection to %s? ", host)) {
+ "connection to %s,\nrequested by \"%s\"? ",
+ host, getpeerproc(c->sock))) {
debug2("%s: stop listen refused by user", __func__);
buffer_put_int(r, MUX_S_PERMISSION_DENIED);
buffer_put_int(r, rid);
diff --git a/myproposal.h b/myproposal.h
index 0bc1c77..6a0bae1 100644
--- a/myproposal.h
+++ b/myproposal.h
@@ -71,10 +71,11 @@
"ssh-dss"
#define KEX_DEFAULT_ENCRYPT \
- "aes128-ctr,aes192-ctr,aes256-ctr," \
+ "aes256-ctr,aes192-ctr,aes128-ctr," \
"arcfour256,arcfour128," \
- "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \
- "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se"
+ "blowfish-cbc,aes256-cbc,aes192-cbc," \
+ "aes128-cbc,3des-cbc,cast128-cbc," \
+ "arcfour,rijndael-cbc@lysator.liu.se"
#ifdef HAVE_EVP_SHA256
#define SHA2_HMAC_MODES \
"hmac-sha2-256," \
diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
index 41b22d8..e370189 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -18,7 +18,7 @@ LDFLAGS=-L. @LDFLAGS@
OPENBSD=base64.o basename.o bindresvport.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o timingsafe_bcmp.o vis.o
-COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o getpeerproc.o openssl-compat.o xmmap.o xcrypt.o
PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
diff --git a/openbsd-compat/getopt.c b/openbsd-compat/getopt.c
index 5450e43..da8cae3 100644
--- a/openbsd-compat/getopt.c
+++ b/openbsd-compat/getopt.c
@@ -91,7 +91,7 @@ BSDgetopt(nargc, nargv, ostr)
++BSDoptind;
if (BSDopterr && *ostr != ':')
(void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname, BSDoptopt);
+ "%s: invalid option -- %c\n", __progname, BSDoptopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
diff --git a/openbsd-compat/getpeerproc.c b/openbsd-compat/getpeerproc.c
new file mode 100644
index 0000000..2f122c2
--- /dev/null
+++ b/openbsd-compat/getpeerproc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2002,2004 Damien Miller <djm@mindrot.org>
+ * Copyright (c) 2007 Dmitry V. Levin <ldv@altlinux.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include "xmalloc.h"
+
+static pid_t
+getpeerpid(int s)
+{
+#if defined(SO_PEERCRED)
+ struct ucred cred;
+ socklen_t len = sizeof(cred);
+
+ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
+ return -1;
+
+ return cred.pid;
+#else
+ return 0;
+#endif /* defined(SO_PEERCRED) */
+}
+
+const char *
+getpeerproc(int s)
+{
+ pid_t pid;
+ int len, fd, i;
+ char path[80];
+ static char line[80];
+
+ if (!(pid = getpeerpid(s)))
+ return "<unknown>";
+
+ len = snprintf(path, sizeof(path), "/proc/%u/cmdline", (unsigned)pid);
+ if (len < 0 || (size_t)len > sizeof(path) ||
+ (fd = open(path, O_RDONLY)) < 0)
+ return "<unknown>";
+
+ if ((len = read(fd, line, sizeof(line) - 1)) > 0)
+ {
+ for (i = 0; i < len; ++i)
+ if (isspace(line[i]) || !isprint(line[i]))
+ line[i] = ' ';
+ if (line[len - 1] == ' ')
+ line[len - 1] = '\0';
+ else
+ line[len] = '\0';
+ }
+
+ close(fd);
+
+ return (len > 0) ? line : "<unknown>";
+}
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index 77c5ed2..ede06af 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -217,6 +217,8 @@ char *group_from_gid(gid_t, int);
int timingsafe_bcmp(const void *, const void *, size_t);
#endif
+const char *getpeerproc(int);
+
void *xmmap(size_t size);
char *xcrypt(const char *password, const char *salt);
char *shadow_pw(struct passwd *pw);
diff --git a/openbsd-compat/xmmap.c b/openbsd-compat/xmmap.c
index 04c6bab..e88fd23 100644
--- a/openbsd-compat/xmmap.c
+++ b/openbsd-compat/xmmap.c
@@ -70,7 +70,9 @@ xmmap(size_t size)
if (tmpfd == -1)
fatal("mkstemp(\"%s\"): %s",
MM_SWAP_TEMPLATE, strerror(errno));
- unlink(tmpname);
+ if (unlink(tmpname))
+ fatal("unlink(\"%s\"): %s",
+ tmpname, strerror(errno));
if (ftruncate(tmpfd, size) != 0)
fatal("%s: ftruncate: %s", __func__, strerror(errno));
address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED,
diff --git a/packet.c b/packet.c
index ba93417..e753308 100644
--- a/packet.c
+++ b/packet.c
@@ -252,7 +252,7 @@ packet_set_timeout(int timeout, int count)
active_state->packet_timeout_ms = timeout * count * 1000;
}
-static void
+static void __attribute__((noreturn))
packet_stop_discard(void)
{
if (active_state->packet_discard_mac) {
diff --git a/packet.h b/packet.h
index 90eec17..58f1f42 100644
--- a/packet.h
+++ b/packet.h
@@ -72,7 +72,7 @@ void *packet_get_raw(u_int *length_ptr);
void *packet_get_string(u_int *length_ptr);
char *packet_get_cstring(u_int *length_ptr);
void *packet_get_string_ptr(u_int *length_ptr);
-void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2),noreturn));
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void set_newkeys(int mode);
diff --git a/pathnames.h b/pathnames.h
index c3d9abf..daf0ead 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -44,6 +44,8 @@
/* Backwards compatibility */
#define _PATH_DH_PRIMES SSHDIR "/primes"
+#define _PATH_BLACKLIST SSHDIR "/blacklist"
+
#ifndef _PATH_SSH_PROGRAM
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
#endif
@@ -94,9 +96,11 @@
* may need to be world-readable. (This file is read by the daemon which is
* running as root.)
*/
+#define _PATH_SSH_SYSTEM_PERMITTED_KEYS SSHDIR "/authorized_keys/%u"
#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
/* backward compat for protocol v2 */
+#define _PATH_SSH_SYSTEM_PERMITTED_KEYS2 SSHDIR "/authorized_keys2/%u"
#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
diff --git a/progressmeter.c b/progressmeter.c
index 0f95222..fe0b521 100644
--- a/progressmeter.c
+++ b/progressmeter.c
@@ -44,7 +44,7 @@
#define MAX_WINSIZE 512
#define PADDING 1 /* padding between the progress indicators */
#define UPDATE_INTERVAL 1 /* update the progress meter every second */
-#define STALL_TIME 5 /* we're stalled after this many seconds */
+#define STALL_TIME 60 /* we're stalled after this many seconds */
/* determines whether we can output to the terminal */
static int can_output(void);
diff --git a/readconf.c b/readconf.c
index 91dfa56..f5963d7 100644
--- a/readconf.c
+++ b/readconf.c
@@ -99,8 +99,8 @@
ForwardX11 no
PasswordAuthentication yes
RSAAuthentication yes
- RhostsRSAAuthentication yes
- StrictHostKeyChecking yes
+ RhostsRSAAuthentication no
+ StrictHostKeyChecking ask
TcpKeepAlive no
IdentityFile ~/.ssh/identity
Port 22
@@ -1235,7 +1235,7 @@ fill_default_options(Options * options)
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->challenge_response_authentication == -1)
- options->challenge_response_authentication = 1;
+ options->challenge_response_authentication = 0;
if (options->gss_authentication == -1)
options->gss_authentication = 0;
if (options->gss_deleg_creds == -1)
diff --git a/schnorr.c b/schnorr.c
index 4d54d68..fbd008d 100644
--- a/schnorr.c
+++ b/schnorr.c
@@ -489,9 +489,9 @@ debug3_bn(const BIGNUM *n, const char *fmt, ...)
char *out, *h;
va_list args;
- out = NULL;
va_start(args, fmt);
- vasprintf(&out, fmt, args);
+ if (vasprintf(&out, fmt, args) < 0)
+ out = NULL;
va_end(args);
if (out == NULL)
fatal("%s: vasprintf failed", __func__);
@@ -514,9 +514,9 @@ debug3_buf(const u_char *buf, u_int len, const char *fmt, ...)
u_int i, j;
va_list args;
- out = NULL;
va_start(args, fmt);
- vasprintf(&out, fmt, args);
+ if (vasprintf(&out, fmt, args) < 0)
+ out = NULL;
va_end(args);
if (out == NULL)
fatal("%s: vasprintf failed", __func__);
diff --git a/scp.c b/scp.c
index 18b2597..54724c6 100644
--- a/scp.c
+++ b/scp.c
@@ -150,7 +150,7 @@ char *ssh_program = _PATH_SSH_PROGRAM;
/* This is used to store the pid of ssh_program */
pid_t do_cmd_pid = -1;
-static void
+static void __attribute__((noreturn))
killchild(int signo)
{
if (do_cmd_pid > 1) {
@@ -344,7 +344,7 @@ typedef struct {
} BUF;
BUF *allocbuf(BUF *, int, int);
-void lostconn(int);
+void lostconn(int) __attribute__((noreturn));
int okname(char *);
void run_err(const char *,...);
void verifydir(char *);
@@ -363,7 +363,7 @@ void sink(int, char *[]);
void source(int, char *[]);
void tolocal(int, char *[]);
void toremote(char *, int, char *[]);
-void usage(void);
+void usage(void) __attribute__((noreturn));
int
main(int argc, char **argv)
diff --git a/servconf.c b/servconf.c
index 91986e5..98949e0 100644
--- a/servconf.c
+++ b/servconf.c
@@ -45,6 +45,7 @@
#include "match.h"
#include "channels.h"
#include "groupaccess.h"
+#include "blacklist.h"
static void add_listen_addr(ServerOptions *, char *, int);
static void add_one_listen_addr(ServerOptions *, char *, int);
@@ -101,6 +102,7 @@ initialize_server_options(ServerOptions *options)
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->challenge_response_authentication = -1;
+ options->ignore_blacklist_errors = -1;
options->permit_empty_passwd = -1;
options->permit_user_env = -1;
options->use_login = -1;
@@ -145,7 +147,7 @@ fill_default_server_options(ServerOptions *options)
{
/* Portable-specific options */
if (options->use_pam == -1)
- options->use_pam = 0;
+ options->use_pam = 1;
/* Standard Options */
if (options->protocol == SSH_PROTO_UNKNOWN)
@@ -180,7 +182,7 @@ fill_default_server_options(ServerOptions *options)
if (options->key_regeneration_time == -1)
options->key_regeneration_time = 3600;
if (options->permit_root_login == PERMIT_NOT_SET)
- options->permit_root_login = PERMIT_YES;
+ options->permit_root_login = PERMIT_NO_PASSWD;
if (options->ignore_rhosts == -1)
options->ignore_rhosts = 1;
if (options->ignore_user_known_hosts == -1)
@@ -190,7 +192,7 @@ fill_default_server_options(ServerOptions *options)
if (options->print_lastlog == -1)
options->print_lastlog = 1;
if (options->x11_forwarding == -1)
- options->x11_forwarding = 0;
+ options->x11_forwarding = 1;
if (options->x11_display_offset == -1)
options->x11_display_offset = 10;
if (options->x11_use_localhost == -1)
@@ -232,7 +234,9 @@ fill_default_server_options(ServerOptions *options)
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0;
if (options->challenge_response_authentication == -1)
- options->challenge_response_authentication = 1;
+ options->challenge_response_authentication = 0;
+ if (options->ignore_blacklist_errors == -1)
+ options->ignore_blacklist_errors = BLACKLIST_ERROR_VERSION;
if (options->permit_empty_passwd == -1)
options->permit_empty_passwd = 0;
if (options->permit_user_env == -1)
@@ -248,11 +252,13 @@ fill_default_server_options(ServerOptions *options)
if (options->gateway_ports == -1)
options->gateway_ports = 0;
if (options->max_startups == -1)
- options->max_startups = 10;
+ options->max_startups = 20;
if (options->max_startups_rate == -1)
- options->max_startups_rate = 100; /* 100% */
+ options->max_startups_rate = 30; /* 30% */
if (options->max_startups_begin == -1)
- options->max_startups_begin = options->max_startups;
+ options->max_startups_begin =
+ (options->max_startups_rate >= 100) ?
+ options->max_startups : options->max_startups/2;
if (options->max_authtries == -1)
options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
if (options->max_sessions == -1)
@@ -265,6 +271,10 @@ fill_default_server_options(ServerOptions *options)
options->client_alive_count_max = 3;
if (options->num_authkeys_files == 0) {
options->authorized_keys_files[options->num_authkeys_files++] =
+ xstrdup(_PATH_SSH_SYSTEM_PERMITTED_KEYS);
+ options->authorized_keys_files[options->num_authkeys_files++] =
+ xstrdup(_PATH_SSH_SYSTEM_PERMITTED_KEYS2);
+ options->authorized_keys_files[options->num_authkeys_files++] =
xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
options->authorized_keys_files[options->num_authkeys_files++] =
xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
@@ -280,7 +290,7 @@ fill_default_server_options(ServerOptions *options)
/* Turn privilege separation on by default */
if (use_privsep == -1)
- use_privsep = PRIVSEP_ON;
+ use_privsep = PRIVSEP_SANDBOX;
#ifndef HAVE_MMAP
if (use_privsep && options->compression == 1) {
@@ -309,7 +319,7 @@ typedef enum {
sListenAddress, sAddressFamily,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
- sStrictModes, sEmptyPasswd, sTCPKeepAlive,
+ sStrictModes, sIgnoreBlacklistErrors, sEmptyPasswd, sTCPKeepAlive,
sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
@@ -407,6 +417,7 @@ static struct {
{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
+ { "ignoreblacklisterrors", sIgnoreBlacklistErrors, SSHCFG_GLOBAL },
{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
{ "uselogin", sUseLogin, SSHCFG_GLOBAL },
@@ -435,6 +446,8 @@ static struct {
{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
+ { "authorizedkeyssystemfile", sDeprecated, SSHCFG_ALL },
+ { "authorizedkeyssystemfile2", sDeprecated, SSHCFG_ALL },
{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
{ "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
@@ -1014,6 +1027,32 @@ process_server_config_line(ServerOptions *options, char *line,
intptr = &options->tcp_keep_alive;
goto parse_flag;
+ case sIgnoreBlacklistErrors:
+ intptr = &options->ignore_blacklist_errors;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing none/missing/version/format/access/all argument.",
+ filename, linenum);
+ value = 0; /* silence compiler */
+ if (strcmp(arg, "none") == 0)
+ value = BLACKLIST_ERROR_NONE;
+ else if (strcmp(arg, "missing") == 0)
+ value = BLACKLIST_ERROR_MISSING;
+ else if (strcmp(arg, "version") == 0)
+ value = BLACKLIST_ERROR_VERSION;
+ else if (strcmp(arg, "format") == 0)
+ value = BLACKLIST_ERROR_FORMAT;
+ else if (strcmp(arg, "access") == 0)
+ value = BLACKLIST_ERROR_ACCESS;
+ else if (strcmp(arg, "all") == 0)
+ value = BLACKLIST_ERROR_ALL;
+ else
+ fatal("%s line %d: Bad none/missing/version/format/access/all argument: %s",
+ filename, linenum, arg);
+ if (*activep && *intptr == -1)
+ *intptr = value;
+ break;
+
case sEmptyPasswd:
intptr = &options->permit_empty_passwd;
goto parse_flag;
@@ -1211,10 +1250,10 @@ process_server_config_line(ServerOptions *options, char *line,
options->max_startups ||
options->max_startups_rate > 100 ||
options->max_startups_rate < 1)
- fatal("%s line %d: Illegal MaxStartups spec.",
+ fatal("%s line %d: Invalid MaxStartups spec.",
filename, linenum);
} else if (n != 1)
- fatal("%s line %d: Illegal MaxStartups spec.",
+ fatal("%s line %d: Invalid MaxStartups spec.",
filename, linenum);
else
options->max_startups = options->max_startups_begin;
diff --git a/servconf.h b/servconf.h
index 89f38e2..427ab7d 100644
--- a/servconf.h
+++ b/servconf.h
@@ -110,6 +110,7 @@ typedef struct {
int challenge_response_authentication;
int zero_knowledge_password_authentication;
/* If true, permit jpake auth */
+ int ignore_blacklist_errors; /* none/missing/version/format/access/all */
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int permit_user_env; /* If true, read ~/.ssh/environment */
diff --git a/session.c b/session.c
index 6a70400..bc45324 100644
--- a/session.c
+++ b/session.c
@@ -120,7 +120,7 @@ void do_login(Session *, const char *);
#ifdef LOGIN_NEEDS_UTMPX
static void do_pre_login(Session *s);
#endif
-void do_child(Session *, const char *);
+void do_child(Session *, const char *) __attribute__((noreturn));
void do_motd(void);
int check_quietlogin(Session *, const char *);
@@ -1273,6 +1273,9 @@ do_setup_env(Session *s, const char *shell)
child_set_env(&env, &envsize, "KRB5CCNAME",
s->authctxt->krb5_ccname);
#endif
+ if (s->authctxt->key_fingerprint)
+ child_set_env(&env, &envsize, "SSH_KEY_FINGERPRINT",
+ s->authctxt->key_fingerprint);
#ifdef USE_PAM
/*
* Pull in any environment variables that may have
diff --git a/sftp-glob.c b/sftp-glob.c
index cdc2708..bc19862 100644
--- a/sftp-glob.c
+++ b/sftp-glob.c
@@ -145,5 +145,5 @@ remote_glob(struct sftp_conn *conn, const char *pattern, int flags,
memset(&cur, 0, sizeof(cur));
cur.conn = conn;
- return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob));
+ return(glob(pattern, flags | GLOB_ALTDIRFUNC | GLOB_LIMIT, errfunc, pglob));
}
diff --git a/sftp-server.8 b/sftp-server.8
index bb19c15..f33d90c 100644
--- a/sftp-server.8
+++ b/sftp-server.8
@@ -63,9 +63,9 @@ to print logging information to stderr instead of syslog for debugging.
.It Fl f Ar log_facility
Specifies the facility code that is used when logging messages from
.Nm .
-The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
+The possible values are: DAEMON, USER, AUTH, AUTHPRIV, LOCAL0, LOCAL1, LOCAL2,
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
-The default is AUTH.
+The default is AUTHPRIV.
.It Fl h
Displays
.Nm
diff --git a/sftp-server.c b/sftp-server.c
index 9d01c7d..a8cc10d 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1401,7 +1401,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
fd_set *rset, *wset;
int in, out, max, ch, skipargs = 0, log_stderr = 0;
ssize_t len, olen, set_size;
+#ifdef LOG_AUTHPRIV
+ SyslogFacility log_facility = SYSLOG_FACILITY_AUTHPRIV;
+#else
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
+#endif
char *cp, buf[4*4096];
long mask;
diff --git a/sftp.c b/sftp.c
index ab667f5..f8a710c 100644
--- a/sftp.c
+++ b/sftp.c
@@ -201,7 +201,7 @@ static const struct CMD cmds[] = {
int interactive_loop(struct sftp_conn *, char *file1, char *file2);
/* ARGSUSED */
-static void
+static void __attribute__((noreturn))
killchild(int signo)
{
if (sshpid > 1) {
@@ -1707,7 +1707,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
tmp = make_absolute(tmp, remote_path);
remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
} else
- glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
+ glob(tmp, GLOB_DOOFFS|GLOB_LIMIT|GLOB_MARK, NULL, &g);
/* Determine length of pwd so we can trim completion display */
for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
@@ -2060,7 +2060,7 @@ connect_to_server(char *path, char **args, int *in, int *out)
close(c_out);
}
-static void
+static void __attribute__((noreturn))
usage(void)
{
extern char *__progname;
diff --git a/ssh-agent.1 b/ssh-agent.1
index bb801c9..fd5aec0 100644
--- a/ssh-agent.1
+++ b/ssh-agent.1
@@ -43,6 +43,7 @@
.Sh SYNOPSIS
.Nm ssh-agent
.Op Fl c | s
+.Op Fl u
.Op Fl d
.Op Fl a Ar bind_address
.Op Fl t Ar life
@@ -79,6 +80,8 @@ Generate C-shell commands on
This is the default if
.Ev SHELL
looks like it's a csh style of shell.
+.It Fl u
+Run the agent in unique mode.
.It Fl d
Debug mode.
When this option is specified
@@ -183,16 +186,18 @@ environment variable holds the agent's process ID.
The agent exits automatically when the command given on the command
line terminates.
.Sh FILES
-.Bl -tag -width Ds
+.Bl -tag -width Ds -compact
.It Pa ~/.ssh/identity
Contains the protocol version 1 RSA authentication identity of the user.
+.Pp
.It Pa ~/.ssh/id_dsa
Contains the protocol version 2 DSA authentication identity of the user.
.It Pa ~/.ssh/id_ecdsa
Contains the protocol version 2 ECDSA authentication identity of the user.
.It Pa ~/.ssh/id_rsa
Contains the protocol version 2 RSA authentication identity of the user.
-.It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt
+.It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt ,
+.It Pa ~/.ssh/agent
.Ux Ns -domain
sockets used to contain the connection to the authentication agent.
These sockets should only be readable by the owner.
diff --git a/ssh-agent.c b/ssh-agent.c
index b9498e6..b9ac403 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -194,14 +194,14 @@ lookup_identity(Key *key, int version)
/* Check confirmation of keysign request */
static int
-confirm_key(Identity *id)
+confirm_key(Identity *id, const char *proc)
{
char *p;
int ret = -1;
p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
- if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
- id->comment, p))
+ if (ask_permission("Allow use of key %s?\nKey fingerprint %s.\n"
+ "Request from \"%s\".", id->comment, p, proc))
ret = 0;
xfree(p);
@@ -271,7 +271,7 @@ process_authentication_challenge1(SocketEntry *e)
goto failure;
id = lookup_identity(key, 1);
- if (id != NULL && (!id->confirm || confirm_key(id) == 0)) {
+ if (id != NULL && (!id->confirm || confirm_key(id, getpeerproc(e->fd)) == 0)) {
Key *private = id->key;
/* Decrypt the challenge using the private key. */
if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
@@ -333,7 +333,7 @@ process_sign_request2(SocketEntry *e)
key = key_from_blob(blob, blen);
if (key != NULL) {
Identity *id = lookup_identity(key, 2);
- if (id != NULL && (!id->confirm || confirm_key(id) == 0))
+ if (id != NULL && (!id->confirm || confirm_key(id, getpeerproc(e->fd)) == 0))
ok = key_sign(id->key, &signature, &slen, data, dlen);
key_free(key);
}
@@ -1012,13 +1012,12 @@ after_select(fd_set *readset, fd_set *writeset)
sock = accept(sockets[i].fd,
(struct sockaddr *)&sunaddr, &slen);
if (sock < 0) {
- error("accept from AUTH_SOCKET: %s",
- strerror(errno));
+ error("accept from AUTH_SOCKET: %m");
break;
}
if (getpeereid(sock, &euid, &egid) < 0) {
- error("getpeereid %d failed: %s",
- sock, strerror(errno));
+ error("getpeereid %d failed: %m",
+ sock);
close(sock);
break;
}
@@ -1108,7 +1107,27 @@ check_parent_exists(void)
}
}
-static void
+static int
+check_auth_socket(const char *authsocket)
+{
+ int sock, rc;
+ struct sockaddr_un sunaddr;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ return sock;
+
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
+
+ rc = connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
+ close(sock);
+
+ return rc;
+}
+
+static void __attribute__((noreturn))
usage(void)
{
fprintf(stderr, "usage: %s [options] [command [arg ...]]\n",
@@ -1117,6 +1136,7 @@ usage(void)
fprintf(stderr, " -c Generate C-shell commands on stdout.\n");
fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n");
fprintf(stderr, " -k Kill the current agent.\n");
+ fprintf(stderr, " -u Unique mode.\n");
fprintf(stderr, " -d Debug mode.\n");
fprintf(stderr, " -a socket Bind agent socket to given name.\n");
fprintf(stderr, " -t life Default identity lifetime (seconds).\n");
@@ -1127,6 +1147,7 @@ int
main(int ac, char **av)
{
int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0;
+ int u_flag = 0, already_running = 0;
int sock, fd, ch, result, saved_errno;
u_int nalloc;
char *shell, *format, *pidstr, *agentsocket = NULL;
@@ -1139,7 +1160,6 @@ main(int ac, char **av)
extern int optind;
extern char *optarg;
pid_t pid;
- char pidstrbuf[1 + 3 * sizeof pid];
struct timeval *tvp = NULL;
size_t len;
@@ -1160,7 +1180,7 @@ main(int ac, char **av)
__progname = ssh_get_progname(av[0]);
seed_rng();
- while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
+ while ((ch = getopt(ac, av, "cdksua:t:")) != -1) {
switch (ch) {
case 'c':
if (s_flag)
@@ -1175,6 +1195,9 @@ main(int ac, char **av)
usage();
s_flag++;
break;
+ case 'u':
+ u_flag++;
+ break;
case 'd':
if (d_flag)
usage();
@@ -1196,7 +1219,10 @@ main(int ac, char **av)
ac -= optind;
av += optind;
- if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
+ if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || u_flag))
+ usage();
+
+ if (u_flag && (k_flag || agentsocket))
usage();
if (ac == 0 && !c_flag && !s_flag) {
@@ -1210,20 +1236,16 @@ main(int ac, char **av)
pidstr = getenv(SSH_AGENTPID_ENV_NAME);
if (pidstr == NULL) {
- fprintf(stderr, "%s not set, cannot kill agent\n",
- SSH_AGENTPID_ENV_NAME);
- exit(1);
+ fatal("%s not set, cannot kill agent",
+ SSH_AGENTPID_ENV_NAME);
}
pid = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
if (errstr) {
- fprintf(stderr,
- "%s=\"%s\", which is not a good PID: %s\n",
- SSH_AGENTPID_ENV_NAME, pidstr, errstr);
- exit(1);
+ fatal( "%s=\"%s\", which is not a good PID: %s",
+ SSH_AGENTPID_ENV_NAME, pidstr, errstr);
}
if (kill(pid, SIGTERM) == -1) {
- perror("kill");
- exit(1);
+ fatal("kill: %m");
}
format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME);
@@ -1233,15 +1255,22 @@ main(int ac, char **av)
}
parent_pid = getpid();
- if (agentsocket == NULL) {
+ if (u_flag) {
+ struct passwd *pw = getpwuid(geteuid());
+ if (!pw)
+ fatal("getpwuid: %m");
+ snprintf(socket_name, sizeof socket_name,
+ "%s/.ssh/agent", pw->pw_dir);
+ endpwent();
+ }
+ else if (agentsocket == NULL) {
/* Create private directory for agent socket */
mktemp_proto(socket_dir, sizeof(socket_dir));
if (mkdtemp(socket_dir) == NULL) {
- perror("mkdtemp: private socket dir");
- exit(1);
+ fatal("mkdtemp: private socket dir: %m");
}
- snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
- (long)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';
@@ -1254,7 +1283,7 @@ main(int ac, char **av)
*/
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
- perror("socket");
+ error("socket: %m");
*socket_name = '\0'; /* Don't unlink any existing file */
cleanup_exit(1);
}
@@ -1263,14 +1292,44 @@ main(int ac, char **av)
strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
prev_mask = umask(0177);
if (bind(sock, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) < 0) {
- perror("bind");
- *socket_name = '\0'; /* Don't unlink any existing file */
- umask(prev_mask);
- cleanup_exit(1);
+ int rc = -1;
+
+ if (u_flag && (EADDRINUSE == errno)) {
+ if (check_auth_socket(socket_name) < 0) {
+ (void) unlink(socket_name);
+ rc = bind(sock, (struct sockaddr *) & sunaddr,
+ sizeof(sunaddr));
+ } else {
+ already_running = 1;
+ rc = 0;
+ }
+ }
+ if (rc < 0) {
+ error("bind: %s: %m", socket_name);
+ *socket_name = '\0'; /* Don't unlink any existing file */
+ umask(prev_mask);
+ cleanup_exit(1);
+ }
}
umask(prev_mask);
+
+ if (already_running) {
+ close(sock);
+ 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);
+ exit(0);
+ }
+ if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) < 0) {
+ fatal("setenv: %m");
+ }
+ execvp(av[0], av);
+ fatal("execvp: %s: %m", av[0]);
+ }
+
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
- perror("listen");
+ error("listen: %m");
cleanup_exit(1);
}
@@ -1288,10 +1347,12 @@ main(int ac, char **av)
}
pid = fork();
if (pid == -1) {
- perror("fork");
+ error("fork: %m");
cleanup_exit(1);
}
if (pid != 0) { /* Parent - execute the given command. */
+ char pidstrbuf[1 + 3 * sizeof pid];
+
close(sock);
snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
if (ac == 0) {
@@ -1305,22 +1366,23 @@ main(int ac, char **av)
}
if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
- perror("setenv");
- exit(1);
+ fatal("setenv: %m");
}
execvp(av[0], av);
- perror(av[0]);
- exit(1);
+ fatal("execvp: %s: %m", av[0]);
}
/* child */
log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
if (setsid() == -1) {
- error("setsid: %s", strerror(errno));
+ error("setsid: %m");
cleanup_exit(1);
}
- (void)chdir("/");
+ if (chdir("/") == -1) {
+ error("chdir: %m");
+ cleanup_exit(1);
+ }
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
/* XXX might close listen socket */
(void)dup2(fd, STDIN_FILENO);
@@ -1334,7 +1396,7 @@ main(int ac, char **av)
/* deny core dumps, since memory contains unencrypted private keys */
rlim.rlim_cur = rlim.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
- error("setrlimit RLIMIT_CORE: %s", strerror(errno));
+ error("setrlimit RLIMIT_CORE: %m");
cleanup_exit(1);
}
#endif
@@ -1345,7 +1407,7 @@ skip:
pkcs11_init(0);
#endif
new_socket(AUTH_SOCKET, sock);
- if (ac > 0)
+ if (!u_flag && ac > 0)
parent_alive_interval = 10;
idtab_init();
if (!d_flag)
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index ede3792..38006a3 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -633,6 +633,8 @@ will read this file when a login attempt is made.
Contains the protocol version 1 RSA public key for authentication.
The contents of this file should be added to
.Pa ~/.ssh/authorized_keys
+or
+.Pa /etc/openssh/authorized_keys/
on all machines
where the user wishes to log in using RSA authentication.
There is no need to keep the contents of this file secret.
@@ -657,6 +659,8 @@ will read this file when a login attempt is made.
Contains the protocol version 2 DSA, ECDSA or RSA public key for authentication.
The contents of this file should be added to
.Pa ~/.ssh/authorized_keys
+or
+.Pa /etc/openssh/authorized_keys/
on all machines
where the user wishes to log in using public key authentication.
There is no need to keep the contents of this file secret.
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 4b6218b..7598c2d 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -179,8 +179,8 @@ type_bits_valid(int type, u_int32_t *bitsp)
fprintf(stderr, "key bits exceeds maximum %d\n", maxbits);
exit(1);
}
- if (type == KEY_DSA && *bitsp != 1024)
- fatal("DSA keys must be 1024 bits");
+ if (type == KEY_DSA && *bitsp < 1024)
+ fatal("DSA keys must be at least 1024 bits");
else if (type != KEY_ECDSA && *bitsp < 768)
fatal("Key must at least be 768 bits");
else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1)
@@ -630,7 +630,7 @@ do_convert_from_pem(Key **k, int *private)
fatal("%s: unrecognised raw private key format", __func__);
}
-static void
+static void __attribute__((noreturn))
do_convert_from(struct passwd *pw)
{
Key *k = NULL;
@@ -966,7 +966,7 @@ printhost(FILE *f, const char *name, Key *public, int ca, int hash)
}
}
-static void
+static void __attribute__((noreturn))
do_known_hosts(struct passwd *pw, const char *name)
{
FILE *in, *out = stdout;
@@ -1287,7 +1287,7 @@ do_print_resource_record(struct passwd *pw, char *fname, char *hname)
/*
* Change the comment of a private key file.
*/
-static void
+static void __attribute__((noreturn))
do_change_comment(struct passwd *pw)
{
char new_comment[1024], *comment, *passphrase;
@@ -1861,7 +1861,7 @@ do_show_cert(struct passwd *pw)
exit(0);
}
-static void
+static void __attribute__((noreturn))
usage(void)
{
fprintf(stderr, "usage: %s [options]\n", __progname);
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index b085dd4..70fa110 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -597,7 +597,7 @@ fatal(const char *fmt,...)
exit(255);
}
-static void
+static void __attribute__((noreturn))
usage(void)
{
fprintf(stderr,
@@ -705,11 +705,11 @@ main(int argc, char **argv)
maxfd = fdlim_get(1);
if (maxfd < 0)
- fatal("%s: fdlim_get: bad value", __progname);
+ fatal("fdlim_get: bad value");
if (maxfd > MAXMAXFD)
maxfd = MAXMAXFD;
if (MAXCON <= 0)
- fatal("%s: not enough file descriptors", __progname);
+ fatal("not enough file descriptors");
if (maxfd > fdlim_get(0))
fdlim_set(maxfd);
fdcon = xcalloc(maxfd, sizeof(con));
diff --git a/ssh.1 b/ssh.1
index 9c1ca4b..f6efc31 100644
--- a/ssh.1
+++ b/ssh.1
@@ -167,7 +167,7 @@ that do not support the
cipher.
Its use is strongly discouraged due to cryptographic weaknesses.
The default is
-.Dq 3des .
+.Dq blowfish .
.Pp
For protocol version 2,
.Ar cipher_spec
@@ -736,6 +736,9 @@ contains a brief discussion of the DSA and RSA algorithms.
The file
.Pa ~/.ssh/authorized_keys
lists the public keys that are permitted for logging in.
+Alternatively, public keys list can be stored in
+.Pa /etc/openssh/authorized_keys/%u
+(where %u is the username).
When the user logs in, the
.Nm
program tells the server which key pair it would like to use for
@@ -770,8 +773,10 @@ in the user's home directory.
The user should then copy the public key
to
.Pa ~/.ssh/authorized_keys
-in his/her home directory on the remote machine.
-The
+in his/her home directory on the remote machine, or, alternatively,
+that contents should be added to
+.Pa /etc/openssh/authorized_keys/%u
+on the remote machine. The
.Pa authorized_keys
file corresponds to the conventional
.Pa ~/.rhosts
@@ -804,9 +809,7 @@ text, and prompts for a response.
Protocol 2 allows multiple challenges and responses;
protocol 1 is restricted to just one challenge/response.
Examples of challenge-response authentication include
-BSD Authentication (see
-.Xr login.conf 5 )
-and PAM (some non-OpenBSD systems).
+BSD Authentication and PAM (some non-OpenBSD systems).
.Pp
Finally, if other authentication methods fail,
.Nm
@@ -1292,6 +1295,11 @@ manual page.
This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
.Pp
+.It Pa /etc/openssh/authorized_keys/
+This directory can contain files named with usernames, in the same format as
+.Pa ~/.ssh/authorized_keys
+do.
+.Pp
.It Pa ~/.ssh/config
This is the per-user configuration file.
The file format and configuration options are described in
diff --git a/ssh.c b/ssh.c
index c717dcf..2f32328 100644
--- a/ssh.c
+++ b/ssh.c
@@ -192,7 +192,7 @@ extern u_int muxclient_command;
/* Prints a help message to the user. This function never returns. */
-static void
+static void __attribute__((noreturn))
usage(void)
{
fprintf(stderr,
@@ -311,7 +311,7 @@ main(int ac, char **av)
* writable only by the owner, which is ok for all files for which we
* don't set the modes explicitly.
*/
- umask(022);
+ umask(umask(077) | 022);
/*
* Initialize option structure to indicate that no values have been
@@ -1041,7 +1041,7 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
}
}
-static void
+static void __attribute__((noreturn))
client_cleanup_stdio_fwd(int id, void *arg)
{
debug("stdio forwarding: done");
@@ -1070,11 +1070,8 @@ client_setup_stdio_fwd(const char *host_to_connect, u_short port_to_connect)
}
static void
-ssh_init_forwarding(void)
+ssh_init_stdio_forwarding(void)
{
- int success = 0;
- int i;
-
if (stdio_forward_host != NULL) {
if (!compat20) {
fatal("stdio forwarding require Protocol 2");
@@ -1083,6 +1080,13 @@ ssh_init_forwarding(void)
stdio_forward_port))
fatal("Failed to connect in stdio forward mode.");
}
+}
+
+static void
+ssh_init_forwarding(void)
+{
+ int success = 0;
+ int i;
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
@@ -1271,6 +1275,7 @@ ssh_session(void)
}
/* Initiate port forwardings. */
+ ssh_init_stdio_forwarding();
ssh_init_forwarding();
/* Execute a local command */
@@ -1409,15 +1414,18 @@ ssh_session2(void)
int id = -1;
/* XXX should be pre-session */
+ if (!options.control_persist)
+ ssh_init_stdio_forwarding();
ssh_init_forwarding();
/* Start listening for multiplex clients */
muxserver_listen();
/*
- * If we are in control persist mode, then prepare to background
- * ourselves and have a foreground client attach as a control
- * slave. NB. we must save copies of the flags that we override for
+ * If we are in control persist mode and have a working mux listen
+ * socket, then prepare to background ourselves and have a foreground
+ * client attach as a control slave.
+ * NB. we must save copies of the flags that we override for
* the backgrounding, since we defer attachment of the slave until
* after the connection is fully established (in particular,
* async rfwd replies have been received for ExitOnForwardFailure).
@@ -1434,6 +1442,12 @@ ssh_session2(void)
need_controlpersist_detach = 1;
fork_after_authentication_flag = 1;
}
+ /*
+ * ControlPersist mux listen socket setup failed, attempt the
+ * stdio forward setup that we skipped earlier.
+ */
+ if (options.control_persist && muxserver_sock == -1)
+ ssh_init_stdio_forwarding();
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
id = ssh_session2_open();
diff --git a/ssh_config b/ssh_config
index 1893674..e9963c4 100644
--- a/ssh_config
+++ b/ssh_config
@@ -17,7 +17,11 @@
# list of available options, their meanings and defaults, please see the
# ssh_config(5) man page.
-# Host *
+Host *
+ # Send locale environment variables
+ SendEnv LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE
+ SendEnv LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY
+ SendEnv LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME
# ForwardAgent no
# ForwardX11 no
# RhostsRSAAuthentication no
@@ -36,8 +40,8 @@
# IdentityFile ~/.ssh/id_dsa
# Port 22
# Protocol 2,1
-# Cipher 3des
-# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc
+# Cipher blowfish
+# Ciphers aes256-ctr,arcfour256,blowfish-cbc,aes256-cbc
# MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
# EscapeChar ~
# Tunnel no
diff --git a/ssh_config.5 b/ssh_config.5
index a782d6f..386caeb 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -159,7 +159,7 @@ The argument to this keyword must be
or
.Dq no .
The default is
-.Dq yes .
+.Dq no .
.It Cm CheckHostIP
If this flag is set to
.Dq yes ,
@@ -191,7 +191,7 @@ that do not support the
cipher.
Its use is strongly discouraged due to cryptographic weaknesses.
The default is
-.Dq 3des .
+.Dq blowfish .
.It Cm Ciphers
Specifies the ciphers allowed for protocol version 2
in order of preference.
@@ -212,9 +212,9 @@ and
.Dq cast128-cbc .
The default is:
.Bd -literal -offset 3n
-aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
-aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
-aes256-cbc,arcfour
+aes256-ctr,aes192-ctr,aes128-ctr,arcfour256,arcfour128,
+blowfish-cbc,aes256-cbc,aes192-cbc,aes128-cbc,3des-cbc,
+cast128-cbc,arcfour
.Ed
.It Cm ClearAllForwardings
Specifies that all local, remote, and dynamic port forwardings
@@ -1229,7 +1229,7 @@ Specifies the full pathname of the
.Xr xauth 1
program.
The default is
-.Pa /usr/X11R6/bin/xauth .
+.Pa /usr/bin/xauth .
.El
.Sh PATTERNS
A
diff --git a/sshconnect.c b/sshconnect.c
index 0ee7266..765650e 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -71,7 +71,6 @@ static pid_t proxy_command_pid = 0;
/* import */
extern Options options;
-extern char *__progname;
extern uid_t original_real_uid;
extern uid_t original_effective_uid;
@@ -357,7 +356,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%u", port);
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
- fatal("%s: Could not resolve hostname %.100s: %s", __progname,
+ fatal("Could not resolve hostname %.100s: %s",
host, ssh_gai_strerror(gaierr));
for (attempt = 0; attempt < connection_attempts; attempt++) {
@@ -408,7 +407,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* Return failure if we didn't get a successful connection. */
if (sock == -1) {
- error("ssh: connect to host %s port %s: %s",
+ error("connect to host %s port %s: %s",
host, strport, strerror(errno));
return (-1);
}
diff --git a/sshconnect1.c b/sshconnect1.c
index fd07bbf..dd82f8d 100644
--- a/sshconnect1.c
+++ b/sshconnect1.c
@@ -483,7 +483,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
BIGNUM *key;
Key *host_key, *server_key;
int bits, rbits;
- int ssh_cipher_default = SSH_CIPHER_3DES;
+ int ssh_cipher_default = SSH_CIPHER_BLOWFISH;
u_char session_key[SSH_SESSION_KEY_LENGTH];
u_char cookie[8];
u_int supported_ciphers;
diff --git a/sshconnect2.c b/sshconnect2.c
index c24b202..396f955 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -278,10 +278,10 @@ struct Authmethod {
};
void input_userauth_success(int, u_int32_t, void *);
-void input_userauth_success_unexpected(int, u_int32_t, void *);
+void input_userauth_success_unexpected(int, u_int32_t, void *) __attribute__((noreturn));
void input_userauth_failure(int, u_int32_t, void *);
void input_userauth_banner(int, u_int32_t, void *);
-void input_userauth_error(int, u_int32_t, void *);
+void input_userauth_error(int, u_int32_t, void *) __attribute__((noreturn));
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 *);
diff --git a/sshd.8 b/sshd.8
index a91be0f..224b4fd 100644
--- a/sshd.8
+++ b/sshd.8
@@ -950,7 +950,6 @@ The content of this file is not sensitive; it can be world-readable.
.Xr ssh-keyscan 1 ,
.Xr chroot 2 ,
.Xr hosts_access 5 ,
-.Xr login.conf 5 ,
.Xr moduli 5 ,
.Xr sshd_config 5 ,
.Xr inetd 8 ,
diff --git a/sshd.c b/sshd.c
index cc10395..afaaec0 100644
--- a/sshd.c
+++ b/sshd.c
@@ -120,6 +120,7 @@
#include "roaming.h"
#include "ssh-sandbox.h"
#include "version.h"
+#include "blacklist.h"
#ifdef LIBWRAP
#include <tcpd.h>
@@ -1175,15 +1176,18 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
}
if (unset_nonblock(*newsock) == -1) {
close(*newsock);
+ *newsock = -1;
continue;
}
if (drop_connection(startups) == 1) {
debug("drop connection #%d", startups);
close(*newsock);
+ *newsock = -1;
continue;
}
if (pipe(startup_p) == -1) {
close(*newsock);
+ *newsock = -1;
continue;
}
@@ -1192,6 +1196,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
error("reexec socketpair: %s",
strerror(errno));
close(*newsock);
+ *newsock = -1;
close(startup_p[0]);
close(startup_p[1]);
continue;
@@ -1290,6 +1295,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
}
close(*newsock);
+ *newsock = -1;
/*
* Ensure that our random state differs
@@ -1480,7 +1486,7 @@ main(int ac, char **av)
break;
}
}
- if (rexeced_flag || inetd_flag)
+ if (rexeced_flag || inetd_flag || test_flag)
rexec_flag = 0;
if (!test_flag && (rexec_flag && (av[0] == NULL || *av[0] != '/')))
fatal("sshd re-exec requires execution with an absolute path");
@@ -1594,6 +1600,11 @@ main(int ac, char **av)
sensitive_data.host_keys[i] = NULL;
continue;
}
+ if (blacklisted_key(key, 1)) {
+ sensitive_data.host_keys[i] = NULL;
+ key_free(key);
+ continue;
+ }
switch (key->type) {
case KEY_RSA1:
sensitive_data.ssh1_host_key = key;
@@ -1774,7 +1785,8 @@ main(int ac, char **av)
/* Chdir to the root directory so that the current disk can be
unmounted if desired. */
- chdir("/");
+ if (chdir("/") == -1)
+ fatal("chdir(\"/\"): %s", strerror(errno));
/* ignore SIGPIPE */
signal(SIGPIPE, SIG_IGN);
@@ -1999,6 +2011,11 @@ main(int ac, char **av)
}
authenticated:
+
+#ifdef HAVE_FCHOWN
+ fchown(newsock, authctxt->pw->pw_uid, authctxt->pw->pw_gid);
+#endif
+
/*
* Cancel the alarm we set to limit the time taken for
* authentication.
diff --git a/sshd_config b/sshd_config
index 473e866..4c7c9eb 100644
--- a/sshd_config
+++ b/sshd_config
@@ -31,13 +31,13 @@
# Logging
# obsoletes QuietMode and FascistLogging
-#SyslogFacility AUTH
+#SyslogFacility AUTHPRIV
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
-#PermitRootLogin yes
+#PermitRootLogin without-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
@@ -45,9 +45,7 @@
#RSAAuthentication yes
#PubkeyAuthentication yes
-# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
-# but this is overridden so installations will only check .ssh/authorized_keys
-AuthorizedKeysFile .ssh/authorized_keys
+#AuthorizedKeysFile /etc/openssh/authorized_keys/%u /etc/openssh/authorized_keys2/%u .ssh/authorized_keys .ssh/authorized_keys2
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
@@ -63,8 +61,8 @@ AuthorizedKeysFile .ssh/authorized_keys
#PasswordAuthentication yes
#PermitEmptyPasswords no
-# Change to no to disable s/key passwords
-#ChallengeResponseAuthentication yes
+# Change to yes to enable s/key passwords
+#ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
@@ -85,26 +83,26 @@ AuthorizedKeysFile .ssh/authorized_keys
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
-#UsePAM no
+#UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
-#X11Forwarding no
+#X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
-#UsePrivilegeSeparation yes
+#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS yes
#PidFile /var/run/sshd.pid
-#MaxStartups 10
+#MaxStartups 10:30:20
#PermitTunnel no
#ChrootDirectory none
@@ -112,10 +110,21 @@ AuthorizedKeysFile .ssh/authorized_keys
#Banner none
# override default of no subsystems
-Subsystem sftp /usr/libexec/sftp-server
+#Subsystem sftp /usr/libexec/sftp-server
+
+#AllowGroups wheel users
+
+# Accept locale environment variables
+AcceptEnv LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE
+AcceptEnv LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY
+AcceptEnv LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME
# Example of overriding settings on a per-user basis
#Match User anoncvs
-# X11Forwarding no
+# X11Forwarding yes
# AllowTcpForwarding no
# ForceCommand cvs server
+#Match Group secured
+# AuthorizedKeysFile /etc/openssh/authorized_keys/%u
+#Match Group !secured,*
+# AuthorizedKeysFile /etc/openssh/authorized_keys/%u .ssh/authorized_keys
diff --git a/sshd_config.5 b/sshd_config.5
index a6c3787..8ba5890 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -170,7 +170,7 @@ is taken to be an absolute path or one relative to the user's home
directory.
Multiple files may be listed, separated by whitespace.
The default is
-.Dq .ssh/authorized_keys .ssh/authorized_keys2 .
+.Dq /etc/openssh/authorized_keys/%u /etc/openssh/authorized_keys2/%u .ssh/authorized_keys .ssh/authorized_keys2 .
.It Cm AuthorizedPrincipalsFile
Specifies a file that lists principal names that are accepted for
certificate authentication.
@@ -206,7 +206,9 @@ Note that
is only used when authentication proceeds using a CA listed in
.Cm TrustedUserCAKeys
and is not consulted for certification authorities trusted via
-.Pa ~/.ssh/authorized_keys ,
+.Pa ~/.ssh/authorized_keys
+or
+.Pa /etc/openssh/authorized_keys/ ,
though the
.Cm principals=
key option offers a similar facility (see
@@ -223,9 +225,9 @@ By default, no banner is displayed.
.It Cm ChallengeResponseAuthentication
Specifies whether challenge-response authentication is allowed (e.g. via
PAM or though authentication styles supported in
-.Xr login.conf 5 )
+.Xr login.conf 5 ).
The default is
-.Dq yes .
+.Dq no .
.It Cm ChrootDirectory
Specifies the pathname of a directory to
.Xr chroot 2
@@ -255,7 +257,7 @@ nodes such as
.Xr stdin 4 ,
.Xr stdout 4 ,
.Xr stderr 4 ,
-.Xr arandom 4
+.Xr urandom 4
and
.Xr tty 4
devices.
@@ -290,9 +292,9 @@ and
.Dq cast128-cbc .
The default is:
.Bd -literal -offset 3n
-aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
-aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
-aes256-cbc,arcfour
+aes256-ctr,aes192-ctr,aes128-ctr,arcfour256,arcfour128,
+blowfish-cbc,aes256-cbc,aes192-cbc,aes128-cbc,3des-cbc,
+cast128-cbc,arcfour
.Ed
.It Cm ClientAliveCountMax
Sets the number of client alive messages (see below) which may be
@@ -716,6 +718,7 @@ Available keywords are
.Cm HostbasedUsesNameFromPacketOnly ,
.Cm KbdInteractiveAuthentication ,
.Cm KerberosAuthentication ,
+.Cm Match ,
.Cm MaxAuthTries ,
.Cm MaxSessions ,
.Cm PasswordAuthentication ,
@@ -745,7 +748,6 @@ SSH daemon.
Additional connections will be dropped until authentication succeeds or the
.Cm LoginGraceTime
expires for a connection.
-The default is 10.
.Pp
Alternatively, random early drop can be enabled by specifying
the three colon separated values
@@ -763,10 +765,45 @@ The probability increases linearly and all connection attempts
are refused if the number of unauthenticated connections reaches
.Dq full
(60).
+.Pp
+The default is 10:30:20.
.It Cm PasswordAuthentication
Specifies whether password authentication is allowed.
The default is
.Dq yes .
+.It Cm IgnoreBlacklistErrors
+Specifies whether
+.Xr sshd 8
+should allow keys recorded in its blacklist of known-compromised keys.
+If
+.Dq all ,
+then attempts to authenticate with compromised keys will be logged
+but accepted.
+If
+.Dq access ,
+then attempts to authenticate with compromised keys will be rejected,
+but blacklist file access errors will be ignored.
+If
+.Dq format ,
+then attempts to authenticate with compromised keys will be rejected, but
+blacklist file access errors due to missing blacklist file or blacklist
+file unrecognized format will be ignored.
+If
+.Dq version ,
+then attempts to authenticate with compromised keys will be rejected, but
+blacklist file access errors due to missing blacklist file or blacklist
+file format version mismatch will be ignored.
+If
+.Dq missing ,
+then attempts to authenticate with compromised keys will be rejected,
+but blacklist file access errors due to missing blacklist file will
+be ignored.
+If
+.Dq none ,
+then attempts to authenticate with compromised keys, or in case of
+any blacklist file access error, will be rejected.
+The default is
+.Dq version .
.It Cm PermitEmptyPasswords
When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings.
@@ -809,7 +846,7 @@ The argument must be
or
.Dq no .
The default is
-.Dq yes .
+.Dq without-password .
.Pp
If this option is set to
.Dq without-password ,
@@ -854,6 +891,8 @@ and
.Cm environment=
options in
.Pa ~/.ssh/authorized_keys
+and
+.Pa /etc/openssh/authorized_keys/
are processed by
.Xr sshd 8 .
The default is
@@ -971,9 +1010,9 @@ Note that this option applies to protocol version 2 only.
.It Cm SyslogFacility
Gives the facility code that is used when logging messages from
.Xr sshd 8 .
-The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
+The possible values are: DAEMON, USER, AUTH, AUTHPRIV, LOCAL0, LOCAL1, LOCAL2,
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
-The default is AUTH.
+The default is AUTHPRIV.
.It Cm TCPKeepAlive
Specifies whether the system should send TCP keepalive messages to the
other side.
@@ -1061,7 +1100,7 @@ is enabled, you will not be able to run
.Xr sshd 8
as a non-root user.
The default is
-.Dq no .
+.Dq yes .
.It Cm UsePrivilegeSeparation
Specifies whether
.Xr sshd 8
@@ -1071,14 +1110,14 @@ After successful authentication, another process will be created that has
the privilege of the authenticated user.
The goal of privilege separation is to prevent privilege
escalation by containing any corruption within the unprivileged processes.
-The default is
-.Dq yes .
If
.Cm UsePrivilegeSeparation
is set to
.Dq sandbox
then the pre-authentication unprivileged process is subject to additional
restrictions.
+The default is
+.Dq sandbox .
.It Cm X11DisplayOffset
Specifies the first display number available for
.Xr sshd 8 Ns 's
@@ -1092,7 +1131,7 @@ The argument must be
or
.Dq no .
The default is
-.Dq no .
+.Dq yes .
.Pp
When X11 forwarding is enabled, there may be additional exposure to
the server and to client displays if the
@@ -1149,7 +1188,7 @@ Specifies the full pathname of the
.Xr xauth 1
program.
The default is
-.Pa /usr/X11R6/bin/xauth .
+.Pa /usr/bin/xauth .
.El
.Sh TIME FORMATS
.Xr sshd 8