"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_gpo.c" (30 Nov 2019, 154761 Bytes) of package /linux/misc/sssd-2.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ad_gpo.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.1.0_vs_2.2.0.

    1 /*
    2     SSSD
    3 
    4     Authors:
    5         Yassir Elley <yelley@redhat.com>
    6 
    7     Copyright (C) 2013 Red Hat
    8 
    9     This program is free software; you can redistribute it and/or modify
   10     it under the terms of the GNU General Public License as published by
   11     the Free Software Foundation; either version 3 of the License, or
   12     (at your option) any later version.
   13 
   14     This program is distributed in the hope that it will be useful,
   15     but WITHOUT ANY WARRANTY; without even the implied warranty of
   16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17     GNU General Public License for more details.
   18 
   19     You should have received a copy of the GNU General Public License
   20     along with this program.  If not, see <http://www.gnu.org/licenses/>.
   21 */
   22 
   23 /*
   24  * This file implements the following pair of *public* functions (see header):
   25  *   ad_gpo_access_send/recv: provides client-side GPO processing
   26  *
   27  * This file also implements the following pairs of *private* functions (which
   28  * are used by the public functions):
   29  *   ad_gpo_process_som_send/recv: populate list of gp_som objects
   30  *   ad_gpo_process_gpo_send/recv: populate list of gp_gpo objects
   31  *   ad_gpo_process_cse_send/recv: retrieve policy file data
   32  */
   33 
   34 #include <security/pam_modules.h>
   35 #include <syslog.h>
   36 #include <fcntl.h>
   37 #include <ini_configobj.h>
   38 #include "util/util.h"
   39 #include "util/strtonum.h"
   40 #include "util/child_common.h"
   41 #include "providers/data_provider.h"
   42 #include "providers/backend.h"
   43 #include "providers/ad/ad_access.h"
   44 #include "providers/ad/ad_common.h"
   45 #include "providers/ad/ad_domain_info.h"
   46 #include "providers/ad/ad_gpo.h"
   47 #include "providers/ldap/sdap_access.h"
   48 #include "providers/ldap/sdap_async.h"
   49 #include "providers/ldap/sdap.h"
   50 #include "providers/ldap/sdap_idmap.h"
   51 #include "util/util_sss_idmap.h"
   52 #include <ndr.h>
   53 #include <gen_ndr/security.h>
   54 
   55 /* == gpo-ldap constants =================================================== */
   56 
   57 #define AD_AT_DN "distinguishedName"
   58 #define AD_AT_UAC "userAccountControl"
   59 #define AD_AT_CONFIG_NC "configurationNamingContext"
   60 #define AD_AT_GPLINK "gPLink"
   61 #define AD_AT_GPOPTIONS "gpOptions"
   62 #define AD_AT_NT_SEC_DESC "nTSecurityDescriptor"
   63 #define AD_AT_CN "cn"
   64 #define AD_AT_FILE_SYS_PATH "gPCFileSysPath"
   65 #define AD_AT_MACHINE_EXT_NAMES "gPCMachineExtensionNames"
   66 #define AD_AT_FUNC_VERSION "gPCFunctionalityVersion"
   67 #define AD_AT_FLAGS "flags"
   68 
   69 #define UAC_WORKSTATION_TRUST_ACCOUNT 0x00001000
   70 #define UAC_SERVER_TRUST_ACCOUNT 0x00002000
   71 #define AD_AGP_GUID "edacfd8f-ffb3-11d1-b41d-00a0c968f939"
   72 #define AD_AUTHENTICATED_USERS_SID "S-1-5-11"
   73 
   74 /* == gpo-smb constants ==================================================== */
   75 
   76 #define SMB_STANDARD_URI "smb://"
   77 #define BUFSIZE 65536
   78 
   79 #define RIGHTS_SECTION "Privilege Rights"
   80 #define ALLOW_LOGON_INTERACTIVE "SeInteractiveLogonRight"
   81 #define DENY_LOGON_INTERACTIVE "SeDenyInteractiveLogonRight"
   82 #define ALLOW_LOGON_REMOTE_INTERACTIVE "SeRemoteInteractiveLogonRight"
   83 #define DENY_LOGON_REMOTE_INTERACTIVE "SeDenyRemoteInteractiveLogonRight"
   84 #define ALLOW_LOGON_NETWORK "SeNetworkLogonRight"
   85 #define DENY_LOGON_NETWORK "SeDenyNetworkLogonRight"
   86 #define ALLOW_LOGON_BATCH "SeBatchLogonRight"
   87 #define DENY_LOGON_BATCH "SeDenyBatchLogonRight"
   88 #define ALLOW_LOGON_SERVICE "SeServiceLogonRight"
   89 #define DENY_LOGON_SERVICE "SeDenyServiceLogonRight"
   90 
   91 #define GP_EXT_GUID_SECURITY "{827D319E-6EAC-11D2-A4EA-00C04F79F83A}"
   92 #define GP_EXT_GUID_SECURITY_SUFFIX "/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf"
   93 
   94 #ifndef SSSD_LIBEXEC_PATH
   95 #error "SSSD_LIBEXEC_PATH not defined"
   96 #else
   97 #define GPO_CHILD SSSD_LIBEXEC_PATH"/gpo_child"
   98 #endif
   99 
  100 /* If INI_PARSE_IGNORE_NON_KVP is not defined, use 0 (no effect) */
  101 #ifndef INI_PARSE_IGNORE_NON_KVP
  102 #define INI_PARSE_IGNORE_NON_KVP 0
  103 #warning INI_PARSE_IGNORE_NON_KVP not defined.
  104 #endif
  105 
  106 /* fd used by the gpo_child process for logging */
  107 int gpo_child_debug_fd = -1;
  108 
  109 /* == common data structures and declarations ============================= */
  110 
  111 struct gp_som {
  112     const char *som_dn;
  113     struct gp_gplink **gplink_list;
  114     int num_gplinks;
  115 };
  116 
  117 struct gp_gplink {
  118     const char *gpo_dn;
  119     bool enforced;
  120 };
  121 
  122 struct gp_gpo {
  123     struct security_descriptor *gpo_sd;
  124     const char *gpo_dn;
  125     const char *gpo_guid;
  126     const char *smb_server;
  127     const char *smb_share;
  128     const char *smb_path;
  129     const char **gpo_cse_guids;
  130     int num_gpo_cse_guids;
  131     int gpo_func_version;
  132     int gpo_flags;
  133     bool send_to_child;
  134     const char *policy_filename;
  135 };
  136 
  137 enum ace_eval_status {
  138     AD_GPO_ACE_DENIED,
  139     AD_GPO_ACE_ALLOWED,
  140     AD_GPO_ACE_NEUTRAL
  141 };
  142 
  143 struct tevent_req *ad_gpo_process_som_send(TALLOC_CTX *mem_ctx,
  144                                            struct tevent_context *ev,
  145                                            struct sdap_id_conn_ctx *conn,
  146                                            struct ldb_context *ldb_ctx,
  147                                            struct sdap_id_op *sdap_op,
  148                                            struct sdap_options *opts,
  149                                            struct dp_option *ad_options,
  150                                            int timeout,
  151                                            const char *target_dn,
  152                                            const char *domain_name);
  153 int ad_gpo_process_som_recv(struct tevent_req *req,
  154                             TALLOC_CTX *mem_ctx,
  155                             struct gp_som ***som_list);
  156 
  157 struct tevent_req *
  158 ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
  159                         struct tevent_context *ev,
  160                         struct sdap_id_op *sdap_op,
  161                         struct sdap_options *opts,
  162                         char *server_hostname,
  163                         struct sss_domain_info *host_domain,
  164                         struct ad_access_ctx *access_ctx,
  165                         int timeout,
  166                         struct gp_som **som_list);
  167 int ad_gpo_process_gpo_recv(struct tevent_req *req,
  168                             TALLOC_CTX *mem_ctx,
  169                             struct gp_gpo ***candidate_gpos,
  170                             int *num_candidate_gpos);
  171 
  172 struct tevent_req *ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
  173                                            struct tevent_context *ev,
  174                                            bool send_to_child,
  175                                            struct sss_domain_info *domain,
  176                                            const char *gpo_guid,
  177                                            const char *smb_server,
  178                                            const char *smb_share,
  179                                            const char *smb_path,
  180                                            const char *smb_cse_suffix,
  181                                            int cached_gpt_version,
  182                                            int gpo_timeout_option);
  183 
  184 int ad_gpo_process_cse_recv(struct tevent_req *req);
  185 
  186 /* == ad_gpo_parse_map_options and helpers ==================================*/
  187 
  188 #define GPO_LOGIN "login"
  189 #define GPO_SU "su"
  190 #define GPO_SU_L "su-l"
  191 #define GPO_GDM_FINGERPRINT "gdm-fingerprint"
  192 #define GPO_GDM_PASSWORD "gdm-password"
  193 #define GPO_GDM_SMARTCARD "gdm-smartcard"
  194 #define GPO_KDM "kdm"
  195 #define GPO_LIGHTDM "lightdm"
  196 #define GPO_LXDM "lxdm"
  197 #define GPO_SDDM "sddm"
  198 #define GPO_UNITY "unity"
  199 #define GPO_XDM "xdm"
  200 #define GPO_SSHD "sshd"
  201 #define GPO_FTP "ftp"
  202 #define GPO_SAMBA "samba"
  203 #ifdef HAVE_DEBIAN
  204 #define GPO_CROND "cron"
  205 #else
  206 #define GPO_CROND "crond"
  207 #endif
  208 #define GPO_POLKIT "polkit-1"
  209 #define GPO_SUDO "sudo"
  210 #define GPO_SUDO_I "sudo-i"
  211 #define GPO_SYSTEMD_USER "systemd-user"
  212 #define GPO_COCKPIT "cockpit"
  213 
  214 struct gpo_map_option_entry {
  215     enum gpo_map_type gpo_map_type;
  216     enum ad_basic_opt ad_basic_opt;
  217     const char **gpo_map_defaults;
  218     const char *allow_key;
  219     const char *deny_key;
  220 };
  221 
  222 const char *gpo_map_interactive_defaults[] =
  223     {GPO_LOGIN, GPO_SU, GPO_SU_L,
  224      GPO_GDM_FINGERPRINT, GPO_GDM_PASSWORD, GPO_GDM_SMARTCARD, GPO_KDM,
  225      GPO_LIGHTDM, GPO_LXDM, GPO_SDDM, GPO_UNITY, GPO_XDM, NULL};
  226 const char *gpo_map_remote_interactive_defaults[] = {GPO_SSHD, GPO_COCKPIT,
  227                                                      NULL};
  228 const char *gpo_map_network_defaults[] = {GPO_FTP, GPO_SAMBA, NULL};
  229 const char *gpo_map_batch_defaults[] = {GPO_CROND, NULL};
  230 const char *gpo_map_service_defaults[] = {NULL};
  231 const char *gpo_map_permit_defaults[] = {GPO_POLKIT,
  232                                          GPO_SUDO, GPO_SUDO_I,
  233                                          GPO_SYSTEMD_USER,  NULL};
  234 const char *gpo_map_deny_defaults[] = {NULL};
  235 
  236 struct gpo_map_option_entry gpo_map_option_entries[] = {
  237     {GPO_MAP_INTERACTIVE, AD_GPO_MAP_INTERACTIVE, gpo_map_interactive_defaults,
  238      ALLOW_LOGON_INTERACTIVE, DENY_LOGON_INTERACTIVE},
  239     {GPO_MAP_REMOTE_INTERACTIVE, AD_GPO_MAP_REMOTE_INTERACTIVE,
  240      gpo_map_remote_interactive_defaults,
  241      ALLOW_LOGON_REMOTE_INTERACTIVE, DENY_LOGON_REMOTE_INTERACTIVE},
  242     {GPO_MAP_NETWORK, AD_GPO_MAP_NETWORK, gpo_map_network_defaults,
  243      ALLOW_LOGON_NETWORK, DENY_LOGON_NETWORK},
  244     {GPO_MAP_BATCH, AD_GPO_MAP_BATCH, gpo_map_batch_defaults,
  245      ALLOW_LOGON_BATCH, DENY_LOGON_BATCH},
  246     {GPO_MAP_SERVICE, AD_GPO_MAP_SERVICE, gpo_map_service_defaults,
  247      ALLOW_LOGON_SERVICE, DENY_LOGON_SERVICE},
  248     {GPO_MAP_PERMIT, AD_GPO_MAP_PERMIT, gpo_map_permit_defaults, NULL, NULL},
  249     {GPO_MAP_DENY, AD_GPO_MAP_DENY, gpo_map_deny_defaults, NULL, NULL},
  250 };
  251 
  252 const char* gpo_map_type_string(int gpo_map_type)
  253 {
  254     switch(gpo_map_type) {
  255     case GPO_MAP_INTERACTIVE:        return "Interactive";
  256     case GPO_MAP_REMOTE_INTERACTIVE: return "Remote Interactive";
  257     case GPO_MAP_NETWORK:            return "Network";
  258     case GPO_MAP_BATCH:              return "Batch";
  259     case GPO_MAP_SERVICE:            return "Service";
  260     case GPO_MAP_PERMIT:             return "Permitted";
  261     case GPO_MAP_DENY:               return "Denied";
  262     }
  263     return NULL;
  264 }
  265 
  266 static inline bool
  267 ad_gpo_service_in_list(char **list, size_t nlist, const char *str)
  268 {
  269     size_t i;
  270 
  271     for (i = 0; i < nlist; i++) {
  272         if (strcasecmp(list[i], str) == 0) {
  273             break;
  274         }
  275     }
  276 
  277     return (i < nlist) ? true : false;
  278 }
  279 
  280 errno_t
  281 ad_gpo_parse_map_option_helper(enum gpo_map_type gpo_map_type,
  282                                hash_key_t key,
  283                                hash_table_t *options_table)
  284 {
  285     hash_value_t val;
  286     int hret;
  287     int ret;
  288 
  289     hret = hash_lookup(options_table, &key, &val);
  290     if (hret != HASH_SUCCESS && hret != HASH_ERROR_KEY_NOT_FOUND) {
  291         DEBUG(SSSDBG_OP_FAILURE, "Error checking hash table: [%s]\n",
  292               hash_error_string(hret));
  293         ret = EINVAL;
  294         goto done;
  295     } else if (hret == HASH_SUCCESS) {
  296         /* handle unexpected case where mapping for key already exists */
  297         if (val.i == gpo_map_type) {
  298             /* mapping for key exists for same map type; no error */
  299             DEBUG(SSSDBG_TRACE_FUNC,
  300                   "PAM service %s maps to %s multiple times\n", key.str,
  301                   gpo_map_type_string(gpo_map_type));
  302             ret = EOK;
  303         } else {
  304             /* mapping for key exists for different map type; error! */
  305             DEBUG(SSSDBG_CRIT_FAILURE,
  306                   "Configuration error: PAM service %s maps to both %s and "
  307                   "%s. If you are changing the default mappings of Group "
  308                   "Policy rules to PAM services using one of the ad_gpo_map_*"
  309                   " options make sure that the PAM service you add to one map "
  310                   "using the '+service' syntax is not already present in "
  311                   "another map by default (if it is then remove it from the "
  312                   "other map by using the '-service' syntax. Check manual "
  313                   "pages 'man sssd-ad' for details).\n", key.str,
  314                   gpo_map_type_string(val.i), gpo_map_type_string(gpo_map_type));
  315             sss_log(SSS_LOG_ERR,
  316                   "Configuration error: PAM service %s maps to both %s and "
  317                   "%s. If you are changing the default mappings of Group "
  318                   "Policy rules to PAM services using one of the ad_gpo_map_*"
  319                   " options make sure that the PAM service you add to one map "
  320                   "using the '+service' syntax is not already present in "
  321                   "another map by default (if it is then remove it from the "
  322                   "other map by using the '-service' syntax. Check manual "
  323                   "pages 'man sssd-ad' for details).\n", key.str,
  324                   gpo_map_type_string(val.i), gpo_map_type_string(gpo_map_type));
  325             ret = EINVAL;
  326         }
  327         goto done;
  328     } else {
  329         /* handle expected case where mapping for key doesn't already exist */
  330         val.type = HASH_VALUE_INT;
  331         val.i = gpo_map_type;
  332 
  333         hret = hash_enter(options_table, &key, &val);
  334         if (hret != HASH_SUCCESS) {
  335             DEBUG(SSSDBG_OP_FAILURE, "Error checking hash table: [%s]\n",
  336                   hash_error_string(hret));
  337             ret = EIO;
  338             goto done;
  339         }
  340         ret = EOK;
  341     }
  342 
  343 done:
  344     return ret;
  345 }
  346 
  347 errno_t
  348 ad_gpo_parse_map_option(TALLOC_CTX *mem_ctx,
  349                         enum gpo_map_type gpo_map_type,
  350                         hash_table_t *options_table,
  351                         char *conf_str,
  352                         const char **defaults)
  353 {
  354     TALLOC_CTX *tmp_ctx;
  355     errno_t ret;
  356     char **conf_list = NULL;
  357     int conf_list_size = 0;
  358     char **add_list = NULL;
  359     char **remove_list = NULL;
  360     int ai = 0, ri = 0;
  361     int i;
  362     hash_key_t key;
  363 
  364     tmp_ctx = talloc_new(NULL);
  365     if (tmp_ctx == NULL) {
  366         ret = ENOMEM;
  367         goto done;
  368     }
  369 
  370     DEBUG(SSSDBG_TRACE_ALL, "gpo_map_type: %s\n",
  371           gpo_map_type_string(gpo_map_type));
  372 
  373     if (conf_str) {
  374         ret = split_on_separator(tmp_ctx, conf_str, ',', true, true,
  375                                  &conf_list, &conf_list_size);
  376         if (ret != EOK) {
  377             DEBUG(SSSDBG_OP_FAILURE,
  378                   "Cannot parse list of service names %s: %d\n", conf_str, ret);
  379             ret = EINVAL;
  380             goto done;
  381         }
  382 
  383         add_list = talloc_zero_array(tmp_ctx, char *, conf_list_size);
  384         remove_list = talloc_zero_array(tmp_ctx, char *, conf_list_size);
  385         if (add_list == NULL || remove_list == NULL) {
  386             ret = ENOMEM;
  387             goto done;
  388         }
  389     }
  390 
  391     for (i = 0; i < conf_list_size; i++) {
  392         switch (conf_list[i][0]) {
  393         case '+':
  394             add_list[ai] = conf_list[i] + 1;
  395             ai++;
  396             continue;
  397         case '-':
  398             remove_list[ri] = conf_list[i] + 1;
  399             ri++;
  400             continue;
  401         default:
  402             DEBUG(SSSDBG_CRIT_FAILURE, "ad_gpo_map values must start with"
  403                   "either '+' (for adding service) or '-' (for removing service), "
  404                   "got '%s'\n",
  405                   conf_list[i]);
  406             ret = EINVAL;
  407             goto done;
  408         }
  409     }
  410 
  411     /* Start by adding explicitly added services ('+') to hashtable */
  412     for (i = 0; i < ai; i++) {
  413         /* if the service is explicitly configured to be removed, skip it */
  414         if (ad_gpo_service_in_list(remove_list, ri, add_list[i])) {
  415             continue;
  416         }
  417 
  418         key.type = HASH_KEY_STRING;
  419         key.str = (char *)add_list[i];
  420 
  421         ret = ad_gpo_parse_map_option_helper(gpo_map_type, key, options_table);
  422         if (ret != EOK) {
  423             DEBUG(SSSDBG_OP_FAILURE, "Invalid configuration: %d\n", ret);
  424             goto done;
  425         }
  426 
  427         DEBUG(SSSDBG_TRACE_ALL, "Explicitly added service: %s\n", key.str);
  428     }
  429 
  430     /* Add defaults to hashtable */
  431     for (i = 0; defaults[i]; i++) {
  432         /* if the service is explicitly configured to be removed, skip it */
  433         if (ad_gpo_service_in_list(remove_list, ri, defaults[i])) {
  434             continue;
  435         }
  436 
  437         key.type = HASH_KEY_STRING;
  438         key.str = talloc_strdup(mem_ctx, defaults[i]);
  439 
  440         ret = ad_gpo_parse_map_option_helper(gpo_map_type, key, options_table);
  441         if (ret != EOK) {
  442             DEBUG(SSSDBG_OP_FAILURE, "Invalid configuration: %d\n", ret);
  443             goto done;
  444         }
  445 
  446         DEBUG(SSSDBG_TRACE_ALL, "Default service (not explicitly removed): %s\n",
  447               key.str);
  448     }
  449 
  450     ret = EOK;
  451 done:
  452     talloc_free(tmp_ctx);
  453     return ret;
  454 }
  455 
  456 errno_t
  457 ad_gpo_parse_map_options(struct ad_access_ctx *access_ctx)
  458 {
  459     char *gpo_default_right_config;
  460     enum gpo_map_type gpo_default_right;
  461     errno_t ret;
  462     int i;
  463 
  464     for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
  465 
  466         struct gpo_map_option_entry entry = gpo_map_option_entries[i];
  467 
  468         char *entry_config =  dp_opt_get_string(access_ctx->ad_options,
  469                                                 entry.ad_basic_opt);
  470 
  471         ret = ad_gpo_parse_map_option(access_ctx, entry.gpo_map_type,
  472                                       access_ctx->gpo_map_options_table,
  473                                       entry_config, entry.gpo_map_defaults);
  474 
  475         if (ret != EOK) {
  476             DEBUG(SSSDBG_OP_FAILURE, "Invalid configuration: %d\n", ret);
  477             ret = EINVAL;
  478             goto fail;
  479         }
  480     }
  481 
  482     /* default right (applicable for services without any mapping) */
  483     gpo_default_right_config =
  484         dp_opt_get_string(access_ctx->ad_options, AD_GPO_DEFAULT_RIGHT);
  485 
  486     DEBUG(SSSDBG_TRACE_ALL, "gpo_default_right_config: %s\n",
  487           gpo_default_right_config);
  488 
  489     /* if default right not set in config, set them to DENY */
  490     if (gpo_default_right_config == NULL) {
  491         gpo_default_right = GPO_MAP_DENY;
  492     } else if (strncasecmp(gpo_default_right_config, "interactive",
  493                            strlen("interactive")) == 0) {
  494         gpo_default_right = GPO_MAP_INTERACTIVE;
  495     } else if (strncasecmp(gpo_default_right_config, "remote_interactive",
  496                            strlen("remote_interactive")) == 0) {
  497         gpo_default_right = GPO_MAP_REMOTE_INTERACTIVE;
  498     } else if (strncasecmp(gpo_default_right_config, "network",
  499                            strlen("network")) == 0) {
  500         gpo_default_right = GPO_MAP_NETWORK;
  501     } else if (strncasecmp(gpo_default_right_config, "batch",
  502                            strlen("batch")) == 0) {
  503         gpo_default_right = GPO_MAP_BATCH;
  504     } else if (strncasecmp(gpo_default_right_config, "service",
  505                            strlen("service")) == 0) {
  506         gpo_default_right = GPO_MAP_SERVICE;
  507     } else if (strncasecmp(gpo_default_right_config, "permit",
  508                            strlen("permit")) == 0) {
  509         gpo_default_right = GPO_MAP_PERMIT;
  510     } else if (strncasecmp(gpo_default_right_config, "deny",
  511                            strlen("deny")) == 0) {
  512         gpo_default_right = GPO_MAP_DENY;
  513     } else {
  514         ret = EINVAL;
  515         goto fail;
  516     }
  517 
  518     DEBUG(SSSDBG_TRACE_ALL, "gpo_default_right: %d\n", gpo_default_right);
  519     access_ctx->gpo_default_right = gpo_default_right;
  520 
  521 fail:
  522     return ret;
  523 }
  524 
  525 /* == ad_gpo_access_send/recv helpers =======================================*/
  526 
  527 static bool
  528 ad_gpo_dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
  529 {
  530     int i;
  531 
  532     if (sid1 == sid2) {
  533         return true;
  534     }
  535 
  536     if (!sid1 || !sid2) {
  537         return false;
  538     }
  539 
  540     if (sid1->sid_rev_num != sid2->sid_rev_num) {
  541         return false;
  542     }
  543 
  544     for (i = 0; i < 6; i++) {
  545         if (sid1->id_auth[i] != sid2->id_auth[i]) {
  546             return false;
  547         }
  548     }
  549 
  550     if (sid1->num_auths != sid2->num_auths) {
  551         return false;
  552     }
  553 
  554     for (i = 0; i < sid1->num_auths; i++) {
  555         if (sid1->sub_auths[i] != sid2->sub_auths[i]) {
  556             return false;
  557         }
  558     }
  559 
  560     return true;
  561 }
  562 
  563 
  564 /*
  565  * This function retrieves the SIDs corresponding to the input user and returns
  566  * the user_sid, group_sids, and group_size in their respective output params.
  567  *
  568  * Note: since authentication must complete successfully before the
  569  * gpo access checks are called, we can safely assume that the user/computer
  570  * has been authenticated. As such, this function always adds the
  571  * AD_AUTHENTICATED_USERS_SID to the group_sids.
  572  */
  573 static errno_t
  574 ad_gpo_get_sids(TALLOC_CTX *mem_ctx,
  575                 const char *user,
  576                 struct sss_domain_info *domain,
  577                 const char **_user_sid,
  578                 const char ***_group_sids,
  579                 int *_group_size)
  580 {
  581     TALLOC_CTX *tmp_ctx = NULL;
  582     struct ldb_result *res;
  583     int ret = 0;
  584     int i = 0;
  585     int num_group_sids = 0;
  586     const char *user_sid = NULL;
  587     const char *group_sid = NULL;
  588     const char **group_sids = NULL;
  589 
  590     tmp_ctx = talloc_new(NULL);
  591     if (tmp_ctx == NULL) {
  592         ret = ENOMEM;
  593         goto done;
  594     }
  595 
  596     /* first result from sysdb_initgroups is user_sid; rest are group_sids */
  597     ret = sysdb_initgroups(tmp_ctx, domain, user, &res);
  598     if (ret != EOK) {
  599         DEBUG(SSSDBG_OP_FAILURE,
  600               "sysdb_initgroups failed: [%d](%s)\n",
  601               ret, sss_strerror(ret));
  602         goto done;
  603     }
  604 
  605     if (res->count == 0) {
  606         ret = ENOENT;
  607         DEBUG(SSSDBG_OP_FAILURE,
  608               "sysdb_initgroups returned empty result\n");
  609         goto done;
  610     }
  611 
  612     user_sid = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SID_STR, NULL);
  613     num_group_sids = (res->count) - 1;
  614 
  615     /* include space for AD_AUTHENTICATED_USERS_SID and NULL */
  616     group_sids = talloc_array(tmp_ctx, const char *, num_group_sids + 1 + 1);
  617     if (group_sids == NULL) {
  618         ret = ENOMEM;
  619         goto done;
  620     }
  621 
  622     for (i = 0; i < num_group_sids; i++) {
  623         group_sid = ldb_msg_find_attr_as_string(res->msgs[i+1],
  624                                                 SYSDB_SID_STR, NULL);
  625         if (group_sid == NULL) {
  626             DEBUG(SSSDBG_CRIT_FAILURE, "Missing SID for cache entry [%s].\n",
  627                   ldb_dn_get_linearized(res->msgs[i+1]->dn));
  628             ret = EINVAL;
  629             goto done;
  630         }
  631 
  632         group_sids[i] = talloc_steal(group_sids, group_sid);
  633         if (group_sids[i] == NULL) {
  634             ret = ENOMEM;
  635             goto done;
  636         }
  637     }
  638     group_sids[i++] = talloc_strdup(group_sids, AD_AUTHENTICATED_USERS_SID);
  639     group_sids[i] = NULL;
  640 
  641     *_group_size = num_group_sids + 1;
  642     *_group_sids = talloc_steal(mem_ctx, group_sids);
  643     *_user_sid = talloc_steal(mem_ctx, user_sid);
  644     ret = EOK;
  645 
  646  done:
  647     talloc_free(tmp_ctx);
  648     return ret;
  649 }
  650 
  651 /*
  652  * This function determines whether the input ace_dom_sid matches any of the
  653  * client's SIDs. The boolean result is assigned to the _included output param.
  654  */
  655 static errno_t
  656 ad_gpo_ace_includes_client_sid(const char *user_sid,
  657                                const char **group_sids,
  658                                int group_size,
  659                                struct dom_sid ace_dom_sid,
  660                                struct sss_idmap_ctx *idmap_ctx,
  661                                bool *_included)
  662 {
  663     int i = 0;
  664     struct dom_sid *user_dom_sid;
  665     struct dom_sid *group_dom_sid;
  666     enum idmap_error_code err;
  667     bool included = false;
  668 
  669     err = sss_idmap_sid_to_smb_sid(idmap_ctx, user_sid, &user_dom_sid);
  670     if (err != IDMAP_SUCCESS) {
  671         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
  672         return EFAULT;
  673     }
  674 
  675     included = ad_gpo_dom_sid_equal(&ace_dom_sid, user_dom_sid);
  676     sss_idmap_free_smb_sid(idmap_ctx, user_dom_sid);
  677     if (included) {
  678         *_included = true;
  679         return EOK;
  680     }
  681 
  682     for (i = 0; i < group_size; i++) {
  683         err = sss_idmap_sid_to_smb_sid(idmap_ctx, group_sids[i], &group_dom_sid);
  684         if (err != IDMAP_SUCCESS) {
  685             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
  686             return EFAULT;
  687         }
  688         included = ad_gpo_dom_sid_equal(&ace_dom_sid, group_dom_sid);
  689         sss_idmap_free_smb_sid(idmap_ctx, group_dom_sid);
  690         if (included) {
  691             *_included = true;
  692             return EOK;
  693         }
  694     }
  695 
  696     *_included = false;
  697     return EOK;
  698 }
  699 
  700 /*
  701  * This function determines whether use of the extended right
  702  * named "ApplyGroupPolicy" (AGP) is allowed, by comparing the specified
  703  * user_sid and group_sids against the specified access control entry (ACE).
  704  * This function returns ALLOWED, DENIED, or NEUTRAL depending on whether
  705  * the ACE explicitly allows, explicitly denies, or does neither.
  706  *
  707  * Note that the 'M' abbreviation used in the evaluation algorithm stands for
  708  * "access_mask", which represents the set of access rights associated with an
  709  * individual ACE. The access right of interest to the GPO code is
  710  * RIGHT_DS_CONTROL_ACCESS, which serves as a container for all control access
  711  * rights. The specific control access right is identified by a GUID in the
  712  * ACE's ObjectType. In our case, this is the GUID corresponding to AGP.
  713  *
  714  * The ACE evaluation algorithm is specified in [MS-ADTS] 5.1.3.3.4:
  715  * - Deny access by default
  716  * - If the "Inherit Only" (IO) flag is set in the ACE, skip the ACE.
  717  * - If the SID in the ACE does not match any SID in the requester's
  718  *   security context, skip the ACE
  719  * - If the ACE type is "Object Access Allowed", the access right
  720  *   RIGHT_DS_CONTROL_ACCESS (CR) is present in M, and the ObjectType
  721  *   field in the ACE is either not present OR contains a GUID value equal
  722  *   to AGP, then grant requested control access right. Stop access checking.
  723  * - If the ACE type is "Object Access Denied", the access right
  724  *   RIGHT_DS_CONTROL_ACCESS (CR) is present in M, and the ObjectType
  725  *   field in the ACE is either not present OR contains a GUID value equal to
  726  *   AGP, then deny the requested control access right. Stop access checking.
  727  */
  728 static enum ace_eval_status ad_gpo_evaluate_ace(struct security_ace *ace,
  729                                                 struct sss_idmap_ctx *idmap_ctx,
  730                                                 const char *user_sid,
  731                                                 const char **group_sids,
  732                                                 int group_size)
  733 {
  734     bool agp_included = false;
  735     bool included = false;
  736     int ret = 0;
  737     struct security_ace_object object;
  738     struct GUID ext_right_agp_guid;
  739 
  740     if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
  741         return AD_GPO_ACE_NEUTRAL;
  742     }
  743 
  744     ret = ad_gpo_ace_includes_client_sid(user_sid, group_sids, group_size,
  745                                          ace->trustee, idmap_ctx, &included);
  746 
  747     if (ret != EOK) {
  748         return AD_GPO_ACE_DENIED;
  749     }
  750 
  751     if (!included) {
  752         return AD_GPO_ACE_NEUTRAL;
  753     }
  754 
  755     object = ace->object.object;
  756     GUID_from_string(AD_AGP_GUID, &ext_right_agp_guid);
  757 
  758     if (object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
  759         if (GUID_equal(&object.type.type, &ext_right_agp_guid)) {
  760             agp_included = true;
  761         }
  762     } else {
  763         agp_included = false;
  764     }
  765 
  766     if (ace->access_mask & SEC_ADS_CONTROL_ACCESS) {
  767         if (agp_included) {
  768             if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
  769                 return AD_GPO_ACE_ALLOWED;
  770             } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT) {
  771                 return AD_GPO_ACE_DENIED;
  772             }
  773         }
  774     }
  775 
  776     return AD_GPO_ACE_DENIED;
  777 }
  778 
  779 /*
  780  * This function extracts the GPO's DACL (discretionary access control list)
  781  * from the GPO's specified security descriptor, and determines whether
  782  * the GPO is applicable to the policy target, by comparing the specified
  783  * user_sid and group_sids against each access control entry (ACE) in the DACL.
  784  * The boolean result is assigned to the _access_allowed output parameter.
  785  */
  786 static errno_t ad_gpo_evaluate_dacl(struct security_acl *dacl,
  787                                     struct sss_idmap_ctx *idmap_ctx,
  788                                     const char *user_sid,
  789                                     const char **group_sids,
  790                                     int group_size,
  791                                     bool *_dacl_access_allowed)
  792 {
  793     uint32_t num_aces = 0;
  794     enum ace_eval_status ace_status;
  795     int i = 0;
  796     struct security_ace *ace = NULL;
  797 
  798     num_aces = dacl->num_aces;
  799 
  800     /*
  801      * [MS-ADTS] 5.1.3.3.4:
  802      * If the DACL does not have any ACE, then deny the requester the
  803      * requested control access right.
  804      */
  805     if (num_aces == 0) {
  806         *_dacl_access_allowed = false;
  807         return EOK;
  808     }
  809 
  810     for (i = 0; i < dacl->num_aces; i ++) {
  811         ace = &dacl->aces[i];
  812 
  813         ace_status = ad_gpo_evaluate_ace(ace, idmap_ctx, user_sid,
  814                                          group_sids, group_size);
  815 
  816         switch (ace_status) {
  817         case AD_GPO_ACE_NEUTRAL:
  818             continue;
  819         case AD_GPO_ACE_ALLOWED:
  820             *_dacl_access_allowed = true;
  821             return EOK;
  822         case AD_GPO_ACE_DENIED:
  823             *_dacl_access_allowed = false;
  824             return EOK;
  825         }
  826     }
  827 
  828     *_dacl_access_allowed = false;
  829     return EOK;
  830 }
  831 
  832 /*
  833  * This function takes candidate_gpos as input, filters out any gpo that is
  834  * not applicable to the policy target and assigns the result to the
  835  * _dacl_filtered_gpos output parameter. The filtering algorithm is
  836  * defined in [MS-GPOL] 3.2.5.1.6
  837  */
  838 static errno_t
  839 ad_gpo_filter_gpos_by_dacl(TALLOC_CTX *mem_ctx,
  840                            const char *user,
  841                            struct sss_domain_info *domain,
  842                            struct sss_idmap_ctx *idmap_ctx,
  843                            struct gp_gpo **candidate_gpos,
  844                            int num_candidate_gpos,
  845                            struct gp_gpo ***_dacl_filtered_gpos,
  846                            int *_num_dacl_filtered_gpos)
  847 {
  848     TALLOC_CTX *tmp_ctx = NULL;
  849     int i = 0;
  850     int ret = 0;
  851     struct gp_gpo *candidate_gpo = NULL;
  852     struct security_descriptor *sd = NULL;
  853     struct security_acl *dacl = NULL;
  854     const char *user_sid = NULL;
  855     const char **group_sids = NULL;
  856     int group_size = 0;
  857     int gpo_dn_idx = 0;
  858     bool access_allowed = false;
  859     struct gp_gpo **dacl_filtered_gpos = NULL;
  860 
  861     tmp_ctx = talloc_new(NULL);
  862     if (tmp_ctx == NULL) {
  863         ret = ENOMEM;
  864         goto done;
  865     }
  866 
  867     ret = ad_gpo_get_sids(tmp_ctx, user, domain, &user_sid,
  868                           &group_sids, &group_size);
  869     if (ret != EOK) {
  870         ret = ERR_NO_SIDS;
  871         DEBUG(SSSDBG_OP_FAILURE,
  872               "Unable to retrieve SIDs: [%d](%s)\n", ret, sss_strerror(ret));
  873         goto done;
  874     }
  875 
  876     dacl_filtered_gpos = talloc_array(tmp_ctx,
  877                                  struct gp_gpo *,
  878                                  num_candidate_gpos + 1);
  879 
  880     if (dacl_filtered_gpos == NULL) {
  881         ret = ENOMEM;
  882         goto done;
  883     }
  884 
  885     for (i = 0; i < num_candidate_gpos; i++) {
  886 
  887         access_allowed = false;
  888         candidate_gpo = candidate_gpos[i];
  889 
  890         DEBUG(SSSDBG_TRACE_ALL, "examining dacl candidate_gpo_guid:%s\n",
  891                                 candidate_gpo->gpo_guid);
  892 
  893         /* gpo_func_version must be set to version 2 */
  894         if (candidate_gpo->gpo_func_version != 2) {
  895             DEBUG(SSSDBG_TRACE_ALL,
  896                   "GPO not applicable to target per security filtering: "
  897                   "gPCFunctionalityVersion is not 2\n");
  898             continue;
  899         }
  900 
  901         sd = candidate_gpo->gpo_sd;
  902         if (sd == NULL) {
  903             DEBUG(SSSDBG_TRACE_ALL, "Security descriptor is missing\n");
  904             ret = EINVAL;
  905             goto done;
  906         }
  907 
  908         dacl = candidate_gpo->gpo_sd->dacl;
  909 
  910         /* gpo_flags value of 2 means that GPO's computer portion is disabled */
  911         if (candidate_gpo->gpo_flags == 2) {
  912             DEBUG(SSSDBG_TRACE_ALL,
  913                   "GPO not applicable to target per security filtering: "
  914                   "GPO's computer portion is disabled\n");
  915             continue;
  916         }
  917 
  918         /*
  919          * [MS-ADTS] 5.1.3.3.4:
  920          * If the security descriptor has no DACL or its "DACL Present" bit
  921          * is not set, then grant requester the requested control access right.
  922          */
  923 
  924         if ((!(sd->type & SEC_DESC_DACL_PRESENT)) || (dacl == NULL)) {
  925             DEBUG(SSSDBG_TRACE_ALL, "DACL is not present\n");
  926             access_allowed = true;
  927             break;
  928         }
  929 
  930         ret = ad_gpo_evaluate_dacl(dacl, idmap_ctx, user_sid, group_sids,
  931                                    group_size, &access_allowed);
  932         if (ret != EOK) {
  933             DEBUG(SSSDBG_MINOR_FAILURE, "Could not determine if GPO is applicable\n");
  934             continue;
  935         }
  936 
  937         if (access_allowed) {
  938             DEBUG(SSSDBG_TRACE_ALL,
  939                   "GPO applicable to target per security filtering\n");
  940             dacl_filtered_gpos[gpo_dn_idx] = talloc_steal(dacl_filtered_gpos,
  941                                                           candidate_gpo);
  942             gpo_dn_idx++;
  943         } else {
  944             DEBUG(SSSDBG_TRACE_ALL,
  945                   "GPO not applicable to target per security filtering: "
  946                   "result of DACL evaluation\n");
  947             continue;
  948         }
  949     }
  950 
  951     dacl_filtered_gpos[gpo_dn_idx] = NULL;
  952 
  953     *_dacl_filtered_gpos = talloc_steal(mem_ctx, dacl_filtered_gpos);
  954     *_num_dacl_filtered_gpos = gpo_dn_idx;
  955 
  956     ret = EOK;
  957 
  958  done:
  959     talloc_free(tmp_ctx);
  960     return ret;
  961 }
  962 
  963 /*
  964  * This function determines whether the input cse_guid matches any of the input
  965  * gpo_cse_guids. The boolean result is assigned to the _included output param.
  966  */
  967 static bool
  968 ad_gpo_includes_cse_guid(const char *cse_guid,
  969                          const char **gpo_cse_guids,
  970                          int num_gpo_cse_guids)
  971 {
  972     int i = 0;
  973     const char *gpo_cse_guid = NULL;
  974 
  975     for (i = 0; i < num_gpo_cse_guids; i++) {
  976         gpo_cse_guid = gpo_cse_guids[i];
  977         if (strcmp(gpo_cse_guid, cse_guid) == 0) {
  978             return true;
  979         }
  980     }
  981 
  982     return false;
  983 }
  984 
  985 /*
  986  * This function takes an input dacl_filtered_gpos list, filters out any gpo
  987  * that does not contain the input cse_guid, and assigns the result to the
  988  * _cse_filtered_gpos output parameter.
  989  */
  990 static errno_t
  991 ad_gpo_filter_gpos_by_cse_guid(TALLOC_CTX *mem_ctx,
  992                                const char *cse_guid,
  993                                struct gp_gpo **dacl_filtered_gpos,
  994                                int num_dacl_filtered_gpos,
  995                                struct gp_gpo ***_cse_filtered_gpos,
  996                                int *_num_cse_filtered_gpos)
  997 {
  998     TALLOC_CTX *tmp_ctx = NULL;
  999     int i = 0;
 1000     int ret = 0;
 1001     struct gp_gpo *dacl_filtered_gpo = NULL;
 1002     int gpo_dn_idx = 0;
 1003     struct gp_gpo **cse_filtered_gpos = NULL;
 1004     bool included;
 1005 
 1006     tmp_ctx = talloc_new(NULL);
 1007     if (tmp_ctx == NULL) {
 1008         ret = ENOMEM;
 1009         goto done;
 1010     }
 1011 
 1012     cse_filtered_gpos = talloc_array(tmp_ctx,
 1013                                      struct gp_gpo *,
 1014                                      num_dacl_filtered_gpos + 1);
 1015     if (cse_filtered_gpos == NULL) {
 1016         ret = ENOMEM;
 1017         goto done;
 1018     }
 1019 
 1020     for (i = 0; i < num_dacl_filtered_gpos; i++) {
 1021 
 1022         dacl_filtered_gpo = dacl_filtered_gpos[i];
 1023 
 1024         DEBUG(SSSDBG_TRACE_ALL, "examining cse candidate_gpo_guid: %s\n",
 1025               dacl_filtered_gpo->gpo_guid);
 1026 
 1027         included = ad_gpo_includes_cse_guid(cse_guid,
 1028                                             dacl_filtered_gpo->gpo_cse_guids,
 1029                                             dacl_filtered_gpo->num_gpo_cse_guids);
 1030 
 1031         if (included) {
 1032             DEBUG(SSSDBG_TRACE_ALL,
 1033                   "GPO applicable to target per cse_guid filtering\n");
 1034             cse_filtered_gpos[gpo_dn_idx] = talloc_steal(cse_filtered_gpos,
 1035                                                          dacl_filtered_gpo);
 1036             dacl_filtered_gpos[i] = NULL;
 1037             gpo_dn_idx++;
 1038         } else {
 1039             DEBUG(SSSDBG_TRACE_ALL,
 1040                   "GPO not applicable to target per cse_guid filtering\n");
 1041             continue;
 1042         }
 1043     }
 1044 
 1045     cse_filtered_gpos[gpo_dn_idx] = NULL;
 1046 
 1047     *_cse_filtered_gpos = talloc_steal(mem_ctx, cse_filtered_gpos);
 1048     *_num_cse_filtered_gpos = gpo_dn_idx;
 1049 
 1050     ret = EOK;
 1051 
 1052  done:
 1053     talloc_free(tmp_ctx);
 1054     return ret;
 1055 }
 1056 
 1057 /*
 1058  * This cse-specific function (GP_EXT_GUID_SECURITY) returns a boolean value
 1059  * based on whether the input user_sid or any of the input group_sids appear
 1060  * in the input list of privilege_sids.
 1061  */
 1062 static bool
 1063 check_rights(char **privilege_sids,
 1064              int privilege_size,
 1065              const char *user_sid,
 1066              const char **group_sids,
 1067              int group_size)
 1068 {
 1069     int i, j;
 1070 
 1071     for (i = 0; i < privilege_size; i++) {
 1072         if (strcmp(user_sid, privilege_sids[i]) == 0) {
 1073             return true;
 1074         }
 1075         for (j = 0; j < group_size; j++) {
 1076             if (strcmp(group_sids[j], privilege_sids[i]) == 0) {
 1077                 return true;
 1078             }
 1079         }
 1080     }
 1081 
 1082     return false;
 1083 }
 1084 
 1085 /*
 1086  * This function parses the input ini_config object (which represents
 1087  * the cse-specific filename), and returns the policy_setting_value
 1088  * corresponding to the input policy_setting_key.
 1089  */
 1090 static errno_t
 1091 ad_gpo_extract_policy_setting(TALLOC_CTX *mem_ctx,
 1092                               struct ini_cfgobj *ini_config,
 1093                               const char *policy_setting_key,
 1094                               char **_policy_setting_value)
 1095 {
 1096     struct value_obj *vobj = NULL;
 1097     int ret;
 1098     const char *policy_setting_value;
 1099 
 1100     ret = ini_get_config_valueobj(RIGHTS_SECTION, policy_setting_key, ini_config,
 1101                                   INI_GET_FIRST_VALUE, &vobj);
 1102     if (ret != 0) {
 1103         DEBUG(SSSDBG_CRIT_FAILURE,
 1104               "ini_get_config_valueobj failed [%d][%s]\n", ret, strerror(ret));
 1105         goto done;
 1106     }
 1107     if (vobj == NULL) {
 1108         DEBUG(SSSDBG_TRACE_ALL, "section/name not found: [%s][%s]\n",
 1109               RIGHTS_SECTION, policy_setting_key);
 1110         ret = ENOENT;
 1111         goto done;
 1112     }
 1113     policy_setting_value = ini_get_string_config_value(vobj, &ret);
 1114     if (ret != 0) {
 1115         DEBUG(SSSDBG_CRIT_FAILURE,
 1116               "ini_get_string_config_value failed [%d][%s]\n",
 1117               ret, strerror(ret));
 1118         goto done;
 1119     }
 1120 
 1121     if (policy_setting_value[0]) {
 1122         *_policy_setting_value = talloc_strdup(mem_ctx, policy_setting_value);
 1123         if (!*_policy_setting_value) {
 1124             ret = ENOMEM;
 1125             goto done;
 1126         }
 1127     } else {
 1128         /* This is an explicitly empty policy setting.
 1129          * We need to remove this from the LDB.
 1130          */
 1131         *_policy_setting_value = NULL;
 1132     }
 1133 
 1134     ret = EOK;
 1135 
 1136  done:
 1137 
 1138     return ret;
 1139 }
 1140 
 1141 /*
 1142  * This function parses the cse-specific (GP_EXT_GUID_SECURITY) filename,
 1143  * and stores the allow_key and deny_key of all of the gpo_map_types present
 1144  * in the file (as part of the GPO Result object in the sysdb cache).
 1145  */
 1146 static errno_t
 1147 ad_gpo_store_policy_settings(struct sss_domain_info *domain,
 1148                              const char *filename)
 1149 {
 1150     struct ini_cfgfile *file_ctx = NULL;
 1151     struct ini_cfgobj *ini_config = NULL;
 1152     int ret;
 1153     int i;
 1154     char *allow_value = NULL;
 1155     char *deny_value = NULL;
 1156     const char *empty_val = "NO_SID";
 1157     const char *allow_key = NULL;
 1158     const char *deny_key = NULL;
 1159     TALLOC_CTX *tmp_ctx = NULL;
 1160 
 1161     tmp_ctx = talloc_new(NULL);
 1162     if (tmp_ctx == NULL) {
 1163         ret = ENOMEM;
 1164         goto done;
 1165     }
 1166 
 1167     ret = ini_config_create(&ini_config);
 1168     if (ret != 0) {
 1169         DEBUG(SSSDBG_CRIT_FAILURE,
 1170               "ini_config_create failed [%d][%s]\n", ret, strerror(ret));
 1171         goto done;
 1172     }
 1173 
 1174     ret = ini_config_file_open(filename, 0, &file_ctx);
 1175     if (ret != 0) {
 1176         DEBUG(SSSDBG_CRIT_FAILURE,
 1177               "ini_config_file_open failed [%d][%s]\n", ret, strerror(ret));
 1178         goto done;
 1179     }
 1180 
 1181     ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, 0, ini_config);
 1182     if (ret != 0) {
 1183         int lret;
 1184         char **errors;
 1185 
 1186         DEBUG(SSSDBG_CRIT_FAILURE,
 1187               "[%s]: ini_config_parse failed [%d][%s]\n",
 1188               filename, ret, strerror(ret));
 1189 
 1190         /* Now get specific errors if there are any */
 1191         lret = ini_config_get_errors(ini_config, &errors);
 1192         if (lret != 0) {
 1193             DEBUG(SSSDBG_CRIT_FAILURE,
 1194                   "Failed to get specific parse error [%d][%s]\n", lret,
 1195                   strerror(lret));
 1196             goto done;
 1197         }
 1198 
 1199         for (int a = 0; errors[a]; a++) {
 1200              DEBUG(SSSDBG_CRIT_FAILURE, "%s\n", errors[a]);
 1201         }
 1202         ini_config_free_errors(errors);
 1203 
 1204         /* Do not 'goto done' here. We will try to parse
 1205          * the GPO file again. */
 1206     }
 1207 
 1208     if (ret != EOK) {
 1209         /* A problem occurred during parsing. Try again
 1210          * with INI_PARSE_IGNORE_NON_KVP flag */
 1211 
 1212         ini_config_file_destroy(file_ctx);
 1213         file_ctx = NULL;
 1214         ini_config_destroy(ini_config);
 1215         ini_config = NULL;
 1216 
 1217         ret = ini_config_file_open(filename, 0, &file_ctx);
 1218         if (ret != 0) {
 1219             DEBUG(SSSDBG_CRIT_FAILURE,
 1220                   "ini_config_file_open failed [%d][%s]\n",
 1221                   ret, strerror(ret));
 1222             goto done;
 1223         }
 1224 
 1225         ret = ini_config_create(&ini_config);
 1226         if (ret != 0) {
 1227             DEBUG(SSSDBG_CRIT_FAILURE,
 1228                   "ini_config_create failed [%d][%s]\n", ret, strerror(ret));
 1229             goto done;
 1230         }
 1231 
 1232         ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0,
 1233                                INI_PARSE_IGNORE_NON_KVP, ini_config);
 1234         if (ret != 0) {
 1235             int lret;
 1236             char **errors;
 1237 
 1238             DEBUG(SSSDBG_CRIT_FAILURE,
 1239                   "[%s]: ini_config_parse failed [%d][%s]\n",
 1240                   filename, ret, strerror(ret));
 1241 
 1242             /* Now get specific errors if there are any */
 1243             lret = ini_config_get_errors(ini_config, &errors);
 1244             if (lret != 0) {
 1245                 DEBUG(SSSDBG_CRIT_FAILURE,
 1246                       "Failed to get specific parse error [%d][%s]\n", lret,
 1247                       strerror(lret));
 1248                 goto done;
 1249             }
 1250 
 1251             for (int a = 0; errors[a]; a++) {
 1252                  DEBUG(SSSDBG_CRIT_FAILURE, "%s\n", errors[a]);
 1253             }
 1254             ini_config_free_errors(errors);
 1255 
 1256             goto done;
 1257         }
 1258     }
 1259 
 1260     for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
 1261         /* The NO_SID val is used as special SID value for the case when
 1262          * no SIDs are found in the rule, but we need to store some
 1263          * value (SID) with the key (rule name) so that it is clear
 1264          * that the rule is defined on the server. */
 1265         struct gpo_map_option_entry entry = gpo_map_option_entries[i];
 1266 
 1267         allow_key = entry.allow_key;
 1268         if (allow_key != NULL) {
 1269             DEBUG(SSSDBG_TRACE_ALL, "allow_key = %s\n", allow_key);
 1270             ret = ad_gpo_extract_policy_setting(tmp_ctx,
 1271                                                 ini_config,
 1272                                                 allow_key,
 1273                                                 &allow_value);
 1274             if (ret != EOK && ret != ENOENT) {
 1275                 DEBUG(SSSDBG_CRIT_FAILURE,
 1276                       "ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
 1277                       allow_key, ret, sss_strerror(ret));
 1278                 goto done;
 1279             } else if (ret != ENOENT) {
 1280                 const char *value = allow_value ? allow_value : empty_val;
 1281                 ret = sysdb_gpo_store_gpo_result_setting(domain,
 1282                                                          allow_key,
 1283                                                          value);
 1284                 if (ret != EOK) {
 1285                     DEBUG(SSSDBG_CRIT_FAILURE,
 1286                           "sysdb_gpo_store_gpo_result_setting failed for key:"
 1287                           "'%s' value:'%s' [%d][%s]\n", allow_key, allow_value,
 1288                           ret, sss_strerror(ret));
 1289                     goto done;
 1290                 }
 1291             }
 1292         }
 1293 
 1294         deny_key = entry.deny_key;
 1295         if (deny_key != NULL) {
 1296             DEBUG(SSSDBG_TRACE_ALL, "deny_key = %s\n", deny_key);
 1297             ret = ad_gpo_extract_policy_setting(tmp_ctx,
 1298                                                 ini_config,
 1299                                                 deny_key,
 1300                                                 &deny_value);
 1301             if (ret != EOK && ret != ENOENT) {
 1302                 DEBUG(SSSDBG_CRIT_FAILURE,
 1303                       "ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
 1304                       deny_key, ret, sss_strerror(ret));
 1305                 goto done;
 1306             } else if (ret != ENOENT) {
 1307                 const char *value = deny_value ? deny_value : empty_val;
 1308                 ret = sysdb_gpo_store_gpo_result_setting(domain,
 1309                                                          deny_key,
 1310                                                          value);
 1311                 if (ret != EOK) {
 1312                     DEBUG(SSSDBG_CRIT_FAILURE,
 1313                           "sysdb_gpo_store_gpo_result_setting failed for key:"
 1314                           "'%s' value:'%s' [%d][%s]\n", deny_key, deny_value,
 1315                           ret, sss_strerror(ret));
 1316                     goto done;
 1317                 }
 1318             }
 1319         }
 1320     }
 1321 
 1322     ret = EOK;
 1323 
 1324  done:
 1325 
 1326     if (ret != EOK) {
 1327       DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
 1328     }
 1329     ini_config_file_destroy(file_ctx);
 1330     ini_config_destroy(ini_config);
 1331     talloc_free(tmp_ctx);
 1332     return ret;
 1333 }
 1334 
 1335 /*
 1336  * This cse-specific function (GP_EXT_GUID_SECURITY) performs the access
 1337  * check for determining whether logon access is granted or denied for
 1338  * the {user,domain} tuple specified in the inputs. This function returns EOK
 1339  * to indicate that access is granted. Any other return value indicates that
 1340  * access is denied.
 1341  *
 1342  * The access control algorithm first determines whether the "principal_sids"
 1343  * (i.e. user_sid or group_sids) appear in allowed_sids and denied_sids.
 1344  *
 1345  * For access to be granted, both the "allowed_sids_condition" *and* the
 1346  * "denied_sids_condition" must be met (in all other cases, access is denied).
 1347  * 1) The "allowed_sids_condition" is satisfied if any of the principal_sids
 1348  *    appears in allowed_sids OR if the allowed_sids list is empty
 1349  * 2) The "denied_sids_condition" is satisfied if none of the principal_sids
 1350  *    appear in denied_sids
 1351  *
 1352  * Note that a deployment that is unaware of GPO-based access-control policy
 1353  * settings is unaffected by them (b/c absence of allowed_sids grants access).
 1354  *
 1355  * Note that if a principal_sid appears in both allowed_sids and denied_sids,
 1356  * the "allowed_sids_condition" is met, but the "denied_sids_condition" is not.
 1357  * In other words, Deny takes precedence over Allow.
 1358  */
 1359 static errno_t
 1360 ad_gpo_access_check(TALLOC_CTX *mem_ctx,
 1361                     enum gpo_access_control_mode gpo_mode,
 1362                     enum gpo_map_type gpo_map_type,
 1363                     const char *user,
 1364                     struct sss_domain_info *domain,
 1365                     char **allowed_sids,
 1366                     int allowed_size,
 1367                     char **denied_sids,
 1368                     int denied_size)
 1369 {
 1370     const char *user_sid;
 1371     const char **group_sids;
 1372     int group_size = 0;
 1373     bool access_granted = false;
 1374     bool access_denied = false;
 1375     int ret;
 1376     int j;
 1377 
 1378     DEBUG(SSSDBG_TRACE_FUNC, "RESULTANT POLICY:\n");
 1379     DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %s\n",
 1380           gpo_map_type_string(gpo_map_type));
 1381     DEBUG(SSSDBG_TRACE_FUNC, "allowed_size = %d\n", allowed_size);
 1382     for (j= 0; j < allowed_size; j++) {
 1383         DEBUG(SSSDBG_TRACE_FUNC, "allowed_sids[%d] = %s\n", j, allowed_sids[j]);
 1384     }
 1385 
 1386     DEBUG(SSSDBG_TRACE_FUNC, "denied_size = %d\n", denied_size);
 1387     for (j= 0; j < denied_size; j++) {
 1388         DEBUG(SSSDBG_TRACE_FUNC, " denied_sids[%d] = %s\n", j, denied_sids[j]);
 1389     }
 1390 
 1391     ret = ad_gpo_get_sids(mem_ctx, user, domain, &user_sid,
 1392                           &group_sids, &group_size);
 1393     if (ret != EOK) {
 1394         ret = ERR_NO_SIDS;
 1395         DEBUG(SSSDBG_OP_FAILURE,
 1396               "Unable to retrieve SIDs: [%d](%s)\n", ret, sss_strerror(ret));
 1397         goto done;
 1398     }
 1399 
 1400     DEBUG(SSSDBG_TRACE_FUNC, "CURRENT USER:\n");
 1401     DEBUG(SSSDBG_TRACE_FUNC, "       user_sid = %s\n", user_sid);
 1402 
 1403     for (j= 0; j < group_size; j++) {
 1404         DEBUG(SSSDBG_TRACE_FUNC, "  group_sids[%d] = %s\n", j,
 1405               group_sids[j]);
 1406     }
 1407 
 1408     if (allowed_size == 0) {
 1409         access_granted = true;
 1410     }  else {
 1411         access_granted = check_rights(allowed_sids, allowed_size, user_sid,
 1412                                       group_sids, group_size);
 1413     }
 1414 
 1415     DEBUG(SSSDBG_TRACE_FUNC, "POLICY DECISION:\n");
 1416 
 1417     DEBUG(SSSDBG_TRACE_FUNC, " access_granted = %d\n", access_granted);
 1418 
 1419     access_denied = check_rights(denied_sids, denied_size, user_sid,
 1420                                  group_sids, group_size);
 1421     DEBUG(SSSDBG_TRACE_FUNC, "  access_denied = %d\n", access_denied);
 1422 
 1423     if (access_granted && !access_denied) {
 1424         return EOK;
 1425     } else {
 1426         switch (gpo_mode) {
 1427         case GPO_ACCESS_CONTROL_ENFORCING:
 1428             return ERR_ACCESS_DENIED;
 1429         case GPO_ACCESS_CONTROL_PERMISSIVE:
 1430             DEBUG(SSSDBG_TRACE_FUNC, "access denied: permissive mode\n");
 1431             sss_log_ext(SSS_LOG_WARNING, LOG_AUTHPRIV, "Warning: user would " \
 1432                         "have been denied GPO-based logon access if the " \
 1433                         "ad_gpo_access_control option were set to enforcing " \
 1434                         "mode.");
 1435             return EOK;
 1436         default:
 1437             return EINVAL;
 1438         }
 1439     }
 1440 
 1441  done:
 1442 
 1443     if (ret) {
 1444         DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
 1445     }
 1446 
 1447     return ret;
 1448 }
 1449 
 1450 #define GPO_CHILD_LOG_FILE "gpo_child"
 1451 
 1452 static errno_t gpo_child_init(void)
 1453 {
 1454     return child_debug_init(GPO_CHILD_LOG_FILE, &gpo_child_debug_fd);
 1455 }
 1456 
 1457 /*
 1458  * This function retrieves the raw policy_setting_value for the input key from
 1459  * the GPO_Result object in the sysdb cache. It then parses the raw value and
 1460  * uses the results to populate the output parameters with the sids_list and
 1461  * the size of the sids_list.
 1462  */
 1463 errno_t
 1464 parse_policy_setting_value(TALLOC_CTX *mem_ctx,
 1465                            struct sss_domain_info *domain,
 1466                            const char *key,
 1467                            char ***_sids_list,
 1468                            int *_sids_list_size)
 1469 {
 1470     int ret;
 1471     int i;
 1472     const char *value;
 1473     int sids_list_size;
 1474     char **sids_list = NULL;
 1475 
 1476     ret = sysdb_gpo_get_gpo_result_setting(mem_ctx, domain, key, &value);
 1477     if (ret == ENOENT) {
 1478         DEBUG(SSSDBG_TRACE_FUNC, "No previous GPO result\n");
 1479         value = NULL;
 1480     } else if (ret != EOK) {
 1481         DEBUG(SSSDBG_OP_FAILURE,
 1482               "Cannot retrieve settings from sysdb for key: '%s' [%d][%s].\n",
 1483               key, ret, sss_strerror(ret));
 1484         goto done;
 1485     }
 1486 
 1487     if (value == NULL) {
 1488         DEBUG(SSSDBG_TRACE_FUNC,
 1489               "No value for key [%s] found in gpo result\n", key);
 1490         sids_list_size = 0;
 1491     } else {
 1492         ret = split_on_separator(mem_ctx, value, ',', true, true,
 1493                                  &sids_list, &sids_list_size);
 1494         if (ret != EOK) {
 1495             DEBUG(SSSDBG_OP_FAILURE,
 1496                   "Cannot parse list of sids %s: %d\n", value, ret);
 1497             ret = EINVAL;
 1498             goto done;
 1499         }
 1500 
 1501         for (i = 0; i < sids_list_size; i++) {
 1502             /* remove the asterisk prefix found on sids */
 1503             sids_list[i]++;
 1504         }
 1505     }
 1506 
 1507     *_sids_list = talloc_steal(mem_ctx, sids_list);
 1508     *_sids_list_size = sids_list_size;
 1509 
 1510     ret = EOK;
 1511 
 1512  done:
 1513     return ret;
 1514 }
 1515 
 1516 /*
 1517  * This cse-specific function (GP_EXT_GUID_SECURITY) performs HBAC policy
 1518  * processing and determines whether logon access is granted or denied for
 1519  * the {user,domain} tuple specified in the inputs. This function returns EOK
 1520  * to indicate that access is granted. Any other return value indicates that
 1521  * access is denied.
 1522  *
 1523  * Internally, this function retrieves the allow_value and deny_value for the
 1524  * input gpo_map_type from the GPO Result object in the sysdb cache, parses
 1525  * the values into allow_sids and deny_sids, and executes the access control
 1526  * algorithm which compares the allow_sids and deny_sids against the user_sid
 1527  * and group_sids for the input user.
 1528  */
 1529 static errno_t
 1530 ad_gpo_perform_hbac_processing(TALLOC_CTX *mem_ctx,
 1531                                enum gpo_access_control_mode gpo_mode,
 1532                                enum gpo_map_type gpo_map_type,
 1533                                const char *user,
 1534                                struct sss_domain_info *user_domain,
 1535                                struct sss_domain_info *host_domain)
 1536 {
 1537     int ret;
 1538     const char *allow_key = NULL;
 1539     char **allow_sids;
 1540     int allow_size ;
 1541     const char *deny_key = NULL;
 1542     char **deny_sids;
 1543     int deny_size;
 1544 
 1545     allow_key = gpo_map_option_entries[gpo_map_type].allow_key;
 1546     DEBUG(SSSDBG_TRACE_ALL, "allow_key: %s\n", allow_key);
 1547     deny_key = gpo_map_option_entries[gpo_map_type].deny_key;
 1548     DEBUG(SSSDBG_TRACE_ALL, "deny_key: %s\n", deny_key);
 1549 
 1550     ret = parse_policy_setting_value(mem_ctx, host_domain, allow_key,
 1551                                      &allow_sids, &allow_size);
 1552     if (ret != EOK) {
 1553         DEBUG(SSSDBG_OP_FAILURE,
 1554               "parse_policy_setting_value failed for key %s: [%d](%s)\n",
 1555               allow_key, ret, sss_strerror(ret));
 1556         ret = EINVAL;
 1557         goto done;
 1558     }
 1559 
 1560     ret = parse_policy_setting_value(mem_ctx, host_domain, deny_key,
 1561                                      &deny_sids, &deny_size);
 1562     if (ret != EOK) {
 1563         DEBUG(SSSDBG_OP_FAILURE,
 1564               "parse_policy_setting_value failed for key %s: [%d](%s)\n",
 1565               deny_key, ret, sss_strerror(ret));
 1566         ret = EINVAL;
 1567         goto done;
 1568     }
 1569 
 1570     /* perform access check with the final resultant allow_sids and deny_sids */
 1571     ret = ad_gpo_access_check(mem_ctx, gpo_mode, gpo_map_type, user,
 1572                               user_domain, allow_sids, allow_size, deny_sids,
 1573                               deny_size);
 1574 
 1575     if (ret != EOK) {
 1576         DEBUG(SSSDBG_OP_FAILURE,
 1577               "GPO access check failed: [%d](%s)\n",
 1578               ret, sss_strerror(ret));
 1579         goto done;
 1580     }
 1581 
 1582  done:
 1583     return ret;
 1584 }
 1585 
 1586 /* == ad_gpo_access_send/recv implementation ================================*/
 1587 
 1588 struct ad_gpo_access_state {
 1589     struct tevent_context *ev;
 1590     struct ldb_context *ldb_ctx;
 1591     struct ad_access_ctx *access_ctx;
 1592     enum gpo_access_control_mode gpo_mode;
 1593     bool gpo_implicit_deny;
 1594     enum gpo_map_type gpo_map_type;
 1595     struct sdap_id_conn_ctx *conn;
 1596     struct sdap_id_op *sdap_op;
 1597     char *server_hostname;
 1598     struct sdap_options *opts;
 1599     int timeout;
 1600     struct sss_domain_info *user_domain;
 1601     struct sss_domain_info *host_domain;
 1602     const char *user;
 1603     int gpo_timeout_option;
 1604     const char *ad_hostname;
 1605     const char *target_dn;
 1606     struct gp_gpo **dacl_filtered_gpos;
 1607     int num_dacl_filtered_gpos;
 1608     struct gp_gpo **cse_filtered_gpos;
 1609     int num_cse_filtered_gpos;
 1610     int cse_gpo_index;
 1611 };
 1612 
 1613 static void ad_gpo_connect_done(struct tevent_req *subreq);
 1614 static void ad_gpo_target_dn_retrieval_done(struct tevent_req *subreq);
 1615 static void ad_gpo_process_som_done(struct tevent_req *subreq);
 1616 static void ad_gpo_process_gpo_done(struct tevent_req *subreq);
 1617 
 1618 static errno_t ad_gpo_cse_step(struct tevent_req *req);
 1619 static void ad_gpo_cse_done(struct tevent_req *subreq);
 1620 
 1621 struct tevent_req *
 1622 ad_gpo_access_send(TALLOC_CTX *mem_ctx,
 1623                    struct tevent_context *ev,
 1624                    struct sss_domain_info *domain,
 1625                    struct ad_access_ctx *ctx,
 1626                    const char *user,
 1627                    const char *service)
 1628 {
 1629     struct tevent_req *req;
 1630     struct tevent_req *subreq;
 1631     struct ad_gpo_access_state *state;
 1632     errno_t ret;
 1633     int hret;
 1634     hash_key_t key;
 1635     hash_value_t val;
 1636     enum gpo_map_type gpo_map_type;
 1637 
 1638     /* setup logging for gpo child */
 1639     gpo_child_init();
 1640 
 1641     req = tevent_req_create(mem_ctx, &state, struct ad_gpo_access_state);
 1642     if (req == NULL) {
 1643         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 1644         return NULL;
 1645     }
 1646 
 1647     /* determine service's option_type (e.g. interactive, network, etc) */
 1648     key.type = HASH_KEY_STRING;
 1649     key.str = talloc_strdup(state, service);
 1650 
 1651     hret = hash_lookup(ctx->gpo_map_options_table, &key, &val);
 1652     if (hret != HASH_SUCCESS && hret != HASH_ERROR_KEY_NOT_FOUND) {
 1653         DEBUG(SSSDBG_OP_FAILURE, "Error checking hash table: [%s]\n",
 1654               hash_error_string(hret));
 1655         ret = EINVAL;
 1656         goto immediately;
 1657     }
 1658 
 1659     /* if service isn't mapped, map it to value of ad_gpo_default_right option */
 1660     if (hret == HASH_ERROR_KEY_NOT_FOUND) {
 1661         DEBUG(SSSDBG_TRACE_FUNC,
 1662               "Configuration hint: PAM service '%s' is not mapped to any Group"
 1663               " Policy rule. If you plan to use this PAM service it is "
 1664               "recommended to use the ad_gpo_map_* family of options to map "
 1665               "this PAM service to a Group Policy rule. PAM services not "
 1666               "present in any map will fall back to value set in "
 1667               "ad_gpo_default_right, which is currently set to %s (see manual "
 1668               "pages 'man sssd-ad' for more details).\n", service,
 1669               gpo_map_type_string(ctx->gpo_default_right));
 1670         gpo_map_type = ctx->gpo_default_right;
 1671     } else {
 1672         gpo_map_type = (enum gpo_map_type) val.i;
 1673     }
 1674 
 1675     DEBUG(SSSDBG_TRACE_FUNC, "service %s maps to %s\n", service,
 1676           gpo_map_type_string(gpo_map_type));
 1677 
 1678     if (gpo_map_type == GPO_MAP_PERMIT) {
 1679         ret = EOK;
 1680         goto immediately;
 1681     }
 1682 
 1683     if (gpo_map_type == GPO_MAP_DENY) {
 1684         switch (ctx->gpo_access_control_mode) {
 1685         case GPO_ACCESS_CONTROL_ENFORCING:
 1686             ret = ERR_ACCESS_DENIED;
 1687             goto immediately;
 1688         case GPO_ACCESS_CONTROL_PERMISSIVE:
 1689             DEBUG(SSSDBG_TRACE_FUNC, "access denied: permissive mode\n");
 1690             sss_log_ext(SSS_LOG_WARNING, LOG_AUTHPRIV, "Warning: user would " \
 1691                         "have been denied GPO-based logon access if the " \
 1692                         "ad_gpo_access_control option were set to enforcing " \
 1693                         "mode.");
 1694             ret = EOK;
 1695             goto immediately;
 1696         default:
 1697             ret = EINVAL;
 1698             goto immediately;
 1699         }
 1700     }
 1701 
 1702     /* GPO Operations all happen against the enrolled domain,
 1703      * not the user's domain (which may be a trusted realm)
 1704      */
 1705     state->user_domain = domain;
 1706     state->host_domain = get_domains_head(domain);
 1707 
 1708     state->gpo_map_type = gpo_map_type;
 1709     state->dacl_filtered_gpos = NULL;
 1710     state->num_dacl_filtered_gpos = 0;
 1711     state->cse_filtered_gpos = NULL;
 1712     state->num_cse_filtered_gpos = 0;
 1713     state->cse_gpo_index = 0;
 1714     state->ev = ev;
 1715     state->user = user;
 1716     state->ldb_ctx = sysdb_ctx_get_ldb(state->host_domain->sysdb);
 1717     state->gpo_mode = ctx->gpo_access_control_mode;
 1718     state->gpo_timeout_option = ctx->gpo_cache_timeout;
 1719     state->ad_hostname = dp_opt_get_string(ctx->ad_options, AD_HOSTNAME);
 1720     state->gpo_implicit_deny = dp_opt_get_bool(ctx->ad_options,
 1721                                                AD_GPO_IMPLICIT_DENY);
 1722     state->access_ctx = ctx;
 1723     state->opts = ctx->sdap_access_ctx->id_ctx->opts;
 1724     state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
 1725     state->conn = ad_get_dom_ldap_conn(ctx->ad_id_ctx, state->host_domain);
 1726     state->sdap_op = sdap_id_op_create(state, state->conn->conn_cache);
 1727     if (state->sdap_op == NULL) {
 1728         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
 1729         ret = ENOMEM;
 1730         goto immediately;
 1731     }
 1732 
 1733     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
 1734     if (subreq == NULL) {
 1735         DEBUG(SSSDBG_OP_FAILURE,
 1736               "sdap_id_op_connect_send failed: [%d](%s)\n",
 1737                ret, sss_strerror(ret));
 1738         goto immediately;
 1739     }
 1740     tevent_req_set_callback(subreq, ad_gpo_connect_done, req);
 1741 
 1742     return req;
 1743 
 1744 immediately:
 1745 
 1746     if (ret == EOK) {
 1747         tevent_req_done(req);
 1748     } else {
 1749         tevent_req_error(req, ret);
 1750     }
 1751 
 1752     tevent_req_post(req, ev);
 1753     return req;
 1754 }
 1755 
 1756 static errno_t
 1757 process_offline_gpos(TALLOC_CTX *mem_ctx,
 1758                      const char *user,
 1759                      enum gpo_access_control_mode gpo_mode,
 1760                      struct sss_domain_info *user_domain,
 1761                      struct sss_domain_info *host_domain,
 1762                      enum gpo_map_type gpo_map_type)
 1763 
 1764 {
 1765     errno_t ret;
 1766 
 1767     ret = ad_gpo_perform_hbac_processing(mem_ctx,
 1768                                          gpo_mode,
 1769                                          gpo_map_type,
 1770                                          user,
 1771                                          user_domain,
 1772                                          host_domain);
 1773     if (ret != EOK) {
 1774         DEBUG(SSSDBG_OP_FAILURE, "HBAC processing failed: [%d](%s}\n",
 1775               ret, sss_strerror(ret));
 1776         goto done;
 1777     }
 1778 
 1779     /* we have successfully processed all offline gpos */
 1780     ret = EOK;
 1781 
 1782  done:
 1783     return ret;
 1784 }
 1785 
 1786 static void
 1787 ad_gpo_connect_done(struct tevent_req *subreq)
 1788 {
 1789     struct tevent_req *req;
 1790     struct ad_gpo_access_state *state;
 1791     char *filter;
 1792     const char *sam_account_name;
 1793     char *domain_dn;
 1794     int dp_error;
 1795     errno_t ret;
 1796     char *server_uri;
 1797     LDAPURLDesc *lud;
 1798 
 1799     const char *attrs[] = {AD_AT_DN, AD_AT_UAC, NULL};
 1800 
 1801     req = tevent_req_callback_data(subreq, struct tevent_req);
 1802     state = tevent_req_data(req, struct ad_gpo_access_state);
 1803 
 1804     ret = sdap_id_op_connect_recv(subreq, &dp_error);
 1805     talloc_zfree(subreq);
 1806 
 1807     if (ret != EOK) {
 1808         if (dp_error != DP_ERR_OFFLINE) {
 1809             DEBUG(SSSDBG_OP_FAILURE,
 1810                   "Failed to connect to AD server: [%d](%s)\n",
 1811                   ret, sss_strerror(ret));
 1812             goto done;
 1813         } else {
 1814             DEBUG(SSSDBG_TRACE_FUNC, "Preparing for offline operation.\n");
 1815             ret = process_offline_gpos(state,
 1816                                        state->user,
 1817                                        state->gpo_mode,
 1818                                        state->user_domain,
 1819                                        state->host_domain,
 1820                                        state->gpo_map_type);
 1821 
 1822             if (ret == EOK) {
 1823                 DEBUG(SSSDBG_TRACE_FUNC, "process_offline_gpos succeeded\n");
 1824                 tevent_req_done(req);
 1825                 goto done;
 1826             } else {
 1827                 DEBUG(SSSDBG_OP_FAILURE,
 1828                       "process_offline_gpos failed [%d](%s)\n",
 1829                       ret, sss_strerror(ret));
 1830                 goto done;
 1831             }
 1832         }
 1833     }
 1834 
 1835     /* extract server_hostname from server_uri */
 1836     server_uri = state->conn->service->uri;
 1837     ret = ldap_url_parse(server_uri, &lud);
 1838     if (ret != LDAP_SUCCESS) {
 1839         DEBUG(SSSDBG_CRIT_FAILURE,
 1840               "Failed to parse ldap URI (%s)!\n", server_uri);
 1841         ret = EINVAL;
 1842         goto done;
 1843     }
 1844 
 1845     if (lud->lud_host == NULL) {
 1846         DEBUG(SSSDBG_CRIT_FAILURE,
 1847               "The LDAP URI (%s) did not contain a host name\n", server_uri);
 1848         ldap_free_urldesc(lud);
 1849         ret = EINVAL;
 1850         goto done;
 1851     }
 1852 
 1853     state->server_hostname = talloc_strdup(state, lud->lud_host);
 1854     ldap_free_urldesc(lud);
 1855     if (!state->server_hostname) {
 1856         ret = ENOMEM;
 1857         goto done;
 1858     }
 1859     DEBUG(SSSDBG_TRACE_ALL, "server_hostname from uri: %s\n",
 1860           state->server_hostname);
 1861 
 1862     /* SDAP_SASL_AUTHID contains the name used for kinit and SASL bind which
 1863      * in the AD case is the NetBIOS name. */
 1864     sam_account_name = dp_opt_get_string(state->opts->basic, SDAP_SASL_AUTHID);
 1865     if (sam_account_name == NULL) {
 1866         ret = ENOMEM;
 1867         goto done;
 1868     }
 1869 
 1870     DEBUG(SSSDBG_TRACE_FUNC, "sam_account_name is %s\n", sam_account_name);
 1871 
 1872     /* Convert the domain name into domain DN */
 1873     ret = domain_to_basedn(state, state->host_domain->name, &domain_dn);
 1874     if (ret != EOK) {
 1875         DEBUG(SSSDBG_OP_FAILURE,
 1876               "Cannot convert domain name [%s] to base DN [%d]: %s\n",
 1877                state->host_domain->name, ret, sss_strerror(ret));
 1878         goto done;
 1879     }
 1880 
 1881     /* SDAP_OC_USER objectclass covers both users and computers */
 1882     filter = talloc_asprintf(state,
 1883                              "(&(objectclass=%s)(%s=%s))",
 1884                              state->opts->user_map[SDAP_OC_USER].name,
 1885                              state->opts->user_map[SDAP_AT_USER_NAME].name,
 1886                              sam_account_name);
 1887     if (filter == NULL) {
 1888         ret = ENOMEM;
 1889         goto done;
 1890     }
 1891 
 1892     subreq = sdap_get_generic_send(state, state->ev, state->opts,
 1893                                    sdap_id_op_handle(state->sdap_op),
 1894                                    domain_dn, LDAP_SCOPE_SUBTREE,
 1895                                    filter, attrs, NULL, 0,
 1896                                    state->timeout,
 1897                                    false);
 1898 
 1899     if (subreq == NULL) {
 1900         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
 1901         ret = EIO;
 1902         goto done;
 1903     }
 1904 
 1905     tevent_req_set_callback(subreq, ad_gpo_target_dn_retrieval_done, req);
 1906 
 1907     ret = EOK;
 1908 
 1909  done:
 1910 
 1911     if (ret != EOK) {
 1912         tevent_req_error(req, ret);
 1913     }
 1914 }
 1915 
 1916 static void
 1917 ad_gpo_target_dn_retrieval_done(struct tevent_req *subreq)
 1918 {
 1919     struct tevent_req *req;
 1920     struct ad_gpo_access_state *state;
 1921     int ret;
 1922     int dp_error;
 1923     size_t reply_count;
 1924     struct sysdb_attrs **reply;
 1925     const char *target_dn = NULL;
 1926     uint32_t uac;
 1927 
 1928     req = tevent_req_callback_data(subreq, struct tevent_req);
 1929     state = tevent_req_data(req, struct ad_gpo_access_state);
 1930     ret = sdap_get_generic_recv(subreq, state,
 1931                                 &reply_count, &reply);
 1932     talloc_zfree(subreq);
 1933     if (ret != EOK) {
 1934         ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 1935         if (ret == EAGAIN && dp_error == DP_ERR_OFFLINE) {
 1936             DEBUG(SSSDBG_TRACE_FUNC, "Preparing for offline operation.\n");
 1937             ret = process_offline_gpos(state,
 1938                                        state->user,
 1939                                        state->gpo_mode,
 1940                                        state->user_domain,
 1941                                        state->host_domain,
 1942                                        state->gpo_map_type);
 1943 
 1944             if (ret == EOK) {
 1945                 DEBUG(SSSDBG_TRACE_FUNC, "process_offline_gpos succeeded\n");
 1946                 tevent_req_done(req);
 1947                 goto done;
 1948             } else {
 1949                 DEBUG(SSSDBG_OP_FAILURE,
 1950                       "process_offline_gpos failed [%d](%s)\n",
 1951                       ret, sss_strerror(ret));
 1952                 goto done;
 1953             }
 1954         }
 1955 
 1956         DEBUG(SSSDBG_OP_FAILURE,
 1957               "Unable to get policy target's DN: [%d](%s)\n",
 1958                ret, sss_strerror(ret));
 1959         ret = ENOENT;
 1960         goto done;
 1961     }
 1962 
 1963     /* make sure there is only one non-NULL reply returned */
 1964 
 1965     if (reply_count < 1) {
 1966         DEBUG(SSSDBG_OP_FAILURE, "No DN retrieved for policy target.\n");
 1967         ret = ENOENT;
 1968         goto done;
 1969     } else if (reply_count > 1) {
 1970         DEBUG(SSSDBG_OP_FAILURE, "Multiple replies for policy target\n");
 1971         ret = ERR_INTERNAL;
 1972         goto done;
 1973     } else if (reply == NULL) {
 1974         DEBUG(SSSDBG_OP_FAILURE, "reply_count is 1, but reply is NULL\n");
 1975         ret = ERR_INTERNAL;
 1976         goto done;
 1977     }
 1978 
 1979     /* reply[0] holds requested attributes of single reply */
 1980     ret = sysdb_attrs_get_string(reply[0], AD_AT_DN, &target_dn);
 1981     if (ret != EOK) {
 1982         DEBUG(SSSDBG_OP_FAILURE,
 1983               "sysdb_attrs_get_string failed: [%d](%s)\n",
 1984                ret, sss_strerror(ret));
 1985         goto done;
 1986     }
 1987     state->target_dn = talloc_steal(state, target_dn);
 1988     if (state->target_dn == NULL) {
 1989         ret = ENOMEM;
 1990         goto done;
 1991     }
 1992 
 1993     ret = sysdb_attrs_get_uint32_t(reply[0], AD_AT_UAC, &uac);
 1994     if (ret != EOK) {
 1995         DEBUG(SSSDBG_OP_FAILURE,
 1996               "sysdb_attrs_get_uint32_t failed: [%d](%s)\n",
 1997                ret, sss_strerror(ret));
 1998         goto done;
 1999     }
 2000 
 2001     /* we only support computer policy targets, not users */
 2002     if (!(uac & UAC_WORKSTATION_TRUST_ACCOUNT ||
 2003           uac & UAC_SERVER_TRUST_ACCOUNT)) {
 2004         DEBUG(SSSDBG_OP_FAILURE,
 2005               "Invalid userAccountControl (%x) value for machine account.\n",
 2006               uac);
 2007         ret = EINVAL;
 2008         goto done;
 2009     }
 2010 
 2011     subreq = ad_gpo_process_som_send(state,
 2012                                      state->ev,
 2013                                      state->conn,
 2014                                      state->ldb_ctx,
 2015                                      state->sdap_op,
 2016                                      state->opts,
 2017                                      state->access_ctx->ad_options,
 2018                                      state->timeout,
 2019                                      state->target_dn,
 2020                                      state->host_domain->name);
 2021     if (subreq == NULL) {
 2022         ret = ENOMEM;
 2023         goto done;
 2024     }
 2025 
 2026     tevent_req_set_callback(subreq, ad_gpo_process_som_done, req);
 2027 
 2028     ret = EOK;
 2029 
 2030  done:
 2031 
 2032     if (ret != EOK) {
 2033         tevent_req_error(req, ret);
 2034     }
 2035 }
 2036 
 2037 static void
 2038 ad_gpo_process_som_done(struct tevent_req *subreq)
 2039 {
 2040     struct tevent_req *req;
 2041     struct ad_gpo_access_state *state;
 2042     int ret;
 2043     struct gp_som **som_list;
 2044 
 2045     req = tevent_req_callback_data(subreq, struct tevent_req);
 2046     state = tevent_req_data(req, struct ad_gpo_access_state);
 2047     ret = ad_gpo_process_som_recv(subreq, state, &som_list);
 2048     talloc_zfree(subreq);
 2049 
 2050     if (ret != EOK) {
 2051         DEBUG(SSSDBG_OP_FAILURE,
 2052               "Unable to get som list: [%d](%s)\n",
 2053                ret, sss_strerror(ret));
 2054         ret = ENOENT;
 2055         goto done;
 2056     }
 2057 
 2058     subreq = ad_gpo_process_gpo_send(state,
 2059                                      state->ev,
 2060                                      state->sdap_op,
 2061                                      state->opts,
 2062                                      state->server_hostname,
 2063                                      state->host_domain,
 2064                                      state->access_ctx,
 2065                                      state->timeout,
 2066                                      som_list);
 2067     if (subreq == NULL) {
 2068         ret = ENOMEM;
 2069         goto done;
 2070     }
 2071 
 2072     tevent_req_set_callback(subreq, ad_gpo_process_gpo_done, req);
 2073 
 2074     ret = EOK;
 2075 
 2076  done:
 2077 
 2078     if (ret != EOK) {
 2079         tevent_req_error(req, ret);
 2080     }
 2081 }
 2082 
 2083 /*
 2084  * This function retrieves a list of candidate_gpos and potentially reduces it
 2085  * to a list of dacl_filtered_gpos, based on each GPO's DACL.
 2086  *
 2087  * This function then takes the list of dacl_filtered_gpos and potentially
 2088  * reduces it to a list of cse_filtered_gpos, based on whether each GPO's list
 2089  * of cse_guids includes the "SecuritySettings" CSE GUID (used for HBAC).
 2090  *
 2091  * Ultimately, this function then sends each cse_filtered_gpo to the gpo_child,
 2092  * which retrieves the GPT.INI and policy files (as needed). Once all files
 2093  * have been downloaded, the ad_gpo_cse_done function performs HBAC processing.
 2094  */
 2095 static void
 2096 ad_gpo_process_gpo_done(struct tevent_req *subreq)
 2097 {
 2098     struct tevent_req *req;
 2099     struct ad_gpo_access_state *state;
 2100     int ret;
 2101     int dp_error;
 2102     struct gp_gpo **candidate_gpos = NULL;
 2103     int num_candidate_gpos = 0;
 2104     int i = 0;
 2105     const char **cse_filtered_gpo_guids;
 2106 
 2107     req = tevent_req_callback_data(subreq, struct tevent_req);
 2108     state = tevent_req_data(req, struct ad_gpo_access_state);
 2109     ret = ad_gpo_process_gpo_recv(subreq, state, &candidate_gpos,
 2110                                   &num_candidate_gpos);
 2111 
 2112     talloc_zfree(subreq);
 2113 
 2114     ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 2115 
 2116     if (ret != EOK && ret != ENOENT) {
 2117         DEBUG(SSSDBG_OP_FAILURE,
 2118               "Unable to get GPO list: [%d](%s)\n",
 2119               ret, sss_strerror(ret));
 2120         goto done;
 2121     } else if (ret == ENOENT) {
 2122         DEBUG(SSSDBG_TRACE_FUNC,
 2123               "No GPOs found that apply to this system.\n");
 2124         /*
 2125          * Delete the result object list, since there are no
 2126          * GPOs to include in it.
 2127          */
 2128         ret = sysdb_gpo_delete_gpo_result_object(state, state->host_domain);
 2129         if (ret != EOK) {
 2130             switch (ret) {
 2131             case ENOENT:
 2132                 DEBUG(SSSDBG_TRACE_FUNC, "No GPO Result available in cache\n");
 2133                 break;
 2134             default:
 2135                 DEBUG(SSSDBG_FATAL_FAILURE,
 2136                       "Could not delete GPO Result from cache: [%s]\n",
 2137                       sss_strerror(ret));
 2138                 goto done;
 2139             }
 2140         }
 2141 
 2142         ret = EOK;
 2143         goto done;
 2144     }
 2145 
 2146     ret = ad_gpo_filter_gpos_by_dacl(state, state->user, state->user_domain,
 2147                                      state->opts->idmap_ctx->map,
 2148                                      candidate_gpos, num_candidate_gpos,
 2149                                      &state->dacl_filtered_gpos,
 2150                                      &state->num_dacl_filtered_gpos);
 2151     if (ret != EOK) {
 2152         DEBUG(SSSDBG_OP_FAILURE,
 2153               "Unable to filter GPO list by DACL: [%d](%s)\n",
 2154               ret, sss_strerror(ret));
 2155         goto done;
 2156     }
 2157 
 2158     if (state->dacl_filtered_gpos[0] == NULL) {
 2159         /* since no applicable gpos were found, there is nothing to enforce */
 2160         DEBUG(SSSDBG_TRACE_FUNC,
 2161               "no applicable gpos found after dacl filtering\n");
 2162 
 2163         /*
 2164          * Delete the result object list, since there are no
 2165          * GPOs to include in it.
 2166          */
 2167         ret = sysdb_gpo_delete_gpo_result_object(state, state->host_domain);
 2168         if (ret != EOK) {
 2169             switch (ret) {
 2170             case ENOENT:
 2171                 DEBUG(SSSDBG_TRACE_FUNC, "No GPO Result available in cache\n");
 2172                 break;
 2173             default:
 2174                 DEBUG(SSSDBG_FATAL_FAILURE,
 2175                       "Could not delete GPO Result from cache: [%s]\n",
 2176                       sss_strerror(ret));
 2177                 goto done;
 2178             }
 2179         }
 2180 
 2181         if (state->gpo_implicit_deny == true) {
 2182             DEBUG(SSSDBG_TRACE_FUNC,
 2183                   "No applicable GPOs have been found and ad_gpo_implicit_deny"
 2184                   " is set to 'true'. The user will be denied access.\n");
 2185             ret = ERR_ACCESS_DENIED;
 2186         } else {
 2187             ret = EOK;
 2188         }
 2189 
 2190         goto done;
 2191     }
 2192 
 2193     for (i = 0; i < state->num_dacl_filtered_gpos; i++) {
 2194         DEBUG(SSSDBG_TRACE_FUNC, "dacl_filtered_gpos[%d]->gpo_guid is %s\n", i,
 2195               state->dacl_filtered_gpos[i]->gpo_guid);
 2196     }
 2197 
 2198     ret = ad_gpo_filter_gpos_by_cse_guid(state,
 2199                                          GP_EXT_GUID_SECURITY,
 2200                                          state->dacl_filtered_gpos,
 2201                                          state->num_dacl_filtered_gpos,
 2202                                          &state->cse_filtered_gpos,
 2203                                          &state->num_cse_filtered_gpos);
 2204 
 2205     if (ret != EOK) {
 2206         DEBUG(SSSDBG_OP_FAILURE,
 2207               "Unable to filter GPO list by CSE_GUID: [%d](%s)\n",
 2208                ret, sss_strerror(ret));
 2209         goto done;
 2210     }
 2211 
 2212     if (state->cse_filtered_gpos[0] == NULL) {
 2213         /* no gpos contain "SecuritySettings" cse_guid, nothing to enforce */
 2214         DEBUG(SSSDBG_TRACE_FUNC,
 2215               "no applicable gpos found after cse_guid filtering\n");
 2216         ret = EOK;
 2217         goto done;
 2218     }
 2219 
 2220     /* we create and populate an array of applicable gpo-guids */
 2221     cse_filtered_gpo_guids =
 2222         talloc_array(state, const char *, state->num_cse_filtered_gpos);
 2223     if (cse_filtered_gpo_guids == NULL) {
 2224         ret = ENOMEM;
 2225         goto done;
 2226     }
 2227 
 2228     for (i = 0; i < state->num_cse_filtered_gpos; i++) {
 2229         DEBUG(SSSDBG_TRACE_FUNC, "cse_filtered_gpos[%d]->gpo_guid is %s\n", i,
 2230                                   state->cse_filtered_gpos[i]->gpo_guid);
 2231         cse_filtered_gpo_guids[i] = talloc_steal(cse_filtered_gpo_guids,
 2232                                                  state->cse_filtered_gpos[i]->gpo_guid);
 2233         if (cse_filtered_gpo_guids[i] == NULL) {
 2234             ret = ENOMEM;
 2235             goto done;
 2236         }
 2237     }
 2238 
 2239     DEBUG(SSSDBG_TRACE_FUNC, "num_cse_filtered_gpos: %d\n",
 2240           state->num_cse_filtered_gpos);
 2241 
 2242     /*
 2243      * before we start processing each gpo, we delete the GPO Result object
 2244      * from the sysdb cache so that any previous policy settings are cleared;
 2245      * subsequent functions will add the GPO Result object (and populate it
 2246      * with resultant policy settings) for this policy application
 2247      */
 2248     ret = sysdb_gpo_delete_gpo_result_object(state, state->host_domain);
 2249     if (ret != EOK) {
 2250         switch (ret) {
 2251         case ENOENT:
 2252             DEBUG(SSSDBG_TRACE_FUNC, "No GPO Result available in cache\n");
 2253             break;
 2254         default:
 2255             DEBUG(SSSDBG_FATAL_FAILURE,
 2256                   "Could not delete GPO Result from cache: [%s]\n",
 2257                   sss_strerror(ret));
 2258             goto done;
 2259         }
 2260     }
 2261 
 2262     ret = ad_gpo_cse_step(req);
 2263 
 2264  done:
 2265 
 2266     if (ret == EOK) {
 2267         tevent_req_done(req);
 2268     } else if (ret != EAGAIN) {
 2269         tevent_req_error(req, ret);
 2270     }
 2271 }
 2272 
 2273 static errno_t
 2274 ad_gpo_cse_step(struct tevent_req *req)
 2275 {
 2276     struct tevent_req *subreq;
 2277     struct ad_gpo_access_state *state;
 2278     int i = 0;
 2279     struct ldb_result *res;
 2280     errno_t ret;
 2281     bool send_to_child = true;
 2282     int cached_gpt_version = 0;
 2283     time_t policy_file_timeout = 0;
 2284 
 2285     state = tevent_req_data(req, struct ad_gpo_access_state);
 2286 
 2287     struct gp_gpo *cse_filtered_gpo =
 2288         state->cse_filtered_gpos[state->cse_gpo_index];
 2289 
 2290     /* cse_filtered_gpo is NULL after all GPO policy files have been downloaded */
 2291     if (cse_filtered_gpo == NULL) return EOK;
 2292 
 2293     DEBUG(SSSDBG_TRACE_FUNC, "cse filtered_gpos[%d]->gpo_guid is %s\n",
 2294           state->cse_gpo_index, cse_filtered_gpo->gpo_guid);
 2295     for (i = 0; i < cse_filtered_gpo->num_gpo_cse_guids; i++) {
 2296         DEBUG(SSSDBG_TRACE_ALL,
 2297               "cse_filtered_gpos[%d]->gpo_cse_guids[%d]->gpo_guid is %s\n",
 2298               state->cse_gpo_index, i, cse_filtered_gpo->gpo_cse_guids[i]);
 2299     }
 2300 
 2301     DEBUG(SSSDBG_TRACE_FUNC, "smb_server: %s\n", cse_filtered_gpo->smb_server);
 2302     DEBUG(SSSDBG_TRACE_FUNC, "smb_share: %s\n", cse_filtered_gpo->smb_share);
 2303     DEBUG(SSSDBG_TRACE_FUNC, "smb_path: %s\n", cse_filtered_gpo->smb_path);
 2304     DEBUG(SSSDBG_TRACE_FUNC, "gpo_guid: %s\n", cse_filtered_gpo->gpo_guid);
 2305 
 2306     cse_filtered_gpo->policy_filename =
 2307         talloc_asprintf(state,
 2308                         GPO_CACHE_PATH"%s%s",
 2309                         cse_filtered_gpo->smb_path,
 2310                         GP_EXT_GUID_SECURITY_SUFFIX);
 2311     if (cse_filtered_gpo->policy_filename == NULL) {
 2312         return ENOMEM;
 2313     }
 2314 
 2315     /* retrieve gpo cache entry; set cached_gpt_version to -1 if unavailable */
 2316     DEBUG(SSSDBG_TRACE_FUNC, "retrieving GPO from cache [%s]\n",
 2317           cse_filtered_gpo->gpo_guid);
 2318     ret = sysdb_gpo_get_gpo_by_guid(state,
 2319                                     state->host_domain,
 2320                                     cse_filtered_gpo->gpo_guid,
 2321                                     &res);
 2322     if (ret == EOK) {
 2323         /*
 2324          * Note: if the timeout is valid, then we can later avoid downloading
 2325          * the GPT.INI file, as well as any policy files (i.e. we don't need
 2326          * to interact with the gpo_child at all). However, even if the timeout
 2327          * is not valid, while we will have to interact with the gpo child to
 2328          * download the GPT.INI file, we may still be able to avoid downloading
 2329          * the policy files (if the cached_gpt_version is the same as the
 2330          * GPT.INI version). In other words, the timeout is *not* an expiration
 2331          * for the entire cache entry; the cached_gpt_version never expires.
 2332          */
 2333 
 2334         cached_gpt_version = ldb_msg_find_attr_as_int(res->msgs[0],
 2335                                                       SYSDB_GPO_VERSION_ATTR,
 2336                                                       0);
 2337 
 2338         policy_file_timeout = ldb_msg_find_attr_as_uint64
 2339             (res->msgs[0], SYSDB_GPO_TIMEOUT_ATTR, 0);
 2340 
 2341         if (policy_file_timeout >= time(NULL)) {
 2342             send_to_child = false;
 2343         }
 2344     } else if (ret == ENOENT) {
 2345         DEBUG(SSSDBG_TRACE_FUNC, "ENOENT\n");
 2346         cached_gpt_version = -1;
 2347     } else {
 2348         DEBUG(SSSDBG_FATAL_FAILURE, "Could not read GPO from cache: [%s]\n",
 2349               sss_strerror(ret));
 2350         return ret;
 2351     }
 2352 
 2353     DEBUG(SSSDBG_TRACE_FUNC, "send_to_child: %d\n", send_to_child);
 2354     DEBUG(SSSDBG_TRACE_FUNC, "cached_gpt_version: %d\n", cached_gpt_version);
 2355 
 2356     cse_filtered_gpo->send_to_child = send_to_child;
 2357 
 2358     subreq = ad_gpo_process_cse_send(state,
 2359                                      state->ev,
 2360                                      send_to_child,
 2361                                      state->host_domain,
 2362                                      cse_filtered_gpo->gpo_guid,
 2363                                      cse_filtered_gpo->smb_server,
 2364                                      cse_filtered_gpo->smb_share,
 2365                                      cse_filtered_gpo->smb_path,
 2366                                      GP_EXT_GUID_SECURITY_SUFFIX,
 2367                                      cached_gpt_version,
 2368                                      state->gpo_timeout_option);
 2369 
 2370     tevent_req_set_callback(subreq, ad_gpo_cse_done, req);
 2371     return EAGAIN;
 2372 }
 2373 
 2374 /*
 2375  * This cse-specific function (GP_EXT_GUID_SECURITY) increments the
 2376  * cse_gpo_index until the policy settings for all applicable GPOs have been
 2377  * stored as part of the GPO Result object in the sysdb cache. Once all
 2378  * GPOs have been processed, this functions performs HBAC processing by
 2379  * comparing the resultant policy setting values in the GPO Result object
 2380  * with the user_sid/group_sids of interest.
 2381  */
 2382 static void
 2383 ad_gpo_cse_done(struct tevent_req *subreq)
 2384 {
 2385     struct tevent_req *req;
 2386     struct ad_gpo_access_state *state;
 2387     int ret;
 2388 
 2389     req = tevent_req_callback_data(subreq, struct tevent_req);
 2390     state = tevent_req_data(req, struct ad_gpo_access_state);
 2391 
 2392     struct gp_gpo *cse_filtered_gpo =
 2393         state->cse_filtered_gpos[state->cse_gpo_index];
 2394 
 2395     const char *gpo_guid = cse_filtered_gpo->gpo_guid;
 2396 
 2397     DEBUG(SSSDBG_TRACE_FUNC, "gpo_guid: %s\n", gpo_guid);
 2398 
 2399     ret = ad_gpo_process_cse_recv(subreq);
 2400 
 2401     talloc_zfree(subreq);
 2402 
 2403     if (ret != EOK) {
 2404         DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve policy data: [%d](%s}\n",
 2405               ret, sss_strerror(ret));
 2406         goto done;
 2407     }
 2408 
 2409     /*
 2410      * now that the policy file for this gpo have been downloaded to the
 2411      * GPO CACHE, we store all of the supported keys present in the file
 2412      * (as part of the GPO Result object in the sysdb cache).
 2413      */
 2414     ret = ad_gpo_store_policy_settings(state->host_domain,
 2415                                        cse_filtered_gpo->policy_filename);
 2416     if (ret != EOK) {
 2417         DEBUG(SSSDBG_OP_FAILURE,
 2418               "ad_gpo_store_policy_settings failed: [%d](%s)\n",
 2419               ret, sss_strerror(ret));
 2420         goto done;
 2421     }
 2422 
 2423     state->cse_gpo_index++;
 2424     ret = ad_gpo_cse_step(req);
 2425 
 2426     if (ret == EOK) {
 2427         /* ret is EOK only after all GPO policy files have been downloaded */
 2428         ret = ad_gpo_perform_hbac_processing(state,
 2429                                              state->gpo_mode,
 2430                                              state->gpo_map_type,
 2431                                              state->user,
 2432                                              state->user_domain,
 2433                                              state->host_domain);
 2434         if (ret != EOK) {
 2435             DEBUG(SSSDBG_OP_FAILURE, "HBAC processing failed: [%d](%s}\n",
 2436                   ret, sss_strerror(ret));
 2437             goto done;
 2438         }
 2439 
 2440     }
 2441 
 2442  done:
 2443 
 2444     if (ret == EOK) {
 2445         tevent_req_done(req);
 2446     } else if (ret != EAGAIN) {
 2447         tevent_req_error(req, ret);
 2448     }
 2449 }
 2450 
 2451 errno_t
 2452 ad_gpo_access_recv(struct tevent_req *req)
 2453 {
 2454     TEVENT_REQ_RETURN_ON_ERROR(req);
 2455 
 2456     return EOK;
 2457 }
 2458 
 2459 /* == ad_gpo_process_som_send/recv helpers ================================= */
 2460 
 2461 /*
 2462  * This function returns the parent of an LDAP DN
 2463  */
 2464 static errno_t
 2465 ad_gpo_parent_dn(TALLOC_CTX *mem_ctx,
 2466                  struct ldb_context *ldb_ctx,
 2467                  const char *dn,
 2468                  const char **_parent_dn)
 2469 {
 2470     struct ldb_dn *ldb_dn;
 2471     struct ldb_dn *parent_ldb_dn;
 2472     const char *p;
 2473     int ret;
 2474     TALLOC_CTX *tmp_ctx = NULL;
 2475 
 2476     tmp_ctx = talloc_new(NULL);
 2477     if (tmp_ctx == NULL) {
 2478         ret = ENOMEM;
 2479         goto done;
 2480     }
 2481 
 2482     ldb_dn = ldb_dn_new(tmp_ctx, ldb_ctx, dn);
 2483     parent_ldb_dn = ldb_dn_get_parent(tmp_ctx, ldb_dn);
 2484     p = ldb_dn_get_linearized(parent_ldb_dn);
 2485 
 2486     *_parent_dn = talloc_steal(mem_ctx, p);
 2487     ret = EOK;
 2488 
 2489  done:
 2490     talloc_free(tmp_ctx);
 2491     return ret;
 2492 }
 2493 
 2494 /*
 2495  * This function populates the _som_list output parameter by parsing the input
 2496  * DN into a list of gp_som objects. This function essentially repeatedly
 2497  * appends the input DN's parent to the SOM List (if the parent starts with
 2498  * "OU=" or "DC="), until the first "DC=" component is reached.
 2499  * Example: if input DN is "CN=MyComputer,CN=Computers,OU=Sales,DC=FOO,DC=COM",
 2500  * then SOM List has 2 SOM entries: {[OU=Sales,DC=FOO,DC=COM], [DC=FOO, DC=COM]}
 2501  */
 2502 
 2503 static errno_t
 2504 ad_gpo_populate_som_list(TALLOC_CTX *mem_ctx,
 2505                          struct ldb_context *ldb_ctx,
 2506                          const char *target_dn,
 2507                          int *_num_soms,
 2508                          struct gp_som ***_som_list)
 2509 {
 2510     TALLOC_CTX *tmp_ctx = NULL;
 2511     int ret;
 2512     int rdn_count = 0;
 2513     int som_idx = 0;
 2514     struct gp_som **som_list;
 2515     const char *parent_dn = NULL;
 2516     const char *tmp_dn = NULL;
 2517     struct ldb_dn *ldb_target_dn;
 2518 
 2519     tmp_ctx = talloc_new(NULL);
 2520     if (tmp_ctx == NULL) {
 2521         ret = ENOMEM;
 2522         goto done;
 2523     }
 2524 
 2525     ldb_target_dn = ldb_dn_new(tmp_ctx, ldb_ctx, target_dn);
 2526     if (ldb_target_dn == NULL) {
 2527         ret = EINVAL;
 2528         goto done;
 2529     }
 2530 
 2531     rdn_count = ldb_dn_get_comp_num(ldb_target_dn);
 2532     if (rdn_count == -1) {
 2533         ret = EINVAL;
 2534         goto done;
 2535     }
 2536 
 2537     if (rdn_count == 0) {
 2538         *_som_list = NULL;
 2539         ret = EOK;
 2540         goto done;
 2541     }
 2542 
 2543     /* assume the worst-case, in which every parent is a SOM */
 2544     /* include space for Site SOM and NULL: rdn_count + 1 + 1 */
 2545     som_list = talloc_array(tmp_ctx, struct gp_som *, rdn_count + 1 + 1);
 2546     if (som_list == NULL) {
 2547         ret = ENOMEM;
 2548         goto done;
 2549     }
 2550 
 2551     /* first, populate the OU and Domain SOMs */
 2552     tmp_dn = target_dn;
 2553     while ((ad_gpo_parent_dn(tmp_ctx, ldb_ctx, tmp_dn, &parent_dn)) == EOK) {
 2554 
 2555         if ((strncasecmp(parent_dn, "OU=", strlen("OU=")) == 0) ||
 2556             (strncasecmp(parent_dn, "DC=", strlen("DC=")) == 0)) {
 2557 
 2558             som_list[som_idx] = talloc_zero(som_list, struct gp_som);
 2559             if (som_list[som_idx] == NULL) {
 2560                 ret = ENOMEM;
 2561                 goto done;
 2562             }
 2563             som_list[som_idx]->som_dn = talloc_steal(som_list[som_idx],
 2564                                                      parent_dn);
 2565             if (som_list[som_idx]->som_dn == NULL) {
 2566                 ret = ENOMEM;
 2567                 goto done;
 2568             }
 2569             som_idx++;
 2570         }
 2571 
 2572         if (strncasecmp(parent_dn, "DC=", strlen("DC=")) == 0) {
 2573             break;
 2574         }
 2575         tmp_dn = parent_dn;
 2576     }
 2577 
 2578     som_list[som_idx] = NULL;
 2579 
 2580     *_num_soms = som_idx;
 2581     *_som_list = talloc_steal(mem_ctx, som_list);
 2582 
 2583     ret = EOK;
 2584 
 2585  done:
 2586     talloc_free(tmp_ctx);
 2587     return ret;
 2588 }
 2589 
 2590 /*
 2591  * This function populates the _gplink_list output parameter by parsing the
 2592  * input raw_gplink_value into an array of gp_gplink objects, each consisting of
 2593  * a GPO DN and bool enforced field.
 2594  *
 2595  * The raw_gplink_value is single string consisting of multiple gplink strings.
 2596  * The raw_gplink_value is in the following format:
 2597  *  "[GPO_DN_1;GPLinkOptions_1]...[GPO_DN_n;GPLinkOptions_n]"
 2598  *
 2599  * Each gplink string consists of a GPO DN and a GPLinkOptions field (which
 2600  * indicates whether its associated GPO DN is ignored, unenforced, or enforced).
 2601  * If a GPO DN is flagged as ignored, it is discarded and will not be added to
 2602  * the _gplink_list. If the allow_enforced_only input is true, AND a GPO DN is
 2603  * flagged as unenforced, it will also be discarded.
 2604  *
 2605  * Example: if raw_gplink_value="[OU=Sales,DC=FOO,DC=COM;0][DC=FOO,DC=COM;2]"
 2606  *   and allow_enforced_only=FALSE, then the output would consist of following:
 2607  *    _gplink_list[0]: {GPO DN: "OU=Sales,DC=FOO,DC=COM", enforced: FALSE}
 2608  *    _gplink_list[1]: {GPO DN: "DC=FOO,DC=COM",          enforced: TRUE}
 2609  */
 2610 static errno_t
 2611 ad_gpo_populate_gplink_list(TALLOC_CTX *mem_ctx,
 2612                             const char *som_dn,
 2613                             char *raw_gplink_value,
 2614                             struct gp_gplink ***_gplink_list,
 2615                             bool allow_enforced_only)
 2616 {
 2617     TALLOC_CTX *tmp_ctx = NULL;
 2618     char *ptr;
 2619     char *first;
 2620     char *last;
 2621     char *dn;
 2622     char *gplink_options;
 2623     const char delim = ']';
 2624     struct gp_gplink **gplink_list;
 2625     int i;
 2626     int ret;
 2627     uint32_t gplink_number;
 2628     int gplink_count = 0;
 2629     int num_enabled = 0;
 2630 
 2631     if (raw_gplink_value == NULL ||
 2632         *raw_gplink_value == '\0' ||
 2633         _gplink_list == NULL) {
 2634         return EINVAL;
 2635     }
 2636 
 2637     DEBUG(SSSDBG_TRACE_FUNC, "som_dn: %s\n", som_dn);
 2638     tmp_ctx = talloc_new(NULL);
 2639     if (tmp_ctx == NULL) {
 2640         ret = ENOMEM;
 2641         goto done;
 2642     }
 2643 
 2644     ptr = raw_gplink_value;
 2645 
 2646     while ((ptr = strchr(ptr, delim))) {
 2647         ptr++;
 2648         gplink_count++;
 2649     }
 2650 
 2651     if (gplink_count == 0) {
 2652         ret = EOK;
 2653         goto done;
 2654     }
 2655 
 2656     gplink_list = talloc_array(tmp_ctx, struct gp_gplink *, gplink_count + 1);
 2657     if (gplink_list == NULL) {
 2658         ret = ENOMEM;
 2659         goto done;
 2660     }
 2661 
 2662     num_enabled = 0;
 2663     ptr = raw_gplink_value;
 2664     for (i = 0; i < gplink_count; i++) {
 2665         first = ptr + 1;
 2666         last = strchr(first, delim);
 2667         if (last == NULL) {
 2668             ret = EINVAL;
 2669             goto done;
 2670         }
 2671         *last = '\0';
 2672         last++;
 2673         dn = first;
 2674         if ( strncasecmp(dn, "LDAP://", 7)== 0 ) {
 2675             dn = dn + 7;
 2676         }
 2677         gplink_options = strchr(first, ';');
 2678         if (gplink_options == NULL) {
 2679             ret = EINVAL;
 2680             goto done;
 2681         }
 2682         *gplink_options = '\0';
 2683         gplink_options++;
 2684 
 2685         gplink_number = strtouint32(gplink_options, NULL, 10);
 2686         if (errno != 0) {
 2687             ret = errno;
 2688             DEBUG(SSSDBG_OP_FAILURE,
 2689                   "strtouint32 failed: [%d](%s)\n", ret, sss_strerror(ret));
 2690             goto done;
 2691         }
 2692 
 2693         DEBUG(SSSDBG_TRACE_ALL,
 2694               "gplink_list[%d]: [%s; %d]\n", num_enabled, dn, gplink_number);
 2695 
 2696         if ((gplink_number == 1) || (gplink_number ==3)) {
 2697             /* ignore flag is set */
 2698             DEBUG(SSSDBG_TRACE_ALL, "ignored gpo skipped\n");
 2699             ptr = last;
 2700             continue;
 2701         }
 2702 
 2703         if (allow_enforced_only && (gplink_number == 0)) {
 2704             /* unenforced flag is set; only enforced gpos allowed */
 2705             DEBUG(SSSDBG_TRACE_ALL, "unenforced gpo skipped\n");
 2706             ptr = last;
 2707             continue;
 2708         }
 2709 
 2710         gplink_list[num_enabled] = talloc_zero(gplink_list, struct gp_gplink);
 2711         if (gplink_list[num_enabled] == NULL) {
 2712             ret = ENOMEM;
 2713             goto done;
 2714         }
 2715         gplink_list[num_enabled]->gpo_dn =
 2716             talloc_strdup(gplink_list[num_enabled], dn);
 2717 
 2718         if (gplink_list[num_enabled]->gpo_dn == NULL) {
 2719             ret = ENOMEM;
 2720             goto done;
 2721         }
 2722 
 2723         if (gplink_number == 0) {
 2724             gplink_list[num_enabled]->enforced = 0;
 2725             num_enabled++;
 2726         } else if (gplink_number == 2) {
 2727             gplink_list[num_enabled]->enforced = 1;
 2728             num_enabled++;
 2729         } else {
 2730             ret = EINVAL;
 2731             goto done;
 2732         }
 2733 
 2734         ptr = last;
 2735     }
 2736     gplink_list[num_enabled] = NULL;
 2737 
 2738     *_gplink_list = talloc_steal(mem_ctx, gplink_list);
 2739     ret = EOK;
 2740 
 2741  done:
 2742     talloc_free(tmp_ctx);
 2743     return ret;
 2744 }
 2745 
 2746 /* == ad_gpo_process_som_send/recv implementation ========================== */
 2747 
 2748 struct ad_gpo_process_som_state {
 2749     struct tevent_context *ev;
 2750     struct sdap_id_op *sdap_op;
 2751     struct sdap_options *opts;
 2752     struct dp_option *ad_options;
 2753     int timeout;
 2754     bool allow_enforced_only;
 2755     char *site_name;
 2756     char *site_dn;
 2757     struct gp_som **som_list;
 2758     int som_index;
 2759     int num_soms;
 2760 };
 2761 
 2762 static void ad_gpo_site_name_retrieval_done(struct tevent_req *subreq);
 2763 static void ad_gpo_site_dn_retrieval_done(struct tevent_req *subreq);
 2764 static errno_t ad_gpo_get_som_attrs_step(struct tevent_req *req);
 2765 static void ad_gpo_get_som_attrs_done(struct tevent_req *subreq);
 2766 
 2767 /*
 2768  * This function uses the input target_dn and input domain_name to populate
 2769  * a list of gp_som objects. Each object in this list represents a SOM
 2770  * associated with the target (such as OU, Domain, and Site).
 2771  *
 2772  * The inputs are used to determine the DNs of each SOM associated with the
 2773  * target. In turn, the SOM object DNs are used to retrieve certain LDAP
 2774  * attributes of each SOM object, that are parsed into an array of gp_gplink
 2775  * objects, essentially representing the GPOs that have been linked to each
 2776  * SOM object. Note that it is perfectly valid for there to be *no* GPOs
 2777  * linked to a SOM object.
 2778  */
 2779 struct tevent_req *
 2780 ad_gpo_process_som_send(TALLOC_CTX *mem_ctx,
 2781                         struct tevent_context *ev,
 2782                         struct sdap_id_conn_ctx *conn,
 2783                         struct ldb_context *ldb_ctx,
 2784                         struct sdap_id_op *sdap_op,
 2785                         struct sdap_options *opts,
 2786                         struct dp_option *ad_options,
 2787                         int timeout,
 2788                         const char *target_dn,
 2789                         const char *domain_name)
 2790 {
 2791     struct tevent_req *req;
 2792     struct tevent_req *subreq;
 2793     struct ad_gpo_process_som_state *state;
 2794     errno_t ret;
 2795 
 2796     req = tevent_req_create(mem_ctx, &state, struct ad_gpo_process_som_state);
 2797     if (req == NULL) {
 2798         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 2799         return NULL;
 2800     }
 2801 
 2802     state->ev = ev;
 2803     state->sdap_op = sdap_op;
 2804     state->opts = opts;
 2805     state->ad_options = ad_options;
 2806     state->timeout = timeout;
 2807     state->som_index = 0;
 2808     state->allow_enforced_only = 0;
 2809 
 2810     ret = ad_gpo_populate_som_list(state, ldb_ctx, target_dn,
 2811                                    &state->num_soms, &state->som_list);
 2812     if (ret != EOK) {
 2813         DEBUG(SSSDBG_OP_FAILURE,
 2814               "Unable to retrieve SOM List : [%d](%s)\n",
 2815               ret, sss_strerror(ret));
 2816         ret = ENOENT;
 2817         goto immediately;
 2818     }
 2819 
 2820     if (state->som_list == NULL) {
 2821         DEBUG(SSSDBG_OP_FAILURE, "target dn must have at least one parent\n");
 2822         ret = EINVAL;
 2823         goto immediately;
 2824     }
 2825 
 2826     subreq = ad_master_domain_send(state, state->ev, conn,
 2827                                    state->sdap_op, domain_name);
 2828 
 2829     if (subreq == NULL) {
 2830         DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
 2831         ret = ENOMEM;
 2832         goto immediately;
 2833     }
 2834 
 2835     tevent_req_set_callback(subreq, ad_gpo_site_name_retrieval_done, req);
 2836 
 2837     ret = EOK;
 2838 
 2839  immediately:
 2840 
 2841     if (ret != EOK) {
 2842         tevent_req_error(req, ret);
 2843         tevent_req_post(req, ev);
 2844     }
 2845 
 2846     return req;
 2847 }
 2848 
 2849 static void
 2850 ad_gpo_site_name_retrieval_done(struct tevent_req *subreq)
 2851 {
 2852     struct tevent_req *req;
 2853     struct ad_gpo_process_som_state *state;
 2854     int ret;
 2855     char *site = NULL;
 2856     char *site_override = NULL;
 2857     const char *attrs[] = {AD_AT_CONFIG_NC, NULL};
 2858 
 2859     req = tevent_req_callback_data(subreq, struct tevent_req);
 2860     state = tevent_req_data(req, struct ad_gpo_process_som_state);
 2861 
 2862     /* gpo code only cares about the site name */
 2863     ret = ad_master_domain_recv(subreq, state, NULL, NULL, &site, NULL);
 2864     talloc_zfree(subreq);
 2865 
 2866     if (ret != EOK || site == NULL) {
 2867         DEBUG(SSSDBG_TRACE_FUNC,
 2868               "Could not autodiscover AD site. This is not fatal if "
 2869               "ad_site option was set.\n");
 2870     }
 2871 
 2872     site_override = dp_opt_get_string(state->ad_options, AD_SITE);
 2873     if (site_override != NULL) {
 2874         DEBUG(SSSDBG_TRACE_FUNC,
 2875               "Overriding autodiscovered AD site value '%s' with '%s' from "
 2876               "configuration.\n", site ? site : "none", site_override);
 2877     }
 2878 
 2879     if (site == NULL && site_override == NULL) {
 2880         sss_log(SSS_LOG_WARNING,
 2881                 "Could not autodiscover AD site value using DNS and ad_site "
 2882                 "option was not set in configuration. GPO will not work. "
 2883                 "To work around this issue you can use ad_site option in SSSD "
 2884                 "configuration.");
 2885         DEBUG(SSSDBG_OP_FAILURE,
 2886               "Could not autodiscover AD site value using DNS and ad_site "
 2887               "option was not set in configuration. GPO will not work. "
 2888               "To work around this issue you can use ad_site option in SSSD "
 2889               "configuration.\n");
 2890         tevent_req_error(req, ENOENT);
 2891         return;
 2892     }
 2893 
 2894     state->site_name = talloc_asprintf(state, "cn=%s",
 2895                                        site_override ? site_override
 2896                                                      : site);
 2897     if (state->site_name == NULL) {
 2898         tevent_req_error(req, ENOMEM);
 2899         return;
 2900     }
 2901 
 2902     DEBUG(SSSDBG_TRACE_FUNC, "Using AD site '%s'.\n", state->site_name);
 2903 
 2904     /*
 2905      * note: the configNC attribute is being retrieved here from the rootDSE
 2906      * entry. In future, since we already make an LDAP query for the rootDSE
 2907      * entry when LDAP connection is made, this attribute should really be
 2908      * retrieved at that point (see https://fedorahosted.org/sssd/ticket/2276)
 2909      */
 2910     subreq = sdap_get_generic_send(state, state->ev, state->opts,
 2911                                    sdap_id_op_handle(state->sdap_op),
 2912                                    "", LDAP_SCOPE_BASE,
 2913                                    "(objectclass=*)", attrs, NULL, 0,
 2914                                    state->timeout,
 2915                                    false);
 2916 
 2917     if (subreq == NULL) {
 2918         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
 2919         tevent_req_error(req, ENOMEM);
 2920         return;
 2921     }
 2922 
 2923     tevent_req_set_callback(subreq, ad_gpo_site_dn_retrieval_done, req);
 2924 }
 2925 
 2926 static void
 2927 ad_gpo_site_dn_retrieval_done(struct tevent_req *subreq)
 2928 {
 2929     struct tevent_req *req;
 2930     struct ad_gpo_process_som_state *state;
 2931     int ret;
 2932     int dp_error;
 2933     int i = 0;
 2934     size_t reply_count;
 2935     struct sysdb_attrs **reply;
 2936     const char *configNC;
 2937 
 2938     req = tevent_req_callback_data(subreq, struct tevent_req);
 2939     state = tevent_req_data(req, struct ad_gpo_process_som_state);
 2940 
 2941     ret = sdap_get_generic_recv(subreq, state,
 2942                                 &reply_count, &reply);
 2943     talloc_zfree(subreq);
 2944     if (ret != EOK) {
 2945         ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 2946 
 2947         DEBUG(SSSDBG_OP_FAILURE,
 2948               "Unable to get configNC: [%d](%s)\n", ret, sss_strerror(ret));
 2949         ret = ENOENT;
 2950         goto done;
 2951     }
 2952 
 2953     /* make sure there is only one non-NULL reply returned */
 2954 
 2955     if (reply_count < 1) {
 2956         DEBUG(SSSDBG_OP_FAILURE, "No configNC retrieved\n");
 2957         ret = ENOENT;
 2958         goto done;
 2959     } else if (reply_count > 1) {
 2960         DEBUG(SSSDBG_OP_FAILURE, "Multiple replies for configNC\n");
 2961         ret = ERR_INTERNAL;
 2962         goto done;
 2963     } else if (reply == NULL) {
 2964         DEBUG(SSSDBG_OP_FAILURE, "reply_count is 1, but reply is NULL\n");
 2965         ret = ERR_INTERNAL;
 2966         goto done;
 2967     }
 2968 
 2969     /* reply[0] holds requested attributes of single reply */
 2970     ret = sysdb_attrs_get_string(reply[0], AD_AT_CONFIG_NC, &configNC);
 2971     if (ret != EOK) {
 2972         DEBUG(SSSDBG_OP_FAILURE,
 2973               "sysdb_attrs_get_string failed: [%d](%s)\n",
 2974               ret, sss_strerror(ret));
 2975         goto done;
 2976     }
 2977     state->site_dn =
 2978         talloc_asprintf(state, "%s,cn=Sites,%s", state->site_name, configNC);
 2979     if (state->site_dn == NULL) {
 2980         ret = ENOMEM;
 2981         goto done;
 2982     }
 2983 
 2984     /* note that space was allocated for site_dn when allocating som_list */
 2985     state->som_list[state->num_soms] =
 2986         talloc_zero(state->som_list, struct gp_som);
 2987     if (state->som_list[state->num_soms] == NULL) {
 2988         ret = ENOMEM;
 2989         goto done;
 2990     }
 2991 
 2992     state->som_list[state->num_soms]->som_dn =
 2993         talloc_steal(state->som_list[state->num_soms], state->site_dn);
 2994 
 2995     if (state->som_list[state->num_soms]->som_dn == NULL) {
 2996         ret = ENOMEM;
 2997         goto done;
 2998     }
 2999 
 3000     state->num_soms++;
 3001     state->som_list[state->num_soms] = NULL;
 3002 
 3003     i = 0;
 3004     while (state->som_list[i]) {
 3005         DEBUG(SSSDBG_TRACE_FUNC, "som_list[%d]->som_dn is %s\n", i,
 3006               state->som_list[i]->som_dn);
 3007         i++;
 3008     }
 3009 
 3010     ret = ad_gpo_get_som_attrs_step(req);
 3011 
 3012  done:
 3013 
 3014     if (ret == EOK) {
 3015         tevent_req_done(req);
 3016     } else if (ret != EAGAIN) {
 3017         tevent_req_error(req, ret);
 3018     }
 3019 
 3020 }
 3021 static errno_t
 3022 ad_gpo_get_som_attrs_step(struct tevent_req *req)
 3023 {
 3024     const char *attrs[] = {AD_AT_GPLINK, AD_AT_GPOPTIONS, NULL};
 3025     struct tevent_req *subreq;
 3026     struct ad_gpo_process_som_state *state;
 3027 
 3028     state = tevent_req_data(req, struct ad_gpo_process_som_state);
 3029 
 3030     struct gp_som *gp_som = state->som_list[state->som_index];
 3031 
 3032     /* gp_som is NULL only after all SOMs have been processed */
 3033     if (gp_som == NULL) return EOK;
 3034 
 3035     const char *som_dn = gp_som->som_dn;
 3036     subreq = sdap_get_generic_send(state, state->ev,  state->opts,
 3037                                    sdap_id_op_handle(state->sdap_op),
 3038                                    som_dn, LDAP_SCOPE_BASE,
 3039                                    "(objectclass=*)", attrs, NULL, 0,
 3040                                    state->timeout,
 3041                                    false);
 3042 
 3043     if (subreq == NULL) {
 3044         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
 3045         return ENOMEM;
 3046     }
 3047 
 3048     tevent_req_set_callback(subreq, ad_gpo_get_som_attrs_done, req);
 3049     return EAGAIN;
 3050 }
 3051 
 3052 static void
 3053 ad_gpo_get_som_attrs_done(struct tevent_req *subreq)
 3054 {
 3055     struct tevent_req *req;
 3056     struct ad_gpo_process_som_state *state;
 3057     int ret;
 3058     int dp_error;
 3059     size_t num_results;
 3060     struct sysdb_attrs **results;
 3061     struct ldb_message_element *el = NULL;
 3062     uint8_t *raw_gplink_value;
 3063     uint8_t *raw_gpoptions_value;
 3064     uint32_t allow_enforced_only = 0;
 3065     struct gp_som *gp_som;
 3066 
 3067     req = tevent_req_callback_data(subreq, struct tevent_req);
 3068     state = tevent_req_data(req, struct ad_gpo_process_som_state);
 3069     ret = sdap_get_generic_recv(subreq, state,
 3070                                 &num_results, &results);
 3071     talloc_zfree(subreq);
 3072 
 3073     if (ret != EOK) {
 3074         ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 3075 
 3076         DEBUG(SSSDBG_OP_FAILURE,
 3077               "Unable to get SOM attributes: [%d](%s)\n",
 3078               ret, sss_strerror(ret));
 3079         ret = ENOENT;
 3080         goto done;
 3081     }
 3082     if ((num_results < 1) || (results == NULL)) {
 3083         DEBUG(SSSDBG_OP_FAILURE, "no attrs found for SOM; try next SOM.\n");
 3084         state->som_index++;
 3085         ret = ad_gpo_get_som_attrs_step(req);
 3086         goto done;
 3087     } else if (num_results > 1) {
 3088         DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
 3089         ret = ERR_INTERNAL;
 3090         goto done;
 3091     }
 3092 
 3093     /* Get the gplink value, if available */
 3094     ret = sysdb_attrs_get_el(results[0], AD_AT_GPLINK, &el);
 3095 
 3096     if (ret != EOK && ret != ENOENT) {
 3097         DEBUG(SSSDBG_OP_FAILURE,
 3098               "sysdb_attrs_get_el() failed: [%d](%s)\n",
 3099               ret, sss_strerror(ret));
 3100         goto done;
 3101     }
 3102 
 3103     if ((ret == ENOENT) || (el->num_values == 0)) {
 3104         DEBUG(SSSDBG_OP_FAILURE, "no attrs found for SOM; try next SOM\n");
 3105         state->som_index++;
 3106         ret = ad_gpo_get_som_attrs_step(req);
 3107         goto done;
 3108     }
 3109 
 3110     raw_gplink_value = el[0].values[0].data;
 3111 
 3112     ret = sysdb_attrs_get_el(results[0], AD_AT_GPOPTIONS, &el);
 3113 
 3114     if (ret != EOK && ret != ENOENT) {
 3115         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
 3116         goto done;
 3117     }
 3118 
 3119     if ((ret == ENOENT) || (el->num_values == 0)) {
 3120         DEBUG(SSSDBG_TRACE_ALL,
 3121               "gpoptions attr not found or has no value; defaults to 0\n");
 3122         allow_enforced_only = 0;
 3123     }  else {
 3124         raw_gpoptions_value = el[0].values[0].data;
 3125         allow_enforced_only = strtouint32((char *)raw_gpoptions_value, NULL, 10);
 3126         if (errno != 0) {
 3127             ret = errno;
 3128             DEBUG(SSSDBG_OP_FAILURE,
 3129                   "strtouint32 failed: [%d](%s)\n", ret, sss_strerror(ret));
 3130             goto done;
 3131         }
 3132     }
 3133 
 3134     gp_som = state->som_list[state->som_index];
 3135     ret = ad_gpo_populate_gplink_list(gp_som,
 3136                                       gp_som->som_dn,
 3137                                       (char *)raw_gplink_value,
 3138                                       &gp_som->gplink_list,
 3139                                       state->allow_enforced_only);
 3140 
 3141     if (ret != EOK) {
 3142         DEBUG(SSSDBG_OP_FAILURE,
 3143               "ad_gpo_populate_gplink_list() failed\n");
 3144         goto done;
 3145     }
 3146 
 3147     if (allow_enforced_only) {
 3148         state->allow_enforced_only = 1;
 3149     }
 3150 
 3151     state->som_index++;
 3152     ret = ad_gpo_get_som_attrs_step(req);
 3153 
 3154  done:
 3155 
 3156     if (ret == EOK) {
 3157         tevent_req_done(req);
 3158     } else if (ret != EAGAIN) {
 3159         tevent_req_error(req, ret);
 3160     }
 3161 }
 3162 
 3163 int
 3164 ad_gpo_process_som_recv(struct tevent_req *req,
 3165                         TALLOC_CTX *mem_ctx,
 3166                         struct gp_som ***som_list)
 3167 {
 3168 
 3169     struct ad_gpo_process_som_state *state =
 3170         tevent_req_data(req, struct ad_gpo_process_som_state);
 3171 
 3172     TEVENT_REQ_RETURN_ON_ERROR(req);
 3173     *som_list = talloc_steal(mem_ctx, state->som_list);
 3174     return EOK;
 3175 }
 3176 
 3177 /* == ad_gpo_process_gpo_send/recv helpers ================================= */
 3178 
 3179 /*
 3180  * This function examines the gp_gplink objects in each gp_som object specified
 3181  * in the input som_list, and populates the _candidate_gpos output parameter's
 3182  * gpo_dn fields with prioritized list of GPO DNs. Prioritization ensures that:
 3183  * - GPOs linked to an OU will be applied after GPOs linked to a Domain,
 3184  *   which will be applied after GPOs linked to a Site.
 3185  * - multiple GPOs linked to a single SOM are applied in their link order
 3186  *   (i.e. 1st GPO linked to SOM is applied after 2nd GPO linked to SOM, etc).
 3187  * - enforced GPOs are applied after unenforced GPOs.
 3188  *
 3189  * As such, the _candidate_gpos output's dn fields looks like (in link order):
 3190  * [unenforced {Site, Domain, OU}; enforced {Site, Domain, OU}]
 3191  *
 3192  * Note that in the case of conflicting policy settings, GPOs appearing later
 3193  * in the list will trump GPOs appearing earlier in the list.
 3194  */
 3195 static errno_t
 3196 ad_gpo_populate_candidate_gpos(TALLOC_CTX *mem_ctx,
 3197                                struct gp_som **som_list,
 3198                                struct gp_gpo ***_candidate_gpos,
 3199                                int *_num_candidate_gpos)
 3200 {
 3201 
 3202     TALLOC_CTX *tmp_ctx = NULL;
 3203     struct gp_som *gp_som = NULL;
 3204     struct gp_gplink *gp_gplink = NULL;
 3205     struct gp_gpo **candidate_gpos = NULL;
 3206     int num_candidate_gpos = 0;
 3207     const char **enforced_gpo_dns = NULL;
 3208     const char **unenforced_gpo_dns = NULL;
 3209     int gpo_dn_idx = 0;
 3210     int num_enforced = 0;
 3211     int enforced_idx = 0;
 3212     int num_unenforced = 0;
 3213     int unenforced_idx = 0;
 3214     int i = 0;
 3215     int j = 0;
 3216     int ret;
 3217 
 3218     tmp_ctx = talloc_new(NULL);
 3219     if (tmp_ctx == NULL) {
 3220         ret = ENOMEM;
 3221         goto done;
 3222     }
 3223 
 3224     while (som_list[i]) {
 3225         gp_som = som_list[i];
 3226         j = 0;
 3227         while (gp_som && gp_som->gplink_list && gp_som->gplink_list[j]) {
 3228             gp_gplink = gp_som->gplink_list[j];
 3229             if (gp_gplink == NULL) {
 3230                 DEBUG(SSSDBG_OP_FAILURE, "unexpected null gp_gplink\n");
 3231                 ret = EINVAL;
 3232                 goto done;
 3233             }
 3234             if (gp_gplink->enforced) {
 3235                 num_enforced++;
 3236             } else {
 3237                 num_unenforced++;
 3238             }
 3239             j++;
 3240         }
 3241         i++;
 3242     }
 3243 
 3244     num_candidate_gpos = num_enforced + num_unenforced;
 3245 
 3246     if (num_candidate_gpos == 0) {
 3247         *_candidate_gpos = NULL;
 3248         *_num_candidate_gpos = 0;
 3249         ret = EOK;
 3250         goto done;
 3251     }
 3252 
 3253     enforced_gpo_dns = talloc_array(tmp_ctx, const char *, num_enforced + 1);
 3254     if (enforced_gpo_dns == NULL) {
 3255         ret = ENOMEM;
 3256         goto done;
 3257     }
 3258 
 3259     unenforced_gpo_dns = talloc_array(tmp_ctx, const char *, num_unenforced + 1);
 3260     if (unenforced_gpo_dns == NULL) {
 3261         ret = ENOMEM;
 3262         goto done;
 3263     }
 3264 
 3265     i = 0;
 3266     while (som_list[i]) {
 3267         gp_som = som_list[i];
 3268         j = 0;
 3269         while (gp_som && gp_som->gplink_list && gp_som->gplink_list[j]) {
 3270             gp_gplink = gp_som->gplink_list[j];
 3271             if (gp_gplink == NULL) {
 3272                 DEBUG(SSSDBG_OP_FAILURE, "unexpected null gp_gplink\n");
 3273                 ret = EINVAL;
 3274                 goto done;
 3275             }
 3276 
 3277             if (gp_gplink->enforced) {
 3278                 enforced_gpo_dns[enforced_idx] =
 3279                     talloc_steal(enforced_gpo_dns, gp_gplink->gpo_dn);
 3280                 if (enforced_gpo_dns[enforced_idx] == NULL) {
 3281                     ret = ENOMEM;
 3282                     goto done;
 3283                 }
 3284                 enforced_idx++;
 3285             } else {
 3286 
 3287                 unenforced_gpo_dns[unenforced_idx] =
 3288                     talloc_steal(unenforced_gpo_dns, gp_gplink->gpo_dn);
 3289 
 3290                 if (unenforced_gpo_dns[unenforced_idx] == NULL) {
 3291                     ret = ENOMEM;
 3292                     goto done;
 3293                 }
 3294                 unenforced_idx++;
 3295             }
 3296             j++;
 3297         }
 3298         i++;
 3299     }
 3300     enforced_gpo_dns[num_enforced] = NULL;
 3301     unenforced_gpo_dns[num_unenforced] = NULL;
 3302 
 3303     candidate_gpos = talloc_array(tmp_ctx,
 3304                                   struct gp_gpo *,
 3305                                   num_candidate_gpos + 1);
 3306 
 3307     if (candidate_gpos == NULL) {
 3308         ret = ENOMEM;
 3309         goto done;
 3310     }
 3311 
 3312     gpo_dn_idx = 0;
 3313     for (i = num_unenforced - 1; i >= 0; i--) {
 3314         candidate_gpos[gpo_dn_idx] = talloc_zero(candidate_gpos, struct gp_gpo);
 3315         if (candidate_gpos[gpo_dn_idx] == NULL) {
 3316             ret = ENOMEM;
 3317             goto done;
 3318         }
 3319         candidate_gpos[gpo_dn_idx]->gpo_dn =
 3320             talloc_steal(candidate_gpos[gpo_dn_idx], unenforced_gpo_dns[i]);
 3321 
 3322         if (candidate_gpos[gpo_dn_idx]->gpo_dn == NULL) {
 3323             ret = ENOMEM;
 3324             goto done;
 3325         }
 3326         DEBUG(SSSDBG_TRACE_FUNC,
 3327               "candidate_gpos[%d]->gpo_dn: %s\n",
 3328               gpo_dn_idx, candidate_gpos[gpo_dn_idx]->gpo_dn);
 3329         gpo_dn_idx++;
 3330     }
 3331 
 3332     for (i = 0; i < num_enforced; i++) {
 3333 
 3334         candidate_gpos[gpo_dn_idx] = talloc_zero(candidate_gpos, struct gp_gpo);
 3335         if (candidate_gpos[gpo_dn_idx] == NULL) {
 3336             ret = ENOMEM;
 3337             goto done;
 3338         }
 3339 
 3340         candidate_gpos[gpo_dn_idx]->gpo_dn =
 3341             talloc_steal(candidate_gpos[gpo_dn_idx], enforced_gpo_dns[i]);
 3342         if (candidate_gpos[gpo_dn_idx]->gpo_dn == NULL) {
 3343             ret = ENOMEM;
 3344             goto done;
 3345         }
 3346 
 3347         DEBUG(SSSDBG_TRACE_FUNC,
 3348               "candidate_gpos[%d]->gpo_dn: %s\n",
 3349               gpo_dn_idx, candidate_gpos[gpo_dn_idx]->gpo_dn);
 3350         gpo_dn_idx++;
 3351     }
 3352 
 3353     candidate_gpos[gpo_dn_idx] = NULL;
 3354 
 3355     *_candidate_gpos = talloc_steal(mem_ctx, candidate_gpos);
 3356     *_num_candidate_gpos = num_candidate_gpos;
 3357 
 3358     ret = EOK;
 3359 
 3360  done:
 3361     talloc_free(tmp_ctx);
 3362     return ret;
 3363 }
 3364 
 3365 /*
 3366  * This function parses the input_path into its components, replaces each
 3367  * back slash ('\') with a forward slash ('/'), and populates the output params.
 3368  *
 3369  * The smb_server output is constructed by concatenating the following elements:
 3370  * - SMB_STANDARD_URI ("smb://")
 3371  * - server_hostname (which replaces domain_name in input path)
 3372  * The smb_share and smb_path outputs are extracted from the input_path.
 3373  *
 3374  * Example: if input_path = "\\foo.com\SysVol\foo.com\..." and
 3375  * server_hostname = "adserver.foo.com", then
 3376  *   _smb_server = "smb://adserver.foo.com"
 3377  *   _smb_share = "SysVol"
 3378  *   _smb_path = "/foo.com/..."
 3379  *
 3380  * Note that the input_path must have at least four forward slash separators.
 3381  * For example, input_path = "\\foo.com\SysVol" is not a valid input_path,
 3382  * because it has only three forward slash separators.
 3383  */
 3384 static errno_t
 3385 ad_gpo_extract_smb_components(TALLOC_CTX *mem_ctx,
 3386                               char *server_hostname,
 3387                               char *input_path,
 3388                               const char **_smb_server,
 3389                               const char **_smb_share,
 3390                               const char **_smb_path)
 3391 {
 3392     char *ptr;
 3393     const char delim = '\\';
 3394     int ret;
 3395     int num_seps = 0;
 3396     char *smb_path = NULL;
 3397     char *smb_share = NULL;
 3398 
 3399     DEBUG(SSSDBG_TRACE_ALL, "input_path: %s\n", input_path);
 3400 
 3401     if (input_path == NULL ||
 3402         *input_path == '\0' ||
 3403         _smb_server == NULL ||
 3404         _smb_share == NULL ||
 3405         _smb_path == NULL) {
 3406         ret = EINVAL;
 3407         goto done;
 3408     }
 3409 
 3410     ptr = input_path;
 3411     while ((ptr = strchr(ptr, delim))) {
 3412         num_seps++;
 3413         if (num_seps == 3) {
 3414             /* replace the slash before the share name with null string */
 3415 
 3416             *ptr = '\0';
 3417             ptr++;
 3418             smb_share = ptr;
 3419             continue;
 3420         } else if (num_seps == 4) {
 3421             /* replace the slash after the share name with null string */
 3422             *ptr = '\0';
 3423             ptr++;
 3424             smb_path = ptr;
 3425             continue;
 3426         }
 3427         *ptr = '/';
 3428         ptr++;
 3429     }
 3430 
 3431     if (num_seps == 0) {
 3432         ret = EINVAL;
 3433         goto done;
 3434     }
 3435 
 3436     if (smb_path == NULL)  {
 3437         ret = EINVAL;
 3438         goto done;
 3439     }
 3440 
 3441     *_smb_server = talloc_asprintf(mem_ctx, "%s%s",
 3442                                    SMB_STANDARD_URI,
 3443                                    server_hostname);
 3444     if (*_smb_server == NULL) {
 3445         ret = ENOMEM;
 3446         goto done;
 3447     }
 3448 
 3449     *_smb_share = talloc_asprintf(mem_ctx, "/%s", smb_share);
 3450     if (*_smb_share == NULL) {
 3451         ret = ENOMEM;
 3452         goto done;
 3453     }
 3454 
 3455     *_smb_path = talloc_asprintf(mem_ctx, "/%s", smb_path);
 3456     if (*_smb_path == NULL) {
 3457         ret = ENOMEM;
 3458         goto done;
 3459     }
 3460 
 3461     ret = EOK;
 3462 
 3463  done:
 3464     return ret;
 3465 }
 3466 
 3467 /*
 3468  * This function populates the _cse_guid_list output parameter by parsing the
 3469  * input raw_machine_ext_names_value into an array of cse_guid strings.
 3470  *
 3471  * The raw_machine_ext_names_value is a single string in the following format:
 3472  * "[{cse_guid_1}{tool_guid1}]...[{cse_guid_n}{tool_guid_n}]"
 3473  */
 3474 static errno_t
 3475 ad_gpo_parse_machine_ext_names(TALLOC_CTX *mem_ctx,
 3476                                char *raw_machine_ext_names_value,
 3477                                const char ***_gpo_cse_guids,
 3478                                int *_num_gpo_cse_guids)
 3479 {
 3480     TALLOC_CTX *tmp_ctx = NULL;
 3481     char *ptr;
 3482     char *first;
 3483     char *last;
 3484     char *cse_guid;
 3485     char *tool_guid;
 3486     const char delim = ']';
 3487     const char **gpo_cse_guids;
 3488     int i;
 3489     int ret;
 3490     int num_gpo_cse_guids = 0;
 3491 
 3492     if (raw_machine_ext_names_value == NULL ||
 3493         *raw_machine_ext_names_value == '\0' ||
 3494         _gpo_cse_guids == NULL) {
 3495         return EINVAL;
 3496     }
 3497 
 3498     tmp_ctx = talloc_new(NULL);
 3499     if (tmp_ctx == NULL) {
 3500         ret = ENOMEM;
 3501         goto done;
 3502     }
 3503 
 3504     ptr = raw_machine_ext_names_value;
 3505     while ((ptr = strchr(ptr, delim))) {
 3506         ptr++;
 3507         num_gpo_cse_guids++;
 3508     }
 3509 
 3510     if (num_gpo_cse_guids == 0) {
 3511         ret = EINVAL;
 3512         goto done;
 3513     }
 3514 
 3515     gpo_cse_guids = talloc_array(tmp_ctx, const char *, num_gpo_cse_guids + 1);
 3516     if (gpo_cse_guids == NULL) {
 3517         ret = ENOMEM;
 3518         goto done;
 3519     }
 3520 
 3521     ptr = raw_machine_ext_names_value;
 3522     for (i = 0; i < num_gpo_cse_guids; i++) {
 3523         first = ptr + 1;
 3524         last = strchr(first, delim);
 3525         if (last == NULL) {
 3526             break;
 3527         }
 3528         *last = '\0';
 3529         last++;
 3530         cse_guid = first;
 3531         first ++;
 3532         tool_guid = strchr(first, '{');
 3533         if (tool_guid == NULL) {
 3534             break;
 3535         }
 3536         *tool_guid = '\0';
 3537         gpo_cse_guids[i] = talloc_strdup(gpo_cse_guids, cse_guid);
 3538         ptr = last;
 3539     }
 3540     gpo_cse_guids[i] = NULL;
 3541 
 3542     DEBUG(SSSDBG_TRACE_ALL, "num_gpo_cse_guids: %d\n", num_gpo_cse_guids);
 3543 
 3544     for (i = 0; i < num_gpo_cse_guids; i++) {
 3545         DEBUG(SSSDBG_TRACE_ALL,
 3546               "gpo_cse_guids[%d] is %s\n", i, gpo_cse_guids[i]);
 3547     }
 3548 
 3549     *_gpo_cse_guids = talloc_steal(mem_ctx, gpo_cse_guids);
 3550     *_num_gpo_cse_guids = num_gpo_cse_guids;
 3551     ret = EOK;
 3552 
 3553  done:
 3554     talloc_free(tmp_ctx);
 3555     return ret;
 3556 }
 3557 
 3558 enum ndr_err_code
 3559 ad_gpo_ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags,
 3560                                     struct security_descriptor *r);
 3561 
 3562 /*
 3563  * This function parses the input data blob and assigns the resulting
 3564  * security_descriptor object to the _gpo_sd output parameter.
 3565  */
 3566 static errno_t ad_gpo_parse_sd(TALLOC_CTX *mem_ctx,
 3567                                uint8_t *data,
 3568                                size_t length,
 3569                                struct security_descriptor **_gpo_sd)
 3570 {
 3571 
 3572     struct ndr_pull *ndr_pull = NULL;
 3573     struct security_descriptor sd;
 3574     DATA_BLOB blob;
 3575     enum ndr_err_code ndr_err;
 3576 
 3577     blob.data = data;
 3578     blob.length = length;
 3579 
 3580     ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
 3581     if (ndr_pull == NULL) {
 3582         DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
 3583         return EINVAL;
 3584     }
 3585 
 3586     ndr_err = ad_gpo_ndr_pull_security_descriptor(ndr_pull,
 3587                                                   NDR_SCALARS|NDR_BUFFERS,
 3588                                                   &sd);
 3589 
 3590     if (ndr_err != NDR_ERR_SUCCESS) {
 3591         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to pull security descriptor\n");
 3592         return EINVAL;
 3593     }
 3594 
 3595     *_gpo_sd = talloc_memdup(mem_ctx, &sd, sizeof(struct security_descriptor));
 3596 
 3597     return EOK;
 3598 }
 3599 
 3600 /* == ad_gpo_process_gpo_send/recv implementation ========================== */
 3601 
 3602 struct ad_gpo_process_gpo_state {
 3603     struct ad_access_ctx *access_ctx;
 3604     struct tevent_context *ev;
 3605     struct sdap_id_op *sdap_op;
 3606     struct dp_option *ad_options;
 3607     struct sdap_options *opts;
 3608     char *server_hostname;
 3609     struct sss_domain_info *host_domain;
 3610     int timeout;
 3611     struct gp_gpo **candidate_gpos;
 3612     int num_candidate_gpos;
 3613     int gpo_index;
 3614 };
 3615 
 3616 static errno_t ad_gpo_get_gpo_attrs_step(struct tevent_req *req);
 3617 static void ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq);
 3618 
 3619 /*
 3620  * This function uses the input som_list to populate a prioritized list of
 3621  * gp_gpo objects, prioritized based on SOM type, link order, and whether the
 3622  * GPO is "enforced". This list represents the initial set of candidate GPOs
 3623  * that might be applicable to the target. This list can not be expanded, but
 3624  * it might be reduced based on subsequent filtering steps. The GPO object DNs
 3625  * are used to retrieve certain LDAP attributes of each GPO object, that are
 3626  * parsed into the various fields of the gp_gpo object.
 3627  */
 3628 struct tevent_req *
 3629 ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
 3630                         struct tevent_context *ev,
 3631                         struct sdap_id_op *sdap_op,
 3632                         struct sdap_options *opts,
 3633                         char *server_hostname,
 3634                         struct sss_domain_info *host_domain,
 3635                         struct ad_access_ctx *access_ctx,
 3636                         int timeout,
 3637                         struct gp_som **som_list)
 3638 {
 3639     struct tevent_req *req;
 3640     struct ad_gpo_process_gpo_state *state;
 3641     errno_t ret;
 3642 
 3643     req = tevent_req_create(mem_ctx, &state, struct ad_gpo_process_gpo_state);
 3644     if (req == NULL) {
 3645         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 3646         return NULL;
 3647     }
 3648 
 3649     state->ev = ev;
 3650     state->sdap_op = sdap_op;
 3651     state->ad_options = access_ctx->ad_options;
 3652     state->opts = opts;
 3653     state->server_hostname = server_hostname;
 3654     state->host_domain = host_domain;
 3655     state->access_ctx = access_ctx;
 3656     state->timeout = timeout;
 3657     state->gpo_index = 0;
 3658     state->candidate_gpos = NULL;
 3659     state->num_candidate_gpos = 0;
 3660 
 3661     ret = ad_gpo_populate_candidate_gpos(state,
 3662                                          som_list,
 3663                                          &state->candidate_gpos,
 3664                                          &state->num_candidate_gpos);
 3665 
 3666     if (ret != EOK) {
 3667         DEBUG(SSSDBG_OP_FAILURE,
 3668               "Unable to retrieve GPO List: [%d](%s)\n",
 3669               ret, sss_strerror(ret));
 3670         goto immediately;
 3671     }
 3672 
 3673     if (state->candidate_gpos == NULL) {
 3674         DEBUG(SSSDBG_OP_FAILURE, "no gpos found\n");
 3675         ret = ENOENT;
 3676         goto immediately;
 3677     }
 3678 
 3679     ret = ad_gpo_get_gpo_attrs_step(req);
 3680 
 3681 immediately:
 3682 
 3683     if (ret == EOK) {
 3684         tevent_req_done(req);
 3685         tevent_req_post(req, ev);
 3686     } else if (ret != EAGAIN) {
 3687         tevent_req_error(req, ret);
 3688         tevent_req_post(req, ev);
 3689     }
 3690 
 3691     return req;
 3692 }
 3693 
 3694 static errno_t
 3695 ad_gpo_get_gpo_attrs_step(struct tevent_req *req)
 3696 {
 3697     const char *attrs[] = AD_GPO_ATTRS;
 3698     struct tevent_req *subreq;
 3699     struct ad_gpo_process_gpo_state *state;
 3700 
 3701     state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
 3702 
 3703     struct gp_gpo *gp_gpo = state->candidate_gpos[state->gpo_index];
 3704 
 3705     /* gp_gpo is NULL only after all GPOs have been processed */
 3706     if (gp_gpo == NULL) return EOK;
 3707 
 3708     const char *gpo_dn = gp_gpo->gpo_dn;
 3709 
 3710     subreq = sdap_sd_search_send(state, state->ev,
 3711                                  state->opts, sdap_id_op_handle(state->sdap_op),
 3712                                  gpo_dn, SECINFO_DACL, attrs, state->timeout);
 3713 
 3714     if (subreq == NULL) {
 3715         DEBUG(SSSDBG_OP_FAILURE, "sdap_sd_search_send failed.\n");
 3716         return ENOMEM;
 3717     }
 3718 
 3719     tevent_req_set_callback(subreq, ad_gpo_get_gpo_attrs_done, req);
 3720     return EAGAIN;
 3721 }
 3722 
 3723 static errno_t
 3724 ad_gpo_sd_process_attrs(struct tevent_req *req,
 3725                         char *smb_host,
 3726                         struct sysdb_attrs *result);
 3727 void
 3728 ad_gpo_get_sd_referral_done(struct tevent_req *subreq);
 3729 
 3730 static struct tevent_req *
 3731 ad_gpo_get_sd_referral_send(TALLOC_CTX *mem_ctx,
 3732                             struct tevent_context *ev,
 3733                             struct ad_access_ctx *access_ctx,
 3734                             struct sdap_options *opts,
 3735                             const char *referral,
 3736                             struct sss_domain_info *host_domain,
 3737                             int timeout);
 3738 errno_t
 3739 ad_gpo_get_sd_referral_recv(struct tevent_req *req,
 3740                             TALLOC_CTX *mem_ctx,
 3741                             char **_smb_host,
 3742                             struct sysdb_attrs **_reply);
 3743 
 3744 static void
 3745 ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
 3746 {
 3747     struct tevent_req *req;
 3748     struct ad_gpo_process_gpo_state *state;
 3749     int ret;
 3750     int dp_error;
 3751     size_t num_results, refcount;
 3752     struct sysdb_attrs **results;
 3753     char **refs;
 3754 
 3755     req = tevent_req_callback_data(subreq, struct tevent_req);
 3756     state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
 3757 
 3758     ret = sdap_sd_search_recv(subreq, state,
 3759                               &num_results, &results,
 3760                               &refcount, &refs);
 3761     talloc_zfree(subreq);
 3762 
 3763     if (ret != EOK) {
 3764         ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 3765 
 3766         DEBUG(SSSDBG_OP_FAILURE,
 3767               "Unable to get GPO attributes: [%d](%s)\n",
 3768               ret, sss_strerror(ret));
 3769         ret = ENOENT;
 3770         goto done;
 3771     }
 3772 
 3773     if ((num_results < 1) || (results == NULL)) {
 3774         if (refcount == 1) {
 3775             /* If we were redirected to a referral, process it.
 3776              * There must be a single referral result here; if we get
 3777              * more than one (or zero) it's a bug.
 3778              */
 3779 
 3780             subreq = ad_gpo_get_sd_referral_send(state, state->ev,
 3781                                                  state->access_ctx,
 3782                                                  state->opts,
 3783                                                  refs[0],
 3784                                                  state->host_domain,
 3785                                                  state->timeout);
 3786             if (!subreq) {
 3787                 ret = ENOMEM;
 3788                 goto done;
 3789             }
 3790 
 3791             tevent_req_set_callback(subreq, ad_gpo_get_sd_referral_done, req);
 3792             ret = EAGAIN;
 3793             goto done;
 3794 
 3795         } else {
 3796             const char *gpo_dn = state->candidate_gpos[state->gpo_index]->gpo_dn;
 3797 
 3798             DEBUG(SSSDBG_OP_FAILURE,
 3799                   "No attrs found for GPO [%s].\n", gpo_dn);
 3800             ret = ENOENT;
 3801             goto done;
 3802         }
 3803     } else if (num_results > 1) {
 3804         DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
 3805         ret = ERR_INTERNAL;
 3806         goto done;
 3807     }
 3808 
 3809     ret = ad_gpo_sd_process_attrs(req, state->server_hostname, results[0]);
 3810 
 3811 done:
 3812 
 3813    if (ret == EOK) {
 3814        tevent_req_done(req);
 3815    } else if (ret != EAGAIN) {
 3816        tevent_req_error(req, ret);
 3817    }
 3818 }
 3819 
 3820 void
 3821 ad_gpo_get_sd_referral_done(struct tevent_req *subreq)
 3822 {
 3823     errno_t ret;
 3824     int dp_error;
 3825     struct sysdb_attrs *reply;
 3826     char *smb_host;
 3827 
 3828     struct tevent_req *req =
 3829             tevent_req_callback_data(subreq, struct tevent_req);
 3830     struct ad_gpo_process_gpo_state *state =
 3831             tevent_req_data(req, struct ad_gpo_process_gpo_state);
 3832 
 3833     ret = ad_gpo_get_sd_referral_recv(subreq, state, &smb_host, &reply);
 3834     talloc_zfree(subreq);
 3835     if (ret != EOK) {
 3836         /* Terminate the sdap_id_op */
 3837         ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 3838 
 3839         DEBUG(SSSDBG_OP_FAILURE,
 3840               "Unable to get referred GPO attributes: [%d](%s)\n",
 3841               ret, sss_strerror(ret));
 3842 
 3843         goto done;
 3844     }
 3845 
 3846     /* Lookup succeeded. Process it */
 3847     ret = ad_gpo_sd_process_attrs(req, smb_host, reply);
 3848 
 3849 done:
 3850 
 3851    if (ret == EOK) {
 3852        tevent_req_done(req);
 3853    } else if (ret != EAGAIN) {
 3854        tevent_req_error(req, ret);
 3855    }
 3856 }
 3857 
 3858 static bool machine_ext_names_is_blank(char *attr_value)
 3859 {
 3860     char *ptr;
 3861 
 3862     if (attr_value == NULL) {
 3863         return true;
 3864     }
 3865 
 3866     ptr = attr_value;
 3867     for (; *ptr != '\0'; ptr++) {
 3868         if (!isspace(*ptr)) {
 3869             return false;
 3870         }
 3871     }
 3872 
 3873     return true;
 3874 }
 3875 
 3876 static errno_t
 3877 ad_gpo_missing_or_unreadable_attr(struct ad_gpo_process_gpo_state *state,
 3878                                   struct tevent_req *req)
 3879 {
 3880     bool ignore_unreadable = dp_opt_get_bool(state->ad_options,
 3881                                              AD_GPO_IGNORE_UNREADABLE);
 3882 
 3883     if (ignore_unreadable) {
 3884         /* If admins decided to skip GPOs with unreadable
 3885          * attributes just log the SID of skipped GPO */
 3886         DEBUG(SSSDBG_TRACE_FUNC,
 3887               "Group Policy Container with DN [%s] has unreadable or missing "
 3888               "attributes -> skipping this GPO "
 3889               "(ad_gpo_ignore_unreadable = True)\n",
 3890               state->candidate_gpos[state->gpo_index]->gpo_dn);
 3891         state->gpo_index++;
 3892         return ad_gpo_get_gpo_attrs_step(req);
 3893     } else {
 3894         /* Inform in logs and syslog that this GPO can
 3895          * not be processed due to unreadable or missing
 3896          * attributes and point to possible server side
 3897          * and client side solutions. */
 3898         DEBUG(SSSDBG_CRIT_FAILURE,
 3899               "Group Policy Container with DN [%s] is unreadable or has "
 3900               "unreadable or missing attributes. In order to fix this "
 3901               "make sure that this AD object has following attributes "
 3902               "readable: nTSecurityDescriptor, cn, gPCFileSysPath, "
 3903               "gPCMachineExtensionNames, gPCFunctionalityVersion, flags. "
 3904               "Alternatively if you do not have access to the server or can "
 3905               "not change permissions on this object, you can use option "
 3906               "ad_gpo_ignore_unreadable = True which will skip this GPO. "
 3907               "See ad_gpo_ignore_unreadable in 'man sssd-ad' for details.\n",
 3908               state->candidate_gpos[state->gpo_index]->gpo_dn);
 3909         sss_log(SSSDBG_CRIT_FAILURE,
 3910                 "Group Policy Container with DN [%s] is unreadable or has "
 3911                 "unreadable or missing attributes. In order to fix this "
 3912                 "make sure that this AD object has following attributes "
 3913                 "readable: nTSecurityDescriptor, cn, gPCFileSysPath, "
 3914                 "gPCMachineExtensionNames, gPCFunctionalityVersion, flags. "
 3915                 "Alternatively if you do not have access to the server or can "
 3916                 "not change permissions on this object, you can use option "
 3917                 "ad_gpo_ignore_unreadable = True which will skip this GPO. "
 3918                 "See ad_gpo_ignore_unreadable in 'man sssd-ad' for details.\n",
 3919                 state->candidate_gpos[state->gpo_index]->gpo_dn);
 3920         return EFAULT;
 3921     }
 3922 }
 3923 
 3924 static errno_t
 3925 ad_gpo_sd_process_attrs(struct tevent_req *req,
 3926                         char *smb_host,
 3927                         struct sysdb_attrs *result)
 3928 {
 3929     struct ad_gpo_process_gpo_state *state;
 3930     struct gp_gpo *gp_gpo;
 3931     int ret;
 3932     struct ldb_message_element *el = NULL;
 3933     const char *gpo_guid = NULL;
 3934     const char *raw_file_sys_path = NULL;
 3935     char *file_sys_path = NULL;
 3936     uint8_t *raw_machine_ext_names = NULL;
 3937 
 3938     state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
 3939     gp_gpo = state->candidate_gpos[state->gpo_index];
 3940 
 3941     /* retrieve AD_AT_CN */
 3942     ret = sysdb_attrs_get_string(result, AD_AT_CN, &gpo_guid);
 3943     if (ret == ENOENT) {
 3944         ret = ad_gpo_missing_or_unreadable_attr(state, req);
 3945         goto done;
 3946     } else if (ret != EOK) {
 3947         DEBUG(SSSDBG_OP_FAILURE,
 3948               "sysdb_attrs_get_string failed: [%d](%s)\n",
 3949               ret, sss_strerror(ret));
 3950         goto done;
 3951     }
 3952 
 3953     gp_gpo->gpo_guid = talloc_steal(gp_gpo, gpo_guid);
 3954     if (gp_gpo->gpo_guid == NULL) {
 3955         ret = ENOMEM;
 3956         goto done;
 3957     }
 3958 
 3959     DEBUG(SSSDBG_TRACE_ALL, "populating attrs for gpo_guid: %s\n",
 3960           gp_gpo->gpo_guid);
 3961 
 3962     /* retrieve AD_AT_FILE_SYS_PATH */
 3963     ret = sysdb_attrs_get_string(result,
 3964                                  AD_AT_FILE_SYS_PATH,
 3965                                  &raw_file_sys_path);
 3966 
 3967     if (ret == ENOENT) {
 3968         ret = ad_gpo_missing_or_unreadable_attr(state, req);
 3969         goto done;
 3970     } else if (ret != EOK) {
 3971         DEBUG(SSSDBG_OP_FAILURE,
 3972               "sysdb_attrs_get_string failed: [%d](%s)\n",
 3973               ret, sss_strerror(ret));
 3974         goto done;
 3975     }
 3976 
 3977     file_sys_path = talloc_strdup(gp_gpo, raw_file_sys_path);
 3978 
 3979     ret = ad_gpo_extract_smb_components(gp_gpo, smb_host,
 3980                                         file_sys_path, &gp_gpo->smb_server,
 3981                                         &gp_gpo->smb_share, &gp_gpo->smb_path);
 3982     if (ret != EOK) {
 3983         DEBUG(SSSDBG_OP_FAILURE,
 3984               "unable to extract smb components from file_sys_path: [%d](%s)\n",
 3985               ret, sss_strerror(ret));
 3986         goto done;
 3987     }
 3988 
 3989     DEBUG(SSSDBG_TRACE_ALL, "smb_server: %s\n", gp_gpo->smb_server);
 3990     DEBUG(SSSDBG_TRACE_ALL, "smb_share: %s\n", gp_gpo->smb_share);
 3991     DEBUG(SSSDBG_TRACE_ALL, "smb_path: %s\n", gp_gpo->smb_path);
 3992 
 3993     /* retrieve AD_AT_FUNC_VERSION */
 3994     ret = sysdb_attrs_get_int32_t(result, AD_AT_FUNC_VERSION,
 3995                                   &gp_gpo->gpo_func_version);
 3996     if (ret == ENOENT) {
 3997         /* If this attribute is missing we can skip the GPO. It will
 3998          * be filtered out according to MS-GPOL:
 3999          * https://msdn.microsoft.com/en-us/library/cc232538.aspx */
 4000         DEBUG(SSSDBG_TRACE_ALL, "GPO with GUID %s is missing attribute "
 4001               AD_AT_FUNC_VERSION " and will be skipped.\n", gp_gpo->gpo_guid);
 4002         state->gpo_index++;
 4003         ret = ad_gpo_get_gpo_attrs_step(req);
 4004         goto done;
 4005     } else if (ret != EOK) {
 4006         DEBUG(SSSDBG_OP_FAILURE,
 4007               "sysdb_attrs_get_int32_t failed: [%d](%s)\n",
 4008               ret, sss_strerror(ret));
 4009         goto done;
 4010     }
 4011 
 4012     DEBUG(SSSDBG_TRACE_ALL, "gpo_func_version: %d\n",
 4013                             gp_gpo->gpo_func_version);
 4014 
 4015     /* retrieve AD_AT_FLAGS */
 4016     ret = sysdb_attrs_get_int32_t(result, AD_AT_FLAGS,
 4017                                   &gp_gpo->gpo_flags);
 4018     if (ret == ENOENT) {
 4019         ret = ad_gpo_missing_or_unreadable_attr(state, req);
 4020         goto done;
 4021     } else if (ret != EOK) {
 4022         DEBUG(SSSDBG_OP_FAILURE,
 4023               "sysdb_attrs_get_int32_t failed: [%d](%s)\n",
 4024               ret, sss_strerror(ret));
 4025         goto done;
 4026     }
 4027 
 4028     DEBUG(SSSDBG_TRACE_ALL, "gpo_flags: %d\n", gp_gpo->gpo_flags);
 4029 
 4030     /* retrieve AD_AT_NT_SEC_DESC */
 4031     ret = sysdb_attrs_get_el(result, AD_AT_NT_SEC_DESC, &el);
 4032     if (ret != EOK && ret != ENOENT) {
 4033         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
 4034         goto done;
 4035     }
 4036     if ((ret == ENOENT) || (el->num_values == 0)) {
 4037         DEBUG(SSSDBG_OP_FAILURE,
 4038               "nt_sec_desc attribute not found or has no value\n");
 4039         ret = ad_gpo_missing_or_unreadable_attr(state, req);
 4040         goto done;
 4041     }
 4042 
 4043     ret = ad_gpo_parse_sd(gp_gpo, el[0].values[0].data, el[0].values[0].length,
 4044                           &gp_gpo->gpo_sd);
 4045     if (ret != EOK) {
 4046         DEBUG(SSSDBG_OP_FAILURE, "ad_gpo_parse_sd() failed\n");
 4047         goto done;
 4048     }
 4049 
 4050     /* retrieve AD_AT_MACHINE_EXT_NAMES */
 4051     ret = sysdb_attrs_get_el(result, AD_AT_MACHINE_EXT_NAMES, &el);
 4052     if (ret != EOK && ret != ENOENT) {
 4053         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
 4054         goto done;
 4055     }
 4056 
 4057     if ((ret == ENOENT) || (el->num_values == 0)
 4058             || machine_ext_names_is_blank((char *) el[0].values[0].data)) {
 4059         /*
 4060          * if gpo has no machine_ext_names (which is perfectly valid: it could
 4061          * have only user_ext_names, for example), we continue to next gpo
 4062          */
 4063         DEBUG(SSSDBG_TRACE_ALL,
 4064               "machine_ext_names attribute not found or has no value\n");
 4065         state->gpo_index++;
 4066     } else {
 4067         raw_machine_ext_names = el[0].values[0].data;
 4068 
 4069         ret = ad_gpo_parse_machine_ext_names(gp_gpo,
 4070                                              (char *)raw_machine_ext_names,
 4071                                              &gp_gpo->gpo_cse_guids,
 4072                                              &gp_gpo->num_gpo_cse_guids);
 4073         if (ret != EOK) {
 4074             DEBUG(SSSDBG_OP_FAILURE,
 4075                   "ad_gpo_parse_machine_ext_names() failed\n");
 4076             goto done;
 4077         }
 4078 
 4079         state->gpo_index++;
 4080     }
 4081 
 4082     ret = ad_gpo_get_gpo_attrs_step(req);
 4083 
 4084  done:
 4085 
 4086     return ret;
 4087 }
 4088 
 4089 int
 4090 ad_gpo_process_gpo_recv(struct tevent_req *req,
 4091                         TALLOC_CTX *mem_ctx,
 4092                         struct gp_gpo ***candidate_gpos,
 4093                         int *num_candidate_gpos)
 4094 {
 4095     struct ad_gpo_process_gpo_state *state =
 4096         tevent_req_data(req, struct ad_gpo_process_gpo_state);
 4097 
 4098     TEVENT_REQ_RETURN_ON_ERROR(req);
 4099 
 4100     *candidate_gpos = talloc_steal(mem_ctx, state->candidate_gpos);
 4101     *num_candidate_gpos = state->num_candidate_gpos;
 4102     return EOK;
 4103 }
 4104 
 4105 /* == ad_gpo_process_cse_send/recv helpers ================================= */
 4106 static errno_t
 4107 create_cse_send_buffer(TALLOC_CTX *mem_ctx,
 4108                        const char *smb_server,
 4109                        const char *smb_share,
 4110                        const char *smb_path,
 4111                        const char *smb_cse_suffix,
 4112                        int cached_gpt_version,
 4113                        struct io_buffer **io_buf)
 4114 {
 4115     struct io_buffer *buf;
 4116     size_t rp;
 4117     int smb_server_length;
 4118     int smb_share_length;
 4119     int smb_path_length;
 4120     int smb_cse_suffix_length;
 4121 
 4122     smb_server_length = strlen(smb_server);
 4123     smb_share_length = strlen(smb_share);
 4124     smb_path_length = strlen(smb_path);
 4125     smb_cse_suffix_length = strlen(smb_cse_suffix);
 4126 
 4127     buf = talloc(mem_ctx, struct io_buffer);
 4128     if (buf == NULL) {
 4129         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
 4130         return ENOMEM;
 4131     }
 4132 
 4133     buf->size = 5 * sizeof(uint32_t);
 4134     buf->size += smb_server_length + smb_share_length + smb_path_length +
 4135         smb_cse_suffix_length;
 4136 
 4137     DEBUG(SSSDBG_TRACE_ALL, "buffer size: %zu\n", buf->size);
 4138 
 4139     buf->data = talloc_size(buf, buf->size);
 4140     if (buf->data == NULL) {
 4141         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
 4142         talloc_free(buf);
 4143         return ENOMEM;
 4144     }
 4145 
 4146     rp = 0;
 4147     /* cached_gpt_version */
 4148     SAFEALIGN_SET_UINT32(&buf->data[rp], cached_gpt_version, &rp);
 4149 
 4150     /* smb_server */
 4151     SAFEALIGN_SET_UINT32(&buf->data[rp], smb_server_length, &rp);
 4152     safealign_memcpy(&buf->data[rp], smb_server, smb_server_length, &rp);
 4153 
 4154     /* smb_share */
 4155     SAFEALIGN_SET_UINT32(&buf->data[rp], smb_share_length, &rp);
 4156     safealign_memcpy(&buf->data[rp], smb_share, smb_share_length, &rp);
 4157 
 4158     /* smb_path */
 4159     SAFEALIGN_SET_UINT32(&buf->data[rp], smb_path_length, &rp);
 4160     safealign_memcpy(&buf->data[rp], smb_path, smb_path_length, &rp);
 4161 
 4162     /* smb_cse_suffix */
 4163     SAFEALIGN_SET_UINT32(&buf->data[rp], smb_cse_suffix_length, &rp);
 4164     safealign_memcpy(&buf->data[rp], smb_cse_suffix, smb_cse_suffix_length, &rp);
 4165 
 4166     *io_buf = buf;
 4167     return EOK;
 4168 }
 4169 
 4170 static errno_t
 4171 ad_gpo_parse_gpo_child_response(uint8_t *buf,
 4172                                 ssize_t size,
 4173                                 uint32_t *_sysvol_gpt_version,
 4174                                 uint32_t *_result)
 4175 {
 4176 
 4177     int ret;
 4178     size_t p = 0;
 4179     uint32_t sysvol_gpt_version;
 4180     uint32_t result;
 4181 
 4182     /* sysvol_gpt_version */
 4183     SAFEALIGN_COPY_UINT32_CHECK(&sysvol_gpt_version, buf + p, size, &p);
 4184 
 4185     /* operation result code */
 4186     SAFEALIGN_COPY_UINT32_CHECK(&result, buf + p, size, &p);
 4187 
 4188     *_sysvol_gpt_version = sysvol_gpt_version;
 4189     *_result = result;
 4190 
 4191     ret = EOK;
 4192     return ret;
 4193 }
 4194 
 4195 /* == ad_gpo_process_cse_send/recv implementation ========================== */
 4196 
 4197 struct ad_gpo_process_cse_state {
 4198     struct tevent_context *ev;
 4199     struct sss_domain_info *domain;
 4200     int gpo_timeout_option;
 4201     const char *gpo_guid;
 4202     const char *smb_path;
 4203     const char *smb_cse_suffix;
 4204     pid_t child_pid;
 4205     uint8_t *buf;
 4206     ssize_t len;
 4207     struct child_io_fds *io;
 4208 };
 4209 
 4210 static errno_t gpo_fork_child(struct tevent_req *req);
 4211 static void gpo_cse_step(struct tevent_req *subreq);
 4212 static void gpo_cse_done(struct tevent_req *subreq);
 4213 
 4214 /*
 4215  * This cse-specific function (GP_EXT_GUID_SECURITY) sends the input smb uri
 4216  * components and cached_gpt_version to the gpo child, which, in turn,
 4217  * will download the GPT.INI file and policy files (as needed) and store
 4218  * them in the GPO_CACHE directory. Note that if the send_to_child input is
 4219  * false, this function simply completes the request.
 4220  */
 4221 struct tevent_req *
 4222 ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
 4223                         struct tevent_context *ev,
 4224                         bool send_to_child,
 4225                         struct sss_domain_info *domain,
 4226                         const char *gpo_guid,
 4227                         const char *smb_server,
 4228                         const char *smb_share,
 4229                         const char *smb_path,
 4230                         const char *smb_cse_suffix,
 4231                         int cached_gpt_version,
 4232                         int gpo_timeout_option)
 4233 {
 4234     struct tevent_req *req;
 4235     struct tevent_req *subreq;
 4236     struct ad_gpo_process_cse_state *state;
 4237     struct io_buffer *buf = NULL;
 4238     errno_t ret;
 4239 
 4240     req = tevent_req_create(mem_ctx, &state, struct ad_gpo_process_cse_state);
 4241     if (req == NULL) {
 4242         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 4243         return NULL;
 4244     }
 4245 
 4246     if (!send_to_child) {
 4247         /*
 4248          * if we don't need to talk to child (b/c cache timeout is still valid),
 4249          * we simply complete the request
 4250          */
 4251         ret = EOK;
 4252         goto immediately;
 4253     }
 4254 
 4255     state->ev = ev;
 4256     state->buf = NULL;
 4257     state->len = 0;
 4258     state->domain = domain;
 4259     state->gpo_timeout_option = gpo_timeout_option;
 4260     state->gpo_guid = gpo_guid;
 4261     state->smb_path = smb_path;
 4262     state->smb_cse_suffix = smb_cse_suffix;
 4263     state->io = talloc(state, struct child_io_fds);
 4264     if (state->io == NULL) {
 4265         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
 4266         ret = ENOMEM;
 4267         goto immediately;
 4268     }
 4269 
 4270     state->io->write_to_child_fd = -1;
 4271     state->io->read_from_child_fd = -1;
 4272     talloc_set_destructor((void *) state->io, child_io_destructor);
 4273 
 4274     /* prepare the data to pass to child */
 4275     ret = create_cse_send_buffer(state, smb_server, smb_share, smb_path,
 4276                                  smb_cse_suffix, cached_gpt_version, &buf);
 4277     if (ret != EOK) {
 4278         DEBUG(SSSDBG_CRIT_FAILURE, "create_cse_send_buffer failed.\n");
 4279         goto immediately;
 4280     }
 4281 
 4282     ret = gpo_fork_child(req);
 4283     if (ret != EOK) {
 4284         DEBUG(SSSDBG_CRIT_FAILURE, "gpo_fork_child failed.\n");
 4285         goto immediately;
 4286     }
 4287 
 4288     subreq = write_pipe_send(state, ev, buf->data, buf->size,
 4289                              state->io->write_to_child_fd);
 4290     if (subreq == NULL) {
 4291         ret = ENOMEM;
 4292         goto immediately;
 4293     }
 4294     tevent_req_set_callback(subreq, gpo_cse_step, req);
 4295 
 4296     return req;
 4297 
 4298 immediately:
 4299 
 4300     if (ret == EOK) {
 4301         tevent_req_done(req);
 4302         tevent_req_post(req, ev);
 4303     } else {
 4304         tevent_req_error(req, ret);
 4305         tevent_req_post(req, ev);
 4306     }
 4307 
 4308     return req;
 4309 }
 4310 
 4311 static void gpo_cse_step(struct tevent_req *subreq)
 4312 {
 4313     struct tevent_req *req;
 4314     struct ad_gpo_process_cse_state *state;
 4315     int ret;
 4316 
 4317     req = tevent_req_callback_data(subreq, struct tevent_req);
 4318     state = tevent_req_data(req, struct ad_gpo_process_cse_state);
 4319 
 4320     ret = write_pipe_recv(subreq);
 4321     talloc_zfree(subreq);
 4322     if (ret != EOK) {
 4323         tevent_req_error(req, ret);
 4324         return;
 4325     }
 4326 
 4327     PIPE_FD_CLOSE(state->io->write_to_child_fd);
 4328 
 4329     subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
 4330 
 4331     if (subreq == NULL) {
 4332         tevent_req_error(req, ENOMEM);
 4333         return;
 4334     }
 4335     tevent_req_set_callback(subreq, gpo_cse_done, req);
 4336 }
 4337 
 4338 static void gpo_cse_done(struct tevent_req *subreq)
 4339 {
 4340     struct tevent_req *req;
 4341     struct ad_gpo_process_cse_state *state;
 4342     uint32_t sysvol_gpt_version = -1;
 4343     uint32_t child_result;
 4344     time_t now;
 4345 
 4346     req = tevent_req_callback_data(subreq, struct tevent_req);
 4347     state = tevent_req_data(req, struct ad_gpo_process_cse_state);
 4348     int ret;
 4349 
 4350     ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
 4351     talloc_zfree(subreq);
 4352     if (ret != EOK) {
 4353         tevent_req_error(req, ret);
 4354         return;
 4355     }
 4356 
 4357     PIPE_FD_CLOSE(state->io->read_from_child_fd);
 4358 
 4359     ret = ad_gpo_parse_gpo_child_response(state->buf, state->len,
 4360                                           &sysvol_gpt_version, &child_result);
 4361     if (ret != EOK) {
 4362         DEBUG(SSSDBG_CRIT_FAILURE,
 4363               "ad_gpo_parse_gpo_child_response failed: [%d][%s]\n",
 4364               ret, sss_strerror(ret));
 4365         tevent_req_error(req, ret);
 4366         return;
 4367     } else if (child_result != 0){
 4368         DEBUG(SSSDBG_CRIT_FAILURE,
 4369               "Error in gpo_child: [%d][%s]\n",
 4370               child_result, strerror(child_result));
 4371         tevent_req_error(req, child_result);
 4372         return;
 4373     }
 4374 
 4375     now = time(NULL);
 4376     DEBUG(SSSDBG_TRACE_FUNC, "sysvol_gpt_version: %d\n", sysvol_gpt_version);
 4377     ret = sysdb_gpo_store_gpo(state->domain, state->gpo_guid, sysvol_gpt_version,
 4378                               state->gpo_timeout_option, now);
 4379     if (ret != EOK) {
 4380         DEBUG(SSSDBG_OP_FAILURE, "Unable to store gpo cache entry: [%d](%s}\n",
 4381               ret, sss_strerror(ret));
 4382         tevent_req_error(req, ret);
 4383         return;
 4384     }
 4385 
 4386     tevent_req_done(req);
 4387     return;
 4388 }
 4389 
 4390 int ad_gpo_process_cse_recv(struct tevent_req *req)
 4391 {
 4392     TEVENT_REQ_RETURN_ON_ERROR(req);
 4393     return EOK;
 4394 }
 4395 
 4396 static errno_t
 4397 gpo_fork_child(struct tevent_req *req)
 4398 {
 4399     int pipefd_to_child[2] = PIPE_INIT;
 4400     int pipefd_from_child[2] = PIPE_INIT;
 4401     pid_t pid;
 4402     errno_t ret;
 4403     struct ad_gpo_process_cse_state *state;
 4404 
 4405     state = tevent_req_data(req, struct ad_gpo_process_cse_state);
 4406 
 4407     ret = pipe(pipefd_from_child);
 4408     if (ret == -1) {
 4409         ret = errno;
 4410         DEBUG(SSSDBG_CRIT_FAILURE,
 4411               "pipe failed [%d][%s].\n", errno, strerror(errno));
 4412         goto fail;
 4413     }
 4414     ret = pipe(pipefd_to_child);
 4415     if (ret == -1) {
 4416         ret = errno;
 4417         DEBUG(SSSDBG_CRIT_FAILURE,
 4418               "pipe failed [%d][%s].\n", errno, strerror(errno));
 4419         goto fail;
 4420     }
 4421 
 4422     pid = fork();
 4423 
 4424     if (pid == 0) { /* child */
 4425         exec_child_ex(state,
 4426                       pipefd_to_child, pipefd_from_child,
 4427                       GPO_CHILD, gpo_child_debug_fd, NULL, false,
 4428                       STDIN_FILENO, AD_GPO_CHILD_OUT_FILENO);
 4429 
 4430         /* We should never get here */
 4431         DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec gpo_child:\n");
 4432     } else if (pid > 0) { /* parent */
 4433         state->child_pid = pid;
 4434         state->io->read_from_child_fd = pipefd_from_child[0];
 4435         PIPE_FD_CLOSE(pipefd_from_child[1]);
 4436         state->io->write_to_child_fd = pipefd_to_child[1];
 4437         PIPE_FD_CLOSE(pipefd_to_child[0]);
 4438         sss_fd_nonblocking(state->io->read_from_child_fd);
 4439         sss_fd_nonblocking(state->io->write_to_child_fd);
 4440 
 4441         ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
 4442         if (ret != EOK) {
 4443             DEBUG(SSSDBG_CRIT_FAILURE,
 4444                   "Could not set up child signal handler\n");
 4445             goto fail;
 4446         }
 4447     } else { /* error */
 4448         ret = errno;
 4449         DEBUG(SSSDBG_CRIT_FAILURE,
 4450               "fork failed [%d][%s].\n", errno, strerror(errno));
 4451         goto fail;
 4452     }
 4453 
 4454     return EOK;
 4455 
 4456 fail:
 4457     PIPE_CLOSE(pipefd_from_child);
 4458     PIPE_CLOSE(pipefd_to_child);
 4459     return ret;
 4460 }
 4461 
 4462 struct ad_gpo_get_sd_referral_state {
 4463     struct tevent_context *ev;
 4464     struct ad_access_ctx *access_ctx;
 4465     struct sdap_options *opts;
 4466     struct sss_domain_info *host_domain;
 4467     struct sss_domain_info *ref_domain;
 4468     struct sdap_id_conn_ctx *conn;
 4469     struct sdap_id_op *ref_op;
 4470     int timeout;
 4471     char *gpo_dn;
 4472     char *smb_host;
 4473 
 4474 
 4475     struct sysdb_attrs *reply;
 4476 };
 4477 
 4478 static void
 4479 ad_gpo_get_sd_referral_conn_done(struct tevent_req *subreq);
 4480 
 4481 static struct tevent_req *
 4482 ad_gpo_get_sd_referral_send(TALLOC_CTX *mem_ctx,
 4483                             struct tevent_context *ev,
 4484                             struct ad_access_ctx *access_ctx,
 4485                             struct sdap_options *opts,
 4486                             const char *referral,
 4487                             struct sss_domain_info *host_domain,
 4488                             int timeout)
 4489 {
 4490     errno_t ret;
 4491     struct tevent_req *req;
 4492     struct ad_gpo_get_sd_referral_state *state;
 4493     struct tevent_req *subreq;
 4494     LDAPURLDesc *lud = NULL;
 4495 
 4496     req = tevent_req_create(mem_ctx, &state,
 4497                             struct ad_gpo_get_sd_referral_state);
 4498     if (!req) return NULL;
 4499 
 4500     state->ev = ev;
 4501     state->access_ctx = access_ctx;
 4502     state->opts = opts;
 4503     state->host_domain = host_domain;
 4504     state->timeout = timeout;
 4505 
 4506     /* Parse the URL for the domain */
 4507     ret = ldap_url_parse(referral, &lud);
 4508     if (ret != LDAP_SUCCESS) {
 4509         DEBUG(SSSDBG_CRIT_FAILURE,
 4510               "Failed to parse referral URI (%s)!\n", referral);
 4511         ret = EINVAL;
 4512         goto done;
 4513     }
 4514 
 4515     state->gpo_dn = talloc_strdup(state, lud->lud_dn);
 4516     if (!state->gpo_dn) {
 4517         DEBUG(SSSDBG_OP_FAILURE,
 4518               "Could not copy referral DN (%s)!\n", lud->lud_dn);
 4519         ldap_free_urldesc(lud);
 4520         ret = ENOMEM;
 4521         goto done;
 4522     }
 4523 
 4524     /* Active Directory returns the domain name as the hostname
 4525      * in these referrals, so we can use that to look up the
 4526      * necessary connection.
 4527      */
 4528     state->ref_domain = find_domain_by_name(state->host_domain,
 4529                                             lud->lud_host, true);
 4530     if (!state->ref_domain) {
 4531         DEBUG(SSSDBG_CRIT_FAILURE,
 4532               "Could not find domain matching [%s]\n",
 4533               lud->lud_host);
 4534         ldap_free_urldesc(lud);
 4535         ret = EIO;
 4536         goto done;
 4537     }
 4538 
 4539     ldap_free_urldesc(lud);
 4540     lud = NULL;
 4541 
 4542     state->conn = ad_get_dom_ldap_conn(state->access_ctx->ad_id_ctx,
 4543                                        state->ref_domain);
 4544     if (!state->conn) {
 4545         DEBUG(SSSDBG_OP_FAILURE,
 4546               "No connection for %s\n", state->ref_domain->name);
 4547         ret = EINVAL;
 4548         goto done;
 4549     }
 4550 
 4551     /* Get the hostname we're going to connect to.
 4552      * We'll need this later for performing the samba
 4553      * connection.
 4554      */
 4555     ret = ldap_url_parse(state->conn->service->uri, &lud);
 4556     if (ret != LDAP_SUCCESS) {
 4557         DEBUG(SSSDBG_CRIT_FAILURE,
 4558               "Failed to parse service URI (%s)!\n", referral);
 4559         ret = EINVAL;
 4560         goto done;
 4561     }
 4562 
 4563     state->smb_host = talloc_strdup(state, lud->lud_host);
 4564     ldap_free_urldesc(lud);
 4565     if (!state->smb_host) {
 4566         ret = ENOMEM;
 4567         goto done;
 4568     }
 4569 
 4570     /* Start an ID operation for the referral */
 4571     state->ref_op = sdap_id_op_create(state, state->conn->conn_cache);
 4572     if (!state->ref_op) {
 4573         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
 4574         ret = ENOMEM;
 4575         goto done;
 4576     }
 4577 
 4578     /* Establish the sdap_id_op connection */
 4579     subreq = sdap_id_op_connect_send(state->ref_op, state, &ret);
 4580     if (subreq == NULL) {
 4581         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
 4582                                   ret, sss_strerror(ret));
 4583         goto done;
 4584     }
 4585     tevent_req_set_callback(subreq, ad_gpo_get_sd_referral_conn_done, req);
 4586 
 4587 done:
 4588 
 4589     if (ret != EOK) {
 4590         tevent_req_error(req, ret);
 4591         tevent_req_post(req, ev);
 4592     }
 4593     return req;
 4594 }
 4595 
 4596 static void
 4597 ad_gpo_get_sd_referral_search_done(struct tevent_req *subreq);
 4598 
 4599 static void
 4600 ad_gpo_get_sd_referral_conn_done(struct tevent_req *subreq)
 4601 {
 4602     errno_t ret;
 4603     int dp_error;
 4604     const char *attrs[] = AD_GPO_ATTRS;
 4605 
 4606     struct tevent_req *req =
 4607             tevent_req_callback_data(subreq, struct tevent_req);
 4608     struct ad_gpo_get_sd_referral_state *state =
 4609             tevent_req_data(req, struct ad_gpo_get_sd_referral_state);
 4610 
 4611     ret = sdap_id_op_connect_recv(subreq, &dp_error);
 4612     talloc_zfree(subreq);
 4613     if (ret != EOK) {
 4614         if (dp_error == DP_ERR_OFFLINE) {
 4615             DEBUG(SSSDBG_TRACE_FUNC,
 4616                   "Backend is marked offline, retry later!\n");
 4617             tevent_req_done(req);
 4618         } else {
 4619             DEBUG(SSSDBG_MINOR_FAILURE,
 4620                   "Cross-realm GPO processing failed to connect to " \
 4621                    "referred LDAP server: (%d)[%s]\n",
 4622                    ret, sss_strerror(ret));
 4623             tevent_req_error(req, ret);
 4624         }
 4625         return;
 4626     }
 4627 
 4628     /* Request the referred GPO data */
 4629     subreq = sdap_sd_search_send(state, state->ev, state->opts,
 4630                                  sdap_id_op_handle(state->ref_op),
 4631                                  state->gpo_dn,
 4632                                  SECINFO_DACL,
 4633                                  attrs,
 4634                                  state->timeout);
 4635     if (subreq == NULL) {
 4636         DEBUG(SSSDBG_OP_FAILURE, "sdap_sd_search_send failed.\n");
 4637         tevent_req_error(req, ENOMEM);
 4638         return;
 4639     }
 4640     tevent_req_set_callback(subreq, ad_gpo_get_sd_referral_search_done, req);
 4641 
 4642 }
 4643 
 4644 static void
 4645 ad_gpo_get_sd_referral_search_done(struct tevent_req *subreq)
 4646 {
 4647     errno_t ret;
 4648     int dp_error;
 4649     size_t num_results, num_refs;
 4650     struct sysdb_attrs **results = NULL;
 4651     char **refs;
 4652     struct tevent_req *req =
 4653             tevent_req_callback_data(subreq, struct tevent_req);
 4654     struct ad_gpo_get_sd_referral_state *state =
 4655             tevent_req_data(req, struct ad_gpo_get_sd_referral_state);
 4656 
 4657     ret = sdap_sd_search_recv(subreq, NULL,
 4658                               &num_results, &results,
 4659                               &num_refs, &refs);
 4660     talloc_zfree(subreq);
 4661     if (ret != EOK) {
 4662         ret = sdap_id_op_done(state->ref_op, ret, &dp_error);
 4663 
 4664         DEBUG(SSSDBG_OP_FAILURE,
 4665               "Unable to get GPO attributes: [%d](%s)\n",
 4666               ret, sss_strerror(ret));
 4667         ret = ENOENT;
 4668         goto done;
 4669 
 4670     }
 4671 
 4672     if ((num_results < 1) || (results == NULL)) {
 4673         /* TODO:
 4674          * It's strictly possible for the referral search to return
 4675          * another referral value here, but it shouldn't actually
 4676          * happen with Active Directory. Properly handling (and
 4677          * limiting) the referral chain would be fairly complex, so
 4678          * we will do it later if it ever becomes necessary.
 4679          */
 4680         DEBUG(SSSDBG_OP_FAILURE,
 4681               "No attrs found for referred GPO [%s].\n", state->gpo_dn);
 4682         ret = ENOENT;
 4683         goto done;
 4684 
 4685     } else if (num_results > 1) {
 4686         DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
 4687         ret = ERR_INTERNAL;
 4688         goto done;
 4689     }
 4690 
 4691     state->reply = talloc_steal(state, results[0]);
 4692 
 4693 done:
 4694    talloc_free(results);
 4695 
 4696    if (ret == EOK) {
 4697        tevent_req_done(req);
 4698    } else if (ret != EAGAIN) {
 4699        tevent_req_error(req, ret);
 4700    }
 4701 }
 4702 
 4703 errno_t
 4704 ad_gpo_get_sd_referral_recv(struct tevent_req *req,
 4705                             TALLOC_CTX *mem_ctx,
 4706                             char **_smb_host,
 4707                             struct sysdb_attrs **_reply)
 4708 {
 4709     struct ad_gpo_get_sd_referral_state *state =
 4710                 tevent_req_data(req, struct ad_gpo_get_sd_referral_state);
 4711 
 4712     TEVENT_REQ_RETURN_ON_ERROR(req);
 4713 
 4714     *_smb_host = talloc_steal(mem_ctx, state->smb_host);
 4715     *_reply = talloc_steal(mem_ctx, state->reply);
 4716 
 4717     return EOK;
 4718 }