s3: Make cli_cm_open return NTSTATUS
[sfrench/samba-autobuild/.git] / libgpo / gpo_ldap.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Group Policy Object Support
4  *  Copyright (C) Guenther Deschner 2005,2007
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "libgpo/gpo.h"
22 #include "auth.h"
23 #if _SAMBA_BUILD_ == 4
24 #include "libgpo/gpo_s4.h"
25 #include "source4/libgpo/ads_convenience.h"
26 #endif
27 #include "../libcli/security/security.h"
28
29 /****************************************************************
30  parse the raw extension string into a GP_EXT structure
31 ****************************************************************/
32
33 bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
34                       const char *extension_raw,
35                       struct GP_EXT **gp_ext)
36 {
37         bool ret = false;
38         struct GP_EXT *ext = NULL;
39         char **ext_list = NULL;
40         char **ext_strings = NULL;
41         int i;
42
43         if (!extension_raw) {
44                 goto parse_error;
45         }
46
47         DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw));
48
49         ext = talloc_zero(mem_ctx, struct GP_EXT);
50         if (!ext) {
51                 goto parse_error;
52         }
53
54         ext_list = str_list_make(mem_ctx, extension_raw, "]");
55         if (!ext_list) {
56                 goto parse_error;
57         }
58
59         for (i = 0; ext_list[i] != NULL; i++) {
60                 /* no op */
61         }
62
63         ext->num_exts = i;
64
65         if (ext->num_exts) {
66                 ext->extensions         = talloc_zero_array(mem_ctx, char *,
67                                                             ext->num_exts);
68                 ext->extensions_guid    = talloc_zero_array(mem_ctx, char *,
69                                                             ext->num_exts);
70                 ext->snapins            = talloc_zero_array(mem_ctx, char *,
71                                                             ext->num_exts);
72                 ext->snapins_guid       = talloc_zero_array(mem_ctx, char *,
73                                                             ext->num_exts);
74         }
75
76         ext->gp_extension = talloc_strdup(mem_ctx, extension_raw);
77
78         if (!ext->extensions || !ext->extensions_guid ||
79             !ext->snapins || !ext->snapins_guid ||
80             !ext->gp_extension) {
81                 goto parse_error;
82         }
83
84         for (i = 0; ext_list[i] != NULL; i++) {
85
86                 int k;
87                 char *p, *q;
88
89                 DEBUGADD(10,("extension #%d\n", i));
90
91                 p = ext_list[i];
92
93                 if (p[0] == '[') {
94                         p++;
95                 }
96
97                 ext_strings = str_list_make(mem_ctx, p, "}");
98                 if (ext_strings == NULL) {
99                         goto parse_error;
100                 }
101
102                 for (k = 0; ext_strings[k] != NULL; k++) {
103                         /* no op */
104                 }
105
106                 q = ext_strings[0];
107
108                 if (q[0] == '{') {
109                         q++;
110                 }
111
112                 ext->extensions[i] = talloc_strdup(mem_ctx,
113                                            cse_gpo_guid_string_to_name(q));
114                 ext->extensions_guid[i] = talloc_strdup(mem_ctx, q);
115
116                 /* we might have no name for the guid */
117                 if (ext->extensions_guid[i] == NULL) {
118                         goto parse_error;
119                 }
120
121                 for (k = 1; ext_strings[k] != NULL; k++) {
122
123                         char *m = ext_strings[k];
124
125                         if (m[0] == '{') {
126                                 m++;
127                         }
128
129                         /* FIXME: theoretically there could be more than one
130                          * snapin per extension */
131                         ext->snapins[i] = talloc_strdup(mem_ctx,
132                                 cse_snapin_gpo_guid_string_to_name(m));
133                         ext->snapins_guid[i] = talloc_strdup(mem_ctx, m);
134
135                         /* we might have no name for the guid */
136                         if (ext->snapins_guid[i] == NULL) {
137                                 goto parse_error;
138                         }
139                 }
140         }
141
142         *gp_ext = ext;
143
144         ret = true;
145
146  parse_error:
147         talloc_free(ext_list);
148         talloc_free(ext_strings);
149
150         return ret;
151 }
152
153 #ifdef HAVE_LDAP
154
155 /****************************************************************
156  parse the raw link string into a GP_LINK structure
157 ****************************************************************/
158
159 static ADS_STATUS gpo_parse_gplink(TALLOC_CTX *mem_ctx,
160                                    const char *gp_link_raw,
161                                    uint32_t options,
162                                    struct GP_LINK *gp_link)
163 {
164         ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
165         char **link_list;
166         int i;
167
168         ZERO_STRUCTP(gp_link);
169
170         DEBUG(10,("gpo_parse_gplink: gPLink: %s\n", gp_link_raw));
171
172         link_list = str_list_make_v3(mem_ctx, gp_link_raw, "]");
173         if (!link_list) {
174                 goto parse_error;
175         }
176
177         for (i = 0; link_list[i] != NULL; i++) {
178                 /* no op */
179         }
180
181         gp_link->gp_opts = options;
182         gp_link->num_links = i;
183
184         if (gp_link->num_links) {
185                 gp_link->link_names = talloc_zero_array(mem_ctx, char *,
186                                                         gp_link->num_links);
187                 gp_link->link_opts = talloc_zero_array(mem_ctx, uint32_t,
188                                                        gp_link->num_links);
189         }
190
191         gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw);
192
193         if (!gp_link->link_names || !gp_link->link_opts || !gp_link->gp_link) {
194                 goto parse_error;
195         }
196
197         for (i = 0; link_list[i] != NULL; i++) {
198
199                 char *p, *q;
200
201                 DEBUGADD(10,("gpo_parse_gplink: processing link #%d\n", i));
202
203                 q = link_list[i];
204                 if (q[0] == '[') {
205                         q++;
206                 };
207
208                 p = strchr(q, ';');
209
210                 if (p == NULL) {
211                         goto parse_error;
212                 }
213
214                 gp_link->link_names[i] = talloc_strdup(mem_ctx, q);
215                 if (gp_link->link_names[i] == NULL) {
216                         goto parse_error;
217                 }
218                 gp_link->link_names[i][PTR_DIFF(p, q)] = 0;
219
220                 gp_link->link_opts[i] = atoi(p + 1);
221
222                 DEBUGADD(10,("gpo_parse_gplink: link: %s\n",
223                         gp_link->link_names[i]));
224                 DEBUGADD(10,("gpo_parse_gplink: opt: %d\n",
225                         gp_link->link_opts[i]));
226
227         }
228
229         status = ADS_SUCCESS;
230
231  parse_error:
232         talloc_free(link_list);
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, mem_ctx, 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 parameters
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 = SECINFO_DACL;
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, mem_ctx, 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         TALLOC_FREE(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 security_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(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 security_token **token)
625 {
626         ADS_STATUS status;
627         struct dom_sid object_sid;
628         struct dom_sid primary_group_sid;
629         struct dom_sid *ad_token_sids;
630         size_t num_ad_token_sids = 0;
631         struct dom_sid *token_sids;
632         uint32_t num_token_sids = 0;
633         struct security_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, struct dom_sid, 1);
644         ADS_ERROR_HAVE_NO_MEMORY(token_sids);
645
646         status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
647                                                       &primary_group_sid,
648                                                       &token_sids,
649                                                       &num_token_sids));
650         if (!ADS_ERR_OK(status)) {
651                 return status;
652         }
653
654         for (i = 0; i < num_ad_token_sids; i++) {
655
656                 if (sid_check_is_in_builtin(&ad_token_sids[i])) {
657                         continue;
658                 }
659
660                 status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
661                                                               &ad_token_sids[i],
662                                                               &token_sids,
663                                                               &num_token_sids));
664                 if (!ADS_ERR_OK(status)) {
665                         return status;
666                 }
667         }
668
669         new_token = create_local_nt_token(mem_ctx, &object_sid, false,
670                                           num_token_sids, token_sids);
671         ADS_ERROR_HAVE_NO_MEMORY(new_token);
672
673         *token = new_token;
674
675         security_token_debug(DBGC_CLASS, 5, *token);
676
677         return ADS_ERROR_LDAP(LDAP_SUCCESS);
678 }
679
680 /****************************************************************
681 ****************************************************************/
682
683 static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx,
684                                                struct GROUP_POLICY_OBJECT **gpo_list,
685                                                enum GPO_LINK_TYPE link_type)
686 {
687         struct GROUP_POLICY_OBJECT *gpo = NULL;
688
689         ADS_ERROR_HAVE_NO_MEMORY(gpo_list);
690
691         gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
692         ADS_ERROR_HAVE_NO_MEMORY(gpo);
693
694         gpo->name = talloc_strdup(mem_ctx, "Local Policy");
695         ADS_ERROR_HAVE_NO_MEMORY(gpo->name);
696
697         gpo->display_name = talloc_strdup(mem_ctx, "Local Policy");
698         ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name);
699
700         gpo->link_type = link_type;
701
702         DLIST_ADD(*gpo_list, gpo);
703
704         return ADS_ERROR_NT(NT_STATUS_OK);
705 }
706
707 /****************************************************************
708  get the full list of GROUP_POLICY_OBJECTs for a given dn
709 ****************************************************************/
710
711 ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
712                             TALLOC_CTX *mem_ctx,
713                             const char *dn,
714                             uint32_t flags,
715                             const struct security_token *token,
716                             struct GROUP_POLICY_OBJECT **gpo_list)
717 {
718         /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */
719
720         ADS_STATUS status;
721         struct GP_LINK gp_link;
722         const char *parent_dn, *site_dn, *tmp_dn;
723         bool add_only_forced_gpos = false;
724
725         ZERO_STRUCTP(gpo_list);
726
727         if (!dn) {
728                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
729         }
730
731         if (!ads_set_sasl_wrap_flags(ads, ADS_AUTH_SASL_SIGN)) {
732                 return ADS_ERROR(LDAP_INVALID_CREDENTIALS);
733         }
734
735         DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn));
736
737         /* (L)ocal */
738         status = add_local_policy_to_gpo_list(mem_ctx, gpo_list,
739                                               GP_LINK_LOCAL);
740         if (!ADS_ERR_OK(status)) {
741                 return status;
742         }
743
744         /* (S)ite */
745
746         /* are site GPOs valid for users as well ??? */
747         if (flags & GPO_LIST_FLAG_MACHINE) {
748
749                 status = ads_site_dn_for_machine(ads, mem_ctx,
750                                                  ads->config.ldap_server_name,
751                                                  &site_dn);
752                 if (!ADS_ERR_OK(status)) {
753                         return status;
754                 }
755
756                 DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n",
757                         site_dn));
758
759                 status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link);
760                 if (ADS_ERR_OK(status)) {
761
762                         if (DEBUGLEVEL >= 100) {
763                                 dump_gplink(ads, mem_ctx, &gp_link);
764                         }
765
766                         status = add_gplink_to_gpo_list(ads, mem_ctx, gpo_list,
767                                                         site_dn, &gp_link,
768                                                         GP_LINK_SITE,
769                                                         add_only_forced_gpos,
770                                                         token);
771                         if (!ADS_ERR_OK(status)) {
772                                 return status;
773                         }
774
775                         if (flags & GPO_LIST_FLAG_SITEONLY) {
776                                 return ADS_ERROR(LDAP_SUCCESS);
777                         }
778
779                         /* inheritance can't be blocked at the site level */
780                 }
781         }
782
783         tmp_dn = dn;
784
785         while ((parent_dn = ads_parent_dn(tmp_dn)) &&
786                (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
787
788                 /* (D)omain */
789
790                 /* An account can just be a member of one domain */
791                 if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) {
792
793                         DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n",
794                                 parent_dn));
795
796                         status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
797                                                   &gp_link);
798                         if (ADS_ERR_OK(status)) {
799
800                                 if (DEBUGLEVEL >= 100) {
801                                         dump_gplink(ads, mem_ctx, &gp_link);
802                                 }
803
804                                 /* block inheritance from now on */
805                                 if (gp_link.gp_opts &
806                                     GPOPTIONS_BLOCK_INHERITANCE) {
807                                         add_only_forced_gpos = true;
808                                 }
809
810                                 status = add_gplink_to_gpo_list(ads,
811                                                         mem_ctx,
812                                                         gpo_list,
813                                                         parent_dn,
814                                                         &gp_link,
815                                                         GP_LINK_DOMAIN,
816                                                         add_only_forced_gpos,
817                                                         token);
818                                 if (!ADS_ERR_OK(status)) {
819                                         return status;
820                                 }
821                         }
822                 }
823
824                 tmp_dn = parent_dn;
825         }
826
827         /* reset dn again */
828         tmp_dn = dn;
829
830         while ((parent_dn = ads_parent_dn(tmp_dn)) &&
831                (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
832
833
834                 /* (O)rganizational(U)nit */
835
836                 /* An account can be a member of more OUs */
837                 if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) {
838
839                         DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n",
840                                 parent_dn));
841
842                         status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
843                                                   &gp_link);
844                         if (ADS_ERR_OK(status)) {
845
846                                 if (DEBUGLEVEL >= 100) {
847                                         dump_gplink(ads, mem_ctx, &gp_link);
848                                 }
849
850                                 /* block inheritance from now on */
851                                 if (gp_link.gp_opts &
852                                     GPOPTIONS_BLOCK_INHERITANCE) {
853                                         add_only_forced_gpos = true;
854                                 }
855
856                                 status = add_gplink_to_gpo_list(ads,
857                                                         mem_ctx,
858                                                         gpo_list,
859                                                         parent_dn,
860                                                         &gp_link,
861                                                         GP_LINK_OU,
862                                                         add_only_forced_gpos,
863                                                         token);
864                                 if (!ADS_ERR_OK(status)) {
865                                         return status;
866                                 }
867                         }
868                 }
869
870                 tmp_dn = parent_dn;
871
872         };
873
874         return ADS_ERROR(LDAP_SUCCESS);
875 }
876
877 #endif /* HAVE_LDAP */