71a589cc6ba9588f8ea3401a9750e52d28ee0b64
[debian/sudo] / plugins / sudoers / sssd.c
1 /*
2  * Copyright (c) 2003-2013 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/stat.h>
25 #include <stdio.h>
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 # include <stddef.h>
29 #else
30 # ifdef HAVE_STDLIB_H
31 #  include <stdlib.h>
32 # endif
33 #endif /* STDC_HEADERS */
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif /* HAVE_STRING_H */
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif /* HAVE_STRINGS_H */
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 #if TIME_WITH_SYS_TIME
44 # include <time.h>
45 #endif
46 #ifdef HAVE_DLOPEN
47 # include <dlfcn.h>
48 #else
49 # include "compat/dlfcn.h"
50 #endif
51 #include <ctype.h>
52 #include <pwd.h>
53 #include <grp.h>
54
55 #include <errno.h>
56 #include <stdint.h>
57
58 #include "sudoers.h"
59 #include "parse.h"
60 #include "lbuf.h"
61 #include "sudo_debug.h"
62
63 /* SSSD <--> SUDO interface - do not change */
64 struct sss_sudo_attr {
65     char *name;
66     char **values;
67     unsigned int num_values;
68 };
69
70 struct sss_sudo_rule {
71     unsigned int num_attrs;
72     struct sss_sudo_attr *attrs;
73 };
74
75 struct sss_sudo_result {
76     unsigned int num_rules;
77     struct sss_sudo_rule *rules;
78 };
79
80 typedef int  (*sss_sudo_send_recv_t)(uid_t, const char*, const char*,
81                                      uint32_t*, struct sss_sudo_result**);
82
83 typedef int  (*sss_sudo_send_recv_defaults_t)(uid_t, const char*, uint32_t*,
84                                               char**, struct sss_sudo_result**);
85
86 typedef void (*sss_sudo_free_result_t)(struct sss_sudo_result*);
87
88 typedef int  (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*,
89                                       char***);
90
91 typedef void (*sss_sudo_free_values_t)(char**);
92
93 /* sudo_nss implementation */
94
95 struct sudo_sss_handle {
96     char *domainname;
97     struct passwd *pw;
98     void *ssslib;
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;
104 };
105
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,
115                                      struct lbuf *lbuf);
116
117 static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
118                                            struct passwd *pw, struct lbuf *lbuf);
119
120 static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
121                                   struct lbuf *lbuf);
122
123
124 static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
125                                                    struct passwd *pw,
126                                                    uint32_t *state);
127
128 static void
129 sudo_sss_attrcpy(struct sss_sudo_attr *dst, const struct sss_sudo_attr *src)
130 {
131      int i;
132      debug_decl(sudo_sss_attrcpy, SUDO_DEBUG_SSSD)
133
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);
136
137      dst->name = estrdup(src->name);
138      dst->num_values = src->num_values;
139      dst->values = emalloc2(dst->num_values, sizeof(char *));
140
141      for (i = 0; i < dst->num_values; ++i)
142           dst->values[i] = estrdup(src->values[i]);
143
144      debug_return;
145 }
146
147 static void
148 sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
149 {
150      int i;
151      debug_decl(sudo_sss_rulecpy, SUDO_DEBUG_SSSD)
152
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);
155
156      dst->num_attrs = src->num_attrs;
157      dst->attrs = emalloc2(dst->num_attrs, sizeof(struct sss_sudo_attr));
158
159      for (i = 0; i < dst->num_attrs; ++i)
160           sudo_sss_attrcpy(dst->attrs + i, src->attrs + i);
161
162      debug_return;
163 }
164
165 #define _SUDO_SSS_FILTER_INCLUDE 0
166 #define _SUDO_SSS_FILTER_EXCLUDE 1
167
168 #define _SUDO_SSS_STATE_HOSTMATCH 0x01
169 #define _SUDO_SSS_STATE_USERMATCH 0x02
170
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)
176 {
177     struct sss_sudo_result *out_res;
178     int i, l, r;
179     debug_decl(sudo_sss_filter_result, SUDO_DEBUG_SSSD)
180
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");
184
185     if (in_res == NULL)
186         debug_return_ptr(NULL);
187
188     sudo_debug_printf(SUDO_DEBUG_DEBUG, "emalloc: cnt=%d", in_res->num_rules);
189
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;
194
195     for (i = l = 0; i < in_res->num_rules; ++i) {
196          r = filterp(handle, in_res->rules + i, filterp_arg);
197
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);
204
205             sudo_sss_rulecpy(out_res->rules + l, in_res->rules + i);
206             ++l;
207         }
208     }
209
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);
214         if (l > 0) {
215             out_res->rules =
216                 erealloc3(out_res->rules, l, sizeof(struct sss_sudo_rule));
217         } else {
218             efree(out_res->rules);
219             out_res->rules = NULL;
220         }
221     }
222
223     out_res->num_rules = l;
224
225     debug_return_ptr(out_res);
226 }
227
228 struct sudo_nss sudo_nss_sss = {
229     &sudo_nss_sss,
230     NULL,
231     sudo_sss_open,
232     sudo_sss_close,
233     sudo_sss_parse,
234     sudo_sss_setdefs,
235     sudo_sss_lookup,
236     sudo_sss_display_cmnd,
237     sudo_sss_display_defaults,
238     sudo_sss_display_bound_defaults,
239     sudo_sss_display_privs
240 };
241
242 /* sudo_nss implementation */
243 // ok
244 static int sudo_sss_open(struct sudo_nss *nss)
245 {
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);
249
250     /* Create a handle container. */
251     handle = emalloc(sizeof(struct sudo_sss_handle));
252
253     /* Load symbols */
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);
259     }
260
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);
266     }
267
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);
274     }
275
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);
281     }
282
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);
288     }
289
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);
295     }
296
297     handle->domainname = NULL;
298     handle->pw = sudo_user.pw;
299     nss->handle = handle;
300
301     sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle);
302
303     debug_return_int(0);
304 }
305
306 // ok
307 static int sudo_sss_close(struct sudo_nss *nss)
308 {
309     struct sudo_sss_handle *handle;
310     debug_decl(sudo_sss_close, SUDO_DEBUG_SSSD);
311
312     if (nss && nss->handle) {
313         handle = nss->handle;
314         dlclose(handle->ssslib);
315     }
316
317     efree(nss->handle);
318     debug_return_int(0);
319 }
320
321 // ok
322 static int sudo_sss_parse(struct sudo_nss *nss)
323 {
324     debug_decl(sudo_sss_parse, SUDO_DEBUG_SSSD);
325     debug_return_int(0);
326 }
327
328 static int sudo_sss_setdefs(struct sudo_nss *nss)
329 {
330     struct sudo_sss_handle *handle = nss->handle;
331
332     struct sss_sudo_result *sss_result;
333     struct sss_sudo_rule   *sss_rule;
334     uint32_t sss_error;
335     int i;
336     debug_decl(sudo_sss_setdefs, SUDO_DEBUG_SSSD);
337
338     if (handle == NULL)
339         debug_return_int(-1);
340
341     sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
342
343     if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
344                                       &sss_error, &handle->domainname,
345                                       &sss_result) != 0) {
346         sudo_debug_printf(SUDO_DEBUG_INFO,
347             "handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
348         debug_return_int(-1);
349     }
350
351     if (sss_error == ENOENT) {
352         sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
353         debug_return_int(0);
354     } else if(sss_error != 0) {
355         sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
356         debug_return_int(-1);
357     }
358
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);
364     }
365
366     handle->fn_free_result(sss_result);
367     debug_return_int(0);
368 }
369
370 static int sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
371 {
372     struct sudo_sss_handle *handle = nss->handle;
373     debug_decl(sudo_sss_checkpw, SUDO_DEBUG_SSSD);
374
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...");
379         handle->pw = pw;
380
381         if (sudo_sss_setdefs(nss) != 0)
382             debug_return_int(-1);
383     }
384
385      debug_return_int(0);
386 }
387
388 static int
389 sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule)
390 {
391     char **val_array = NULL;
392     char *val;
393     int ret = false, i;
394     debug_decl(sudo_sss_check_runas_user, SUDO_DEBUG_SSSD);
395
396     if (!runas_pw)
397         debug_return_int(UNSPEC);
398
399     /* get the runas user from the entry */
400     switch (handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array)) {
401     case 0:
402         break;
403     case ENOENT:
404         sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs)");
405
406         /* try old style */
407         switch (handle->fn_get_values(sss_rule, "sudoRunAs", &val_array)) {
408         case 0:
409             break;
410         case ENOENT:
411             sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Matching against runas_default");
412             /*
413              * If there are no runas entries, match runas_default against
414              * what the user specified on the command line.
415              */
416             return !strcasecmp(runas_pw->pw_name, def_runas_default);
417         default:
418             sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
419             debug_return_int(UNSPEC);
420         }
421         break;
422     default:
423         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
424         debug_return_int(UNSPEC);
425     }
426
427     /*
428      * BUG:
429      *
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.
436      *
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
439      * /etc/sudoers.
440      *
441      * Sigh - maybe add this feature later
442      */
443
444     /* walk through values returned, looking for a match */
445     for (i = 0; val_array[i] != NULL && !ret; ++i) {
446         val = val_array[i];
447
448         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
449
450         switch (val[0]) {
451         case '+':
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");
455                 ret = true;
456             }
457             break;
458         case '%':
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");
462                 ret = true;
463             }
464             break;
465         case 'A':
466             if (strcmp(val, "ALL") == 0) {
467                 sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
468                 ret = true;
469                 break;
470             }
471             /* FALLTHROUGH */
472             sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
473         default:
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);
477                 ret = true;
478             }
479             break;
480         }
481
482         sudo_debug_printf(SUDO_DEBUG_INFO,
483             "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
484     }
485
486     handle->fn_free_values(val_array); /* cleanup */
487
488     debug_return_int(ret);
489 }
490
491 static int
492 sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
493 {
494     char **val_array = NULL;
495     char *val;
496     int ret = false, i;
497     debug_decl(sudo_sss_check_runas_group, SUDO_DEBUG_SSSD);
498
499     /* runas_gr is only set if the user specified the -g flag */
500     if (!runas_gr)
501         debug_return_int(UNSPEC);
502
503     /* get the values from the entry */
504     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
505     case 0:
506         break;
507     case ENOENT:
508         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
509         debug_return_int(false);
510     default:
511         sudo_debug_printf(SUDO_DEBUG_INFO,
512             "handle->fn_get_values(sudoRunAsGroup): != 0");
513         debug_return_int(UNSPEC);
514     }
515
516     /* walk through values returned, looking for a match */
517     for (i = 0; val_array[i] != NULL; ++i) {
518         val = val_array[i];
519         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
520
521         if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
522             ret = true;
523
524         sudo_debug_printf(SUDO_DEBUG_INFO,
525             "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
526     }
527
528     handle->fn_free_values(val_array);
529
530     debug_return_int(ret);
531 }
532
533 /*
534  * Walk through search results and return true if we have a runas match,
535  * else false.  RunAs info is optional.
536  */
537 static int
538 sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
539 {
540     int ret;
541     debug_decl(sudo_sss_check_runas, SUDO_DEBUG_SSSD);
542
543     if (rule == NULL)
544          debug_return_int(false);
545
546     ret = sudo_sss_check_runas_user(handle, rule) != false &&
547          sudo_sss_check_runas_group(handle, rule) != false;
548
549     debug_return_int(ret);
550 }
551
552 static int
553 sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
554 {
555     char **val_array, *val;
556     int ret = false, i;
557     debug_decl(sudo_sss_check_host, SUDO_DEBUG_SSSD);
558
559     if (rule == NULL)
560         debug_return_int(ret);
561
562     /* get the values from the rule */
563     switch (handle->fn_get_values(rule, "sudoHost", &val_array))
564     {
565     case 0:
566         break;
567     case ENOENT:
568         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
569         debug_return_int(false);
570     default:
571         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoHost): != 0");
572         debug_return_int(ret);
573     }
574
575     /* walk through values */
576     for (i = 0; val_array[i] != NULL; ++i) {
577         val = val_array[i];
578         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
579
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))
584             ret = true;
585
586         sudo_debug_printf(SUDO_DEBUG_INFO,
587             "sssd/ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
588     }
589
590     handle->fn_free_values(val_array);
591
592     debug_return_int(ret);
593 }
594
595 static int
596 sudo_sss_result_filterp(struct sudo_sss_handle *handle,
597     struct sss_sudo_rule *rule, void *unused)
598 {
599     (void)unused;
600     debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_SSSD);
601
602     if (sudo_sss_check_host(handle, rule))
603         debug_return_int(1);
604     else
605         debug_return_int(0);
606 }
607
608 static struct sss_sudo_result *
609 sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
610 {
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);
615
616     if (sudo_sss_checkpw(nss, pw) != 0)
617         debug_return_ptr(NULL);
618
619     sudo_debug_printf(SUDO_DEBUG_DIAG, "  username=%s", handle->pw->pw_name);
620     sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s", handle->domainname);
621
622     u_sss_result = f_sss_result = NULL;
623
624     ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
625         handle->domainname, &sss_error, &u_sss_result);
626
627     switch (ret) {
628     case 0:
629         switch (sss_error) {
630         case 0:
631             if (u_sss_result != NULL) {
632                 if (state != NULL) {
633                     sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
634                     *state |= _SUDO_SSS_STATE_USERMATCH;
635                 }
636                 sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
637                     u_sss_result->num_rules);
638             } else {
639                 sudo_debug_printf(SUDO_DEBUG_INFO,
640                     "Internal error: u_sss_result == NULL && sss_error == 0");
641                 debug_return_ptr(NULL);
642             }
643             break;
644         case ENOENT:
645             sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
646         default:
647             sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
648             debug_return_ptr(NULL);
649         }
650         break;
651     default:
652         sudo_debug_printf(SUDO_DEBUG_INFO,
653             "handle->fn_send_recv: != 0: ret=%d", ret);
654         debug_return_ptr(NULL);
655     }
656
657     f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
658         sudo_sss_result_filterp, _SUDO_SSS_FILTER_INCLUDE, NULL);
659
660     if (f_sss_result != NULL) {
661         if (f_sss_result->num_rules > 0) {
662             if (state != NULL) {
663                 sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
664                 *state |= _SUDO_SSS_STATE_HOSTMATCH;
665             }
666         }
667     }
668
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);
672
673     handle->fn_free_result(u_sss_result);
674
675     debug_return_ptr(f_sss_result);
676 }
677
678 /*
679  * Search for boolean "option" in sudoOption.
680  * Returns true if found and allowed, false if negated, else UNSPEC.
681  */
682 static int
683 sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
684     char *option)
685 {
686     char ch, *var, **val_array = NULL;
687     int i, ret = UNSPEC;
688     debug_decl(sudo_sss_check_bool, SUDO_DEBUG_SSSD);
689
690     if (rule == NULL)
691         debug_return_int(ret);
692
693     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
694     case 0:
695         break;
696     case ENOENT:
697         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
698         debug_return_int(ret);
699     default:
700         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
701         debug_return_int(ret);
702     }
703
704     /* walk through options */
705     for (i = 0; val_array[i] != NULL; ++i) {
706         var = val_array[i];
707         sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
708
709         if ((ch = *var) == '!')
710             var++;
711         if (strcmp(var, option) == 0)
712             ret = (ch != '!');
713     }
714
715     handle->fn_free_values(val_array);
716
717     debug_return_int(ret);
718 }
719
720 /*
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.
724  */
725 static struct sudo_digest *
726 sudo_sss_extract_digest(char **cmnd, struct sudo_digest *digest)
727 {
728     char *ep, *cp = *cmnd;
729     int digest_type = SUDO_DIGEST_INVALID;
730     debug_decl(sudo_sss_check_command, SUDO_DEBUG_LDAP)
731
732     /*
733      * Check for and extract a digest prefix, e.g.
734      * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
735      */
736     if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
737         switch (cp[3]) {
738         case '2':
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;
743             break;
744         case '3':
745             if (cp[4] == '8' && cp[5] == '4')
746                 digest_type = SUDO_DIGEST_SHA384;
747             break;
748         case '5':
749             if (cp[4] == '1' && cp[5] == '2')
750                 digest_type = SUDO_DIGEST_SHA512;
751             break;
752         }
753         if (digest_type != SUDO_DIGEST_INVALID) {
754             cp += 6;
755             while (isblank((unsigned char)*cp))
756                 cp++;
757             if (*cp == ':') {
758                 cp++;
759                 while (isblank((unsigned char)*cp))
760                     cp++;
761                 ep = cp;
762                 while (*ep != '\0' && !isblank((unsigned char)*ep))
763                     ep++;
764                 if (*ep != '\0') {
765                     digest->digest_type = digest_type;
766                     digest->digest_str = estrndup(cp, (size_t)(ep - cp));
767                     cp = ep + 1;
768                     while (isblank((unsigned char)*cp))
769                         cp++;
770                     *cmnd = 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);
778                 }
779             }
780         }
781     }
782     debug_return_ptr(NULL);
783 }
784
785 /*
786  * Walk through search results and return true if we have a command match,
787  * false if disallowed and UNSPEC if not matched.
788  */
789 static int
790 sudo_sss_check_command(struct sudo_sss_handle *handle,
791     struct sss_sudo_rule *rule, int *setenv_implied)
792 {
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);
798
799     if (rule == NULL)
800         debug_return_int(ret);
801
802     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
803     case 0:
804         break;
805     case ENOENT:
806         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
807         debug_return_int(ret);
808     default:
809         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
810         debug_return_int(ret);
811     }
812
813     for (i = 0; val_array[i] != NULL && ret != false; ++i) {
814         val = val_array[i];
815
816         sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
817
818         /* Match against ALL ? */
819         if (!strcmp(val, "ALL")) {
820             ret = true;
821             if (setenv_implied != NULL)
822                 *setenv_implied = true;
823             sudo_debug_printf(SUDO_DEBUG_INFO,
824                 "sssd/ldap sudoCommand '%s' ... MATCH!", val);
825             continue;
826         }
827
828         /* check for sha-2 digest */
829         allowed_digest = sudo_ldap_extract_digest(&val, &digest);
830
831         /* check for !command */
832         if (*val == '!') {
833             foundbang = true;
834             allowed_cmnd = estrdup(1 + val);    /* !command */
835         } else {
836             foundbang = false;
837             allowed_cmnd = estrdup(val);        /* command */
838         }
839
840         /* split optional args away from command */
841         allowed_args = strchr(allowed_cmnd, ' ');
842         if (allowed_args)
843             *allowed_args++ = '\0';
844
845         /* check the command like normal */
846         if (command_matches(allowed_cmnd, allowed_args, NULL)) {
847             /*
848              * If allowed (no bang) set ret but keep on checking.
849              * If disallowed (bang), exit loop.
850              */
851             ret = foundbang ? false : true;
852         }
853
854         sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
855             val, ret == true ? "MATCH!" : "not");
856         efree(allowed_cmnd);    /* cleanup */
857     }
858
859     handle->fn_free_values(val_array); /* more cleanup */
860
861     debug_return_int(ret);
862 }
863
864 static void
865 sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
866 {
867     int i;
868     char op, *v, *val;
869     char **val_array = NULL;
870     debug_decl(sudo_sss_parse_options, SUDO_DEBUG_SSSD);
871
872     if (rule == NULL)
873         debug_return;
874
875     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
876     case 0:
877         break;
878     case ENOENT:
879         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
880         debug_return;
881     default:
882         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
883         debug_return;
884     }
885
886     /* walk through options */
887     for (i = 0; val_array[i] != NULL; i++) {
888         sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'",
889          val_array[i]);
890         v = estrdup(val_array[i]);
891
892         /* check for equals sign past first char */
893         val = strchr(v, '=');
894         if (val > 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);
901             } else {
902                 /* case var=val */
903                 set_default(v, val, true);
904             }
905         } else if (*v == '!') {
906             /* case !var Boolean False */
907             set_default(v + 1, NULL, false);
908         } else {
909             /* case var Boolean True */
910             set_default(v, NULL, true);
911         }
912         efree(v);
913     }
914
915     handle->fn_free_values(val_array);
916     debug_return;
917 }
918
919 static int
920 sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
921 {
922     int rc, setenv_implied;
923
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);
929
930     /* Fetch list of sudoRole entries that match user and host. */
931     sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
932
933     /*
934      * The following queries are only determine whether or not a
935      * password is required, so the order of the entries doesn't matter.
936      */
937     if (pwflag) {
938         int doauth = UNSPEC;
939         int matched = UNSPEC;
940         enum def_tuple pwcheck =
941             (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
942
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");
950                 }
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)) {
955                     matched = true;
956                     break;
957                 }
958             }
959         }
960         if (matched || user_uid == 0) {
961             SET(ret, VALIDATE_OK);
962             CLR(ret, VALIDATE_NOT_OK);
963             if (def_authenticate) {
964                 switch (pwcheck) {
965                     case always:
966                         SET(ret, FLAG_CHECK_USER);
967                         break;
968                     case all:
969                     case any:
970                         if (doauth == false)
971                             def_authenticate = false;
972                         break;
973                     case never:
974                         def_authenticate = false;
975                         break;
976                     default:
977                         break;
978                 }
979             }
980         }
981         goto done;
982     }
983
984     sudo_debug_printf(SUDO_DEBUG_DIAG,
985         "searching SSSD/LDAP for sudoers entries");
986
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))
992                 continue;
993             rc = sudo_sss_check_command(handle, rule, &setenv_implied);
994             if (rc != UNSPEC) {
995                 /* We have a match. */
996                 sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
997                     rc == true ? "" : "NOT ");
998                 if (rc == true) {
999                     sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
1000                     /* Apply entry-specific options. */
1001                     if (setenv_implied)
1002                         def_setenv = true;
1003                     sudo_sss_parse_options(handle, rule);
1004 #ifdef HAVE_SELINUX
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);
1013                 } else {
1014                     SET(ret, VALIDATE_NOT_OK);
1015                     CLR(ret, VALIDATE_OK);
1016                 }
1017                 break;
1018             }
1019         }
1020     }
1021 done:
1022     sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
1023
1024     if (!ISSET(ret, VALIDATE_OK)) {
1025         /* No matching entries. */
1026         if (pwflag && list_pw == NULL)
1027             SET(ret, FLAG_NO_CHECK);
1028     }
1029
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);
1034
1035     sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
1036      pwflag, ret);
1037
1038     debug_return_int(ret);
1039 }
1040
1041 static int
1042 sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
1043 {
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);
1049
1050     if (handle == NULL)
1051         goto done;
1052
1053     if (sudo_sss_checkpw(nss, pw) != 0)
1054         debug_return_int(-1);
1055
1056     /*
1057      * The sudo_sss_result_get() function returns all nodes that match
1058      * the user and the host.
1059      */
1060     sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
1061     sss_result = sudo_sss_result_get(nss, pw, NULL);
1062
1063     if (sss_result == NULL)
1064         goto done;
1065
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)) {
1070             found = true;
1071             goto done;
1072         }
1073     }
1074
1075 done:
1076     if (found)
1077         printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1078             user_args ? " " : "", user_args ? user_args : "");
1079
1080     if (sss_result != NULL)
1081         handle->fn_free_result(sss_result);
1082
1083     debug_return_int(!found);
1084 }
1085
1086 static int
1087 sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1088     struct lbuf *lbuf)
1089 {
1090     struct sudo_sss_handle *handle = nss->handle;
1091
1092     struct sss_sudo_rule *rule;
1093     struct sss_sudo_result *sss_result = NULL;
1094
1095     uint32_t sss_error = 0;
1096
1097     char *prefix, *val, **val_array = NULL;
1098     int count = 0, i, j;
1099
1100     debug_decl(sudo_sss_display_defaults, SUDO_DEBUG_SSSD);
1101
1102     if (handle == NULL)
1103         goto done;
1104
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);
1109         goto done;
1110     }
1111
1112     if (sss_error == ENOENT) {
1113         sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
1114         goto done;
1115     } else if(sss_error != 0) {
1116         sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
1117         goto done;
1118     }
1119
1120     handle->pw = pw;
1121
1122     for (i = 0; i < sss_result->num_rules; ++i) {
1123         rule = sss_result->rules + i;
1124
1125         switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1126         case 0:
1127             break;
1128         case ENOENT:
1129             sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1130             continue;
1131         default:
1132             sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
1133             continue;
1134         }
1135
1136         if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1137             prefix = "    ";
1138         else
1139             prefix = ", ";
1140
1141         for (j = 0; val_array[j] != NULL; ++j) {
1142             val = val_array[j];
1143             lbuf_append(lbuf, "%s%s", prefix, val);
1144             prefix = ", ";
1145             count++;
1146         }
1147
1148         handle->fn_free_values(val_array);
1149         val_array = NULL;
1150     }
1151
1152     handle->fn_free_result(sss_result);
1153 done:
1154     debug_return_int(count);
1155 }
1156
1157 // ok
1158 static int
1159 sudo_sss_display_bound_defaults(struct sudo_nss *nss,
1160     struct passwd *pw, struct lbuf *lbuf)
1161 {
1162     debug_decl(sudo_sss_display_bound_defaults, SUDO_DEBUG_SSSD);
1163     debug_return_int(0);
1164 }
1165
1166 static int
1167 sudo_sss_display_entry_long(struct sudo_sss_handle *handle,
1168     struct sss_sudo_rule *rule, struct lbuf *lbuf)
1169 {
1170     char **val_array = NULL;
1171     int count = 0, i;
1172     debug_decl(sudo_sss_display_entry_long, SUDO_DEBUG_SSSD);
1173
1174     /* get the RunAsUser Values from the entry */
1175     lbuf_append(lbuf, "    RunAsUsers: ");
1176     switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1177     case 0:
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);
1181         break;
1182     case ENOENT:
1183         switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1184         case 0:
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);
1188             break;
1189         case ENOENT:
1190             sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1191             lbuf_append(lbuf, "%s", def_runas_default);
1192             break;
1193         default:
1194             sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
1195             debug_return_int(count);
1196         }
1197         break;
1198     default:
1199         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
1200         debug_return_int(count);
1201     }
1202     lbuf_append(lbuf, "\n");
1203
1204     /* get the RunAsGroup Values from the entry */
1205     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1206     case 0:
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");
1212         break;
1213     case ENOENT:
1214         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1215         break;
1216     default:
1217         sudo_debug_printf(SUDO_DEBUG_INFO,
1218             "handle->fn_get_values(sudoRunAsGroup): != 0");
1219         debug_return_int(count);
1220     }
1221
1222     /* get the Option Values from the entry */
1223     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1224     case 0:
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");
1230         break;
1231     case ENOENT:
1232         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1233         break;
1234     default:
1235         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
1236         debug_return_int(count);
1237     }
1238
1239     /* Get the command values from the entry. */
1240     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1241     case 0:
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]);
1245              count++;
1246         }
1247         handle->fn_free_values(val_array);
1248         break;
1249     case ENOENT:
1250         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1251         break;
1252     default:
1253         sudo_debug_printf(SUDO_DEBUG_INFO,
1254             "handle->fn_get_values(sudoCommand): != 0");
1255         debug_return_int(count);
1256     }
1257
1258     debug_return_int(count);
1259 }
1260
1261 static int
1262 sudo_sss_display_entry_short(struct sudo_sss_handle *handle,
1263     struct sss_sudo_rule *rule, struct lbuf *lbuf)
1264 {
1265     char **val_array = NULL;
1266     int count = 0, i;
1267     debug_decl(sudo_sss_display_entry_short, SUDO_DEBUG_SSSD);
1268
1269     lbuf_append(lbuf, "    (");
1270
1271     /* get the RunAsUser Values from the entry */
1272     switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
1273     case 0:
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);
1277         break;
1278     case ENOENT:
1279         sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs).");
1280         /* try old style */
1281         switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
1282         case 0:
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);
1286             break;
1287         case ENOENT:
1288             sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1289             lbuf_append(lbuf, "%s", def_runas_default);
1290             break;
1291         default:
1292             sudo_debug_printf(SUDO_DEBUG_INFO,
1293                 "handle->fn_get_values(sudoRunAs): != 0");
1294             debug_return_int(count);
1295         }
1296         break;
1297     default:
1298         sudo_debug_printf(SUDO_DEBUG_INFO,
1299             "handle->fn_get_values(sudoRunAsUser): != 0");
1300         debug_return_int(count);
1301     }
1302
1303     /* get the RunAsGroup Values from the entry */
1304     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
1305     case 0:
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);
1310         break;
1311     case ENOENT:
1312         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1313         break;
1314     default:
1315         sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsGroup): != 0");
1316         debug_return_int(count);
1317     }
1318
1319     lbuf_append(lbuf, ") ");
1320
1321     /* get the Option Values from the entry */
1322     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
1323     case 0:
1324         for (i = 0; val_array[i] != NULL; ++i) {
1325             char *cp = val_array[i];
1326             if (*cp == '!')
1327                 cp++;
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: ");
1337         }
1338         handle->fn_free_values(val_array);
1339         break;
1340     case ENOENT:
1341         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1342         break;
1343     default:
1344         sudo_debug_printf(SUDO_DEBUG_INFO,
1345             "handle->fn_get_values(sudoOption): != 0");
1346         debug_return_int(count);
1347     }
1348
1349     /* get the Command Values from the entry */
1350     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
1351     case 0:
1352         for (i = 0; val_array[i] != NULL; ++i) {
1353             lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
1354             count++;
1355         }
1356         handle->fn_free_values(val_array);
1357         break;
1358     case ENOENT:
1359         sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
1360         break;
1361     default:
1362         sudo_debug_printf(SUDO_DEBUG_INFO,
1363             "handle->fn_get_values(sudoCommand): != 0");
1364         debug_return_int(count);
1365     }
1366     lbuf_append(lbuf, "\n");
1367
1368     debug_return_int(count);
1369 }
1370
1371 static int
1372 sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
1373     struct lbuf *lbuf)
1374 {
1375     struct sudo_sss_handle *handle = nss->handle;
1376
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);
1381
1382     if (handle == NULL)
1383         debug_return_int(-1);
1384     if (sudo_sss_checkpw(nss, pw) != 0)
1385         debug_return_int(-1);
1386
1387     sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
1388
1389     sss_result = sudo_sss_result_get(nss, pw, NULL);
1390
1391     if (sss_result == NULL)
1392         debug_return_int(count);
1393
1394     /* Display all matching entries. */
1395     for (i = 0; i < sss_result->num_rules; ++i) {
1396         rule = sss_result->rules + i;
1397         if (long_list)
1398             count += sudo_sss_display_entry_long(handle, rule, lbuf);
1399         else
1400             count += sudo_sss_display_entry_short(handle, rule, lbuf);
1401     }
1402
1403     if (sss_result != NULL)
1404         handle->fn_free_result(sss_result);
1405
1406     debug_return_int(count);
1407 }