From dceabc7ad7ebc7769c8214a1647af64c9a1d92e5 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 5 Oct 2017 15:52:03 +0000 Subject: upstream commit replace statically-sized arrays in ServerOptions with dynamic ones managed by xrecallocarray, removing some arbitrary (though large) limits and saving a bit of memory; "much nicer" markus@ Upstream-ID: 1732720b2f478fe929d6687ac7b0a97ff2efe9d2 --- monitor_wrap.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'monitor_wrap.c') diff --git a/monitor_wrap.c b/monitor_wrap.c index 69212aaf3..a46628fb1 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.94 2017/10/02 19:33:20 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.95 2017/10/05 15:52:03 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -287,19 +287,15 @@ out: newopts->x = buffer_get_string(&m, NULL); \ } while (0) #define M_CP_STRARRAYOPT(x, nx) do { \ - for (i = 0; i < newopts->nx; i++) \ - newopts->x[i] = buffer_get_string(&m, NULL); \ - } while (0) -#define M_CP_STRARRAYOPT_ALLOC(x, nx) do { \ newopts->x = newopts->nx == 0 ? \ NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \ - M_CP_STRARRAYOPT(x, nx); \ + for (i = 0; i < newopts->nx; i++) \ + newopts->x[i] = buffer_get_string(&m, NULL); \ } while (0) /* See comment in servconf.h */ COPY_MATCH_STRING_OPTS(); #undef M_CP_STROPT #undef M_CP_STRARRAYOPT -#undef M_CP_STRARRAYOPT_ALLOC copy_set_server_options(&options, newopts, 1); log_change_level(options.log_level); -- cgit v1.2.3 From 04c7e28f83062dc42f2380d1bb3a6bf0190852c0 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Dec 2017 02:25:15 +0000 Subject: upstream commit pass negotiated signing algorithm though to sshkey_verify() and check that the negotiated algorithm matches the type in the signature (only matters for RSA SHA1/SHA2 sigs). ok markus@ OpenBSD-Commit-ID: 735fb15bf4adc060d3bee9d047a4bcaaa81b1af9 --- auth2-hostbased.c | 4 ++-- auth2-pubkey.c | 4 ++-- clientloop.c | 5 +++-- hash.c | 2 ++ kexc25519c.c | 4 ++-- kexdhc.c | 4 ++-- kexecdhc.c | 4 ++-- kexgexc.c | 4 ++-- key.c | 17 +---------------- key.h | 3 +-- krl.c | 4 ++-- monitor.c | 8 +++++--- monitor_wrap.c | 5 +++-- monitor_wrap.h | 4 ++-- serverloop.c | 5 +++-- ssh-keygen.c | 4 ++-- ssh-rsa.c | 19 +++++++++++++------ sshkey.c | 9 +++++---- sshkey.h | 7 ++++--- 19 files changed, 58 insertions(+), 58 deletions(-) (limited to 'monitor_wrap.c') diff --git a/auth2-hostbased.c b/auth2-hostbased.c index 92758b38c..8112cfaa3 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.32 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -144,7 +144,7 @@ userauth_hostbased(struct ssh *ssh) authenticated = 0; if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && PRIVSEP(sshkey_verify(key, sig, slen, - sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0) + sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat)) == 0) authenticated = 1; auth2_record_key(authctxt, authenticated, key); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 169839b01..0707b8ab3 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.72 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -198,7 +198,7 @@ userauth_pubkey(struct ssh *ssh) authenticated = 0; if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), - sshbuf_len(b), ssh->compat)) == 0) { + sshbuf_len(b), pkalg, ssh->compat)) == 0) { authenticated = 1; } sshbuf_free(b); diff --git a/clientloop.c b/clientloop.c index e3824ccd9..3ce5d930e 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.307 2017/11/25 05:58:47 dtucker Exp $ */ +/* $OpenBSD: clientloop.c,v 1.308 2017/12/18 02:25:15 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1934,7 +1934,8 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type, goto out; } if ((r = sshkey_verify(ctx->keys[i], sig, siglen, - sshbuf_ptr(signdata), sshbuf_len(signdata), 0)) != 0) { + sshbuf_ptr(signdata), sshbuf_len(signdata), + ssh->kex->hostkey_alg, 0)) != 0) { error("%s: server gave bad signature for %s key %zu", __func__, sshkey_type(ctx->keys[i]), i); goto out; diff --git a/hash.c b/hash.c index bc87808a3..21f464e67 100644 --- a/hash.c +++ b/hash.c @@ -1,5 +1,7 @@ /* $OpenBSD: hash.c,v 1.4 2017/12/14 21:07:39 naddy Exp $ */ +#include "includes.h" + #include "crypto_api.h" #include diff --git a/kexc25519c.c b/kexc25519c.c index e488013e9..a8d92149c 100644 --- a/kexc25519c.c +++ b/kexc25519c.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519c.c,v 1.8 2017/05/31 04:17:12 djm Exp $ */ +/* $OpenBSD: kexc25519c.c,v 1.9 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -141,7 +141,7 @@ input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, - ssh->compat)) != 0) + kex->hostkey_alg, ssh->compat)) != 0) goto out; /* save session id */ diff --git a/kexdhc.c b/kexdhc.c index 9864ee2ec..5e1a353a5 100644 --- a/kexdhc.c +++ b/kexdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdhc.c,v 1.20 2017/05/30 14:23:52 markus Exp $ */ +/* $OpenBSD: kexdhc.c,v 1.21 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -183,7 +183,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, - ssh->compat)) != 0) + kex->hostkey_alg, ssh->compat)) != 0) goto out; /* save session id */ diff --git a/kexecdhc.c b/kexecdhc.c index d8a8b660f..67669b3bf 100644 --- a/kexecdhc.c +++ b/kexecdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexecdhc.c,v 1.11 2017/05/30 14:23:52 markus Exp $ */ +/* $OpenBSD: kexecdhc.c,v 1.12 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -188,7 +188,7 @@ input_kex_ecdh_reply(int type, u_int32_t seq, struct ssh *ssh) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, - hashlen, ssh->compat)) != 0) + hashlen, kex->hostkey_alg, ssh->compat)) != 0) goto out; /* save session id */ diff --git a/kexgexc.c b/kexgexc.c index cd1128752..6f8cf48a6 100644 --- a/kexgexc.c +++ b/kexgexc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexc.c,v 1.25 2017/05/30 14:23:52 markus Exp $ */ +/* $OpenBSD: kexgexc.c,v 1.26 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -230,7 +230,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, - hashlen, ssh->compat)) != 0) + hashlen, kex->hostkey_alg, ssh->compat)) != 0) goto out; /* save session id */ diff --git a/key.c b/key.c index 6e338c495..a05fdd3c0 100644 --- a/key.c +++ b/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.131 2017/05/30 14:16:41 markus Exp $ */ +/* $OpenBSD: key.c,v 1.132 2017/12/18 02:25:15 djm Exp $ */ /* * placed in the public domain */ @@ -95,21 +95,6 @@ key_sign(const Key *key, u_char **sigp, u_int *lenp, return 0; } -int -key_verify(const Key *key, const u_char *signature, u_int signaturelen, - const u_char *data, u_int datalen) -{ - int r; - - if ((r = sshkey_verify(key, signature, signaturelen, - data, datalen, datafellows)) != 0) { - fatal_on_fatal_errors(r, __func__, 0); - error("%s: %s", __func__, ssh_err(r)); - return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1; - } - return 1; -} - Key * key_demote(const Key *k) { diff --git a/key.h b/key.h index a14f37037..fd59cbf54 100644 --- a/key.h +++ b/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.51 2017/05/30 14:16:41 markus Exp $ */ +/* $OpenBSD: key.h,v 1.52 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -58,7 +58,6 @@ int key_to_blob(const Key *, u_char **, u_int *); int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int, const char *); -int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); /* authfile.c */ Key *key_load_cert(const char *); diff --git a/krl.c b/krl.c index 086fc20e5..379153247 100644 --- a/krl.c +++ b/krl.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $OpenBSD: krl.c,v 1.40 2017/05/31 09:15:42 deraadt Exp $ */ +/* $OpenBSD: krl.c,v 1.41 2017/12/18 02:25:15 djm Exp $ */ #include "includes.h" @@ -1014,7 +1014,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, } /* Check signature over entire KRL up to this point */ if ((r = sshkey_verify(key, blob, blen, - sshbuf_ptr(buf), sig_off, 0)) != 0) + sshbuf_ptr(buf), sig_off, NULL, 0)) != 0) goto out; /* Check if this key has already signed this KRL */ for (i = 0; i < nca_used; i++) { diff --git a/monitor.c b/monitor.c index a0ad9857d..5b8f0ef65 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.175 2017/10/05 15:52:03 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.176 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -1339,12 +1339,14 @@ mm_answer_keyverify(int sock, struct sshbuf *m) { struct sshkey *key; u_char *signature, *data, *blob; + char *sigalg; size_t signaturelen, datalen, bloblen; int r, ret, valid_data = 0, encoded_ret; if ((r = sshbuf_get_string(m, &blob, &bloblen)) != 0 || (r = sshbuf_get_string(m, &signature, &signaturelen)) != 0 || - (r = sshbuf_get_string(m, &data, &datalen)) != 0) + (r = sshbuf_get_string(m, &data, &datalen)) != 0 || + (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (hostbased_cuser == NULL || hostbased_chost == NULL || @@ -1373,7 +1375,7 @@ mm_answer_keyverify(int sock, struct sshbuf *m) fatal("%s: bad signature data blob", __func__); ret = sshkey_verify(key, signature, signaturelen, data, datalen, - active_state->compat); + sigalg, active_state->compat); debug3("%s: %s %p signature %s", __func__, auth_method, key, (ret == 0) ? "verified" : "unverified"); auth2_record_key(authctxt, ret == 0, key); diff --git a/monitor_wrap.c b/monitor_wrap.c index a46628fb1..502d41687 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.95 2017/10/05 15:52:03 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.96 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -441,7 +441,7 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host, int mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, - const u_char *data, size_t datalen, u_int compat) + const u_char *data, size_t datalen, const char *sigalg, u_int compat) { Buffer m; u_char *blob; @@ -458,6 +458,7 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, buffer_put_string(&m, blob, len); buffer_put_string(&m, sig, siglen); buffer_put_string(&m, data, datalen); + buffer_put_cstring(&m, sigalg); free(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); diff --git a/monitor_wrap.h b/monitor_wrap.h index 9e032d204..f5af1e819 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.35 2017/05/31 08:09:45 markus Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.36 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -51,7 +51,7 @@ int mm_user_key_allowed(struct passwd *, struct sshkey *, int); int mm_hostbased_key_allowed(struct passwd *, const char *, const char *, struct sshkey *); int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, - const u_char *, size_t, u_int); + const u_char *, size_t, const char *, u_int); #ifdef GSSAPI OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); diff --git a/serverloop.c b/serverloop.c index 464c07d2f..fb2980568 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.200 2017/12/10 05:55:29 dtucker Exp $ */ +/* $OpenBSD: serverloop.c,v 1.201 2017/12/18 02:25:15 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -715,7 +715,8 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp) ssh->kex->session_id, ssh->kex->session_id_len)) != 0 || (r = sshkey_puts(key, sigbuf)) != 0 || (r = ssh->kex->sign(key_prv, key_pub, &sig, &slen, - sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), NULL, 0)) != 0 || + sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), + ssh->kex->hostkey_alg, 0)) != 0 || (r = sshbuf_put_string(resp, sig, slen)) != 0) { error("%s: couldn't prepare signature: %s", __func__, ssh_err(r)); diff --git a/ssh-keygen.c b/ssh-keygen.c index 02f9b3fb8..d2736eee2 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.308 2017/11/03 05:14:04 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.309 2017/12/18 02:25:15 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -539,7 +539,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) /* try the key */ if (sshkey_sign(key, &sig, &slen, data, sizeof(data), NULL, 0) != 0 || - sshkey_verify(key, sig, slen, data, sizeof(data), 0) != 0) { + sshkey_verify(key, sig, slen, data, sizeof(data), NULL, 0) != 0) { sshkey_free(key); free(sig); return NULL; diff --git a/ssh-rsa.c b/ssh-rsa.c index f570ae6d4..9b4de8e8d 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.62 2017/07/01 13:50:45 djm Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.63 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -198,9 +198,10 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, int ssh_rsa_verify(const struct sshkey *key, - const u_char *sig, size_t siglen, const u_char *data, size_t datalen) + const u_char *sig, size_t siglen, const u_char *data, size_t datalen, + const char *alg) { - char *ktype = NULL; + char *sigtype = NULL; int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; size_t len, diff, modlen, dlen; struct sshbuf *b = NULL; @@ -215,11 +216,17 @@ ssh_rsa_verify(const struct sshkey *key, if ((b = sshbuf_from(sig, siglen)) == NULL) return SSH_ERR_ALLOC_FAIL; - if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { + if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } - if ((hash_alg = rsa_hash_alg_from_ident(ktype)) == -1) { + /* XXX djm: need cert types that reliably yield SHA-2 signatures */ + if (alg != NULL && strcmp(alg, sigtype) != 0 && + strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { + ret = SSH_ERR_SIGNATURE_INVALID; + goto out; + } + if ((hash_alg = rsa_hash_alg_from_ident(sigtype)) == -1) { ret = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } @@ -263,7 +270,7 @@ ssh_rsa_verify(const struct sshkey *key, explicit_bzero(sigblob, len); free(sigblob); } - free(ktype); + free(sigtype); sshbuf_free(b); explicit_bzero(digest, sizeof(digest)); return ret; diff --git a/sshkey.c b/sshkey.c index 19f26a117..91e0073ff 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.58 2017/12/18 02:22:29 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.59 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -1814,7 +1814,7 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) goto out; } if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, - sshbuf_ptr(key->cert->certblob), signed_len, 0)) != 0) + sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0) goto out; /* Success */ @@ -2109,11 +2109,12 @@ sshkey_sign(const struct sshkey *key, /* * ssh_key_verify returns 0 for a correct signature and < 0 on error. + * If "alg" specified, then the signature must use that algorithm. */ int sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, - const u_char *data, size_t dlen, u_int compat) + const u_char *data, size_t dlen, const char *alg, u_int compat) { if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; @@ -2129,7 +2130,7 @@ sshkey_verify(const struct sshkey *key, # endif /* OPENSSL_HAS_ECC */ case KEY_RSA_CERT: case KEY_RSA: - return ssh_rsa_verify(key, sig, siglen, data, dlen); + return ssh_rsa_verify(key, sig, siglen, data, dlen, alg); #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: diff --git a/sshkey.h b/sshkey.h index b5346a92d..7efa16ff9 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.22 2017/12/18 02:22:29 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.23 2017/12/18 02:25:15 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -178,7 +178,7 @@ int sshkey_sigtype(const u_char *, size_t, char **); int sshkey_sign(const struct sshkey *, u_char **, size_t *, const u_char *, size_t, const char *, u_int); int sshkey_verify(const struct sshkey *, const u_char *, size_t, - const u_char *, size_t, u_int); + const u_char *, size_t, const char *, u_int); /* for debug */ void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *); @@ -205,7 +205,8 @@ int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, const char *ident); int ssh_rsa_verify(const struct sshkey *key, - const u_char *sig, size_t siglen, const u_char *data, size_t datalen); + const u_char *sig, size_t siglen, const u_char *data, size_t datalen, + const char *alg); int ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat); int ssh_dss_verify(const struct sshkey *key, -- cgit v1.2.3 From d45d69f2a937cea215c7f0424e5a4677b6d8c7fe Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 21 Dec 2017 00:00:28 +0000 Subject: upstream commit revert stricter key type / signature type checking in userauth path; too much software generates inconsistent messages, so we need a better plan. OpenBSD-Commit-ID: 4a44ddc991c803c4ecc8f1ad40e0ab4d22e1c519 --- auth2-pubkey.c | 4 ++-- monitor.c | 9 ++++++++- monitor_wrap.c | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'monitor_wrap.c') diff --git a/auth2-pubkey.c b/auth2-pubkey.c index eac79cc3d..0713a9de8 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.73 2017/12/19 00:24:34 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.74 2017/12/21 00:00:28 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -214,7 +214,7 @@ userauth_pubkey(struct ssh *ssh) authenticated = 0; if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), - sshbuf_len(b), pkalg, ssh->compat)) == 0) { + sshbuf_len(b), NULL, ssh->compat)) == 0) { authenticated = 1; } sshbuf_free(b); diff --git a/monitor.c b/monitor.c index 5b8f0ef65..b0227eee1 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.176 2017/12/18 02:25:15 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.177 2017/12/21 00:00:28 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -1353,6 +1353,12 @@ mm_answer_keyverify(int sock, struct sshbuf *m) !monitor_allowed_key(blob, bloblen)) fatal("%s: bad key, not previously allowed", __func__); + /* Empty signature algorithm means NULL. */ + if (*sigalg == '\0') { + free(sigalg); + sigalg = NULL; + } + /* XXX use sshkey_froms here; need to change key_blob, etc. */ if ((r = sshkey_from_blob(blob, bloblen, &key)) != 0) fatal("%s: bad public key blob: %s", __func__, ssh_err(r)); @@ -1383,6 +1389,7 @@ mm_answer_keyverify(int sock, struct sshbuf *m) free(blob); free(signature); free(data); + free(sigalg); monitor_reset_key_state(); diff --git a/monitor_wrap.c b/monitor_wrap.c index 502d41687..7471e4546 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.96 2017/12/18 02:25:15 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.97 2017/12/21 00:00:28 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -458,7 +458,7 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, buffer_put_string(&m, blob, len); buffer_put_string(&m, sig, siglen); buffer_put_string(&m, data, datalen); - buffer_put_cstring(&m, sigalg); + buffer_put_cstring(&m, sigalg == NULL ? "" : sigalg); free(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); -- cgit v1.2.3 From 25aae35d3d6ee86a8c4c0b1896acafc1eab30172 Mon Sep 17 00:00:00 2001 From: "markus@openbsd.org" Date: Mon, 8 Jan 2018 15:14:44 +0000 Subject: upstream commit uuencode.h is not used OpenBSD-Commit-ID: 238eb4659f3c119904326b9e94a5e507a912796c --- monitor_wrap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'monitor_wrap.c') diff --git a/monitor_wrap.c b/monitor_wrap.c index 7471e4546..cce318bc5 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.97 2017/12/21 00:00:28 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.98 2018/01/08 15:14:44 markus Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -76,7 +76,6 @@ #include "atomicio.h" #include "monitor_fdpass.h" #include "misc.h" -#include "uuencode.h" #include "channels.h" #include "session.h" -- cgit v1.2.3 From 7c856857607112a3dfe6414696bf4c7ab7fb0cb3 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 3 Mar 2018 03:15:51 +0000 Subject: upstream: switch over to the new authorized_keys options API and remove the legacy one. Includes a fairly big refactor of auth2-pubkey.c to retain less state between key file lines. feedback and ok markus@ OpenBSD-Commit-ID: dece6cae0f47751b9892080eb13d6625599573df --- .depend | 7 +- auth-options.c | 650 +-------------------------------------------------------- auth-options.h | 46 ++-- auth-pam.c | 4 +- auth-pam.h | 4 +- auth-passwd.c | 30 ++- auth.c | 180 +++++++++++++++- auth.h | 28 ++- auth2-none.c | 4 +- auth2-passwd.c | 4 +- auth2-pubkey.c | 532 +++++++++++++++++++++++++++++++--------------- auth2.c | 4 +- misc.c | 3 +- monitor.c | 70 ++++--- monitor_wrap.c | 44 ++-- monitor_wrap.h | 11 +- serverloop.c | 33 +-- session.c | 85 +++++--- sshd.c | 12 +- 19 files changed, 767 insertions(+), 984 deletions(-) (limited to 'monitor_wrap.c') diff --git a/.depend b/.depend index 4c6b49d54..0893a87ab 100644 --- a/.depend +++ b/.depend @@ -7,8 +7,7 @@ audit-linux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c audit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h auth-bsdauth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h auth-krb5.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h ssh.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h uidswap.h key.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h -auth-options.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h openbsd-compat/sys-queue.h key.h sshkey.h xmalloc.h match.h ssherr.h log.h canohost.h packet.h dispatch.h opacket.h misc.h channels.h servconf.h auth-options.h hostfile.h auth.h auth-pam.h -auth-options.o: audit.h loginrec.h +auth-options.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h openbsd-compat/sys-queue.h xmalloc.h ssherr.h log.h misc.h sshkey.h match.h ssh2.h auth-options.h auth-pam.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h auth-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h key.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h auth-rhosts.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h uidswap.h pathnames.h log.h misc.h key.h sshkey.h servconf.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h @@ -16,7 +15,7 @@ auth-shadow.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c auth-sia.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h auth-skey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h match.h groupaccess.h log.h misc.h servconf.h key.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h canohost.h uidswap.h packet.h openbsd-compat/sys-queue.h -auth.o: dispatch.h opacket.h authfile.h monitor_wrap.h ssherr.h compat.h +auth.o: dispatch.h opacket.h authfile.h monitor_wrap.h ssherr.h compat.h channels.h auth2-chall.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h ssh2.h key.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h auth2-gss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h auth2-hostbased.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h canohost.h @@ -161,7 +160,7 @@ sshconnect.o: ssh2.h version.h authfile.h ssherr.h authfd.h sshconnect2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h packet.h dispatch.h opacket.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h key.h sshkey.h kex.h mac.h sshconnect2.o: myproposal.h sshconnect.h authfile.h dh.h authfd.h log.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h ssherr.h utf8.h sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h opacket.h log.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h -sshd.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h key.h sshkey.h kex.h mac.h myproposal.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h ssh-sandbox.h version.h ssherr.h +sshd.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h key.h sshkey.h kex.h mac.h myproposal.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h ssh-sandbox.h auth-options.h version.h ssherr.h ssherr.o: ssherr.h sshkey-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h crypto_api.h ssh2.h ssherr.h misc.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h sshkey-xmss.h match.h xmss_fast.h diff --git a/auth-options.c b/auth-options.c index 8b93b51e5..484e44b74 100644 --- a/auth-options.c +++ b/auth-options.c @@ -1,14 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.75 2018/03/03 03:06:02 djm Exp $ */ -/* - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - * All rights reserved - * As far as I am concerned, the code I have written for this software - * can be used freely for any purpose. Any derived versions of this - * software must be clearly marked as such, and if the derived work is - * incompatible with the protocol description in the RFC file, it must be - * called by a name other than "ssh" or "Secure Shell". - */ +/* $OpenBSD: auth-options.c,v 1.76 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2018 Damien Miller * @@ -39,649 +29,15 @@ #include "openbsd-compat/sys-queue.h" -#include "key.h" /* XXX for typedef */ -#include "buffer.h" /* XXX for typedef */ #include "xmalloc.h" -#include "match.h" #include "ssherr.h" -#include "ssh2.h" #include "log.h" -#include "canohost.h" -#include "packet.h" #include "sshbuf.h" #include "misc.h" -#include "channels.h" -#include "servconf.h" #include "sshkey.h" +#include "match.h" +#include "ssh2.h" #include "auth-options.h" -#include "hostfile.h" -#include "auth.h" - -/* Flags set authorized_keys flags */ -int no_port_forwarding_flag = 0; -int no_agent_forwarding_flag = 0; -int no_x11_forwarding_flag = 0; -int no_pty_flag = 0; -int no_user_rc = 0; -int key_is_cert_authority = 0; - -/* "command=" option. */ -char *forced_command = NULL; - -/* "environment=" options. */ -struct envstring *custom_environment = NULL; - -/* "tunnel=" option. */ -int forced_tun_device = -1; - -/* "principals=" option. */ -char *authorized_principals = NULL; - -extern ServerOptions options; - -/* XXX refactor to be stateless */ - -void -auth_clear_options(void) -{ - struct ssh *ssh = active_state; /* XXX */ - - no_agent_forwarding_flag = 0; - no_port_forwarding_flag = 0; - no_pty_flag = 0; - no_x11_forwarding_flag = 0; - no_user_rc = 0; - key_is_cert_authority = 0; - while (custom_environment) { - struct envstring *ce = custom_environment; - custom_environment = ce->next; - free(ce->s); - free(ce); - } - free(forced_command); - forced_command = NULL; - free(authorized_principals); - authorized_principals = NULL; - forced_tun_device = -1; - channel_clear_permitted_opens(ssh); -} - -/* - * Match flag 'opt' in *optsp, and if allow_negate is set then also match - * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0 - * if negated option matches. - * If the option or negated option matches, then *optsp is updated to - * point to the first character after the option and, if 'msg' is not NULL - * then a message based on it added via auth_debug_add(). - */ -static int -match_flag(const char *opt, int allow_negate, char **optsp, const char *msg) -{ - size_t opt_len = strlen(opt); - char *opts = *optsp; - int negate = 0; - - if (allow_negate && strncasecmp(opts, "no-", 3) == 0) { - opts += 3; - negate = 1; - } - if (strncasecmp(opts, opt, opt_len) == 0) { - *optsp = opts + opt_len; - if (msg != NULL) { - auth_debug_add("%s %s.", msg, - negate ? "disabled" : "enabled"); - } - return negate ? 0 : 1; - } - return -1; -} - -/* - * return 1 if access is granted, 0 if not. - * side effect: sets key option flags - * XXX remove side effects; fill structure instead. - */ -int -auth_parse_options(struct passwd *pw, char *opts, const char *file, - u_long linenum) -{ - struct ssh *ssh = active_state; /* XXX */ - const char *cp; - int i, r; - - /* reset options */ - auth_clear_options(); - - if (!opts) - return 1; - - while (*opts && *opts != ' ' && *opts != '\t') { - if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) { - key_is_cert_authority = r; - goto next_option; - } - if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) { - auth_debug_add("Key is restricted."); - no_port_forwarding_flag = 1; - no_agent_forwarding_flag = 1; - no_x11_forwarding_flag = 1; - no_pty_flag = 1; - no_user_rc = 1; - goto next_option; - } - if ((r = match_flag("port-forwarding", 1, &opts, - "Port forwarding")) != -1) { - no_port_forwarding_flag = r != 1; - goto next_option; - } - if ((r = match_flag("agent-forwarding", 1, &opts, - "Agent forwarding")) != -1) { - no_agent_forwarding_flag = r != 1; - goto next_option; - } - if ((r = match_flag("x11-forwarding", 1, &opts, - "X11 forwarding")) != -1) { - no_x11_forwarding_flag = r != 1; - goto next_option; - } - if ((r = match_flag("pty", 1, &opts, - "PTY allocation")) != -1) { - no_pty_flag = r != 1; - goto next_option; - } - if ((r = match_flag("user-rc", 1, &opts, - "User rc execution")) != -1) { - no_user_rc = r != 1; - goto next_option; - } - cp = "command=\""; - if (strncasecmp(opts, cp, strlen(cp)) == 0) { - opts += strlen(cp); - free(forced_command); - forced_command = xmalloc(strlen(opts) + 1); - i = 0; - while (*opts) { - if (*opts == '"') - break; - if (*opts == '\\' && opts[1] == '"') { - opts += 2; - forced_command[i++] = '"'; - continue; - } - forced_command[i++] = *opts++; - } - if (!*opts) { - debug("%.100s, line %lu: missing end quote", - file, linenum); - auth_debug_add("%.100s, line %lu: missing end quote", - file, linenum); - free(forced_command); - forced_command = NULL; - goto bad_option; - } - forced_command[i] = '\0'; - auth_debug_add("Forced command."); - opts++; - goto next_option; - } - cp = "principals=\""; - if (strncasecmp(opts, cp, strlen(cp)) == 0) { - opts += strlen(cp); - free(authorized_principals); - authorized_principals = xmalloc(strlen(opts) + 1); - i = 0; - while (*opts) { - if (*opts == '"') - break; - if (*opts == '\\' && opts[1] == '"') { - opts += 2; - authorized_principals[i++] = '"'; - continue; - } - authorized_principals[i++] = *opts++; - } - if (!*opts) { - debug("%.100s, line %lu: missing end quote", - file, linenum); - auth_debug_add("%.100s, line %lu: missing end quote", - file, linenum); - free(authorized_principals); - authorized_principals = NULL; - goto bad_option; - } - authorized_principals[i] = '\0'; - auth_debug_add("principals: %.900s", - authorized_principals); - opts++; - goto next_option; - } - cp = "environment=\""; - if (strncasecmp(opts, cp, strlen(cp)) == 0) { - char *s; - struct envstring *new_envstring; - - opts += strlen(cp); - s = xmalloc(strlen(opts) + 1); - i = 0; - while (*opts) { - if (*opts == '"') - break; - if (*opts == '\\' && opts[1] == '"') { - opts += 2; - s[i++] = '"'; - continue; - } - s[i++] = *opts++; - } - if (!*opts) { - debug("%.100s, line %lu: missing end quote", - file, linenum); - auth_debug_add("%.100s, line %lu: missing end quote", - file, linenum); - free(s); - goto bad_option; - } - s[i] = '\0'; - opts++; - if (options.permit_user_env) { - auth_debug_add("Adding to environment: " - "%.900s", s); - debug("Adding to environment: %.900s", s); - new_envstring = xcalloc(1, - sizeof(*new_envstring)); - new_envstring->s = s; - new_envstring->next = custom_environment; - custom_environment = new_envstring; - s = NULL; - } - free(s); - goto next_option; - } - cp = "from=\""; - if (strncasecmp(opts, cp, strlen(cp)) == 0) { - const char *remote_ip = ssh_remote_ipaddr(ssh); - const char *remote_host = auth_get_canonical_hostname( - ssh, options.use_dns); - char *patterns = xmalloc(strlen(opts) + 1); - - opts += strlen(cp); - i = 0; - while (*opts) { - if (*opts == '"') - break; - if (*opts == '\\' && opts[1] == '"') { - opts += 2; - patterns[i++] = '"'; - continue; - } - patterns[i++] = *opts++; - } - if (!*opts) { - debug("%.100s, line %lu: missing end quote", - file, linenum); - auth_debug_add("%.100s, line %lu: missing end quote", - file, linenum); - free(patterns); - goto bad_option; - } - patterns[i] = '\0'; - opts++; - switch (match_host_and_ip(remote_host, remote_ip, - patterns)) { - case 1: - free(patterns); - /* Host name matches. */ - goto next_option; - case -1: - debug("%.100s, line %lu: invalid criteria", - file, linenum); - auth_debug_add("%.100s, line %lu: " - "invalid criteria", file, linenum); - /* FALLTHROUGH */ - case 0: - free(patterns); - logit("Authentication tried for %.100s with " - "correct key but not from a permitted " - "host (host=%.200s, ip=%.200s).", - pw->pw_name, remote_host, remote_ip); - auth_debug_add("Your host '%.200s' is not " - "permitted to use this key for login.", - remote_host); - break; - } - /* deny access */ - return 0; - } - cp = "permitopen=\""; - if (strncasecmp(opts, cp, strlen(cp)) == 0) { - char *host, *p; - int port; - char *patterns = xmalloc(strlen(opts) + 1); - - opts += strlen(cp); - i = 0; - while (*opts) { - if (*opts == '"') - break; - if (*opts == '\\' && opts[1] == '"') { - opts += 2; - patterns[i++] = '"'; - continue; - } - patterns[i++] = *opts++; - } - if (!*opts) { - debug("%.100s, line %lu: missing end quote", - file, linenum); - auth_debug_add("%.100s, line %lu: missing " - "end quote", file, linenum); - free(patterns); - goto bad_option; - } - patterns[i] = '\0'; - opts++; - p = patterns; - /* XXX - add streamlocal support */ - host = hpdelim(&p); - if (host == NULL || strlen(host) >= NI_MAXHOST) { - debug("%.100s, line %lu: Bad permitopen " - "specification <%.100s>", file, linenum, - patterns); - auth_debug_add("%.100s, line %lu: " - "Bad permitopen specification", file, - linenum); - free(patterns); - goto bad_option; - } - host = cleanhostname(host); - if (p == NULL || (port = permitopen_port(p)) < 0) { - debug("%.100s, line %lu: Bad permitopen port " - "<%.100s>", file, linenum, p ? p : ""); - auth_debug_add("%.100s, line %lu: " - "Bad permitopen port", file, linenum); - free(patterns); - goto bad_option; - } - if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) - channel_add_permitted_opens(ssh, host, port); - free(patterns); - goto next_option; - } - cp = "tunnel=\""; - if (strncasecmp(opts, cp, strlen(cp)) == 0) { - char *tun = NULL; - opts += strlen(cp); - tun = xmalloc(strlen(opts) + 1); - i = 0; - while (*opts) { - if (*opts == '"') - break; - tun[i++] = *opts++; - } - if (!*opts) { - debug("%.100s, line %lu: missing end quote", - file, linenum); - auth_debug_add("%.100s, line %lu: missing end quote", - file, linenum); - free(tun); - forced_tun_device = -1; - goto bad_option; - } - tun[i] = '\0'; - forced_tun_device = a2tun(tun, NULL); - free(tun); - if (forced_tun_device == SSH_TUNID_ERR) { - debug("%.100s, line %lu: invalid tun device", - file, linenum); - auth_debug_add("%.100s, line %lu: invalid tun device", - file, linenum); - forced_tun_device = -1; - goto bad_option; - } - auth_debug_add("Forced tun device: %d", forced_tun_device); - opts++; - goto next_option; - } -next_option: - /* - * Skip the comma, and move to the next option - * (or break out if there are no more). - */ - if (!*opts) - fatal("Bugs in auth-options.c option processing."); - if (*opts == ' ' || *opts == '\t') - break; /* End of options. */ - if (*opts != ',') - goto bad_option; - opts++; - /* Process the next option. */ - } - - /* grant access */ - return 1; - -bad_option: - logit("Bad options in %.100s file, line %lu: %.50s", - file, linenum, opts); - auth_debug_add("Bad options in %.100s file, line %lu: %.50s", - file, linenum, opts); - - /* deny access */ - return 0; -} - -#define OPTIONS_CRITICAL 1 -#define OPTIONS_EXTENSIONS 2 -static int -parse_option_list(struct sshbuf *oblob, struct passwd *pw, - u_int which, int crit, - int *cert_no_port_forwarding_flag, - int *cert_no_agent_forwarding_flag, - int *cert_no_x11_forwarding_flag, - int *cert_no_pty_flag, - int *cert_no_user_rc, - char **cert_forced_command, - int *cert_source_address_done) -{ - struct ssh *ssh = active_state; /* XXX */ - char *command, *allowed; - const char *remote_ip; - char *name = NULL; - struct sshbuf *c = NULL, *data = NULL; - int r, ret = -1, result, found; - - if ((c = sshbuf_fromb(oblob)) == NULL) { - error("%s: sshbuf_fromb failed", __func__); - goto out; - } - - while (sshbuf_len(c) > 0) { - sshbuf_free(data); - data = NULL; - if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 || - (r = sshbuf_froms(c, &data)) != 0) { - error("Unable to parse certificate options: %s", - ssh_err(r)); - goto out; - } - debug3("found certificate option \"%.100s\" len %zu", - name, sshbuf_len(data)); - found = 0; - if ((which & OPTIONS_EXTENSIONS) != 0) { - if (strcmp(name, "permit-X11-forwarding") == 0) { - *cert_no_x11_forwarding_flag = 0; - found = 1; - } else if (strcmp(name, - "permit-agent-forwarding") == 0) { - *cert_no_agent_forwarding_flag = 0; - found = 1; - } else if (strcmp(name, - "permit-port-forwarding") == 0) { - *cert_no_port_forwarding_flag = 0; - found = 1; - } else if (strcmp(name, "permit-pty") == 0) { - *cert_no_pty_flag = 0; - found = 1; - } else if (strcmp(name, "permit-user-rc") == 0) { - *cert_no_user_rc = 0; - found = 1; - } - } - if (!found && (which & OPTIONS_CRITICAL) != 0) { - if (strcmp(name, "force-command") == 0) { - if ((r = sshbuf_get_cstring(data, &command, - NULL)) != 0) { - error("Unable to parse \"%s\" " - "section: %s", name, ssh_err(r)); - goto out; - } - if (*cert_forced_command != NULL) { - error("Certificate has multiple " - "force-command options"); - free(command); - goto out; - } - *cert_forced_command = command; - found = 1; - } - if (strcmp(name, "source-address") == 0) { - if ((r = sshbuf_get_cstring(data, &allowed, - NULL)) != 0) { - error("Unable to parse \"%s\" " - "section: %s", name, ssh_err(r)); - goto out; - } - if ((*cert_source_address_done)++) { - error("Certificate has multiple " - "source-address options"); - free(allowed); - goto out; - } - remote_ip = ssh_remote_ipaddr(ssh); - result = addr_match_cidr_list(remote_ip, - allowed); - free(allowed); - switch (result) { - case 1: - /* accepted */ - break; - case 0: - /* no match */ - logit("Authentication tried for %.100s " - "with valid certificate but not " - "from a permitted host " - "(ip=%.200s).", pw->pw_name, - remote_ip); - auth_debug_add("Your address '%.200s' " - "is not permitted to use this " - "certificate for login.", - remote_ip); - goto out; - case -1: - default: - error("Certificate source-address " - "contents invalid"); - goto out; - } - found = 1; - } - } - - if (!found) { - if (crit) { - error("Certificate critical option \"%s\" " - "is not supported", name); - goto out; - } else { - logit("Certificate extension \"%s\" " - "is not supported", name); - } - } else if (sshbuf_len(data) != 0) { - error("Certificate option \"%s\" corrupt " - "(extra data)", name); - goto out; - } - free(name); - name = NULL; - } - /* successfully parsed all options */ - ret = 0; - - out: - if (ret != 0 && - cert_forced_command != NULL && - *cert_forced_command != NULL) { - free(*cert_forced_command); - *cert_forced_command = NULL; - } - free(name); - sshbuf_free(data); - sshbuf_free(c); - return ret; -} - -/* - * Set options from critical certificate options. These supersede user key - * options so this must be called after auth_parse_options(). - */ -int -auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason) -{ - int cert_no_port_forwarding_flag = 1; - int cert_no_agent_forwarding_flag = 1; - int cert_no_x11_forwarding_flag = 1; - int cert_no_pty_flag = 1; - int cert_no_user_rc = 1; - char *cert_forced_command = NULL; - int cert_source_address_done = 0; - - *reason = "invalid certificate options"; - - /* Separate options and extensions for v01 certs */ - if (parse_option_list(k->cert->critical, pw, - OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, - &cert_forced_command, - &cert_source_address_done) == -1) - return -1; - if (parse_option_list(k->cert->extensions, pw, - OPTIONS_EXTENSIONS, 0, - &cert_no_port_forwarding_flag, - &cert_no_agent_forwarding_flag, - &cert_no_x11_forwarding_flag, - &cert_no_pty_flag, - &cert_no_user_rc, - NULL, NULL) == -1) - return -1; - - no_port_forwarding_flag |= cert_no_port_forwarding_flag; - no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; - no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; - no_pty_flag |= cert_no_pty_flag; - no_user_rc |= cert_no_user_rc; - /* - * Only permit both CA and key option forced-command if they match. - * Otherwise refuse the certificate. - */ - if (cert_forced_command != NULL && forced_command != NULL) { - if (strcmp(forced_command, cert_forced_command) == 0) { - free(forced_command); - forced_command = cert_forced_command; - } else { - *reason = "certificate and key options forced command " - "do not match"; - free(cert_forced_command); - return -1; - } - } else if (cert_forced_command != NULL) - forced_command = cert_forced_command; - /* success */ - *reason = NULL; - return 0; -} - -/* - * authorized_keys options processing. - */ /* * Match flag 'opt' in *optsp, and if allow_negate is set then also match diff --git a/auth-options.h b/auth-options.h index 0dbfc325e..16871d754 100644 --- a/auth-options.h +++ b/auth-options.h @@ -1,15 +1,19 @@ -/* $OpenBSD: auth-options.h,v 1.24 2018/03/03 03:06:02 djm Exp $ */ +/* $OpenBSD: auth-options.h,v 1.25 2018/03/03 03:15:51 djm Exp $ */ /* - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - * All rights reserved + * Copyright (c) 2018 Damien Miller * - * As far as I am concerned, the code I have written for this software - * can be used freely for any purpose. Any derived versions of this - * software must be clearly marked as such, and if the derived work is - * incompatible with the protocol description in the RFC file, it must be - * called by a name other than "ssh" or "Secure Shell". + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef AUTH_OPTIONS_H @@ -18,30 +22,6 @@ struct passwd; struct sshkey; -/* Linked list of custom environment strings */ -struct envstring { - struct envstring *next; - char *s; -}; - -/* Flags that may be set in authorized_keys options. */ -extern int no_port_forwarding_flag; -extern int no_agent_forwarding_flag; -extern int no_x11_forwarding_flag; -extern int no_pty_flag; -extern int no_user_rc; -extern char *forced_command; -extern struct envstring *custom_environment; -extern int forced_tun_device; -extern int key_is_cert_authority; -extern char *authorized_principals; - -int auth_parse_options(struct passwd *, char *, const char *, u_long); -void auth_clear_options(void); -int auth_cert_options(struct sshkey *, struct passwd *, const char **); - -/* authorized_keys options handling */ - /* * sshauthopt represents key options parsed from authorized_keys or * from certificate extensions/options. diff --git a/auth-pam.c b/auth-pam.c index de29c04c9..50d2073d7 100644 --- a/auth-pam.c +++ b/auth-pam.c @@ -1077,7 +1077,7 @@ do_pam_chauthtok(void) } void -do_pam_session(void) +do_pam_session(struct ssh *ssh) { debug3("PAM: opening session"); @@ -1093,7 +1093,7 @@ do_pam_session(void) sshpam_session_open = 1; else { sshpam_session_open = 0; - disable_forwarding(); + auth_restrict_session(ssh); error("PAM: pam_open_session(): %s", pam_strerror(sshpam_handle, sshpam_err)); } diff --git a/auth-pam.h b/auth-pam.h index c47b442e4..419860745 100644 --- a/auth-pam.h +++ b/auth-pam.h @@ -25,10 +25,12 @@ #include "includes.h" #ifdef USE_PAM +struct ssh; + void start_pam(Authctxt *); void finish_pam(void); u_int do_pam_account(void); -void do_pam_session(void); +void do_pam_session(struct ssh *); void do_pam_setcred(int ); void do_pam_chauthtok(void); int do_pam_putenv(char *, char *); diff --git a/auth-passwd.c b/auth-passwd.c index 996c2cf71..6097fdd24 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-passwd.c,v 1.45 2016/07/21 01:39:35 dtucker Exp $ */ +/* $OpenBSD: auth-passwd.c,v 1.46 2018/03/03 03:15:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -68,22 +68,15 @@ extern login_cap_t *lc; #define MAX_PASSWORD_LEN 1024 -void -disable_forwarding(void) -{ - no_port_forwarding_flag = 1; - no_agent_forwarding_flag = 1; - no_x11_forwarding_flag = 1; -} - /* * Tries to authenticate the user using password. Returns true if * authentication succeeds. */ int -auth_password(Authctxt *authctxt, const char *password) +auth_password(struct ssh *ssh, const char *password) { - struct passwd * pw = authctxt->pw; + Authctxt *authctxt = ssh->authctxt; + struct passwd *pw = authctxt->pw; int result, ok = authctxt->valid; #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) static int expire_checked = 0; @@ -128,9 +121,9 @@ auth_password(Authctxt *authctxt, const char *password) authctxt->force_pwchange = 1; } #endif - result = sys_auth_passwd(authctxt, password); + result = sys_auth_passwd(ssh, password); if (authctxt->force_pwchange) - disable_forwarding(); + auth_restrict_session(ssh); return (result && ok); } @@ -170,19 +163,19 @@ warn_expiry(Authctxt *authctxt, auth_session_t *as) } int -sys_auth_passwd(Authctxt *authctxt, const char *password) +sys_auth_passwd(struct ssh *ssh, const char *password) { - struct passwd *pw = authctxt->pw; + Authctxt *authctxt = ssh->authctxt; auth_session_t *as; static int expire_checked = 0; - as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh", + as = auth_usercheck(authctxt->pw->pw_name, authctxt->style, "auth-ssh", (char *)password); if (as == NULL) return (0); if (auth_getstate(as) & AUTH_PWEXPIRED) { auth_close(as); - disable_forwarding(); + auth_restrict_session(ssh); authctxt->force_pwchange = 1; return (1); } else { @@ -195,8 +188,9 @@ sys_auth_passwd(Authctxt *authctxt, const char *password) } #elif !defined(CUSTOM_SYS_AUTH_PASSWD) int -sys_auth_passwd(Authctxt *authctxt, const char *password) +sys_auth_passwd(struct ssh *ssh, const char *password) { + Authctxt *authctxt = ssh->authctxt; struct passwd *pw = authctxt->pw; char *encrypted_password, *salt = NULL; diff --git a/auth.c b/auth.c index fd02eff07..041a09e3f 100644 --- a/auth.c +++ b/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.125 2018/01/08 15:21:49 markus Exp $ */ +/* $OpenBSD: auth.c,v 1.126 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -74,12 +74,14 @@ #include "authfile.h" #include "ssherr.h" #include "compat.h" +#include "channels.h" /* import */ extern ServerOptions options; extern int use_privsep; extern Buffer loginmsg; extern struct passwd *privsep_pw; +extern struct sshauthopt *auth_opts; /* Debugging messages */ Buffer auth_debug; @@ -386,10 +388,8 @@ auth_maxtries_exceeded(Authctxt *authctxt) * Check whether root logins are disallowed. */ int -auth_root_allowed(const char *method) +auth_root_allowed(struct ssh *ssh, const char *method) { - struct ssh *ssh = active_state; /* XXX */ - switch (options.permit_root_login) { case PERMIT_YES: return 1; @@ -400,7 +400,7 @@ auth_root_allowed(const char *method) return 1; break; case PERMIT_FORCED_ONLY: - if (forced_command) { + if (auth_opts->force_command != NULL) { logit("Root login accepted for forced command."); return 1; } @@ -993,3 +993,173 @@ subprocess(const char *tag, struct passwd *pw, const char *command, *child = f; return pid; } + +/* These functions link key/cert options to the auth framework */ + +/* Log sshauthopt options locally and (optionally) for remote transmission */ +void +auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote) +{ + int do_env = options.permit_user_env && opts->nenv > 0; + int do_permitopen = opts->npermitopen > 0 && + (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0; + size_t i; + char msg[1024], tbuf[32]; + + snprintf(tbuf, sizeof(tbuf), "%d", opts->force_tun_device); + /* Try to keep this alphabetically sorted */ + snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s", + opts->permit_agent_forwarding_flag ? " agent-forwarding" : "", + opts->force_command == NULL ? "" : " command", + do_env ? " environment" : "", + do_permitopen ? " permitopen" : "", + opts->permit_port_forwarding_flag ? " port-forwarding" : "", + opts->cert_principals == NULL ? "" : " principals", + opts->permit_pty_flag ? " pty" : "", + opts->force_tun_device == -1 ? "" : " tun=", + opts->force_tun_device == -1 ? "" : tbuf, + opts->permit_user_rc ? " user-rc" : "", + opts->permit_x11_forwarding_flag ? " x11-forwarding" : ""); + + debug("%s: %s", loc, msg); + if (do_remote) + auth_debug_add("%s: %s", loc, msg); + + if (options.permit_user_env) { + for (i = 0; i < opts->nenv; i++) { + debug("%s: environment: %s", loc, opts->env[i]); + if (do_remote) { + auth_debug_add("%s: environment: %s", + loc, opts->env[i]); + } + } + } + + /* Go into a little more details for the local logs. */ + if (opts->cert_principals != NULL) { + debug("%s: authorized principals: \"%s\"", + loc, opts->cert_principals); + } + if (opts->force_command != NULL) + debug("%s: forced command: \"%s\"", loc, opts->force_command); + if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) { + for (i = 0; i < opts->npermitopen; i++) { + debug("%s: permitted open: %s", + loc, opts->permitopen[i]); + } + } +} + +/* Activate a new set of key/cert options; merging with what is there. */ +int +auth_activate_options(struct ssh *ssh, struct sshauthopt *opts) +{ + struct sshauthopt *old = auth_opts; + const char *emsg = NULL; + + debug("%s: setting new authentication options", __func__); + if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) { + error("Inconsistent authentication options: %s", emsg); + return -1; + } + return 0; +} + +/* Disable forwarding, etc for the session */ +void +auth_restrict_session(struct ssh *ssh) +{ + struct sshauthopt *restricted; + + debug("%s: restricting session", __func__); + + /* A blank sshauthopt defaults to permitting nothing */ + restricted = sshauthopt_new(); + restricted->restricted = 1; + + if (auth_activate_options(ssh, restricted) != 0) + fatal("%s: failed to restrict session", __func__); + sshauthopt_free(restricted); +} + +int +auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw, + struct sshauthopt *opts, int allow_cert_authority, const char *loc) +{ + const char *remote_ip = ssh_remote_ipaddr(ssh); + const char *remote_host = auth_get_canonical_hostname(ssh, + options.use_dns); + + /* Consistency checks */ + if (opts->cert_principals != NULL && !opts->cert_authority) { + debug("%s: principals on non-CA key", loc); + auth_debug_add("%s: principals on non-CA key", loc); + /* deny access */ + return -1; + } + /* cert-authority flag isn't valid in authorized_principals files */ + if (!allow_cert_authority && opts->cert_authority) { + debug("%s: cert-authority flag invalid here", loc); + auth_debug_add("%s: cert-authority flag invalid here", loc); + /* deny access */ + return -1; + } + + /* Perform from= checks */ + if (opts->required_from_host_keys != NULL) { + switch (match_host_and_ip(remote_host, remote_ip, + opts->required_from_host_keys )) { + case 1: + /* Host name matches. */ + break; + case -1: + default: + debug("%s: invalid from criteria", loc); + auth_debug_add("%s: invalid from criteria", loc); + /* FALLTHROUGH */ + case 0: + logit("%s: Authentication tried for %.100s with " + "correct key but not from a permitted " + "host (host=%.200s, ip=%.200s, required=%.200s).", + loc, pw->pw_name, remote_host, remote_ip, + opts->required_from_host_keys); + auth_debug_add("%s: Your host '%.200s' is not " + "permitted to use this key for login.", + loc, remote_host); + /* deny access */ + return -1; + } + } + /* Check source-address restriction from certificate */ + if (opts->required_from_host_cert != NULL) { + switch (addr_match_cidr_list(remote_ip, + opts->required_from_host_cert)) { + case 1: + /* accepted */ + break; + case -1: + default: + /* invalid */ + error("%s: Certificate source-address invalid", + loc); + /* FALLTHROUGH */ + case 0: + logit("%s: Authentication tried for %.100s with valid " + "certificate but not from a permitted source " + "address (%.200s).", loc, pw->pw_name, remote_ip); + auth_debug_add("%s: Your address '%.200s' is not " + "permitted to use this certificate for login.", + loc, remote_ip); + return -1; + } + } + /* + * + * XXX this is spammy. We should report remotely only for keys + * that are successful in actual auth attempts, and not PK_OK + * tests. + */ + auth_log_authopts(loc, opts, 1); + + return 0; +} diff --git a/auth.h b/auth.h index 64f3c2eb5..23ce67caf 100644 --- a/auth.h +++ b/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.94 2018/01/08 15:21:49 markus Exp $ */ +/* $OpenBSD: auth.h,v 1.95 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -42,9 +42,11 @@ #include #endif +struct passwd; struct ssh; -struct sshkey; struct sshbuf; +struct sshkey; +struct sshauthopt; typedef struct Authctxt Authctxt; typedef struct Authmethod Authmethod; @@ -128,11 +130,12 @@ struct KbdintDevice int auth_rhosts2(struct passwd *, const char *, const char *, const char *); -int auth_password(Authctxt *, const char *); +int auth_password(struct ssh *, const char *); int hostbased_key_allowed(struct passwd *, const char *, char *, struct sshkey *); -int user_key_allowed(struct passwd *, struct sshkey *, int); +int user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int, + struct sshauthopt **); int auth2_key_already_used(Authctxt *, const struct sshkey *); /* @@ -163,14 +166,12 @@ int auth_shadow_pwexpired(Authctxt *); #include "audit.h" void remove_kbdint_device(const char *); -void disable_forwarding(void); - void do_authentication2(Authctxt *); void auth_log(Authctxt *, int, int, const char *, const char *); void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn)); void userauth_finish(struct ssh *, int, const char *, const char *); -int auth_root_allowed(const char *); +int auth_root_allowed(struct ssh *, const char *); void userauth_send_banner(const char *); @@ -214,8 +215,17 @@ int get_hostkey_index(struct sshkey *, int, struct ssh *); int sshd_hostkey_sign(struct sshkey *, struct sshkey *, u_char **, size_t *, const u_char *, size_t, const char *, u_int); +/* Key / cert options linkage to auth layer */ +const struct sshauthopt *auth_options(struct ssh *); +int auth_activate_options(struct ssh *, struct sshauthopt *); +void auth_restrict_session(struct ssh *); +int auth_authorise_keyopts(struct ssh *, struct passwd *pw, + struct sshauthopt *, int, const char *); +void auth_log_authopts(const char *, const struct sshauthopt *, int); + /* debug messages during authentication */ -void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void auth_debug_add(const char *fmt,...) + __attribute__((format(printf, 1, 2))); void auth_debug_send(void); void auth_debug_reset(void); @@ -227,7 +237,7 @@ struct passwd *fakepw(void); pid_t subprocess(const char *, struct passwd *, const char *, int, char **, FILE **, u_int flags); -int sys_auth_passwd(Authctxt *, const char *); +int sys_auth_passwd(struct ssh *, const char *); #define SKEY_PROMPT "\nS/Key Password: " diff --git a/auth2-none.c b/auth2-none.c index 35d25fa63..8d4e9bb8c 100644 --- a/auth2-none.c +++ b/auth2-none.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-none.c,v 1.20 2017/05/30 14:29:59 markus Exp $ */ +/* $OpenBSD: auth2-none.c,v 1.21 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -68,7 +68,7 @@ userauth_none(struct ssh *ssh) if ((r = sshpkt_get_end(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); if (options.permit_empty_passwd && options.password_authentication) - return (PRIVSEP(auth_password(ssh->authctxt, ""))); + return (PRIVSEP(auth_password(ssh, ""))); return (0); } diff --git a/auth2-passwd.c b/auth2-passwd.c index 5f7ba3244..445016aec 100644 --- a/auth2-passwd.c +++ b/auth2-passwd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-passwd.c,v 1.14 2017/05/30 14:29:59 markus Exp $ */ +/* $OpenBSD: auth2-passwd.c,v 1.15 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -63,7 +63,7 @@ userauth_passwd(struct ssh *ssh) if (change) logit("password change not supported"); - else if (PRIVSEP(auth_password(ssh->authctxt, password)) == 1) + else if (PRIVSEP(auth_password(ssh, password)) == 1) authenticated = 1; explicit_bzero(password, len); free(password); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 8fb7ffe71..8024b1d6a 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.76 2018/02/07 22:52:45 dtucker Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.77 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -88,6 +88,7 @@ static int userauth_pubkey(struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; + struct passwd *pw = authctxt->pw; struct sshbuf *b; struct sshkey *key = NULL; char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL; @@ -95,6 +96,7 @@ userauth_pubkey(struct ssh *ssh) size_t blen, slen; int r, pktype; int authenticated = 0; + struct sshauthopt *authopts = NULL; if (!authctxt->valid) { debug2("%s: disabled because of invalid user", __func__); @@ -185,7 +187,7 @@ userauth_pubkey(struct ssh *ssh) /* test for correct signature */ authenticated = 0; - if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && + if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, ssh->compat)) == 0) { authenticated = 1; @@ -210,7 +212,7 @@ userauth_pubkey(struct ssh *ssh) * if a user is not allowed to login. is this an * issue? -markus */ - if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { + if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) { if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) != 0 || (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || @@ -221,10 +223,14 @@ userauth_pubkey(struct ssh *ssh) authctxt->postponed = 1; } } - if (authenticated != 1) - auth_clear_options(); done: + if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) { + debug("%s: key options inconsistent with existing", __func__); + authenticated = 0; + } debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); + + sshauthopt_free(authopts); sshkey_free(key); free(userstyle); free(pkalg); @@ -254,18 +260,77 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert) return 0; } +/* + * Process a single authorized_principals format line. Returns 0 and sets + * authoptsp is principal is authorised, -1 otherwise. "loc" is used as a + * log preamble for file/line information. + */ +static int +check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert, + const char *loc, struct sshauthopt **authoptsp) +{ + u_int i, found = 0; + char *ep, *line_opts; + const char *reason = NULL; + struct sshauthopt *opts = NULL; + + if (authoptsp != NULL) + *authoptsp = NULL; + + /* Trim trailing whitespace. */ + ep = cp + strlen(cp) - 1; + while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) + *ep-- = '\0'; + + /* + * If the line has internal whitespace then assume it has + * key options. + */ + line_opts = NULL; + if ((ep = strrchr(cp, ' ')) != NULL || + (ep = strrchr(cp, '\t')) != NULL) { + for (; *ep == ' ' || *ep == '\t'; ep++) + ; + line_opts = cp; + cp = ep; + } + if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) { + debug("%s: bad principals options: %s", loc, reason); + auth_debug_add("%s: bad principals options: %s", loc, reason); + return -1; + } + /* Check principals in cert against those on line */ + for (i = 0; i < cert->nprincipals; i++) { + if (strcmp(cp, cert->principals[i]) != 0) + continue; + debug3("%s: matched principal \"%.100s\"", + loc, cert->principals[i]); + found = 1; + } + if (found && authoptsp != NULL) { + *authoptsp = opts; + opts = NULL; + } + sshauthopt_free(opts); + return found ? 0 : -1; +} + static int -process_principals(FILE *f, const char *file, struct passwd *pw, - const struct sshkey_cert *cert) +process_principals(struct ssh *ssh, FILE *f, const char *file, + const struct sshkey_cert *cert, struct sshauthopt **authoptsp) { - char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; + char loc[256], line[SSH_MAX_PUBKEY_BYTES], *cp, *ep; u_long linenum = 0; - u_int i, found_principal = 0; + u_int found_principal = 0; + + if (authoptsp != NULL) + *authoptsp = NULL; while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { /* Always consume entire input */ if (found_principal) continue; + /* Skip leading whitespace. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; @@ -274,50 +339,33 @@ process_principals(FILE *f, const char *file, struct passwd *pw, *ep = '\0'; if (!*cp || *cp == '\n') continue; - /* Trim trailing whitespace. */ - ep = cp + strlen(cp) - 1; - while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) - *ep-- = '\0'; - /* - * If the line has internal whitespace then assume it has - * key options. - */ - line_opts = NULL; - if ((ep = strrchr(cp, ' ')) != NULL || - (ep = strrchr(cp, '\t')) != NULL) { - for (; *ep == ' ' || *ep == '\t'; ep++) - ; - line_opts = cp; - cp = ep; - } - for (i = 0; i < cert->nprincipals; i++) { - if (strcmp(cp, cert->principals[i]) == 0) { - debug3("%s:%lu: matched principal \"%.100s\"", - file, linenum, cert->principals[i]); - if (auth_parse_options(pw, line_opts, - file, linenum) != 1) - continue; - found_principal = 1; - continue; - } - } + + snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum); + if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0) + found_principal = 1; } return found_principal; } +/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */ + static int -match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) +match_principals_file(struct ssh *ssh, struct passwd *pw, char *file, + struct sshkey_cert *cert, struct sshauthopt **authoptsp) { FILE *f; int success; + if (authoptsp != NULL) + *authoptsp = NULL; + temporarily_use_uid(pw); debug("trying authorized principals file %s", file); if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { restore_uid(); return 0; } - success = process_principals(f, file, pw, cert); + success = process_principals(ssh, f, file, cert, authoptsp); fclose(f); restore_uid(); return success; @@ -328,12 +376,13 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) * returns 1 if the principal is allowed or 0 otherwise. */ static int -match_principals_command(struct passwd *user_pw, const struct sshkey *key) +match_principals_command(struct ssh *ssh, struct passwd *user_pw, + const struct sshkey *key, struct sshauthopt **authoptsp) { + struct passwd *runas_pw = NULL; const struct sshkey_cert *cert = key->cert; FILE *f = NULL; int r, ok, found_principal = 0; - struct passwd *pw; int i, ac = 0, uid_swapped = 0; pid_t pid; char *tmp, *username = NULL, *command = NULL, **av = NULL; @@ -341,6 +390,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) char serial_s[16]; void (*osigchld)(int); + if (authoptsp != NULL) + *authoptsp = NULL; if (options.authorized_principals_command == NULL) return 0; if (options.authorized_principals_command_user == NULL) { @@ -358,8 +409,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_principals_command_user, "u", user_pw->pw_name, (char *)NULL); - pw = getpwnam(username); - if (pw == NULL) { + runas_pw = getpwnam(username); + if (runas_pw == NULL) { error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; @@ -417,15 +468,15 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) /* Prepare a printable command for logs, etc. */ command = argv_assemble(ac, av); - if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, + if ((pid = subprocess("AuthorizedPrincipalsCommand", runas_pw, command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) goto out; uid_swapped = 1; - temporarily_use_uid(pw); + temporarily_use_uid(runas_pw); - ok = process_principals(f, "(command)", pw, cert); + ok = process_principals(ssh, f, "(command)", cert, authoptsp); fclose(f); f = NULL; @@ -452,130 +503,225 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) free(keytext); return found_principal; } + +static void +skip_space(char **cpp) +{ + char *cp; + + for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) + ; + *cpp = cp; +} + +/* + * Advanced *cpp past the end of key options, defined as the first unquoted + * whitespace character. Returns 0 on success or -1 on failure (e.g. + * unterminated quotes). + */ +static int +advance_past_options(char **cpp) +{ + char *cp = *cpp; + int quoted = 0; + + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; + } + *cpp = cp; + /* return failure for unterminated quotes */ + return (*cp == '\0' && quoted) ? -1 : 0; +} + +/* + * Check a single line of an authorized_keys-format file. Returns 0 if key + * matches, -1 otherwise. Will return key/cert options via *authoptsp + * on success. "loc" is used as file/line location in log messages. + */ +static int +check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key, + char *cp, const char *loc, struct sshauthopt **authoptsp) +{ + int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type; + struct sshkey *found = NULL; + struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL; + char *key_options = NULL, *fp = NULL; + const char *reason = NULL; + int ret = -1; + + if (authoptsp != NULL) + *authoptsp = NULL; + + if ((found = sshkey_new(want_keytype)) == NULL) { + debug3("%s: keytype %d failed", __func__, want_keytype); + goto out; + } + + /* XXX djm: peek at key type in line and skip if unwanted */ + + if (sshkey_read(found, &cp) != 0) { + /* no key? check for options */ + debug2("%s: check options: '%s'", loc, cp); + key_options = cp; + if (advance_past_options(&cp) != 0) { + reason = "invalid key option string"; + goto fail_reason; + } + skip_space(&cp); + if (sshkey_read(found, &cp) != 0) { + /* still no key? advance to next line*/ + debug2("%s: advance: '%s'", loc, cp); + goto out; + } + } + /* Parse key options now; we need to know if this is a CA key */ + if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) { + debug("%s: bad key options: %s", loc, reason); + auth_debug_add("%s: bad key options: %s", loc, reason); + goto out; + } + /* Ignore keys that don't match or incorrectly marked as CAs */ + if (sshkey_is_cert(key)) { + /* Certificate; check signature key against CA */ + if (!sshkey_equal(found, key->cert->signature_key) || + !keyopts->cert_authority) + goto out; + } else { + /* Plain key: check it against key found in file */ + if (!sshkey_equal(found, key) || keyopts->cert_authority) + goto out; + } + + /* We have a candidate key, perform authorisation checks */ + if ((fp = sshkey_fingerprint(found, + options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) + fatal("%s: fingerprint failed", __func__); + + debug("%s: matching %s found: %s %s", loc, + sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp); + + if (auth_authorise_keyopts(ssh, pw, keyopts, + sshkey_is_cert(key), loc) != 0) { + reason = "Refused by key options"; + goto fail_reason; + } + /* That's all we need for plain keys. */ + if (!sshkey_is_cert(key)) { + verbose("Accepted key %s %s found at %s", + sshkey_type(found), fp, loc); + finalopts = keyopts; + keyopts = NULL; + goto success; + } + + /* + * Additional authorisation for certificates. + */ + + /* Parse and check options present in certificate */ + if ((certopts = sshauthopt_from_cert(key)) == NULL) { + reason = "Invalid certificate options"; + goto fail_reason; + } + if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) { + reason = "Refused by certificate options"; + goto fail_reason; + } + if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL) + goto fail_reason; + + /* + * If the user has specified a list of principals as + * a key option, then prefer that list to matching + * their username in the certificate principals list. + */ + if (keyopts->cert_principals != NULL && + !match_principals_option(keyopts->cert_principals, key->cert)) { + reason = "Certificate does not contain an authorized principal"; + goto fail_reason; + } + if (sshkey_cert_check_authority(key, 0, 0, + keyopts->cert_principals == NULL ? pw->pw_name : NULL, &reason) != 0) + goto fail_reason; + + verbose("Accepted certificate ID \"%s\" (serial %llu) " + "signed by CA %s %s found at %s", + key->cert->key_id, + (unsigned long long)key->cert->serial, + sshkey_type(found), fp, loc); + + success: + if (finalopts == NULL) + fatal("%s: internal error: missing options", __func__); + if (authoptsp != NULL) { + *authoptsp = finalopts; + finalopts = NULL; + } + /* success */ + ret = 0; + goto out; + + fail_reason: + error("%s", reason); + auth_debug_add("%s", reason); + out: + free(fp); + sshauthopt_free(keyopts); + sshauthopt_free(certopts); + sshauthopt_free(finalopts); + sshkey_free(found); + return ret; +} + /* * Checks whether key is allowed in authorized_keys-format file, * returns 1 if the key is allowed or 0 otherwise. */ static int -check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw) +check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f, + char *file, struct sshkey *key, struct sshauthopt **authoptsp) { - char line[SSH_MAX_PUBKEY_BYTES]; + char *cp, line[SSH_MAX_PUBKEY_BYTES], loc[256]; int found_key = 0; u_long linenum = 0; - struct sshkey *found = NULL; - while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { - char *cp, *key_options = NULL, *fp = NULL; - const char *reason = NULL; + if (authoptsp != NULL) + *authoptsp = NULL; + while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { /* Always consume entire file */ if (found_key) continue; - sshkey_free(found); - found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type); - if (found == NULL) - goto done; - auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ - for (cp = line; *cp == ' ' || *cp == '\t'; cp++) - ; + cp = line; + skip_space(&cp); if (!*cp || *cp == '\n' || *cp == '#') continue; - - if (sshkey_read(found, &cp) != 0) { - /* no key? check if there are options for this key */ - int quoted = 0; - debug2("user_key_allowed: check options: '%s'", cp); - key_options = cp; - for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { - if (*cp == '\\' && cp[1] == '"') - cp++; /* Skip both */ - else if (*cp == '"') - quoted = !quoted; - } - /* Skip remaining whitespace. */ - for (; *cp == ' ' || *cp == '\t'; cp++) - ; - if (sshkey_read(found, &cp) != 0) { - debug2("user_key_allowed: advance: '%s'", cp); - /* still no key? advance to next line*/ - continue; - } - } - if (sshkey_is_cert(key)) { - if (!sshkey_equal(found, key->cert->signature_key)) - continue; - if (auth_parse_options(pw, key_options, file, - linenum) != 1) - continue; - if (!key_is_cert_authority) - continue; - if ((fp = sshkey_fingerprint(found, - options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) - continue; - debug("matching CA found: file %s, line %lu, %s %s", - file, linenum, sshkey_type(found), fp); - /* - * If the user has specified a list of principals as - * a key option, then prefer that list to matching - * their username in the certificate principals list. - */ - if (authorized_principals != NULL && - !match_principals_option(authorized_principals, - key->cert)) { - reason = "Certificate does not contain an " - "authorized principal"; - fail_reason: - free(fp); - error("%s", reason); - auth_debug_add("%s", reason); - continue; - } - if (sshkey_cert_check_authority(key, 0, 0, - authorized_principals == NULL ? pw->pw_name : NULL, - &reason) != 0) - goto fail_reason; - if (auth_cert_options(key, pw, &reason) != 0) - goto fail_reason; - verbose("Accepted certificate ID \"%s\" (serial %llu) " - "signed by %s CA %s via %s", key->cert->key_id, - (unsigned long long)key->cert->serial, - sshkey_type(found), fp, file); - free(fp); - found_key = 1; - break; - } else if (sshkey_equal(found, key)) { - if (auth_parse_options(pw, key_options, file, - linenum) != 1) - continue; - if (key_is_cert_authority) - continue; - if ((fp = sshkey_fingerprint(found, - options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) - continue; - debug("matching key found: file %s, line %lu %s %s", - file, linenum, sshkey_type(found), fp); - free(fp); + snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum); + if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0) found_key = 1; - continue; - } } - done: - sshkey_free(found); - if (!found_key) - debug2("key not found"); return found_key; } /* Authenticate a certificate key against TrustedUserCAKeys */ static int -user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) +user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key, + struct sshauthopt **authoptsp) { char *ca_fp, *principals_file = NULL; const char *reason; + struct sshauthopt *principals_opts = NULL, *cert_opts = NULL; + struct sshauthopt *final_opts = NULL; int r, ret = 0, found_principal = 0, use_authorized_principals; + if (authoptsp != NULL) + *authoptsp = NULL; + if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) return 0; @@ -596,36 +742,69 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) * against the username. */ if ((principals_file = authorized_principals_file(pw)) != NULL) { - if (match_principals_file(principals_file, pw, key->cert)) + if (match_principals_file(ssh, pw, principals_file, + key->cert, &principals_opts)) found_principal = 1; } /* Try querying command if specified */ - if (!found_principal && match_principals_command(pw, key)) + if (!found_principal && match_principals_command(ssh, pw, key, + &principals_opts)) found_principal = 1; /* If principals file or command is specified, then require a match */ use_authorized_principals = principals_file != NULL || options.authorized_principals_command != NULL; if (!found_principal && use_authorized_principals) { reason = "Certificate does not contain an authorized principal"; - fail_reason: - error("%s", reason); - auth_debug_add("%s", reason); - goto out; + goto fail_reason; } + if (use_authorized_principals && principals_opts == NULL) + fatal("%s: internal error: missing principals_opts", __func__); if (sshkey_cert_check_authority(key, 0, 1, use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) goto fail_reason; - if (auth_cert_options(key, pw, &reason) != 0) + + /* Check authority from options in key and from principals file/cmd */ + if ((cert_opts = sshauthopt_from_cert(key)) == NULL) { + reason = "Invalid certificate options"; + goto fail_reason; + } + if (auth_authorise_keyopts(ssh, pw, cert_opts, 0, "cert") != 0) { + reason = "Refused by certificate options"; goto fail_reason; + } + if (principals_opts == NULL) { + final_opts = cert_opts; + cert_opts = NULL; + } else { + if (auth_authorise_keyopts(ssh, pw, principals_opts, 0, + "principals") != 0) { + reason = "Refused by certificate principals options"; + goto fail_reason; + } + if ((final_opts = sshauthopt_merge(principals_opts, + cert_opts, &reason)) == NULL) { + fail_reason: + error("%s", reason); + auth_debug_add("%s", reason); + goto out; + } + } + /* Success */ verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " "%s CA %s via %s", key->cert->key_id, (unsigned long long)key->cert->serial, sshkey_type(key->cert->signature_key), ca_fp, options.trusted_user_ca_keys); + if (authoptsp != NULL) { + *authoptsp = final_opts; + final_opts = NULL; + } ret = 1; - out: + sshauthopt_free(principals_opts); + sshauthopt_free(cert_opts); + sshauthopt_free(final_opts); free(principals_file); free(ca_fp); return ret; @@ -636,17 +815,22 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) * returns 1 if the key is allowed or 0 otherwise. */ static int -user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file) +user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key, + char *file, struct sshauthopt **authoptsp) { FILE *f; int found_key = 0; + if (authoptsp != NULL) + *authoptsp = NULL; + /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { - found_key = check_authkeys_file(f, file, key, pw); + found_key = check_authkeys_file(ssh, pw, f, file, + key, authoptsp); fclose(f); } @@ -659,17 +843,20 @@ user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file) * returns 1 if the key is allowed or 0 otherwise. */ static int -user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) +user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw, + struct sshkey *key, struct sshauthopt **authoptsp) { + struct passwd *runas_pw = NULL; FILE *f = NULL; int r, ok, found_key = 0; - struct passwd *pw; int i, uid_swapped = 0, ac = 0; pid_t pid; char *username = NULL, *key_fp = NULL, *keytext = NULL; char *tmp, *command = NULL, **av = NULL; void (*osigchld)(int); + if (authoptsp != NULL) + *authoptsp = NULL; if (options.authorized_keys_command == NULL) return 0; if (options.authorized_keys_command_user == NULL) { @@ -686,8 +873,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_keys_command_user, "u", user_pw->pw_name, (char *)NULL); - pw = getpwnam(username); - if (pw == NULL) { + runas_pw = getpwnam(username); + if (runas_pw == NULL) { error("AuthorizedKeysCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; @@ -745,15 +932,16 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) xasprintf(&command, "%s %s", av[0], av[1]); } - if ((pid = subprocess("AuthorizedKeysCommand", pw, command, + if ((pid = subprocess("AuthorizedKeysCommand", runas_pw, command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) goto out; uid_swapped = 1; - temporarily_use_uid(pw); + temporarily_use_uid(runas_pw); - ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); + ok = check_authkeys_file(ssh, user_pw, f, + options.authorized_keys_command, key, authoptsp); fclose(f); f = NULL; @@ -783,10 +971,14 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) * Check whether key authenticates and authorises the user. */ int -user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) +user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key, + int auth_attempt, struct sshauthopt **authoptsp) { u_int success, i; char *file; + struct sshauthopt *opts = NULL; + if (authoptsp != NULL) + *authoptsp = NULL; if (auth_key_is_revoked(key)) return 0; @@ -794,25 +986,31 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) auth_key_is_revoked(key->cert->signature_key)) return 0; - success = user_cert_trusted_ca(pw, key); - if (success) - return success; + if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0) + goto out; + sshauthopt_free(opts); + opts = NULL; - success = user_key_command_allowed2(pw, key); - if (success > 0) - return success; + if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0) + goto out; + sshauthopt_free(opts); + opts = NULL; for (i = 0; !success && i < options.num_authkeys_files; i++) { - if (strcasecmp(options.authorized_keys_files[i], "none") == 0) continue; file = expand_authorized_keys( options.authorized_keys_files[i], pw); - - success = user_key_allowed2(pw, key, file); + success = user_key_allowed2(ssh, pw, key, file, &opts); free(file); } + out: + if (success && authoptsp != NULL) { + *authoptsp = opts; + opts = NULL; + } + sshauthopt_free(opts); return success; } diff --git a/auth2.c b/auth2.c index c80911aeb..e0034229a 100644 --- a/auth2.c +++ b/auth2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2.c,v 1.144 2018/01/23 05:27:21 djm Exp $ */ +/* $OpenBSD: auth2.c,v 1.145 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -310,7 +310,7 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && - !auth_root_allowed(method)) { + !auth_root_allowed(ssh, method)) { authenticated = 0; #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); diff --git a/misc.c b/misc.c index b45a9ec63..1e660b021 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.124 2018/03/02 03:02:11 djm Exp $ */ +/* $OpenBSD: misc.c,v 1.125 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -1921,6 +1921,7 @@ child_set_env(char ***envp, u_int *envsizep, const char *name, } /* Allocate space and format the variable in the appropriate slot. */ + /* XXX xasprintf */ env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); } diff --git a/monitor.c b/monitor.c index e4ac3ccfd..c68e1b0d9 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.179 2018/02/05 05:37:46 tb Exp $ */ +/* $OpenBSD: monitor.c,v 1.180 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -116,6 +116,7 @@ extern u_char session_id[]; extern Buffer auth_debug; extern int auth_debug_init; extern Buffer loginmsg; +extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ /* State exported from the child */ static struct sshbuf *child_state; @@ -172,6 +173,7 @@ static Authctxt *authctxt; static u_char *key_blob = NULL; static u_int key_bloblen = 0; static int key_blobtype = MM_NOKEY; +static struct sshauthopt *key_opts = NULL; static char *hostbased_cuser = NULL; static char *hostbased_chost = NULL; static char *auth_method = "unknown"; @@ -252,7 +254,6 @@ struct mon_table mon_dispatch_postauth20[] = { struct mon_table *mon_dispatch; /* Specifies if a certain message is allowed at the moment */ - static void monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit) { @@ -297,6 +298,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) authctxt = _authctxt; memset(authctxt, 0, sizeof(*authctxt)); + ssh->authctxt = authctxt; authctxt->loginmsg = &loginmsg; @@ -331,7 +333,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) fatal("%s: unexpected authentication from %d", __func__, ent->type); if (authctxt->pw->pw_uid == 0 && - !auth_root_allowed(auth_method)) + !auth_root_allowed(ssh, auth_method)) authenticated = 0; #ifdef USE_PAM /* PAM needs to perform account checks after auth */ @@ -365,6 +367,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) debug("%s: %s has been authenticated by privileged process", __func__, authctxt->user); + ssh->authctxt = NULL; ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); mm_get_keystate(pmonitor); @@ -413,7 +416,7 @@ monitor_child_postauth(struct monitor *pmonitor) monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); - if (!no_pty_flag) { + if (auth_opts->permit_pty_flag) { monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); } @@ -558,9 +561,11 @@ monitor_reset_key_state(void) free(key_blob); free(hostbased_cuser); free(hostbased_chost); + sshauthopt_free(key_opts); key_blob = NULL; key_bloblen = 0; key_blobtype = MM_NOKEY; + key_opts = NULL; hostbased_cuser = NULL; hostbased_chost = NULL; } @@ -828,6 +833,7 @@ mm_answer_authserv(int sock, Buffer *m) int mm_answer_authpassword(int sock, Buffer *m) { + struct ssh *ssh = active_state; /* XXX */ static int call_count; char *passwd; int authenticated; @@ -838,7 +844,7 @@ mm_answer_authpassword(int sock, Buffer *m) passwd = buffer_get_string(m, &plen); /* Only authenticate if the context is valid */ authenticated = options.password_authentication && - auth_password(authctxt, passwd); + auth_password(ssh, passwd); explicit_bzero(passwd, strlen(passwd)); free(passwd); @@ -1129,15 +1135,16 @@ mm_answer_pam_free_ctx(int sock, Buffer *m) int mm_answer_keyallowed(int sock, Buffer *m) { + struct ssh *ssh = active_state; /* XXX */ struct sshkey *key; char *cuser, *chost; u_char *blob; u_int bloblen, pubkey_auth_attempt; enum mm_keytype type = 0; - int allowed = 0; + int r, allowed = 0; + struct sshauthopt *opts = NULL; debug3("%s entering", __func__); - type = buffer_get_int(m); cuser = buffer_get_string(m, NULL); chost = buffer_get_string(m, NULL); @@ -1156,28 +1163,31 @@ mm_answer_keyallowed(int sock, Buffer *m) switch (type) { case MM_USERKEY: - allowed = options.pubkey_authentication && - !auth2_key_already_used(authctxt, key) && - match_pattern_list(sshkey_ssh_name(key), - options.pubkey_key_types, 0) == 1 && - user_key_allowed(authctxt->pw, key, - pubkey_auth_attempt); auth_method = "publickey"; - if (options.pubkey_authentication && - (!pubkey_auth_attempt || allowed != 1)) - auth_clear_options(); + if (!options.pubkey_authentication) + break; + if (auth2_key_already_used(authctxt, key)) + break; + if (match_pattern_list(sshkey_ssh_name(key), + options.pubkey_key_types, 0) != 1) + break; + allowed = user_key_allowed(ssh, authctxt->pw, key, + pubkey_auth_attempt, &opts); break; case MM_HOSTKEY: - allowed = options.hostbased_authentication && - !auth2_key_already_used(authctxt, key) && - match_pattern_list(sshkey_ssh_name(key), - options.hostbased_key_types, 0) == 1 && - hostbased_key_allowed(authctxt->pw, + auth_method = "hostbased"; + if (!options.hostbased_authentication) + break; + if (auth2_key_already_used(authctxt, key)) + break; + if (match_pattern_list(sshkey_ssh_name(key), + options.hostbased_key_types, 0) != 1) + break; + allowed = hostbased_key_allowed(authctxt->pw, cuser, chost, key); auth2_record_info(authctxt, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); - auth_method = "hostbased"; break; default: fatal("%s: unknown key type %d", __func__, type); @@ -1185,7 +1195,10 @@ mm_answer_keyallowed(int sock, Buffer *m) } } - debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed"); + debug3("%s: %s authentication%s: %s key is %s", __func__, + auth_method, pubkey_auth_attempt ? "" : " test", + (key == NULL || !authctxt->valid) ? "invalid" : sshkey_type(key), + allowed ? "allowed" : "not allowed"); auth2_record_key(authctxt, 0, key); sshkey_free(key); @@ -1198,6 +1211,7 @@ mm_answer_keyallowed(int sock, Buffer *m) key_blob = blob; key_bloblen = bloblen; key_blobtype = type; + key_opts = opts; hostbased_cuser = cuser; hostbased_chost = chost; } else { @@ -1210,10 +1224,13 @@ mm_answer_keyallowed(int sock, Buffer *m) buffer_clear(m); buffer_put_int(m, allowed); - buffer_put_int(m, forced_command != NULL); - + if (opts != NULL && (r = sshauthopt_serialise(opts, m, 1)) != 0) + fatal("%s: sshauthopt_serialise: %s", __func__, ssh_err(r)); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); + if (!allowed) + sshauthopt_free(opts); + return (0); } @@ -1336,6 +1353,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, int mm_answer_keyverify(int sock, struct sshbuf *m) { + struct ssh *ssh = active_state; /* XXX */ struct sshkey *key; u_char *signature, *data, *blob; char *sigalg; @@ -1390,6 +1408,8 @@ mm_answer_keyverify(int sock, struct sshbuf *m) free(data); free(sigalg); + if (key_blobtype == MM_USERKEY) + auth_activate_options(ssh, key_opts); monitor_reset_key_state(); sshkey_free(key); diff --git a/monitor_wrap.c b/monitor_wrap.c index cce318bc5..9666bda4b 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.98 2018/01/08 15:14:44 markus Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.99 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -351,7 +351,7 @@ mm_inform_authserv(char *service, char *style) /* Do the password authentication */ int -mm_auth_password(Authctxt *authctxt, char *password) +mm_auth_password(struct ssh *ssh, char *password) { Buffer m; int authenticated = 0; @@ -378,34 +378,38 @@ mm_auth_password(Authctxt *authctxt, char *password) } int -mm_user_key_allowed(struct passwd *pw, struct sshkey *key, - int pubkey_auth_attempt) +mm_user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key, + int pubkey_auth_attempt, struct sshauthopt **authoptp) { return (mm_key_allowed(MM_USERKEY, NULL, NULL, key, - pubkey_auth_attempt)); + pubkey_auth_attempt, authoptp)); } int mm_hostbased_key_allowed(struct passwd *pw, const char *user, const char *host, struct sshkey *key) { - return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0)); + return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0, NULL)); } int mm_key_allowed(enum mm_keytype type, const char *user, const char *host, - struct sshkey *key, int pubkey_auth_attempt) + struct sshkey *key, int pubkey_auth_attempt, struct sshauthopt **authoptp) { Buffer m; u_char *blob; u_int len; - int allowed = 0, have_forced = 0; + int r, allowed = 0; + struct sshauthopt *opts = NULL; debug3("%s entering", __func__); + if (authoptp != NULL) + *authoptp = NULL; + /* Convert the key to a blob and the pass it over */ if (!key_to_blob(key, &blob, &len)) - return (0); + return 0; buffer_init(&m); buffer_put_int(&m, type); @@ -418,18 +422,24 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host, mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m); debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __func__); - mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m); + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_KEYALLOWED, &m); allowed = buffer_get_int(&m); - - /* fake forced command */ - auth_clear_options(); - have_forced = buffer_get_int(&m); - forced_command = have_forced ? xstrdup("true") : NULL; - + if (allowed && type == MM_USERKEY) { + if ((r = sshauthopt_deserialise(&m, &opts)) != 0) + fatal("%s: sshauthopt_deserialise: %s", + __func__, ssh_err(r)); + } buffer_free(&m); - return (allowed); + if (authoptp != NULL) { + *authoptp = opts; + opts = NULL; + } + sshauthopt_free(opts); + + return allowed; } /* diff --git a/monitor_wrap.h b/monitor_wrap.h index f5af1e819..762332704 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.36 2017/12/18 02:25:15 djm Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.37 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -35,6 +35,8 @@ enum mm_keytype { MM_NOKEY, MM_HOSTKEY, MM_USERKEY }; struct monitor; struct Authctxt; +struct sshkey; +struct sshauthopt; void mm_log_handler(LogLevel, const char *, void *); int mm_is_monitor(void); @@ -44,10 +46,11 @@ int mm_key_sign(struct sshkey *, u_char **, u_int *, const u_char *, u_int, void mm_inform_authserv(char *, char *); struct passwd *mm_getpwnamallow(const char *); char *mm_auth2_read_banner(void); -int mm_auth_password(struct Authctxt *, char *); +int mm_auth_password(struct ssh *, char *); int mm_key_allowed(enum mm_keytype, const char *, const char *, struct sshkey *, - int); -int mm_user_key_allowed(struct passwd *, struct sshkey *, int); + int, struct sshauthopt **); +int mm_user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int, + struct sshauthopt **); int mm_hostbased_key_allowed(struct passwd *, const char *, const char *, struct sshkey *); int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, diff --git a/serverloop.c b/serverloop.c index 7e2abd52f..d6fe24cc1 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.204 2018/02/11 21:16:56 dtucker Exp $ */ +/* $OpenBSD: serverloop.c,v 1.205 2018/03/03 03:15:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -82,6 +82,7 @@ extern ServerOptions options; /* XXX */ extern Authctxt *the_authctxt; +extern struct sshauthopt *auth_opts; extern int use_privsep; static int no_more_sessions = 0; /* Disallow further sessions. */ @@ -456,12 +457,13 @@ server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg) originator_port = packet_get_int(); packet_check_eom(); - debug("server_request_direct_tcpip: originator %s port %d, target %s " - "port %d", originator, originator_port, target, target_port); + debug("%s: originator %s port %d, target %s port %d", __func__, + originator, originator_port, target, target_port); /* XXX fine grained permissions */ if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 && - !no_port_forwarding_flag && !options.disable_forwarding) { + auth_opts->permit_port_forwarding_flag && + !options.disable_forwarding) { c = channel_connect_to_port(ssh, target, target_port, "direct-tcpip", "direct-tcpip", reason, errmsg); } else { @@ -487,20 +489,20 @@ server_request_direct_streamlocal(struct ssh *ssh) struct passwd *pw = the_authctxt->pw; if (pw == NULL || !the_authctxt->valid) - fatal("server_input_global_request: no/invalid user"); + fatal("%s: no/invalid user", __func__); target = packet_get_string(NULL); originator = packet_get_string(NULL); originator_port = packet_get_int(); packet_check_eom(); - debug("server_request_direct_streamlocal: originator %s port %d, target %s", + debug("%s: originator %s port %d, target %s", __func__, originator, originator_port, target); /* XXX fine grained permissions */ if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 && - !no_port_forwarding_flag && !options.disable_forwarding && - (pw->pw_uid == 0 || use_privsep)) { + auth_opts->permit_port_forwarding_flag && + !options.disable_forwarding && (pw->pw_uid == 0 || use_privsep)) { c = channel_connect_to_path(ssh, target, "direct-streamlocal@openssh.com", "direct-streamlocal"); } else { @@ -519,8 +521,7 @@ static Channel * server_request_tun(struct ssh *ssh) { Channel *c = NULL; - int mode, tun; - int sock; + int mode, tun, sock; char *tmp, *ifname = NULL; mode = packet_get_int(); @@ -539,10 +540,10 @@ server_request_tun(struct ssh *ssh) } tun = packet_get_int(); - if (forced_tun_device != -1) { - if (tun != SSH_TUNID_ANY && forced_tun_device != tun) + if (auth_opts->force_tun_device != -1) { + if (tun != SSH_TUNID_ANY && auth_opts->force_tun_device != tun) goto done; - tun = forced_tun_device; + tun = auth_opts->force_tun_device; } sock = tun_open(tun, mode, &ifname); if (sock < 0) @@ -767,7 +768,8 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh) /* check permissions */ if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 || - no_port_forwarding_flag || options.disable_forwarding || + !auth_opts->permit_port_forwarding_flag || + options.disable_forwarding || (!want_reply && fwd.listen_port == 0) || (fwd.listen_port != 0 && !bind_permitted(fwd.listen_port, pw->pw_uid))) { @@ -805,7 +807,8 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh) /* check permissions */ if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0 - || no_port_forwarding_flag || options.disable_forwarding || + || !auth_opts->permit_port_forwarding_flag || + options.disable_forwarding || (pw->pw_uid != 0 && !use_privsep)) { success = 0; packet_send_debug("Server has disabled " diff --git a/session.c b/session.c index 51c5ea0ec..58826db16 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.293 2017/10/23 05:08:00 djm Exp $ */ +/* $OpenBSD: session.c,v 1.294 2018/03/03 03:15:51 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -140,6 +140,7 @@ extern u_int utmp_len; extern int startup_pipe; extern void destroy_sensitive_data(void); extern Buffer loginmsg; +extern struct sshauthopt *auth_opts; char *tun_fwd_ifnames; /* serverloop.c */ /* original command from peer. */ @@ -288,14 +289,42 @@ prepare_auth_info_file(struct passwd *pw, struct sshbuf *info) restore_uid(); } +static void +set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts) +{ + char *tmp, *cp, *host; + int port; + size_t i; + + if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) + return; + channel_clear_permitted_opens(ssh); + for (i = 0; i < auth_opts->npermitopen; i++) { + tmp = cp = xstrdup(auth_opts->permitopen[i]); + /* This shouldn't fail as it has already been checked */ + if ((host = hpdelim(&cp)) == NULL) + fatal("%s: internal error: hpdelim", __func__); + host = cleanhostname(host); + if (cp == NULL || (port = permitopen_port(cp)) < 0) + fatal("%s: internal error: permitopen port", + __func__); + channel_add_permitted_opens(ssh, host, port); + free(tmp); + } +} + void do_authenticated(struct ssh *ssh, Authctxt *authctxt) { setproctitle("%s", authctxt->pw->pw_name); + auth_log_authopts("active", auth_opts, 0); + /* setup the channel layer */ /* XXX - streamlocal? */ - if (no_port_forwarding_flag || options.disable_forwarding || + set_permitopen_from_authopts(ssh, auth_opts); + if (!auth_opts->permit_port_forwarding_flag || + options.disable_forwarding || (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) channel_disable_adm_local_opens(ssh); else @@ -642,9 +671,9 @@ do_exec(struct ssh *ssh, Session *s, const char *command) original_command = command; command = options.adm_forced_command; forced = "(config)"; - } else if (forced_command) { + } else if (auth_opts->force_command != NULL) { original_command = command; - command = forced_command; + command = auth_opts->force_command; forced = "(key-option)"; } if (forced != NULL) { @@ -947,8 +976,9 @@ static char ** do_setup_env(struct ssh *ssh, Session *s, const char *shell) { char buf[256]; + size_t n; u_int i, envsize; - char **env, *laddr; + char *ocp, *cp, **env, *laddr; struct passwd *pw = s->pw; #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) char *path = NULL; @@ -1023,20 +1053,17 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) if (getenv("TZ")) child_set_env(&env, &envsize, "TZ", getenv("TZ")); - /* Set custom environment options from RSA authentication. */ - while (custom_environment) { - struct envstring *ce = custom_environment; - char *str = ce->s; - - for (i = 0; str[i] != '=' && str[i]; i++) - ; - if (str[i] == '=') { - str[i] = 0; - child_set_env(&env, &envsize, str, str + i + 1); + /* Set custom environment options from pubkey authentication. */ + if (options.permit_user_env) { + for (n = 0 ; n < auth_opts->nenv; n++) { + ocp = xstrdup(auth_opts->env[n]); + cp = strchr(ocp, '='); + if (*cp == '=') { + *cp = '\0'; + child_set_env(&env, &envsize, ocp, cp + 1); + } + free(ocp); } - custom_environment = ce->next; - free(ce->s); - free(ce); } /* SSH_CLIENT deprecated */ @@ -1138,7 +1165,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) * first in this order). */ static void -do_rc_files(Session *s, const char *shell) +do_rc_files(struct ssh *ssh, Session *s, const char *shell) { FILE *f = NULL; char cmd[1024]; @@ -1150,7 +1177,7 @@ do_rc_files(Session *s, const char *shell) /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ if (!s->is_subsystem && options.adm_forced_command == NULL && - !no_user_rc && options.permit_user_rc && + auth_opts->permit_user_rc && options.permit_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) { snprintf(cmd, sizeof cmd, "%s -c '%s %s'", shell, _PATH_BSHELL, _PATH_SSH_USER_RC); @@ -1570,7 +1597,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) closefrom(STDERR_FILENO + 1); - do_rc_files(s, shell); + do_rc_files(ssh, s, shell); /* restore SIGPIPE for child */ signal(SIGPIPE, SIG_DFL); @@ -1833,8 +1860,8 @@ session_pty_req(struct ssh *ssh, Session *s) u_int len; int n_bytes; - if (no_pty_flag || !options.permit_tty) { - debug("Allocating a pty not permitted for this authentication."); + if (!auth_opts->permit_pty_flag || !options.permit_tty) { + debug("Allocating a pty not permitted for this connection."); return 0; } if (s->ttyfd != -1) { @@ -2022,9 +2049,11 @@ static int session_auth_agent_req(struct ssh *ssh, Session *s) { static int called = 0; + packet_check_eom(); - if (no_agent_forwarding_flag || !options.allow_agent_forwarding) { - debug("session_auth_agent_req: no_agent_forwarding_flag"); + if (!auth_opts->permit_agent_forwarding_flag || + !options.allow_agent_forwarding) { + debug("%s: agent forwarding disabled", __func__); return 0; } if (called) { @@ -2402,8 +2431,8 @@ session_setup_x11fwd(struct ssh *ssh, Session *s) char hostname[NI_MAXHOST]; u_int i; - if (no_x11_forwarding_flag) { - packet_send_debug("X11 forwarding disabled in user configuration file."); + if (!auth_opts->permit_x11_forwarding_flag) { + packet_send_debug("X11 forwarding disabled by key options."); return 0; } if (!options.x11_forwarding) { @@ -2412,7 +2441,7 @@ session_setup_x11fwd(struct ssh *ssh, Session *s) } if (options.xauth_location == NULL || (stat(options.xauth_location, &st) == -1)) { - packet_send_debug("No xauth program; cannot forward with spoofing."); + packet_send_debug("No xauth program; cannot forward X11."); return 0; } if (s->display != NULL) { diff --git a/sshd.c b/sshd.c index 0b9a7ec46..fd95b681b 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.505 2018/02/23 15:58:38 markus Exp $ */ +/* $OpenBSD: sshd.c,v 1.506 2018/03/03 03:15:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -119,6 +119,7 @@ #endif #include "monitor_wrap.h" #include "ssh-sandbox.h" +#include "auth-options.h" #include "version.h" #include "ssherr.h" @@ -232,6 +233,9 @@ static int privsep_chroot = 1; /* global authentication context */ Authctxt *the_authctxt = NULL; +/* global key/cert auth options. XXX move to permanent ssh->authctxt? */ +struct sshauthopt *auth_opts = NULL; + /* sshd_config buffer */ Buffer cfg; @@ -2066,6 +2070,10 @@ main(int ac, char **av) /* XXX global for cleanup, access from other modules */ the_authctxt = authctxt; + /* Set default key authentication options */ + if ((auth_opts = sshauthopt_new_with_keys_defaults()) == NULL) + fatal("allocation failed"); + /* prepare buffer to collect messages to display to user after login */ buffer_init(&loginmsg); auth_debug_reset(); @@ -2122,7 +2130,7 @@ main(int ac, char **av) #ifdef USE_PAM if (options.use_pam) { do_pam_setcred(1); - do_pam_session(); + do_pam_session(ssh); } #endif -- cgit v1.2.3