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