2 * Copyright (c) 2003-2012 Todd C. Miller <Todd.Miller@courtesan.com>
3 * Copyright (c) 2011 Daniel Kopecek <dkopecek@redhat.com>
5 * This code is derived from software contributed by Aaron Spangler.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/types.h>
24 #include <sys/param.h>
34 #endif /* STDC_HEADERS */
37 #endif /* HAVE_STRING_H */
40 #endif /* HAVE_STRINGS_H */
43 #endif /* HAVE_UNISTD_H */
44 #if TIME_WITH_SYS_TIME
50 # include "compat/dlfcn.h"
62 #include "sudo_debug.h"
64 /* SSSD <--> SUDO interface - do not change */
65 struct sss_sudo_attr {
68 unsigned int num_values;
71 struct sss_sudo_rule {
72 unsigned int num_attrs;
73 struct sss_sudo_attr *attrs;
76 struct sss_sudo_result {
77 unsigned int num_rules;
78 struct sss_sudo_rule *rules;
81 typedef int (*sss_sudo_send_recv_t)(uid_t, const char*, const char*,
82 uint32_t*, struct sss_sudo_result**);
84 typedef int (*sss_sudo_send_recv_defaults_t)(uid_t, const char*, uint32_t*,
85 char**, struct sss_sudo_result**);
87 typedef void (*sss_sudo_free_result_t)(struct sss_sudo_result*);
89 typedef int (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*,
92 typedef void (*sss_sudo_free_values_t)(char**);
94 /* sudo_nss implementation */
96 struct sudo_sss_handle {
100 sss_sudo_send_recv_t fn_send_recv;
101 sss_sudo_send_recv_defaults_t fn_send_recv_defaults;
102 sss_sudo_free_result_t fn_free_result;
103 sss_sudo_get_values_t fn_get_values;
104 sss_sudo_free_values_t fn_free_values;
107 static int sudo_sss_open(struct sudo_nss *nss);
108 static int sudo_sss_close(struct sudo_nss *nss);
109 static int sudo_sss_parse(struct sudo_nss *nss);
110 static void sudo_sss_parse_options(struct sudo_sss_handle *handle,
111 struct sss_sudo_rule *rule);
112 static int sudo_sss_setdefs(struct sudo_nss *nss);
113 static int sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag);
114 static int sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
115 static int sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
118 static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
119 struct passwd *pw, struct lbuf *lbuf);
121 static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
125 static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
130 sudo_sss_attrcpy(struct sss_sudo_attr *dst, const struct sss_sudo_attr *src)
133 debug_decl(sudo_sss_attrcpy, SUDO_DEBUG_SSSD)
135 sudo_debug_printf(SUDO_DEBUG_DEBUG, "dst=%p, src=%p", dst, src);
136 sudo_debug_printf(SUDO_DEBUG_INFO, "emalloc: cnt=%d", src->num_values);
138 dst->name = estrdup(src->name);
139 dst->num_values = src->num_values;
140 dst->values = emalloc2(dst->num_values, sizeof(char *));
142 for (i = 0; i < dst->num_values; ++i)
143 dst->values[i] = estrdup(src->values[i]);
149 sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
152 debug_decl(sudo_sss_rulecpy, SUDO_DEBUG_SSSD)
154 sudo_debug_printf(SUDO_DEBUG_DEBUG, "dst=%p, src=%p", dst, src);
155 sudo_debug_printf(SUDO_DEBUG_INFO, "emalloc: cnt=%d", src->num_attrs);
157 dst->num_attrs = src->num_attrs;
158 dst->attrs = emalloc2(dst->num_attrs, sizeof(struct sss_sudo_attr));
160 for (i = 0; i < dst->num_attrs; ++i)
161 sudo_sss_attrcpy(dst->attrs + i, src->attrs + i);
166 #define _SUDO_SSS_FILTER_INCLUDE 0
167 #define _SUDO_SSS_FILTER_EXCLUDE 1
169 #define _SUDO_SSS_STATE_HOSTMATCH 0x01
170 #define _SUDO_SSS_STATE_USERMATCH 0x02
172 static struct sss_sudo_result *
173 sudo_sss_filter_result(struct sudo_sss_handle *handle,
174 struct sss_sudo_result *in_res,
175 int (*filterp)(struct sudo_sss_handle *, struct sss_sudo_rule *, void *),
176 int act, void *filterp_arg)
178 struct sss_sudo_result *out_res;
180 debug_decl(sudo_sss_filter_result, SUDO_DEBUG_SSSD)
182 sudo_debug_printf(SUDO_DEBUG_DEBUG, "in_res=%p, count=%u, act=%s",
183 in_res, in_res->num_rules,
184 act == _SUDO_SSS_FILTER_EXCLUDE ? "EXCLUDE" : "INCLUDE");
187 debug_return_ptr(NULL);
189 sudo_debug_printf(SUDO_DEBUG_DEBUG, "emalloc: cnt=%d", in_res->num_rules);
191 out_res = emalloc(sizeof(struct sss_sudo_result));
192 out_res->rules = in_res->num_rules > 0 ?
193 emalloc2(in_res->num_rules, sizeof(struct sss_sudo_rule)) : NULL;
194 out_res->num_rules = 0;
196 for (i = l = 0; i < in_res->num_rules; ++i) {
197 r = filterp(handle, in_res->rules + i, filterp_arg);
199 if (( r && act == _SUDO_SSS_FILTER_INCLUDE) ||
200 (!r && act == _SUDO_SSS_FILTER_EXCLUDE)) {
201 sudo_debug_printf(SUDO_DEBUG_DEBUG,
202 "COPY (%s): %p[%u] => %p[%u] (= %p)",
203 act == _SUDO_SSS_FILTER_EXCLUDE ? "not excluded" : "included",
204 in_res->rules, i, out_res->rules, l, in_res->rules + i);
206 sudo_sss_rulecpy(out_res->rules + l, in_res->rules + i);
211 if (l < in_res->num_rules) {
212 sudo_debug_printf(SUDO_DEBUG_DEBUG,
213 "reallocating result: %p (count: %u -> %u)", out_res->rules,
214 in_res->num_rules, l);
215 out_res->rules = erealloc3(out_res->rules, l, sizeof(struct sss_sudo_rule));
218 out_res->num_rules = l;
220 debug_return_ptr(out_res);
223 struct sudo_nss sudo_nss_sss = {
231 sudo_sss_display_cmnd,
232 sudo_sss_display_defaults,
233 sudo_sss_display_bound_defaults,
234 sudo_sss_display_privs
237 /* sudo_nss implementation */
239 static int sudo_sss_open(struct sudo_nss *nss)
241 struct sudo_sss_handle *handle;
242 static const char path[] = _PATH_SSSD_LIB"/libsss_sudo.so";
243 debug_decl(sudo_sss_open, SUDO_DEBUG_SSSD);
245 /* Create a handle container. */
246 handle = emalloc(sizeof(struct sudo_sss_handle));
249 handle->ssslib = dlopen(path, RTLD_LAZY);
250 if (handle->ssslib == NULL) {
251 warningx(_("Unable to dlopen %s: %s"), path, dlerror());
252 warningx(_("Unable to initialize SSS source. Is SSSD installed on your machine?"));
253 debug_return_int(EFAULT);
256 handle->fn_send_recv = dlsym(handle->ssslib, "sss_sudo_send_recv");
257 if (handle->fn_send_recv == NULL) {
258 warningx(_("unable to find symbol \"%s\" in %s"), path,
259 "sss_sudo_send_recv");
260 debug_return_int(EFAULT);
263 handle->fn_send_recv_defaults =
264 dlsym(handle->ssslib, "sss_sudo_send_recv_defaults");
265 if (handle->fn_send_recv_defaults == NULL) {
266 warningx(_("unable to find symbol \"%s\" in %s"), path,
267 "sss_sudo_send_recv_defaults");
268 debug_return_int(EFAULT);
271 handle->fn_free_result = dlsym(handle->ssslib, "sss_sudo_free_result");
272 if (handle->fn_free_result == NULL) {
273 warningx(_("unable to find symbol \"%s\" in %s"), path,
274 "sss_sudo_free_result");
275 debug_return_int(EFAULT);
278 handle->fn_get_values = dlsym(handle->ssslib, "sss_sudo_get_values");
279 if (handle->fn_get_values == NULL) {
280 warningx(_("unable to find symbol \"%s\" in %s"), path,
281 "sss_sudo_get_values");
282 debug_return_int(EFAULT);
285 handle->fn_free_values = dlsym(handle->ssslib, "sss_sudo_free_values");
286 if (handle->fn_free_values == NULL) {
287 warningx(_("unable to find symbol \"%s\" in %s"), path,
288 "sss_sudo_free_values");
289 debug_return_int(EFAULT);
292 handle->domainname = NULL;
293 handle->pw = sudo_user.pw;
294 nss->handle = handle;
296 sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle);
302 static int sudo_sss_close(struct sudo_nss *nss)
304 struct sudo_sss_handle *handle;
305 debug_decl(sudo_sss_close, SUDO_DEBUG_SSSD);
307 if (nss && nss->handle) {
308 handle = nss->handle;
309 dlclose(handle->ssslib);
317 static int sudo_sss_parse(struct sudo_nss *nss)
319 debug_decl(sudo_sss_parse, SUDO_DEBUG_SSSD);
323 static int sudo_sss_setdefs(struct sudo_nss *nss)
325 struct sudo_sss_handle *handle = nss->handle;
327 struct sss_sudo_result *sss_result;
328 struct sss_sudo_rule *sss_rule;
331 debug_decl(sudo_sss_setdefs, SUDO_DEBUG_SSSD);
334 debug_return_int(-1);
336 sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
338 if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
339 &sss_error, &handle->domainname,
341 sudo_debug_printf(SUDO_DEBUG_INFO,
342 "handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
343 debug_return_int(-1);
346 if (sss_error == ENOENT) {
347 sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
348 debug_return_int(-1);
349 } else if(sss_error != 0) {
350 sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
351 debug_return_int(-1);
354 for (i = 0; i < sss_result->num_rules; ++i) {
355 sudo_debug_printf(SUDO_DEBUG_DIAG,
356 "Parsing cn=defaults, %d/%d", i, sss_result->num_rules);
357 sss_rule = sss_result->rules + i;
358 sudo_sss_parse_options(handle, sss_rule);
361 handle->fn_free_result(sss_result);
365 static int sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
367 struct sudo_sss_handle *handle = nss->handle;
368 debug_decl(sudo_sss_checkpw, SUDO_DEBUG_SSSD);
370 if (pw->pw_name != handle->pw->pw_name ||
371 pw->pw_uid != handle->pw->pw_uid) {
372 sudo_debug_printf(SUDO_DEBUG_DIAG,
373 "Requested name or uid don't match the initial once, reinitializing...");
376 if (sudo_sss_setdefs(nss) != 0)
377 debug_return_int(-1);
384 sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule)
386 char **val_array = NULL;
389 debug_decl(sudo_sss_check_runas_user, SUDO_DEBUG_SSSD);
392 debug_return_int(UNSPEC);
394 /* get the runas user from the entry */
395 switch (handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array)) {
399 sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs)");
402 switch (handle->fn_get_values(sss_rule, "sudoRunAs", &val_array)) {
406 sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Matching against runas_default");
408 * If there are no runas entries, match runas_default against
409 * what the user specified on the command line.
411 return !strcasecmp(runas_pw->pw_name, def_runas_default);
413 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
414 debug_return_int(UNSPEC);
418 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
419 debug_return_int(UNSPEC);
425 * if runas is not specified on the command line, the only information
426 * as to which user to run as is in the runas_default option. We should
427 * check to see if we have the local option present. Unfortunately we
428 * don't parse these options until after this routine says yes or no.
429 * The query has already returned, so we could peek at the attribute
430 * values here though.
432 * For now just require users to always use -u option unless its set
433 * in the global defaults. This behaviour is no different than the global
436 * Sigh - maybe add this feature later
439 /* walk through values returned, looking for a match */
440 for (i = 0; val_array[i] != NULL && !ret; ++i) {
443 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
447 sudo_debug_printf(SUDO_DEBUG_DEBUG, "netgr_");
448 if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) {
449 sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
454 sudo_debug_printf(SUDO_DEBUG_DEBUG, "usergr_");
455 if (usergr_matches(val, runas_pw->pw_name, runas_pw)) {
456 sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
461 if (strcmp(val, "ALL") == 0) {
462 sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
467 sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
469 if (strcasecmp(val, runas_pw->pw_name) == 0) {
470 sudo_debug_printf(SUDO_DEBUG_DEBUG,
471 "%s == %s (pw_name) => match", val, runas_pw->pw_name);
477 sudo_debug_printf(SUDO_DEBUG_INFO,
478 "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
481 handle->fn_free_values(val_array); /* cleanup */
483 debug_return_int(ret);
487 sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
489 char **val_array = NULL;
492 debug_decl(sudo_sss_check_runas_group, SUDO_DEBUG_SSSD);
494 /* runas_gr is only set if the user specified the -g flag */
496 debug_return_int(UNSPEC);
498 /* get the values from the entry */
499 switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
503 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
504 debug_return_int(false);
506 sudo_debug_printf(SUDO_DEBUG_INFO,
507 "handle->fn_get_values(sudoRunAsGroup): != 0");
508 debug_return_int(UNSPEC);
511 /* walk through values returned, looking for a match */
512 for (i = 0; val_array[i] != NULL; ++i) {
514 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
516 if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
519 sudo_debug_printf(SUDO_DEBUG_INFO,
520 "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
523 handle->fn_free_values(val_array);
525 debug_return_int(ret);
529 * Walk through search results and return true if we have a runas match,
530 * else false. RunAs info is optional.
533 sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
536 debug_decl(sudo_sss_check_runas, SUDO_DEBUG_SSSD);
539 debug_return_int(false);
541 ret = sudo_sss_check_runas_user(handle, rule) != false &&
542 sudo_sss_check_runas_group(handle, rule) != false;
544 debug_return_int(ret);
548 sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
550 char **val_array, *val;
552 debug_decl(sudo_sss_check_host, SUDO_DEBUG_SSSD);
555 debug_return_int(ret);
557 /* get the values from the rule */
558 switch (handle->fn_get_values(rule, "sudoHost", &val_array))
563 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
564 debug_return_int(false);
566 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoHost): != 0");
567 debug_return_int(ret);
570 /* walk through values */
571 for (i = 0; val_array[i] != NULL; ++i) {
573 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
575 /* match any or address or netgroup or hostname */
576 if (!strcmp(val, "ALL") || addr_matches(val) ||
577 netgr_matches(val, user_host, user_shost, NULL) ||
578 hostname_matches(user_shost, user_host, val))
581 sudo_debug_printf(SUDO_DEBUG_INFO,
582 "sssd/ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
585 handle->fn_free_values(val_array);
587 debug_return_int(ret);
591 sudo_sss_result_filterp(struct sudo_sss_handle *handle,
592 struct sss_sudo_rule *rule, void *unused)
595 debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_SSSD);
597 if (sudo_sss_check_host(handle, rule))
603 static struct sss_sudo_result *
604 sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
606 struct sudo_sss_handle *handle = nss->handle;
607 struct sss_sudo_result *u_sss_result, *f_sss_result;
608 uint32_t sss_error = 0, ret;
609 debug_decl(sudo_sss_result_get, SUDO_DEBUG_SSSD);
611 if (sudo_sss_checkpw(nss, pw) != 0)
612 debug_return_ptr(NULL);
614 sudo_debug_printf(SUDO_DEBUG_DIAG, " username=%s", handle->pw->pw_name);
615 sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s", handle->domainname);
617 u_sss_result = f_sss_result = NULL;
619 ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
620 handle->domainname, &sss_error, &u_sss_result);
626 if (u_sss_result != NULL) {
628 sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
629 *state |= _SUDO_SSS_STATE_USERMATCH;
631 sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
632 u_sss_result->num_rules);
634 sudo_debug_printf(SUDO_DEBUG_INFO,
635 "Internal error: u_sss_result == NULL && sss_error == 0");
636 debug_return_ptr(NULL);
640 sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
642 sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
643 debug_return_ptr(NULL);
647 sudo_debug_printf(SUDO_DEBUG_INFO,
648 "handle->fn_send_recv: != 0: ret=%d", ret);
649 debug_return_ptr(NULL);
652 f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
653 sudo_sss_result_filterp, _SUDO_SSS_FILTER_INCLUDE, NULL);
655 if (f_sss_result != NULL) {
656 if (f_sss_result->num_rules > 0) {
658 sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
659 *state |= _SUDO_SSS_STATE_HOSTMATCH;
664 sudo_debug_printf(SUDO_DEBUG_DEBUG,
665 "u_sss_result=(%p, %u) => f_sss_result=(%p, %u)", u_sss_result,
666 u_sss_result->num_rules, f_sss_result, f_sss_result->num_rules);
668 handle->fn_free_result(u_sss_result);
670 debug_return_ptr(f_sss_result);
674 * Search for boolean "option" in sudoOption.
675 * Returns true if found and allowed, false if negated, else UNSPEC.
678 sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
681 char ch, *var, **val_array = NULL;
683 debug_decl(sudo_sss_check_bool, SUDO_DEBUG_SSSD);
686 debug_return_int(ret);
688 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
692 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
693 debug_return_int(ret);
695 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
696 debug_return_int(ret);
699 /* walk through options */
700 for (i = 0; val_array[i] != NULL; ++i) {
702 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
704 if ((ch = *var) == '!')
706 if (strcmp(var, option) == 0)
710 handle->fn_free_values(val_array);
712 debug_return_int(ret);
716 * Walk through search results and return true if we have a command match,
717 * false if disallowed and UNSPEC if not matched.
720 sudo_sss_check_command(struct sudo_sss_handle *handle,
721 struct sss_sudo_rule *rule, int *setenv_implied)
723 char **val_array = NULL, *val;
724 char *allowed_cmnd, *allowed_args;
725 int i, foundbang, ret = UNSPEC;
726 debug_decl(sudo_sss_check_command, SUDO_DEBUG_SSSD);
729 debug_return_int(ret);
731 switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
735 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
736 debug_return_int(ret);
738 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
739 debug_return_int(ret);
742 for (i = 0; val_array[i] != NULL && ret != false; ++i) {
745 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
747 /* Match against ALL ? */
748 if (!strcmp(val, "ALL")) {
750 if (setenv_implied != NULL)
751 *setenv_implied = true;
752 sudo_debug_printf(SUDO_DEBUG_INFO,
753 "sssd/ldap sudoCommand '%s' ... MATCH!", val);
757 /* check for !command */
760 allowed_cmnd = estrdup(1 + val); /* !command */
763 allowed_cmnd = estrdup(val); /* command */
766 /* split optional args away from command */
767 allowed_args = strchr(allowed_cmnd, ' ');
769 *allowed_args++ = '\0';
771 /* check the command like normal */
772 if (command_matches(allowed_cmnd, allowed_args)) {
774 * If allowed (no bang) set ret but keep on checking.
775 * If disallowed (bang), exit loop.
777 ret = foundbang ? false : true;
780 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
781 val, ret == true ? "MATCH!" : "not");
782 efree(allowed_cmnd); /* cleanup */
785 handle->fn_free_values(val_array); /* more cleanup */
787 debug_return_int(ret);
791 sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
795 char **val_array = NULL;
796 debug_decl(sudo_sss_parse_options, SUDO_DEBUG_SSSD);
801 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
805 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
808 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
812 /* walk through options */
813 for (i = 0; val_array[i] != NULL; i++) {
814 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'",
816 v = estrdup(val_array[i]);
818 /* check for equals sign past first char */
819 val = strchr(v, '=');
821 *val++ = '\0'; /* split on = and truncate var */
822 op = *(val - 2); /* peek for += or -= cases */
823 if (op == '+' || op == '-') {
824 *(val - 2) = '\0'; /* found, remove extra char */
825 /* case var+=val or var-=val */
826 set_default(v, val, (int) op);
829 set_default(v, val, true);
831 } else if (*v == '!') {
832 /* case !var Boolean False */
833 set_default(v + 1, NULL, false);
835 /* case var Boolean True */
836 set_default(v, NULL, true);
841 handle->fn_free_values(val_array);
846 sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
848 int rc, setenv_implied;
850 struct sudo_sss_handle *handle = nss->handle;
851 struct sss_sudo_result *sss_result = NULL;
852 struct sss_sudo_rule *rule;
853 uint32_t i, state = 0;
854 debug_decl(sudo_sss_lookup, SUDO_DEBUG_SSSD);
856 /* Fetch list of sudoRole entries that match user and host. */
857 sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
860 * The following queries are only determine whether or not a
861 * password is required, so the order of the entries doesn't matter.
865 int matched = UNSPEC;
866 enum def_tuple pwcheck =
867 (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
869 sudo_debug_printf(SUDO_DEBUG_INFO, "perform search for pwflag %d", pwflag);
870 if (sss_result != NULL) {
871 for (i = 0; i < sss_result->num_rules; i++) {
872 rule = sss_result->rules + i;
873 if ((pwcheck == any && doauth != false) ||
874 (pwcheck == all && doauth == false)) {
875 doauth = sudo_sss_check_bool(handle, rule, "authenticate");
877 /* Only check the command when listing another user. */
878 if (user_uid == 0 || list_pw == NULL ||
879 user_uid == list_pw->pw_uid ||
880 sudo_sss_check_command(handle, rule, NULL)) {
886 if (matched || user_uid == 0) {
887 SET(ret, VALIDATE_OK);
888 CLR(ret, VALIDATE_NOT_OK);
889 if (def_authenticate) {
892 SET(ret, FLAG_CHECK_USER);
897 def_authenticate = false;
900 def_authenticate = false;
910 sudo_debug_printf(SUDO_DEBUG_DIAG,
911 "searching SSSD/LDAP for sudoers entries");
913 setenv_implied = false;
914 if (sss_result != NULL) {
915 for (i = 0; i < sss_result->num_rules; i++) {
916 rule = sss_result->rules + i;
917 if (!sudo_sss_check_runas(handle, rule))
919 rc = sudo_sss_check_command(handle, rule, &setenv_implied);
921 /* We have a match. */
922 sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
923 rc == true ? "" : "NOT ");
925 sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
926 /* Apply entry-specific options. */
929 sudo_sss_parse_options(handle, rule);
931 /* Set role and type if not specified on command line. */
932 if (user_role == NULL)
933 user_role = def_role;
934 if (user_type == NULL)
935 user_type = def_type;
936 #endif /* HAVE_SELINUX */
937 SET(ret, VALIDATE_OK);
938 CLR(ret, VALIDATE_NOT_OK);
940 SET(ret, VALIDATE_NOT_OK);
941 CLR(ret, VALIDATE_OK);
948 sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
950 if (!ISSET(ret, VALIDATE_OK)) {
951 /* No matching entries. */
952 if (pwflag && list_pw == NULL)
953 SET(ret, FLAG_NO_CHECK);
956 if (state & _SUDO_SSS_STATE_USERMATCH)
957 CLR(ret, FLAG_NO_USER);
958 if (state & _SUDO_SSS_STATE_HOSTMATCH)
959 CLR(ret, FLAG_NO_HOST);
961 sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
964 debug_return_int(ret);
968 sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
970 struct sudo_sss_handle *handle = nss->handle;
971 struct sss_sudo_result *sss_result = NULL;
972 struct sss_sudo_rule *rule;
973 int i, found = false;
974 debug_decl(sudo_sss_display_cmnd, SUDO_DEBUG_SSSD);
979 if (sudo_sss_checkpw(nss, pw) != 0)
980 debug_return_int(-1);
983 * The sudo_sss_result_get() function returns all nodes that match
984 * the user and the host.
986 sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
987 sss_result = sudo_sss_result_get(nss, pw, NULL);
989 if (sss_result == NULL)
992 for (i = 0; i < sss_result->num_rules; i++) {
993 rule = sss_result->rules + i;
994 if (sudo_sss_check_command(handle, rule, NULL) &&
995 sudo_sss_check_runas(handle, rule)) {
1003 printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1004 user_args ? " " : "", user_args ? user_args : "");
1006 if (sss_result != NULL)
1007 handle->fn_free_result(sss_result);
1009 debug_return_int(!found);
1013 sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1016 struct sudo_sss_handle *handle = nss->handle;
1018 struct sss_sudo_rule *rule;
1019 struct sss_sudo_result *sss_result = NULL;
1021 uint32_t sss_error = 0;
1023 char *prefix, *val, **val_array = NULL;
1024 int count = 0, i, j;
1026 debug_decl(sudo_sss_display_defaults, SUDO_DEBUG_SSSD);
1031 if (handle->fn_send_recv_defaults(pw->pw_uid, pw->pw_name,
1032 &sss_error, &handle->domainname,
1033 &sss_result) != 0) {
1034 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_send_recv_defaults: !=0, sss_error=%u", sss_error);
1038 if (sss_error == ENOENT) {
1039 sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
1041 } else if(sss_error != 0) {
1042 sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
1048 for (i = 0; i < sss_result->num_rules; ++i) {
1049 rule = sss_result->rules + i;
1051 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1055 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1058 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
1062 if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1067 for (j = 0; val_array[j] != NULL; ++j) {
1069 lbuf_append(lbuf, "%s%s", prefix, val);
1074 handle->fn_free_values(val_array);
1078 handle->fn_free_result(sss_result);
1080 debug_return_int(count);
1085 sudo_sss_display_bound_defaults(struct sudo_nss *nss,
1086 struct passwd *pw, struct lbuf *lbuf)
1088 debug_decl(sudo_sss_display_bound_defaults, SUDO_DEBUG_SSSD);
1089 debug_return_int(0);
1093 sudo_sss_display_entry_long(struct sudo_sss_handle *handle,
1094 struct sss_sudo_rule *rule, struct lbuf *lbuf)
1096 char **val_array = NULL;
1098 debug_decl(sudo_sss_display_entry_long, SUDO_DEBUG_SSSD);
1100 /* get the RunAsUser Values from the entry */
1101 lbuf_append(lbuf, " RunAsUsers: ");
1102 switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1104 for (i = 0; val_array[i] != NULL; ++i)
1105 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1106 handle->fn_free_values(val_array);
1109 switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1111 for (i = 0; val_array[i] != NULL; ++i)
1112 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1113 handle->fn_free_values(val_array);
1116 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1117 lbuf_append(lbuf, "%s", def_runas_default);
1120 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
1121 debug_return_int(count);
1125 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
1126 debug_return_int(count);
1128 lbuf_append(lbuf, "\n");
1130 /* get the RunAsGroup Values from the entry */
1131 switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1133 lbuf_append(lbuf, " RunAsGroups: ");
1134 for (i = 0; val_array[i] != NULL; ++i)
1135 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1136 handle->fn_free_values(val_array);
1137 lbuf_append(lbuf, "\n");
1140 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1143 sudo_debug_printf(SUDO_DEBUG_INFO,
1144 "handle->fn_get_values(sudoRunAsGroup): != 0");
1145 debug_return_int(count);
1148 /* get the Option Values from the entry */
1149 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1151 lbuf_append(lbuf, " Options: ");
1152 for (i = 0; val_array[i] != NULL; ++i)
1153 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1154 handle->fn_free_values(val_array);
1155 lbuf_append(lbuf, "\n");
1158 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1161 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
1162 debug_return_int(count);
1165 /* Get the command values from the entry. */
1166 switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1168 lbuf_append(lbuf, _(" Commands:\n"));
1169 for (i = 0; val_array[i] != NULL; ++i) {
1170 lbuf_append(lbuf, "\t%s\n", val_array[i]);
1173 handle->fn_free_values(val_array);
1176 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1179 sudo_debug_printf(SUDO_DEBUG_INFO,
1180 "handle->fn_get_values(sudoCommand): != 0");
1181 debug_return_int(count);
1184 debug_return_int(count);
1188 sudo_sss_display_entry_short(struct sudo_sss_handle *handle,
1189 struct sss_sudo_rule *rule, struct lbuf *lbuf)
1191 char **val_array = NULL;
1193 debug_decl(sudo_sss_display_entry_short, SUDO_DEBUG_SSSD);
1195 lbuf_append(lbuf, " (");
1197 /* get the RunAsUser Values from the entry */
1198 switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1200 for (i = 0; val_array[i] != NULL; ++i)
1201 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1202 handle->fn_free_values(val_array);
1205 sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs).");
1207 switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1209 for (i = 0; val_array[i] != NULL; ++i)
1210 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1211 handle->fn_free_values(val_array);
1214 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1215 lbuf_append(lbuf, "%s", def_runas_default);
1218 sudo_debug_printf(SUDO_DEBUG_INFO,
1219 "handle->fn_get_values(sudoRunAs): != 0");
1220 debug_return_int(count);
1224 sudo_debug_printf(SUDO_DEBUG_INFO,
1225 "handle->fn_get_values(sudoRunAsUser): != 0");
1226 debug_return_int(count);
1229 /* get the RunAsGroup Values from the entry */
1230 switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1232 lbuf_append(lbuf, " : ");
1233 for (i = 0; val_array[i] != NULL; ++i)
1234 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1235 handle->fn_free_values(val_array);
1238 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1241 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsGroup): != 0");
1242 debug_return_int(count);
1245 lbuf_append(lbuf, ") ");
1247 /* get the Option Values from the entry */
1248 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1250 for (i = 0; val_array[i] != NULL; ++i) {
1251 char *cp = val_array[i];
1254 if (strcmp(cp, "authenticate") == 0)
1255 lbuf_append(lbuf, val_array[i][0] == '!' ?
1256 "NOPASSWD: " : "PASSWD: ");
1257 else if (strcmp(cp, "noexec") == 0)
1258 lbuf_append(lbuf, val_array[i][0] == '!' ?
1259 "EXEC: " : "NOEXEC: ");
1260 else if (strcmp(cp, "setenv") == 0)
1261 lbuf_append(lbuf, val_array[i][0] == '!' ?
1262 "NOSETENV: " : "SETENV: ");
1264 handle->fn_free_values(val_array);
1267 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1270 sudo_debug_printf(SUDO_DEBUG_INFO,
1271 "handle->fn_get_values(sudoOption): != 0");
1272 debug_return_int(count);
1275 /* get the Command Values from the entry */
1276 switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1278 for (i = 0; val_array[i] != NULL; ++i) {
1279 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1282 handle->fn_free_values(val_array);
1285 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1288 sudo_debug_printf(SUDO_DEBUG_INFO,
1289 "handle->fn_get_values(sudoCommand): != 0");
1290 debug_return_int(count);
1292 lbuf_append(lbuf, "\n");
1294 debug_return_int(count);
1298 sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
1301 struct sudo_sss_handle *handle = nss->handle;
1303 struct sss_sudo_result *sss_result = NULL;
1304 struct sss_sudo_rule *rule;
1305 unsigned int i, count = 0;
1306 debug_decl(sudo_sss_display_privs, SUDO_DEBUG_SSSD);
1309 debug_return_int(-1);
1310 if (sudo_sss_checkpw(nss, pw) != 0)
1311 debug_return_int(-1);
1313 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
1315 sss_result = sudo_sss_result_get(nss, pw, NULL);
1317 if (sss_result == NULL)
1318 debug_return_int(count);
1320 /* Display all matching entries. */
1321 for (i = 0; i < sss_result->num_rules; ++i) {
1322 rule = sss_result->rules + i;
1324 count += sudo_sss_display_entry_long(handle, rule, lbuf);
1326 count += sudo_sss_display_entry_short(handle, rule, lbuf);
1329 if (sss_result != NULL)
1330 handle->fn_free_result(sss_result);
1332 debug_return_int(count);