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