Index: auth2.c =================================================================== --- auth2.c +++ auth2.c @@ -276,7 +276,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); @@ -291,7 +291,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: buffer.h =================================================================== --- buffer.h +++ buffer.h @@ -21,6 +21,7 @@ #ifndef BUFFER_H #define BUFFER_H +#include #include "sshbuf.h" typedef struct sshbuf Buffer; @@ -91,5 +92,9 @@ void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *); #endif +void buffer_put_passwd(Buffer *, const struct passwd *); +struct passwd *buffer_get_passwd(Buffer *); +void buffer_free_passwd(struct passwd *); + #endif /* BUFFER_H */ Index: buffer.c =================================================================== --- buffer.c +++ buffer.c @@ -115,4 +115,75 @@ fatal("%s: buffer error", __func__); } +void +buffer_put_passwd(Buffer *buffer, const struct passwd *pwent) +{ + /* We never send pointer values of struct passwd. + It is safe from wild pointer even if a new pointer member is added. */ + buffer_put_int64(buffer, sizeof(*pwent)); + buffer_put_cstring(buffer, pwent->pw_name); + buffer_put_cstring(buffer, "*"); + buffer_put_int(buffer, pwent->pw_uid); + buffer_put_int(buffer, pwent->pw_gid); + buffer_put_int64(buffer, pwent->pw_change); +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS + buffer_put_cstring(buffer, pwent->pw_gecos); +#endif +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS + buffer_put_cstring(buffer, pwent->pw_class); +#endif + buffer_put_cstring(buffer, pwent->pw_dir); + buffer_put_cstring(buffer, pwent->pw_shell); + buffer_put_int64(buffer, pwent->pw_expire); + buffer_put_int(buffer, pwent->pw_fields); +} + +struct passwd * +buffer_get_passwd(Buffer *buffer) +{ + struct passwd *pw; + size_t len; + + /* check if size of struct passwd is as same as sender's size */ + len = buffer_get_int64(buffer); + if (len != sizeof(*pw)) + return NULL; + + pw = calloc(1, sizeof(*pw)); + if (pw == NULL) + return NULL; + + pw->pw_name = buffer_get_string(buffer, NULL); + pw->pw_passwd = buffer_get_string(buffer, NULL); + pw->pw_uid = buffer_get_int(buffer); + pw->pw_gid = buffer_get_int(buffer); + pw->pw_change = buffer_get_int64(buffer); +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS + pw->pw_gecos = buffer_get_string(buffer, NULL); +#endif +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS + pw->pw_class = buffer_get_string(buffer, NULL); +#endif + pw->pw_dir = buffer_get_string(buffer, NULL); + pw->pw_shell = buffer_get_string(buffer, NULL); + pw->pw_expire = buffer_get_int64(buffer); + pw->pw_fields = buffer_get_int(buffer); + return pw; +} + +void +buffer_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: monitor.h =================================================================== --- monitor.h +++ monitor.h @@ -55,7 +55,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 @@ -125,6 +125,7 @@ int mm_answer_moduli(int, Buffer *); int mm_answer_sign(int, Buffer *); +int mm_answer_login_getpwclass(int, Buffer *); int mm_answer_pwnamallow(int, Buffer *); int mm_answer_auth2_read_banner(int, Buffer *); int mm_answer_authserv(int, Buffer *); @@ -203,6 +204,7 @@ #endif {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_GETPWCLASS, MON_AUTH, mm_answer_login_getpwclass}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, @@ -707,6 +709,40 @@ return (0); } +int +mm_answer_login_getpwclass(int sock, Buffer *m) +{ + login_cap_t *lc; + struct passwd *pw; + u_int len; + + debug3("%s", __func__); + + pw = buffer_get_passwd(m); + if (pw == NULL) + fatal("%s: receive get struct passwd failed", __func__); + + lc = login_getpwclass(pw); + if (lc == NULL) { + buffer_put_char(m, 0); + goto out; + } + + buffer_put_char(m, 1); + buffer_put_cstring(m, lc->lc_class); + buffer_put_cstring(m, lc->lc_cap); + buffer_put_cstring(m, lc->lc_style); + + login_close(lc); + out: + debug3("%s: sending MONITOR_ANS_GETPWCLASS", __func__); + mm_request_send(sock, MONITOR_ANS_GETPWCLASS, m); + + buffer_free_passwd(pw); + + return (0); +} + /* Retrieves the password entry and also checks if the user is permitted */ int @@ -744,17 +780,7 @@ authctxt->valid = 1; buffer_put_char(m, 1); - buffer_put_string(m, pwent, sizeof(struct passwd)); - buffer_put_cstring(m, pwent->pw_name); - buffer_put_cstring(m, "*"); -#ifdef HAVE_STRUCT_PASSWD_PW_GECOS - buffer_put_cstring(m, pwent->pw_gecos); -#endif -#ifdef HAVE_STRUCT_PASSWD_PW_CLASS - buffer_put_cstring(m, pwent->pw_class); -#endif - buffer_put_cstring(m, pwent->pw_dir); - buffer_put_cstring(m, pwent->pw_shell); + buffer_put_passwd(m, pwent); out: ssh_packet_set_log_preamble(ssh, "%suser %s", 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 *); 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 @@ -238,6 +238,51 @@ return (0); } +login_cap_t * +mm_login_getpwclass(const struct passwd *pwent) +{ + Buffer m; + login_cap_t *lc; + + debug3("%s entering", __func__); + + buffer_init(&m); + buffer_put_passwd(&m, pwent); + + 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 (buffer_get_char(&m) == 0) { + lc = NULL; + goto out; + } + + lc = malloc(sizeof(*lc)); + if (lc == NULL) + fatal("%s: fail to allocate memory", __func__); + lc->lc_class = buffer_get_string(&m, NULL); + lc->lc_cap = buffer_get_string(&m, NULL); + lc->lc_style = buffer_get_string(&m, NULL); + + out: + buffer_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) { @@ -261,19 +306,9 @@ pw = NULL; goto out; } - pw = buffer_get_string(&m, &len); - if (len != sizeof(struct passwd)) - fatal("%s: struct passwd size mismatch", __func__); - pw->pw_name = buffer_get_string(&m, NULL); - pw->pw_passwd = buffer_get_string(&m, NULL); -#ifdef HAVE_STRUCT_PASSWD_PW_GECOS - pw->pw_gecos = buffer_get_string(&m, NULL); -#endif -#ifdef HAVE_STRUCT_PASSWD_PW_CLASS - pw->pw_class = buffer_get_string(&m, NULL); -#endif - pw->pw_dir = buffer_get_string(&m, NULL); - pw->pw_shell = buffer_get_string(&m, NULL); + pw = buffer_get_passwd(&m); + if (pw == NULL) + fatal("%s: receive 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" @@ -71,6 +72,8 @@ struct rlimit rl_zero; cap_rights_t rights; + caph_cache_tzdata(); + rl_zero.rlim_cur = rl_zero.rlim_max = 0; if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1) Index: sshd.c =================================================================== --- sshd.c +++ sshd.c @@ -2084,6 +2084,10 @@ * the socket goes away. */ 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);