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