Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 6 Oct 2018 21:32:56 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r339216 - head/crypto/openssh
Message-ID:  <201810062132.w96LWufS002919@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <login_cap.h>
+
 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 <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <capsicum_helpers.h>
 
 #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 <stdio.h>
 #include <string.h>
 
+#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 <sys/types.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <pwd.h>
 #ifdef WITH_OPENSSL
 # include <openssl/bn.h>
 # 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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201810062132.w96LWufS002919>