ad_gpo.c revision 77b13371c87702aee3f858f6b2b73826cf5a01bd
/*
SSSD
Authors:
Yassir Elley <yelley@redhat.com>
Copyright (C) 2013 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file implements the following pair of *public* functions (see header):
* ad_gpo_access_send/recv: provides client-side GPO processing
*
* This file also implements the following pairs of *private* functions (which
* are used by the public functions):
* ad_gpo_process_som_send/recv: populate list of gp_som objects
* ad_gpo_process_gpo_send/recv: populate list of gp_gpo objects
* ad_gpo_process_cse_send/recv: retrieve policy file data
*/
#include <security/pam_modules.h>
#include <syslog.h>
#include <fcntl.h>
#include <ini_configobj.h>
#include "util/strtonum.h"
#include "util/child_common.h"
#include "providers/data_provider.h"
#include "providers/dp_backend.h"
#include "providers/ad/ad_access.h"
#include "providers/ad/ad_common.h"
#include "providers/ad/ad_domain_info.h"
#include "providers/ldap/sdap_access.h"
#include "providers/ldap/sdap_async.h"
#include "providers/ldap/sdap_idmap.h"
#include "util/util_sss_idmap.h"
#include <ndr.h>
#include <gen_ndr/security.h>
/* == gpo-ldap constants =================================================== */
#define AD_AT_DN "distinguishedName"
#define AD_AT_UAC "userAccountControl"
#define AD_AT_CONFIG_NC "configurationNamingContext"
#define AD_AT_GPLINK "gPLink"
#define AD_AT_GPOPTIONS "gpOptions"
#define AD_AT_NT_SEC_DESC "nTSecurityDescriptor"
#define AD_AT_CN "cn"
#define AD_AT_FILE_SYS_PATH "gPCFileSysPath"
#define AD_AT_MACHINE_EXT_NAMES "gPCMachineExtensionNames"
#define AD_AT_FUNC_VERSION "gPCFunctionalityVersion"
#define AD_AT_FLAGS "flags"
#define UAC_WORKSTATION_TRUST_ACCOUNT 0x00001000
#define AD_AGP_GUID "edacfd8f-ffb3-11d1-b41d-00a0c968f939"
#define AD_AUTHENTICATED_USERS_SID "S-1-5-11"
/* == gpo-smb constants ==================================================== */
#define SMB_STANDARD_URI "smb://"
#define BUFSIZE 65536
#define RIGHTS_SECTION "Privilege Rights"
#define ALLOW_LOGON_INTERACTIVE "SeInteractiveLogonRight"
#define DENY_LOGON_INTERACTIVE "SeDenyInteractiveLogonRight"
#define ALLOW_LOGON_REMOTE_INTERACTIVE "SeRemoteInteractiveLogonRight"
#define DENY_LOGON_REMOTE_INTERACTIVE "SeDenyRemoteInteractiveLogonRight"
#define ALLOW_LOGON_NETWORK "SeNetworkLogonRight"
#define DENY_LOGON_NETWORK "SeDenyNetworkLogonRight"
#define ALLOW_LOGON_BATCH "SeBatchLogonRight"
#define DENY_LOGON_BATCH "SeDenyBatchLogonRight"
#define ALLOW_LOGON_SERVICE "SeServiceLogonRight"
#define DENY_LOGON_SERVICE "SeDenyServiceLogonRight"
#define GP_EXT_GUID_SECURITY "{827D319E-6EAC-11D2-A4EA-00C04F79F83A}"
#ifndef SSSD_LIBEXEC_PATH
#error "SSSD_LIBEXEC_PATH not defined"
#else
#endif
/* fd used by the gpo_child process for logging */
int gpo_child_debug_fd = -1;
/* == common data structures and declarations ============================= */
struct gp_som {
const char *som_dn;
struct gp_gplink **gplink_list;
int num_gplinks;
};
struct gp_gplink {
const char *gpo_dn;
bool enforced;
};
struct gp_gpo {
struct security_descriptor *gpo_sd;
const char *gpo_dn;
const char *gpo_guid;
const char *smb_server;
const char *smb_share;
const char *smb_path;
const char **gpo_cse_guids;
int num_gpo_cse_guids;
int gpo_func_version;
int gpo_flags;
bool send_to_child;
const char *policy_filename;
};
enum ace_eval_status {
};
struct tevent_context *ev,
struct sdap_id_conn_ctx *conn,
struct ldb_context *ldb_ctx,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
int timeout,
const char *target_dn,
const char *domain_name);
struct tevent_context *ev,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
char *server_hostname,
int timeout,
struct gp_gpo ***candidate_gpos,
int *num_candidate_gpos);
struct tevent_context *ev,
bool send_to_child,
struct sss_domain_info *domain,
const char *gpo_guid,
const char *smb_server,
const char *smb_share,
const char *smb_path,
const char *smb_cse_suffix,
int cached_gpt_version,
int gpo_timeout_option);
/* == ad_gpo_parse_map_options and helpers ==================================*/
#define GPO_LOGIN "login"
#define GPO_SU "su"
#define GPO_SU_L "su-l"
#define GPO_GDM_FINGERPRINT "gdm-fingerprint"
#define GPO_GDM_PASSWORD "gdm-password"
#define GPO_GDM_SMARTCARD "gdm-smartcard"
#define GPO_KDM "kdm"
#define GPO_SSHD "sshd"
#define GPO_FTP "ftp"
#define GPO_SAMBA "samba"
#define GPO_CROND "crond"
#define GPO_SUDO "sudo"
#define GPO_SUDO_I "sudo-i"
struct gpo_map_option_entry {
enum gpo_map_type gpo_map_type;
enum ad_basic_opt ad_basic_opt;
const char **gpo_map_defaults;
const char *allow_key;
const char *deny_key;
};
const char *gpo_map_interactive_defaults[] =
const char *gpo_map_service_defaults[] = {NULL};
const char *gpo_map_deny_defaults[] = {NULL};
struct gpo_map_option_entry gpo_map_option_entries[] = {
};
const char* gpo_map_type_string(int gpo_map_type)
{
switch(gpo_map_type) {
case GPO_MAP_INTERACTIVE: return "Interactive";
case GPO_MAP_REMOTE_INTERACTIVE: return "Remote Interactive";
case GPO_MAP_NETWORK: return "Network";
case GPO_MAP_BATCH: return "Batch";
case GPO_MAP_SERVICE: return "Service";
case GPO_MAP_PERMIT: return "Permitted";
case GPO_MAP_DENY: return "Denied";
}
return NULL;
}
static inline bool
{
size_t i;
for (i = 0; i < nlist; i++) {
break;
}
}
return (i < nlist) ? true : false;
}
{
int hret;
int ret;
goto done;
} else if (hret == HASH_SUCCESS) {
/* handle unexpected case where mapping for key already exists */
if (val.i == gpo_map_type) {
/* mapping for key exists for same map type; no error */
} else {
/* mapping for key exists for different map type; error! */
}
goto done;
} else {
/* handle expected case where mapping for key doesn't already exist */
val.i = gpo_map_type;
if (hret != HASH_SUCCESS) {
goto done;
}
}
done:
return ret;
}
enum gpo_map_type gpo_map_type,
char *conf_str,
const char **defaults)
{
int conf_list_size = 0;
char **remove_list = NULL;
int i;
goto done;
}
if (conf_str) {
&conf_list, &conf_list_size);
goto done;
}
goto done;
}
}
for (i = 0; i < conf_list_size; i++) {
switch (conf_list[i][0]) {
case '+':
ai++;
continue;
case '-':
ri++;
continue;
default:
"either '+' (for adding service) or '-' (for removing service), "
"got '%s'\n",
conf_list[i]);
goto done;
}
}
/* Start by adding explicitly added services ('+') to hashtable */
for (i = 0; i < ai; i++) {
/* if the service is explicitly configured to be removed, skip it */
continue;
}
goto done;
}
}
/* Add defaults to hashtable */
for (i = 0; defaults[i]; i++) {
/* if the service is explicitly configured to be removed, skip it */
continue;
}
goto done;
}
}
done:
return ret;
}
{
char *gpo_default_right_config;
int i;
for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
goto fail;
}
}
/* default right (applicable for services without any mapping) */
/* if default right not set in config, set them to DENY */
if (gpo_default_right_config == NULL) {
strlen("interactive")) == 0) {
strlen("remote_interactive")) == 0) {
strlen("network")) == 0) {
strlen("batch")) == 0) {
strlen("service")) == 0) {
strlen("permit")) == 0) {
strlen("deny")) == 0) {
} else {
goto fail;
}
fail:
return ret;
}
/* == ad_gpo_access_send/recv helpers =======================================*/
static bool
{
int i;
return true;
}
return false;
}
return false;
}
for (i = 0; i < 6; i++) {
return false;
}
}
return false;
}
return false;
}
}
return true;
}
/*
* This function retrieves the SIDs corresponding to the input user and returns
* the user_sid, group_sids, and group_size in their respective output params.
*
* Note: since authentication must complete successfully before the
* has been authenticated. As such, this function always adds the
* AD_AUTHENTICATED_USERS_SID to the group_sids.
*/
static errno_t
const char *user,
struct sss_domain_info *domain,
const char **_user_sid,
const char ***_group_sids,
int *_group_size)
{
struct ldb_result *res;
int ret = 0;
int i = 0;
int num_group_sids = 0;
const char **group_sids = NULL;
goto done;
}
/* first result from sysdb_initgroups is user_sid; rest are group_sids */
"sysdb_initgroups failed: [%d](%s)\n",
return ret;
}
"sysdb_initgroups returned empty result\n");
return ret;
}
/* include space for AD_AUTHENTICATED_USERS_SID and NULL */
if (group_sids == NULL) {
goto done;
}
for (i = 0; i < num_group_sids; i++) {
continue;
}
if (group_sids[i] == NULL) {
goto done;
}
}
group_sids[i] = NULL;
return EOK;
done:
return ret;
}
/*
* This function determines whether the input ace_dom_sid matches any of the
* client's SIDs. The boolean result is assigned to the _included output param.
*/
static errno_t
ad_gpo_ace_includes_client_sid(const char *user_sid,
const char **group_sids,
int group_size,
struct dom_sid ace_dom_sid,
struct sss_idmap_ctx *idmap_ctx,
bool *_included)
{
int i = 0;
struct dom_sid *user_dom_sid;
struct dom_sid *group_dom_sid;
enum idmap_error_code err;
bool included = false;
if (err != IDMAP_SUCCESS) {
return EFAULT;
}
if (included) {
*_included = true;
return EOK;
}
for (i = 0; i < group_size; i++) {
if (err != IDMAP_SUCCESS) {
return EFAULT;
}
if (included) {
*_included = true;
return EOK;
}
}
*_included = false;
return EOK;
}
/*
* This function determines whether use of the extended right
* named "ApplyGroupPolicy" (AGP) is allowed, by comparing the specified
* user_sid and group_sids against the specified access control entry (ACE).
* This function returns ALLOWED, DENIED, or NEUTRAL depending on whether
* the ACE explictly allows, explicitly denies, or does neither.
*
* Note that the 'M' abbreviation used in the evaluation algorithm stands for
* "access_mask", which represents the set of access rights associated with an
* individual ACE. The access right of interest to the GPO code is
* RIGHT_DS_CONTROL_ACCESS, which serves as a container for all control access
* rights. The specific control access right is identified by a GUID in the
* ACE's ObjectType. In our case, this is the GUID corresponding to AGP.
*
* The ACE evaluation algorithm is specified in [MS-ADTS] 5.1.3.3.4:
* - Deny access by default
* - If the "Inherit Only" (IO) flag is set in the ACE, skip the ACE.
* - If the SID in the ACE does not match any SID in the requester's
* security context, skip the ACE
* - If the ACE type is "Object Access Allowed", the access right
* RIGHT_DS_CONTROL_ACCESS (CR) is present in M, and the ObjectType
* field in the ACE is either not present OR contains a GUID value equal
* to AGP, then grant requested control access right. Stop access checking.
* - If the ACE type is "Object Access Denied", the access right
* RIGHT_DS_CONTROL_ACCESS (CR) is present in M, and the ObjectType
* field in the ACE is either not present OR contains a GUID value equal to
* AGP, then deny the requested control access right. Stop access checking.
*/
struct sss_idmap_ctx *idmap_ctx,
const char *user_sid,
const char **group_sids,
int group_size)
{
bool agp_included = false;
bool included = false;
int ret = 0;
struct security_ace_object object;
struct GUID ext_right_agp_guid;
return AD_GPO_ACE_NEUTRAL;
}
return AD_GPO_ACE_DENIED;
}
if (!included) {
return AD_GPO_ACE_NEUTRAL;
}
agp_included = true;
}
} else {
agp_included = false;
}
if (agp_included) {
return AD_GPO_ACE_ALLOWED;
return AD_GPO_ACE_DENIED;
}
}
}
return AD_GPO_ACE_DENIED;
}
/*
* This function extracts the GPO's DACL (discretionary access control list)
* from the GPO's specified security descriptor, and determines whether
* the GPO is applicable to the policy target, by comparing the specified
* user_sid and group_sids against each access control entry (ACE) in the DACL.
* The boolean result is assigned to the _access_allowed output parameter.
*/
struct sss_idmap_ctx *idmap_ctx,
const char *user_sid,
const char **group_sids,
int group_size,
bool *_dacl_access_allowed)
{
enum ace_eval_status ace_status;
int i = 0;
/*
* [MS-ADTS] 5.1.3.3.4:
* If the DACL does not have any ACE, then deny the requester the
* requested control access right.
*/
if (num_aces == 0) {
*_dacl_access_allowed = false;
return EOK;
}
switch (ace_status) {
case AD_GPO_ACE_NEUTRAL:
continue;
case AD_GPO_ACE_ALLOWED:
*_dacl_access_allowed = true;
return EOK;
case AD_GPO_ACE_DENIED:
*_dacl_access_allowed = false;
return EOK;
}
}
*_dacl_access_allowed = false;
return EOK;
}
/*
* This function takes candidate_gpos as input, filters out any gpo that is
* not applicable to the policy target and assigns the result to the
* _dacl_filtered_gpos output parameter. The filtering algorithm is
* defined in [MS-GPOL] 3.2.5.1.6
*/
static errno_t
const char *user,
struct sss_domain_info *domain,
struct sss_idmap_ctx *idmap_ctx,
struct gp_gpo **candidate_gpos,
int num_candidate_gpos,
struct gp_gpo ***_dacl_filtered_gpos,
int *_num_dacl_filtered_gpos)
{
int i = 0;
int ret = 0;
const char **group_sids = NULL;
int group_size = 0;
int gpo_dn_idx = 0;
bool access_allowed = false;
goto done;
}
&group_sids, &group_size);
ret = ERR_NO_SIDS;
goto done;
}
struct gp_gpo *,
num_candidate_gpos + 1);
if (dacl_filtered_gpos == NULL) {
goto done;
}
for (i = 0; i < num_candidate_gpos; i++) {
access_allowed = false;
candidate_gpo = candidate_gpos[i];
/* gpo_func_version must be set to version 2 */
"GPO not applicable to target per security filtering\n");
continue;
}
/* gpo_flags value of 2 means that GPO's computer portion is disabled */
"GPO not applicable to target per security filtering\n");
continue;
}
/*
* [MS-ADTS] 5.1.3.3.4:
* If the security descriptor has no DACL or its "DACL Present" bit
* is not set, then grant requester the requested control access right.
*/
access_allowed = true;
break;
}
continue;
}
if (access_allowed) {
"GPO applicable to target per security filtering\n");
gpo_dn_idx++;
} else {
"GPO not applicable to target per security filtering\n");
continue;
}
}
done:
return ret;
}
/*
* This function determines whether the input cse_guid matches any of the input
* gpo_cse_guids. The boolean result is assigned to the _included output param.
*/
static bool
ad_gpo_includes_cse_guid(const char *cse_guid,
const char **gpo_cse_guids,
int num_gpo_cse_guids)
{
int i = 0;
const char *gpo_cse_guid = NULL;
for (i = 0; i < num_gpo_cse_guids; i++) {
gpo_cse_guid = gpo_cse_guids[i];
return true;
}
}
return false;
}
/*
* This function takes an input dacl_filtered_gpos list, filters out any gpo
* that does not contain the input cse_guid, and assigns the result to the
* _cse_filtered_gpos output parameter.
*/
static errno_t
const char *cse_guid,
struct gp_gpo **dacl_filtered_gpos,
struct gp_gpo ***_cse_filtered_gpos,
int *_num_cse_filtered_gpos)
{
int i = 0;
int ret = 0;
int gpo_dn_idx = 0;
bool included;
goto done;
}
struct gp_gpo *,
num_dacl_filtered_gpos + 1);
if (cse_filtered_gpos == NULL) {
goto done;
}
for (i = 0; i < num_dacl_filtered_gpos; i++) {
if (included) {
"GPO applicable to target per cse_guid filtering\n");
dacl_filtered_gpos[i] = NULL;
gpo_dn_idx++;
} else {
"GPO not applicable to target per cse_guid filtering\n");
continue;
}
}
done:
return ret;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) returns a boolean value
* based on whether the input user_sid or any of the input group_sids appear
* in the input list of privilege_sids.
*/
static bool
check_rights(char **privilege_sids,
int privilege_size,
const char *user_sid,
const char **group_sids,
int group_size)
{
int i, j;
for (i = 0; i < privilege_size; i++) {
return true;
}
for (j = 0; j < group_size; j++) {
return true;
}
}
}
return false;
}
/*
* This function parses the input ini_config object (which represents
* the cse-specific filename), and returns the policy_setting_value
* corresponding to the input policy_setting_key.
*/
static errno_t
struct ini_cfgobj *ini_config,
const char *policy_setting_key,
char **_policy_setting_value)
{
int ret;
const char *policy_setting_value;
if (ret != 0) {
goto done;
}
goto done;
}
if (ret != 0) {
"ini_get_string_config_value failed [%d][%s]\n",
goto done;
}
if (policy_setting_value[0]) {
if (!*_policy_setting_value) {
goto done;
}
} else {
/* This is an explicitly empty policy setting.
* We need to remove this from the LDB.
*/
}
done:
return ret;
}
/*
* This function parses the cse-specific (GP_EXT_GUID_SECURITY) filename,
* and stores the allow_key and deny_key of all of the gpo_map_types present
* in the file (as part of the GPO Result object in the sysdb cache).
*/
static errno_t
const char *filename)
{
int ret;
int i;
char *allow_value = NULL;
char *deny_value = NULL;
goto done;
}
if (ret != 0) {
goto done;
}
if (ret != 0) {
goto done;
}
if (ret != 0) {
goto done;
}
for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
&allow_value);
"ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
goto done;
"sysdb_gpo_store_gpo_result_setting failed for key:"
goto done;
}
}
}
&deny_value);
"ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
goto done;
"sysdb_gpo_store_gpo_result_setting failed for key:"
goto done;
}
}
}
}
done:
}
return ret;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) performs the access
* check for determining whether logon access is granted or denied for
* the {user,domain} tuple specified in the inputs. This function returns EOK
* to indicate that access is granted. Any other return value indicates that
* access is denied.
*
* The access control algorithm first determines whether the "principal_sids"
* (i.e. user_sid or group_sids) appear in allowed_sids and denied_sids.
*
* For access to be granted, both the "allowed_sids_condition" *and* the
* "denied_sids_condition" must be met (in all other cases, access is denied).
* 1) The "allowed_sids_condition" is satisfied if any of the principal_sids
* appears in allowed_sids OR if the allowed_sids list is empty
* 2) The "denied_sids_condition" is satisfied if none of the principal_sids
* appear in denied_sids
*
* Note that a deployment that is unaware of GPO-based access-control policy
* settings is unaffected by them (b/c absence of allowed_sids grants access).
*
* Note that if a principal_sid appears in both allowed_sids and denied_sids,
* the "allowed_sids_condition" is met, but the "denied_sids_condition" is not.
* In other words, Deny takes precedence over Allow.
*/
static errno_t
enum gpo_map_type gpo_map_type,
const char *user,
struct sss_domain_info *domain,
char **allowed_sids,
int allowed_size,
char **denied_sids,
int denied_size)
{
const char *user_sid;
const char **group_sids;
int group_size = 0;
bool access_granted = false;
bool access_denied = false;
int ret;
int j;
for (j= 0; j < allowed_size; j++) {
}
for (j= 0; j < denied_size; j++) {
}
&group_sids, &group_size);
ret = ERR_NO_SIDS;
goto done;
}
for (j= 0; j < group_size; j++) {
group_sids[j]);
}
if (allowed_size == 0) {
access_granted = true;
} else {
}
if (access_granted && !access_denied) {
return EOK;
} else {
switch (gpo_mode) {
return ERR_ACCESS_DENIED;
"have been denied GPO-based logon access if the " \
"ad_gpo_access_control option were set to enforcing " \
"mode.");
return EOK;
default:
return EINVAL;
}
}
done:
if (ret) {
}
return ret;
}
#define GPO_CHILD_LOG_FILE "gpo_child"
static errno_t gpo_child_init(void)
{
}
/*
* This function retrieves the raw policy_setting_value for the input key from
* the GPO_Result object in the sysdb cache. It then parses the raw value and
* uses the results to populate the output parameters with the sids_list and
* the size of the sids_list.
*/
struct sss_domain_info *domain,
const char *key,
char ***_sids_list,
int *_sids_list_size)
{
int ret;
int i;
const char *value;
int sids_list_size;
"Cannot retrieve settings from sysdb for key: '%s' [%d][%s].\n",
goto done;
}
"No value for key [%s] found in gpo result\n", key);
sids_list_size = 0;
} else {
&sids_list, &sids_list_size);
goto done;
}
for (i = 0; i < sids_list_size; i++) {
/* remove the asterisk prefix found on sids */
sids_list[i]++;
}
}
done:
return ret;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) performs HBAC policy
* processing and determines whether logon access is granted or denied for
* the {user,domain} tuple specified in the inputs. This function returns EOK
* to indicate that access is granted. Any other return value indicates that
* access is denied.
*
* Internally, this function retrieves the allow_value and deny_value for the
* input gpo_map_type from the GPO Result object in the sysdb cache, parses
* the values into allow_sids and deny_sids, and executes the access control
* algorithm which compares the allow_sids and deny_sids against the user_sid
* and group_sids for the input user.
*/
static errno_t
enum gpo_map_type gpo_map_type,
const char *user,
struct sss_domain_info *domain)
{
int ret;
char **allow_sids;
int allow_size ;
char **deny_sids;
int deny_size;
&allow_sids, &allow_size);
"parse_policy_setting_value failed for key %s: [%d](%s)\n",
goto done;
}
"parse_policy_setting_value failed for key %s: [%d](%s)\n",
goto done;
}
/* perform access check with the final resultant allow_sids and deny_sids */
"GPO access check failed: [%d](%s)\n",
goto done;
}
done:
return ret;
}
/* == ad_gpo_access_send/recv implementation ================================*/
struct ad_gpo_access_state {
struct tevent_context *ev;
struct ldb_context *ldb_ctx;
enum gpo_map_type gpo_map_type;
struct sdap_id_conn_ctx *conn;
struct sdap_id_op *sdap_op;
char *server_hostname;
struct sdap_options *opts;
int timeout;
struct sss_domain_info *domain;
const char *user;
int gpo_timeout_option;
const char *ad_hostname;
const char *target_dn;
struct gp_gpo **dacl_filtered_gpos;
struct gp_gpo **cse_filtered_gpos;
int cse_gpo_index;
};
struct tevent_req *
struct tevent_context *ev,
struct sss_domain_info *domain,
struct ad_access_ctx *ctx,
const char *user,
const char *service)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct ad_gpo_access_state *state;
char *server_uri;
int hret;
enum gpo_map_type gpo_map_type;
/* setup logging for gpo child */
return NULL;
}
/* determine service's option_type (e.g. interactive, network, etc) */
goto immediately;
}
/* if service isn't mapped, map it to value of ad_gpo_default_right option */
if (hret == HASH_ERROR_KEY_NOT_FOUND) {
} else {
}
if (gpo_map_type == GPO_MAP_PERMIT) {
goto immediately;
}
if (gpo_map_type == GPO_MAP_DENY) {
switch (ctx->gpo_access_control_mode) {
goto immediately;
"have been denied GPO-based logon access if the " \
"ad_gpo_access_control option were set to enforcing " \
"mode.");
goto immediately;
default:
goto immediately;
}
}
state->num_dacl_filtered_gpos = 0;
state->num_cse_filtered_gpos = 0;
state->cse_gpo_index = 0;
goto immediately;
}
/* extract server_hostname from server_uri */
if (ret != LDAP_SUCCESS) {
"Failed to parse ldap URI (%s)!\n", server_uri);
goto immediately;
}
"The LDAP URI (%s) did not contain a host name\n", server_uri);
goto immediately;
}
if (!state->server_hostname) {
goto immediately;
}
"sdap_id_op_connect_send failed: [%d](%s)\n",
goto immediately;
}
}
return req;
}
static errno_t
const char *user,
struct sss_domain_info *domain,
enum gpo_map_type gpo_map_type)
{
user,
domain);
goto done;
}
/* we have successfully processed all offline gpos */
done:
return ret;
}
static void
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
char *filter;
char *sam_account_name;
char *domain_dn;
int dp_error;
if (dp_error != DP_ERR_OFFLINE) {
"Failed to connect to AD server: [%d](%s)\n",
goto done;
} else {
goto done;
} else {
"process_offline_gpos failed [%d](%s)\n",
goto done;
}
}
}
if (sam_account_name == NULL) {
goto done;
}
/* Convert the domain name into domain DN */
"Cannot convert domain name [%s] to base DN [%d]: %s\n",
goto done;
}
/* SDAP_OC_USER objectclass covers both users and computers */
"(&(objectclass=%s)(%s=%s))",
goto done;
}
false);
goto done;
}
done:
}
}
static void
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
int dp_error;
struct sysdb_attrs **reply;
&reply_count, &reply);
"Unable to get policy target's DN: [%d](%s)\n",
goto done;
}
/* make sure there is only one non-NULL reply returned */
if (reply_count < 1) {
goto done;
} else if (reply_count > 1) {
ret = ERR_INTERNAL;
goto done;
ret = ERR_INTERNAL;
goto done;
}
/* reply[0] holds requested attributes of single reply */
"sysdb_attrs_get_string failed: [%d](%s)\n",
goto done;
}
goto done;
}
"sysdb_attrs_get_uint32_t failed: [%d](%s)\n",
goto done;
}
/* we only support computer policy targets, not users */
if (!(uac & UAC_WORKSTATION_TRUST_ACCOUNT)) {
goto done;
}
goto done;
}
done:
}
}
static void
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
"Unable to get som list: [%d](%s)\n",
goto done;
}
som_list);
goto done;
}
done:
}
}
/*
* This function retrieves a list of candidate_gpos and potentially reduces it
* to a list of dacl_filtered_gpos, based on each GPO's DACL.
*
* This function then takes the list of dacl_filtered_gpos and potentially
* reduces it to a list of cse_filtered_gpos, based on whether each GPO's list
* of cse_guids includes the "SecuritySettings" CSE GUID (used for HBAC).
*
* Ultimately, this function then sends each cse_filtered_gpo to the gpo_child,
* which retrieves the GPT.INI and policy files (as needed). Once all files
* have been downloaded, the ad_gpo_cse_done function performs HBAC processing.
*/
static void
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
int dp_error;
int num_candidate_gpos = 0;
int i = 0;
const char **cse_filtered_gpo_guids;
"Unable to get GPO list: [%d](%s)\n",
goto done;
}
"Unable to filter GPO list by DACKL: [%d](%s)\n",
goto done;
}
/* since no applicable gpos were found, there is nothing to enforce */
"no applicable gpos found after dacl filtering\n");
goto done;
}
for (i = 0; i < state->num_dacl_filtered_gpos; i++) {
}
"Unable to filter GPO list by CSE_GUID: [%d](%s)\n",
goto done;
}
/* no gpos contain "SecuritySettings" cse_guid, nothing to enforce */
"no applicable gpos found after cse_guid filtering\n");
goto done;
}
/* we create and populate an array of applicable gpo-guids */
if (cse_filtered_gpo_guids == NULL) {
goto done;
}
for (i = 0; i < state->num_cse_filtered_gpos; i++) {
if (cse_filtered_gpo_guids[i] == NULL) {
goto done;
}
}
/*
* before we start processing each gpo, we delete the GPO Result object
* from the sysdb cache so that any previous policy settings are cleared;
* subsequent functions will add the GPO Result object (and populate it
* with resultant policy settings) for this policy application
*/
switch (ret) {
case ENOENT:
break;
default:
"Could not delete GPO Result from cache: [%s]\n",
goto done;
}
}
done:
}
}
static errno_t
{
struct tevent_req *subreq;
struct ad_gpo_access_state *state;
int i = 0;
struct ldb_result *res;
bool send_to_child = true;
int cached_gpt_version = 0;
struct gp_gpo *cse_filtered_gpo =
/* cse_filtered_gpo is NULL after all GPO policy files have been downloaded */
for (i = 0; i < cse_filtered_gpo->num_gpo_cse_guids; i++) {
"cse_filtered_gpos[%d]->gpo_cse_guids[%d]->gpo_guid is %s\n",
}
GPO_CACHE_PATH"%s%s",
return ENOMEM;
}
/* retrieve gpo cache entry; set cached_gpt_version to -1 if unavailable */
&res);
/*
* Note: if the timeout is valid, then we can later avoid downloading
* the GPT.INI file, as well as any policy files (i.e. we don't need
* to interact with the gpo_child at all). However, even if the timeout
* is not valid, while we will have to interact with the gpo child to
* download the GPT.INI file, we may still be able to avoid downloading
* the policy files (if the cached_gpt_version is the same as the
* GPT.INI version). In other words, the timeout is *not* an expiration
* for the entire cache entry; the cached_gpt_version never expires.
*/
0);
send_to_child = false;
}
cached_gpt_version = -1;
} else {
return ret;
}
return EAGAIN;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) increments the
* cse_gpo_index until the policy settings for all applicable GPOs have been
* stored as part of the GPO Result object in the sysdb cache. Once all
* GPOs have been processed, this functions performs HBAC processing by
* comparing the resultant policy setting values in the GPO Result object
* with the user_sid/group_sids of interest.
*/
static void
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
struct gp_gpo *cse_filtered_gpo =
goto done;
}
/*
* now that the policy file for this gpo have been downloaded to the
* GPO CACHE, we store all of the supported keys present in the file
* (as part of the GPO Result object in the sysdb cache).
*/
state->cse_gpo_index++;
/* ret is EOK only after all GPO policy files have been downloaded */
goto done;
}
}
done:
}
}
{
return EOK;
}
/* == ad_gpo_process_som_send/recv helpers ================================= */
/*
* This function returns the parent of an LDAP DN
*/
static errno_t
struct ldb_context *ldb_ctx,
const char *dn,
const char **_parent_dn)
{
struct ldb_dn *parent_ldb_dn;
const char *p;
int ret;
goto done;
}
done:
return ret;
}
/*
* This function populates the _som_list output parameter by parsing the input
* DN into a list of gp_som objects. This function essentially repeatedly
* appends the input DN's parent to the SOM List (if the parent starts with
* "OU=" or "DC="), until the first "DC=" component is reached.
* Example: if input DN is "CN=MyComputer,CN=Computers,OU=Sales,DC=FOO,DC=COM",
* then SOM List has 2 SOM entries: {[OU=Sales,DC=FOO,DC=COM], [DC=FOO, DC=COM]}
*/
static errno_t
struct ldb_context *ldb_ctx,
const char *target_dn,
int *_num_soms,
{
int ret;
int rdn_count = 0;
int som_idx = 0;
struct ldb_dn *ldb_target_dn;
goto done;
}
if (ldb_target_dn == NULL) {
goto done;
}
if (rdn_count == -1) {
goto done;
}
if (rdn_count == 0) {
goto done;
}
/* assume the worst-case, in which every parent is a SOM */
/* include space for Site SOM and NULL: rdn_count + 1 + 1 */
goto done;
}
/* first, populate the OU and Domain SOMs */
goto done;
}
goto done;
}
som_idx++;
}
break;
}
}
done:
return ret;
}
/*
* This function populates the _gplink_list output parameter by parsing the
* input raw_gplink_value into an array of gp_gplink objects, each consisting of
* a GPO DN and bool enforced field.
*
* The raw_gplink_value is single string consisting of multiple gplink strings.
* The raw_gplink_value is in the following format:
* "[GPO_DN_1;GPLinkOptions_1]...[GPO_DN_n;GPLinkOptions_n]"
*
* Each gplink string consists of a GPO DN and a GPLinkOptions field (which
* indicates whether its associated GPO DN is ignored, unenforced, or enforced).
* If a GPO DN is flagged as ignored, it is discarded and will not be added to
* the _gplink_list. If the allow_enforced_only input is true, AND a GPO DN is
* flagged as unenforced, it will also be discarded.
*
* Example: if raw_gplink_value="[OU=Sales,DC=FOO,DC=COM;0][DC=FOO,DC=COM;2]"
* and allow_enforced_only=FALSE, then the output would consist of following:
* _gplink_list[0]: {GPO DN: "OU=Sales,DC=FOO,DC=COM", enforced: FALSE}
* _gplink_list[1]: {GPO DN: "DC=FOO,DC=COM", enforced: TRUE}
*/
static errno_t
const char *som_dn,
char *raw_gplink_value,
struct gp_gplink ***_gplink_list,
bool allow_enforced_only)
{
char *ptr;
char *first;
char *last;
char *dn;
char *gplink_options;
const char delim = ']';
struct gp_gplink **gplink_list;
int i;
int ret;
int gplink_count = 0;
int num_enabled = 0;
if (raw_gplink_value == NULL ||
*raw_gplink_value == '\0' ||
_gplink_list == NULL) {
return EINVAL;
}
goto done;
}
ptr++;
gplink_count++;
}
if (gplink_count == 0) {
goto done;
}
if (gplink_list == NULL) {
goto done;
}
num_enabled = 0;
for (i = 0; i < gplink_count; i++) {
goto done;
}
*last = '\0';
last++;
}
if (gplink_options == NULL) {
goto done;
}
*gplink_options = '\0';
if (errno != 0) {
goto done;
}
/* ignore flag is set */
continue;
}
if (allow_enforced_only && (gplink_number == 0)) {
/* unenforced flag is set; only enforced gpos allowed */
continue;
}
goto done;
}
goto done;
}
if (gplink_number == 0) {
num_enabled++;
} else if (gplink_number == 2) {
num_enabled++;
} else {
goto done;
}
}
done:
return ret;
}
/* == ad_gpo_process_som_send/recv implementation ========================== */
struct ad_gpo_process_som_state {
struct tevent_context *ev;
struct sdap_id_op *sdap_op;
struct sdap_options *opts;
int timeout;
bool allow_enforced_only;
char *site_name;
char *site_dn;
int som_index;
int num_soms;
};
/*
* This function uses the input target_dn and input domain_name to populate
* a list of gp_som objects. Each object in this list represents a SOM
* associated with the target (such as OU, Domain, and Site).
*
* The inputs are used to determine the DNs of each SOM associated with the
* target. In turn, the SOM object DNs are used to retrieve certain LDAP
* attributes of each SOM object, that are parsed into an array of gp_gplink
* objects, essentially representing the GPOs that have been linked to each
* SOM object. Note that it is perfectly valid for there to be *no* GPOs
* linked to a SOM object.
*/
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_conn_ctx *conn,
struct ldb_context *ldb_ctx,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
int timeout,
const char *target_dn,
const char *domain_name)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct ad_gpo_process_som_state *state;
return NULL;
}
state->allow_enforced_only = 0;
"Unable to retrieve SOM List : [%d](%s)\n",
goto immediately;
}
goto immediately;
}
goto immediately;
}
}
return req;
}
static void
{
struct tevent_req *req;
struct ad_gpo_process_som_state *state;
int ret;
char *site;
/* gpo code only cares about the site name */
return;
}
return;
}
/*
* note: the configNC attribute is being retrieved here from the rootDSE
* entry. In future, since we already make an LDAP query for the rootDSE
* entry when LDAP connection is made, this attribute should really be
* retrieved at that point (see https://fedorahosted.org/sssd/ticket/2276)
*/
"", LDAP_SCOPE_BASE,
false);
return;
}
}
static void
{
struct tevent_req *req;
struct ad_gpo_process_som_state *state;
int ret;
int dp_error;
int i = 0;
struct sysdb_attrs **reply;
const char *configNC;
&reply_count, &reply);
goto done;
}
/* make sure there is only one non-NULL reply returned */
if (reply_count < 1) {
goto done;
} else if (reply_count > 1) {
ret = ERR_INTERNAL;
goto done;
ret = ERR_INTERNAL;
goto done;
}
/* reply[0] holds requested attributes of single reply */
"sysdb_attrs_get_string failed: [%d](%s)\n",
goto done;
}
goto done;
}
/* note that space was allocated for site_dn when allocating som_list */
goto done;
}
goto done;
}
i = 0;
i++;
}
done:
}
}
static errno_t
{
struct tevent_req *subreq;
struct ad_gpo_process_som_state *state;
/* gp_som is NULL only after all SOMs have been processed */
false);
return ENOMEM;
}
return EAGAIN;
}
static void
{
struct tevent_req *req;
struct ad_gpo_process_som_state *state;
int ret;
int dp_error;
struct sysdb_attrs **results;
&num_results, &results);
"Unable to get SOM attributes: [%d](%s)\n",
goto done;
}
goto done;
} else if (num_results > 1) {
ret = ERR_INTERNAL;
goto done;
}
/* Get the gplink value, if available */
"sysdb_attrs_get_el() failed: [%d](%s)\n",
goto done;
}
goto done;
}
goto done;
}
"gpoptions attr not found or has no value; defaults to 0\n");
allow_enforced_only = 0;
} else {
if (errno != 0) {
goto done;
}
}
(char *)raw_gplink_value,
"ad_gpo_populate_gplink_list() failed\n");
goto done;
}
if (allow_enforced_only) {
}
done:
}
}
int
{
struct ad_gpo_process_som_state *state =
return EOK;
}
/* == ad_gpo_process_gpo_send/recv helpers ================================= */
/*
* This function examines the gp_gplink objects in each gp_som object specified
* in the input som_list, and populates the _candidate_gpos output parameter's
* gpo_dn fields with prioritized list of GPO DNs. Prioritization ensures that:
* - GPOs linked to an OU will be applied after GPOs linked to a Domain,
* which will be applied after GPOs linked to a Site.
* - multiple GPOs linked to a single SOM are applied in their link order
* (i.e. 1st GPO linked to SOM is applied after 2nd GPO linked to SOM, etc).
* - enforced GPOs are applied after unenforced GPOs.
*
* As such, the _candidate_gpos output's dn fields looks like (in link order):
* [unenforced {Site, Domain, OU}; enforced {Site, Domain, OU}]
*
* Note that in the case of conflicting policy settings, GPOs appearing later
* in the list will trump GPOs appearing earlier in the list.
*/
static errno_t
struct gp_gpo ***_candidate_gpos,
int *_num_candidate_gpos)
{
int num_candidate_gpos = 0;
const char **enforced_gpo_dns = NULL;
const char **unenforced_gpo_dns = NULL;
int gpo_dn_idx = 0;
int num_enforced = 0;
int enforced_idx = 0;
int num_unenforced = 0;
int unenforced_idx = 0;
int i = 0;
int j = 0;
int ret;
goto done;
}
while (som_list[i]) {
j = 0;
goto done;
}
num_enforced++;
} else {
}
j++;
}
i++;
}
if (num_candidate_gpos == 0) {
*_candidate_gpos = NULL;
*_num_candidate_gpos = 0;
goto done;
}
if (enforced_gpo_dns == NULL) {
goto done;
}
if (unenforced_gpo_dns == NULL) {
goto done;
}
i = 0;
while (som_list[i]) {
j = 0;
goto done;
}
goto done;
}
enforced_idx++;
} else {
goto done;
}
}
j++;
}
i++;
}
struct gp_gpo *,
num_candidate_gpos + 1);
if (candidate_gpos == NULL) {
goto done;
}
gpo_dn_idx = 0;
for (i = num_unenforced - 1; i >= 0; i--) {
goto done;
}
goto done;
}
"candidate_gpos[%d]->gpo_dn: %s\n",
gpo_dn_idx++;
}
for (i = 0; i < num_enforced; i++) {
goto done;
}
goto done;
}
"candidate_gpos[%d]->gpo_dn: %s\n",
gpo_dn_idx++;
}
done:
return ret;
}
/*
* This function parses the input_path into its components, replaces each
* back slash ('\') with a forward slash ('/'), and populates the output params.
*
* The smb_server output is constructed by concatenating the following elements:
* - SMB_STANDARD_URI ("smb://")
* - server_hostname (which replaces domain_name in input path)
* The smb_share and smb_path outputs are extracted from the input_path.
*
* server_hostname = "adserver.foo.com", then
* _smb_server = "smb://adserver.foo.com"
* _smb_share = "SysVol"
* _smb_path = "/foo.com/..."
*
* Note that the input_path must have at least four forward slash separators.
* For example, input_path = "\\foo.com\SysVol" is not a valid input_path,
* because it has only three forward slash separators.
*/
static errno_t
char *server_hostname,
char *input_path,
const char **_smb_server,
const char **_smb_share,
const char **_smb_path)
{
char *ptr;
const char delim = '\\';
int ret;
int num_seps = 0;
if (input_path == NULL ||
*input_path == '\0' ||
_smb_server == NULL ||
_smb_share == NULL ||
goto done;
}
ptr = input_path;
num_seps++;
if (num_seps == 3) {
/* replace the slash before the share name with null string */
*ptr = '\0';
ptr++;
continue;
} else if (num_seps == 4) {
/* replace the slash after the share name with null string */
*ptr = '\0';
ptr++;
continue;
}
*ptr = '/';
ptr++;
}
if (num_seps == 0) {
goto done;
}
goto done;
}
if (*_smb_server == NULL) {
goto done;
}
if (*_smb_share == NULL) {
goto done;
}
goto done;
}
done:
return ret;
}
/*
* This function populates the _cse_guid_list output parameter by parsing the
* input raw_machine_ext_names_value into an array of cse_guid strings.
*
* The raw_machine_ext_names_value is a single string in the following format:
* "[{cse_guid_1}{tool_guid1}]...[{cse_guid_n}{tool_guid_n}]"
*/
static errno_t
char *raw_machine_ext_names_value,
const char ***_gpo_cse_guids,
int *_num_gpo_cse_guids)
{
char *ptr;
char *first;
char *last;
char *cse_guid;
char *tool_guid;
const char delim = ']';
const char **gpo_cse_guids;
int i;
int ret;
int num_gpo_cse_guids = 0;
if (raw_machine_ext_names_value == NULL ||
*raw_machine_ext_names_value == '\0' ||
_gpo_cse_guids == NULL) {
return EINVAL;
}
goto done;
}
ptr++;
}
if (num_gpo_cse_guids == 0) {
goto done;
}
if (gpo_cse_guids == NULL) {
goto done;
}
for (i = 0; i < num_gpo_cse_guids; i++) {
break;
}
*last = '\0';
last++;
first ++;
break;
}
*tool_guid = '\0';
}
gpo_cse_guids[i] = NULL;
for (i = 0; i < num_gpo_cse_guids; i++) {
"gpo_cse_guids[%d] is %s\n", i, gpo_cse_guids[i]);
}
done:
return ret;
}
enum ndr_err_code
struct security_descriptor *r);
/*
* This function parses the input data blob and assigns the resulting
* security_descriptor object to the _gpo_sd output parameter.
*/
struct security_descriptor **_gpo_sd)
{
struct security_descriptor sd;
enum ndr_err_code ndr_err;
return EINVAL;
}
&sd);
if (ndr_err != NDR_ERR_SUCCESS) {
return EINVAL;
}
return EOK;
}
/* == ad_gpo_process_gpo_send/recv implementation ========================== */
struct ad_gpo_process_gpo_state {
struct tevent_context *ev;
struct sdap_id_op *sdap_op;
struct sdap_options *opts;
char *server_hostname;
int timeout;
struct gp_gpo **candidate_gpos;
int num_candidate_gpos;
int gpo_index;
};
/*
* This function uses the input som_list to populate a prioritized list of
* gp_gpo objects, prioritized based on SOM type, link order, and whether the
* GPO is "enforced". This list represents the initial set of candidate GPOs
* that might be applicable to the target. This list can not be expanded, but
* it might be reduced based on subsequent filtering steps. The GPO object DNs
* are used to retrieve certain LDAP attributes of each GPO object, that are
* parsed into the various fields of the gp_gpo object.
*/
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
char *server_hostname,
int timeout,
{
struct tevent_req *req;
struct ad_gpo_process_gpo_state *state;
return NULL;
}
state->num_candidate_gpos = 0;
"Unable to retrieve GPO List: [%d](%s)\n",
goto immediately;
}
goto immediately;
}
}
return req;
}
static errno_t
{
AD_AT_FLAGS, NULL};
struct tevent_req *subreq;
struct ad_gpo_process_gpo_state *state;
/* gp_gpo is NULL only after all GPOs have been processed */
return ENOMEM;
}
return EAGAIN;
}
static void
{
struct tevent_req *req;
struct ad_gpo_process_gpo_state *state;
int ret;
int dp_error;
struct sysdb_attrs **results;
const char *raw_file_sys_path = NULL;
char *file_sys_path = NULL;
"Unable to get GPO attributes: [%d](%s)\n",
goto done;
}
goto done;
}
else if (num_results > 1) {
ret = ERR_INTERNAL;
goto done;
}
/* retrieve AD_AT_CN */
"sysdb_attrs_get_string failed: [%d](%s)\n",
goto done;
}
goto done;
}
/* retrieve AD_AT_FILE_SYS_PATH */
"sysdb_attrs_get_string failed: [%d](%s)\n",
goto done;
}
"unable to extract smb components from file_sys_path: [%d](%s)\n",
goto done;
}
/* retrieve AD_AT_FUNC_VERSION */
"sysdb_attrs_get_int32_t failed: [%d](%s)\n",
goto done;
}
/* retrieve AD_AT_FLAGS */
"sysdb_attrs_get_int32_t failed: [%d](%s)\n",
goto done;
}
/* retrieve AD_AT_NT_SEC_DESC */
goto done;
}
"nt_sec_desc attribute not found or has no value\n");
goto done;
}
goto done;
}
/* retrieve AD_AT_MACHINE_EXT_NAMES */
goto done;
}
/*
* if gpo has no machine_ext_names (which is perfectly valid: it could
* have only user_ext_names, for example), we continue to next gpo
*/
"machine_ext_names attribute not found or has no value\n");
} else {
(char *)raw_machine_ext_names,
"ad_gpo_parse_machine_ext_names() failed\n");
goto done;
}
}
done:
}
}
int
struct gp_gpo ***candidate_gpos,
int *num_candidate_gpos)
{
struct ad_gpo_process_gpo_state *state =
return EOK;
}
/* == ad_gpo_process_cse_send/recv helpers ================================= */
static errno_t
const char *smb_server,
const char *smb_share,
const char *smb_path,
const char *smb_cse_suffix,
int cached_gpt_version,
{
int smb_server_length;
int smb_share_length;
int smb_path_length;
return ENOMEM;
}
return ENOMEM;
}
rp = 0;
/* cached_gpt_version */
/* smb_server */
/* smb_share */
/* smb_path */
/* smb_cse_suffix */
return EOK;
}
static errno_t
{
int ret;
size_t p = 0;
/* sysvol_gpt_version */
/* operation result code */
return ret;
}
/* == ad_gpo_process_cse_send/recv implementation ========================== */
struct ad_gpo_process_cse_state {
struct tevent_context *ev;
struct sss_domain_info *domain;
int gpo_timeout_option;
const char *gpo_guid;
const char *smb_path;
const char *smb_cse_suffix;
struct child_io_fds *io;
};
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) sends the input smb uri
* components and cached_gpt_version to the gpo child, which, in turn,
* will download the GPT.INI file and policy files (as needed) and store
* them in the GPO_CACHE directory. Note that if the send_to_child input is
* false, this function simply completes the request.
*/
struct tevent_req *
struct tevent_context *ev,
bool send_to_child,
struct sss_domain_info *domain,
const char *gpo_guid,
const char *smb_server,
const char *smb_share,
const char *smb_path,
const char *smb_cse_suffix,
int cached_gpt_version,
int gpo_timeout_option)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct ad_gpo_process_cse_state *state;
return NULL;
}
if (!send_to_child) {
/*
* if we don't need to talk to child (b/c cache timeout is still valid),
* we simply complete the request
*/
goto immediately;
}
goto immediately;
}
/* prepare the data to pass to child */
goto immediately;
}
goto immediately;
}
goto immediately;
}
return req;
} else {
}
return req;
}
{
struct tevent_req *req;
struct ad_gpo_process_cse_state *state;
int ret;
return;
}
return;
}
}
{
struct tevent_req *req;
struct ad_gpo_process_cse_state *state;
int ret;
return;
}
"ad_gpo_parse_gpo_child_response failed: [%d][%s]\n",
return;
} else if (child_result != 0){
"Error in gpo_child: [%d][%s]\n",
return;
}
return;
}
return;
}
{
return EOK;
}
static errno_t
{
int pipefd_to_child[2];
int pipefd_from_child[2];
int ret;
struct ad_gpo_process_cse_state *state;
if (ret == -1) {
return err;
}
if (ret == -1) {
return err;
}
if (pid == 0) { /* child */
return err;
} else if (pid > 0) { /* parent */
close(pipefd_to_child[0]);
"Could not set up child signal handler\n");
return ret;
}
} else { /* error */
return err;
}
return EOK;
}