LCOV - code coverage report
Current view: top level - providers/ad - ad_gpo.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 140 1854 7.6 %
Date: 2015-10-19 Functions: 5 59 8.5 %

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

Generated by: LCOV version 1.10