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
This commit is contained in:
parent
7e524b0746
commit
fc3c19a9fc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=339216
@ -316,7 +316,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
|
||||
#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 ssh *ssh)
|
||||
authctxt->pw->pw_name, from_host);
|
||||
packet_disconnect("Logins not available right now.");
|
||||
}
|
||||
login_close(lc);
|
||||
PRIVSEP(login_close(lc));
|
||||
}
|
||||
#endif /* HAVE_LOGIN_CAP */
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -247,6 +247,57 @@ mm_sshkey_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
|
||||
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 */
|
||||
|
@ -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 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 *,
|
||||
|
@ -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"
|
||||
@ -71,6 +72,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;
|
||||
|
||||
if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
|
||||
@ -462,3 +463,95 @@ sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
@ -246,6 +247,21 @@ int sshbuf_b64tod(struct sshbuf *buf, const char *b64);
|
||||
*/
|
||||
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) \
|
||||
(((u_int64_t)(((const u_char *)(p))[0]) << 56) | \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user