Index: auth2.c =================================================================== --- auth2.c +++ auth2.c @@ -316,7 +316,7 @@ #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 @@ authctxt->pw->pw_name, from_host); packet_disconnect("Logins not available right now."); } - login_close(lc); + PRIVSEP(login_close(lc)); } #endif /* HAVE_LOGIN_CAP */ Index: monitor.h =================================================================== --- monitor.h +++ monitor.h @@ -53,7 +53,8 @@ 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, Index: monitor.c =================================================================== --- monitor.c +++ monitor.c @@ -112,6 +112,7 @@ 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 *); @@ -187,6 +188,7 @@ {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}, @@ -703,6 +705,46 @@ 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 @@ -741,19 +783,8 @@ 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: Index: monitor_wrap.h =================================================================== --- monitor_wrap.h +++ monitor_wrap.h @@ -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 @@ 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 *, Index: monitor_wrap.c =================================================================== --- monitor_wrap.c +++ monitor_wrap.c @@ -247,6 +247,57 @@ 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) { + 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 @@ 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 */ Index: sandbox-capsicum.c =================================================================== --- sandbox-capsicum.c +++ sandbox-capsicum.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "log.h" #include "monitor.h" @@ -70,6 +71,8 @@ { struct rlimit rl_zero; cap_rights_t rights; + + caph_cache_tzdata(); rl_zero.rlim_cur = rl_zero.rlim_max = 0; Index: sshbuf-getput-basic.c =================================================================== --- sshbuf-getput-basic.c +++ sshbuf-getput-basic.c @@ -25,6 +25,7 @@ #include #include +#include "xmalloc.h" #include "ssherr.h" #include "sshbuf.h" @@ -461,4 +462,102 @@ 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) { + if (pw->pw_name != NULL) free(pw->pw_name); + if (pw->pw_passwd != NULL) free(pw->pw_passwd); +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS + if (pw->pw_gecos != NULL) free(pw->pw_gecos); +#endif +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS + if (pw->pw_class != NULL) free(pw->pw_class); +#endif + if (pw->pw_dir != NULL) free(pw->pw_dir); + if (pw->pw_shell != NULL) free(pw->pw_shell); + free(pw); + return NULL; + } + return pw; +} + +/* + * free struct passwd obtained from sshbuf_get_passwd. + */ +void +sshbuf_free_passwd(struct passwd *pwent) +{ + 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); } Index: sshbuf.h =================================================================== --- sshbuf.h +++ sshbuf.h @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef WITH_OPENSSL # include # ifdef OPENSSL_HAS_ECC @@ -245,6 +246,21 @@ * 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) \ Index: sshd.c =================================================================== --- sshd.c +++ sshd.c @@ -2143,6 +2143,11 @@ */ 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