File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / sssd.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 2 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    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: #ifdef TIME_WITH_SYS_TIME
   44: # include <time.h>
   45: #endif
   46: #include <ctype.h>
   47: #include <pwd.h>
   48: #include <grp.h>
   49: 
   50: #include <errno.h>
   51: #include <stdint.h>
   52: 
   53: #include "sudoers.h"
   54: #include "parse.h"
   55: #include "lbuf.h"
   56: #include "sudo_dso.h"
   57: #include "sudo_debug.h"
   58: 
   59: /* SSSD <--> SUDO interface - do not change */
   60: struct sss_sudo_attr {
   61:     char *name;
   62:     char **values;
   63:     unsigned int num_values;
   64: };
   65: 
   66: struct sss_sudo_rule {
   67:     unsigned int num_attrs;
   68:     struct sss_sudo_attr *attrs;
   69: };
   70: 
   71: struct sss_sudo_result {
   72:     unsigned int num_rules;
   73:     struct sss_sudo_rule *rules;
   74: };
   75: 
   76: typedef int  (*sss_sudo_send_recv_t)(uid_t, const char*, const char*,
   77:                                      uint32_t*, struct sss_sudo_result**);
   78: 
   79: typedef int  (*sss_sudo_send_recv_defaults_t)(uid_t, const char*, uint32_t*,
   80:                                               char**, struct sss_sudo_result**);
   81: 
   82: typedef void (*sss_sudo_free_result_t)(struct sss_sudo_result*);
   83: 
   84: typedef int  (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*,
   85:                                       char***);
   86: 
   87: typedef void (*sss_sudo_free_values_t)(char**);
   88: 
   89: /* sudo_nss implementation */
   90: 
   91: struct sudo_sss_handle {
   92:     char *domainname;
   93:     struct passwd *pw;
   94:     void *ssslib;
   95:     sss_sudo_send_recv_t fn_send_recv;
   96:     sss_sudo_send_recv_defaults_t fn_send_recv_defaults;
   97:     sss_sudo_free_result_t fn_free_result;
   98:     sss_sudo_get_values_t fn_get_values;
   99:     sss_sudo_free_values_t fn_free_values;
  100: };
  101: 
  102: static int sudo_sss_open(struct sudo_nss *nss);
  103: static int sudo_sss_close(struct sudo_nss *nss);
  104: static int sudo_sss_parse(struct sudo_nss *nss);
  105: static void sudo_sss_parse_options(struct sudo_sss_handle *handle,
  106: 				   struct sss_sudo_rule *rule);
  107: static int sudo_sss_setdefs(struct sudo_nss *nss);
  108: static int sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag);
  109: static int sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
  110: static int sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
  111: 				     struct lbuf *lbuf);
  112: 
  113: static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
  114: 					   struct passwd *pw, struct lbuf *lbuf);
  115: 
  116: static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
  117: 				  struct lbuf *lbuf);
  118: 
  119: 
  120: static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
  121: 						   struct passwd *pw,
  122: 						   uint32_t *state);
  123: 
  124: static void
  125: sudo_sss_attrcpy(struct sss_sudo_attr *dst, const struct sss_sudo_attr *src)
  126: {
  127:      int i;
  128:      debug_decl(sudo_sss_attrcpy, SUDO_DEBUG_SSSD)
  129: 
  130:      sudo_debug_printf(SUDO_DEBUG_DEBUG, "dst=%p, src=%p", dst, src);
  131:      sudo_debug_printf(SUDO_DEBUG_INFO, "emalloc: cnt=%d", src->num_values);
  132: 
  133:      dst->name = estrdup(src->name);
  134:      dst->num_values = src->num_values;
  135:      dst->values = emalloc2(dst->num_values, sizeof(char *));
  136: 
  137:      for (i = 0; i < dst->num_values; ++i)
  138: 	  dst->values[i] = estrdup(src->values[i]);
  139: 
  140:      debug_return;
  141: }
  142: 
  143: static void
  144: sudo_sss_rulecpy(struct sss_sudo_rule *dst, const struct sss_sudo_rule *src)
  145: {
  146:      int i;
  147:      debug_decl(sudo_sss_rulecpy, SUDO_DEBUG_SSSD)
  148: 
  149:      sudo_debug_printf(SUDO_DEBUG_DEBUG, "dst=%p, src=%p", dst, src);
  150:      sudo_debug_printf(SUDO_DEBUG_INFO, "emalloc: cnt=%d", src->num_attrs);
  151: 
  152:      dst->num_attrs = src->num_attrs;
  153:      dst->attrs = emalloc2(dst->num_attrs, sizeof(struct sss_sudo_attr));
  154: 
  155:      for (i = 0; i < dst->num_attrs; ++i)
  156: 	  sudo_sss_attrcpy(dst->attrs + i, src->attrs + i);
  157: 
  158:      debug_return;
  159: }
  160: 
  161: #define _SUDO_SSS_FILTER_INCLUDE 0
  162: #define _SUDO_SSS_FILTER_EXCLUDE 1
  163: 
  164: #define _SUDO_SSS_STATE_HOSTMATCH 0x01
  165: #define _SUDO_SSS_STATE_USERMATCH 0x02
  166: 
  167: static struct sss_sudo_result *
  168: sudo_sss_filter_result(struct sudo_sss_handle *handle,
  169:     struct sss_sudo_result *in_res,
  170:     int (*filterp)(struct sudo_sss_handle *, struct sss_sudo_rule *, void *),
  171:     int act, void *filterp_arg)
  172: {
  173:     struct sss_sudo_result *out_res;
  174:     int i, l, r;
  175:     debug_decl(sudo_sss_filter_result, SUDO_DEBUG_SSSD)
  176: 
  177:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "in_res=%p, count=%u, act=%s",
  178: 	in_res, in_res ? in_res->num_rules : 0,
  179: 	act == _SUDO_SSS_FILTER_EXCLUDE ? "EXCLUDE" : "INCLUDE");
  180: 
  181:     if (in_res == NULL)
  182: 	debug_return_ptr(NULL);
  183: 
  184:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "emalloc: cnt=%d", in_res->num_rules);
  185: 
  186:     out_res = emalloc(sizeof(struct sss_sudo_result));
  187:     out_res->rules = in_res->num_rules > 0 ?
  188: 	emalloc2(in_res->num_rules, sizeof(struct sss_sudo_rule)) : NULL;
  189:     out_res->num_rules = 0;
  190: 
  191:     for (i = l = 0; i < in_res->num_rules; ++i) {
  192: 	 r = filterp(handle, in_res->rules + i, filterp_arg);
  193: 
  194: 	 if (( r && act == _SUDO_SSS_FILTER_INCLUDE) ||
  195: 	     (!r && act == _SUDO_SSS_FILTER_EXCLUDE)) {
  196: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG,
  197: 		"COPY (%s): %p[%u] => %p[%u] (= %p)",
  198: 		act == _SUDO_SSS_FILTER_EXCLUDE ? "not excluded" : "included",
  199: 		in_res->rules, i, out_res->rules, l, in_res->rules + i);
  200: 
  201: 	    sudo_sss_rulecpy(out_res->rules + l, in_res->rules + i);
  202: 	    ++l;
  203: 	}
  204:     }
  205: 
  206:     if (l < in_res->num_rules) {
  207: 	sudo_debug_printf(SUDO_DEBUG_DEBUG,
  208: 	    "reallocating result: %p (count: %u -> %u)", out_res->rules,
  209: 	    in_res->num_rules, l);
  210: 	if (l > 0) {
  211: 	    out_res->rules =
  212: 		erealloc3(out_res->rules, l, sizeof(struct sss_sudo_rule));
  213: 	} else {
  214: 	    efree(out_res->rules);
  215: 	    out_res->rules = NULL;
  216: 	}
  217:     }
  218: 
  219:     out_res->num_rules = l;
  220: 
  221:     debug_return_ptr(out_res);
  222: }
  223: 
  224: struct sudo_nss sudo_nss_sss = {
  225:     { NULL, 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 = sudo_dso_load(path, SUDO_DSO_LAZY);
  250:     if (handle->ssslib == NULL) {
  251: 	warningx(U_("unable to load %s: %s"), path, sudo_dso_strerror());
  252: 	warningx(U_("unable to initialize SSS source. Is SSSD installed on your machine?"));
  253: 	debug_return_int(EFAULT);
  254:     }
  255: 
  256:     handle->fn_send_recv =
  257: 	sudo_dso_findsym(handle->ssslib, "sss_sudo_send_recv");
  258:     if (handle->fn_send_recv == NULL) {
  259: 	warningx(U_("unable to find symbol \"%s\" in %s"), path,
  260: 	   "sss_sudo_send_recv");
  261: 	debug_return_int(EFAULT);
  262:     }
  263: 
  264:     handle->fn_send_recv_defaults =
  265: 	sudo_dso_findsym(handle->ssslib, "sss_sudo_send_recv_defaults");
  266:     if (handle->fn_send_recv_defaults == NULL) {
  267: 	warningx(U_("unable to find symbol \"%s\" in %s"), path,
  268: 	   "sss_sudo_send_recv_defaults");
  269: 	debug_return_int(EFAULT);
  270:     }
  271: 
  272:     handle->fn_free_result =
  273: 	sudo_dso_findsym(handle->ssslib, "sss_sudo_free_result");
  274:     if (handle->fn_free_result == NULL) {
  275: 	warningx(U_("unable to find symbol \"%s\" in %s"), path,
  276: 	   "sss_sudo_free_result");
  277: 	debug_return_int(EFAULT);
  278:     }
  279: 
  280:     handle->fn_get_values =
  281: 	sudo_dso_findsym(handle->ssslib, "sss_sudo_get_values");
  282:     if (handle->fn_get_values == NULL) {
  283: 	warningx(U_("unable to find symbol \"%s\" in %s"), path,
  284: 	   "sss_sudo_get_values");
  285: 	debug_return_int(EFAULT);
  286:     }
  287: 
  288:     handle->fn_free_values =
  289: 	sudo_dso_findsym(handle->ssslib, "sss_sudo_free_values");
  290:     if (handle->fn_free_values == NULL) {
  291: 	warningx(U_("unable to find symbol \"%s\" in %s"), path,
  292: 	   "sss_sudo_free_values");
  293: 	debug_return_int(EFAULT);
  294:     }
  295: 
  296:     handle->domainname = NULL;
  297:     handle->pw = sudo_user.pw;
  298:     nss->handle = handle;
  299: 
  300:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle);
  301: 
  302:     debug_return_int(0);
  303: }
  304: 
  305: // ok
  306: static int sudo_sss_close(struct sudo_nss *nss)
  307: {
  308:     struct sudo_sss_handle *handle;
  309:     debug_decl(sudo_sss_close, SUDO_DEBUG_SSSD);
  310: 
  311:     if (nss && nss->handle) {
  312: 	handle = nss->handle;
  313: 	sudo_dso_unload(handle->ssslib);
  314: 	efree(nss->handle);
  315:     }
  316:     debug_return_int(0);
  317: }
  318: 
  319: // ok
  320: static int sudo_sss_parse(struct sudo_nss *nss)
  321: {
  322:     debug_decl(sudo_sss_parse, SUDO_DEBUG_SSSD);
  323:     debug_return_int(0);
  324: }
  325: 
  326: static int sudo_sss_setdefs(struct sudo_nss *nss)
  327: {
  328:     struct sudo_sss_handle *handle = nss->handle;
  329: 
  330:     struct sss_sudo_result *sss_result;
  331:     struct sss_sudo_rule   *sss_rule;
  332:     uint32_t sss_error;
  333:     int i;
  334:     debug_decl(sudo_sss_setdefs, SUDO_DEBUG_SSSD);
  335: 
  336:     if (handle == NULL)
  337: 	debug_return_int(-1);
  338: 
  339:     sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
  340: 
  341:     if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
  342: 				      &sss_error, &handle->domainname,
  343: 				      &sss_result) != 0) {
  344: 	sudo_debug_printf(SUDO_DEBUG_INFO,
  345: 	    "handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
  346: 	debug_return_int(-1);
  347:     }
  348: 
  349:     if (sss_error == ENOENT) {
  350: 	sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
  351: 	debug_return_int(0);
  352:     } else if(sss_error != 0) {
  353: 	sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
  354: 	debug_return_int(-1);
  355:     }
  356: 
  357:     for (i = 0; i < sss_result->num_rules; ++i) {
  358: 	 sudo_debug_printf(SUDO_DEBUG_DIAG,
  359: 	    "Parsing cn=defaults, %d/%d", i, sss_result->num_rules);
  360: 	 sss_rule = sss_result->rules + i;
  361: 	 sudo_sss_parse_options(handle, sss_rule);
  362:     }
  363: 
  364:     handle->fn_free_result(sss_result);
  365:     debug_return_int(0);
  366: }
  367: 
  368: static int sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
  369: {
  370:     struct sudo_sss_handle *handle = nss->handle;
  371:     debug_decl(sudo_sss_checkpw, SUDO_DEBUG_SSSD);
  372: 
  373:     if (pw->pw_name != handle->pw->pw_name ||
  374: 	pw->pw_uid  != handle->pw->pw_uid) {
  375: 	sudo_debug_printf(SUDO_DEBUG_DIAG,
  376: 	    "Requested name or uid don't match the initial once, reinitializing...");
  377: 	handle->pw = pw;
  378: 
  379: 	if (sudo_sss_setdefs(nss) != 0)
  380: 	    debug_return_int(-1);
  381:     }
  382: 
  383:      debug_return_int(0);
  384: }
  385: 
  386: static int
  387: sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule)
  388: {
  389:     char **val_array = NULL;
  390:     char *val;
  391:     int ret = false, i;
  392:     debug_decl(sudo_sss_check_runas_user, SUDO_DEBUG_SSSD);
  393: 
  394:     if (!runas_pw)
  395: 	debug_return_int(UNSPEC);
  396: 
  397:     /* get the runas user from the entry */
  398:     switch (handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array)) {
  399:     case 0:
  400: 	break;
  401:     case ENOENT:
  402: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs)");
  403: 
  404: 	/* try old style */
  405: 	switch (handle->fn_get_values(sss_rule, "sudoRunAs", &val_array)) {
  406: 	case 0:
  407: 	    break;
  408: 	case ENOENT:
  409: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Matching against runas_default");
  410: 	    /*
  411: 	     * If there are no runas entries, match runas_default against
  412: 	     * what the user specified on the command line.
  413: 	     */
  414: 	    return !strcasecmp(runas_pw->pw_name, def_runas_default);
  415: 	default:
  416: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
  417: 	    debug_return_int(UNSPEC);
  418: 	}
  419: 	break;
  420:     default:
  421: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
  422: 	debug_return_int(UNSPEC);
  423:     }
  424: 
  425:     /*
  426:      * BUG:
  427:      *
  428:      * if runas is not specified on the command line, the only information
  429:      * as to which user to run as is in the runas_default option.  We should
  430:      * check to see if we have the local option present.  Unfortunately we
  431:      * don't parse these options until after this routine says yes or no.
  432:      * The query has already returned, so we could peek at the attribute
  433:      * values here though.
  434:      *
  435:      * For now just require users to always use -u option unless its set
  436:      * in the global defaults. This behaviour is no different than the global
  437:      * /etc/sudoers.
  438:      *
  439:      * Sigh - maybe add this feature later
  440:      */
  441: 
  442:     /* walk through values returned, looking for a match */
  443:     for (i = 0; val_array[i] != NULL && !ret; ++i) {
  444: 	val = val_array[i];
  445: 
  446: 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
  447: 
  448: 	switch (val[0]) {
  449: 	case '+':
  450: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG, "netgr_");
  451: 	    if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) {
  452: 		sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
  453: 		ret = true;
  454: 	    }
  455: 	    break;
  456: 	case '%':
  457: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG, "usergr_");
  458: 	    if (usergr_matches(val, runas_pw->pw_name, runas_pw)) {
  459: 		sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
  460: 		ret = true;
  461: 	    }
  462: 	    break;
  463: 	case 'A':
  464: 	    if (strcmp(val, "ALL") == 0) {
  465: 		sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
  466: 		ret = true;
  467: 		break;
  468: 	    }
  469: 	    /* FALLTHROUGH */
  470: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
  471: 	default:
  472: 	    if (userpw_matches(val, runas_pw->pw_name, runas_pw)) {
  473: 		sudo_debug_printf(SUDO_DEBUG_DEBUG,
  474: 		    "%s == %s (pw_name) => match", val, runas_pw->pw_name);
  475: 		ret = true;
  476: 	    }
  477: 	    break;
  478: 	}
  479: 
  480: 	sudo_debug_printf(SUDO_DEBUG_INFO,
  481: 	    "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
  482:     }
  483: 
  484:     handle->fn_free_values(val_array); /* cleanup */
  485: 
  486:     debug_return_int(ret);
  487: }
  488: 
  489: static int
  490: sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
  491: {
  492:     char **val_array = NULL;
  493:     char *val;
  494:     int ret = false, i;
  495:     debug_decl(sudo_sss_check_runas_group, SUDO_DEBUG_SSSD);
  496: 
  497:     /* runas_gr is only set if the user specified the -g flag */
  498:     if (!runas_gr)
  499: 	debug_return_int(UNSPEC);
  500: 
  501:     /* get the values from the entry */
  502:     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
  503:     case 0:
  504: 	break;
  505:     case ENOENT:
  506: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
  507: 	debug_return_int(false);
  508:     default:
  509: 	sudo_debug_printf(SUDO_DEBUG_INFO,
  510: 	    "handle->fn_get_values(sudoRunAsGroup): != 0");
  511: 	debug_return_int(UNSPEC);
  512:     }
  513: 
  514:     /* walk through values returned, looking for a match */
  515:     for (i = 0; val_array[i] != NULL; ++i) {
  516: 	val = val_array[i];
  517: 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
  518: 
  519: 	if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
  520: 	    ret = true;
  521: 
  522: 	sudo_debug_printf(SUDO_DEBUG_INFO,
  523: 	    "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
  524:     }
  525: 
  526:     handle->fn_free_values(val_array);
  527: 
  528:     debug_return_int(ret);
  529: }
  530: 
  531: /*
  532:  * Walk through search results and return true if we have a runas match,
  533:  * else false.  RunAs info is optional.
  534:  */
  535: static bool
  536: sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
  537: {
  538:     bool ret;
  539:     debug_decl(sudo_sss_check_runas, SUDO_DEBUG_SSSD);
  540: 
  541:     if (rule == NULL)
  542: 	 debug_return_bool(false);
  543: 
  544:     ret = sudo_sss_check_runas_user(handle, rule) != false &&
  545: 	 sudo_sss_check_runas_group(handle, rule) != false;
  546: 
  547:     debug_return_bool(ret);
  548: }
  549: 
  550: static bool
  551: sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
  552: {
  553:     char **val_array, *val;
  554:     bool ret = false;
  555:     int i;
  556:     debug_decl(sudo_sss_check_host, SUDO_DEBUG_SSSD);
  557: 
  558:     if (rule == NULL)
  559: 	debug_return_bool(ret);
  560: 
  561:     /* get the values from the rule */
  562:     switch (handle->fn_get_values(rule, "sudoHost", &val_array))
  563:     {
  564:     case 0:
  565: 	break;
  566:     case ENOENT:
  567: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
  568: 	debug_return_bool(false);
  569:     default:
  570: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoHost): != 0");
  571: 	debug_return_bool(ret);
  572:     }
  573: 
  574:     /* walk through values */
  575:     for (i = 0; val_array[i] != NULL; ++i) {
  576: 	val = val_array[i];
  577: 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
  578: 
  579: 	/* match any or address or netgroup or hostname */
  580: 	if (!strcmp(val, "ALL") || addr_matches(val) ||
  581: 	    netgr_matches(val, user_host, user_shost, NULL) ||
  582: 	    hostname_matches(user_shost, user_host, val))
  583: 	    ret = true;
  584: 
  585: 	sudo_debug_printf(SUDO_DEBUG_INFO,
  586: 	    "sssd/ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
  587:     }
  588: 
  589:     handle->fn_free_values(val_array);
  590: 
  591:     debug_return_bool(ret);
  592: }
  593: 
  594: /*
  595:  * Look for netgroup specifcations in the sudoUser attribute and
  596:  * if found, filter according to netgroup membership.
  597:  *  returns:
  598:  *   true -> netgroup spec found && netgroup member
  599:  *  false -> netgroup spec found && not a member of netgroup
  600:  *   true -> netgroup spec not found (filtered by SSSD already, netgroups are an exception)
  601:  */
  602: static bool
  603: sudo_sss_filter_user_netgroup(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
  604: {
  605:     bool ret = false, netgroup_spec_found = false;
  606:     char **val_array, *val;
  607:     int i;
  608:     debug_decl(sudo_sss_filter_user_netgroup, SUDO_DEBUG_SSSD);
  609: 
  610:     if (!handle || !rule)
  611: 	debug_return_bool(ret);
  612: 
  613:     switch (handle->fn_get_values(rule, "sudoUser", &val_array)) {
  614: 	case 0:
  615: 	    break;
  616: 	case ENOENT:
  617: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
  618: 	    debug_return_bool(ret);
  619: 	default:
  620: 	    sudo_debug_printf(SUDO_DEBUG_INFO,
  621: 		"handle->fn_get_values(sudoUser): != 0");
  622: 	    debug_return_bool(ret);
  623:     }
  624: 
  625:     for (i = 0; val_array[i] != NULL && !ret; ++i) {
  626: 	val = val_array[i];
  627: 	if (*val == '+') {
  628: 	    netgroup_spec_found = true;
  629: 	}
  630: 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
  631: 	if (strcmp(val, "ALL") == 0 || netgr_matches(val, NULL, NULL, handle->pw->pw_name)) {
  632: 	    ret = true;
  633: 	    sudo_debug_printf(SUDO_DEBUG_DIAG,
  634: 		"sssd/ldap sudoUser '%s' ... MATCH! (%s)",
  635: 		val, handle->pw->pw_name);
  636: 	    break;
  637: 	}
  638:     }
  639:     handle->fn_free_values(val_array);
  640:     debug_return_bool(netgroup_spec_found ? ret : true);
  641: }
  642: 
  643: static int
  644: sudo_sss_result_filterp(struct sudo_sss_handle *handle,
  645:     struct sss_sudo_rule *rule, void *unused)
  646: {
  647:     (void)unused;
  648:     debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_SSSD);
  649: 
  650:     if (sudo_sss_check_host(handle, rule) &&
  651:         sudo_sss_filter_user_netgroup(handle, rule))
  652: 	debug_return_int(1);
  653:     else
  654: 	debug_return_int(0);
  655: }
  656: 
  657: static struct sss_sudo_result *
  658: sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
  659: {
  660:     struct sudo_sss_handle *handle = nss->handle;
  661:     struct sss_sudo_result *u_sss_result, *f_sss_result;
  662:     uint32_t sss_error = 0, ret;
  663:     debug_decl(sudo_sss_result_get, SUDO_DEBUG_SSSD);
  664: 
  665:     if (sudo_sss_checkpw(nss, pw) != 0)
  666: 	debug_return_ptr(NULL);
  667: 
  668:     sudo_debug_printf(SUDO_DEBUG_DIAG, "  username=%s", handle->pw->pw_name);
  669:     sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s",
  670: 	handle->domainname ? handle->domainname : "NULL");
  671: 
  672:     u_sss_result = f_sss_result = NULL;
  673: 
  674:     ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
  675: 	handle->domainname, &sss_error, &u_sss_result);
  676: 
  677:     switch (ret) {
  678:     case 0:
  679: 	switch (sss_error) {
  680: 	case 0:
  681: 	    if (u_sss_result != NULL) {
  682: 		if (state != NULL) {
  683: 		    sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
  684: 		    *state |= _SUDO_SSS_STATE_USERMATCH;
  685: 		}
  686: 		sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
  687: 		    u_sss_result->num_rules);
  688: 	    } else {
  689: 		sudo_debug_printf(SUDO_DEBUG_INFO,
  690: 		    "Internal error: u_sss_result == NULL && sss_error == 0");
  691: 		debug_return_ptr(NULL);
  692: 	    }
  693: 	    break;
  694: 	case ENOENT:
  695: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
  696: 	default:
  697: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
  698: 	    debug_return_ptr(NULL);
  699: 	}
  700: 	break;
  701:     default:
  702: 	sudo_debug_printf(SUDO_DEBUG_INFO,
  703: 	    "handle->fn_send_recv: != 0: ret=%d", ret);
  704: 	debug_return_ptr(NULL);
  705:     }
  706: 
  707:     f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
  708: 	sudo_sss_result_filterp, _SUDO_SSS_FILTER_INCLUDE, NULL);
  709: 
  710:     if (f_sss_result != NULL) {
  711: 	if (f_sss_result->num_rules > 0) {
  712: 	    if (state != NULL) {
  713: 		sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
  714: 		*state |= _SUDO_SSS_STATE_HOSTMATCH;
  715: 	    }
  716: 	}
  717: 	sudo_debug_printf(SUDO_DEBUG_DEBUG,
  718: 	    "u_sss_result=(%p, %u) => f_sss_result=(%p, %u)", u_sss_result,
  719: 	    u_sss_result->num_rules, f_sss_result, f_sss_result->num_rules);
  720:     } else {
  721: 	sudo_debug_printf(SUDO_DEBUG_DEBUG,
  722: 	    "u_sss_result=(%p, %u) => f_sss_result=NULL", u_sss_result,
  723: 	    u_sss_result->num_rules);
  724:     }
  725: 
  726:     handle->fn_free_result(u_sss_result);
  727: 
  728:     debug_return_ptr(f_sss_result);
  729: }
  730: 
  731: /*
  732:  * Search for boolean "option" in sudoOption.
  733:  * Returns true if found and allowed, false if negated, else UNSPEC.
  734:  */
  735: static int
  736: sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
  737:     char *option)
  738: {
  739:     char ch, *var, **val_array = NULL;
  740:     int i, ret = UNSPEC;
  741:     debug_decl(sudo_sss_check_bool, SUDO_DEBUG_SSSD);
  742: 
  743:     if (rule == NULL)
  744: 	debug_return_int(ret);
  745: 
  746:     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
  747:     case 0:
  748: 	break;
  749:     case ENOENT:
  750: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
  751: 	debug_return_int(ret);
  752:     default:
  753: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
  754: 	debug_return_int(ret);
  755:     }
  756: 
  757:     /* walk through options */
  758:     for (i = 0; val_array[i] != NULL; ++i) {
  759: 	var = val_array[i];
  760: 	sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
  761: 
  762: 	if ((ch = *var) == '!')
  763: 	    var++;
  764: 	if (strcmp(var, option) == 0)
  765: 	    ret = (ch != '!');
  766:     }
  767: 
  768:     handle->fn_free_values(val_array);
  769: 
  770:     debug_return_int(ret);
  771: }
  772: 
  773: /*
  774:  * If a digest prefix is present, fills in struct sudo_digest
  775:  * and returns a pointer to it, updating cmnd to point to the
  776:  * command after the digest.
  777:  */
  778: static struct sudo_digest *
  779: sudo_sss_extract_digest(char **cmnd, struct sudo_digest *digest)
  780: {
  781:     char *ep, *cp = *cmnd;
  782:     int digest_type = SUDO_DIGEST_INVALID;
  783:     debug_decl(sudo_sss_check_command, SUDO_DEBUG_LDAP)
  784: 
  785:     /*
  786:      * Check for and extract a digest prefix, e.g.
  787:      * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
  788:      */
  789:     if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
  790: 	switch (cp[3]) {
  791: 	case '2':
  792: 	    if (cp[4] == '2' && cp[5] == '4')
  793: 		digest_type = SUDO_DIGEST_SHA224;
  794: 	    else if (cp[4] == '5' && cp[5] == '6')
  795: 		digest_type = SUDO_DIGEST_SHA256;
  796: 	    break;
  797: 	case '3':
  798: 	    if (cp[4] == '8' && cp[5] == '4')
  799: 		digest_type = SUDO_DIGEST_SHA384;
  800: 	    break;
  801: 	case '5':
  802: 	    if (cp[4] == '1' && cp[5] == '2')
  803: 		digest_type = SUDO_DIGEST_SHA512;
  804: 	    break;
  805: 	}
  806: 	if (digest_type != SUDO_DIGEST_INVALID) {
  807: 	    cp += 6;
  808: 	    while (isblank((unsigned char)*cp))
  809: 		cp++;
  810: 	    if (*cp == ':') {
  811: 		cp++;
  812: 		while (isblank((unsigned char)*cp))
  813: 		    cp++;
  814: 		ep = cp;
  815: 		while (*ep != '\0' && !isblank((unsigned char)*ep))
  816: 		    ep++;
  817: 		if (*ep != '\0') {
  818: 		    digest->digest_type = digest_type;
  819: 		    digest->digest_str = estrndup(cp, (size_t)(ep - cp));
  820: 		    cp = ep + 1;
  821: 		    while (isblank((unsigned char)*cp))
  822: 			cp++;
  823: 		    *cmnd = cp;
  824: 		    sudo_debug_printf(SUDO_DEBUG_INFO,
  825: 			"%s digest %s for %s",
  826: 			digest_type == SUDO_DIGEST_SHA224 ? "sha224" :
  827: 			digest_type == SUDO_DIGEST_SHA256 ? "sha256" :
  828: 			digest_type == SUDO_DIGEST_SHA384 ? "sha384" :
  829: 			"sha512", digest->digest_str, cp);
  830: 		    debug_return_ptr(digest);
  831: 		}
  832: 	    }
  833: 	}
  834:     }
  835:     debug_return_ptr(NULL);
  836: }
  837: 
  838: /*
  839:  * Walk through search results and return true if we have a command match,
  840:  * false if disallowed and UNSPEC if not matched.
  841:  */
  842: static int
  843: sudo_sss_check_command(struct sudo_sss_handle *handle,
  844:     struct sss_sudo_rule *rule, int *setenv_implied)
  845: {
  846:     char **val_array = NULL, *val;
  847:     char *allowed_cmnd, *allowed_args;
  848:     int i, foundbang, ret = UNSPEC;
  849:     struct sudo_digest digest, *allowed_digest = NULL;
  850:     debug_decl(sudo_sss_check_command, SUDO_DEBUG_SSSD);
  851: 
  852:     if (rule == NULL)
  853: 	debug_return_int(ret);
  854: 
  855:     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
  856:     case 0:
  857: 	break;
  858:     case ENOENT:
  859: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
  860: 	debug_return_int(ret);
  861:     default:
  862: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
  863: 	debug_return_int(ret);
  864:     }
  865: 
  866:     for (i = 0; val_array[i] != NULL && ret != false; ++i) {
  867: 	val = val_array[i];
  868: 
  869: 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
  870: 
  871: 	/* Match against ALL ? */
  872: 	if (!strcmp(val, "ALL")) {
  873: 	    ret = true;
  874: 	    if (setenv_implied != NULL)
  875: 		*setenv_implied = true;
  876: 	    sudo_debug_printf(SUDO_DEBUG_INFO,
  877: 		"sssd/ldap sudoCommand '%s' ... MATCH!", val);
  878: 	    continue;
  879: 	}
  880: 
  881:         /* check for sha-2 digest */
  882: 	allowed_digest = sudo_sss_extract_digest(&val, &digest);
  883: 
  884: 	/* check for !command */
  885: 	if (*val == '!') {
  886: 	    foundbang = true;
  887: 	    allowed_cmnd = estrdup(1 + val);	/* !command */
  888: 	} else {
  889: 	    foundbang = false;
  890: 	    allowed_cmnd = estrdup(val);	/* command */
  891: 	}
  892: 
  893: 	/* split optional args away from command */
  894: 	allowed_args = strchr(allowed_cmnd, ' ');
  895: 	if (allowed_args)
  896: 	    *allowed_args++ = '\0';
  897: 
  898: 	/* check the command like normal */
  899: 	if (command_matches(allowed_cmnd, allowed_args, NULL)) {
  900: 	    /*
  901: 	     * If allowed (no bang) set ret but keep on checking.
  902: 	     * If disallowed (bang), exit loop.
  903: 	     */
  904: 	    ret = foundbang ? false : true;
  905: 	}
  906: 
  907: 	sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
  908: 	    val, ret == true ? "MATCH!" : "not");
  909: 	efree(allowed_cmnd);	/* cleanup */
  910:     }
  911: 
  912:     handle->fn_free_values(val_array); /* more cleanup */
  913: 
  914:     debug_return_int(ret);
  915: }
  916: 
  917: static void
  918: sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
  919: {
  920:     int i;
  921:     char op, *v, *val;
  922:     char **val_array = NULL;
  923:     debug_decl(sudo_sss_parse_options, SUDO_DEBUG_SSSD);
  924: 
  925:     if (rule == NULL)
  926: 	debug_return;
  927: 
  928:     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
  929:     case 0:
  930: 	break;
  931:     case ENOENT:
  932: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
  933: 	debug_return;
  934:     default:
  935: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
  936: 	debug_return;
  937:     }
  938: 
  939:     /* walk through options */
  940:     for (i = 0; val_array[i] != NULL; i++) {
  941: 	sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'",
  942: 	 val_array[i]);
  943: 	v = estrdup(val_array[i]);
  944: 
  945: 	/* check for equals sign past first char */
  946: 	val = strchr(v, '=');
  947: 	if (val > v) {
  948: 	    *val++ = '\0';	/* split on = and truncate var */
  949: 	    op = *(val - 2);	/* peek for += or -= cases */
  950: 	    if (op == '+' || op == '-') {
  951: 		*(val - 2) = '\0';	/* found, remove extra char */
  952: 		/* case var+=val or var-=val */
  953: 		set_default(v, val, (int) op);
  954: 	    } else {
  955: 		/* case var=val */
  956: 		set_default(v, val, true);
  957: 	    }
  958: 	} else if (*v == '!') {
  959: 	    /* case !var Boolean False */
  960: 	    set_default(v + 1, NULL, false);
  961: 	} else {
  962: 	    /* case var Boolean True */
  963: 	    set_default(v, NULL, true);
  964: 	}
  965: 	efree(v);
  966:     }
  967: 
  968:     handle->fn_free_values(val_array);
  969:     debug_return;
  970: }
  971: 
  972: static int
  973: sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
  974: {
  975:     int rc, setenv_implied;
  976: 
  977:     struct sudo_sss_handle *handle = nss->handle;
  978:     struct sss_sudo_result *sss_result = NULL;
  979:     struct sss_sudo_rule   *rule;
  980:     uint32_t i, state = 0;
  981:     debug_decl(sudo_sss_lookup, SUDO_DEBUG_SSSD);
  982: 
  983:     /* Fetch list of sudoRole entries that match user and host. */
  984:     sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
  985: 
  986:     /*
  987:      * The following queries are only determine whether or not a
  988:      * password is required, so the order of the entries doesn't matter.
  989:      */
  990:     if (pwflag) {
  991: 	int doauth = UNSPEC;
  992: 	int matched = UNSPEC;
  993: 	enum def_tuple pwcheck =
  994: 	    (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
  995: 
  996: 	sudo_debug_printf(SUDO_DEBUG_INFO, "perform search for pwflag %d", pwflag);
  997: 	if (sss_result != NULL) {
  998: 	    for (i = 0; i < sss_result->num_rules; i++) {
  999: 		rule = sss_result->rules + i;
 1000: 		if ((pwcheck == any && doauth != false) ||
 1001: 		    (pwcheck == all && doauth == false)) {
 1002: 		    doauth = sudo_sss_check_bool(handle, rule, "authenticate");
 1003: 		}
 1004: 		/* Only check the command when listing another user. */
 1005: 		if (user_uid == 0 || list_pw == NULL ||
 1006: 		    user_uid == list_pw->pw_uid ||
 1007: 		    sudo_sss_check_command(handle, rule, NULL)) {
 1008: 		    matched = true;
 1009: 		    break;
 1010: 		}
 1011: 	    }
 1012: 	}
 1013: 	if (matched || user_uid == 0) {
 1014: 	    SET(ret, VALIDATE_OK);
 1015: 	    CLR(ret, VALIDATE_NOT_OK);
 1016: 	    if (def_authenticate) {
 1017: 		switch (pwcheck) {
 1018: 		    case always:
 1019: 			SET(ret, FLAG_CHECK_USER);
 1020: 			break;
 1021: 		    case all:
 1022: 		    case any:
 1023: 			if (doauth == false)
 1024: 			    def_authenticate = false;
 1025: 			break;
 1026: 		    case never:
 1027: 			def_authenticate = false;
 1028: 			break;
 1029: 		    default:
 1030: 			break;
 1031: 		}
 1032: 	    }
 1033: 	}
 1034: 	goto done;
 1035:     }
 1036: 
 1037:     sudo_debug_printf(SUDO_DEBUG_DIAG,
 1038: 	"searching SSSD/LDAP for sudoers entries");
 1039: 
 1040:     setenv_implied = false;
 1041:     if (sss_result != NULL) {
 1042: 	for (i = 0; i < sss_result->num_rules; i++) {
 1043: 	    rule = sss_result->rules + i;
 1044: 	    if (!sudo_sss_check_runas(handle, rule))
 1045: 		continue;
 1046: 	    rc = sudo_sss_check_command(handle, rule, &setenv_implied);
 1047: 	    if (rc != UNSPEC) {
 1048: 		/* We have a match. */
 1049: 		sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
 1050: 		    rc == true ? "" : "NOT ");
 1051: 		if (rc == true) {
 1052: 		    sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
 1053: 		    /* Apply entry-specific options. */
 1054: 		    if (setenv_implied)
 1055: 			def_setenv = true;
 1056: 		    sudo_sss_parse_options(handle, rule);
 1057: #ifdef HAVE_SELINUX
 1058: 		    /* Set role and type if not specified on command line. */
 1059: 		    if (user_role == NULL)
 1060: 			user_role = def_role;
 1061: 		    if (user_type == NULL)
 1062: 			user_type = def_type;
 1063: #endif /* HAVE_SELINUX */
 1064: 		    SET(ret, VALIDATE_OK);
 1065: 		    CLR(ret, VALIDATE_NOT_OK);
 1066: 		} else {
 1067: 		    SET(ret, VALIDATE_NOT_OK);
 1068: 		    CLR(ret, VALIDATE_OK);
 1069: 		}
 1070: 		break;
 1071: 	    }
 1072: 	}
 1073:     }
 1074: done:
 1075:     sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
 1076: 
 1077:     if (!ISSET(ret, VALIDATE_OK)) {
 1078: 	/* No matching entries. */
 1079: 	if (pwflag && list_pw == NULL)
 1080: 	    SET(ret, FLAG_NO_CHECK);
 1081:     }
 1082: 
 1083:     if (state & _SUDO_SSS_STATE_USERMATCH)
 1084: 	CLR(ret, FLAG_NO_USER);
 1085:     if (state & _SUDO_SSS_STATE_HOSTMATCH)
 1086: 	CLR(ret, FLAG_NO_HOST);
 1087: 
 1088:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
 1089:      pwflag, ret);
 1090: 
 1091:     debug_return_int(ret);
 1092: }
 1093: 
 1094: static int
 1095: sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
 1096: {
 1097:     struct sudo_sss_handle *handle = nss->handle;
 1098:     struct sss_sudo_result *sss_result = NULL;
 1099:     struct sss_sudo_rule *rule;
 1100:     int i, found = false;
 1101:     debug_decl(sudo_sss_display_cmnd, SUDO_DEBUG_SSSD);
 1102: 
 1103:     if (handle == NULL)
 1104: 	goto done;
 1105: 
 1106:     if (sudo_sss_checkpw(nss, pw) != 0)
 1107: 	debug_return_int(-1);
 1108: 
 1109:     /*
 1110:      * The sudo_sss_result_get() function returns all nodes that match
 1111:      * the user and the host.
 1112:      */
 1113:     sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
 1114:     sss_result = sudo_sss_result_get(nss, pw, NULL);
 1115: 
 1116:     if (sss_result == NULL)
 1117: 	goto done;
 1118: 
 1119:     for (i = 0; i < sss_result->num_rules; i++) {
 1120: 	rule = sss_result->rules + i;
 1121: 	if (sudo_sss_check_command(handle, rule, NULL) &&
 1122: 	    sudo_sss_check_runas(handle, rule)) {
 1123: 	    found = true;
 1124: 	    goto done;
 1125: 	}
 1126:     }
 1127: 
 1128: done:
 1129:     if (found)
 1130: 	printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
 1131: 	    user_args ? " " : "", user_args ? user_args : "");
 1132: 
 1133:     if (sss_result != NULL)
 1134: 	handle->fn_free_result(sss_result);
 1135: 
 1136:     debug_return_int(!found);
 1137: }
 1138: 
 1139: static int
 1140: sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
 1141:     struct lbuf *lbuf)
 1142: {
 1143:     struct sudo_sss_handle *handle = nss->handle;
 1144: 
 1145:     struct sss_sudo_rule *rule;
 1146:     struct sss_sudo_result *sss_result = NULL;
 1147: 
 1148:     uint32_t sss_error = 0;
 1149: 
 1150:     char *prefix, *val, **val_array = NULL;
 1151:     int count = 0, i, j;
 1152: 
 1153:     debug_decl(sudo_sss_display_defaults, SUDO_DEBUG_SSSD);
 1154: 
 1155:     if (handle == NULL)
 1156: 	goto done;
 1157: 
 1158:     if (handle->fn_send_recv_defaults(pw->pw_uid, pw->pw_name,
 1159: 				    &sss_error, &handle->domainname,
 1160: 				    &sss_result) != 0) {
 1161: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_send_recv_defaults: !=0, sss_error=%u", sss_error);
 1162: 	goto done;
 1163:     }
 1164: 
 1165:     if (sss_error == ENOENT) {
 1166: 	sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
 1167: 	goto done;
 1168:     } else if(sss_error != 0) {
 1169: 	sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
 1170: 	goto done;
 1171:     }
 1172: 
 1173:     handle->pw = pw;
 1174: 
 1175:     for (i = 0; i < sss_result->num_rules; ++i) {
 1176: 	rule = sss_result->rules + i;
 1177: 
 1178: 	switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
 1179: 	case 0:
 1180: 	    break;
 1181: 	case ENOENT:
 1182: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1183: 	    continue;
 1184: 	default:
 1185: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
 1186: 	    continue;
 1187: 	}
 1188: 
 1189: 	if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
 1190: 	    prefix = "    ";
 1191: 	else
 1192: 	    prefix = ", ";
 1193: 
 1194: 	for (j = 0; val_array[j] != NULL; ++j) {
 1195: 	    val = val_array[j];
 1196: 	    lbuf_append(lbuf, "%s%s", prefix, val);
 1197: 	    prefix = ", ";
 1198: 	    count++;
 1199: 	}
 1200: 
 1201: 	handle->fn_free_values(val_array);
 1202: 	val_array = NULL;
 1203:     }
 1204: 
 1205:     handle->fn_free_result(sss_result);
 1206: done:
 1207:     debug_return_int(count);
 1208: }
 1209: 
 1210: // ok
 1211: static int
 1212: sudo_sss_display_bound_defaults(struct sudo_nss *nss,
 1213:     struct passwd *pw, struct lbuf *lbuf)
 1214: {
 1215:     debug_decl(sudo_sss_display_bound_defaults, SUDO_DEBUG_SSSD);
 1216:     debug_return_int(0);
 1217: }
 1218: 
 1219: static int
 1220: sudo_sss_display_entry_long(struct sudo_sss_handle *handle,
 1221:     struct sss_sudo_rule *rule, struct lbuf *lbuf)
 1222: {
 1223:     char **val_array = NULL;
 1224:     int count = 0, i;
 1225:     debug_decl(sudo_sss_display_entry_long, SUDO_DEBUG_SSSD);
 1226: 
 1227:     /* get the RunAsUser Values from the entry */
 1228:     lbuf_append(lbuf, "    RunAsUsers: ");
 1229:     switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
 1230:     case 0:
 1231: 	for (i = 0; val_array[i] != NULL; ++i)
 1232: 	    lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1233: 	handle->fn_free_values(val_array);
 1234: 	break;
 1235:     case ENOENT:
 1236: 	switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
 1237: 	case 0:
 1238: 	    for (i = 0; val_array[i] != NULL; ++i)
 1239: 		 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1240: 	    handle->fn_free_values(val_array);
 1241: 	    break;
 1242: 	case ENOENT:
 1243: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1244: 	    lbuf_append(lbuf, "%s", def_runas_default);
 1245: 	    break;
 1246: 	default:
 1247: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
 1248: 	    debug_return_int(count);
 1249: 	}
 1250: 	break;
 1251:     default:
 1252: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
 1253: 	debug_return_int(count);
 1254:     }
 1255:     lbuf_append(lbuf, "\n");
 1256: 
 1257:     /* get the RunAsGroup Values from the entry */
 1258:     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
 1259:     case 0:
 1260: 	lbuf_append(lbuf, "    RunAsGroups: ");
 1261: 	for (i = 0; val_array[i] != NULL; ++i)
 1262: 	     lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1263: 	handle->fn_free_values(val_array);
 1264: 	lbuf_append(lbuf, "\n");
 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(sudoRunAsGroup): != 0");
 1272: 	debug_return_int(count);
 1273:     }
 1274: 
 1275:     /* get the Option Values from the entry */
 1276:     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
 1277:     case 0:
 1278: 	lbuf_append(lbuf, "    Options: ");
 1279: 	for (i = 0; val_array[i] != NULL; ++i)
 1280: 	     lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1281: 	handle->fn_free_values(val_array);
 1282: 	lbuf_append(lbuf, "\n");
 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, "handle->fn_get_values(sudoOption): != 0");
 1289: 	debug_return_int(count);
 1290:     }
 1291: 
 1292:     /* Get the command values from the entry. */
 1293:     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
 1294:     case 0:
 1295: 	lbuf_append(lbuf, _("    Commands:\n"));
 1296: 	for (i = 0; val_array[i] != NULL; ++i) {
 1297: 	     lbuf_append(lbuf, "\t%s\n", val_array[i]);
 1298: 	     count++;
 1299: 	}
 1300: 	handle->fn_free_values(val_array);
 1301: 	break;
 1302:     case ENOENT:
 1303: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1304: 	break;
 1305:     default:
 1306: 	sudo_debug_printf(SUDO_DEBUG_INFO,
 1307: 	    "handle->fn_get_values(sudoCommand): != 0");
 1308: 	debug_return_int(count);
 1309:     }
 1310: 
 1311:     debug_return_int(count);
 1312: }
 1313: 
 1314: static int
 1315: sudo_sss_display_entry_short(struct sudo_sss_handle *handle,
 1316:     struct sss_sudo_rule *rule, struct lbuf *lbuf)
 1317: {
 1318:     char **val_array = NULL;
 1319:     int count = 0, i;
 1320:     debug_decl(sudo_sss_display_entry_short, SUDO_DEBUG_SSSD);
 1321: 
 1322:     lbuf_append(lbuf, "    (");
 1323: 
 1324:     /* get the RunAsUser Values from the entry */
 1325:     switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
 1326:     case 0:
 1327: 	for (i = 0; val_array[i] != NULL; ++i)
 1328: 	     lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1329: 	handle->fn_free_values(val_array);
 1330: 	break;
 1331:     case ENOENT:
 1332: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs).");
 1333: 	/* try old style */
 1334: 	switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
 1335: 	case 0:
 1336: 	    for (i = 0; val_array[i] != NULL; ++i)
 1337: 		 lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1338: 	    handle->fn_free_values(val_array);
 1339: 	    break;
 1340: 	case ENOENT:
 1341: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1342: 	    lbuf_append(lbuf, "%s", def_runas_default);
 1343: 	    break;
 1344: 	default:
 1345: 	    sudo_debug_printf(SUDO_DEBUG_INFO,
 1346: 		"handle->fn_get_values(sudoRunAs): != 0");
 1347: 	    debug_return_int(count);
 1348: 	}
 1349: 	break;
 1350:     default:
 1351: 	sudo_debug_printf(SUDO_DEBUG_INFO,
 1352: 	    "handle->fn_get_values(sudoRunAsUser): != 0");
 1353: 	debug_return_int(count);
 1354:     }
 1355: 
 1356:     /* get the RunAsGroup Values from the entry */
 1357:     switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
 1358:     case 0:
 1359: 	lbuf_append(lbuf, " : ");
 1360: 	for (i = 0; val_array[i] != NULL; ++i)
 1361: 	     lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1362: 	handle->fn_free_values(val_array);
 1363: 	break;
 1364:     case ENOENT:
 1365: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1366: 	break;
 1367:     default:
 1368: 	sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsGroup): != 0");
 1369: 	debug_return_int(count);
 1370:     }
 1371: 
 1372:     lbuf_append(lbuf, ") ");
 1373: 
 1374:     /* get the Option Values from the entry */
 1375:     switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
 1376:     case 0:
 1377: 	for (i = 0; val_array[i] != NULL; ++i) {
 1378: 	    char *cp = val_array[i];
 1379: 	    if (*cp == '!')
 1380: 		cp++;
 1381: 	    if (strcmp(cp, "authenticate") == 0)
 1382: 		lbuf_append(lbuf, val_array[i][0] == '!' ?
 1383: 			    "NOPASSWD: " : "PASSWD: ");
 1384: 	    else if (strcmp(cp, "noexec") == 0)
 1385: 		lbuf_append(lbuf, val_array[i][0] == '!' ?
 1386: 			    "EXEC: " : "NOEXEC: ");
 1387: 	    else if (strcmp(cp, "setenv") == 0)
 1388: 		lbuf_append(lbuf, val_array[i][0] == '!' ?
 1389: 			    "NOSETENV: " : "SETENV: ");
 1390: 	}
 1391: 	handle->fn_free_values(val_array);
 1392: 	break;
 1393:     case ENOENT:
 1394: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1395: 	break;
 1396:     default:
 1397: 	sudo_debug_printf(SUDO_DEBUG_INFO,
 1398: 	    "handle->fn_get_values(sudoOption): != 0");
 1399: 	debug_return_int(count);
 1400:     }
 1401: 
 1402:     /* get the Command Values from the entry */
 1403:     switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
 1404:     case 0:
 1405: 	for (i = 0; val_array[i] != NULL; ++i) {
 1406: 	    lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
 1407: 	    count++;
 1408: 	}
 1409: 	handle->fn_free_values(val_array);
 1410: 	break;
 1411:     case ENOENT:
 1412: 	sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
 1413: 	break;
 1414:     default:
 1415: 	sudo_debug_printf(SUDO_DEBUG_INFO,
 1416: 	    "handle->fn_get_values(sudoCommand): != 0");
 1417: 	debug_return_int(count);
 1418:     }
 1419:     lbuf_append(lbuf, "\n");
 1420: 
 1421:     debug_return_int(count);
 1422: }
 1423: 
 1424: static int
 1425: sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
 1426:     struct lbuf *lbuf)
 1427: {
 1428:     struct sudo_sss_handle *handle = nss->handle;
 1429: 
 1430:     struct sss_sudo_result *sss_result = NULL;
 1431:     struct sss_sudo_rule *rule;
 1432:     unsigned int i, count = 0;
 1433:     debug_decl(sudo_sss_display_privs, SUDO_DEBUG_SSSD);
 1434: 
 1435:     if (handle == NULL)
 1436: 	debug_return_int(-1);
 1437:     if (sudo_sss_checkpw(nss, pw) != 0)
 1438: 	debug_return_int(-1);
 1439: 
 1440:     sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
 1441: 
 1442:     sss_result = sudo_sss_result_get(nss, pw, NULL);
 1443: 
 1444:     if (sss_result == NULL)
 1445: 	debug_return_int(count);
 1446: 
 1447:     /* Display all matching entries. */
 1448:     for (i = 0; i < sss_result->num_rules; ++i) {
 1449: 	rule = sss_result->rules + i;
 1450: 	if (long_list)
 1451: 	    count += sudo_sss_display_entry_long(handle, rule, lbuf);
 1452: 	else
 1453: 	    count += sudo_sss_display_entry_short(handle, rule, lbuf);
 1454:     }
 1455: 
 1456:     if (sss_result != NULL)
 1457: 	handle->fn_free_result(sss_result);
 1458: 
 1459:     debug_return_int(count);
 1460: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>