2 * Copyright (c) 2003-2013 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>
33 #endif /* STDC_HEADERS */
36 #endif /* HAVE_STRING_H */
39 #endif /* HAVE_STRINGS_H */
42 #endif /* HAVE_UNISTD_H */
43 #if TIME_WITH_SYS_TIME
49 # include "compat/dlfcn.h"
61 #include "sudo_debug.h"
63 /* SSSD <--> SUDO interface - do not change */
64 struct sss_sudo_attr {
67 unsigned int num_values;
70 struct sss_sudo_rule {
71 unsigned int num_attrs;
72 struct sss_sudo_attr *attrs;
75 struct sss_sudo_result {
76 unsigned int num_rules;
77 struct sss_sudo_rule *rules;
80 typedef int (*sss_sudo_send_recv_t)(uid_t, const char*, const char*,
81 uint32_t*, struct sss_sudo_result**);
83 typedef int (*sss_sudo_send_recv_defaults_t)(uid_t, const char*, uint32_t*,
84 char**, struct sss_sudo_result**);
86 typedef void (*sss_sudo_free_result_t)(struct sss_sudo_result*);
88 typedef int (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*,
91 typedef void (*sss_sudo_free_values_t)(char**);
93 /* sudo_nss implementation */
95 struct sudo_sss_handle {
99 sss_sudo_send_recv_t fn_send_recv;
100 sss_sudo_send_recv_defaults_t fn_send_recv_defaults;
101 sss_sudo_free_result_t fn_free_result;
102 sss_sudo_get_values_t fn_get_values;
103 sss_sudo_free_values_t fn_free_values;
106 static int sudo_sss_open(struct sudo_nss *nss);
107 static int sudo_sss_close(struct sudo_nss *nss);
108 static int sudo_sss_parse(struct sudo_nss *nss);
109 static void sudo_sss_parse_options(struct sudo_sss_handle *handle,
110 struct sss_sudo_rule *rule);
111 static int sudo_sss_setdefs(struct sudo_nss *nss);
112 static int sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag);
113 static int sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
114 static int sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
117 static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
118 struct passwd *pw, struct lbuf *lbuf);
120 static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
124 static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
129 sudo_sss_attrcpy(struct sss_sudo_attr *dst, const struct sss_sudo_attr *src)
132 debug_decl(sudo_sss_attrcpy, SUDO_DEBUG_SSSD)
134 sudo_debug_printf(SUDO_DEBUG_DEBUG, "dst=%p, src=%p", dst, src);
135 sudo_debug_printf(SUDO_DEBUG_INFO, "emalloc: cnt=%d", src->num_values);
137 dst->name = estrdup(src->name);
138 dst->num_values = src->num_values;
139 dst->values = emalloc2(dst->num_values, sizeof(char *));
141 for (i = 0; i < dst->num_values; ++i)
142 dst->values[i] = estrdup(src->values[i]);
148 sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
151 debug_decl(sudo_sss_rulecpy, SUDO_DEBUG_SSSD)
153 sudo_debug_printf(SUDO_DEBUG_DEBUG, "dst=%p, src=%p", dst, src);
154 sudo_debug_printf(SUDO_DEBUG_INFO, "emalloc: cnt=%d", src->num_attrs);
156 dst->num_attrs = src->num_attrs;
157 dst->attrs = emalloc2(dst->num_attrs, sizeof(struct sss_sudo_attr));
159 for (i = 0; i < dst->num_attrs; ++i)
160 sudo_sss_attrcpy(dst->attrs + i, src->attrs + i);
165 #define _SUDO_SSS_FILTER_INCLUDE 0
166 #define _SUDO_SSS_FILTER_EXCLUDE 1
168 #define _SUDO_SSS_STATE_HOSTMATCH 0x01
169 #define _SUDO_SSS_STATE_USERMATCH 0x02
171 static struct sss_sudo_result *
172 sudo_sss_filter_result(struct sudo_sss_handle *handle,
173 struct sss_sudo_result *in_res,
174 int (*filterp)(struct sudo_sss_handle *, struct sss_sudo_rule *, void *),
175 int act, void *filterp_arg)
177 struct sss_sudo_result *out_res;
179 debug_decl(sudo_sss_filter_result, SUDO_DEBUG_SSSD)
181 sudo_debug_printf(SUDO_DEBUG_DEBUG, "in_res=%p, count=%u, act=%s",
182 in_res, in_res->num_rules,
183 act == _SUDO_SSS_FILTER_EXCLUDE ? "EXCLUDE" : "INCLUDE");
186 debug_return_ptr(NULL);
188 sudo_debug_printf(SUDO_DEBUG_DEBUG, "emalloc: cnt=%d", in_res->num_rules);
190 out_res = emalloc(sizeof(struct sss_sudo_result));
191 out_res->rules = in_res->num_rules > 0 ?
192 emalloc2(in_res->num_rules, sizeof(struct sss_sudo_rule)) : NULL;
193 out_res->num_rules = 0;
195 for (i = l = 0; i < in_res->num_rules; ++i) {
196 r = filterp(handle, in_res->rules + i, filterp_arg);
198 if (( r && act == _SUDO_SSS_FILTER_INCLUDE) ||
199 (!r && act == _SUDO_SSS_FILTER_EXCLUDE)) {
200 sudo_debug_printf(SUDO_DEBUG_DEBUG,
201 "COPY (%s): %p[%u] => %p[%u] (= %p)",
202 act == _SUDO_SSS_FILTER_EXCLUDE ? "not excluded" : "included",
203 in_res->rules, i, out_res->rules, l, in_res->rules + i);
205 sudo_sss_rulecpy(out_res->rules + l, in_res->rules + i);
210 if (l < in_res->num_rules) {
211 sudo_debug_printf(SUDO_DEBUG_DEBUG,
212 "reallocating result: %p (count: %u -> %u)", out_res->rules,
213 in_res->num_rules, l);
216 erealloc3(out_res->rules, l, sizeof(struct sss_sudo_rule));
218 efree(out_res->rules);
219 out_res->rules = NULL;
223 out_res->num_rules = l;
225 debug_return_ptr(out_res);
228 struct sudo_nss sudo_nss_sss = {
236 sudo_sss_display_cmnd,
237 sudo_sss_display_defaults,
238 sudo_sss_display_bound_defaults,
239 sudo_sss_display_privs
242 /* sudo_nss implementation */
244 static int sudo_sss_open(struct sudo_nss *nss)
246 struct sudo_sss_handle *handle;
247 static const char path[] = _PATH_SSSD_LIB"/libsss_sudo.so";
248 debug_decl(sudo_sss_open, SUDO_DEBUG_SSSD);
250 /* Create a handle container. */
251 handle = emalloc(sizeof(struct sudo_sss_handle));
254 handle->ssslib = dlopen(path, RTLD_LAZY);
255 if (handle->ssslib == NULL) {
256 warningx(_("unable to dlopen %s: %s"), path, dlerror());
257 warningx(_("unable to initialize SSS source. Is SSSD installed on your machine?"));
258 debug_return_int(EFAULT);
261 handle->fn_send_recv = dlsym(handle->ssslib, "sss_sudo_send_recv");
262 if (handle->fn_send_recv == NULL) {
263 warningx(_("unable to find symbol \"%s\" in %s"), path,
264 "sss_sudo_send_recv");
265 debug_return_int(EFAULT);
268 handle->fn_send_recv_defaults =
269 dlsym(handle->ssslib, "sss_sudo_send_recv_defaults");
270 if (handle->fn_send_recv_defaults == NULL) {
271 warningx(_("unable to find symbol \"%s\" in %s"), path,
272 "sss_sudo_send_recv_defaults");
273 debug_return_int(EFAULT);
276 handle->fn_free_result = dlsym(handle->ssslib, "sss_sudo_free_result");
277 if (handle->fn_free_result == NULL) {
278 warningx(_("unable to find symbol \"%s\" in %s"), path,
279 "sss_sudo_free_result");
280 debug_return_int(EFAULT);
283 handle->fn_get_values = dlsym(handle->ssslib, "sss_sudo_get_values");
284 if (handle->fn_get_values == NULL) {
285 warningx(_("unable to find symbol \"%s\" in %s"), path,
286 "sss_sudo_get_values");
287 debug_return_int(EFAULT);
290 handle->fn_free_values = dlsym(handle->ssslib, "sss_sudo_free_values");
291 if (handle->fn_free_values == NULL) {
292 warningx(_("unable to find symbol \"%s\" in %s"), path,
293 "sss_sudo_free_values");
294 debug_return_int(EFAULT);
297 handle->domainname = NULL;
298 handle->pw = sudo_user.pw;
299 nss->handle = handle;
301 sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle);
307 static int sudo_sss_close(struct sudo_nss *nss)
309 struct sudo_sss_handle *handle;
310 debug_decl(sudo_sss_close, SUDO_DEBUG_SSSD);
312 if (nss && nss->handle) {
313 handle = nss->handle;
314 dlclose(handle->ssslib);
322 static int sudo_sss_parse(struct sudo_nss *nss)
324 debug_decl(sudo_sss_parse, SUDO_DEBUG_SSSD);
328 static int sudo_sss_setdefs(struct sudo_nss *nss)
330 struct sudo_sss_handle *handle = nss->handle;
332 struct sss_sudo_result *sss_result;
333 struct sss_sudo_rule *sss_rule;
336 debug_decl(sudo_sss_setdefs, SUDO_DEBUG_SSSD);
339 debug_return_int(-1);
341 sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
343 if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
344 &sss_error, &handle->domainname,
346 sudo_debug_printf(SUDO_DEBUG_INFO,
347 "handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
348 debug_return_int(-1);
351 if (sss_error == ENOENT) {
352 sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
354 } else if(sss_error != 0) {
355 sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
356 debug_return_int(-1);
359 for (i = 0; i < sss_result->num_rules; ++i) {
360 sudo_debug_printf(SUDO_DEBUG_DIAG,
361 "Parsing cn=defaults, %d/%d", i, sss_result->num_rules);
362 sss_rule = sss_result->rules + i;
363 sudo_sss_parse_options(handle, sss_rule);
366 handle->fn_free_result(sss_result);
370 static int sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
372 struct sudo_sss_handle *handle = nss->handle;
373 debug_decl(sudo_sss_checkpw, SUDO_DEBUG_SSSD);
375 if (pw->pw_name != handle->pw->pw_name ||
376 pw->pw_uid != handle->pw->pw_uid) {
377 sudo_debug_printf(SUDO_DEBUG_DIAG,
378 "Requested name or uid don't match the initial once, reinitializing...");
381 if (sudo_sss_setdefs(nss) != 0)
382 debug_return_int(-1);
389 sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule)
391 char **val_array = NULL;
394 debug_decl(sudo_sss_check_runas_user, SUDO_DEBUG_SSSD);
397 debug_return_int(UNSPEC);
399 /* get the runas user from the entry */
400 switch (handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array)) {
404 sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs)");
407 switch (handle->fn_get_values(sss_rule, "sudoRunAs", &val_array)) {
411 sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Matching against runas_default");
413 * If there are no runas entries, match runas_default against
414 * what the user specified on the command line.
416 return !strcasecmp(runas_pw->pw_name, def_runas_default);
418 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
419 debug_return_int(UNSPEC);
423 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
424 debug_return_int(UNSPEC);
430 * if runas is not specified on the command line, the only information
431 * as to which user to run as is in the runas_default option. We should
432 * check to see if we have the local option present. Unfortunately we
433 * don't parse these options until after this routine says yes or no.
434 * The query has already returned, so we could peek at the attribute
435 * values here though.
437 * For now just require users to always use -u option unless its set
438 * in the global defaults. This behaviour is no different than the global
441 * Sigh - maybe add this feature later
444 /* walk through values returned, looking for a match */
445 for (i = 0; val_array[i] != NULL && !ret; ++i) {
448 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
452 sudo_debug_printf(SUDO_DEBUG_DEBUG, "netgr_");
453 if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) {
454 sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
459 sudo_debug_printf(SUDO_DEBUG_DEBUG, "usergr_");
460 if (usergr_matches(val, runas_pw->pw_name, runas_pw)) {
461 sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
466 if (strcmp(val, "ALL") == 0) {
467 sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
472 sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
474 if (userpw_matches(val, runas_pw->pw_name, runas_pw)) {
475 sudo_debug_printf(SUDO_DEBUG_DEBUG,
476 "%s == %s (pw_name) => match", val, runas_pw->pw_name);
482 sudo_debug_printf(SUDO_DEBUG_INFO,
483 "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
486 handle->fn_free_values(val_array); /* cleanup */
488 debug_return_int(ret);
492 sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
494 char **val_array = NULL;
497 debug_decl(sudo_sss_check_runas_group, SUDO_DEBUG_SSSD);
499 /* runas_gr is only set if the user specified the -g flag */
501 debug_return_int(UNSPEC);
503 /* get the values from the entry */
504 switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
508 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
509 debug_return_int(false);
511 sudo_debug_printf(SUDO_DEBUG_INFO,
512 "handle->fn_get_values(sudoRunAsGroup): != 0");
513 debug_return_int(UNSPEC);
516 /* walk through values returned, looking for a match */
517 for (i = 0; val_array[i] != NULL; ++i) {
519 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
521 if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
524 sudo_debug_printf(SUDO_DEBUG_INFO,
525 "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
528 handle->fn_free_values(val_array);
530 debug_return_int(ret);
534 * Walk through search results and return true if we have a runas match,
535 * else false. RunAs info is optional.
538 sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
541 debug_decl(sudo_sss_check_runas, SUDO_DEBUG_SSSD);
544 debug_return_int(false);
546 ret = sudo_sss_check_runas_user(handle, rule) != false &&
547 sudo_sss_check_runas_group(handle, rule) != false;
549 debug_return_int(ret);
553 sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
555 char **val_array, *val;
557 debug_decl(sudo_sss_check_host, SUDO_DEBUG_SSSD);
560 debug_return_int(ret);
562 /* get the values from the rule */
563 switch (handle->fn_get_values(rule, "sudoHost", &val_array))
568 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
569 debug_return_int(false);
571 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoHost): != 0");
572 debug_return_int(ret);
575 /* walk through values */
576 for (i = 0; val_array[i] != NULL; ++i) {
578 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
580 /* match any or address or netgroup or hostname */
581 if (!strcmp(val, "ALL") || addr_matches(val) ||
582 netgr_matches(val, user_host, user_shost, NULL) ||
583 hostname_matches(user_shost, user_host, val))
586 sudo_debug_printf(SUDO_DEBUG_INFO,
587 "sssd/ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
590 handle->fn_free_values(val_array);
592 debug_return_int(ret);
596 sudo_sss_result_filterp(struct sudo_sss_handle *handle,
597 struct sss_sudo_rule *rule, void *unused)
600 debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_SSSD);
602 if (sudo_sss_check_host(handle, rule))
608 static struct sss_sudo_result *
609 sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
611 struct sudo_sss_handle *handle = nss->handle;
612 struct sss_sudo_result *u_sss_result, *f_sss_result;
613 uint32_t sss_error = 0, ret;
614 debug_decl(sudo_sss_result_get, SUDO_DEBUG_SSSD);
616 if (sudo_sss_checkpw(nss, pw) != 0)
617 debug_return_ptr(NULL);
619 sudo_debug_printf(SUDO_DEBUG_DIAG, " username=%s", handle->pw->pw_name);
620 sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s", handle->domainname);
622 u_sss_result = f_sss_result = NULL;
624 ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
625 handle->domainname, &sss_error, &u_sss_result);
631 if (u_sss_result != NULL) {
633 sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
634 *state |= _SUDO_SSS_STATE_USERMATCH;
636 sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
637 u_sss_result->num_rules);
639 sudo_debug_printf(SUDO_DEBUG_INFO,
640 "Internal error: u_sss_result == NULL && sss_error == 0");
641 debug_return_ptr(NULL);
645 sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
647 sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
648 debug_return_ptr(NULL);
652 sudo_debug_printf(SUDO_DEBUG_INFO,
653 "handle->fn_send_recv: != 0: ret=%d", ret);
654 debug_return_ptr(NULL);
657 f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
658 sudo_sss_result_filterp, _SUDO_SSS_FILTER_INCLUDE, NULL);
660 if (f_sss_result != NULL) {
661 if (f_sss_result->num_rules > 0) {
663 sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
664 *state |= _SUDO_SSS_STATE_HOSTMATCH;
669 sudo_debug_printf(SUDO_DEBUG_DEBUG,
670 "u_sss_result=(%p, %u) => f_sss_result=(%p, %u)", u_sss_result,
671 u_sss_result->num_rules, f_sss_result, f_sss_result->num_rules);
673 handle->fn_free_result(u_sss_result);
675 debug_return_ptr(f_sss_result);
679 * Search for boolean "option" in sudoOption.
680 * Returns true if found and allowed, false if negated, else UNSPEC.
683 sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
686 char ch, *var, **val_array = NULL;
688 debug_decl(sudo_sss_check_bool, SUDO_DEBUG_SSSD);
691 debug_return_int(ret);
693 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
697 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
698 debug_return_int(ret);
700 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
701 debug_return_int(ret);
704 /* walk through options */
705 for (i = 0; val_array[i] != NULL; ++i) {
707 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
709 if ((ch = *var) == '!')
711 if (strcmp(var, option) == 0)
715 handle->fn_free_values(val_array);
717 debug_return_int(ret);
721 * If a digest prefix is present, fills in struct sudo_digest
722 * and returns a pointer to it, updating cmnd to point to the
723 * command after the digest.
725 static struct sudo_digest *
726 sudo_sss_extract_digest(char **cmnd, struct sudo_digest *digest)
728 char *ep, *cp = *cmnd;
729 int digest_type = SUDO_DIGEST_INVALID;
730 debug_decl(sudo_sss_check_command, SUDO_DEBUG_LDAP)
733 * Check for and extract a digest prefix, e.g.
734 * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
736 if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
739 if (cp[4] == '2' && cp[5] == '4')
740 digest_type = SUDO_DIGEST_SHA224;
741 else if (cp[4] == '5' && cp[5] == '6')
742 digest_type = SUDO_DIGEST_SHA256;
745 if (cp[4] == '8' && cp[5] == '4')
746 digest_type = SUDO_DIGEST_SHA384;
749 if (cp[4] == '1' && cp[5] == '2')
750 digest_type = SUDO_DIGEST_SHA512;
753 if (digest_type != SUDO_DIGEST_INVALID) {
755 while (isblank((unsigned char)*cp))
759 while (isblank((unsigned char)*cp))
762 while (*ep != '\0' && !isblank((unsigned char)*ep))
765 digest->digest_type = digest_type;
766 digest->digest_str = estrndup(cp, (size_t)(ep - cp));
768 while (isblank((unsigned char)*cp))
771 sudo_debug_printf(SUDO_DEBUG_INFO,
772 "%s digest %s for %s",
773 digest_type == SUDO_DIGEST_SHA224 ? "sha224" :
774 digest_type == SUDO_DIGEST_SHA256 ? "sha256" :
775 digest_type == SUDO_DIGEST_SHA384 ? "sha384" :
776 "sha512", digest->digest_str, cp);
777 debug_return_ptr(digest);
782 debug_return_ptr(NULL);
786 * Walk through search results and return true if we have a command match,
787 * false if disallowed and UNSPEC if not matched.
790 sudo_sss_check_command(struct sudo_sss_handle *handle,
791 struct sss_sudo_rule *rule, int *setenv_implied)
793 char **val_array = NULL, *val;
794 char *allowed_cmnd, *allowed_args;
795 int i, foundbang, ret = UNSPEC;
796 struct sudo_digest digest, *allowed_digest = NULL;
797 debug_decl(sudo_sss_check_command, SUDO_DEBUG_SSSD);
800 debug_return_int(ret);
802 switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
806 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
807 debug_return_int(ret);
809 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
810 debug_return_int(ret);
813 for (i = 0; val_array[i] != NULL && ret != false; ++i) {
816 sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
818 /* Match against ALL ? */
819 if (!strcmp(val, "ALL")) {
821 if (setenv_implied != NULL)
822 *setenv_implied = true;
823 sudo_debug_printf(SUDO_DEBUG_INFO,
824 "sssd/ldap sudoCommand '%s' ... MATCH!", val);
828 /* check for sha-2 digest */
829 allowed_digest = sudo_ldap_extract_digest(&val, &digest);
831 /* check for !command */
834 allowed_cmnd = estrdup(1 + val); /* !command */
837 allowed_cmnd = estrdup(val); /* command */
840 /* split optional args away from command */
841 allowed_args = strchr(allowed_cmnd, ' ');
843 *allowed_args++ = '\0';
845 /* check the command like normal */
846 if (command_matches(allowed_cmnd, allowed_args, NULL)) {
848 * If allowed (no bang) set ret but keep on checking.
849 * If disallowed (bang), exit loop.
851 ret = foundbang ? false : true;
854 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
855 val, ret == true ? "MATCH!" : "not");
856 efree(allowed_cmnd); /* cleanup */
859 handle->fn_free_values(val_array); /* more cleanup */
861 debug_return_int(ret);
865 sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
869 char **val_array = NULL;
870 debug_decl(sudo_sss_parse_options, SUDO_DEBUG_SSSD);
875 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
879 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
882 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
886 /* walk through options */
887 for (i = 0; val_array[i] != NULL; i++) {
888 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'",
890 v = estrdup(val_array[i]);
892 /* check for equals sign past first char */
893 val = strchr(v, '=');
895 *val++ = '\0'; /* split on = and truncate var */
896 op = *(val - 2); /* peek for += or -= cases */
897 if (op == '+' || op == '-') {
898 *(val - 2) = '\0'; /* found, remove extra char */
899 /* case var+=val or var-=val */
900 set_default(v, val, (int) op);
903 set_default(v, val, true);
905 } else if (*v == '!') {
906 /* case !var Boolean False */
907 set_default(v + 1, NULL, false);
909 /* case var Boolean True */
910 set_default(v, NULL, true);
915 handle->fn_free_values(val_array);
920 sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
922 int rc, setenv_implied;
924 struct sudo_sss_handle *handle = nss->handle;
925 struct sss_sudo_result *sss_result = NULL;
926 struct sss_sudo_rule *rule;
927 uint32_t i, state = 0;
928 debug_decl(sudo_sss_lookup, SUDO_DEBUG_SSSD);
930 /* Fetch list of sudoRole entries that match user and host. */
931 sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
934 * The following queries are only determine whether or not a
935 * password is required, so the order of the entries doesn't matter.
939 int matched = UNSPEC;
940 enum def_tuple pwcheck =
941 (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
943 sudo_debug_printf(SUDO_DEBUG_INFO, "perform search for pwflag %d", pwflag);
944 if (sss_result != NULL) {
945 for (i = 0; i < sss_result->num_rules; i++) {
946 rule = sss_result->rules + i;
947 if ((pwcheck == any && doauth != false) ||
948 (pwcheck == all && doauth == false)) {
949 doauth = sudo_sss_check_bool(handle, rule, "authenticate");
951 /* Only check the command when listing another user. */
952 if (user_uid == 0 || list_pw == NULL ||
953 user_uid == list_pw->pw_uid ||
954 sudo_sss_check_command(handle, rule, NULL)) {
960 if (matched || user_uid == 0) {
961 SET(ret, VALIDATE_OK);
962 CLR(ret, VALIDATE_NOT_OK);
963 if (def_authenticate) {
966 SET(ret, FLAG_CHECK_USER);
971 def_authenticate = false;
974 def_authenticate = false;
984 sudo_debug_printf(SUDO_DEBUG_DIAG,
985 "searching SSSD/LDAP for sudoers entries");
987 setenv_implied = false;
988 if (sss_result != NULL) {
989 for (i = 0; i < sss_result->num_rules; i++) {
990 rule = sss_result->rules + i;
991 if (!sudo_sss_check_runas(handle, rule))
993 rc = sudo_sss_check_command(handle, rule, &setenv_implied);
995 /* We have a match. */
996 sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
997 rc == true ? "" : "NOT ");
999 sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
1000 /* Apply entry-specific options. */
1003 sudo_sss_parse_options(handle, rule);
1005 /* Set role and type if not specified on command line. */
1006 if (user_role == NULL)
1007 user_role = def_role;
1008 if (user_type == NULL)
1009 user_type = def_type;
1010 #endif /* HAVE_SELINUX */
1011 SET(ret, VALIDATE_OK);
1012 CLR(ret, VALIDATE_NOT_OK);
1014 SET(ret, VALIDATE_NOT_OK);
1015 CLR(ret, VALIDATE_OK);
1022 sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
1024 if (!ISSET(ret, VALIDATE_OK)) {
1025 /* No matching entries. */
1026 if (pwflag && list_pw == NULL)
1027 SET(ret, FLAG_NO_CHECK);
1030 if (state & _SUDO_SSS_STATE_USERMATCH)
1031 CLR(ret, FLAG_NO_USER);
1032 if (state & _SUDO_SSS_STATE_HOSTMATCH)
1033 CLR(ret, FLAG_NO_HOST);
1035 sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
1038 debug_return_int(ret);
1042 sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
1044 struct sudo_sss_handle *handle = nss->handle;
1045 struct sss_sudo_result *sss_result = NULL;
1046 struct sss_sudo_rule *rule;
1047 int i, found = false;
1048 debug_decl(sudo_sss_display_cmnd, SUDO_DEBUG_SSSD);
1053 if (sudo_sss_checkpw(nss, pw) != 0)
1054 debug_return_int(-1);
1057 * The sudo_sss_result_get() function returns all nodes that match
1058 * the user and the host.
1060 sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
1061 sss_result = sudo_sss_result_get(nss, pw, NULL);
1063 if (sss_result == NULL)
1066 for (i = 0; i < sss_result->num_rules; i++) {
1067 rule = sss_result->rules + i;
1068 if (sudo_sss_check_command(handle, rule, NULL) &&
1069 sudo_sss_check_runas(handle, rule)) {
1077 printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1078 user_args ? " " : "", user_args ? user_args : "");
1080 if (sss_result != NULL)
1081 handle->fn_free_result(sss_result);
1083 debug_return_int(!found);
1087 sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1090 struct sudo_sss_handle *handle = nss->handle;
1092 struct sss_sudo_rule *rule;
1093 struct sss_sudo_result *sss_result = NULL;
1095 uint32_t sss_error = 0;
1097 char *prefix, *val, **val_array = NULL;
1098 int count = 0, i, j;
1100 debug_decl(sudo_sss_display_defaults, SUDO_DEBUG_SSSD);
1105 if (handle->fn_send_recv_defaults(pw->pw_uid, pw->pw_name,
1106 &sss_error, &handle->domainname,
1107 &sss_result) != 0) {
1108 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_send_recv_defaults: !=0, sss_error=%u", sss_error);
1112 if (sss_error == ENOENT) {
1113 sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
1115 } else if(sss_error != 0) {
1116 sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
1122 for (i = 0; i < sss_result->num_rules; ++i) {
1123 rule = sss_result->rules + i;
1125 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1129 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1132 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
1136 if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1141 for (j = 0; val_array[j] != NULL; ++j) {
1143 lbuf_append(lbuf, "%s%s", prefix, val);
1148 handle->fn_free_values(val_array);
1152 handle->fn_free_result(sss_result);
1154 debug_return_int(count);
1159 sudo_sss_display_bound_defaults(struct sudo_nss *nss,
1160 struct passwd *pw, struct lbuf *lbuf)
1162 debug_decl(sudo_sss_display_bound_defaults, SUDO_DEBUG_SSSD);
1163 debug_return_int(0);
1167 sudo_sss_display_entry_long(struct sudo_sss_handle *handle,
1168 struct sss_sudo_rule *rule, struct lbuf *lbuf)
1170 char **val_array = NULL;
1172 debug_decl(sudo_sss_display_entry_long, SUDO_DEBUG_SSSD);
1174 /* get the RunAsUser Values from the entry */
1175 lbuf_append(lbuf, " RunAsUsers: ");
1176 switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1178 for (i = 0; val_array[i] != NULL; ++i)
1179 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1180 handle->fn_free_values(val_array);
1183 switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1185 for (i = 0; val_array[i] != NULL; ++i)
1186 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1187 handle->fn_free_values(val_array);
1190 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1191 lbuf_append(lbuf, "%s", def_runas_default);
1194 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
1195 debug_return_int(count);
1199 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
1200 debug_return_int(count);
1202 lbuf_append(lbuf, "\n");
1204 /* get the RunAsGroup Values from the entry */
1205 switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1207 lbuf_append(lbuf, " RunAsGroups: ");
1208 for (i = 0; val_array[i] != NULL; ++i)
1209 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1210 handle->fn_free_values(val_array);
1211 lbuf_append(lbuf, "\n");
1214 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1217 sudo_debug_printf(SUDO_DEBUG_INFO,
1218 "handle->fn_get_values(sudoRunAsGroup): != 0");
1219 debug_return_int(count);
1222 /* get the Option Values from the entry */
1223 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1225 lbuf_append(lbuf, " Options: ");
1226 for (i = 0; val_array[i] != NULL; ++i)
1227 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1228 handle->fn_free_values(val_array);
1229 lbuf_append(lbuf, "\n");
1232 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1235 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
1236 debug_return_int(count);
1239 /* Get the command values from the entry. */
1240 switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1242 lbuf_append(lbuf, _(" Commands:\n"));
1243 for (i = 0; val_array[i] != NULL; ++i) {
1244 lbuf_append(lbuf, "\t%s\n", val_array[i]);
1247 handle->fn_free_values(val_array);
1250 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1253 sudo_debug_printf(SUDO_DEBUG_INFO,
1254 "handle->fn_get_values(sudoCommand): != 0");
1255 debug_return_int(count);
1258 debug_return_int(count);
1262 sudo_sss_display_entry_short(struct sudo_sss_handle *handle,
1263 struct sss_sudo_rule *rule, struct lbuf *lbuf)
1265 char **val_array = NULL;
1267 debug_decl(sudo_sss_display_entry_short, SUDO_DEBUG_SSSD);
1269 lbuf_append(lbuf, " (");
1271 /* get the RunAsUser Values from the entry */
1272 switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1274 for (i = 0; val_array[i] != NULL; ++i)
1275 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1276 handle->fn_free_values(val_array);
1279 sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs).");
1281 switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1283 for (i = 0; val_array[i] != NULL; ++i)
1284 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1285 handle->fn_free_values(val_array);
1288 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1289 lbuf_append(lbuf, "%s", def_runas_default);
1292 sudo_debug_printf(SUDO_DEBUG_INFO,
1293 "handle->fn_get_values(sudoRunAs): != 0");
1294 debug_return_int(count);
1298 sudo_debug_printf(SUDO_DEBUG_INFO,
1299 "handle->fn_get_values(sudoRunAsUser): != 0");
1300 debug_return_int(count);
1303 /* get the RunAsGroup Values from the entry */
1304 switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1306 lbuf_append(lbuf, " : ");
1307 for (i = 0; val_array[i] != NULL; ++i)
1308 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1309 handle->fn_free_values(val_array);
1312 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1315 sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsGroup): != 0");
1316 debug_return_int(count);
1319 lbuf_append(lbuf, ") ");
1321 /* get the Option Values from the entry */
1322 switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1324 for (i = 0; val_array[i] != NULL; ++i) {
1325 char *cp = val_array[i];
1328 if (strcmp(cp, "authenticate") == 0)
1329 lbuf_append(lbuf, val_array[i][0] == '!' ?
1330 "NOPASSWD: " : "PASSWD: ");
1331 else if (strcmp(cp, "noexec") == 0)
1332 lbuf_append(lbuf, val_array[i][0] == '!' ?
1333 "EXEC: " : "NOEXEC: ");
1334 else if (strcmp(cp, "setenv") == 0)
1335 lbuf_append(lbuf, val_array[i][0] == '!' ?
1336 "NOSETENV: " : "SETENV: ");
1338 handle->fn_free_values(val_array);
1341 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1344 sudo_debug_printf(SUDO_DEBUG_INFO,
1345 "handle->fn_get_values(sudoOption): != 0");
1346 debug_return_int(count);
1349 /* get the Command Values from the entry */
1350 switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1352 for (i = 0; val_array[i] != NULL; ++i) {
1353 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1356 handle->fn_free_values(val_array);
1359 sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1362 sudo_debug_printf(SUDO_DEBUG_INFO,
1363 "handle->fn_get_values(sudoCommand): != 0");
1364 debug_return_int(count);
1366 lbuf_append(lbuf, "\n");
1368 debug_return_int(count);
1372 sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
1375 struct sudo_sss_handle *handle = nss->handle;
1377 struct sss_sudo_result *sss_result = NULL;
1378 struct sss_sudo_rule *rule;
1379 unsigned int i, count = 0;
1380 debug_decl(sudo_sss_display_privs, SUDO_DEBUG_SSSD);
1383 debug_return_int(-1);
1384 if (sudo_sss_checkpw(nss, pw) != 0)
1385 debug_return_int(-1);
1387 sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
1389 sss_result = sudo_sss_result_get(nss, pw, NULL);
1391 if (sss_result == NULL)
1392 debug_return_int(count);
1394 /* Display all matching entries. */
1395 for (i = 0; i < sss_result->num_rules; ++i) {
1396 rule = sss_result->rules + i;
1398 count += sudo_sss_display_entry_long(handle, rule, lbuf);
1400 count += sudo_sss_display_entry_short(handle, rule, lbuf);
1403 if (sss_result != NULL)
1404 handle->fn_free_result(sss_result);
1406 debug_return_int(count);