external/openssh: update to 6.8p1.
In preparation for some updates to external/openssh to make it work with
BoringSSL, this change updates the code to a recent version. The current
version (5.9p1) is coming up on four years old now.
* Confirmed that f5c67b478bef9992de9e9ec91ce10af4f6205e0d matches
OpenSSH 5.9p1 exactly (save for the removal of the scard
subdirectory).
* Downloaded openssh-6.8p1.tar.gz (SHA256:
3ff64ce73ee124480b5bf767b9830d7d3c03bbcb6abe716b78f0192c37ce160e)
and verified with PGP signature. (I've verified Damien's key in
person previously.)
* Applied changes between f5c67b478bef9992de9e9ec91ce10af4f6205e0d and
OpenSSH 5.9p1 to 6.8p1 and updated the build as best I can. The
ugliest change is probably the duplication of umac.c to umac128.c
because Android conditionally compiles that file twice. See the
comment in those files.
Change-Id: I63cb07a8118afb5a377f116087a0882914cea486
diff --git a/auth.c b/auth.c
index a15b306..25ed53d 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.94 2011/05/23 03:33:38 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.110 2015/02/25 17:29:38 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -27,7 +27,6 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/param.h>
#include <netinet/in.h>
@@ -50,12 +49,14 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <limits.h>
#include "xmalloc.h"
#include "match.h"
#include "groupaccess.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
@@ -63,7 +64,6 @@
#include "auth-options.h"
#include "canohost.h"
#include "uidswap.h"
-#include "misc.h"
#include "packet.h"
#include "loginrec.h"
#ifdef GSSAPI
@@ -71,6 +71,9 @@
#endif
#include "authfile.h"
#include "monitor_wrap.h"
+#include "authfile.h"
+#include "ssherr.h"
+#include "compat.h"
/* import */
extern ServerOptions options;
@@ -164,17 +167,17 @@
if (stat(shell, &st) != 0) {
logit("User %.100s not allowed because shell %.100s "
"does not exist", pw->pw_name, shell);
- xfree(shell);
+ free(shell);
return 0;
}
if (S_ISREG(st.st_mode) == 0 ||
(st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
logit("User %.100s not allowed because shell %.100s "
"is not executable", pw->pw_name, shell);
- xfree(shell);
+ free(shell);
return 0;
}
- xfree(shell);
+ free(shell);
}
if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
@@ -251,7 +254,25 @@
}
void
-auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
+auth_info(Authctxt *authctxt, const char *fmt, ...)
+{
+ va_list ap;
+ int i;
+
+ free(authctxt->info);
+ authctxt->info = NULL;
+
+ va_start(ap, fmt);
+ i = vasprintf(&authctxt->info, fmt, ap);
+ va_end(ap);
+
+ if (i < 0 || authctxt->info == NULL)
+ fatal("vasprintf failed");
+}
+
+void
+auth_log(Authctxt *authctxt, int authenticated, int partial,
+ const char *method, const char *submethod)
{
void (*authlog) (const char *fmt,...) = verbose;
char *authmsg;
@@ -268,17 +289,24 @@
if (authctxt->postponed)
authmsg = "Postponed";
+ else if (partial)
+ authmsg = "Partial";
else
authmsg = authenticated ? "Accepted" : "Failed";
- authlog("%s %s for %s%.100s from %.200s port %d%s",
+ authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
authmsg,
method,
+ submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
authctxt->valid ? "" : "invalid user ",
authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
- info);
+ compat20 ? "ssh2" : "ssh1",
+ authctxt->info != NULL ? ": " : "",
+ authctxt->info != NULL ? authctxt->info : "");
+ free(authctxt->info);
+ authctxt->info = NULL;
#ifdef CUSTOM_FAILED_LOGIN
if (authenticated == 0 && !authctxt->postponed &&
@@ -299,11 +327,26 @@
#endif
}
+
+void
+auth_maxtries_exceeded(Authctxt *authctxt)
+{
+ error("maximum authentication attempts exceeded for "
+ "%s%.100s from %.200s port %d %s",
+ authctxt->valid ? "" : "invalid user ",
+ authctxt->user,
+ get_remote_ipaddr(),
+ get_remote_port(),
+ compat20 ? "ssh2" : "ssh1");
+ packet_disconnect("Too many authentication failures");
+ /* NOTREACHED */
+}
+
/*
* Check whether root logins are disallowed.
*/
int
-auth_root_allowed(char *method)
+auth_root_allowed(const char *method)
{
switch (options.permit_root_login) {
case PERMIT_YES:
@@ -334,7 +377,7 @@
char *
expand_authorized_keys(const char *filename, struct passwd *pw)
{
- char *file, ret[MAXPATHLEN];
+ char *file, ret[PATH_MAX];
int i;
file = percent_expand(filename, "h", pw->pw_dir,
@@ -350,14 +393,15 @@
i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
if (i < 0 || (size_t)i >= sizeof(ret))
fatal("expand_authorized_keys: path too long");
- xfree(file);
+ free(file);
return (xstrdup(ret));
}
char *
authorized_principals_file(struct passwd *pw)
{
- if (options.authorized_principals_file == NULL)
+ if (options.authorized_principals_file == NULL ||
+ strcasecmp(options.authorized_principals_file, "none") == 0)
return NULL;
return expand_authorized_keys(options.authorized_principals_file, pw);
}
@@ -391,7 +435,7 @@
load_hostkeys(hostkeys, host, user_hostfile);
restore_uid();
}
- xfree(user_hostfile);
+ free(user_hostfile);
}
host_status = check_key_in_hostkeys(hostkeys, key, &found);
if (host_status == HOST_REVOKED)
@@ -408,49 +452,50 @@
return host_status;
}
-
/*
- * Check a given file for security. This is defined as all components
+ * Check a given path for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
- * Takes an open file descriptor, the file name, a uid and and
+ * Takes a file name, its stat information (preferably from fstat() to
+ * avoid races), the uid of the expected owner, their home directory and an
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
-static int
-secure_filename(FILE *f, const char *file, struct passwd *pw,
- char *err, size_t errlen)
+int
+auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
+ uid_t uid, char *err, size_t errlen)
{
- uid_t uid = pw->pw_uid;
- char buf[MAXPATHLEN], homedir[MAXPATHLEN];
+ char buf[PATH_MAX], homedir[PATH_MAX];
char *cp;
int comparehome = 0;
struct stat st;
- if (realpath(file, buf) == NULL) {
- snprintf(err, errlen, "realpath %s failed: %s", file,
+ if (realpath(name, buf) == NULL) {
+ snprintf(err, errlen, "realpath %s failed: %s", name,
strerror(errno));
return -1;
}
- if (realpath(pw->pw_dir, homedir) != NULL)
+ if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
comparehome = 1;
- /* check the open file to avoid races */
- if (fstat(fileno(f), &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != uid) ||
- (st.st_mode & 022) != 0) {
-#ifdef ANDROID
- /* needed to allow root login on android */
+ if (!S_ISREG(stp->st_mode)) {
+ snprintf(err, errlen, "%s is not a regular file", buf);
+ return -1;
+ }
+ if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
+ (stp->st_mode & 022) != 0) {
+#if defined(ANDROID)
+ /* needed to allow root login on Android. */
if (getuid() != 0)
#endif
- {
- snprintf(err, errlen, "bad ownership or modes for file %s",
- buf);
- return -1;
+ {
+ snprintf(err, errlen, "bad ownership or modes for file %s",
+ buf);
+ return -1;
}
}
@@ -462,16 +507,17 @@
}
strlcpy(buf, cp, sizeof(buf));
-#ifndef ANDROID
- /* /data is owned by system user, which causes this check to fail */
+#if !defined(ANDROID)
+ /* /data is owned by system user, which causes this check to fail */
if (stat(buf, &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != uid) ||
+ (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
#endif
+
/* If are past the homedir then we can stop */
if (comparehome && strcmp(homedir, buf) == 0)
break;
@@ -486,6 +532,27 @@
return 0;
}
+/*
+ * Version of secure_path() that accepts an open file descriptor to
+ * avoid races.
+ *
+ * Returns 0 on success and -1 on failure
+ */
+static int
+secure_filename(FILE *f, const char *file, struct passwd *pw,
+ char *err, size_t errlen)
+{
+ struct stat st;
+
+ /* check the open file to avoid races */
+ if (fstat(fileno(f), &st) < 0) {
+ snprintf(err, errlen, "cannot stat file %s: %s",
+ file, strerror(errno));
+ return -1;
+ }
+ return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
+}
+
static FILE *
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
int log_missing, char *file_type)
@@ -552,9 +619,10 @@
#endif
#endif
struct passwd *pw;
+ struct connection_info *ci = get_connection_info(1, options.use_dns);
- parse_server_match_config(&options, user,
- get_canonical_hostname(options.use_dns), get_remote_ipaddr());
+ ci->user = user;
+ parse_server_match_config(&options, ci);
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_setauthdb(user);
@@ -616,29 +684,39 @@
int
auth_key_is_revoked(Key *key)
{
- char *key_fp;
+ char *fp = NULL;
+ int r;
if (options.revoked_keys_file == NULL)
return 0;
-
- switch (key_in_file(key, options.revoked_keys_file, 0)) {
- case 0:
- /* key not revoked */
- return 0;
- case -1:
- /* Error opening revoked_keys_file: refuse all keys */
- error("Revoked keys file is unreadable: refusing public key "
- "authentication");
- return 1;
- case 1:
- /* Key revoked */
- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
- error("WARNING: authentication attempt with a revoked "
- "%s key %s ", key_type(key), key_fp);
- xfree(key_fp);
- return 1;
+ if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
+ SSH_FP_DEFAULT)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ error("%s: fingerprint key: %s", __func__, ssh_err(r));
+ goto out;
}
- fatal("key_in_file returned junk");
+
+ r = sshkey_check_revoked(key, options.revoked_keys_file);
+ switch (r) {
+ case 0:
+ break; /* not revoked */
+ case SSH_ERR_KEY_REVOKED:
+ error("Authentication key %s %s revoked by file %s",
+ sshkey_type(key), fp, options.revoked_keys_file);
+ goto out;
+ default:
+ error("Error checking authentication key %s %s in "
+ "revoked keys file %s: %s", sshkey_type(key), fp,
+ options.revoked_keys_file, ssh_err(r));
+ goto out;
+ }
+
+ /* Success */
+ r = 0;
+
+ out:
+ free(fp);
+ return r == 0 ? 0 : 1;
}
void
@@ -666,7 +744,7 @@
while (buffer_len(&auth_debug)) {
msg = buffer_get_string(&auth_debug, NULL);
packet_send_debug("%s", msg);
- xfree(msg);
+ free(msg);
}
}
@@ -690,12 +768,12 @@
fake.pw_name = "NOUSER";
fake.pw_passwd =
"$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
-#ifdef HAVE_PW_GECOS_IN_PASSWD
+#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
fake.pw_gecos = "NOUSER";
#endif
fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
-#ifdef HAVE_PW_CLASS_IN_PASSWD
+#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
fake.pw_class = "";
#endif
fake.pw_dir = "/nonexist";