461 lines
16 KiB
Diff
461 lines
16 KiB
Diff
From ad6e66e766ecc3a76c62c6daf81ebf19432713cb Mon Sep 17 00:00:00 2001
|
|
From: Manoj Srivastava <srivasta@debian.org>
|
|
Date: Sun, 9 Feb 2014 16:09:49 +0000
|
|
Subject: 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: 2024-07-03
|
|
|
|
Patch-Name: selinux-role.patch
|
|
---
|
|
auth.h | 1 +
|
|
auth2.c | 10 ++++++++--
|
|
monitor.c | 36 +++++++++++++++++++++++++++++++++---
|
|
monitor.h | 2 ++
|
|
monitor_wrap.c | 27 ++++++++++++++++++++++++---
|
|
monitor_wrap.h | 3 ++-
|
|
openbsd-compat/port-linux.c | 21 ++++++++++++++-------
|
|
openbsd-compat/port-linux.h | 4 ++--
|
|
platform.c | 4 ++--
|
|
platform.h | 2 +-
|
|
session.c | 8 ++++----
|
|
session.h | 2 +-
|
|
sshd-session.c | 2 +-
|
|
sshpty.c | 4 ++--
|
|
sshpty.h | 2 +-
|
|
15 files changed, 98 insertions(+), 30 deletions(-)
|
|
|
|
diff --git a/auth.h b/auth.h
|
|
index 98bb23d4c..59799a812 100644
|
|
--- a/auth.h
|
|
+++ b/auth.h
|
|
@@ -65,6 +65,7 @@ struct Authctxt {
|
|
char *service;
|
|
struct passwd *pw; /* set if 'valid' */
|
|
char *style;
|
|
+ char *role;
|
|
|
|
/* Method lists for multiple authentication */
|
|
char **auth_methods; /* modified from server config */
|
|
diff --git a/auth2.c b/auth2.c
|
|
index 4fff5a5f7..7ca8a96f8 100644
|
|
--- a/auth2.c
|
|
+++ b/auth2.c
|
|
@@ -272,7 +272,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
|
|
{
|
|
Authctxt *authctxt = ssh->authctxt;
|
|
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;
|
|
double tstart = monotime_double();
|
|
|
|
@@ -286,8 +286,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("attempt %d failures %d", authctxt->attempt, authctxt->failures);
|
|
|
|
+ if ((role = strchr(user, '/')) != NULL)
|
|
+ *role++ = 0;
|
|
+
|
|
if ((style = strchr(user, ':')) != NULL)
|
|
*style++ = 0;
|
|
+ else if (role && (style = strchr(role, ':')) != NULL)
|
|
+ *style++ = '\0';
|
|
|
|
if (authctxt->attempt >= 1024)
|
|
auth_maxtries_exceeded(ssh);
|
|
@@ -315,7 +320,8 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
|
|
setproctitle("%s [net]", authctxt->valid ? user : "unknown");
|
|
authctxt->service = xstrdup(service);
|
|
authctxt->style = style ? xstrdup(style) : NULL;
|
|
- mm_inform_authserv(service, style);
|
|
+ authctxt->role = role ? xstrdup(role) : NULL;
|
|
+ mm_inform_authserv(service, style, role);
|
|
userauth_banner(ssh);
|
|
if ((r = kex_server_update_ext_info(ssh)) != 0)
|
|
fatal_fr(r, "kex_server_update_ext_info failed");
|
|
diff --git a/monitor.c b/monitor.c
|
|
index 1aa81094e..180c6dbbc 100644
|
|
--- a/monitor.c
|
|
+++ b/monitor.c
|
|
@@ -120,6 +120,7 @@ int mm_answer_sign(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_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_bsdauthquery(struct ssh *, int, struct sshbuf *);
|
|
int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *);
|
|
@@ -196,6 +197,7 @@ struct mon_table mon_dispatch_proto20[] = {
|
|
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
|
|
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
|
|
{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_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
|
|
#ifdef USE_PAM
|
|
@@ -929,6 +931,7 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
|
|
/* Allow service/style information on the auth context */
|
|
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);
|
|
|
|
#ifdef USE_PAM
|
|
@@ -962,15 +965,42 @@ mm_answer_authserv(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
monitor_permit_authentications(1);
|
|
|
|
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_fr(r, "parse");
|
|
- debug3_f("service=%s, style=%s", authctxt->service, authctxt->style);
|
|
+ debug3_f("service=%s, style=%s, role=%s",
|
|
+ authctxt->service, authctxt->style, authctxt->role);
|
|
|
|
if (strlen(authctxt->style) == 0) {
|
|
free(authctxt->style);
|
|
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);
|
|
}
|
|
|
|
@@ -1691,7 +1721,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
|
|
if (res == 0)
|
|
goto error;
|
|
- pty_setowner(authctxt->pw, s->tty);
|
|
+ pty_setowner(authctxt->pw, s->tty, authctxt->role);
|
|
|
|
if ((r = sshbuf_put_u32(m, 1)) != 0 ||
|
|
(r = sshbuf_put_cstring(m, s->tty)) != 0)
|
|
diff --git a/monitor.h b/monitor.h
|
|
index 4076f71ea..1eda94540 100644
|
|
--- a/monitor.h
|
|
+++ b/monitor.h
|
|
@@ -66,6 +66,8 @@ enum monitor_reqtype {
|
|
|
|
MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
|
|
MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
|
|
+
|
|
+ MONITOR_REQ_AUTHROLE = 154,
|
|
};
|
|
|
|
struct ssh;
|
|
diff --git a/monitor_wrap.c b/monitor_wrap.c
|
|
index 8a6b4442f..9bf62aac2 100644
|
|
--- a/monitor_wrap.c
|
|
+++ b/monitor_wrap.c
|
|
@@ -421,10 +421,10 @@ mm_auth2_read_banner(void)
|
|
return (banner);
|
|
}
|
|
|
|
-/* Inform the privileged process about service and style */
|
|
+/* Inform the privileged process about service, style, and role */
|
|
|
|
void
|
|
-mm_inform_authserv(char *service, char *style)
|
|
+mm_inform_authserv(char *service, char *style, char *role)
|
|
{
|
|
struct sshbuf *m;
|
|
int r;
|
|
@@ -434,7 +434,8 @@ mm_inform_authserv(char *service, char *style)
|
|
if ((m = sshbuf_new()) == NULL)
|
|
fatal_f("sshbuf_new failed");
|
|
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_fr(r, "assemble");
|
|
|
|
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, m);
|
|
@@ -442,6 +443,26 @@ mm_inform_authserv(char *service, char *style)
|
|
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 */
|
|
int
|
|
mm_auth_password(struct ssh *ssh, char *password)
|
|
diff --git a/monitor_wrap.h b/monitor_wrap.h
|
|
index 01251cf1b..fb6d7e15b 100644
|
|
--- a/monitor_wrap.h
|
|
+++ b/monitor_wrap.h
|
|
@@ -45,7 +45,8 @@ DH *mm_choose_dh(int, int, int);
|
|
int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *,
|
|
const u_char *, size_t, const char *, 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 *);
|
|
char *mm_auth2_read_banner(void);
|
|
int mm_auth_password(struct ssh *, char *);
|
|
diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c
|
|
index c1d54f38d..1fd3bfa81 100644
|
|
--- a/openbsd-compat/port-linux.c
|
|
+++ b/openbsd-compat/port-linux.c
|
|
@@ -65,7 +65,7 @@ ssh_selinux_enabled(void)
|
|
|
|
/* Return the default security context for the given username */
|
|
static char *
|
|
-ssh_selinux_getctxbyname(char *pwname)
|
|
+ssh_selinux_getctxbyname(char *pwname, const char *role)
|
|
{
|
|
char *sc = NULL, *sename = NULL, *lvl = NULL;
|
|
int r;
|
|
@@ -79,9 +79,16 @@ ssh_selinux_getctxbyname(char *pwname)
|
|
#endif
|
|
|
|
#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
|
|
- r = get_default_context_with_level(sename, lvl, NULL, &sc);
|
|
+ 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);
|
|
#else
|
|
- r = get_default_context(sename, NULL, &sc);
|
|
+ if (role != NULL && role[0])
|
|
+ r = get_default_context_with_role(sename, role, NULL, &sc);
|
|
+ else
|
|
+ r = get_default_context(sename, NULL, &sc);
|
|
#endif
|
|
|
|
if (r != 0) {
|
|
@@ -111,7 +118,7 @@ ssh_selinux_getctxbyname(char *pwname)
|
|
|
|
/* Set the execution context to the default for the specified user */
|
|
void
|
|
-ssh_selinux_setup_exec_context(char *pwname)
|
|
+ssh_selinux_setup_exec_context(char *pwname, const char *role)
|
|
{
|
|
char *user_ctx = NULL;
|
|
|
|
@@ -120,7 +127,7 @@ ssh_selinux_setup_exec_context(char *pwname)
|
|
|
|
debug3("%s: setting execution context", __func__);
|
|
|
|
- user_ctx = ssh_selinux_getctxbyname(pwname);
|
|
+ user_ctx = ssh_selinux_getctxbyname(pwname, role);
|
|
if (setexeccon(user_ctx) != 0) {
|
|
switch (security_getenforce()) {
|
|
case -1:
|
|
@@ -142,7 +149,7 @@ ssh_selinux_setup_exec_context(char *pwname)
|
|
|
|
/* Set the TTY context for the specified user */
|
|
void
|
|
-ssh_selinux_setup_pty(char *pwname, const char *tty)
|
|
+ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role)
|
|
{
|
|
char *new_tty_ctx = NULL, *user_ctx = NULL, *old_tty_ctx = NULL;
|
|
security_class_t chrclass;
|
|
@@ -152,7 +159,7 @@ ssh_selinux_setup_pty(char *pwname, const char *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? */
|
|
|
|
diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h
|
|
index 959430de1..7f9a7c195 100644
|
|
--- a/openbsd-compat/port-linux.h
|
|
+++ b/openbsd-compat/port-linux.h
|
|
@@ -19,8 +19,8 @@
|
|
|
|
#ifdef WITH_SELINUX
|
|
int ssh_selinux_enabled(void);
|
|
-void ssh_selinux_setup_pty(char *, const char *);
|
|
-void ssh_selinux_setup_exec_context(char *);
|
|
+void ssh_selinux_setup_pty(char *, const char *, const char *);
|
|
+void ssh_selinux_setup_exec_context(char *, const char *);
|
|
void ssh_selinux_change_context(const char *);
|
|
void ssh_selinux_setfscreatecon(const char *);
|
|
#endif
|
|
diff --git a/platform.c b/platform.c
|
|
index 4c4fe57ea..f3dc7c3a8 100644
|
|
--- a/platform.c
|
|
+++ b/platform.c
|
|
@@ -99,7 +99,7 @@ platform_setusercontext(struct passwd *pw)
|
|
* called if sshd is running as root.
|
|
*/
|
|
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)
|
|
/*
|
|
@@ -140,7 +140,7 @@ platform_setusercontext_post_groups(struct passwd *pw)
|
|
}
|
|
#endif /* HAVE_SETPCRED */
|
|
#ifdef WITH_SELINUX
|
|
- ssh_selinux_setup_exec_context(pw->pw_name);
|
|
+ ssh_selinux_setup_exec_context(pw->pw_name, role);
|
|
#endif
|
|
}
|
|
|
|
diff --git a/platform.h b/platform.h
|
|
index 08cbd225d..2a7364578 100644
|
|
--- a/platform.h
|
|
+++ b/platform.h
|
|
@@ -27,7 +27,7 @@ void platform_post_fork_child(void);
|
|
void platform_pre_session_start(void);
|
|
int platform_privileged_uidswap(void);
|
|
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_krb5_get_principal_name(const char *);
|
|
int platform_locked_account(struct passwd *);
|
|
diff --git a/session.c b/session.c
|
|
index b3833e44c..6614d8560 100644
|
|
--- a/session.c
|
|
+++ b/session.c
|
|
@@ -1344,7 +1344,7 @@ safely_chroot(const char *path, uid_t uid)
|
|
|
|
/* Set login name, uid, gid, and groups. */
|
|
void
|
|
-do_setusercontext(struct passwd *pw)
|
|
+do_setusercontext(struct passwd *pw, const char *role)
|
|
{
|
|
char uidstr[32], *chroot_path, *tmp;
|
|
|
|
@@ -1372,7 +1372,7 @@ do_setusercontext(struct passwd *pw)
|
|
endgrent();
|
|
#endif
|
|
|
|
- platform_setusercontext_post_groups(pw);
|
|
+ platform_setusercontext_post_groups(pw, role);
|
|
|
|
if (!in_chroot && options.chroot_directory != NULL &&
|
|
strcasecmp(options.chroot_directory, "none") != 0) {
|
|
@@ -1515,7 +1515,7 @@ do_child(struct ssh *ssh, Session *s, const char *command)
|
|
|
|
/* Force a password change */
|
|
if (s->authctxt->force_pwchange) {
|
|
- do_setusercontext(pw);
|
|
+ do_setusercontext(pw, s->authctxt->role);
|
|
child_close_fds(ssh);
|
|
do_pwchange(s);
|
|
exit(1);
|
|
@@ -1533,7 +1533,7 @@ do_child(struct ssh *ssh, Session *s, const char *command)
|
|
/* When PAM is enabled we rely on it to do the nologin check */
|
|
if (!options.use_pam)
|
|
do_nologin(pw);
|
|
- do_setusercontext(pw);
|
|
+ do_setusercontext(pw, s->authctxt->role);
|
|
/*
|
|
* PAM session modules in do_setusercontext may have
|
|
* generated messages, so if this in an interactive
|
|
diff --git a/session.h b/session.h
|
|
index 344a1ddf9..20ea822a7 100644
|
|
--- a/session.h
|
|
+++ b/session.h
|
|
@@ -77,7 +77,7 @@ void session_pty_cleanup2(Session *);
|
|
Session *session_new(void);
|
|
Session *session_by_tty(char *);
|
|
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);
|
|
|
|
diff --git a/sshd-session.c b/sshd-session.c
|
|
index c171c8923..372a610b3 100644
|
|
--- a/sshd-session.c
|
|
+++ b/sshd-session.c
|
|
@@ -471,7 +471,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt)
|
|
|
|
/* Drop privileges */
|
|
if (!skip_privdrop)
|
|
- do_setusercontext(authctxt->pw);
|
|
+ do_setusercontext(authctxt->pw, authctxt->role);
|
|
|
|
/* It is safe now to apply the key state */
|
|
monitor_apply_keystate(ssh, pmonitor);
|
|
diff --git a/sshpty.c b/sshpty.c
|
|
index cae0b977a..7870c6482 100644
|
|
--- a/sshpty.c
|
|
+++ b/sshpty.c
|
|
@@ -163,7 +163,7 @@ pty_change_window_size(int ptyfd, u_int row, u_int col,
|
|
}
|
|
|
|
void
|
|
-pty_setowner(struct passwd *pw, const char *tty)
|
|
+pty_setowner(struct passwd *pw, const char *tty, const char *role)
|
|
{
|
|
struct group *grp;
|
|
gid_t gid;
|
|
@@ -187,7 +187,7 @@ pty_setowner(struct passwd *pw, const char *tty)
|
|
strerror(errno));
|
|
|
|
#ifdef WITH_SELINUX
|
|
- ssh_selinux_setup_pty(pw->pw_name, tty);
|
|
+ ssh_selinux_setup_pty(pw->pw_name, tty, role);
|
|
#endif
|
|
|
|
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
|
|
diff --git a/sshpty.h b/sshpty.h
|
|
index 9ec7e9a15..de7e000ae 100644
|
|
--- a/sshpty.h
|
|
+++ b/sshpty.h
|
|
@@ -24,5 +24,5 @@ int pty_allocate(int *, int *, char *, size_t);
|
|
void pty_release(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_setowner(struct passwd *, const char *);
|
|
+void pty_setowner(struct passwd *, const char *, const char *);
|
|
void disconnect_controlling_tty(void);
|