From owner-svn-src-all@freebsd.org Sat Oct 6 21:32:58 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id AACD210C7719; Sat, 6 Oct 2018 21:32:58 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 60AE9854D1; Sat, 6 Oct 2018 21:32:58 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 424C12337; Sat, 6 Oct 2018 21:32:58 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w96LWwrd002928; Sat, 6 Oct 2018 21:32:58 GMT (envelope-from emaste@FreeBSD.org) Received: (from emaste@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w96LWufS002919; Sat, 6 Oct 2018 21:32:56 GMT (envelope-from emaste@FreeBSD.org) Message-Id: <201810062132.w96LWufS002919@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: emaste set sender to emaste@FreeBSD.org using -f From: Ed Maste Date: Sat, 6 Oct 2018 21:32:56 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r339216 - head/crypto/openssh X-SVN-Group: head X-SVN-Commit-Author: emaste X-SVN-Commit-Paths: head/crypto/openssh X-SVN-Commit-Revision: 339216 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 06 Oct 2018 21:32:58 -0000 Author: emaste Date: Sat Oct 6 21:32:55 2018 New Revision: 339216 URL: https://svnweb.freebsd.org/changeset/base/339216 Log: sshd: address capsicum issues * Add a wrapper to proxy login_getpwclass(3) as it is not allowed in capability mode. * Cache timezone data via caph_cache_tzdata() as we cannot access the timezone file. * Reverse resolve hostname before entering capability mode. PR: 231172 Submitted by: naito.yuichiro@gmail.com Reviewed by: cem, des Approved by: re (rgrimes) MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D17128 Modified: head/crypto/openssh/auth2.c head/crypto/openssh/monitor.c head/crypto/openssh/monitor.h head/crypto/openssh/monitor_wrap.c head/crypto/openssh/monitor_wrap.h head/crypto/openssh/sandbox-capsicum.c head/crypto/openssh/sshbuf-getput-basic.c head/crypto/openssh/sshbuf.h head/crypto/openssh/sshd.c Modified: head/crypto/openssh/auth2.c ============================================================================== --- head/crypto/openssh/auth2.c Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/auth2.c Sat Oct 6 21:32:55 2018 (r339216) @@ -316,7 +316,7 @@ input_userauth_request(int type, u_int32_t seq, struct #ifdef HAVE_LOGIN_CAP if (authctxt->pw != NULL && - (lc = login_getpwclass(authctxt->pw)) != NULL) { + (lc = PRIVSEP(login_getpwclass(authctxt->pw))) != NULL) { logit("user %s login class %s", authctxt->pw->pw_name, authctxt->pw->pw_class); from_host = auth_get_canonical_hostname(ssh, options.use_dns); @@ -331,7 +331,7 @@ input_userauth_request(int type, u_int32_t seq, struct authctxt->pw->pw_name, from_host); packet_disconnect("Logins not available right now."); } - login_close(lc); + PRIVSEP(login_close(lc)); } #endif /* HAVE_LOGIN_CAP */ Modified: head/crypto/openssh/monitor.c ============================================================================== --- head/crypto/openssh/monitor.c Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/monitor.c Sat Oct 6 21:32:55 2018 (r339216) @@ -114,6 +114,7 @@ static struct sshbuf *child_state; int mm_answer_moduli(int, struct sshbuf *); int mm_answer_sign(int, struct sshbuf *); +int mm_answer_login_getpwclass(int, struct sshbuf *); int mm_answer_pwnamallow(int, struct sshbuf *); int mm_answer_auth2_read_banner(int, struct sshbuf *); int mm_answer_authserv(int, struct sshbuf *); @@ -189,6 +190,7 @@ struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, #endif {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, + {MONITOR_REQ_GETPWCLASS, MON_AUTH, mm_answer_login_getpwclass}, {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, @@ -707,6 +709,46 @@ mm_answer_sign(int sock, struct sshbuf *m) return (0); } +int +mm_answer_login_getpwclass(int sock, struct sshbuf *m) +{ + login_cap_t *lc; + struct passwd *pw; + int r; + u_int len; + + debug3("%s", __func__); + + pw = sshbuf_get_passwd(m); + if (pw == NULL) + fatal("%s: receive get struct passwd failed", __func__); + + lc = login_getpwclass(pw); + + sshbuf_reset(m); + + if (lc == NULL) { + if (r = sshbuf_put_u8(m, 0) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + goto out; + } + + if ((r = sshbuf_put_u8(m, 1)) != 0 || + (r = sshbuf_put_cstring(m, lc->lc_class)) != 0 || + (r = sshbuf_put_cstring(m, lc->lc_cap)) != 0 || + (r = sshbuf_put_cstring(m, lc->lc_style)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + login_close(lc); + out: + debug3("%s: sending MONITOR_ANS_GETPWCLASS", __func__); + mm_request_send(sock, MONITOR_ANS_GETPWCLASS, m); + + sshbuf_free_passwd(pw); + + return (0); +} + /* Retrieves the password entry and also checks if the user is permitted */ int @@ -745,19 +787,8 @@ mm_answer_pwnamallow(int sock, struct sshbuf *m) authctxt->pw = pwent; authctxt->valid = 1; - /* XXX don't sent pwent to unpriv; send fake class/dir/shell too */ if ((r = sshbuf_put_u8(m, 1)) != 0 || - (r = sshbuf_put_string(m, pwent, sizeof(*pwent))) != 0 || - (r = sshbuf_put_cstring(m, pwent->pw_name)) != 0 || - (r = sshbuf_put_cstring(m, "*")) != 0 || -#ifdef HAVE_STRUCT_PASSWD_PW_GECOS - (r = sshbuf_put_cstring(m, pwent->pw_gecos)) != 0 || -#endif -#ifdef HAVE_STRUCT_PASSWD_PW_CLASS - (r = sshbuf_put_cstring(m, pwent->pw_class)) != 0 || -#endif - (r = sshbuf_put_cstring(m, pwent->pw_dir)) != 0 || - (r = sshbuf_put_cstring(m, pwent->pw_shell)) != 0) + (r = sshbuf_put_passwd(m, pwent)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); out: Modified: head/crypto/openssh/monitor.h ============================================================================== --- head/crypto/openssh/monitor.h Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/monitor.h Sat Oct 6 21:32:55 2018 (r339216) @@ -53,7 +53,8 @@ enum monitor_reqtype { MONITOR_REQ_GSSSTEP = 44, MONITOR_ANS_GSSSTEP = 45, MONITOR_REQ_GSSUSEROK = 46, MONITOR_ANS_GSSUSEROK = 47, MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49, - MONITOR_REQ_TERM = 50, + MONITOR_REQ_GETPWCLASS = 50, MONITOR_ANS_GETPWCLASS = 51, + MONITOR_REQ_TERM = 52, MONITOR_REQ_PAM_START = 100, MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, Modified: head/crypto/openssh/monitor_wrap.c ============================================================================== --- head/crypto/openssh/monitor_wrap.c Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/monitor_wrap.c Sat Oct 6 21:32:55 2018 (r339216) @@ -247,6 +247,57 @@ mm_sshkey_sign(struct sshkey *key, u_char **sigp, size return (0); } +login_cap_t * +mm_login_getpwclass(const struct passwd *pwent) +{ + int r; + struct sshbuf *m; + char rc; + login_cap_t *lc; + + debug3("%s entering", __func__); + + if ((m = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_passwd(m, pwent)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GETPWCLASS, m); + + debug3("%s: waiting for MONITOR_ANS_GETPWCLASS", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GETPWCLASS, m); + + if ((r = sshbuf_get_u8(m, &rc)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + if (rc == 0) { + lc = NULL; + goto out; + } + + lc = xmalloc(sizeof(*lc)); + if ((r = sshbuf_get_cstring(m, &lc->lc_class, NULL)) != 0 || + (r = sshbuf_get_cstring(m, &lc->lc_cap, NULL)) != 0 || + (r = sshbuf_get_cstring(m, &lc->lc_style, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + out: + sshbuf_free(m); + + return (lc); +} + +void +mm_login_close(login_cap_t *lc) +{ + if (lc == NULL) + return; + free(lc->lc_style); + free(lc->lc_class); + free(lc->lc_cap); + free(lc); +} + struct passwd * mm_getpwnamallow(const char *username) { @@ -279,25 +330,9 @@ mm_getpwnamallow(const char *username) goto out; } - /* XXX don't like passing struct passwd like this */ - pw = xcalloc(sizeof(*pw), 1); - if ((r = sshbuf_get_string_direct(m, &p, &len)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); - if (len != sizeof(*pw)) - fatal("%s: struct passwd size mismatch", __func__); - memcpy(pw, p, sizeof(*pw)); - - if ((r = sshbuf_get_cstring(m, &pw->pw_name, NULL)) != 0 || - (r = sshbuf_get_cstring(m, &pw->pw_passwd, NULL)) != 0 || -#ifdef HAVE_STRUCT_PASSWD_PW_GECOS - (r = sshbuf_get_cstring(m, &pw->pw_gecos, NULL)) != 0 || -#endif -#ifdef HAVE_STRUCT_PASSWD_PW_CLASS - (r = sshbuf_get_cstring(m, &pw->pw_class, NULL)) != 0 || -#endif - (r = sshbuf_get_cstring(m, &pw->pw_dir, NULL)) != 0 || - (r = sshbuf_get_cstring(m, &pw->pw_shell, NULL)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); + pw = sshbuf_get_passwd(m); + if (pw == NULL) + fatal("%s: receive get struct passwd failed", __func__); out: /* copy options block as a Match directive may have changed some */ Modified: head/crypto/openssh/monitor_wrap.h ============================================================================== --- head/crypto/openssh/monitor_wrap.h Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/monitor_wrap.h Sat Oct 6 21:32:55 2018 (r339216) @@ -28,6 +28,8 @@ #ifndef _MM_WRAP_H_ #define _MM_WRAP_H_ +#include + extern int use_privsep; #define PRIVSEP(x) (use_privsep ? mm_##x : x) @@ -45,6 +47,8 @@ int mm_sshkey_sign(struct sshkey *, u_char **, size_t const char *, u_int compat); void mm_inform_authserv(char *, char *); struct passwd *mm_getpwnamallow(const char *); +login_cap_t *mm_login_getpwclass(const struct passwd *pwd); +void mm_login_close(login_cap_t *lc); char *mm_auth2_read_banner(void); int mm_auth_password(struct ssh *, char *); int mm_key_allowed(enum mm_keytype, const char *, const char *, struct sshkey *, Modified: head/crypto/openssh/sandbox-capsicum.c ============================================================================== --- head/crypto/openssh/sandbox-capsicum.c Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/sandbox-capsicum.c Sat Oct 6 21:32:55 2018 (r339216) @@ -31,6 +31,7 @@ __RCSID("$FreeBSD$"); #include #include #include +#include #include "log.h" #include "monitor.h" @@ -70,6 +71,8 @@ ssh_sandbox_child(struct ssh_sandbox *box) { struct rlimit rl_zero; cap_rights_t rights; + + caph_cache_tzdata(); rl_zero.rlim_cur = rl_zero.rlim_max = 0; Modified: head/crypto/openssh/sshbuf-getput-basic.c ============================================================================== --- head/crypto/openssh/sshbuf-getput-basic.c Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/sshbuf-getput-basic.c Sat Oct 6 21:32:55 2018 (r339216) @@ -25,6 +25,7 @@ #include #include +#include "xmalloc.h" #include "ssherr.h" #include "sshbuf.h" @@ -461,4 +462,96 @@ sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf, return SSH_ERR_INTERNAL_ERROR; } return 0; +} + +/* + * store struct pwd + */ +int +sshbuf_put_passwd(struct sshbuf *buf, const struct passwd *pwent) +{ + int r; + + /* + * We never send pointer values of struct passwd. + * It is safe from wild pointer even if a new pointer member is added. + */ + + if ((r = sshbuf_put_u64(buf, sizeof(*pwent)) != 0) || + (r = sshbuf_put_cstring(buf, pwent->pw_name)) != 0 || + (r = sshbuf_put_cstring(buf, "*")) != 0 || + (r = sshbuf_put_u32(buf, pwent->pw_uid)) != 0 || + (r = sshbuf_put_u32(buf, pwent->pw_gid)) != 0 || + (r = sshbuf_put_u64(buf, pwent->pw_change)) != 0 || +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS + (r = sshbuf_put_cstring(buf, pwent->pw_gecos)) != 0 || +#endif +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS + (r = sshbuf_put_cstring(buf, pwent->pw_class)) != 0 || +#endif + (r = sshbuf_put_cstring(buf, pwent->pw_dir)) != 0 || + (r = sshbuf_put_cstring(buf, pwent->pw_shell)) != 0 || + (r = sshbuf_put_u64(buf, pwent->pw_expire)) != 0 || + (r = sshbuf_put_u32(buf, pwent->pw_fields)) != 0) { + return r; + } + return 0; +} + +/* + * extract struct pwd + */ +struct passwd * +sshbuf_get_passwd(struct sshbuf *buf) +{ + struct passwd *pw; + int r; + size_t len; + + /* check if size of struct passwd is as same as sender's size */ + r = sshbuf_get_u64(buf, &len); + if (r != 0 || len != sizeof(*pw)) + return NULL; + + pw = xcalloc(1, sizeof(*pw)); + if (sshbuf_get_cstring(buf, &pw->pw_name, NULL) != 0 || + sshbuf_get_cstring(buf, &pw->pw_passwd, NULL) != 0 || + sshbuf_get_u32(buf, &pw->pw_uid) != 0 || + sshbuf_get_u32(buf, &pw->pw_gid) != 0 || + sshbuf_get_u64(buf, &pw->pw_change) != 0 || +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS + sshbuf_get_cstring(buf, &pw->pw_gecos, NULL) != 0 || +#endif +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS + sshbuf_get_cstring(buf, &pw->pw_class, NULL) != 0 || +#endif + sshbuf_get_cstring(buf, &pw->pw_dir, NULL) != 0 || + sshbuf_get_cstring(buf, &pw->pw_shell, NULL) != 0 || + sshbuf_get_u64(buf, &pw->pw_expire) != 0 || + sshbuf_get_u32(buf, &pw->pw_fields) != 0) { + sshbuf_free_passwd(pw); + return NULL; + } + return pw; +} + +/* + * free struct passwd obtained from sshbuf_get_passwd. + */ +void +sshbuf_free_passwd(struct passwd *pwent) +{ + if (pwent == NULL) + return; + free(pwent->pw_shell); + free(pwent->pw_dir); +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS + free(pwent->pw_class); +#endif +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS + free(pwent->pw_gecos); +#endif + free(pwent->pw_passwd); + free(pwent->pw_name); + free(pwent); } Modified: head/crypto/openssh/sshbuf.h ============================================================================== --- head/crypto/openssh/sshbuf.h Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/sshbuf.h Sat Oct 6 21:32:55 2018 (r339216) @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef WITH_OPENSSL # include # ifdef OPENSSL_HAS_ECC @@ -245,6 +246,21 @@ int sshbuf_b64tod(struct sshbuf *buf, const char *b64) * nul character. */ char *sshbuf_dup_string(struct sshbuf *buf); + +/* + * store struct pwd + */ +int sshbuf_put_passwd(struct sshbuf *buf, const struct passwd *pwent); + +/* + * extract struct pwd + */ +struct passwd *sshbuf_get_passwd(struct sshbuf *buf); + +/* + * free struct passwd obtained from sshbuf_get_passwd. + */ +void sshbuf_free_passwd(struct passwd *pwent); /* Macros for decoding/encoding integers */ #define PEEK_U64(p) \ Modified: head/crypto/openssh/sshd.c ============================================================================== --- head/crypto/openssh/sshd.c Sat Oct 6 18:51:49 2018 (r339215) +++ head/crypto/openssh/sshd.c Sat Oct 6 21:32:55 2018 (r339216) @@ -2143,6 +2143,11 @@ main(int ac, char **av) */ remote_ip = ssh_remote_ipaddr(ssh); +#ifdef HAVE_LOGIN_CAP + /* Also caches remote hostname for sandboxed child. */ + auth_get_canonical_hostname(ssh, options.use_dns); +#endif + #ifdef SSH_AUDIT_EVENTS audit_connection_from(remote_ip, remote_port); #endif