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 : }
|