Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Group Policy Object Support
4 : * Copyright (C) Guenther Deschner 2005,2007
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "libgpo/gpo.h"
22 : #include "auth.h"
23 : #include "../libcli/security/security.h"
24 :
25 : /****************************************************************
26 : parse the raw extension string into a GP_EXT structure
27 : ****************************************************************/
28 :
29 0 : bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
30 : const char *extension_raw,
31 : struct GP_EXT **gp_ext)
32 : {
33 0 : bool ret = false;
34 0 : struct GP_EXT *ext = NULL;
35 0 : char **ext_list = NULL;
36 0 : char **ext_strings = NULL;
37 0 : int i;
38 :
39 0 : if (!extension_raw) {
40 0 : goto parse_error;
41 : }
42 :
43 0 : DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw));
44 :
45 0 : ext = talloc_zero(mem_ctx, struct GP_EXT);
46 0 : if (!ext) {
47 0 : goto parse_error;
48 : }
49 :
50 0 : ext_list = str_list_make(mem_ctx, extension_raw, "]");
51 0 : if (!ext_list) {
52 0 : goto parse_error;
53 : }
54 :
55 0 : for (i = 0; ext_list[i] != NULL; i++) {
56 : /* no op */
57 0 : }
58 :
59 0 : ext->num_exts = i;
60 :
61 0 : if (ext->num_exts) {
62 0 : ext->extensions = talloc_zero_array(mem_ctx, char *,
63 : ext->num_exts);
64 0 : ext->extensions_guid = talloc_zero_array(mem_ctx, char *,
65 : ext->num_exts);
66 0 : ext->snapins = talloc_zero_array(mem_ctx, char *,
67 : ext->num_exts);
68 0 : ext->snapins_guid = talloc_zero_array(mem_ctx, char *,
69 : ext->num_exts);
70 : }
71 :
72 0 : ext->gp_extension = talloc_strdup(mem_ctx, extension_raw);
73 :
74 0 : if (!ext->extensions || !ext->extensions_guid ||
75 0 : !ext->snapins || !ext->snapins_guid ||
76 0 : !ext->gp_extension) {
77 0 : goto parse_error;
78 : }
79 :
80 0 : for (i = 0; ext_list[i] != NULL; i++) {
81 :
82 0 : int k;
83 0 : char *p, *q;
84 :
85 0 : DEBUGADD(10,("extension #%d\n", i));
86 :
87 0 : p = ext_list[i];
88 :
89 0 : if (p[0] == '[') {
90 0 : p++;
91 : }
92 :
93 0 : ext_strings = str_list_make(mem_ctx, p, "}");
94 0 : if (ext_strings == NULL) {
95 0 : goto parse_error;
96 : }
97 :
98 0 : for (k = 0; ext_strings[k] != NULL; k++) {
99 : /* no op */
100 0 : }
101 0 : if (k == 0) {
102 0 : goto parse_error;
103 : }
104 0 : q = ext_strings[0];
105 :
106 0 : if (q[0] == '{') {
107 0 : q++;
108 : }
109 :
110 0 : ext->extensions[i] = talloc_strdup(mem_ctx,
111 : cse_gpo_guid_string_to_name(q));
112 0 : ext->extensions_guid[i] = talloc_strdup(mem_ctx, q);
113 :
114 : /* we might have no name for the guid */
115 0 : if (ext->extensions_guid[i] == NULL) {
116 0 : goto parse_error;
117 : }
118 :
119 0 : for (k = 1; ext_strings[k] != NULL; k++) {
120 :
121 0 : char *m = ext_strings[k];
122 :
123 0 : if (m[0] == '{') {
124 0 : m++;
125 : }
126 :
127 : /* FIXME: theoretically there could be more than one
128 : * snapin per extension */
129 0 : ext->snapins[i] = talloc_strdup(mem_ctx,
130 : cse_snapin_gpo_guid_string_to_name(m));
131 0 : ext->snapins_guid[i] = talloc_strdup(mem_ctx, m);
132 :
133 : /* we might have no name for the guid */
134 0 : if (ext->snapins_guid[i] == NULL) {
135 0 : goto parse_error;
136 : }
137 : }
138 : }
139 :
140 0 : *gp_ext = ext;
141 :
142 0 : ret = true;
143 :
144 0 : parse_error:
145 0 : talloc_free(ext_list);
146 0 : talloc_free(ext_strings);
147 :
148 0 : return ret;
149 : }
150 :
151 : #ifdef HAVE_LDAP
152 :
153 : /****************************************************************
154 : parse the raw link string into a GP_LINK structure
155 : ****************************************************************/
156 :
157 4 : static ADS_STATUS gpo_parse_gplink(TALLOC_CTX *mem_ctx,
158 : const char *gp_link_raw,
159 : uint32_t options,
160 : struct GP_LINK *gp_link)
161 : {
162 4 : ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
163 0 : char **link_list;
164 0 : int i;
165 :
166 4 : ZERO_STRUCTP(gp_link);
167 :
168 4 : DEBUG(10,("gpo_parse_gplink: gPLink: %s\n", gp_link_raw));
169 :
170 4 : link_list = str_list_make_v3(mem_ctx, gp_link_raw, "]");
171 4 : if (!link_list) {
172 0 : goto parse_error;
173 : }
174 :
175 8 : for (i = 0; link_list[i] != NULL; i++) {
176 : /* no op */
177 0 : }
178 :
179 4 : gp_link->gp_opts = options;
180 4 : gp_link->num_links = i;
181 :
182 4 : if (gp_link->num_links) {
183 4 : gp_link->link_names = talloc_zero_array(mem_ctx, char *,
184 : gp_link->num_links);
185 4 : gp_link->link_opts = talloc_zero_array(mem_ctx, uint32_t,
186 : gp_link->num_links);
187 : }
188 :
189 4 : gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw);
190 :
191 4 : if (!gp_link->link_names || !gp_link->link_opts || !gp_link->gp_link) {
192 0 : goto parse_error;
193 : }
194 :
195 8 : for (i = 0; link_list[i] != NULL; i++) {
196 :
197 0 : char *p, *q;
198 :
199 4 : DEBUGADD(10,("gpo_parse_gplink: processing link #%d\n", i));
200 :
201 4 : q = link_list[i];
202 4 : if (q[0] == '[') {
203 4 : q++;
204 0 : };
205 :
206 4 : p = strchr(q, ';');
207 :
208 4 : if (p == NULL) {
209 0 : goto parse_error;
210 : }
211 :
212 4 : gp_link->link_names[i] = talloc_strdup(mem_ctx, q);
213 4 : if (gp_link->link_names[i] == NULL) {
214 0 : goto parse_error;
215 : }
216 4 : gp_link->link_names[i][PTR_DIFF(p, q)] = 0;
217 :
218 4 : gp_link->link_opts[i] = atoi(p + 1);
219 :
220 4 : DEBUGADD(10,("gpo_parse_gplink: link: %s\n",
221 : gp_link->link_names[i]));
222 4 : DEBUGADD(10,("gpo_parse_gplink: opt: %d\n",
223 : gp_link->link_opts[i]));
224 :
225 : }
226 :
227 4 : status = ADS_SUCCESS;
228 :
229 4 : parse_error:
230 4 : talloc_free(link_list);
231 :
232 4 : return status;
233 : }
234 :
235 : /****************************************************************
236 : helper call to get a GP_LINK structure from a linkdn
237 : ****************************************************************/
238 :
239 6 : ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads,
240 : TALLOC_CTX *mem_ctx,
241 : const char *link_dn,
242 : struct GP_LINK *gp_link_struct)
243 : {
244 0 : ADS_STATUS status;
245 6 : const char *attrs[] = {"gPLink", "gPOptions", NULL};
246 6 : LDAPMessage *res = NULL;
247 0 : const char *gp_link;
248 0 : uint32_t gp_options;
249 :
250 6 : ZERO_STRUCTP(gp_link_struct);
251 :
252 6 : status = ads_search_dn(ads, &res, link_dn, attrs);
253 6 : if (!ADS_ERR_OK(status)) {
254 0 : DEBUG(10,("ads_get_gpo_link: search failed with %s\n",
255 : ads_errstr(status)));
256 0 : return status;
257 : }
258 :
259 6 : if (ads_count_replies(ads, res) != 1) {
260 0 : DEBUG(10,("ads_get_gpo_link: no result\n"));
261 0 : ads_msgfree(ads, res);
262 0 : return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
263 : }
264 :
265 6 : gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
266 6 : if (gp_link == NULL) {
267 2 : DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n"));
268 2 : ads_msgfree(ads, res);
269 2 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
270 : }
271 :
272 : /* perfectly legal to have no options */
273 4 : if (!ads_pull_uint32(ads, res, "gPOptions", &gp_options)) {
274 4 : DEBUG(10,("ads_get_gpo_link: "
275 : "no 'gPOptions' attribute found\n"));
276 4 : gp_options = 0;
277 : }
278 :
279 4 : ads_msgfree(ads, res);
280 :
281 4 : return gpo_parse_gplink(mem_ctx, gp_link, gp_options, gp_link_struct);
282 : }
283 :
284 : /****************************************************************
285 : helper call to add a gp link
286 : ****************************************************************/
287 :
288 0 : ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
289 : TALLOC_CTX *mem_ctx,
290 : const char *link_dn,
291 : const char *gpo_dn,
292 : uint32_t gpo_opt)
293 : {
294 0 : ADS_STATUS status;
295 0 : const char *attrs[] = {"gPLink", NULL};
296 0 : LDAPMessage *res = NULL;
297 0 : const char *gp_link, *gp_link_new;
298 0 : ADS_MODLIST mods;
299 :
300 : /* although ADS allows one to set anything here, we better check here if
301 : * the gpo_dn is sane */
302 :
303 0 : if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) {
304 0 : return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
305 : }
306 :
307 0 : status = ads_search_dn(ads, &res, link_dn, attrs);
308 0 : if (!ADS_ERR_OK(status)) {
309 0 : DEBUG(10,("ads_add_gpo_link: search failed with %s\n",
310 : ads_errstr(status)));
311 0 : return status;
312 : }
313 :
314 0 : if (ads_count_replies(ads, res) != 1) {
315 0 : DEBUG(10,("ads_add_gpo_link: no result\n"));
316 0 : ads_msgfree(ads, res);
317 0 : return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
318 : }
319 :
320 0 : gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
321 0 : if (gp_link == NULL) {
322 0 : gp_link_new = talloc_asprintf(mem_ctx, "[%s;%d]",
323 : gpo_dn, gpo_opt);
324 : } else {
325 0 : gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]",
326 : gp_link, gpo_dn, gpo_opt);
327 : }
328 :
329 0 : ads_msgfree(ads, res);
330 0 : ADS_ERROR_HAVE_NO_MEMORY(gp_link_new);
331 :
332 0 : mods = ads_init_mods(mem_ctx);
333 0 : ADS_ERROR_HAVE_NO_MEMORY(mods);
334 :
335 0 : status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new);
336 0 : if (!ADS_ERR_OK(status)) {
337 0 : return status;
338 : }
339 :
340 0 : return ads_gen_mod(ads, link_dn, mods);
341 : }
342 :
343 : /****************************************************************
344 : helper call to delete add a gp link
345 : ****************************************************************/
346 :
347 : /* untested & broken */
348 0 : ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
349 : TALLOC_CTX *mem_ctx,
350 : const char *link_dn,
351 : const char *gpo_dn)
352 : {
353 0 : ADS_STATUS status;
354 0 : const char *attrs[] = {"gPLink", NULL};
355 0 : LDAPMessage *res = NULL;
356 0 : const char *gp_link, *gp_link_new = NULL;
357 0 : ADS_MODLIST mods;
358 :
359 : /* check for a sane gpo_dn */
360 0 : if (gpo_dn[0] != '[') {
361 0 : DEBUG(10,("ads_delete_gpo_link: first char not: [\n"));
362 0 : return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
363 : }
364 :
365 0 : if (gpo_dn[strlen(gpo_dn)] != ']') {
366 0 : DEBUG(10,("ads_delete_gpo_link: last char not: ]\n"));
367 0 : return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
368 : }
369 :
370 0 : status = ads_search_dn(ads, &res, link_dn, attrs);
371 0 : if (!ADS_ERR_OK(status)) {
372 0 : DEBUG(10,("ads_delete_gpo_link: search failed with %s\n",
373 : ads_errstr(status)));
374 0 : return status;
375 : }
376 :
377 0 : if (ads_count_replies(ads, res) != 1) {
378 0 : DEBUG(10,("ads_delete_gpo_link: no result\n"));
379 0 : ads_msgfree(ads, res);
380 0 : return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
381 : }
382 :
383 0 : gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
384 0 : if (gp_link == NULL) {
385 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
386 : }
387 :
388 : /* find link to delete */
389 : /* gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link,
390 : gpo_dn, gpo_opt); */
391 :
392 0 : ads_msgfree(ads, res);
393 0 : ADS_ERROR_HAVE_NO_MEMORY(gp_link_new);
394 :
395 0 : mods = ads_init_mods(mem_ctx);
396 0 : ADS_ERROR_HAVE_NO_MEMORY(mods);
397 :
398 0 : status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new);
399 0 : if (!ADS_ERR_OK(status)) {
400 0 : return status;
401 : }
402 :
403 0 : return ads_gen_mod(ads, link_dn, mods);
404 : }
405 :
406 : /****************************************************************
407 : parse a GROUP_POLICY_OBJECT structure from an LDAPMessage result
408 : ****************************************************************/
409 :
410 4 : ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads,
411 : TALLOC_CTX *mem_ctx,
412 : LDAPMessage *res,
413 : const char *gpo_dn,
414 : struct GROUP_POLICY_OBJECT *gpo)
415 : {
416 4 : ZERO_STRUCTP(gpo);
417 :
418 4 : ADS_ERROR_HAVE_NO_MEMORY(res);
419 :
420 4 : if (gpo_dn) {
421 4 : gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn);
422 : } else {
423 0 : gpo->ds_path = ads_get_dn(ads, mem_ctx, res);
424 : }
425 :
426 4 : ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path);
427 :
428 4 : if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) {
429 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
430 : }
431 :
432 4 : if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) {
433 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
434 : }
435 :
436 4 : gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res,
437 : "gPCFileSysPath");
438 4 : if (gpo->file_sys_path == NULL) {
439 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
440 : }
441 :
442 4 : gpo->display_name = ads_pull_string(ads, mem_ctx, res,
443 : "displayName");
444 4 : if (gpo->display_name == NULL) {
445 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
446 : }
447 :
448 4 : gpo->name = ads_pull_string(ads, mem_ctx, res,
449 : "name");
450 4 : if (gpo->name == NULL) {
451 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
452 : }
453 :
454 4 : gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res,
455 : "gPCMachineExtensionNames");
456 4 : gpo->user_extensions = ads_pull_string(ads, mem_ctx, res,
457 : "gPCUserExtensionNames");
458 :
459 4 : ads_pull_sd(ads, mem_ctx, res, "ntSecurityDescriptor",
460 : &gpo->security_descriptor);
461 4 : if (gpo->security_descriptor == NULL) {
462 0 : return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
463 : }
464 :
465 4 : return ADS_ERROR(LDAP_SUCCESS);
466 : }
467 :
468 : /****************************************************************
469 : get a GROUP_POLICY_OBJECT structure based on different input parameters
470 : ****************************************************************/
471 :
472 4 : ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
473 : TALLOC_CTX *mem_ctx,
474 : const char *gpo_dn,
475 : const char *display_name,
476 : const char *guid_name,
477 : struct GROUP_POLICY_OBJECT *gpo)
478 : {
479 4 : ADS_STATUS status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
480 4 : LDAPMessage *res = NULL;
481 0 : char *dn;
482 0 : const char *filter;
483 4 : const char *attrs[] = {
484 : "cn",
485 : "displayName",
486 : "flags",
487 : "gPCFileSysPath",
488 : "gPCFunctionalityVersion",
489 : "gPCMachineExtensionNames",
490 : "gPCUserExtensionNames",
491 : "gPCWQLFilter",
492 : "name",
493 : "ntSecurityDescriptor",
494 : "versionNumber",
495 : NULL};
496 4 : uint32_t sd_flags = SECINFO_DACL;
497 :
498 4 : ZERO_STRUCTP(gpo);
499 :
500 4 : if (!gpo_dn && !display_name && !guid_name) {
501 0 : return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
502 : }
503 :
504 4 : if (gpo_dn) {
505 :
506 4 : if (strnequal(gpo_dn, "LDAP://", strlen("LDAP://")) != 0) {
507 4 : gpo_dn = gpo_dn + strlen("LDAP://");
508 : }
509 :
510 4 : status = ads_search_retry_dn_sd_flags(ads, &res,
511 : sd_flags,
512 : gpo_dn, attrs);
513 :
514 0 : } else if (display_name || guid_name) {
515 :
516 0 : filter = talloc_asprintf(mem_ctx,
517 : "(&(objectclass=groupPolicyContainer)(%s=%s))",
518 : display_name ? "displayName" : "name",
519 : display_name ? display_name : guid_name);
520 0 : ADS_ERROR_HAVE_NO_MEMORY(filter);
521 :
522 0 : status = ads_do_search_all_sd_flags(ads, ads->config.bind_path,
523 : LDAP_SCOPE_SUBTREE, filter,
524 : attrs, sd_flags, &res);
525 : }
526 :
527 4 : if (!ADS_ERR_OK(status)) {
528 0 : DEBUG(10,("ads_get_gpo: search failed with %s\n",
529 : ads_errstr(status)));
530 0 : return status;
531 : }
532 :
533 4 : if (ads_count_replies(ads, res) != 1) {
534 0 : DEBUG(10,("ads_get_gpo: no result\n"));
535 0 : ads_msgfree(ads, res);
536 0 : return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
537 : }
538 :
539 4 : dn = ads_get_dn(ads, mem_ctx, res);
540 4 : if (dn == NULL) {
541 0 : ads_msgfree(ads, res);
542 0 : return ADS_ERROR(LDAP_NO_MEMORY);
543 : }
544 :
545 4 : status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo);
546 4 : ads_msgfree(ads, res);
547 4 : TALLOC_FREE(dn);
548 :
549 4 : return status;
550 : }
551 :
552 : /****************************************************************
553 : add a gplink to the GROUP_POLICY_OBJECT linked list
554 : ****************************************************************/
555 :
556 4 : static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
557 : TALLOC_CTX *mem_ctx,
558 : struct GROUP_POLICY_OBJECT **gpo_list,
559 : struct GROUP_POLICY_OBJECT **forced_gpo_list,
560 : const char *link_dn,
561 : struct GP_LINK *gp_link,
562 : enum GPO_LINK_TYPE link_type,
563 : bool only_add_forced_gpos,
564 : const struct security_token *token)
565 : {
566 0 : ADS_STATUS status;
567 0 : uint32_t count;
568 :
569 : /*
570 : * Note: DLIST_ADD pushes to the front,
571 : * so loop from last to first to get the
572 : * order right.
573 : */
574 8 : for (count = gp_link->num_links; count > 0; count--) {
575 : /* NB. Index into arrays is one less than counter. */
576 4 : uint32_t i = count - 1;
577 4 : struct GROUP_POLICY_OBJECT **target_list = NULL;
578 4 : struct GROUP_POLICY_OBJECT *new_gpo = NULL;
579 4 : bool is_forced =
580 4 : (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) != 0;
581 :
582 4 : if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
583 0 : DEBUG(10,("skipping disabled GPO\n"));
584 0 : continue;
585 : }
586 :
587 4 : if (only_add_forced_gpos) {
588 :
589 0 : if (!is_forced) {
590 0 : DEBUG(10,("skipping nonenforced GPO link "
591 : "because GPOPTIONS_BLOCK_INHERITANCE "
592 : "has been set\n"));
593 0 : continue;
594 : } else {
595 0 : DEBUG(10,("adding enforced GPO link although "
596 : "the GPOPTIONS_BLOCK_INHERITANCE "
597 : "has been set\n"));
598 : }
599 : }
600 :
601 4 : new_gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
602 4 : ADS_ERROR_HAVE_NO_MEMORY(new_gpo);
603 :
604 4 : status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i],
605 : NULL, NULL, new_gpo);
606 4 : if (!ADS_ERR_OK(status)) {
607 0 : DEBUG(10,("failed to get gpo: %s\n",
608 : gp_link->link_names[i]));
609 0 : if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
610 0 : (status.err.rc == LDAP_NO_SUCH_ATTRIBUTE)) {
611 0 : DEBUG(10,("skipping empty gpo: %s\n",
612 : gp_link->link_names[i]));
613 0 : talloc_free(new_gpo);
614 0 : continue;
615 : }
616 0 : return status;
617 : }
618 :
619 4 : status = ADS_ERROR_NT(gpo_apply_security_filtering(new_gpo,
620 : token));
621 4 : if (!ADS_ERR_OK(status)) {
622 0 : DEBUG(10,("skipping GPO \"%s\" as object "
623 : "has no access to it\n",
624 : new_gpo->display_name));
625 0 : talloc_free(new_gpo);
626 0 : continue;
627 : }
628 :
629 4 : new_gpo->link = link_dn;
630 4 : new_gpo->link_type = link_type;
631 :
632 4 : target_list = is_forced ? forced_gpo_list : gpo_list;
633 4 : DLIST_ADD(*target_list, new_gpo);
634 :
635 4 : DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s "
636 : "to GPO list\n", i, gp_link->link_names[i]));
637 : }
638 :
639 4 : return ADS_ERROR(LDAP_SUCCESS);
640 : }
641 :
642 : /****************************************************************
643 : ****************************************************************/
644 :
645 2 : ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
646 : TALLOC_CTX *mem_ctx,
647 : const char *dn,
648 : struct security_token **token)
649 : {
650 0 : ADS_STATUS status;
651 0 : struct dom_sid object_sid;
652 0 : struct dom_sid primary_group_sid;
653 0 : struct dom_sid *ad_token_sids;
654 2 : size_t num_ad_token_sids = 0;
655 0 : struct dom_sid *token_sids;
656 2 : uint32_t num_token_sids = 0;
657 2 : struct security_token *new_token = NULL;
658 0 : int i;
659 :
660 2 : status = ads_get_tokensids(ads, mem_ctx, dn,
661 : &object_sid, &primary_group_sid,
662 : &ad_token_sids, &num_ad_token_sids);
663 2 : if (!ADS_ERR_OK(status)) {
664 0 : return status;
665 : }
666 :
667 2 : token_sids = talloc_array(mem_ctx, struct dom_sid, 1);
668 2 : ADS_ERROR_HAVE_NO_MEMORY(token_sids);
669 :
670 2 : status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
671 : &primary_group_sid,
672 : &token_sids,
673 : &num_token_sids));
674 2 : if (!ADS_ERR_OK(status)) {
675 0 : return status;
676 : }
677 :
678 6 : for (i = 0; i < num_ad_token_sids; i++) {
679 :
680 4 : if (sid_check_is_in_builtin(&ad_token_sids[i])) {
681 0 : continue;
682 : }
683 :
684 4 : status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
685 : &ad_token_sids[i],
686 : &token_sids,
687 : &num_token_sids));
688 4 : if (!ADS_ERR_OK(status)) {
689 0 : return status;
690 : }
691 : }
692 :
693 2 : status = ADS_ERROR_NT(create_local_nt_token(mem_ctx,
694 : &object_sid, false,
695 : num_token_sids, token_sids, &new_token));
696 2 : if (!ADS_ERR_OK(status)) {
697 0 : return status;
698 : }
699 :
700 2 : *token = new_token;
701 :
702 2 : security_token_debug(DBGC_CLASS, 5, *token);
703 :
704 2 : return ADS_ERROR_LDAP(LDAP_SUCCESS);
705 : }
706 :
707 : /****************************************************************
708 : ****************************************************************/
709 :
710 2 : static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx,
711 : struct GROUP_POLICY_OBJECT **gpo_list,
712 : enum GPO_LINK_TYPE link_type)
713 : {
714 2 : struct GROUP_POLICY_OBJECT *gpo = NULL;
715 :
716 2 : ADS_ERROR_HAVE_NO_MEMORY(gpo_list);
717 :
718 2 : gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
719 2 : ADS_ERROR_HAVE_NO_MEMORY(gpo);
720 :
721 2 : gpo->name = talloc_strdup(mem_ctx, "Local Policy");
722 2 : ADS_ERROR_HAVE_NO_MEMORY(gpo->name);
723 :
724 2 : gpo->display_name = talloc_strdup(mem_ctx, "Local Policy");
725 2 : ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name);
726 :
727 2 : gpo->link_type = link_type;
728 :
729 2 : DLIST_ADD(*gpo_list, gpo);
730 :
731 2 : return ADS_ERROR_NT(NT_STATUS_OK);
732 : }
733 :
734 : /****************************************************************
735 : Get the full list of GROUP_POLICY_OBJECTs for a given dn.
736 : ****************************************************************/
737 :
738 2 : static ADS_STATUS ads_get_gpo_list_internal(ADS_STRUCT *ads,
739 : TALLOC_CTX *mem_ctx,
740 : const char *dn,
741 : uint32_t flags,
742 : const struct security_token *token,
743 : struct GROUP_POLICY_OBJECT **gpo_list,
744 : struct GROUP_POLICY_OBJECT **forced_gpo_list)
745 : {
746 : /*
747 : * Push GPOs to gpo_list so that the traversal order of the list matches
748 : * the order of application:
749 : * (L)ocal (S)ite (D)omain (O)rganizational(U)nit
750 : * For different domains and OUs: parent-to-child.
751 : * Within same level of domains and OUs: Link order.
752 : * Since GPOs are pushed to the front of gpo_list, GPOs have to be
753 : * pushed in the opposite order of application (OUs first, local last,
754 : * child-to-parent).
755 : * Forced GPOs are appended in the end since they override all others.
756 : */
757 :
758 0 : ADS_STATUS status;
759 0 : struct GP_LINK gp_link;
760 0 : const char *parent_dn, *site_dn, *tmp_dn;
761 2 : bool add_only_forced_gpos = false;
762 :
763 2 : ZERO_STRUCTP(gpo_list);
764 2 : ZERO_STRUCTP(forced_gpo_list);
765 :
766 2 : if (!dn) {
767 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
768 : }
769 :
770 2 : if (!ads_set_sasl_wrap_flags(ads, ADS_AUTH_SASL_SIGN)) {
771 0 : return ADS_ERROR(LDAP_INVALID_CREDENTIALS);
772 : }
773 :
774 2 : DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn));
775 :
776 2 : tmp_dn = dn;
777 :
778 6 : while ((parent_dn = ads_parent_dn(tmp_dn)) &&
779 6 : (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
780 :
781 :
782 : /* (O)rganizational(U)nit */
783 :
784 : /* An account can be a member of more OUs */
785 4 : if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) {
786 :
787 2 : DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n",
788 : parent_dn));
789 :
790 2 : status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
791 : &gp_link);
792 2 : if (ADS_ERR_OK(status)) {
793 :
794 2 : if (DEBUGLEVEL >= 100) {
795 0 : dump_gplink(&gp_link);
796 : }
797 :
798 2 : status = add_gplink_to_gpo_list(ads,
799 : mem_ctx,
800 : gpo_list,
801 : forced_gpo_list,
802 : parent_dn,
803 : &gp_link,
804 : GP_LINK_OU,
805 : add_only_forced_gpos,
806 : token);
807 2 : if (!ADS_ERR_OK(status)) {
808 0 : return status;
809 : }
810 :
811 : /* block inheritance from now on */
812 2 : if (gp_link.gp_opts &
813 : GPOPTIONS_BLOCK_INHERITANCE) {
814 0 : add_only_forced_gpos = true;
815 : }
816 : }
817 : }
818 :
819 4 : tmp_dn = parent_dn;
820 :
821 : }
822 :
823 : /* reset dn again */
824 2 : tmp_dn = dn;
825 :
826 6 : while ((parent_dn = ads_parent_dn(tmp_dn)) &&
827 6 : (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
828 :
829 : /* (D)omain */
830 :
831 : /* An account can just be a member of one domain */
832 4 : if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) {
833 :
834 2 : DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n",
835 : parent_dn));
836 :
837 2 : status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
838 : &gp_link);
839 2 : if (ADS_ERR_OK(status)) {
840 :
841 2 : if (DEBUGLEVEL >= 100) {
842 0 : dump_gplink(&gp_link);
843 : }
844 :
845 2 : status = add_gplink_to_gpo_list(ads,
846 : mem_ctx,
847 : gpo_list,
848 : forced_gpo_list,
849 : parent_dn,
850 : &gp_link,
851 : GP_LINK_DOMAIN,
852 : add_only_forced_gpos,
853 : token);
854 2 : if (!ADS_ERR_OK(status)) {
855 0 : return status;
856 : }
857 :
858 : /* block inheritance from now on */
859 2 : if (gp_link.gp_opts &
860 : GPOPTIONS_BLOCK_INHERITANCE) {
861 0 : add_only_forced_gpos = true;
862 : }
863 : }
864 : }
865 :
866 4 : tmp_dn = parent_dn;
867 : }
868 :
869 : /* (S)ite */
870 :
871 : /* are site GPOs valid for users as well ??? */
872 2 : if (flags & GPO_LIST_FLAG_MACHINE) {
873 :
874 2 : status = ads_site_dn_for_machine(ads, mem_ctx,
875 : ads->config.ldap_server_name,
876 : &site_dn);
877 2 : if (!ADS_ERR_OK(status)) {
878 0 : return status;
879 : }
880 :
881 2 : DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n",
882 : site_dn));
883 :
884 2 : status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link);
885 2 : if (ADS_ERR_OK(status)) {
886 :
887 0 : if (DEBUGLEVEL >= 100) {
888 0 : dump_gplink(&gp_link);
889 : }
890 :
891 0 : status = add_gplink_to_gpo_list(ads,
892 : mem_ctx,
893 : gpo_list,
894 : forced_gpo_list,
895 : site_dn,
896 : &gp_link,
897 : GP_LINK_SITE,
898 : add_only_forced_gpos,
899 : token);
900 0 : if (!ADS_ERR_OK(status)) {
901 0 : return status;
902 : }
903 :
904 0 : if (flags & GPO_LIST_FLAG_SITEONLY) {
905 0 : return ADS_ERROR(LDAP_SUCCESS);
906 : }
907 :
908 : /* inheritance can't be blocked at the site level */
909 : }
910 : }
911 :
912 : /* (L)ocal */
913 2 : status = add_local_policy_to_gpo_list(mem_ctx, gpo_list,
914 : GP_LINK_LOCAL);
915 2 : if (!ADS_ERR_OK(status)) {
916 0 : return status;
917 : }
918 :
919 2 : return ADS_ERROR(LDAP_SUCCESS);
920 : }
921 :
922 : /****************************************************************
923 : Get the full list of GROUP_POLICY_OBJECTs for a given dn, wrapper
924 : around ads_get_gpo_list_internal() that ensures correct ordering.
925 : ****************************************************************/
926 :
927 2 : ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
928 : TALLOC_CTX *mem_ctx,
929 : const char *dn,
930 : uint32_t flags,
931 : const struct security_token *token,
932 : struct GROUP_POLICY_OBJECT **gpo_list)
933 : {
934 2 : struct GROUP_POLICY_OBJECT *forced_gpo_list = NULL;
935 0 : ADS_STATUS status;
936 :
937 2 : status = ads_get_gpo_list_internal(ads,
938 : mem_ctx,
939 : dn,
940 : flags,
941 : token,
942 : gpo_list,
943 : &forced_gpo_list);
944 2 : if (!ADS_ERR_OK(status)) {
945 0 : return status;
946 : }
947 : /*
948 : * Append |forced_gpo_list| at the end of |gpo_list|,
949 : * so that forced GPOs are applied on top of non enforced GPOs.
950 : */
951 2 : DLIST_CONCATENATE(*gpo_list, forced_gpo_list);
952 :
953 2 : return ADS_ERROR(LDAP_SUCCESS);
954 : }
955 :
956 : #endif /* HAVE_LDAP */
|