openssh: simplify login class restrictions
Login class-based restrictions were introduced in5b400a39b8
. The code was adapted for sshd's Capsicum sandbox and received many changes over time, including at leastfc3c19a9fc
,bd393de91c
, ande8c56fba29
. During an attempt to upstream the work a much simpler approach was suggested. Adopt it now in the in-tree OpenSSH to reduce conflicts with future updates. Submitted by: Yuchiro Naito (against OpenSSH-portable on GitHub) Obtained from: https://github.com/openssh/openssh-portable/pull/262 Reviewed by: allanjude, kevans MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D31760
This commit is contained in:
parent
c511383de7
commit
27ceebbc24
@ -568,6 +568,9 @@ getpwnamallow(const char *user)
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
extern login_cap_t *lc;
|
||||
#ifdef HAVE_AUTH_HOSTOK
|
||||
const char *from_host, *from_ip;
|
||||
#endif
|
||||
#ifdef BSD_AUTH
|
||||
auth_session_t *as;
|
||||
#endif
|
||||
@ -622,6 +625,21 @@ getpwnamallow(const char *user)
|
||||
debug("unable to get login class: %s", user);
|
||||
return (NULL);
|
||||
}
|
||||
#ifdef HAVE_AUTH_HOSTOK
|
||||
from_host = auth_get_canonical_hostname(ssh, options.use_dns);
|
||||
from_ip = ssh_remote_ipaddr(ssh);
|
||||
if (!auth_hostok(lc, from_host, from_ip)) {
|
||||
debug("Denied connection for %.200s from %.200s [%.200s].",
|
||||
pw->pw_name, from_host, from_ip);
|
||||
return (NULL);
|
||||
}
|
||||
#endif /* HAVE_AUTH_HOSTOK */
|
||||
#ifdef HAVE_AUTH_TIMEOK
|
||||
if (!auth_timeok(lc, time(NULL))) {
|
||||
debug("LOGIN %.200s REFUSED (TIME)", pw->pw_name);
|
||||
return (NULL);
|
||||
}
|
||||
#endif /* HAVE_AUTH_TIMEOK */
|
||||
#ifdef BSD_AUTH
|
||||
if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
|
||||
auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
|
||||
|
@ -314,25 +314,6 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
authctxt->user, authctxt->service, user, service);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
if (authctxt->pw != NULL &&
|
||||
(lc = PRIVSEP(login_getpwclass(authctxt->pw))) != NULL) {
|
||||
from_host = auth_get_canonical_hostname(ssh, options.use_dns);
|
||||
from_ip = ssh_remote_ipaddr(ssh);
|
||||
if (!auth_hostok(lc, from_host, from_ip)) {
|
||||
logit("Denied connection for %.200s from %.200s [%.200s].",
|
||||
authctxt->pw->pw_name, from_host, from_ip);
|
||||
packet_disconnect("Sorry, you are not allowed to connect.");
|
||||
}
|
||||
if (!auth_timeok(lc, time(NULL))) {
|
||||
logit("LOGIN %.200s REFUSED (TIME) FROM %.200s",
|
||||
authctxt->pw->pw_name, from_host);
|
||||
packet_disconnect("Logins not available right now.");
|
||||
}
|
||||
PRIVSEP(login_close(lc));
|
||||
}
|
||||
#endif /* HAVE_LOGIN_CAP */
|
||||
|
||||
/* reset state */
|
||||
auth2_challenge_stop(ssh);
|
||||
|
||||
|
@ -211,6 +211,12 @@
|
||||
/* Define to 1 if you have the `aug_get_machine' function. */
|
||||
/* #undef HAVE_AUG_GET_MACHINE */
|
||||
|
||||
/* Define to 1 if you have the `auth_hostok' function. */
|
||||
#define HAVE_AUTH_HOSTOK 1
|
||||
|
||||
/* Define to 1 if you have the `auth_timeok' function. */
|
||||
#define HAVE_AUTH_TIMEOK 1
|
||||
|
||||
/* Define to 1 if you have the `b64_ntop' function. */
|
||||
/* #undef HAVE_B64_NTOP */
|
||||
|
||||
|
@ -1751,6 +1751,8 @@ fi
|
||||
|
||||
dnl Checks for library functions. Please keep in alphabetical order
|
||||
AC_CHECK_FUNCS([ \
|
||||
auth_hostok \
|
||||
auth_timeok \
|
||||
Blowfish_initstate \
|
||||
Blowfish_expandstate \
|
||||
Blowfish_expand0state \
|
||||
|
@ -114,9 +114,6 @@ static struct sshbuf *child_state;
|
||||
|
||||
int mm_answer_moduli(int, struct sshbuf *);
|
||||
int mm_answer_sign(int, struct sshbuf *);
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
int mm_answer_login_getpwclass(int, struct sshbuf *);
|
||||
#endif
|
||||
int mm_answer_pwnamallow(int, struct sshbuf *);
|
||||
int mm_answer_auth2_read_banner(int, struct sshbuf *);
|
||||
int mm_answer_authserv(int, struct sshbuf *);
|
||||
@ -192,9 +189,6 @@ struct mon_table mon_dispatch_proto20[] = {
|
||||
{MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
|
||||
#endif
|
||||
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
{MONITOR_REQ_GETPWCLASS, MON_ISAUTH, mm_answer_login_getpwclass},
|
||||
#endif
|
||||
{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},
|
||||
@ -713,48 +707,6 @@ mm_answer_sign(int sock, struct sshbuf *m)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Retrieves the password entry and also checks if the user is permitted */
|
||||
|
||||
int
|
||||
@ -793,8 +745,19 @@ 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_passwd(m, pwent)) != 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)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
|
||||
out:
|
||||
|
@ -53,8 +53,7 @@ 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_GETPWCLASS = 50, MONITOR_ANS_GETPWCLASS = 51,
|
||||
MONITOR_REQ_TERM = 52,
|
||||
MONITOR_REQ_TERM = 50,
|
||||
|
||||
MONITOR_REQ_PAM_START = 100,
|
||||
MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
|
||||
|
@ -247,61 +247,6 @@ mm_sshkey_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct passwd *
|
||||
mm_getpwnamallow(const char *username)
|
||||
{
|
||||
@ -334,9 +279,25 @@ mm_getpwnamallow(const char *username)
|
||||
goto out;
|
||||
}
|
||||
|
||||
pw = sshbuf_get_passwd(m);
|
||||
if (pw == NULL)
|
||||
fatal("%s: receive get struct passwd failed", __func__);
|
||||
/* 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));
|
||||
|
||||
out:
|
||||
/* copy options block as a Match directive may have changed some */
|
||||
|
@ -44,10 +44,6 @@ DH *mm_choose_dh(int, int, int);
|
||||
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 *);
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
struct login_cap *mm_login_getpwclass(const struct passwd *pwd);
|
||||
void mm_login_close(struct login_cap *lc);
|
||||
#endif
|
||||
struct passwd *mm_getpwnamallow(const char *);
|
||||
char *mm_auth2_read_banner(void);
|
||||
int mm_auth_password(struct ssh *, char *);
|
||||
|
@ -657,7 +657,6 @@
|
||||
#define sshbuf_dump_data Fssh_sshbuf_dump_data
|
||||
#define sshbuf_dup_string Fssh_sshbuf_dup_string
|
||||
#define sshbuf_free Fssh_sshbuf_free
|
||||
#define sshbuf_free_passwd Fssh_sshbuf_free_passwd
|
||||
#define sshbuf_from Fssh_sshbuf_from
|
||||
#define sshbuf_fromb Fssh_sshbuf_fromb
|
||||
#define sshbuf_froms Fssh_sshbuf_froms
|
||||
@ -668,7 +667,6 @@
|
||||
#define sshbuf_get_cstring Fssh_sshbuf_get_cstring
|
||||
#define sshbuf_get_ec Fssh_sshbuf_get_ec
|
||||
#define sshbuf_get_eckey Fssh_sshbuf_get_eckey
|
||||
#define sshbuf_get_passwd Fssh_sshbuf_get_passwd
|
||||
#define sshbuf_get_string Fssh_sshbuf_get_string
|
||||
#define sshbuf_get_string_direct Fssh_sshbuf_get_string_direct
|
||||
#define sshbuf_get_stringb Fssh_sshbuf_get_stringb
|
||||
@ -690,7 +688,6 @@
|
||||
#define sshbuf_put_cstring Fssh_sshbuf_put_cstring
|
||||
#define sshbuf_put_ec Fssh_sshbuf_put_ec
|
||||
#define sshbuf_put_eckey Fssh_sshbuf_put_eckey
|
||||
#define sshbuf_put_passwd Fssh_sshbuf_put_passwd
|
||||
#define sshbuf_put_string Fssh_sshbuf_put_string
|
||||
#define sshbuf_put_stringb Fssh_sshbuf_put_stringb
|
||||
#define sshbuf_put_u16 Fssh_sshbuf_put_u16
|
||||
|
@ -463,103 +463,3 @@ 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 ||
|
||||
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
|
||||
(r = sshbuf_put_time(buf, pwent->pw_change)) != 0 ||
|
||||
#endif
|
||||
#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 ||
|
||||
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
|
||||
(r = sshbuf_put_time(buf, pwent->pw_expire)) != 0 ||
|
||||
#endif
|
||||
(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;
|
||||
u_int64_t len;
|
||||
int r;
|
||||
|
||||
/* 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 ||
|
||||
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
|
||||
sshbuf_get_time(buf, &pw->pw_change) != 0 ||
|
||||
#endif
|
||||
#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 ||
|
||||
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
|
||||
sshbuf_get_time(buf, &pw->pw_expire) != 0 ||
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
@ -254,21 +254,6 @@ 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) | \
|
||||
|
Loading…
Reference in New Issue
Block a user