Sisyphus repository
Last update: 1 october 2023 | SRPMs: 18631 | Visits: 37836803
en ru br
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


 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
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin