Handle SELinux authorisation roles

Rejected upstream due to discomfort with magic usernames; a better approach
will need an SSH protocol change.  In the meantime, this came from Debian's
SELinux maintainer, so we'll keep it until we have something better.

Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1641
Bug-Debian: http://bugs.debian.org/394795
Last-Update: 2020-02-21

Patch-Name: selinux-role.patch

Gbp-Pq: Name selinux-role.patch
This commit is contained in:
Manoj Srivastava 2014-02-09 16:09:49 +00:00 committed by Lu zhiping
parent 592f71b99f
commit ca25cb834b
15 changed files with 99 additions and 32 deletions

1
auth.h
View File

@ -63,6 +63,7 @@ struct Authctxt {
char *service; char *service;
struct passwd *pw; /* set if 'valid' */ struct passwd *pw; /* set if 'valid' */
char *style; char *style;
char *role;
/* Method lists for multiple authentication */ /* Method lists for multiple authentication */
char **auth_methods; /* modified from server config */ char **auth_methods; /* modified from server config */

10
auth2.c
View File

@ -265,7 +265,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
{ {
Authctxt *authctxt = ssh->authctxt; Authctxt *authctxt = ssh->authctxt;
Authmethod *m = NULL; Authmethod *m = NULL;
char *user = NULL, *service = NULL, *method = NULL, *style = NULL; char *user = NULL, *service = NULL, *method = NULL, *style = NULL, *role = NULL;
int r, authenticated = 0; int r, authenticated = 0;
double tstart = monotime_double(); double tstart = monotime_double();
@ -279,8 +279,13 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
debug("userauth-request for user %s service %s method %s", user, service, method); debug("userauth-request for user %s service %s method %s", user, service, method);
debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
if ((role = strchr(user, '/')) != NULL)
*role++ = 0;
if ((style = strchr(user, ':')) != NULL) if ((style = strchr(user, ':')) != NULL)
*style++ = 0; *style++ = 0;
else if (role && (style = strchr(role, ':')) != NULL)
*style++ = '\0';
if (authctxt->attempt++ == 0) { if (authctxt->attempt++ == 0) {
/* setup auth context */ /* setup auth context */
@ -307,8 +312,9 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
use_privsep ? " [net]" : ""); use_privsep ? " [net]" : "");
authctxt->service = xstrdup(service); authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL; authctxt->style = style ? xstrdup(style) : NULL;
authctxt->role = role ? xstrdup(role) : NULL;
if (use_privsep) if (use_privsep)
mm_inform_authserv(service, style); mm_inform_authserv(service, style, role);
userauth_banner(ssh); userauth_banner(ssh);
if (auth2_setup_methods_lists(authctxt) != 0) if (auth2_setup_methods_lists(authctxt) != 0)
ssh_packet_disconnect(ssh, ssh_packet_disconnect(ssh,

View File

@ -118,6 +118,7 @@ int mm_answer_sign(struct ssh *, int, struct sshbuf *);
int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *); int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *);
int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *); int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *);
int mm_answer_authserv(struct ssh *, int, struct sshbuf *); int mm_answer_authserv(struct ssh *, int, struct sshbuf *);
int mm_answer_authrole(struct ssh *, int, struct sshbuf *);
int mm_answer_authpassword(struct ssh *, int, struct sshbuf *); int mm_answer_authpassword(struct ssh *, int, struct sshbuf *);
int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *); int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *);
int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *); int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *);
@ -198,6 +199,7 @@ struct mon_table mon_dispatch_proto20[] = {
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
{MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
{MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
{MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
{MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
#ifdef USE_PAM #ifdef USE_PAM
@ -820,6 +822,7 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m)
/* Allow service/style information on the auth context */ /* Allow service/style information on the auth context */
monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
#ifdef USE_PAM #ifdef USE_PAM
@ -853,16 +856,42 @@ mm_answer_authserv(struct ssh *ssh, int sock, struct sshbuf *m)
monitor_permit_authentications(1); monitor_permit_authentications(1);
if ((r = sshbuf_get_cstring(m, &authctxt->service, NULL)) != 0 || if ((r = sshbuf_get_cstring(m, &authctxt->service, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0) (r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &authctxt->role, NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r)); fatal("%s: buffer error: %s", __func__, ssh_err(r));
debug3("%s: service=%s, style=%s", debug3("%s: service=%s, style=%s, role=%s",
__func__, authctxt->service, authctxt->style); __func__, authctxt->service, authctxt->style, authctxt->role);
if (strlen(authctxt->style) == 0) { if (strlen(authctxt->style) == 0) {
free(authctxt->style); free(authctxt->style);
authctxt->style = NULL; authctxt->style = NULL;
} }
if (strlen(authctxt->role) == 0) {
free(authctxt->role);
authctxt->role = NULL;
}
return (0);
}
int
mm_answer_authrole(struct ssh *ssh, int sock, struct sshbuf *m)
{
int r;
monitor_permit_authentications(1);
if ((r = sshbuf_get_cstring(m, &authctxt->role, NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
debug3("%s: role=%s",
__func__, authctxt->role);
if (strlen(authctxt->role) == 0) {
free(authctxt->role);
authctxt->role = NULL;
}
return (0); return (0);
} }
@ -1554,7 +1583,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m)
res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
if (res == 0) if (res == 0)
goto error; goto error;
pty_setowner(authctxt->pw, s->tty); pty_setowner(authctxt->pw, s->tty, authctxt->role);
if ((r = sshbuf_put_u32(m, 1)) != 0 || if ((r = sshbuf_put_u32(m, 1)) != 0 ||
(r = sshbuf_put_cstring(m, s->tty)) != 0) (r = sshbuf_put_cstring(m, s->tty)) != 0)

View File

@ -65,6 +65,8 @@ enum monitor_reqtype {
MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
MONITOR_REQ_AUTHROLE = 154,
}; };
struct ssh; struct ssh;

View File

@ -364,10 +364,10 @@ mm_auth2_read_banner(void)
return (banner); return (banner);
} }
/* Inform the privileged process about service and style */ /* Inform the privileged process about service, style, and role */
void void
mm_inform_authserv(char *service, char *style) mm_inform_authserv(char *service, char *style, char *role)
{ {
struct sshbuf *m; struct sshbuf *m;
int r; int r;
@ -377,7 +377,8 @@ mm_inform_authserv(char *service, char *style)
if ((m = sshbuf_new()) == NULL) if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__); fatal("%s: sshbuf_new failed", __func__);
if ((r = sshbuf_put_cstring(m, service)) != 0 || if ((r = sshbuf_put_cstring(m, service)) != 0 ||
(r = sshbuf_put_cstring(m, style ? style : "")) != 0) (r = sshbuf_put_cstring(m, style ? style : "")) != 0 ||
(r = sshbuf_put_cstring(m, role ? role : "")) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r)); fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, m); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, m);
@ -385,6 +386,26 @@ mm_inform_authserv(char *service, char *style)
sshbuf_free(m); sshbuf_free(m);
} }
/* Inform the privileged process about role */
void
mm_inform_authrole(char *role)
{
struct sshbuf *m;
int r;
debug3("%s entering", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
if ((r = sshbuf_put_cstring(m, role ? role : "")) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, m);
sshbuf_free(m);
}
/* Do the password authentication */ /* Do the password authentication */
int int
mm_auth_password(struct ssh *ssh, char *password) mm_auth_password(struct ssh *ssh, char *password)

View File

@ -47,7 +47,8 @@ DH *mm_choose_dh(int, int, int);
#endif #endif
int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *, int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *,
const u_char *, size_t, const char *, const char *, u_int compat); const u_char *, size_t, const char *, const char *, u_int compat);
void mm_inform_authserv(char *, char *); void mm_inform_authserv(char *, char *, char *);
void mm_inform_authrole(char *);
struct passwd *mm_getpwnamallow(struct ssh *, const char *); struct passwd *mm_getpwnamallow(struct ssh *, const char *);
char *mm_auth2_read_banner(void); char *mm_auth2_read_banner(void);
int mm_auth_password(struct ssh *, char *); int mm_auth_password(struct ssh *, char *);

View File

@ -56,7 +56,7 @@ ssh_selinux_enabled(void)
/* Return the default security context for the given username */ /* Return the default security context for the given username */
static security_context_t static security_context_t
ssh_selinux_getctxbyname(char *pwname) ssh_selinux_getctxbyname(char *pwname, const char *role)
{ {
security_context_t sc = NULL; security_context_t sc = NULL;
char *sename = NULL, *lvl = NULL; char *sename = NULL, *lvl = NULL;
@ -71,8 +71,15 @@ ssh_selinux_getctxbyname(char *pwname)
#endif #endif
#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
if (role != NULL && role[0])
r = get_default_context_with_rolelevel(sename, role, lvl, NULL,
&sc);
else
r = get_default_context_with_level(sename, lvl, NULL, &sc); r = get_default_context_with_level(sename, lvl, NULL, &sc);
#else #else
if (role != NULL && role[0])
r = get_default_context_with_role(sename, role, NULL, &sc);
else
r = get_default_context(sename, NULL, &sc); r = get_default_context(sename, NULL, &sc);
#endif #endif
@ -103,7 +110,7 @@ ssh_selinux_getctxbyname(char *pwname)
/* Set the execution context to the default for the specified user */ /* Set the execution context to the default for the specified user */
void void
ssh_selinux_setup_exec_context(char *pwname) ssh_selinux_setup_exec_context(char *pwname, const char *role)
{ {
security_context_t user_ctx = NULL; security_context_t user_ctx = NULL;
@ -112,7 +119,7 @@ ssh_selinux_setup_exec_context(char *pwname)
debug3("%s: setting execution context", __func__); debug3("%s: setting execution context", __func__);
user_ctx = ssh_selinux_getctxbyname(pwname); user_ctx = ssh_selinux_getctxbyname(pwname, role);
if (setexeccon(user_ctx) != 0) { if (setexeccon(user_ctx) != 0) {
switch (security_getenforce()) { switch (security_getenforce()) {
case -1: case -1:
@ -134,7 +141,7 @@ ssh_selinux_setup_exec_context(char *pwname)
/* Set the TTY context for the specified user */ /* Set the TTY context for the specified user */
void void
ssh_selinux_setup_pty(char *pwname, const char *tty) ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role)
{ {
security_context_t new_tty_ctx = NULL; security_context_t new_tty_ctx = NULL;
security_context_t user_ctx = NULL; security_context_t user_ctx = NULL;
@ -146,7 +153,7 @@ ssh_selinux_setup_pty(char *pwname, const char *tty)
debug3("%s: setting TTY context on %s", __func__, tty); debug3("%s: setting TTY context on %s", __func__, tty);
user_ctx = ssh_selinux_getctxbyname(pwname); user_ctx = ssh_selinux_getctxbyname(pwname, role);
/* XXX: should these calls fatal() upon failure in enforcing mode? */ /* XXX: should these calls fatal() upon failure in enforcing mode? */

View File

@ -19,8 +19,8 @@
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
int ssh_selinux_enabled(void); int ssh_selinux_enabled(void);
void ssh_selinux_setup_pty(char *, const char *); void ssh_selinux_setup_pty(char *, const char *, const char *);
void ssh_selinux_setup_exec_context(char *); void ssh_selinux_setup_exec_context(char *, const char *);
void ssh_selinux_change_context(const char *); void ssh_selinux_change_context(const char *);
void ssh_selinux_setfscreatecon(const char *); void ssh_selinux_setfscreatecon(const char *);
#endif #endif

View File

@ -143,7 +143,7 @@ platform_setusercontext(struct passwd *pw)
* called if sshd is running as root. * called if sshd is running as root.
*/ */
void void
platform_setusercontext_post_groups(struct passwd *pw) platform_setusercontext_post_groups(struct passwd *pw, const char *role)
{ {
#if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM) #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM)
/* /*
@ -184,7 +184,7 @@ platform_setusercontext_post_groups(struct passwd *pw)
} }
#endif /* HAVE_SETPCRED */ #endif /* HAVE_SETPCRED */
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
ssh_selinux_setup_exec_context(pw->pw_name); ssh_selinux_setup_exec_context(pw->pw_name, role);
#endif #endif
} }

View File

@ -25,7 +25,7 @@ void platform_post_fork_parent(pid_t child_pid);
void platform_post_fork_child(void); void platform_post_fork_child(void);
int platform_privileged_uidswap(void); int platform_privileged_uidswap(void);
void platform_setusercontext(struct passwd *); void platform_setusercontext(struct passwd *);
void platform_setusercontext_post_groups(struct passwd *); void platform_setusercontext_post_groups(struct passwd *, const char *);
char *platform_get_krb5_client(const char *); char *platform_get_krb5_client(const char *);
char *platform_krb5_get_principal_name(const char *); char *platform_krb5_get_principal_name(const char *);
int platform_sys_dir_uid(uid_t); int platform_sys_dir_uid(uid_t);

View File

@ -1360,7 +1360,7 @@ safely_chroot(const char *path, uid_t uid)
/* Set login name, uid, gid, and groups. */ /* Set login name, uid, gid, and groups. */
void void
do_setusercontext(struct passwd *pw) do_setusercontext(struct passwd *pw, const char *role)
{ {
char uidstr[32], *chroot_path, *tmp; char uidstr[32], *chroot_path, *tmp;
@ -1388,7 +1388,7 @@ do_setusercontext(struct passwd *pw)
endgrent(); endgrent();
#endif #endif
platform_setusercontext_post_groups(pw); platform_setusercontext_post_groups(pw, role);
if (!in_chroot && options.chroot_directory != NULL && if (!in_chroot && options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0) { strcasecmp(options.chroot_directory, "none") != 0) {
@ -1529,7 +1529,7 @@ do_child(struct ssh *ssh, Session *s, const char *command)
/* Force a password change */ /* Force a password change */
if (s->authctxt->force_pwchange) { if (s->authctxt->force_pwchange) {
do_setusercontext(pw); do_setusercontext(pw, s->authctxt->role);
child_close_fds(ssh); child_close_fds(ssh);
do_pwchange(s); do_pwchange(s);
exit(1); exit(1);
@ -1547,7 +1547,7 @@ do_child(struct ssh *ssh, Session *s, const char *command)
/* When PAM is enabled we rely on it to do the nologin check */ /* When PAM is enabled we rely on it to do the nologin check */
if (!options.use_pam) if (!options.use_pam)
do_nologin(pw); do_nologin(pw);
do_setusercontext(pw); do_setusercontext(pw, s->authctxt->role);
/* /*
* PAM session modules in do_setusercontext may have * PAM session modules in do_setusercontext may have
* generated messages, so if this in an interactive * generated messages, so if this in an interactive
@ -1946,7 +1946,7 @@ session_pty_req(struct ssh *ssh, Session *s)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__); sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (!use_privsep) if (!use_privsep)
pty_setowner(s->pw, s->tty); pty_setowner(s->pw, s->tty, s->authctxt->role);
/* Set window size from the packet. */ /* Set window size from the packet. */
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);

View File

@ -77,7 +77,7 @@ void session_pty_cleanup2(Session *);
Session *session_new(void); Session *session_new(void);
Session *session_by_tty(char *); Session *session_by_tty(char *);
void session_close(struct ssh *, Session *); void session_close(struct ssh *, Session *);
void do_setusercontext(struct passwd *); void do_setusercontext(struct passwd *, const char *);
const char *session_get_remote_name_or_ip(struct ssh *, u_int, int); const char *session_get_remote_name_or_ip(struct ssh *, u_int, int);

2
sshd.c
View File

@ -595,7 +595,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt)
reseed_prngs(); reseed_prngs();
/* Drop privileges */ /* Drop privileges */
do_setusercontext(authctxt->pw); do_setusercontext(authctxt->pw, authctxt->role);
skip: skip:
/* It is safe now to apply the key state */ /* It is safe now to apply the key state */

View File

@ -162,7 +162,7 @@ pty_change_window_size(int ptyfd, u_int row, u_int col,
} }
void void
pty_setowner(struct passwd *pw, const char *tty) pty_setowner(struct passwd *pw, const char *tty, const char *role)
{ {
struct group *grp; struct group *grp;
gid_t gid; gid_t gid;
@ -186,7 +186,7 @@ pty_setowner(struct passwd *pw, const char *tty)
strerror(errno)); strerror(errno));
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
ssh_selinux_setup_pty(pw->pw_name, tty); ssh_selinux_setup_pty(pw->pw_name, tty, role);
#endif #endif
if (st.st_uid != pw->pw_uid || st.st_gid != gid) { if (st.st_uid != pw->pw_uid || st.st_gid != gid) {

View File

@ -24,5 +24,5 @@ int pty_allocate(int *, int *, char *, size_t);
void pty_release(const char *); void pty_release(const char *);
void pty_make_controlling_tty(int *, const char *); void pty_make_controlling_tty(int *, const char *);
void pty_change_window_size(int, u_int, u_int, u_int, u_int); void pty_change_window_size(int, u_int, u_int, u_int, u_int);
void pty_setowner(struct passwd *, const char *); void pty_setowner(struct passwd *, const char *, const char *);
void disconnect_controlling_tty(void); void disconnect_controlling_tty(void);