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