95a4776d522dfc3252d859343dfcaa97f155ba3a
[debian/sudo] / plugins / sudoers / sssd.c
1 /*
2  * Copyright (c) 2003-2012 Todd C. Miller <Todd.Miller@courtesan.com>
3  * Copyright (c) 2011 Daniel Kopecek <dkopecek@redhat.com>
4  *
5  * This code is derived from software contributed by Aaron Spangler.
6  *
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.
10  *
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.
18  */
19
20 #include <config.h>
21
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/param.h>
25 #include <sys/stat.h>
26 #include <stdio.h>
27 #ifdef STDC_HEADERS
28 # include <stdlib.h>
29 # include <stddef.h>
30 #else
31 # ifdef HAVE_STDLIB_H
32 #  include <stdlib.h>
33 # endif
34 #endif /* STDC_HEADERS */
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif /* HAVE_STRING_H */
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif /* HAVE_STRINGS_H */
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44 #if TIME_WITH_SYS_TIME
45 # include <time.h>
46 #endif
47 #ifdef HAVE_DLOPEN
48 # include <dlfcn.h>
49 #else
50 # include "compat/dlfcn.h"
51 #endif
52 #include <ctype.h>
53 #include <pwd.h>
54 #include <grp.h>
55
56 #include <errno.h>
57 #include <stdint.h>
58
59 #include "sudoers.h"
60 #include "parse.h"
61 #include "lbuf.h"
62 #include "sudo_debug.h"
63
64 /* SSSD <--> SUDO interface - do not change */
65 struct sss_sudo_attr {
66     char *name;
67     char **values;
68     unsigned int num_values;
69 };
70
71 struct sss_sudo_rule {
72     unsigned int num_attrs;
73     struct sss_sudo_attr *attrs;
74 };
75
76 struct sss_sudo_result {
77     unsigned int num_rules;
78     struct sss_sudo_rule *rules;
79 };
80
81 typedef int  (*sss_sudo_send_recv_t)(uid_t, const char*, const char*,
82                                      uint32_t*, struct sss_sudo_result**);
83
84 typedef int  (*sss_sudo_send_recv_defaults_t)(uid_t, const char*, uint32_t*,
85                                               char**, struct sss_sudo_result**);
86
87 typedef void (*sss_sudo_free_result_t)(struct sss_sudo_result*);
88
89 typedef int  (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*,
90                                       char***);
91
92 typedef void (*sss_sudo_free_values_t)(char**);
93
94 /* sudo_nss implementation */
95
96 struct sudo_sss_handle {
97     char *domainname;
98     struct passwd *pw;
99     void *ssslib;
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;
105 };
106
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,
116                                      struct lbuf *lbuf);
117
118 static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
119                                            struct passwd *pw, struct lbuf *lbuf);
120
121 static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
122                                   struct lbuf *lbuf);
123
124
125 static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
126                                                    struct passwd *pw,
127                                                    uint32_t *state);
128
129 static void
130 sudo_sss_attrcpy(struct sss_sudo_attr *dst, const struct sss_sudo_attr *src)
131 {
132      int i;
133      debug_decl(sudo_sss_attrcpy, SUDO_DEBUG_SSSD)
134
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);
137
138      dst->name = estrdup(src->name);
139      dst->num_values = src->num_values;
140      dst->values = emalloc2(dst->num_values, sizeof(char *));
141
142      for (i = 0; i < dst->num_values; ++i)
143           dst->values[i] = estrdup(src->values[i]);
144
145      debug_return;
146 }
147
148 static void
149 sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
150 {
151      int i;
152      debug_decl(sudo_sss_rulecpy, SUDO_DEBUG_SSSD)
153
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);
156
157      dst->num_attrs = src->num_attrs;
158      dst->attrs = emalloc2(dst->num_attrs, sizeof(struct sss_sudo_attr));
159
160      for (i = 0; i < dst->num_attrs; ++i)
161           sudo_sss_attrcpy(dst->attrs + i, src->attrs + i);
162
163      debug_return;
164 }
165
166 #define _SUDO_SSS_FILTER_INCLUDE 0
167 #define _SUDO_SSS_FILTER_EXCLUDE 1
168
169 #define _SUDO_SSS_STATE_HOSTMATCH 0x01
170 #define _SUDO_SSS_STATE_USERMATCH 0x02
171
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)
177 {
178     struct sss_sudo_result *out_res;
179     int i, l, r;
180     debug_decl(sudo_sss_filter_result, SUDO_DEBUG_SSSD)
181
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");
185
186     if (in_res == NULL)
187         debug_return_ptr(NULL);
188
189     sudo_debug_printf(SUDO_DEBUG_DEBUG, "emalloc: cnt=%d", in_res->num_rules);
190
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;
195
196     for (i = l = 0; i < in_res->num_rules; ++i) {
197          r = filterp(handle, in_res->rules + i, filterp_arg);
198
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);
205
206             sudo_sss_rulecpy(out_res->rules + l, in_res->rules + i);
207             ++l;
208         }
209     }
210
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));
216     }
217
218     out_res->num_rules = l;
219
220     debug_return_ptr(out_res);
221 }
222
223 struct sudo_nss sudo_nss_sss = {
224     &sudo_nss_sss,
225     NULL,
226     sudo_sss_open,
227     sudo_sss_close,
228     sudo_sss_parse,
229     sudo_sss_setdefs,
230     sudo_sss_lookup,
231     sudo_sss_display_cmnd,
232     sudo_sss_display_defaults,
233     sudo_sss_display_bound_defaults,
234     sudo_sss_display_privs
235 };
236
237 /* sudo_nss implementation */
238 // ok
239 static int sudo_sss_open(struct sudo_nss *nss)
240 {
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);
244
245     /* Create a handle container. */
246     handle = emalloc(sizeof(struct sudo_sss_handle));
247
248     /* Load symbols */
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);
254     }
255
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);
261     }
262
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);
269     }
270
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);
276     }
277
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);
283     }
284
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);
290     }
291
292     handle->domainname = NULL;
293     handle->pw = sudo_user.pw;
294     nss->handle = handle;
295
296     sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle);
297
298     debug_return_int(0);
299 }
300
301 // ok
302 static int sudo_sss_close(struct sudo_nss *nss)
303 {
304     struct sudo_sss_handle *handle;
305     debug_decl(sudo_sss_close, SUDO_DEBUG_SSSD);
306
307     if (nss && nss->handle) {
308         handle = nss->handle;
309         dlclose(handle->ssslib);
310     }
311
312     efree(nss->handle);
313     debug_return_int(0);
314 }
315
316 // ok
317 static int sudo_sss_parse(struct sudo_nss *nss)
318 {
319     debug_decl(sudo_sss_parse, SUDO_DEBUG_SSSD);
320     debug_return_int(0);
321 }
322
323 static int sudo_sss_setdefs(struct sudo_nss *nss)
324 {
325     struct sudo_sss_handle *handle = nss->handle;
326
327     struct sss_sudo_result *sss_result;
328     struct sss_sudo_rule   *sss_rule;
329     uint32_t sss_error;
330     int i;
331     debug_decl(sudo_sss_setdefs, SUDO_DEBUG_SSSD);
332
333     if (handle == NULL)
334         debug_return_int(-1);
335
336     sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
337
338     if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
339                                       &sss_error, &handle->domainname,
340                                       &sss_result) != 0) {
341         sudo_debug_printf(SUDO_DEBUG_INFO,
342             "handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
343         debug_return_int(-1);
344     }
345
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);
352     }
353
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);
359     }
360
361     handle->fn_free_result(sss_result);
362     debug_return_int(0);
363 }
364
365 static int sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
366 {
367     struct sudo_sss_handle *handle = nss->handle;
368     debug_decl(sudo_sss_checkpw, SUDO_DEBUG_SSSD);
369
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...");
374         handle->pw = pw;
375
376         if (sudo_sss_setdefs(nss) != 0)
377             debug_return_int(-1);
378     }
379
380      debug_return_int(0);
381 }
382
383 static int
384 sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule)
385 {
386     char **val_array = NULL;
387     char *val;
388     int ret = false, i;
389     debug_decl(sudo_sss_check_runas_user, SUDO_DEBUG_SSSD);
390
391     if (!runas_pw)
392         debug_return_int(UNSPEC);
393
394     /* get the runas user from the entry */
395     switch (handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array)) {
396     case 0:
397         break;
398     case ENOENT:
399         sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs)");
400
401         /* try old style */
402         switch (handle->fn_get_values(sss_rule, "sudoRunAs", &val_array)) {
403         case 0:
404             break;
405         case ENOENT:
406             sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Matching against runas_default");
407             /*
408              * If there are no runas entries, match runas_default against
409              * what the user specified on the command line.
410              */
411             return !strcasecmp(runas_pw->pw_name, def_runas_default);
412         default:
413             sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
414             debug_return_int(UNSPEC);
415         }
416         break;
417     default:
418         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
419         debug_return_int(UNSPEC);
420     }
421
422     /*
423      * BUG:
424      *
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.
431      *
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
434      * /etc/sudoers.
435      *
436      * Sigh - maybe add this feature later
437      */
438
439     /* walk through values returned, looking for a match */
440     for (i = 0; val_array[i] != NULL && !ret; ++i) {
441         val = val_array[i];
442
443         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
444
445         switch (val[0]) {
446         case '+':
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");
450                 ret = true;
451             }
452             break;
453         case '%':
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");
457                 ret = true;
458             }
459             break;
460         case 'A':
461             if (strcmp(val, "ALL") == 0) {
462                 sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
463                 ret = true;
464                 break;
465             }
466             /* FALLTHROUGH */
467             sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
468         default:
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);
472                 ret = true;
473             }
474             break;
475         }
476
477         sudo_debug_printf(SUDO_DEBUG_INFO,
478             "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
479     }
480
481     handle->fn_free_values(val_array); /* cleanup */
482
483     debug_return_int(ret);
484 }
485
486 static int
487 sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
488 {
489     char **val_array = NULL;
490     char *val;
491     int ret = false, i;
492     debug_decl(sudo_sss_check_runas_group, SUDO_DEBUG_SSSD);
493
494     /* runas_gr is only set if the user specified the -g flag */
495     if (!runas_gr)
496         debug_return_int(UNSPEC);
497
498     /* get the values from the entry */
499     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
500     case 0:
501         break;
502     case ENOENT:
503         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
504         debug_return_int(false);
505     default:
506         sudo_debug_printf(SUDO_DEBUG_INFO,
507             "handle->fn_get_values(sudoRunAsGroup): != 0");
508         debug_return_int(UNSPEC);
509     }
510
511     /* walk through values returned, looking for a match */
512     for (i = 0; val_array[i] != NULL; ++i) {
513         val = val_array[i];
514         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
515
516         if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
517             ret = true;
518
519         sudo_debug_printf(SUDO_DEBUG_INFO,
520             "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
521     }
522
523     handle->fn_free_values(val_array);
524
525     debug_return_int(ret);
526 }
527
528 /*
529  * Walk through search results and return true if we have a runas match,
530  * else false.  RunAs info is optional.
531  */
532 static int
533 sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
534 {
535     int ret;
536     debug_decl(sudo_sss_check_runas, SUDO_DEBUG_SSSD);
537
538     if (rule == NULL)
539          debug_return_int(false);
540
541     ret = sudo_sss_check_runas_user(handle, rule) != false &&
542          sudo_sss_check_runas_group(handle, rule) != false;
543
544     debug_return_int(ret);
545 }
546
547 static int
548 sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
549 {
550     char **val_array, *val;
551     int ret = false, i;
552     debug_decl(sudo_sss_check_host, SUDO_DEBUG_SSSD);
553
554     if (rule == NULL)
555         debug_return_int(ret);
556
557     /* get the values from the rule */
558     switch (handle->fn_get_values(rule, "sudoHost", &val_array))
559     {
560     case 0:
561         break;
562     case ENOENT:
563         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
564         debug_return_int(false);
565     default:
566         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoHost): != 0");
567         debug_return_int(ret);
568     }
569
570     /* walk through values */
571     for (i = 0; val_array[i] != NULL; ++i) {
572         val = val_array[i];
573         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
574
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))
579             ret = true;
580
581         sudo_debug_printf(SUDO_DEBUG_INFO,
582             "sssd/ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
583     }
584
585     handle->fn_free_values(val_array);
586
587     debug_return_int(ret);
588 }
589
590 static int
591 sudo_sss_result_filterp(struct sudo_sss_handle *handle,
592     struct sss_sudo_rule *rule, void *unused)
593 {
594     (void)unused;
595     debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_SSSD);
596
597     if (sudo_sss_check_host(handle, rule))
598         debug_return_int(1);
599     else
600         debug_return_int(0);
601 }
602
603 static struct sss_sudo_result *
604 sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
605 {
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);
610
611     if (sudo_sss_checkpw(nss, pw) != 0)
612         debug_return_ptr(NULL);
613
614     sudo_debug_printf(SUDO_DEBUG_DIAG, "  username=%s", handle->pw->pw_name);
615     sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s", handle->domainname);
616
617     u_sss_result = f_sss_result = NULL;
618
619     ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
620         handle->domainname, &sss_error, &u_sss_result);
621
622     switch (ret) {
623     case 0:
624         switch (sss_error) {
625         case 0:
626             if (u_sss_result != NULL) {
627                 if (state != NULL) {
628                     sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
629                     *state |= _SUDO_SSS_STATE_USERMATCH;
630                 }
631                 sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
632                     u_sss_result->num_rules);
633             } else {
634                 sudo_debug_printf(SUDO_DEBUG_INFO,
635                     "Internal error: u_sss_result == NULL && sss_error == 0");
636                 debug_return_ptr(NULL);
637             }
638             break;
639         case ENOENT:
640             sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
641         default:
642             sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
643             debug_return_ptr(NULL);
644         }
645         break;
646     default:
647         sudo_debug_printf(SUDO_DEBUG_INFO,
648             "handle->fn_send_recv: != 0: ret=%d", ret);
649         debug_return_ptr(NULL);
650     }
651
652     f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
653         sudo_sss_result_filterp, _SUDO_SSS_FILTER_INCLUDE, NULL);
654
655     if (f_sss_result != NULL) {
656         if (f_sss_result->num_rules > 0) {
657             if (state != NULL) {
658                 sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
659                 *state |= _SUDO_SSS_STATE_HOSTMATCH;
660             }
661         }
662     }
663
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);
667
668     handle->fn_free_result(u_sss_result);
669
670     debug_return_ptr(f_sss_result);
671 }
672
673 /*
674  * Search for boolean "option" in sudoOption.
675  * Returns true if found and allowed, false if negated, else UNSPEC.
676  */
677 static int
678 sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
679     char *option)
680 {
681     char ch, *var, **val_array = NULL;
682     int i, ret = UNSPEC;
683     debug_decl(sudo_sss_check_bool, SUDO_DEBUG_SSSD);
684
685     if (rule == NULL)
686         debug_return_int(ret);
687
688     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
689     case 0:
690         break;
691     case ENOENT:
692         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
693         debug_return_int(ret);
694     default:
695         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
696         debug_return_int(ret);
697     }
698
699     /* walk through options */
700     for (i = 0; val_array[i] != NULL; ++i) {
701         var = val_array[i];
702         sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
703
704         if ((ch = *var) == '!')
705             var++;
706         if (strcmp(var, option) == 0)
707             ret = (ch != '!');
708     }
709
710     handle->fn_free_values(val_array);
711
712     debug_return_int(ret);
713 }
714
715 /*
716  * Walk through search results and return true if we have a command match,
717  * false if disallowed and UNSPEC if not matched.
718  */
719 static int
720 sudo_sss_check_command(struct sudo_sss_handle *handle,
721     struct sss_sudo_rule *rule, int *setenv_implied)
722 {
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);
727
728     if (rule == NULL)
729         debug_return_int(ret);
730
731     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
732     case 0:
733         break;
734     case ENOENT:
735         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
736         debug_return_int(ret);
737     default:
738         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
739         debug_return_int(ret);
740     }
741
742     for (i = 0; val_array[i] != NULL && ret != false; ++i) {
743         val = val_array[i];
744
745         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
746
747         /* Match against ALL ? */
748         if (!strcmp(val, "ALL")) {
749             ret = true;
750             if (setenv_implied != NULL)
751                 *setenv_implied = true;
752             sudo_debug_printf(SUDO_DEBUG_INFO,
753                 "sssd/ldap sudoCommand '%s' ... MATCH!", val);
754             continue;
755         }
756
757         /* check for !command */
758         if (*val == '!') {
759             foundbang = true;
760             allowed_cmnd = estrdup(1 + val);    /* !command */
761         } else {
762             foundbang = false;
763             allowed_cmnd = estrdup(val);        /* command */
764         }
765
766         /* split optional args away from command */
767         allowed_args = strchr(allowed_cmnd, ' ');
768         if (allowed_args)
769             *allowed_args++ = '\0';
770
771         /* check the command like normal */
772         if (command_matches(allowed_cmnd, allowed_args)) {
773             /*
774              * If allowed (no bang) set ret but keep on checking.
775              * If disallowed (bang), exit loop.
776              */
777             ret = foundbang ? false : true;
778         }
779
780         sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
781             val, ret == true ? "MATCH!" : "not");
782         efree(allowed_cmnd);    /* cleanup */
783     }
784
785     handle->fn_free_values(val_array); /* more cleanup */
786
787     debug_return_int(ret);
788 }
789
790 static void
791 sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
792 {
793     int i;
794     char op, *v, *val;
795     char **val_array = NULL;
796     debug_decl(sudo_sss_parse_options, SUDO_DEBUG_SSSD);
797
798     if (rule == NULL)
799         debug_return;
800
801     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
802     case 0:
803         break;
804     case ENOENT:
805         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
806         debug_return;
807     default:
808         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
809         debug_return;
810     }
811
812     /* walk through options */
813     for (i = 0; val_array[i] != NULL; i++) {
814         sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'",
815          val_array[i]);
816         v = estrdup(val_array[i]);
817
818         /* check for equals sign past first char */
819         val = strchr(v, '=');
820         if (val > 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);
827             } else {
828                 /* case var=val */
829                 set_default(v, val, true);
830             }
831         } else if (*v == '!') {
832             /* case !var Boolean False */
833             set_default(v + 1, NULL, false);
834         } else {
835             /* case var Boolean True */
836             set_default(v, NULL, true);
837         }
838         efree(v);
839     }
840
841     handle->fn_free_values(val_array);
842     debug_return;
843 }
844
845 static int
846 sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
847 {
848     int rc, setenv_implied;
849
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);
855
856     /* Fetch list of sudoRole entries that match user and host. */
857     sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
858
859     /*
860      * The following queries are only determine whether or not a
861      * password is required, so the order of the entries doesn't matter.
862      */
863     if (pwflag) {
864         int doauth = UNSPEC;
865         int matched = UNSPEC;
866         enum def_tuple pwcheck =
867             (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
868
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");
876                 }
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)) {
881                     matched = true;
882                     break;
883                 }
884             }
885         }
886         if (matched || user_uid == 0) {
887             SET(ret, VALIDATE_OK);
888             CLR(ret, VALIDATE_NOT_OK);
889             if (def_authenticate) {
890                 switch (pwcheck) {
891                     case always:
892                         SET(ret, FLAG_CHECK_USER);
893                         break;
894                     case all:
895                     case any:
896                         if (doauth == false)
897                             def_authenticate = false;
898                         break;
899                     case never:
900                         def_authenticate = false;
901                         break;
902                     default:
903                         break;
904                 }
905             }
906         }
907         goto done;
908     }
909
910     sudo_debug_printf(SUDO_DEBUG_DIAG,
911         "searching SSSD/LDAP for sudoers entries");
912
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))
918                 continue;
919             rc = sudo_sss_check_command(handle, rule, &setenv_implied);
920             if (rc != UNSPEC) {
921                 /* We have a match. */
922                 sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
923                     rc == true ? "" : "NOT ");
924                 if (rc == true) {
925                     sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
926                     /* Apply entry-specific options. */
927                     if (setenv_implied)
928                         def_setenv = true;
929                     sudo_sss_parse_options(handle, rule);
930 #ifdef HAVE_SELINUX
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);
939                 } else {
940                     SET(ret, VALIDATE_NOT_OK);
941                     CLR(ret, VALIDATE_OK);
942                 }
943                 break;
944             }
945         }
946     }
947 done:
948     sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
949
950     if (!ISSET(ret, VALIDATE_OK)) {
951         /* No matching entries. */
952         if (pwflag && list_pw == NULL)
953             SET(ret, FLAG_NO_CHECK);
954     }
955
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);
960
961     sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
962      pwflag, ret);
963
964     debug_return_int(ret);
965 }
966
967 static int
968 sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
969 {
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);
975
976     if (handle == NULL)
977         goto done;
978
979     if (sudo_sss_checkpw(nss, pw) != 0)
980         debug_return_int(-1);
981
982     /*
983      * The sudo_sss_result_get() function returns all nodes that match
984      * the user and the host.
985      */
986     sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
987     sss_result = sudo_sss_result_get(nss, pw, NULL);
988
989     if (sss_result == NULL)
990         goto done;
991
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)) {
996             found = true;
997             goto done;
998         }
999     }
1000
1001 done:
1002     if (found)
1003         printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1004             user_args ? " " : "", user_args ? user_args : "");
1005
1006     if (sss_result != NULL)
1007         handle->fn_free_result(sss_result);
1008
1009     debug_return_int(!found);
1010 }
1011
1012 static int
1013 sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1014     struct lbuf *lbuf)
1015 {
1016     struct sudo_sss_handle *handle = nss->handle;
1017
1018     struct sss_sudo_rule *rule;
1019     struct sss_sudo_result *sss_result = NULL;
1020
1021     uint32_t sss_error = 0;
1022
1023     char *prefix, *val, **val_array = NULL;
1024     int count = 0, i, j;
1025
1026     debug_decl(sudo_sss_display_defaults, SUDO_DEBUG_SSSD);
1027
1028     if (handle == NULL)
1029         goto done;
1030
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);
1035         goto done;
1036     }
1037
1038     if (sss_error == ENOENT) {
1039         sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
1040         goto done;
1041     } else if(sss_error != 0) {
1042         sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
1043         goto done;
1044     }
1045
1046     handle->pw = pw;
1047
1048     for (i = 0; i < sss_result->num_rules; ++i) {
1049         rule = sss_result->rules + i;
1050
1051         switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1052         case 0:
1053             break;
1054         case ENOENT:
1055             sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1056             continue;
1057         default:
1058             sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
1059             continue;
1060         }
1061
1062         if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1063             prefix = "    ";
1064         else
1065             prefix = ", ";
1066
1067         for (j = 0; val_array[j] != NULL; ++j) {
1068             val = val_array[j];
1069             lbuf_append(lbuf, "%s%s", prefix, val);
1070             prefix = ", ";
1071             count++;
1072         }
1073
1074         handle->fn_free_values(val_array);
1075         val_array = NULL;
1076     }
1077
1078     handle->fn_free_result(sss_result);
1079 done:
1080     debug_return_int(count);
1081 }
1082
1083 // ok
1084 static int
1085 sudo_sss_display_bound_defaults(struct sudo_nss *nss,
1086     struct passwd *pw, struct lbuf *lbuf)
1087 {
1088     debug_decl(sudo_sss_display_bound_defaults, SUDO_DEBUG_SSSD);
1089     debug_return_int(0);
1090 }
1091
1092 static int
1093 sudo_sss_display_entry_long(struct sudo_sss_handle *handle,
1094     struct sss_sudo_rule *rule, struct lbuf *lbuf)
1095 {
1096     char **val_array = NULL;
1097     int count = 0, i;
1098     debug_decl(sudo_sss_display_entry_long, SUDO_DEBUG_SSSD);
1099
1100     /* get the RunAsUser Values from the entry */
1101     lbuf_append(lbuf, "    RunAsUsers: ");
1102     switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1103     case 0:
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);
1107         break;
1108     case ENOENT:
1109         switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1110         case 0:
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);
1114             break;
1115         case ENOENT:
1116             sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1117             lbuf_append(lbuf, "%s", def_runas_default);
1118             break;
1119         default:
1120             sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
1121             debug_return_int(count);
1122         }
1123         break;
1124     default:
1125         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
1126         debug_return_int(count);
1127     }
1128     lbuf_append(lbuf, "\n");
1129
1130     /* get the RunAsGroup Values from the entry */
1131     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1132     case 0:
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");
1138         break;
1139     case ENOENT:
1140         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1141         break;
1142     default:
1143         sudo_debug_printf(SUDO_DEBUG_INFO,
1144             "handle->fn_get_values(sudoRunAsGroup): != 0");
1145         debug_return_int(count);
1146     }
1147
1148     /* get the Option Values from the entry */
1149     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1150     case 0:
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");
1156         break;
1157     case ENOENT:
1158         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1159         break;
1160     default:
1161         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
1162         debug_return_int(count);
1163     }
1164
1165     /* Get the command values from the entry. */
1166     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1167     case 0:
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]);
1171              count++;
1172         }
1173         handle->fn_free_values(val_array);
1174         break;
1175     case ENOENT:
1176         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1177         break;
1178     default:
1179         sudo_debug_printf(SUDO_DEBUG_INFO,
1180             "handle->fn_get_values(sudoCommand): != 0");
1181         debug_return_int(count);
1182     }
1183
1184     debug_return_int(count);
1185 }
1186
1187 static int
1188 sudo_sss_display_entry_short(struct sudo_sss_handle *handle,
1189     struct sss_sudo_rule *rule, struct lbuf *lbuf)
1190 {
1191     char **val_array = NULL;
1192     int count = 0, i;
1193     debug_decl(sudo_sss_display_entry_short, SUDO_DEBUG_SSSD);
1194
1195     lbuf_append(lbuf, "    (");
1196
1197     /* get the RunAsUser Values from the entry */
1198     switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1199     case 0:
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);
1203         break;
1204     case ENOENT:
1205         sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs).");
1206         /* try old style */
1207         switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1208         case 0:
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);
1212             break;
1213         case ENOENT:
1214             sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1215             lbuf_append(lbuf, "%s", def_runas_default);
1216             break;
1217         default:
1218             sudo_debug_printf(SUDO_DEBUG_INFO,
1219                 "handle->fn_get_values(sudoRunAs): != 0");
1220             debug_return_int(count);
1221         }
1222         break;
1223     default:
1224         sudo_debug_printf(SUDO_DEBUG_INFO,
1225             "handle->fn_get_values(sudoRunAsUser): != 0");
1226         debug_return_int(count);
1227     }
1228
1229     /* get the RunAsGroup Values from the entry */
1230     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1231     case 0:
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);
1236         break;
1237     case ENOENT:
1238         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1239         break;
1240     default:
1241         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsGroup): != 0");
1242         debug_return_int(count);
1243     }
1244
1245     lbuf_append(lbuf, ") ");
1246
1247     /* get the Option Values from the entry */
1248     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1249     case 0:
1250         for (i = 0; val_array[i] != NULL; ++i) {
1251             char *cp = val_array[i];
1252             if (*cp == '!')
1253                 cp++;
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: ");
1263         }
1264         handle->fn_free_values(val_array);
1265         break;
1266     case ENOENT:
1267         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1268         break;
1269     default:
1270         sudo_debug_printf(SUDO_DEBUG_INFO,
1271             "handle->fn_get_values(sudoOption): != 0");
1272         debug_return_int(count);
1273     }
1274
1275     /* get the Command Values from the entry */
1276     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1277     case 0:
1278         for (i = 0; val_array[i] != NULL; ++i) {
1279             lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1280             count++;
1281         }
1282         handle->fn_free_values(val_array);
1283         break;
1284     case ENOENT:
1285         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1286         break;
1287     default:
1288         sudo_debug_printf(SUDO_DEBUG_INFO,
1289             "handle->fn_get_values(sudoCommand): != 0");
1290         debug_return_int(count);
1291     }
1292     lbuf_append(lbuf, "\n");
1293
1294     debug_return_int(count);
1295 }
1296
1297 static int
1298 sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
1299     struct lbuf *lbuf)
1300 {
1301     struct sudo_sss_handle *handle = nss->handle;
1302
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);
1307
1308     if (handle == NULL)
1309         debug_return_int(-1);
1310     if (sudo_sss_checkpw(nss, pw) != 0)
1311         debug_return_int(-1);
1312
1313     sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
1314
1315     sss_result = sudo_sss_result_get(nss, pw, NULL);
1316
1317     if (sss_result == NULL)
1318         debug_return_int(count);
1319
1320     /* Display all matching entries. */
1321     for (i = 0; i < sss_result->num_rules; ++i) {
1322         rule = sss_result->rules + i;
1323         if (long_list)
1324             count += sudo_sss_display_entry_long(handle, rule, lbuf);
1325         else
1326             count += sudo_sss_display_entry_short(handle, rule, lbuf);
1327     }
1328
1329     if (sss_result != NULL)
1330         handle->fn_free_result(sss_result);
1331
1332     debug_return_int(count);
1333 }