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