Merge branch 'master' of https://github.com/openssh/openssh-portable into latestw

This commit is contained in:
Manoj Ampalam 2017-07-08 23:18:28 -07:00
commit 3dd748c035
41 changed files with 783 additions and 371 deletions

View File

@ -17,3 +17,5 @@ f6ae971186ba68d066cd102e57d5b0b2c211a5ee systrace is dead.
fe5b31f69a60d47171836911f144acff77810217 Makefile.inc bits fe5b31f69a60d47171836911f144acff77810217 Makefile.inc bits
5781670c0578fe89663c9085ed3ba477cf7e7913 Delete sshconnect1.c 5781670c0578fe89663c9085ed3ba477cf7e7913 Delete sshconnect1.c
ea80f445e819719ccdcb237022cacfac990fdc5c Makefile.inc warning flags ea80f445e819719ccdcb237022cacfac990fdc5c Makefile.inc warning flags
b92c93266d8234d493857bb822260dacf4366157 moduli-gen.sh tweak
b25bf747544265b39af74fe0716dc8d9f5b63b95 Updated moduli

View File

@ -99,7 +99,7 @@ http://www.gnu.org/software/autoconf/
Basic Security Module (BSM): Basic Security Module (BSM):
Native BSM support is know to exist in Solaris from at least 2.5.1, Native BSM support is known to exist in Solaris from at least 2.5.1,
FreeBSD 6.1 and OS X. Alternatively, you may use the OpenBSM FreeBSD 6.1 and OS X. Alternatively, you may use the OpenBSM
implementation (http://www.openbsm.org). implementation (http://www.openbsm.org).

62
auth.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.c,v 1.121 2017/05/30 08:52:19 markus Exp $ */ /* $OpenBSD: auth.c,v 1.122 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -268,21 +268,41 @@ allowed_user(struct passwd * pw)
return 1; return 1;
} }
void /*
auth_info(Authctxt *authctxt, const char *fmt, ...) * Formats any key left in authctxt->auth_method_key for inclusion in
* auth_log()'s message. Also includes authxtct->auth_method_info if present.
*/
static char *
format_method_key(Authctxt *authctxt)
{ {
va_list ap; const struct sshkey *key = authctxt->auth_method_key;
int i; const char *methinfo = authctxt->auth_method_info;
char *fp, *ret = NULL;
free(authctxt->info); if (key == NULL)
authctxt->info = NULL; return NULL;
va_start(ap, fmt); if (key_is_cert(key)) {
i = vasprintf(&authctxt->info, fmt, ap); fp = sshkey_fingerprint(key->cert->signature_key,
va_end(ap); options.fingerprint_hash, SSH_FP_DEFAULT);
xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
if (i < 0 || authctxt->info == NULL) sshkey_type(key), key->cert->key_id,
fatal("vasprintf failed"); (unsigned long long)key->cert->serial,
sshkey_type(key->cert->signature_key),
fp == NULL ? "(null)" : fp,
methinfo == NULL ? "" : ", ",
methinfo == NULL ? "" : methinfo);
free(fp);
} else {
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
fp == NULL ? "(null)" : fp,
methinfo == NULL ? "" : ", ",
methinfo == NULL ? "" : methinfo);
free(fp);
}
return ret;
} }
void void
@ -291,7 +311,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
{ {
struct ssh *ssh = active_state; /* XXX */ struct ssh *ssh = active_state; /* XXX */
void (*authlog) (const char *fmt,...) = verbose; void (*authlog) (const char *fmt,...) = verbose;
char *authmsg; const char *authmsg;
char *extra = NULL;
if (use_privsep && !mm_is_monitor() && !authctxt->postponed) if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
return; return;
@ -310,6 +331,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
else else
authmsg = authenticated ? "Accepted" : "Failed"; authmsg = authenticated ? "Accepted" : "Failed";
if ((extra = format_method_key(authctxt)) == NULL) {
if (authctxt->auth_method_info != NULL)
extra = xstrdup(authctxt->auth_method_info);
}
authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
authmsg, authmsg,
method, method,
@ -318,10 +344,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
authctxt->user, authctxt->user,
ssh_remote_ipaddr(ssh), ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh), ssh_remote_port(ssh),
authctxt->info != NULL ? ": " : "", extra != NULL ? ": " : "",
authctxt->info != NULL ? authctxt->info : ""); extra != NULL ? extra : "");
free(authctxt->info);
authctxt->info = NULL; free(extra);
#ifdef CUSTOM_FAILED_LOGIN #ifdef CUSTOM_FAILED_LOGIN
if (authenticated == 0 && !authctxt->postponed && if (authenticated == 0 && !authctxt->postponed &&

49
auth.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.91 2017/05/30 14:29:59 markus Exp $ */ /* $OpenBSD: auth.h,v 1.92 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -44,6 +44,7 @@
struct ssh; struct ssh;
struct sshkey; struct sshkey;
struct sshbuf;
typedef struct Authctxt Authctxt; typedef struct Authctxt Authctxt;
typedef struct Authmethod Authmethod; typedef struct Authmethod Authmethod;
@ -62,13 +63,17 @@ struct Authctxt {
char *service; char *service;
struct passwd *pw; /* set if 'valid' */ struct passwd *pw; /* set if 'valid' */
char *style; char *style;
/* Method lists for multiple authentication */
char **auth_methods; /* modified from server config */
u_int num_auth_methods;
/* Authentication method-specific data */
void *methoddata;
void *kbdintctxt; void *kbdintctxt;
char *info; /* Extra info for next auth_log */
#ifdef BSD_AUTH #ifdef BSD_AUTH
auth_session_t *as; auth_session_t *as;
#endif #endif
char **auth_methods; /* modified from server config */
u_int num_auth_methods;
#ifdef KRB5 #ifdef KRB5
krb5_context krb5_ctx; krb5_context krb5_ctx;
krb5_ccache krb5_fwd_ccache; krb5_ccache krb5_fwd_ccache;
@ -76,14 +81,23 @@ struct Authctxt {
char *krb5_ticket_file; char *krb5_ticket_file;
char *krb5_ccname; char *krb5_ccname;
#endif #endif
Buffer *loginmsg; struct sshbuf *loginmsg;
void *methoddata;
/* Authentication keys already used; these will be refused henceforth */
struct sshkey **prev_keys;
u_int nprev_keys;
/* Last used key and ancilliary information from active auth method */
struct sshkey *auth_method_key;
char *auth_method_info;
/* Information exposed to session */
struct sshbuf *session_info; /* Auth info for environment */
#ifdef WINDOWS #ifdef WINDOWS
void *auth_token; void *auth_token;
#endif #endif
struct sshkey **prev_userkeys;
u_int nprev_userkeys;
}; };
/* /*
* Every authentication method has to handle authentication requests for * Every authentication method has to handle authentication requests for
* non-existing users, or for users that are not allowed to login. In this * non-existing users, or for users that are not allowed to login. In this
@ -122,10 +136,18 @@ int auth_password(Authctxt *, const char *);
int hostbased_key_allowed(struct passwd *, const char *, char *, int hostbased_key_allowed(struct passwd *, const char *, char *,
struct sshkey *); struct sshkey *);
int user_key_allowed(struct passwd *, struct sshkey *, int); int user_key_allowed(struct passwd *, struct sshkey *, int);
void pubkey_auth_info(Authctxt *, const struct sshkey *, const char *, ...) int auth2_key_already_used(Authctxt *, const struct sshkey *);
__attribute__((__format__ (printf, 3, 4)));
void auth2_record_userkey(Authctxt *, struct sshkey *); /*
int auth2_userkey_already_used(Authctxt *, struct sshkey *); * Handling auth method-specific information for logging and prevention
* of key reuse during multiple authentication.
*/
void auth2_authctxt_reset_info(Authctxt *);
void auth2_record_key(Authctxt *, int, const struct sshkey *);
void auth2_record_info(Authctxt *authctxt, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
void auth2_update_session_info(Authctxt *, const char *, const char *);
struct stat; struct stat;
int auth_secure_path(const char *, struct stat *, const char *, uid_t, int auth_secure_path(const char *, struct stat *, const char *, uid_t,
@ -152,9 +174,6 @@ void disable_forwarding(void);
void do_authentication2(Authctxt *); void do_authentication2(Authctxt *);
void auth_info(Authctxt *authctxt, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
void auth_log(Authctxt *, int, int, const char *, const char *); void auth_log(Authctxt *, int, int, const char *, const char *);
void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn)); void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
void userauth_finish(struct ssh *, int, const char *, const char *); void userauth_finish(struct ssh *, int, const char *, const char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-gss.c,v 1.25 2017/05/30 14:29:59 markus Exp $ */ /* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@ -228,6 +228,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
{ {
Authctxt *authctxt = ssh->authctxt; Authctxt *authctxt = ssh->authctxt;
int authenticated; int authenticated;
const char *displayname;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context"); fatal("No authentication or GSSAPI context");
@ -241,6 +242,10 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
if ((!use_privsep || mm_is_monitor()) &&
(displayname = ssh_gssapi_displayname()) != NULL)
auth2_record_info(authctxt, "%s", displayname);
authctxt->postponed = 0; authctxt->postponed = 0;
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
@ -259,6 +264,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
Buffer b; Buffer b;
gss_buffer_desc mic, gssbuf; gss_buffer_desc mic, gssbuf;
u_int len; u_int len;
const char *displayname;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context"); fatal("No authentication or GSSAPI context");
@ -282,6 +288,10 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
buffer_free(&b); buffer_free(&b);
free(mic.value); free(mic.value);
if ((!use_privsep || mm_is_monitor()) &&
(displayname = ssh_gssapi_displayname()) != NULL)
auth2_record_info(authctxt, "%s", displayname);
authctxt->postponed = 0; authctxt->postponed = 0;
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-hostbased.c,v 1.30 2017/05/30 14:29:59 markus Exp $ */ /* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -137,7 +137,7 @@ userauth_hostbased(struct ssh *ssh)
sshbuf_dump(b, stderr); sshbuf_dump(b, stderr);
#endif #endif
pubkey_auth_info(authctxt, key, auth2_record_info(authctxt,
"client user \"%.100s\", client host \"%.100s\"", cuser, chost); "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
/* test for allowed key and correct signature */ /* test for allowed key and correct signature */
@ -147,11 +147,11 @@ userauth_hostbased(struct ssh *ssh)
sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0) sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
authenticated = 1; authenticated = 1;
auth2_record_key(authctxt, authenticated, key);
sshbuf_free(b); sshbuf_free(b);
done: done:
debug2("%s: authenticated %d", __func__, authenticated); debug2("%s: authenticated %d", __func__, authenticated);
if (key != NULL) sshkey_free(key);
sshkey_free(key);
free(pkalg); free(pkalg);
free(pkblob); free(pkblob);
free(cuser); free(cuser);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.67 2017/05/31 10:54:00 markus Exp $ */ /* $OpenBSD: auth2-pubkey.c,v 1.68 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -138,7 +138,7 @@ userauth_pubkey(struct ssh *ssh)
goto done; goto done;
} }
fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
if (auth2_userkey_already_used(authctxt, key)) { if (auth2_key_already_used(authctxt, key)) {
logit("refusing previously-used %s key", sshkey_type(key)); logit("refusing previously-used %s key", sshkey_type(key));
goto done; goto done;
} }
@ -195,7 +195,6 @@ userauth_pubkey(struct ssh *ssh)
#ifdef DEBUG_PK #ifdef DEBUG_PK
sshbuf_dump(b, stderr); sshbuf_dump(b, stderr);
#endif #endif
pubkey_auth_info(authctxt, key, NULL);
/* test for correct signature */ /* test for correct signature */
authenticated = 0; authenticated = 0;
@ -209,13 +208,10 @@ userauth_pubkey(struct ssh *ssh)
sshbuf_len(b), ssh->compat)) == 0) { sshbuf_len(b), ssh->compat)) == 0) {
#endif #endif
authenticated = 1; authenticated = 1;
/* Record the successful key to prevent reuse */
auth2_record_userkey(authctxt, key);
key = NULL; /* Don't free below */
} }
sshbuf_free(b); sshbuf_free(b);
free(sig); free(sig);
auth2_record_key(authctxt, authenticated, key);
} else { } else {
debug("%s: test whether pkalg/pkblob are acceptable for %s %s", debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
__func__, sshkey_type(key), fp); __func__, sshkey_type(key), fp);
@ -245,8 +241,7 @@ userauth_pubkey(struct ssh *ssh)
auth_clear_options(); auth_clear_options();
done: done:
debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
if (key != NULL) sshkey_free(key);
sshkey_free(key);
free(userstyle); free(userstyle);
free(pkalg); free(pkalg);
free(pkblob); free(pkblob);
@ -254,44 +249,6 @@ done:
return authenticated; return authenticated;
} }
void
pubkey_auth_info(Authctxt *authctxt, const struct sshkey *key,
const char *fmt, ...)
{
char *fp, *extra;
va_list ap;
int i;
extra = NULL;
if (fmt != NULL) {
va_start(ap, fmt);
i = vasprintf(&extra, fmt, ap);
va_end(ap);
if (i < 0 || extra == NULL)
fatal("%s: vasprintf failed", __func__);
}
if (sshkey_is_cert(key)) {
fp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT);
auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",
sshkey_type(key), key->cert->key_id,
(unsigned long long)key->cert->serial,
sshkey_type(key->cert->signature_key),
fp == NULL ? "(null)" : fp,
extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
free(fp);
} else {
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
auth_info(authctxt, "%s %s%s%s", sshkey_type(key),
fp == NULL ? "(null)" : fp,
extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
free(fp);
}
free(extra);
}
/* /*
* Splits 's' into an argument vector. Handles quoted string and basic * Splits 's' into an argument vector. Handles quoted string and basic
* escape characters (\\, \", \'). Caller must free the argument vector * escape characters (\\, \", \'). Caller must free the argument vector
@ -1161,36 +1118,6 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
return success; return success;
} }
/* Records a public key in the list of previously-successful keys */
void
auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
{
struct sshkey **tmp;
if (authctxt->nprev_userkeys >= INT_MAX ||
(tmp = recallocarray(authctxt->prev_userkeys,
authctxt->nprev_userkeys, authctxt->nprev_userkeys + 1,
sizeof(*tmp))) == NULL)
fatal("%s: recallocarray failed", __func__);
authctxt->prev_userkeys = tmp;
authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
authctxt->nprev_userkeys++;
}
/* Checks whether a key has already been used successfully for authentication */
int
auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
{
u_int i;
for (i = 0; i < authctxt->nprev_userkeys; i++) {
if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
return 1;
}
}
return 0;
}
Authmethod method_pubkey = { Authmethod method_pubkey = {
"publickey", "publickey",
userauth_pubkey, userauth_pubkey,

133
auth2.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2.c,v 1.142 2017/05/31 07:00:13 markus Exp $ */ /* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -30,6 +30,7 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <pwd.h> #include <pwd.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
@ -55,6 +56,7 @@
#include "ssh-gss.h" #include "ssh-gss.h"
#endif #endif
#include "monitor_wrap.h" #include "monitor_wrap.h"
#include "ssherr.h"
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
@ -277,6 +279,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
#endif #endif
auth2_authctxt_reset_info(authctxt);
authctxt->postponed = 0; authctxt->postponed = 0;
authctxt->server_caused_failure = 0; authctxt->server_caused_failure = 0;
@ -327,6 +330,10 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method,
/* Log before sending the reply */ /* Log before sending the reply */
auth_log(authctxt, authenticated, partial, method, submethod); auth_log(authctxt, authenticated, partial, method, submethod);
/* Update information exposed to session */
if (authenticated || partial)
auth2_update_session_info(authctxt, method, submethod);
if (authctxt->postponed) if (authctxt->postponed)
return; return;
@ -624,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
return 0; return 0;
} }
/* Reset method-specific information */
void auth2_authctxt_reset_info(Authctxt *authctxt)
{
sshkey_free(authctxt->auth_method_key);
free(authctxt->auth_method_info);
authctxt->auth_method_key = NULL;
authctxt->auth_method_info = NULL;
}
/* Record auth method-specific information for logs */
void
auth2_record_info(Authctxt *authctxt, const char *fmt, ...)
{
va_list ap;
int i;
free(authctxt->auth_method_info);
authctxt->auth_method_info = NULL;
va_start(ap, fmt);
i = vasprintf(&authctxt->auth_method_info, fmt, ap);
va_end(ap);
if (i < 0 || authctxt->auth_method_info == NULL)
fatal("%s: vasprintf failed", __func__);
}
/*
* Records a public key used in authentication. This is used for logging
* and to ensure that the same key is not subsequently accepted again for
* multiple authentication.
*/
void
auth2_record_key(Authctxt *authctxt, int authenticated,
const struct sshkey *key)
{
struct sshkey **tmp, *dup;
int r;
if ((r = sshkey_demote(key, &dup)) != 0)
fatal("%s: copy key: %s", __func__, ssh_err(r));
sshkey_free(authctxt->auth_method_key);
authctxt->auth_method_key = dup;
if (!authenticated)
return;
/* If authenticated, make sure we don't accept this key again */
if ((r = sshkey_demote(key, &dup)) != 0)
fatal("%s: copy key: %s", __func__, ssh_err(r));
if (authctxt->nprev_keys >= INT_MAX ||
(tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys,
authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL)
fatal("%s: reallocarray failed", __func__);
authctxt->prev_keys = tmp;
authctxt->prev_keys[authctxt->nprev_keys] = dup;
authctxt->nprev_keys++;
}
/* Checks whether a key has already been previously used for authentication */
int
auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key)
{
u_int i;
char *fp;
for (i = 0; i < authctxt->nprev_keys; i++) {
if (sshkey_equal_public(key, authctxt->prev_keys[i])) {
fp = sshkey_fingerprint(authctxt->prev_keys[i],
options.fingerprint_hash, SSH_FP_DEFAULT);
debug3("%s: key already used: %s %s", __func__,
sshkey_type(authctxt->prev_keys[i]),
fp == NULL ? "UNKNOWN" : fp);
free(fp);
return 1;
}
}
return 0;
}
/*
* Updates authctxt->session_info with details of authentication. Should be
* whenever an authentication method succeeds.
*/
void
auth2_update_session_info(Authctxt *authctxt, const char *method,
const char *submethod)
{
int r;
if (authctxt->session_info == NULL) {
if ((authctxt->session_info = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new", __func__);
}
/* Append method[/submethod] */
if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s",
method, submethod == NULL ? "" : "/",
submethod == NULL ? "" : submethod)) != 0)
fatal("%s: append method: %s", __func__, ssh_err(r));
/* Append key if present */
if (authctxt->auth_method_key != NULL) {
if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
(r = sshkey_format_text(authctxt->auth_method_key,
authctxt->session_info)) != 0)
fatal("%s: append key: %s", __func__, ssh_err(r));
}
if (authctxt->auth_method_info != NULL) {
/* Ensure no ambiguity here */
if (strchr(authctxt->auth_method_info, '\n') != NULL)
fatal("%s: auth_method_info contains \\n", __func__);
if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
(r = sshbuf_putf(authctxt->session_info, "%s",
authctxt->auth_method_info)) != 0) {
fatal("%s: append method info: %s",
__func__, ssh_err(r));
}
}
if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0)
fatal("%s: append: %s", __func__, ssh_err(r));
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.c,v 1.103 2017/05/05 10:42:49 naddy Exp $ */ /* $OpenBSD: authfd.c,v 1.104 2017/06/28 01:09:22 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -331,7 +331,7 @@ ssh_free_identitylist(struct ssh_identitylist *idl)
/* encode signature algoritm in flag bits, so we can keep the msg format */ /* encode signature algoritm in flag bits, so we can keep the msg format */
static u_int static u_int
agent_encode_alg(struct sshkey *key, const char *alg) agent_encode_alg(const struct sshkey *key, const char *alg)
{ {
if (alg != NULL && key->type == KEY_RSA) { if (alg != NULL && key->type == KEY_RSA) {
if (strcmp(alg, "rsa-sha2-256") == 0) if (strcmp(alg, "rsa-sha2-256") == 0)
@ -344,7 +344,7 @@ agent_encode_alg(struct sshkey *key, const char *alg)
/* ask agent to sign data, returns err.h code on error, 0 on success */ /* ask agent to sign data, returns err.h code on error, 0 on success */
int int
ssh_agent_sign(int sock, struct sshkey *key, ssh_agent_sign(int sock, const struct sshkey *key,
u_char **sigp, size_t *lenp, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, const char *alg, u_int compat) const u_char *data, size_t datalen, const char *alg, u_int compat)
{ {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.h,v 1.40 2017/05/05 10:42:49 naddy Exp $ */ /* $OpenBSD: authfd.h,v 1.41 2017/06/28 01:09:22 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -38,7 +38,7 @@ int ssh_remove_all_identities(int sock, int version);
int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
u_char session_id[16], u_char response[16]); u_char session_id[16], u_char response[16]);
int ssh_agent_sign(int sock, struct sshkey *key, int ssh_agent_sign(int sock, const struct sshkey *key,
u_char **sigp, size_t *lenp, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, const char *alg, u_int compat); const u_char *data, size_t datalen, const char *alg, u_int compat);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.299 2017/05/31 09:15:42 deraadt Exp $ */ /* $OpenBSD: clientloop.c,v 1.300 2017/06/23 07:24:48 mestre Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1259,7 +1259,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
} else { } else {
debug("pledge: network"); debug("pledge: network");
if (pledge("stdio unix inet dns tty", NULL) == -1) if (pledge("stdio unix inet dns proc tty", NULL) == -1)
fatal("%s pledge(): %s", __func__, strerror(errno)); fatal("%s pledge(): %s", __func__, strerror(errno));
} }

View File

@ -3814,6 +3814,8 @@ OSSH_CHECK_HEADER_FOR_FIELD([ut_time], [utmpx.h], [HAVE_TIME_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_tv], [utmpx.h], [HAVE_TV_IN_UTMPX]) OSSH_CHECK_HEADER_FOR_FIELD([ut_tv], [utmpx.h], [HAVE_TV_IN_UTMPX])
AC_CHECK_MEMBERS([struct stat.st_blksize]) AC_CHECK_MEMBERS([struct stat.st_blksize])
AC_CHECK_MEMBERS([struct stat.st_mtim])
AC_CHECK_MEMBERS([struct stat.st_mtime])
AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_class, AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_class,
struct passwd.pw_change, struct passwd.pw_expire], struct passwd.pw_change, struct passwd.pw_expire],
[], [], [[ [], [], [[

View File

@ -35,7 +35,7 @@ The script treats all packages as USR packages (not ROOT+USR when
appropriate). It seems to work, though...... appropriate). It seems to work, though......
If there are any patches to this that have not yet been integrated they If there are any patches to this that have not yet been integrated they
may be found at http://www.zip.com.au/~dtucker/openssh/. may be found at http://www.dtucker.net/openssh/.
Disclaimer: Disclaimer:

View File

@ -519,6 +519,13 @@ struct winsize {
} }
#endif #endif
#ifndef timespeccmp
#define timespeccmp(tsp, usp, cmp) \
(((tsp)->tv_sec == (usp)->tv_sec) ? \
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
((tsp)->tv_sec cmp (usp)->tv_sec))
#endif
#ifndef __P #ifndef __P
# define __P(x) x # define __P(x) x
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */ /* $OpenBSD: gss-serv.c,v 1.30 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@ -393,4 +393,13 @@ ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
return (ctx->major); return (ctx->major);
} }
/* Privileged */
const char *ssh_gssapi_displayname(void)
{
if (gssapi_client.displayname.length == 0 ||
gssapi_client.displayname.value == NULL)
return NULL;
return (char *)gssapi_client.displayname.value;
}
#endif #endif

View File

@ -93,6 +93,9 @@
#ifdef HAVE_SYS_SYSMACROS_H #ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* For MIN, MAX, etc */ # include <sys/sysmacros.h> /* For MIN, MAX, etc */
#endif #endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h> /* for timespeccmp if present */
#endif
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h> /* for MAP_ANONYMOUS */ #include <sys/mman.h> /* for MAP_ANONYMOUS */
#endif #endif

18
kex.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.133 2017/05/30 14:23:52 markus Exp $ */ /* $OpenBSD: kex.c,v 1.134 2017/06/13 12:13:59 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* *
@ -378,7 +378,9 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
{ {
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
u_int32_t i, ninfo; u_int32_t i, ninfo;
char *name, *val, *found; char *name, *found;
u_char *val;
size_t vlen;
int r; int r;
debug("SSH2_MSG_EXT_INFO received"); debug("SSH2_MSG_EXT_INFO received");
@ -388,12 +390,17 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
for (i = 0; i < ninfo; i++) { for (i = 0; i < ninfo; i++) {
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
return r; return r;
if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) { if ((r = sshpkt_get_string(ssh, &val, &vlen)) != 0) {
free(name); free(name);
return r; return r;
} }
debug("%s: %s=<%s>", __func__, name, val);
if (strcmp(name, "server-sig-algs") == 0) { if (strcmp(name, "server-sig-algs") == 0) {
/* Ensure no \0 lurking in value */
if (memchr(val, '\0', vlen) != NULL) {
error("%s: nul byte in %s", __func__, name);
return SSH_ERR_INVALID_FORMAT;
}
debug("%s: %s=<%s>", __func__, name, val);
found = match_list("rsa-sha2-256", val, NULL); found = match_list("rsa-sha2-256", val, NULL);
if (found) { if (found) {
kex->rsa_sha2 = 256; kex->rsa_sha2 = 256;
@ -404,7 +411,8 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
kex->rsa_sha2 = 512; kex->rsa_sha2 = 512;
free(found); free(found);
} }
} } else
debug("%s: %s (unrecognised)", __func__, name);
free(name); free(name);
free(val); free(val);
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.171 2017/05/31 10:04:29 markus Exp $ */ /* $OpenBSD: monitor.c,v 1.172 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org> * Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -308,6 +308,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
partial = 0; partial = 0;
auth_method = "unknown"; auth_method = "unknown";
auth_submethod = NULL; auth_submethod = NULL;
auth2_authctxt_reset_info(authctxt);
authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
/* Special handling for multiple required authentications */ /* Special handling for multiple required authentications */
@ -347,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
auth_method, auth_submethod); auth_method, auth_submethod);
if (!partial && !authenticated) if (!partial && !authenticated)
authctxt->failures++; authctxt->failures++;
if (authenticated || partial) {
auth2_update_session_info(authctxt,
auth_method, auth_submethod);
}
} }
} }
@ -1147,12 +1153,11 @@ mm_answer_keyallowed(int sock, Buffer *m)
switch (type) { switch (type) {
case MM_USERKEY: case MM_USERKEY:
allowed = options.pubkey_authentication && allowed = options.pubkey_authentication &&
!auth2_userkey_already_used(authctxt, key) && !auth2_key_already_used(authctxt, key) &&
match_pattern_list(sshkey_ssh_name(key), match_pattern_list(sshkey_ssh_name(key),
options.pubkey_key_types, 0) == 1 && options.pubkey_key_types, 0) == 1 &&
user_key_allowed(authctxt->pw, key, user_key_allowed(authctxt->pw, key,
pubkey_auth_attempt); pubkey_auth_attempt);
pubkey_auth_info(authctxt, key, NULL);
auth_method = "publickey"; auth_method = "publickey";
if (options.pubkey_authentication && if (options.pubkey_authentication &&
(!pubkey_auth_attempt || allowed != 1)) (!pubkey_auth_attempt || allowed != 1))
@ -1160,11 +1165,12 @@ mm_answer_keyallowed(int sock, Buffer *m)
break; break;
case MM_HOSTKEY: case MM_HOSTKEY:
allowed = options.hostbased_authentication && allowed = options.hostbased_authentication &&
!auth2_key_already_used(authctxt, key) &&
match_pattern_list(sshkey_ssh_name(key), match_pattern_list(sshkey_ssh_name(key),
options.hostbased_key_types, 0) == 1 && options.hostbased_key_types, 0) == 1 &&
hostbased_key_allowed(authctxt->pw, hostbased_key_allowed(authctxt->pw,
cuser, chost, key); cuser, chost, key);
pubkey_auth_info(authctxt, key, auth2_record_info(authctxt,
"client user \"%.100s\", client host \"%.100s\"", "client user \"%.100s\", client host \"%.100s\"",
cuser, chost); cuser, chost);
auth_method = "hostbased"; auth_method = "hostbased";
@ -1175,11 +1181,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
} }
} }
debug3("%s: key %p is %s", debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed");
__func__, key, allowed ? "allowed" : "not allowed");
if (key != NULL) auth2_record_key(authctxt, 0, key);
key_free(key); sshkey_free(key);
/* clear temporarily storage (used by verify) */ /* clear temporarily storage (used by verify) */
monitor_reset_key_state(); monitor_reset_key_state();
@ -1353,10 +1358,12 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
switch (key_blobtype) { switch (key_blobtype) {
case MM_USERKEY: case MM_USERKEY:
valid_data = monitor_valid_userblob(data, datalen); valid_data = monitor_valid_userblob(data, datalen);
auth_method = "publickey";
break; break;
case MM_HOSTKEY: case MM_HOSTKEY:
valid_data = monitor_valid_hostbasedblob(data, datalen, valid_data = monitor_valid_hostbasedblob(data, datalen,
hostbased_cuser, hostbased_chost); hostbased_cuser, hostbased_chost);
auth_method = "hostbased";
break; break;
default: default:
valid_data = 0; valid_data = 0;
@ -1367,23 +1374,17 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
ret = sshkey_verify(key, signature, signaturelen, data, datalen, ret = sshkey_verify(key, signature, signaturelen, data, datalen,
active_state->compat); active_state->compat);
debug3("%s: key %p signature %s", debug3("%s: %s %p signature %s", __func__, auth_method, key,
__func__, key, (ret == 0) ? "verified" : "unverified"); (ret == 0) ? "verified" : "unverified");
auth2_record_key(authctxt, ret == 0, key);
/* If auth was successful then record key to ensure it isn't reused */
if (ret == 0 && key_blobtype == MM_USERKEY)
auth2_record_userkey(authctxt, key);
else
sshkey_free(key);
free(blob); free(blob);
free(signature); free(signature);
free(data); free(data);
auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
monitor_reset_key_state(); monitor_reset_key_state();
sshkey_free(key);
sshbuf_reset(m); sshbuf_reset(m);
/* encode ret != 0 as positive integer, since we're sending u32 */ /* encode ret != 0 as positive integer, since we're sending u32 */
@ -1799,6 +1800,7 @@ int
mm_answer_gss_userok(int sock, Buffer *m) mm_answer_gss_userok(int sock, Buffer *m)
{ {
int authenticated; int authenticated;
const char *displayname;
if (!options.gss_authentication) if (!options.gss_authentication)
fatal("%s: GSSAPI authentication not enabled", __func__); fatal("%s: GSSAPI authentication not enabled", __func__);
@ -1813,6 +1815,9 @@ mm_answer_gss_userok(int sock, Buffer *m)
auth_method = "gssapi-with-mic"; auth_method = "gssapi-with-mic";
if ((displayname = ssh_gssapi_displayname()) != NULL)
auth2_record_info(authctxt, "%s", displayname);
/* Monitor loop will terminate if authenticated */ /* Monitor loop will terminate if authenticated */
return (authenticated); return (authenticated);
} }

30
mux.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: mux.c,v 1.64 2017/01/21 11:32:04 guenther Exp $ */ /* $OpenBSD: mux.c,v 1.65 2017/06/09 06:47:13 djm Exp $ */
/* /*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
* *
@ -1570,31 +1570,38 @@ mux_client_hello_exchange(int fd)
{ {
Buffer m; Buffer m;
u_int type, ver; u_int type, ver;
int ret = -1;
buffer_init(&m); buffer_init(&m);
buffer_put_int(&m, MUX_MSG_HELLO); buffer_put_int(&m, MUX_MSG_HELLO);
buffer_put_int(&m, SSHMUX_VER); buffer_put_int(&m, SSHMUX_VER);
/* no extensions */ /* no extensions */
if (mux_client_write_packet(fd, &m) != 0) if (mux_client_write_packet(fd, &m) != 0) {
fatal("%s: write packet: %s", __func__, strerror(errno)); debug("%s: write packet: %s", __func__, strerror(errno));
goto out;
}
buffer_clear(&m); buffer_clear(&m);
/* Read their HELLO */ /* Read their HELLO */
if (mux_client_read_packet(fd, &m) != 0) { if (mux_client_read_packet(fd, &m) != 0) {
buffer_free(&m); debug("%s: read packet failed", __func__);
return -1; goto out;
} }
type = buffer_get_int(&m); type = buffer_get_int(&m);
if (type != MUX_MSG_HELLO) if (type != MUX_MSG_HELLO) {
fatal("%s: expected HELLO (%u) received %u", error("%s: expected HELLO (%u) received %u",
__func__, MUX_MSG_HELLO, type); __func__, MUX_MSG_HELLO, type);
goto out;
}
ver = buffer_get_int(&m); ver = buffer_get_int(&m);
if (ver != SSHMUX_VER) if (ver != SSHMUX_VER) {
fatal("Unsupported multiplexing protocol version %d " error("Unsupported multiplexing protocol version %d "
"(expected %d)", ver, SSHMUX_VER); "(expected %d)", ver, SSHMUX_VER);
goto out;
}
debug2("%s: master version %u", __func__, ver); debug2("%s: master version %u", __func__, ver);
/* No extensions are presently defined */ /* No extensions are presently defined */
while (buffer_len(&m) > 0) { while (buffer_len(&m) > 0) {
@ -1605,8 +1612,11 @@ mux_client_hello_exchange(int fd)
free(name); free(name);
free(value); free(value);
} }
/* success */
ret = 0;
out:
buffer_free(&m); buffer_free(&m);
return 0; return ret;
} }
static u_int static u_int

View File

@ -22,7 +22,9 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_STDINT_H
#include <stdint.h> #include <stdint.h>
#endif
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.260 2017/06/06 09:12:17 dtucker Exp $ */ /* $OpenBSD: packet.c,v 1.262 2017/06/24 06:38:11 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -901,6 +901,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
/* /*
* The 2^(blocksize*2) limit is too expensive for 3DES, * The 2^(blocksize*2) limit is too expensive for 3DES,
* so enforce a 1GB limit for small blocksizes. * so enforce a 1GB limit for small blocksizes.
* See RFC4344 section 3.2.
*/ */
if (enc->block_size >= 16) if (enc->block_size >= 16)
*max_blocks = (u_int64_t)1 << (enc->block_size*2); *max_blocks = (u_int64_t)1 << (enc->block_size*2);
@ -944,7 +945,10 @@ ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
(int64_t)state->rekey_time + state->rekey_interval <= monotime()) (int64_t)state->rekey_time + state->rekey_interval <= monotime())
return 1; return 1;
/* Always rekey when MAX_PACKETS sent in either direction */ /*
* Always rekey when MAX_PACKETS sent in either direction
* As per RFC4344 section 3.1 we do this after 2^31 packets.
*/
if (state->p_send.packets > MAX_PACKETS || if (state->p_send.packets > MAX_PACKETS ||
state->p_read.packets > MAX_PACKETS) state->p_read.packets > MAX_PACKETS)
return 1; return 1;
@ -2218,9 +2222,7 @@ newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode)
return r; return r;
if ((b = sshbuf_new()) == NULL) if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL; return SSH_ERR_ALLOC_FAIL;
/* The cipher struct is constant and shared, you export pointer */
if ((r = sshbuf_put_cstring(b, enc->name)) != 0 || if ((r = sshbuf_put_cstring(b, enc->name)) != 0 ||
(r = sshbuf_put(b, &enc->cipher, sizeof(enc->cipher))) != 0 ||
(r = sshbuf_put_u32(b, enc->enabled)) != 0 || (r = sshbuf_put_u32(b, enc->enabled)) != 0 ||
(r = sshbuf_put_u32(b, enc->block_size)) != 0 || (r = sshbuf_put_u32(b, enc->block_size)) != 0 ||
(r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 || (r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 ||
@ -2294,12 +2296,15 @@ newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode)
comp = &newkey->comp; comp = &newkey->comp;
if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 || if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 ||
(r = sshbuf_get(b, &enc->cipher, sizeof(enc->cipher))) != 0 ||
(r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 || (r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 ||
(r = sshbuf_get_u32(b, &enc->block_size)) != 0 || (r = sshbuf_get_u32(b, &enc->block_size)) != 0 ||
(r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 || (r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 ||
(r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0) (r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0)
goto out; goto out;
if ((enc->cipher = cipher_by_name(enc->name)) == NULL) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (cipher_authlen(enc->cipher) == 0) { if (cipher_authlen(enc->cipher) == 0) {
if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0) if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0)
goto out; goto out;
@ -2317,11 +2322,6 @@ newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode)
if ((r = sshbuf_get_u32(b, &comp->type)) != 0 || if ((r = sshbuf_get_u32(b, &comp->type)) != 0 ||
(r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0) (r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0)
goto out; goto out;
if (enc->name == NULL ||
cipher_by_name(enc->name) != enc->cipher) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshbuf_len(b) != 0) { if (sshbuf_len(b) != 0) {
r = SSH_ERR_INVALID_FORMAT; r = SSH_ERR_INVALID_FORMAT;
goto out; goto out;

View File

@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.94 2016/12/16 03:51:19 dtucker Exp $ # $OpenBSD: Makefile,v 1.95 2017/06/24 06:35:24 djm Exp $
REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec
tests: prep $(REGRESS_TARGETS) tests: prep $(REGRESS_TARGETS)
@ -79,7 +79,8 @@ LTESTS= connect \
principals-command \ principals-command \
cert-file \ cert-file \
cfginclude \ cfginclude \
allow-deny-users allow-deny-users \
authinfo
# dhgex \ # dhgex \

17
regress/authinfo.sh Normal file
View File

@ -0,0 +1,17 @@
# $OpenBSD: authinfo.sh,v 1.1 2017/06/24 06:35:24 djm Exp $
# Placed in the Public Domain.
tid="authinfo"
# Ensure the environment variable doesn't leak when ExposeAuthInfo=no.
verbose "ExposeAuthInfo=no"
env SSH_USER_AUTH=blah ${SSH} -F $OBJ/ssh_proxy x \
'test -z "$SSH_USER_AUTH"' || fail "SSH_USER_AUTH present"
verbose "ExposeAuthInfo=yes"
echo ExposeAuthInfo=yes >> $OBJ/sshd_proxy
${SSH} -F $OBJ/ssh_proxy x \
'grep ^publickey "$SSH_USER_AUTH" /dev/null >/dev/null' ||
fail "ssh with ExposeAuthInfo failed"
# XXX test multiple auth and key contents

View File

@ -61,6 +61,12 @@ ssh_sandbox_init(struct monitor *monitor)
if (priv_delset(box->pset, PRIV_FILE_LINK_ANY) != 0 || if (priv_delset(box->pset, PRIV_FILE_LINK_ANY) != 0 ||
#ifdef PRIV_NET_ACCESS #ifdef PRIV_NET_ACCESS
priv_delset(box->pset, PRIV_NET_ACCESS) != 0 || priv_delset(box->pset, PRIV_NET_ACCESS) != 0 ||
#endif
#ifdef PRIV_DAX_ACCESS
priv_delset(box->pset, PRIV_DAX_ACCESS) != 0 ||
#endif
#ifdef PRIV_SYS_IB_INFO
priv_delset(box->pset, PRIV_SYS_IB_INFO) != 0 ||
#endif #endif
priv_delset(box->pset, PRIV_PROC_EXEC) != 0 || priv_delset(box->pset, PRIV_PROC_EXEC) != 0 ||
priv_delset(box->pset, PRIV_PROC_FORK) != 0 || priv_delset(box->pset, PRIV_PROC_FORK) != 0 ||

View File

@ -1,5 +1,5 @@
/* $OpenBSD: servconf.c,v 1.308 2017/05/17 01:24:17 djm Exp $ */ /* $OpenBSD: servconf.c,v 1.309 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -164,6 +164,7 @@ initialize_server_options(ServerOptions *options)
options->version_addendum = NULL; options->version_addendum = NULL;
options->fingerprint_hash = -1; options->fingerprint_hash = -1;
options->disable_forwarding = -1; options->disable_forwarding = -1;
options->expose_userauth_info = -1;
} }
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@ -333,6 +334,8 @@ fill_default_server_options(ServerOptions *options)
options->fingerprint_hash = SSH_FP_HASH_DEFAULT; options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
if (options->disable_forwarding == -1) if (options->disable_forwarding == -1)
options->disable_forwarding = 0; options->disable_forwarding = 0;
if (options->expose_userauth_info == -1)
options->expose_userauth_info = 0;
assemble_algorithms(options); assemble_algorithms(options);
@ -418,6 +421,7 @@ typedef enum {
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
sStreamLocalBindMask, sStreamLocalBindUnlink, sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo,
sDeprecated, sIgnore, sUnsupported sDeprecated, sIgnore, sUnsupported
} ServerOpCodes; } ServerOpCodes;
@ -561,6 +565,7 @@ static struct {
{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
{ "disableforwarding", sDisableForwarding, SSHCFG_ALL }, { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
{ NULL, sBadOption, 0 } { NULL, sBadOption, 0 }
}; };
@ -1841,6 +1846,10 @@ process_server_config_line(ServerOptions *options, char *line,
options->fingerprint_hash = value; options->fingerprint_hash = value;
break; break;
case sExposeAuthInfo:
intptr = &options->expose_userauth_info;
goto parse_flag;
case sDeprecated: case sDeprecated:
case sIgnore: case sIgnore:
case sUnsupported: case sUnsupported:
@ -1979,6 +1988,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
M_CP_INTOPT(allow_streamlocal_forwarding); M_CP_INTOPT(allow_streamlocal_forwarding);
M_CP_INTOPT(allow_agent_forwarding); M_CP_INTOPT(allow_agent_forwarding);
M_CP_INTOPT(disable_forwarding); M_CP_INTOPT(disable_forwarding);
M_CP_INTOPT(expose_userauth_info);
M_CP_INTOPT(permit_tun); M_CP_INTOPT(permit_tun);
M_CP_INTOPT(fwd_opts.gateway_ports); M_CP_INTOPT(fwd_opts.gateway_ports);
M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
@ -2278,6 +2288,7 @@ dump_config(ServerOptions *o)
dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
/* string arguments */ /* string arguments */
dump_cfg_string(sPidFile, o->pid_file); dump_cfg_string(sPidFile, o->pid_file);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.123 2016/11/30 03:00:05 djm Exp $ */ /* $OpenBSD: servconf.h,v 1.124 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -189,6 +189,7 @@ typedef struct {
char *auth_methods[MAX_AUTH_METHODS]; char *auth_methods[MAX_AUTH_METHODS];
int fingerprint_hash; int fingerprint_hash;
int expose_userauth_info;
} ServerOptions; } ServerOptions;
/* Information about the incoming connection as used by Match */ /* Information about the incoming connection as used by Match */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.288 2017/05/31 09:15:42 deraadt Exp $ */ /* $OpenBSD: session.c,v 1.290 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -94,6 +94,7 @@
#include "kex.h" #include "kex.h"
#include "monitor_wrap.h" #include "monitor_wrap.h"
#include "sftp.h" #include "sftp.h"
#include "atomicio.h"
#if defined(KRB5) && defined(USE_AFS) #if defined(KRB5) && defined(USE_AFS)
#include <kafs.h> #include <kafs.h>
@ -134,7 +135,6 @@ static int session_pty_req(Session *);
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
extern char *__progname; extern char *__progname;
extern int log_stderr;
extern int debug_flag; extern int debug_flag;
extern u_int utmp_len; extern u_int utmp_len;
extern int startup_pipe; extern int startup_pipe;
@ -161,6 +161,9 @@ login_cap_t *lc;
static int is_child = 0; static int is_child = 0;
static int in_chroot = 0; static int in_chroot = 0;
/* File containing userauth info, if ExposeAuthInfo set */
static char *auth_info_file = NULL;
/* Name and directory of socket for authentication agent forwarding. */ /* Name and directory of socket for authentication agent forwarding. */
static char *auth_sock_name = NULL; static char *auth_sock_name = NULL;
static char *auth_sock_dir = NULL; static char *auth_sock_dir = NULL;
@ -255,6 +258,40 @@ display_loginmsg(void)
} }
} }
static void
prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
{
int fd = -1, success = 0;
if (!options.expose_userauth_info || info == NULL)
return;
temporarily_use_uid(pw);
auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
if ((fd = mkstemp(auth_info_file)) == -1) {
error("%s: mkstemp: %s", __func__, strerror(errno));
goto out;
}
if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
sshbuf_len(info)) != sshbuf_len(info)) {
error("%s: write: %s", __func__, strerror(errno));
goto out;
}
if (close(fd) != 0) {
error("%s: close: %s", __func__, strerror(errno));
goto out;
}
success = 1;
out:
if (!success) {
if (fd != -1)
close(fd);
free(auth_info_file);
auth_info_file = NULL;
}
restore_uid();
}
void void
do_authenticated(Authctxt *authctxt) do_authenticated(Authctxt *authctxt)
{ {
@ -270,7 +307,10 @@ do_authenticated(Authctxt *authctxt)
auth_debug_send(); auth_debug_send();
prepare_auth_info_file(authctxt->pw, authctxt->session_info);
do_authenticated2(authctxt); do_authenticated2(authctxt);
do_cleanup(authctxt); do_cleanup(authctxt);
} }
@ -641,10 +681,6 @@ do_exec_no_pty(Session *s, const char *command)
case 0: case 0:
is_child = 1; is_child = 1;
/* Child. Reinitialize the log since the pid has changed. */
log_init(__progname, options.log_level,
options.log_facility, log_stderr);
/* /*
* Create a new session and process group since the 4.4BSD * Create a new session and process group since the 4.4BSD
* setlogin() affects the entire process group. * setlogin() affects the entire process group.
@ -799,9 +835,6 @@ do_exec_pty(Session *s, const char *command)
close(fdout); close(fdout);
close(ptymaster); close(ptymaster);
/* Child. Reinitialize the log because the pid has changed. */
log_init(__progname, options.log_level,
options.log_facility, log_stderr);
/* Close the master side of the pseudo tty. */ /* Close the master side of the pseudo tty. */
close(ptyfd); close(ptyfd);
@ -1363,6 +1396,8 @@ do_setup_env(Session *s, const char *shell)
free(laddr); free(laddr);
child_set_env(&env, &envsize, "SSH_CONNECTION", buf); child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
if (auth_info_file != NULL)
child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
if (s->ttyfd != -1) if (s->ttyfd != -1)
child_set_env(&env, &envsize, "SSH_TTY", s->tty); child_set_env(&env, &envsize, "SSH_TTY", s->tty);
if (s->term) if (s->term)
@ -2840,6 +2875,15 @@ do_cleanup(Authctxt *authctxt)
/* remove agent socket */ /* remove agent socket */
auth_sock_cleanup_proc(authctxt->pw); auth_sock_cleanup_proc(authctxt->pw);
/* remove userauth info */
if (auth_info_file != NULL) {
temporarily_use_uid(authctxt->pw);
unlink(auth_info_file);
restore_uid();
free(auth_info_file);
auth_info_file = NULL;
}
/* /*
* Cleanup ptys/utmp only if privsep is disabled, * Cleanup ptys/utmp only if privsep is disabled,
* or if running in monitor. * or if running in monitor.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-common.c,v 1.29 2016/09/12 01:22:38 deraadt Exp $ */ /* $OpenBSD: sftp-common.c,v 1.30 2017/06/10 06:36:46 djm Exp $ */
/* /*
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Damien Miller. All rights reserved. * Copyright (c) 2001 Damien Miller. All rights reserved.
@ -216,22 +216,21 @@ ls_file(const char *name, const struct stat *st, int remote, int si_units)
int ulen, glen, sz = 0; int ulen, glen, sz = 0;
struct tm *ltime = localtime(&st->st_mtime); struct tm *ltime = localtime(&st->st_mtime);
char *user, *group; char *user, *group;
char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; char buf[1024], lc[8], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
char sbuf[FMT_SCALED_STRSIZE]; char sbuf[FMT_SCALED_STRSIZE];
time_t now; time_t now;
strmode(st->st_mode, mode); strmode(st->st_mode, mode);
if (!remote) { if (remote) {
user = user_from_uid(st->st_uid, 0);
} else {
snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
user = ubuf; user = ubuf;
}
if (!remote) {
group = group_from_gid(st->st_gid, 0);
} else {
snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
group = gbuf; group = gbuf;
strlcpy(lc, "?", sizeof(lc));
} else {
user = user_from_uid(st->st_uid, 0);
group = group_from_gid(st->st_gid, 0);
snprintf(lc, sizeof(lc), "%u", (u_int)st->st_nlink);
} }
if (ltime != NULL) { if (ltime != NULL) {
now = time(NULL); now = time(NULL);
@ -247,12 +246,12 @@ ls_file(const char *name, const struct stat *st, int remote, int si_units)
glen = MAXIMUM(strlen(group), 8); glen = MAXIMUM(strlen(group), 8);
if (si_units) { if (si_units) {
fmt_scaled((long long)st->st_size, sbuf); fmt_scaled((long long)st->st_size, sbuf);
snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8s %s %s", mode, snprintf(buf, sizeof buf, "%s %3s %-*s %-*s %8s %s %s",
(u_int)st->st_nlink, ulen, user, glen, group, mode, lc, ulen, user, glen, group,
sbuf, tbuf, name); sbuf, tbuf, name);
} else { } else {
snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, snprintf(buf, sizeof buf, "%s %3s %-*s %-*s %8llu %s %s",
(u_int)st->st_nlink, ulen, user, glen, group, mode, lc, ulen, user, glen, group,
(unsigned long long)st->st_size, tbuf, name); (unsigned long long)st->st_size, tbuf, name);
} }
return xstrdup(buf); return xstrdup(buf);

56
sftp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.179 2017/05/02 08:54:19 djm Exp $ */ /* $OpenBSD: sftp.c,v 1.180 2017/06/10 06:33:34 djm Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
* *
@ -106,6 +106,7 @@ volatile sig_atomic_t interrupted = 0;
/* I wish qsort() took a separate ctx for the comparison function...*/ /* I wish qsort() took a separate ctx for the comparison function...*/
int sort_flag; int sort_flag;
glob_t *sort_glob;
/* Context used for commandline completion */ /* Context used for commandline completion */
struct complete_ctx { struct complete_ctx {
@ -927,6 +928,34 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
return (0); return (0);
} }
static int
sglob_comp(const void *aa, const void *bb)
{
u_int a = *(const u_int *)aa;
u_int b = *(const u_int *)bb;
const char *ap = sort_glob->gl_pathv[a];
const char *bp = sort_glob->gl_pathv[b];
const struct stat *as = sort_glob->gl_statv[a];
const struct stat *bs = sort_glob->gl_statv[b];
int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
if (sort_flag & LS_NAME_SORT)
return (rmul * strcmp(ap, bp));
else if (sort_flag & LS_TIME_SORT) {
#if defined(HAVE_STRUCT_STAT_ST_MTIM)
return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <));
#elif defined(HAVE_STRUCT_STAT_ST_MTIME)
return (rmul * NCMP(as->st_mtime, bs->st_mtime));
#else
return rmul * 1;
#endif
} else if (sort_flag & LS_SIZE_SORT)
return (rmul * NCMP(as->st_size, bs->st_size));
fatal("Unknown ls sort type");
}
/* sftp ls.1 replacement which handles path globs */ /* sftp ls.1 replacement which handles path globs */
static int static int
do_globbed_ls(struct sftp_conn *conn, const char *path, do_globbed_ls(struct sftp_conn *conn, const char *path,
@ -936,7 +965,8 @@ do_globbed_ls(struct sftp_conn *conn, const char *path,
glob_t g; glob_t g;
int err, r; int err, r;
struct winsize ws; struct winsize ws;
u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; u_int i, j, nentries, *indices = NULL, c = 1;
u_int colspace = 0, columns = 1, m = 0, width = 80;
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
@ -981,7 +1011,26 @@ do_globbed_ls(struct sftp_conn *conn, const char *path,
colspace = width / columns; colspace = width / columns;
} }
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { /*
* Sorting: rather than mess with the contents of glob_t, prepare
* an array of indices into it and sort that. For the usual
* unsorted case, the indices are just the identity 1=1, 2=2, etc.
*/
for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++)
; /* count entries */
indices = calloc(nentries, sizeof(*indices));
for (i = 0; i < nentries; i++)
indices[i] = i;
if (lflag & SORT_FLAGS) {
sort_glob = &g;
sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
qsort(indices, nentries, sizeof(*indices), sglob_comp);
sort_glob = NULL;
}
for (j = 0; j < nentries && !interrupted; j++) {
i = indices[j];
fname = path_strip(g.gl_pathv[i], strip_path); fname = path_strip(g.gl_pathv[i], strip_path);
if (lflag & LS_LONG_VIEW) { if (lflag & LS_LONG_VIEW) {
if (g.gl_statv[i] == NULL) { if (g.gl_statv[i] == NULL) {
@ -1009,6 +1058,7 @@ do_globbed_ls(struct sftp_conn *conn, const char *path,
out: out:
if (g.gl_pathc) if (g.gl_pathc)
globfree(&g); globfree(&g);
free(indices);
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */ /* $OpenBSD: ssh-gss.h,v 1.12 2017/06/24 06:34:38 djm Exp $ */
/* /*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
* *
@ -128,6 +128,7 @@ OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
void ssh_gssapi_do_child(char ***, u_int *); void ssh_gssapi_do_child(char ***, u_int *);
void ssh_gssapi_cleanup_creds(void); void ssh_gssapi_cleanup_creds(void);
void ssh_gssapi_storecreds(void); void ssh_gssapi_storecreds(void);
const char *ssh_gssapi_displayname(void);
#endif /* GSSAPI */ #endif /* GSSAPI */

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.141 2017/05/05 10:41:58 naddy Exp $ .\" $OpenBSD: ssh-keygen.1,v 1.142 2017/06/28 01:09:22 djm Exp $
.\" .\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd $Mdocdate: May 5 2017 $ .Dd $Mdocdate: June 28 2017 $
.Dt SSH-KEYGEN 1 .Dt SSH-KEYGEN 1
.Os .Os
.Sh NAME .Sh NAME
@ -114,6 +114,8 @@
.Fl s Ar ca_key .Fl s Ar ca_key
.Fl I Ar certificate_identity .Fl I Ar certificate_identity
.Op Fl h .Op Fl h
.Op Fl U
.Op Fl D Ar pkcs11_provider
.Op Fl n Ar principals .Op Fl n Ar principals
.Op Fl O Ar option .Op Fl O Ar option
.Op Fl V Ar validity_interval .Op Fl V Ar validity_interval
@ -558,6 +560,14 @@ The possible values are
.Dq ed25519 , .Dq ed25519 ,
or or
.Dq rsa . .Dq rsa .
.It Fl U
When used in combination with
.Fl s ,
this option indicates that a CA key resides in a
.Xr ssh-agent 1 .
See the
.Sx CERTIFICATES
section for more information.
.It Fl u .It Fl u
Update a KRL. Update a KRL.
When specified with When specified with
@ -705,6 +715,14 @@ to
.Pp .Pp
.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub .Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub
.Pp .Pp
Similarly, it is possible for the CA key to be hosted in a
.Xr ssh-agent 1 .
This is indicated by the
.Fl U
flag and, again, the CA key must be identified by its public half.
.Pp
.Dl $ ssh-keygen -Us ca_key.pub -I key_id user_key.pub
.Pp
In all cases, In all cases,
.Ar key_id .Ar key_id
is a "key identifier" that is logged by the server when the certificate is a "key identifier" that is logged by the server when the certificate

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.304 2017/05/30 14:16:41 markus Exp $ */ /* $OpenBSD: ssh-keygen.c,v 1.305 2017/06/28 01:09:22 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -59,6 +59,7 @@
#include "krl.h" #include "krl.h"
#include "digest.h" #include "digest.h"
#include "utf8.h" #include "utf8.h"
#include "authfd.h"
#include "sshfileperm.h" #include "sshfileperm.h"
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
@ -122,6 +123,9 @@ char *identity_comment = NULL;
/* Path to CA key when certifying keys. */ /* Path to CA key when certifying keys. */
char *ca_key_path = NULL; char *ca_key_path = NULL;
/* Prefer to use agent keys for CA signing */
int prefer_agent = 0;
/* Certificate serial number */ /* Certificate serial number */
unsigned long long cert_serial = 0; unsigned long long cert_serial = 0;
@ -1615,24 +1619,66 @@ load_pkcs11_key(char *path)
#endif /* ENABLE_PKCS11 */ #endif /* ENABLE_PKCS11 */
} }
/* Signer for sshkey_certify_custom that uses the agent */
static int
agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen,
const char *alg, u_int compat, void *ctx)
{
int *agent_fdp = (int *)ctx;
return ssh_agent_sign(*agent_fdp, key, sigp, lenp,
data, datalen, alg, compat);
}
static void static void
do_ca_sign(struct passwd *pw, int argc, char **argv) do_ca_sign(struct passwd *pw, int argc, char **argv)
{ {
int r, i, fd; int r, i, fd, found, agent_fd = -1;
u_int n; u_int n;
struct sshkey *ca, *public; struct sshkey *ca, *public;
char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL;
FILE *f; FILE *f;
struct ssh_identitylist *agent_ids;
size_t j;
#ifdef ENABLE_PKCS11 #ifdef ENABLE_PKCS11
pkcs11_init(1); pkcs11_init(1);
#endif #endif
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
if (pkcs11provider != NULL) { if (pkcs11provider != NULL) {
/* If a PKCS#11 token was specified then try to use it */
if ((ca = load_pkcs11_key(tmp)) == NULL) if ((ca = load_pkcs11_key(tmp)) == NULL)
fatal("No PKCS#11 key matching %s found", ca_key_path); fatal("No PKCS#11 key matching %s found", ca_key_path);
} else } else if (prefer_agent) {
/*
* Agent signature requested. Try to use agent after making
* sure the public key specified is actually present in the
* agent.
*/
if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
fatal("Cannot load CA public key %s: %s",
tmp, ssh_err(r));
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
fatal("Cannot use public key for CA signature: %s",
ssh_err(r));
if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0)
fatal("Retrieve agent key list: %s", ssh_err(r));
found = 0;
for (j = 0; j < agent_ids->nkeys; j++) {
if (sshkey_equal(ca, agent_ids->keys[j])) {
found = 1;
break;
}
}
if (!found)
fatal("CA key %s not found in agent", tmp);
ssh_free_identitylist(agent_ids);
ca->flags |= SSHKEY_FLAG_EXT;
} else {
/* CA key is assumed to be a private key on the filesystem */
ca = load_identity(tmp); ca = load_identity(tmp);
}
free(tmp); free(tmp);
if (key_type_name != NULL && if (key_type_name != NULL &&
@ -1682,8 +1728,16 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
&public->cert->signature_key)) != 0) &public->cert->signature_key)) != 0)
fatal("sshkey_from_private (ca key): %s", ssh_err(r)); fatal("sshkey_from_private (ca key): %s", ssh_err(r));
if ((r = sshkey_certify(public, ca, key_type_name)) != 0) if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
fatal("Couldn't certify key %s: %s", tmp, ssh_err(r)); if ((r = sshkey_certify_custom(public, ca,
key_type_name, agent_signer, &agent_fd)) != 0)
fatal("Couldn't certify key %s via agent: %s",
tmp, ssh_err(r));
} else {
if ((sshkey_certify(public, ca, key_type_name)) != 0)
fatal("Couldn't certify key %s: %s",
tmp, ssh_err(r));
}
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
*cp = '\0'; *cp = '\0';
@ -2279,8 +2333,9 @@ usage(void)
" ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n"
" [-j start_line] [-K checkpt] [-W generator]\n" " [-j start_line] [-K checkpt] [-W generator]\n"
#endif #endif
" ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n" " ssh-keygen -s ca_key -I certificate_identity [-h] [-U]\n"
" [-O option] [-V validity_interval] [-z serial_number] file ...\n" " [-D pkcs11_provider] [-n principals] [-O option]\n"
" [-V validity_interval] [-z serial_number] file ...\n"
" ssh-keygen -L [-f input_keyfile]\n" " ssh-keygen -L [-f input_keyfile]\n"
" ssh-keygen -A\n" " ssh-keygen -A\n"
" ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
@ -2338,8 +2393,8 @@ main(int argc, char **argv)
if (gethostname(hostname, sizeof(hostname)) < 0) if (gethostname(hostname, sizeof(hostname)) < 0)
fatal("gethostname: %s", strerror(errno)); fatal("gethostname: %s", strerror(errno));
/* Remaining characters: UYdw */ /* Remaining characters: Ydw */
while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy"
"C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:"
"a:b:f:g:j:m:n:r:s:t:z:")) != -1) { "a:b:f:g:j:m:n:r:s:t:z:")) != -1) {
switch (opt) { switch (opt) {
@ -2466,6 +2521,9 @@ main(int argc, char **argv)
case 'D': case 'D':
pkcs11provider = optarg; pkcs11provider = optarg;
break; break;
case 'U':
prefer_agent = 1;
break;
case 'u': case 'u':
update_krl = 1; update_krl = 1;
break; break;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keyscan.c,v 1.114 2017/05/31 07:00:13 markus Exp $ */ /* $OpenBSD: ssh-keyscan.c,v 1.115 2017/06/30 04:17:23 dtucker Exp $ */
/* /*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
* *
@ -395,7 +395,6 @@ confree(int s)
{ {
if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
fatal("confree: attempt to free bad fdno %d", s); fatal("confree: attempt to free bad fdno %d", s);
free(fdcon[s].c_namebase); free(fdcon[s].c_namebase);
free(fdcon[s].c_output_name); free(fdcon[s].c_output_name);
if (fdcon[s].c_status == CS_KEYS) if (fdcon[s].c_status == CS_KEYS)

15
ssh.1
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: ssh.1,v 1.382 2017/05/30 18:58:37 bluhm Exp $ .\" $OpenBSD: ssh.1,v 1.383 2017/06/09 06:43:01 djm Exp $
.Dd $Mdocdate: May 30 2017 $ .Dd $Mdocdate: June 9 2017 $
.Dt SSH 1 .Dt SSH 1
.Os .Os
.Sh NAME .Sh NAME
@ -846,6 +846,17 @@ The client proves that it has access to the private key
and the server checks that the corresponding public key and the server checks that the corresponding public key
is authorized to accept the account. is authorized to accept the account.
.Pp .Pp
The server may inform the client of errors that prevented public key
authentication from succeeding after authentication completes using a
different method.
These may be viewed by increasing the
.Cm LogLevel
to
.Cm DEBUG
or higher (e.g. by using the
.Fl v
flag).
.Pp
The user creates his/her key pair by running The user creates his/her key pair by running
.Xr ssh-keygen 1 . .Xr ssh-keygen 1 .
This stores the private key in This stores the private key in

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: ssh_config.5,v 1.250 2017/05/30 19:38:17 jmc Exp $ .\" $OpenBSD: ssh_config.5,v 1.251 2017/06/24 05:35:05 djm Exp $
.Dd $Mdocdate: May 30 2017 $ .Dd $Mdocdate: June 24 2017 $
.Dt SSH_CONFIG 5 .Dt SSH_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -809,7 +809,7 @@ The list of available key types may also be obtained using
.It Cm HostKeyAlias .It Cm HostKeyAlias
Specifies an alias that should be used instead of the Specifies an alias that should be used instead of the
real host name when looking up or saving the host key real host name when looking up or saving the host key
in the host key database files. in the host key database files and when validating host certificates.
This option is useful for tunneling SSH connections This option is useful for tunneling SSH connections
or for multiple servers running on a single host. or for multiple servers running on a single host.
.It Cm HostName .It Cm HostName

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.c,v 1.280 2017/05/30 14:13:40 markus Exp $ */ /* $OpenBSD: sshconnect.c,v 1.282 2017/06/24 05:37:44 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -34,6 +34,9 @@
#include <paths.h> #include <paths.h>
#endif #endif
#include <pwd.h> #include <pwd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <signal.h> #include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -344,87 +347,71 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
return sock; return sock;
} }
/*
* Wait up to *timeoutp milliseconds for fd to be readable. Updates
* *timeoutp with time remaining.
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
static int
waitrfd(int fd, int *timeoutp)
{
struct pollfd pfd;
struct timeval t_start;
int oerrno, r;
gettimeofday(&t_start, NULL);
pfd.fd = fd;
pfd.events = POLLIN;
for (; *timeoutp >= 0;) {
r = poll(&pfd, 1, *timeoutp);
oerrno = errno;
ms_subtract_diff(&t_start, timeoutp);
errno = oerrno;
if (r > 0)
return 0;
else if (r == -1 && errno != EAGAIN)
return -1;
else if (r == 0)
break;
}
/* timeout */
errno = ETIMEDOUT;
return -1;
}
static int static int
timeout_connect(int sockfd, const struct sockaddr *serv_addr, timeout_connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen, int *timeoutp) socklen_t addrlen, int *timeoutp)
{ {
fd_set *fdset; int optval = 0;
struct timeval tv, t_start; socklen_t optlen = sizeof(optval);
socklen_t optlen;
int optval, rc, result = -1;
gettimeofday(&t_start, NULL); /* No timeout: just do a blocking connect() */
if (*timeoutp <= 0)
if (*timeoutp <= 0) { return connect(sockfd, serv_addr, addrlen);
result = connect(sockfd, serv_addr, addrlen);
goto done;
}
set_nonblock(sockfd); set_nonblock(sockfd);
rc = connect(sockfd, serv_addr, addrlen); if (connect(sockfd, serv_addr, addrlen) == 0) {
if (rc == 0) { /* Succeeded already? */
unset_nonblock(sockfd); unset_nonblock(sockfd);
result = 0; return 0;
goto done; } else if (errno != EINPROGRESS)
return -1;
if (waitrfd(sockfd, timeoutp) == -1)
return -1;
/* Completed or failed */
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
debug("getsockopt: %s", strerror(errno));
return -1;
} }
if (errno != EINPROGRESS) { if (optval != 0) {
result = -1; errno = optval;
goto done; return -1;
} }
unset_nonblock(sockfd);
fdset = xcalloc(howmany(sockfd + 1, NFDBITS), return 0;
sizeof(fd_mask));
FD_SET(sockfd, fdset);
ms_to_timeval(&tv, *timeoutp);
for (;;) {
rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
if (rc != -1 || errno != EINTR)
break;
}
switch (rc) {
case 0:
/* Timed out */
errno = ETIMEDOUT;
break;
case -1:
/* Select error */
debug("select: %s", strerror(errno));
break;
case 1:
/* Completed or failed */
optval = 0;
optlen = sizeof(optval);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
&optlen) == -1) {
debug("getsockopt: %s", strerror(errno));
break;
}
if (optval != 0) {
errno = optval;
break;
}
result = 0;
unset_nonblock(sockfd);
break;
default:
/* Should not occur */
fatal("Bogus return (%d) from select()", rc);
}
free(fdset);
done:
if (result == 0 && *timeoutp > 0) {
ms_subtract_diff(&t_start, timeoutp);
if (*timeoutp <= 0) {
errno = ETIMEDOUT;
result = -1;
}
}
return (result);
} }
/* /*
@ -562,42 +549,25 @@ ssh_exchange_identification(int timeout_ms)
int connection_out = packet_get_connection_out(); int connection_out = packet_get_connection_out();
u_int i, n; u_int i, n;
size_t len; size_t len;
int fdsetsz, remaining, rc; int rc;
struct timeval t_start, t_remaining;
fd_set *readfds;
fd_set *exceptfds;
fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
readfds = xcalloc(1, fdsetsz);
exceptfds = xcalloc(1, fdsetsz);
send_client_banner(connection_out, 0); send_client_banner(connection_out, 0);
/* Read other side's version identification. */ /* Read other side's version identification. */
remaining = timeout_ms;
for (n = 0;;) { for (n = 0;;) {
for (i = 0; i < sizeof(buf) - 1; i++) { for (i = 0; i < sizeof(buf) - 1; i++) {
if (timeout_ms > 0) { if (timeout_ms > 0) {
gettimeofday(&t_start, NULL); rc = waitrfd(connection_in, &timeout_ms);
ms_to_timeval(&t_remaining, remaining); if (rc == -1 && errno == ETIMEDOUT) {
FD_SET(connection_in, readfds);
FD_SET(connection_in, exceptfds);
rc = select(connection_in + 1, readfds, NULL,
exceptfds, &t_remaining);
ms_subtract_diff(&t_start, &remaining);
if (rc == 0 || remaining <= 0)
fatal("Connection timed out during " fatal("Connection timed out during "
"banner exchange"); "banner exchange");
if (rc == -1) { } else if (rc == -1) {
if (errno == EINTR) fatal("%s: %s",
continue; __func__, strerror(errno));
fatal("ssh_exchange_identification: "
"select: %s", strerror(errno));
} }
} }
len = atomicio(read, connection_in, &buf[i], 1); len = atomicio(read, connection_in, &buf[i], 1);
if (len != 1 && errno == EPIPE) if (len != 1 && errno == EPIPE)
fatal("ssh_exchange_identification: " fatal("ssh_exchange_identification: "
"Connection closed by remote host"); "Connection closed by remote host");
@ -623,8 +593,6 @@ ssh_exchange_identification(int timeout_ms)
debug("ssh_exchange_identification: %s", buf); debug("ssh_exchange_identification: %s", buf);
} }
server_version_string = xstrdup(buf); server_version_string = xstrdup(buf);
free(readfds);
free(exceptfds);
/* /*
* Check that the versions match. In future this might accept * Check that the versions match. In future this might accept
@ -883,7 +851,9 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
host, type, want_cert ? "certificate" : "key"); host, type, want_cert ? "certificate" : "key");
debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
host_found->file, host_found->line); host_found->file, host_found->line);
if (want_cert && !check_host_cert(hostname, host_key)) if (want_cert &&
!check_host_cert(options.host_key_alias == NULL ?
hostname : options.host_key_alias, host_key))
goto fail; goto fail;
if (options.check_host_ip && ip_status == HOST_NEW) { if (options.check_host_ip && ip_status == HOST_NEW) {
if (readonly || want_cert) if (readonly || want_cert)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect2.c,v 1.263 2017/05/31 07:00:13 markus Exp $ */ /* $OpenBSD: sshconnect2.c,v 1.264 2017/06/14 00:31:38 dtucker Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved.
@ -474,7 +474,8 @@ userauth(Authctxt *authctxt, char *authlist)
for (;;) { for (;;) {
Authmethod *method = authmethod_get(authlist); Authmethod *method = authmethod_get(authlist);
if (method == NULL) if (method == NULL)
fatal("Permission denied (%s).", authlist); fatal("%s@%s: Permission denied (%s).",
authctxt->server_user, authctxt->host, authlist);
authctxt->method = method; authctxt->method = method;
/* reset the per method handler */ /* reset the per method handler */

24
sshd.8
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd.8,v 1.289 2017/05/07 23:12:57 djm Exp $ .\" $OpenBSD: sshd.8,v 1.291 2017/06/24 06:28:50 jmc Exp $
.Dd $Mdocdate: May 7 2017 $ .Dd $Mdocdate: June 24 2017 $
.Dt SSHD 8 .Dt SSHD 8
.Os .Os
.Sh NAME .Sh NAME
@ -652,9 +652,23 @@ Hostnames is a comma-separated list of patterns
and and
.Ql \&? .Ql \&?
act as act as
wildcards); each pattern in turn is matched against the canonical host wildcards); each pattern in turn is matched against the host name.
name (when authenticating a client) or against the user-supplied When
name (when authenticating a server). .Nm sshd
is authenticating a client, such as when using
.Cm HostbasedAuthentication ,
this will be the canonical client host name.
When
.Xr ssh 1
is authenticating a server, this will be the host name
given by the user, the value of the
.Xr ssh 1
.Cm HostkeyAlias
if it was specified, or the canonical server hostname if the
.Xr ssh 1
.Cm CanonicalizeHostname
option was used.
.Pp
A pattern may also be preceded by A pattern may also be preceded by
.Ql \&! .Ql \&!
to indicate negation: if the host name matches a negated to indicate negation: if the host name matches a negated

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd_config.5,v 1.245 2017/05/17 01:24:17 djm Exp $ .\" $OpenBSD: sshd_config.5,v 1.248 2017/06/24 07:08:57 djm Exp $
.Dd $Mdocdate: May 17 2017 $ .Dd $Mdocdate: June 24 2017 $
.Dt SSHD_CONFIG 5 .Dt SSHD_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -564,6 +564,12 @@ Disables all forwarding features, including X11,
TCP and StreamLocal. TCP and StreamLocal.
This option overrides all other forwarding-related options and may This option overrides all other forwarding-related options and may
simplify restricted configurations. simplify restricted configurations.
.It Cm ExposeAuthInfo
Enables writing a file containing a list of authentication methods and
public credentials (e.g. keys) used to authenticate the user.
The location of the file is exposed to the user session through the
.Ev SSH_USER_AUTH
environment variable.
.It Cm FingerprintHash .It Cm FingerprintHash
Specifies the hash algorithm used when logging key fingerprints. Specifies the hash algorithm used when logging key fingerprints.
Valid options are: Valid options are:

127
sshkey.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshkey.c,v 1.51 2017/05/31 09:15:42 deraadt Exp $ */ /* $OpenBSD: sshkey.c,v 1.53 2017/06/28 01:09:22 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@ -1331,7 +1331,7 @@ sshkey_to_base64(const struct sshkey *key, char **b64p)
return r; return r;
} }
static int int
sshkey_format_text(const struct sshkey *key, struct sshbuf *b) sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
{ {
int r = SSH_ERR_INTERNAL_ERROR; int r = SSH_ERR_INTERNAL_ERROR;
@ -2253,7 +2253,8 @@ sshkey_drop_cert(struct sshkey *k)
/* Sign a certified key, (re-)generating the signed certblob. */ /* Sign a certified key, (re-)generating the signed certblob. */
int int
sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg) sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
sshkey_certify_signer *signer, void *signer_ctx)
{ {
struct sshbuf *principals = NULL; struct sshbuf *principals = NULL;
u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
@ -2342,8 +2343,8 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
goto out; goto out;
/* Sign the whole mess */ /* Sign the whole mess */
if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
sshbuf_len(cert), alg, 0)) != 0) sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
goto out; goto out;
/* Append signature and we are done */ /* Append signature and we are done */
@ -2359,6 +2360,22 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
return ret; return ret;
} }
static int
default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen,
const char *alg, u_int compat, void *ctx)
{
if (ctx != NULL)
return SSH_ERR_INVALID_ARGUMENT;
return sshkey_sign(key, sigp, lenp, data, datalen, alg, compat);
}
int
sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
{
return sshkey_certify_custom(k, ca, alg, default_key_sign, NULL);
}
int int
sshkey_cert_check_authority(const struct sshkey *k, sshkey_cert_check_authority(const struct sshkey *k,
int want_host, int require_principal, int want_host, int require_principal,
@ -3365,6 +3382,64 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
static int
translate_libcrypto_error(unsigned long pem_err)
{
int pem_reason = ERR_GET_REASON(pem_err);
switch (ERR_GET_LIB(pem_err)) {
case ERR_LIB_PEM:
switch (pem_reason) {
case PEM_R_BAD_PASSWORD_READ:
case PEM_R_PROBLEMS_GETTING_PASSWORD:
case PEM_R_BAD_DECRYPT:
return SSH_ERR_KEY_WRONG_PASSPHRASE;
default:
return SSH_ERR_INVALID_FORMAT;
}
case ERR_LIB_EVP:
switch (pem_reason) {
case EVP_R_BAD_DECRYPT:
return SSH_ERR_KEY_WRONG_PASSPHRASE;
case EVP_R_BN_DECODE_ERROR:
case EVP_R_DECODE_ERROR:
#ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
case EVP_R_PRIVATE_KEY_DECODE_ERROR:
#endif
return SSH_ERR_INVALID_FORMAT;
default:
return SSH_ERR_LIBCRYPTO_ERROR;
}
case ERR_LIB_ASN1:
return SSH_ERR_INVALID_FORMAT;
}
return SSH_ERR_LIBCRYPTO_ERROR;
}
static void
clear_libcrypto_errors(void)
{
while (ERR_get_error() != 0)
;
}
/*
* Translate OpenSSL error codes to determine whether
* passphrase is required/incorrect.
*/
static int
convert_libcrypto_error(void)
{
/*
* Some password errors are reported at the beginning
* of the error queue.
*/
if (translate_libcrypto_error(ERR_peek_error()) ==
SSH_ERR_KEY_WRONG_PASSPHRASE)
return SSH_ERR_KEY_WRONG_PASSPHRASE;
return translate_libcrypto_error(ERR_peek_last_error());
}
static int static int
sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
const char *passphrase, struct sshkey **keyp) const char *passphrase, struct sshkey **keyp)
@ -3385,48 +3460,10 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
goto out; goto out;
} }
clear_libcrypto_errors();
if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
(char *)passphrase)) == NULL) { (char *)passphrase)) == NULL) {
unsigned long pem_err = ERR_peek_last_error(); r = convert_libcrypto_error();
int pem_reason = ERR_GET_REASON(pem_err);
/*
* Translate OpenSSL error codes to determine whether
* passphrase is required/incorrect.
*/
switch (ERR_GET_LIB(pem_err)) {
case ERR_LIB_PEM:
switch (pem_reason) {
case PEM_R_BAD_PASSWORD_READ:
case PEM_R_PROBLEMS_GETTING_PASSWORD:
case PEM_R_BAD_DECRYPT:
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
default:
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
case ERR_LIB_EVP:
switch (pem_reason) {
case EVP_R_BAD_DECRYPT:
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
case EVP_R_BN_DECODE_ERROR:
case EVP_R_DECODE_ERROR:
#ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
case EVP_R_PRIVATE_KEY_DECODE_ERROR:
#endif
r = SSH_ERR_INVALID_FORMAT;
goto out;
default:
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
case ERR_LIB_ASN1:
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out; goto out;
} }
if (pk->type == EVP_PKEY_RSA && if (pk->type == EVP_PKEY_RSA &&

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshkey.h,v 1.18 2017/05/07 23:15:59 djm Exp $ */ /* $OpenBSD: sshkey.h,v 1.20 2017/06/28 01:09:22 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -124,6 +124,7 @@ int sshkey_fingerprint_raw(const struct sshkey *k,
int, u_char **retp, size_t *lenp); int, u_char **retp, size_t *lenp);
const char *sshkey_type(const struct sshkey *); const char *sshkey_type(const struct sshkey *);
const char *sshkey_cert_type(const struct sshkey *); const char *sshkey_cert_type(const struct sshkey *);
int sshkey_format_text(const struct sshkey *, struct sshbuf *);
int sshkey_write(const struct sshkey *, FILE *); int sshkey_write(const struct sshkey *, FILE *);
int sshkey_read(struct sshkey *, char **); int sshkey_read(struct sshkey *, char **);
u_int sshkey_size(const struct sshkey *); u_int sshkey_size(const struct sshkey *);
@ -136,13 +137,19 @@ int sshkey_type_is_cert(int);
int sshkey_type_plain(int); int sshkey_type_plain(int);
int sshkey_to_certified(struct sshkey *); int sshkey_to_certified(struct sshkey *);
int sshkey_drop_cert(struct sshkey *); int sshkey_drop_cert(struct sshkey *);
int sshkey_certify(struct sshkey *, struct sshkey *, const char *);
int sshkey_cert_copy(const struct sshkey *, struct sshkey *); int sshkey_cert_copy(const struct sshkey *, struct sshkey *);
int sshkey_cert_check_authority(const struct sshkey *, int, int, int sshkey_cert_check_authority(const struct sshkey *, int, int,
const char *, const char **); const char *, const char **);
size_t sshkey_format_cert_validity(const struct sshkey_cert *, size_t sshkey_format_cert_validity(const struct sshkey_cert *,
char *, size_t) __attribute__((__bounded__(__string__, 2, 3))); char *, size_t) __attribute__((__bounded__(__string__, 2, 3)));
int sshkey_certify(struct sshkey *, struct sshkey *, const char *);
/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */
typedef int sshkey_certify_signer(const struct sshkey *, u_char **, size_t *,
const u_char *, size_t, const char *, u_int, void *);
int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *,
sshkey_certify_signer *, void *);
int sshkey_ecdsa_nid_from_name(const char *); int sshkey_ecdsa_nid_from_name(const char *);
int sshkey_curve_name_to_nid(const char *); int sshkey_curve_name_to_nid(const char *);
const char * sshkey_curve_nid_to_name(int); const char * sshkey_curve_nid_to_name(int);