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