1 Description: Handle SELinux authorisation roles
2 Rejected upstream due to discomfort with magic usernames; a better approach
3 will need an SSH protocol change. In the meantime, this came from Debian's
4 SELinux maintainer, so we'll keep it until we have something better.
5 Author: Manoj Srivastava <srivasta@debian.org>
6 Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1641
7 Bug-Debian: http://bugs.debian.org/394795
8 Last-Update: 2010-02-27
11 ===================================================================
16 struct passwd *pw; /* set if 'valid' */
23 ===================================================================
27 do_authentication(Authctxt *authctxt)
30 - char *user, *style = NULL;
31 + char *user, *style = NULL, *role = NULL;
33 /* Get the name of the user that we wish to log in as. */
34 packet_read_expect(SSH_CMSG_USER);
36 user = packet_get_cstring(&ulen);
39 + if ((role = strchr(user, '/')) != NULL)
42 if ((style = strchr(user, ':')) != NULL)
44 + else if (role && (style = strchr(role, ':')) != NULL)
47 authctxt->user = user;
48 authctxt->style = style;
49 + authctxt->role = role;
51 /* Verify that the user is a valid user. */
52 if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
54 ===================================================================
59 Authctxt *authctxt = ctxt;
61 - char *user, *service, *method, *style = NULL;
62 + char *user, *service, *method, *style = NULL, *role = NULL;
63 int authenticated = 0;
67 debug("userauth-request for user %s service %s method %s", user, service, method);
68 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
70 + if ((role = strchr(user, '/')) != NULL)
73 if ((style = strchr(user, ':')) != NULL)
75 + else if (role && (style = strchr(role, ':')) != NULL)
78 if (authctxt->attempt++ == 0) {
79 /* setup auth context */
81 use_privsep ? " [net]" : "");
82 authctxt->service = xstrdup(service);
83 authctxt->style = style ? xstrdup(style) : NULL;
84 + authctxt->role = role ? xstrdup(role) : NULL;
86 - mm_inform_authserv(service, style);
87 + mm_inform_authserv(service, style, role);
89 } else if (strcmp(user, authctxt->user) != 0 ||
90 strcmp(service, authctxt->service) != 0) {
92 ===================================================================
96 int mm_answer_pwnamallow(int, Buffer *);
97 int mm_answer_auth2_read_banner(int, Buffer *);
98 int mm_answer_authserv(int, Buffer *);
99 +int mm_answer_authrole(int, Buffer *);
100 int mm_answer_authpassword(int, Buffer *);
101 int mm_answer_bsdauthquery(int, Buffer *);
102 int mm_answer_bsdauthrespond(int, Buffer *);
104 {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
105 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
106 {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
107 + {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
108 {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
109 {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
113 /* Allow service/style information on the auth context */
114 monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
115 + monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1);
116 monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
119 @@ -732,14 +735,37 @@
121 authctxt->service = buffer_get_string(m, NULL);
122 authctxt->style = buffer_get_string(m, NULL);
123 - debug3("%s: service=%s, style=%s",
124 - __func__, authctxt->service, authctxt->style);
125 + authctxt->role = buffer_get_string(m, NULL);
126 + debug3("%s: service=%s, style=%s, role=%s",
127 + __func__, authctxt->service, authctxt->style, authctxt->role);
129 if (strlen(authctxt->style) == 0) {
130 xfree(authctxt->style);
131 authctxt->style = NULL;
134 + if (strlen(authctxt->role) == 0) {
135 + xfree(authctxt->role);
136 + authctxt->role = NULL;
143 +mm_answer_authrole(int sock, Buffer *m)
145 + monitor_permit_authentications(1);
147 + authctxt->role = buffer_get_string(m, NULL);
148 + debug3("%s: role=%s",
149 + __func__, authctxt->role);
151 + if (strlen(authctxt->role) == 0) {
152 + xfree(authctxt->role);
153 + authctxt->role = NULL;
159 @@ -1327,7 +1353,7 @@
160 res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
163 - pty_setowner(authctxt->pw, s->tty);
164 + pty_setowner(authctxt->pw, s->tty, authctxt->role);
166 buffer_put_int(m, 1);
167 buffer_put_cstring(m, s->tty);
169 ===================================================================
174 enum monitor_reqtype {
175 MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
176 - MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
177 + MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV, MONITOR_REQ_AUTHROLE,
178 MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
179 MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
180 MONITOR_REQ_AUTH2_READ_BANNER, MONITOR_ANS_AUTH2_READ_BANNER,
181 Index: b/monitor_wrap.c
182 ===================================================================
185 @@ -280,10 +280,10 @@
189 -/* Inform the privileged process about service and style */
190 +/* Inform the privileged process about service, style, and role */
193 -mm_inform_authserv(char *service, char *style)
194 +mm_inform_authserv(char *service, char *style, char *role)
198 @@ -292,11 +292,29 @@
200 buffer_put_cstring(&m, service);
201 buffer_put_cstring(&m, style ? style : "");
202 + buffer_put_cstring(&m, role ? role : "");
204 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m);
209 +/* Inform the privileged process about role */
212 +mm_inform_authrole(char *role)
216 + debug3("%s entering", __func__);
219 + buffer_put_cstring(&m, role ? role : "");
221 + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, &m);
226 /* Do the password authentication */
228 Index: b/monitor_wrap.h
229 ===================================================================
233 int mm_is_monitor(void);
234 DH *mm_choose_dh(int, int, int);
235 int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
236 -void mm_inform_authserv(char *, char *);
237 +void mm_inform_authserv(char *, char *, char *);
238 +void mm_inform_authrole(char *);
239 struct passwd *mm_getpwnamallow(const char *);
240 char *mm_auth2_read_banner(void);
241 int mm_auth_password(struct Authctxt *, char *);
242 Index: b/openbsd-compat/port-linux.c
243 ===================================================================
244 --- a/openbsd-compat/port-linux.c
245 +++ b/openbsd-compat/port-linux.c
252 +#include "hostfile.h"
258 #include "port-linux.h"
261 /* Return the default security context for the given username */
262 static security_context_t
263 -ssh_selinux_getctxbyname(char *pwname)
264 +ssh_selinux_getctxbyname(char *pwname, const char *role)
266 - security_context_t sc;
267 + security_context_t sc = NULL;
268 char *sename = NULL, *lvl = NULL;
274 #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
275 - r = get_default_context_with_level(sename, lvl, NULL, &sc);
276 + if (role != NULL && role[0])
277 + r = get_default_context_with_rolelevel(sename, role, lvl, NULL,
280 + r = get_default_context_with_level(sename, lvl, NULL, &sc);
282 - r = get_default_context(sename, NULL, &sc);
283 + if (role != NULL && role[0])
284 + r = get_default_context_with_role(sename, role, NULL, &sc);
286 + r = get_default_context(sename, NULL, &sc);
292 /* Set the execution context to the default for the specified user */
294 -ssh_selinux_setup_exec_context(char *pwname)
295 +ssh_selinux_setup_exec_context(char *pwname, const char *role)
297 security_context_t user_ctx = NULL;
301 debug3("%s: setting execution context", __func__);
303 - user_ctx = ssh_selinux_getctxbyname(pwname);
304 + user_ctx = ssh_selinux_getctxbyname(pwname, role);
305 if (setexeccon(user_ctx) != 0) {
306 switch (security_getenforce()) {
310 /* Set the TTY context for the specified user */
312 -ssh_selinux_setup_pty(char *pwname, const char *tty)
313 +ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role)
315 security_context_t new_tty_ctx = NULL;
316 security_context_t user_ctx = NULL;
319 debug3("%s: setting TTY context on %s", __func__, tty);
321 - user_ctx = ssh_selinux_getctxbyname(pwname);
322 + user_ctx = ssh_selinux_getctxbyname(pwname, role);
324 /* XXX: should these calls fatal() upon failure in enforcing mode? */
326 Index: b/openbsd-compat/port-linux.h
327 ===================================================================
328 --- a/openbsd-compat/port-linux.h
329 +++ b/openbsd-compat/port-linux.h
333 int ssh_selinux_enabled(void);
334 -void ssh_selinux_setup_pty(char *, const char *);
335 -void ssh_selinux_setup_exec_context(char *);
336 +void ssh_selinux_setup_pty(char *, const char *, const char *);
337 +void ssh_selinux_setup_exec_context(char *, const char *);
338 void ssh_selinux_change_context(const char *);
339 void ssh_selinux_setfscreatecon(const char *);
342 ===================================================================
346 * called if sshd is running as root.
349 -platform_setusercontext_post_groups(struct passwd *pw)
350 +platform_setusercontext_post_groups(struct passwd *pw, const char *role)
352 #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM)
356 #endif /* HAVE_SETPCRED */
358 - ssh_selinux_setup_exec_context(pw->pw_name);
359 + ssh_selinux_setup_exec_context(pw->pw_name, role);
364 ===================================================================
368 void platform_post_fork_child(void);
369 int platform_privileged_uidswap(void);
370 void platform_setusercontext(struct passwd *);
371 -void platform_setusercontext_post_groups(struct passwd *);
372 +void platform_setusercontext_post_groups(struct passwd *, const char *);
373 char *platform_get_krb5_client(const char *);
374 char *platform_krb5_get_principal_name(const char *);
377 ===================================================================
380 @@ -1467,7 +1467,7 @@
382 /* Set login name, uid, gid, and groups. */
384 -do_setusercontext(struct passwd *pw)
385 +do_setusercontext(struct passwd *pw, const char *role)
387 char *chroot_path, *tmp;
389 @@ -1495,7 +1495,7 @@
393 - platform_setusercontext_post_groups(pw);
394 + platform_setusercontext_post_groups(pw, role);
396 if (options.chroot_directory != NULL &&
397 strcasecmp(options.chroot_directory, "none") != 0) {
398 @@ -1618,7 +1618,7 @@
400 /* Force a password change */
401 if (s->authctxt->force_pwchange) {
402 - do_setusercontext(pw);
403 + do_setusercontext(pw, s->authctxt->role);
407 @@ -1645,7 +1645,7 @@
408 /* When PAM is enabled we rely on it to do the nologin check */
409 if (!options.use_pam)
411 - do_setusercontext(pw);
412 + do_setusercontext(pw, s->authctxt->role);
414 * PAM session modules in do_setusercontext may have
415 * generated messages, so if this in an interactive
416 @@ -2057,7 +2057,7 @@
417 tty_parse_modes(s->ttyfd, &n_bytes);
420 - pty_setowner(s->pw, s->tty);
421 + pty_setowner(s->pw, s->tty, s->authctxt->role);
423 /* Set window size from the packet. */
424 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
426 ===================================================================
430 Session *session_new(void);
431 Session *session_by_tty(char *);
432 void session_close(Session *);
433 -void do_setusercontext(struct passwd *);
434 +void do_setusercontext(struct passwd *, const char *);
435 void child_set_env(char ***envp, u_int *envsizep, const char *name,
439 ===================================================================
443 RAND_seed(rnd, sizeof(rnd));
445 /* Drop privileges */
446 - do_setusercontext(authctxt->pw);
447 + do_setusercontext(authctxt->pw, authctxt->role);
450 /* It is safe now to apply the key state */
452 ===================================================================
459 -pty_setowner(struct passwd *pw, const char *tty)
460 +pty_setowner(struct passwd *pw, const char *tty, const char *role)
468 - ssh_selinux_setup_pty(pw->pw_name, tty);
469 + ssh_selinux_setup_pty(pw->pw_name, tty, role);
472 if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
474 ===================================================================
478 void pty_release(const char *);
479 void pty_make_controlling_tty(int *, const char *);
480 void pty_change_window_size(int, u_int, u_int, u_int, u_int);
481 -void pty_setowner(struct passwd *, const char *);
482 +void pty_setowner(struct passwd *, const char *, const char *);