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