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