79e36b79a39b6790d1c0906a6408643f0a7fba93
[sfrench/samba-autobuild/.git] / libgpo / gpext / gpext.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Group Policy Support
4  *  Copyright (C) Guenther Deschner 2007-2008
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 "../libgpo/gpext/gpext.h"
23 #include "librpc/gen_ndr/ndr_misc.h"
24 #include "lib/util/dlinklist.h"
25 #include "../libcli/registry/util_reg.h"
26 #include "libgpo/gpo_proto.h"
27 #include "registry.h"
28 #include "registry/reg_api.h"
29 #include "lib/util/util_paths.h"
30
31 static struct gp_extension *extensions = NULL;
32
33 /****************************************************************
34 ****************************************************************/
35
36 struct gp_extension *gpext_get_gp_extension_list(void)
37 {
38         return extensions;
39 }
40
41 /****************************************************************
42 ****************************************************************/
43
44 /* see http://support.microsoft.com/kb/216358/en-us/ for more info */
45
46 struct gp_extension_reg_table gpext_reg_vals[] = {
47         {
48                 .val  = "DllName",
49                 .type = REG_EXPAND_SZ,
50         },
51         {
52                 .val  = "ProcessGroupPolicy",
53                 .type = REG_SZ,
54         },
55         {
56                 .val  = "NoMachinePolicy",
57                 .type = REG_DWORD,
58         },
59         {
60                 .val  = "NoUserPolicy",
61                 .type = REG_DWORD,
62         },
63         {
64                 .val  = "NoSlowLink",
65                 .type = REG_DWORD,
66         },
67         {
68                 .val  = "NoBackgroundPolicy",
69                 .type = REG_DWORD,
70         },
71         {
72                 .val  = "NoGPOListChanges",
73                 .type = REG_DWORD,
74         },
75         {
76                 .val  = "PerUserLocalSettings",
77                 .type = REG_DWORD,
78         },
79         {
80                 .val  = "RequiresSuccessfulRegistry",
81                 .type = REG_DWORD,
82         },
83         {
84                 .val  = "EnableAsynchronousProcessing",
85                 .type = REG_DWORD,
86         },
87         {
88                 .val  = "ExtensionDebugLevel",
89                 .type = REG_DWORD,
90         },
91         /* new */
92         {
93                 .val  = "GenerateGroupPolicy",    /* not supported on w2k */
94                 .type = REG_SZ,
95         },
96         {
97                 .val  = "NotifyLinkTransition",
98                 .type = REG_DWORD,
99         },
100         {
101                 .val  = "ProcessGroupPolicyEx",    /* not supported on w2k */
102                 .type = REG_SZ,
103         },
104         {
105                 .val  = "ExtensionEventSource",    /* not supported on w2k */
106                 .type = REG_MULTI_SZ,
107         },
108         {
109                 .val  = "MaxNoGPOListChangesInterval",
110                 .type = REG_DWORD,
111         },
112         { .type = REG_NONE }
113 };
114
115 /****************************************************************
116 ****************************************************************/
117
118 static struct gp_extension *get_extension_by_name(struct gp_extension *be,
119                                                   const char *name)
120 {
121         struct gp_extension *b;
122
123         for (b = be; b; b = b->next) {
124                 if (strequal(b->name, name)) {
125                         return b;
126                 }
127         }
128
129         return NULL;
130 }
131
132 /****************************************************************
133 ****************************************************************/
134
135 static struct gp_extension_methods *get_methods_by_name(struct gp_extension *be,
136                                                         const char *name)
137 {
138         struct gp_extension *b;
139
140         for (b = be; b; b = b->next) {
141                 if (strequal(b->name, name)) {
142                         return b->methods;
143                 }
144         }
145
146         return NULL;
147 }
148
149 /****************************************************************
150 ****************************************************************/
151
152 NTSTATUS gpext_unregister_gp_extension(const char *name)
153 {
154         struct gp_extension *ext;
155
156         ext = get_extension_by_name(extensions, name);
157         if (!ext) {
158                 return NT_STATUS_OK;
159         }
160
161         DLIST_REMOVE(extensions, ext);
162         talloc_free(ext);
163
164         DEBUG(2,("Successfully removed GP extension '%s'\n", name));
165
166         return NT_STATUS_OK;
167 }
168
169 /****************************************************************
170 ****************************************************************/
171
172 NTSTATUS gpext_register_gp_extension(TALLOC_CTX *gpext_ctx,
173                                      int version,
174                                      const char *name,
175                                      const char *guid,
176                                      struct gp_extension_methods *methods)
177 {
178         struct gp_extension_methods *test;
179         struct gp_extension *entry;
180         NTSTATUS status;
181
182         if (!gpext_ctx) {
183                 return NT_STATUS_INTERNAL_DB_ERROR;
184         }
185
186         if ((version != SMB_GPEXT_INTERFACE_VERSION)) {
187                 DEBUG(0,("Failed to register gp extension.\n"
188                          "The module was compiled against "
189                          "SMB_GPEXT_INTERFACE_VERSION %d,\n"
190                          "current SMB_GPEXT_INTERFACE_VERSION is %d.\n"
191                          "Please recompile against the current "
192                          "version of samba!\n",
193                          version, SMB_GPEXT_INTERFACE_VERSION));
194                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
195         }
196
197         if (!guid || !name || !name[0] || !methods) {
198                 DEBUG(0,("Called with NULL pointer or empty name!\n"));
199                 return NT_STATUS_INVALID_PARAMETER;
200         }
201
202         test = get_methods_by_name(extensions, name);
203         if (test) {
204                 DEBUG(0,("GP extension module %s already registered!\n",
205                         name));
206                 return NT_STATUS_OBJECT_NAME_COLLISION;
207         }
208
209         entry = talloc_zero(gpext_ctx, struct gp_extension);
210         NT_STATUS_HAVE_NO_MEMORY(entry);
211
212         entry->name = talloc_strdup(gpext_ctx, name);
213         NT_STATUS_HAVE_NO_MEMORY(entry->name);
214
215         entry->guid = talloc_zero(gpext_ctx, struct GUID);
216         NT_STATUS_HAVE_NO_MEMORY(entry->guid);
217         status = GUID_from_string(guid, entry->guid);
218         NT_STATUS_NOT_OK_RETURN(status);
219
220         entry->methods = methods;
221         DLIST_ADD(extensions, entry);
222
223         DEBUG(2,("Successfully added GP extension '%s' %s\n",
224                 name, GUID_string2(gpext_ctx, entry->guid)));
225
226         return NT_STATUS_OK;
227 }
228
229 /****************************************************************
230 ****************************************************************/
231
232 static NTSTATUS gp_extension_init_module(TALLOC_CTX *mem_ctx,
233                                          const char *name,
234                                          struct gp_extension **gpext)
235 {
236         NTSTATUS status;
237         struct gp_extension *ext = NULL;
238
239         ext = talloc_zero(mem_ctx, struct gp_extension);
240         NT_STATUS_HAVE_NO_MEMORY(gpext);
241
242         ext->methods = get_methods_by_name(extensions, name);
243         if (!ext->methods) {
244
245                 status = smb_probe_module(SAMBA_SUBSYSTEM_GPEXT,
246                                           name);
247                 if (!NT_STATUS_IS_OK(status)) {
248                         return status;
249                 }
250
251                 ext->methods = get_methods_by_name(extensions, name);
252                 if (!ext->methods) {
253                         return NT_STATUS_DLL_INIT_FAILED;
254                 }
255         }
256
257         *gpext = ext;
258
259         return NT_STATUS_OK;
260 }
261
262 /****************************************************************
263 ****************************************************************/
264
265 static bool add_gp_extension_reg_entry_to_array(TALLOC_CTX *mem_ctx,
266                                                 struct gp_extension_reg_entry *entry,
267                                                 struct gp_extension_reg_entry **entries,
268                                                 size_t *num)
269 {
270         *entries = talloc_realloc(mem_ctx, *entries,
271                                         struct gp_extension_reg_entry,
272                                         (*num)+1);
273         if (*entries == NULL) {
274                 *num = 0;
275                 return false;
276         }
277
278         (*entries)[*num].value = entry->value;
279         (*entries)[*num].data = entry->data;
280
281         *num += 1;
282         return true;
283 }
284
285 /****************************************************************
286 ****************************************************************/
287
288 static bool add_gp_extension_reg_info_entry_to_array(TALLOC_CTX *mem_ctx,
289                                                      struct gp_extension_reg_info_entry *entry,
290                                                      struct gp_extension_reg_info_entry **entries,
291                                                      size_t *num)
292 {
293         *entries = talloc_realloc(mem_ctx, *entries,
294                                         struct gp_extension_reg_info_entry,
295                                         (*num)+1);
296         if (*entries == NULL) {
297                 *num = 0;
298                 return false;
299         }
300
301         (*entries)[*num].guid = entry->guid;
302         (*entries)[*num].num_entries = entry->num_entries;
303         (*entries)[*num].entries = entry->entries;
304
305         *num += 1;
306         return true;
307 }
308
309 /****************************************************************
310 ****************************************************************/
311
312 static NTSTATUS gp_ext_info_add_reg(TALLOC_CTX *mem_ctx,
313                                     struct gp_extension_reg_info_entry *entry,
314                                     const char *value,
315                                     enum winreg_Type type,
316                                     const char *data_s)
317 {
318         struct gp_extension_reg_entry *reg_entry = NULL;
319         struct registry_value *data = NULL;
320
321         reg_entry = talloc_zero(mem_ctx, struct gp_extension_reg_entry);
322         NT_STATUS_HAVE_NO_MEMORY(reg_entry);
323
324         data = talloc_zero(mem_ctx, struct registry_value);
325         NT_STATUS_HAVE_NO_MEMORY(data);
326
327         data->type = type;
328
329         switch (type) {
330                 case REG_SZ:
331                 case REG_EXPAND_SZ:
332                         if (!push_reg_sz(mem_ctx, &data->data, data_s)) {
333                                 return NT_STATUS_NO_MEMORY;
334                         }
335                         break;
336                 case REG_DWORD: {
337                         uint32_t v = atoi(data_s);
338                         data->data = data_blob_talloc(mem_ctx, NULL, 4);
339                         SIVAL(data->data.data, 0, v);
340                         break;
341                 }
342                 default:
343                         return NT_STATUS_NOT_SUPPORTED;
344         }
345
346         reg_entry->value = value;
347         reg_entry->data = data;
348
349         if (!add_gp_extension_reg_entry_to_array(mem_ctx, reg_entry,
350                                                  &entry->entries,
351                                                  &entry->num_entries)) {
352                 return NT_STATUS_NO_MEMORY;
353         }
354
355         return NT_STATUS_OK;
356 }
357
358 /****************************************************************
359 ****************************************************************/
360
361 static NTSTATUS gp_ext_info_add_reg_table(TALLOC_CTX *mem_ctx,
362                                           const char *module,
363                                           struct gp_extension_reg_info_entry *entry,
364                                           struct gp_extension_reg_table *table)
365 {
366         NTSTATUS status;
367         const char *module_name = NULL;
368         int i;
369
370         module_name = talloc_asprintf(mem_ctx, "%s.%s", module, shlib_ext());
371         NT_STATUS_HAVE_NO_MEMORY(module_name);
372
373         status = gp_ext_info_add_reg(mem_ctx, entry,
374                                      "DllName", REG_EXPAND_SZ, module_name);
375         NT_STATUS_NOT_OK_RETURN(status);
376
377         for (i=0; table[i].val; i++) {
378                 status = gp_ext_info_add_reg(mem_ctx, entry,
379                                              table[i].val,
380                                              table[i].type,
381                                              table[i].data);
382                 NT_STATUS_NOT_OK_RETURN(status);
383         }
384
385         return status;
386 }
387
388 /****************************************************************
389 ****************************************************************/
390
391 NTSTATUS gpext_info_add_entry(TALLOC_CTX *mem_ctx,
392                               const char *module,
393                               const char *ext_guid,
394                               struct gp_extension_reg_table *table,
395                               struct gp_extension_reg_info *info)
396 {
397         NTSTATUS status;
398         struct gp_extension_reg_info_entry *entry = NULL;
399
400         entry = talloc_zero(mem_ctx, struct gp_extension_reg_info_entry);
401         NT_STATUS_HAVE_NO_MEMORY(entry);
402
403         status = GUID_from_string(ext_guid, &entry->guid);
404         NT_STATUS_NOT_OK_RETURN(status);
405
406         status = gp_ext_info_add_reg_table(mem_ctx, module, entry, table);
407         NT_STATUS_NOT_OK_RETURN(status);
408
409         if (!add_gp_extension_reg_info_entry_to_array(mem_ctx, entry,
410                                                       &info->entries,
411                                                       &info->num_entries)) {
412                 return NT_STATUS_NO_MEMORY;
413         }
414
415         return NT_STATUS_OK;
416 }
417
418 /****************************************************************
419 ****************************************************************/
420
421 static bool gp_extension_reg_info_verify_entry(struct gp_extension_reg_entry *entry)
422 {
423         int i;
424
425         for (i=0; gpext_reg_vals[i].val; i++) {
426
427                 if ((strequal(entry->value, gpext_reg_vals[i].val)) &&
428                     (entry->data->type == gpext_reg_vals[i].type)) {
429                         return true;
430                 }
431         }
432
433         return false;
434 }
435
436 /****************************************************************
437 ****************************************************************/
438
439 static bool gp_extension_reg_info_verify(struct gp_extension_reg_info_entry *entry)
440 {
441         int i;
442
443         for (i=0; i < entry->num_entries; i++) {
444                 if (!gp_extension_reg_info_verify_entry(&entry->entries[i])) {
445                         return false;
446                 }
447         }
448
449         return true;
450 }
451
452 /****************************************************************
453 ****************************************************************/
454
455 static WERROR gp_extension_store_reg_vals(TALLOC_CTX *mem_ctx,
456                                           struct registry_key *key,
457                                           struct gp_extension_reg_info_entry *entry)
458 {
459         WERROR werr = WERR_OK;
460         size_t i;
461
462         for (i=0; i < entry->num_entries; i++) {
463
464                 werr = reg_setvalue(key,
465                                     entry->entries[i].value,
466                                     entry->entries[i].data);
467                 W_ERROR_NOT_OK_RETURN(werr);
468         }
469
470         return werr;
471 }
472
473 /****************************************************************
474 ****************************************************************/
475
476 static WERROR gp_extension_store_reg_entry(TALLOC_CTX *mem_ctx,
477                                            struct gp_registry_context *reg_ctx,
478                                            struct gp_extension_reg_info_entry *entry)
479 {
480         WERROR werr;
481         struct registry_key *key = NULL;
482         const char *subkeyname = NULL;
483
484         if (!gp_extension_reg_info_verify(entry)) {
485                 return WERR_INVALID_PARAMETER;
486         }
487
488         subkeyname = GUID_string2(mem_ctx, &entry->guid);
489         W_ERROR_HAVE_NO_MEMORY(subkeyname);
490
491         if (!strupper_m(discard_const_p(char, subkeyname))) {
492                 return WERR_INVALID_PARAMETER;
493         }
494
495         werr = gp_store_reg_subkey(mem_ctx,
496                                    subkeyname,
497                                    reg_ctx->curr_key,
498                                    &key);
499         W_ERROR_NOT_OK_RETURN(werr);
500
501         werr = gp_extension_store_reg_vals(mem_ctx,
502                                            key,
503                                            entry);
504         W_ERROR_NOT_OK_RETURN(werr);
505
506         return werr;
507 }
508
509 /****************************************************************
510 ****************************************************************/
511
512 static WERROR gp_extension_store_reg(TALLOC_CTX *mem_ctx,
513                                      struct gp_registry_context *reg_ctx,
514                                      struct gp_extension_reg_info *info)
515 {
516         WERROR werr = WERR_OK;
517         int i;
518
519         if (!info) {
520                 return WERR_OK;
521         }
522
523         for (i=0; i < info->num_entries; i++) {
524                 werr = gp_extension_store_reg_entry(mem_ctx,
525                                                     reg_ctx,
526                                                     &info->entries[i]);
527                 W_ERROR_NOT_OK_RETURN(werr);
528         }
529
530         return werr;
531 }
532
533 /****************************************************************
534 ****************************************************************/
535
536 static NTSTATUS gp_glob_ext_list(TALLOC_CTX *mem_ctx,
537                                  const char ***ext_list,
538                                  size_t *ext_list_len)
539 {
540         DIR *dir = NULL;
541         struct dirent *dirent = NULL;
542
543         dir = opendir(modules_path(talloc_tos(), 
544                                        SAMBA_SUBSYSTEM_GPEXT));
545         if (!dir) {
546                 return map_nt_error_from_unix_common(errno);
547         }
548
549         while ((dirent = readdir(dir))) {
550
551                 fstring name; /* forgive me... */
552                 char *p;
553
554                 if ((strequal(dirent->d_name, ".")) ||
555                     (strequal(dirent->d_name, ".."))) {
556                         continue;
557                 }
558
559                 p = strrchr(dirent->d_name, '.');
560                 if (!p) {
561                         closedir(dir);
562                         return NT_STATUS_NO_MEMORY;
563                 }
564
565                 if (!strcsequal(p+1, shlib_ext())) {
566                         DEBUG(10,("gp_glob_ext_list: not a *.so file: %s\n",
567                                 dirent->d_name));
568                         continue;
569                 }
570
571                 fstrcpy(name, dirent->d_name);
572                 name[PTR_DIFF(p, dirent->d_name)] = 0;
573
574                 if (!add_string_to_array(mem_ctx, name, ext_list,
575                                          ext_list_len)) {
576                         closedir(dir);
577                         return NT_STATUS_NO_MEMORY;
578                 }
579         }
580
581         closedir(dir);
582
583         return NT_STATUS_OK;
584 }
585
586 /****************************************************************
587 ****************************************************************/
588
589 NTSTATUS gpext_shutdown_gp_extensions(void)
590 {
591         struct gp_extension *ext = NULL;
592
593         for (ext = extensions; ext; ext = ext->next) {
594                 if (ext->methods && ext->methods->shutdown) {
595                         ext->methods->shutdown();
596                 }
597         }
598
599         return NT_STATUS_OK;
600 }
601
602 /****************************************************************
603 ****************************************************************/
604
605 NTSTATUS gpext_init_gp_extensions(TALLOC_CTX *mem_ctx)
606 {
607         NTSTATUS status;
608         WERROR werr;
609         int i = 0;
610         const char **ext_array = NULL;
611         size_t ext_array_len = 0;
612         struct gp_extension *gpext = NULL;
613         struct gp_registry_context *reg_ctx = NULL;
614
615         if (gpext_get_gp_extension_list()) {
616                 return NT_STATUS_OK;
617         }
618
619         status = gp_glob_ext_list(mem_ctx, &ext_array, &ext_array_len);
620         NT_STATUS_NOT_OK_RETURN(status);
621
622         for (i=0; i<ext_array_len; i++) {
623
624                 struct gp_extension_reg_info *info = NULL;
625
626                 status = gp_extension_init_module(mem_ctx, ext_array[i],
627                                                   &gpext);
628                 if (!NT_STATUS_IS_OK(status)) {
629                         goto out;
630                 }
631
632                 if (gpext->methods->get_reg_config) {
633
634                         status = gpext->methods->initialize(mem_ctx);
635                         if (!NT_STATUS_IS_OK(status)) {
636                                 gpext->methods->shutdown();
637                                 goto out;
638                         }
639
640                         status = gpext->methods->get_reg_config(mem_ctx,
641                                                                 &info);
642                         if (!NT_STATUS_IS_OK(status)) {
643                                 gpext->methods->shutdown();
644                                 goto out;
645                         }
646
647                         if (!reg_ctx) {
648                                 struct security_token *token;
649
650                                 token = registry_create_system_token(mem_ctx);
651                                 NT_STATUS_HAVE_NO_MEMORY(token);
652
653                                 werr = gp_init_reg_ctx(mem_ctx,
654                                                        KEY_WINLOGON_GPEXT_PATH,
655                                                        REG_KEY_WRITE,
656                                                        token,
657                                                        &reg_ctx);
658                                 if (!W_ERROR_IS_OK(werr)) {
659                                         status = werror_to_ntstatus(werr);
660                                         gpext->methods->shutdown();
661                                         goto out;
662                                 }
663                         }
664
665                         werr = gp_extension_store_reg(mem_ctx, reg_ctx, info);
666                         if (!W_ERROR_IS_OK(werr)) {
667                                 DEBUG(1,("gp_extension_store_reg failed: %s\n",
668                                         win_errstr(werr)));
669                                 TALLOC_FREE(info);
670                                 gpext->methods->shutdown();
671                                 status = werror_to_ntstatus(werr);
672                                 goto out;
673                         }
674                         TALLOC_FREE(info);
675                 }
676
677         }
678
679  out:
680         TALLOC_FREE(reg_ctx);
681
682         return status;
683 }
684
685 /****************************************************************
686 ****************************************************************/
687
688 NTSTATUS gpext_free_gp_extensions(void)
689 {
690         struct gp_extension *ext, *ext_next = NULL;
691
692         for (ext = extensions; ext; ext = ext_next) {
693                 ext_next = ext->next;
694                 DLIST_REMOVE(extensions, ext);
695                 TALLOC_FREE(ext);
696         }
697
698         extensions = NULL;
699
700         return NT_STATUS_OK;
701 }
702
703 /****************************************************************
704 ****************************************************************/
705
706 void gpext_debug_header(int lvl,
707                         const char *name,
708                         uint32_t flags,
709                         const struct GROUP_POLICY_OBJECT *gpo,
710                         const char *extension_guid,
711                         const char *snapin_guid)
712 {
713         char *flags_str = NULL;
714
715         DEBUG(lvl,("%s\n", name));
716         DEBUGADD(lvl,("\tgpo:           %s (%s)\n", gpo->name,
717                 gpo->display_name));
718         DEBUGADD(lvl,("\tcse extension: %s (%s)\n", extension_guid,
719                 cse_gpo_guid_string_to_name(extension_guid)));
720         DEBUGADD(lvl,("\tgplink:        %s\n", gpo->link));
721         DEBUGADD(lvl,("\tsnapin:        %s (%s)\n", snapin_guid,
722                 cse_snapin_gpo_guid_string_to_name(snapin_guid)));
723
724         flags_str = gpo_flag_str(NULL, flags);
725         DEBUGADD(lvl,("\tflags:         0x%08x %s\n", flags, flags_str));
726         TALLOC_FREE(flags_str);
727 }
728
729 /****************************************************************
730 ****************************************************************/
731
732 static NTSTATUS gpext_check_gpo_for_gpext_presence(TALLOC_CTX *mem_ctx,
733                                                    uint32_t flags,
734                                                    const struct GROUP_POLICY_OBJECT *gpo,
735                                                    const struct GUID *guid,
736                                                    bool *gpext_guid_present)
737 {
738         struct GP_EXT *gp_ext = NULL;
739         int i;
740         bool ok;
741
742         *gpext_guid_present = false;
743
744
745         if (gpo->link_type == GP_LINK_LOCAL) {
746                 return NT_STATUS_OK;
747         }
748
749         ok = gpo_get_gp_ext_from_gpo(mem_ctx, flags, gpo, &gp_ext);
750         if (!ok) {
751                 return NT_STATUS_INVALID_PARAMETER;
752         }
753
754         if (gp_ext == NULL) {
755                 return NT_STATUS_OK;
756         }
757
758         for (i = 0; i < gp_ext->num_exts; i++) {
759                 struct GUID guid2;
760                 NTSTATUS status;
761
762                 status = GUID_from_string(gp_ext->extensions_guid[i], &guid2);
763                 if (!NT_STATUS_IS_OK(status)) {
764                         return status;
765                 }
766                 if (GUID_equal(guid, &guid2)) {
767                         *gpext_guid_present = true;
768                         return NT_STATUS_OK;
769                 }
770         }
771
772         return NT_STATUS_OK;
773 }
774
775 /****************************************************************
776 ****************************************************************/
777
778 NTSTATUS gpext_process_extension(TALLOC_CTX *mem_ctx,
779                                  uint32_t flags,
780                                  const struct security_token *token,
781                                  struct registry_key *root_key,
782                                  const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
783                                  const struct GROUP_POLICY_OBJECT *changed_gpo_list,
784                                  const char *extension_guid_filter)
785 {
786         NTSTATUS status;
787         struct gp_extension *ext = NULL;
788         const struct GROUP_POLICY_OBJECT *gpo;
789         struct GUID extension_guid_filter_guid;
790
791         status = gpext_init_gp_extensions(mem_ctx);
792         if (!NT_STATUS_IS_OK(status)) {
793                 DEBUG(1,("gpext_init_gp_extensions failed: %s\n",
794                         nt_errstr(status)));
795                 return status;
796         }
797
798         if (extension_guid_filter) {
799                 status = GUID_from_string(extension_guid_filter,
800                                           &extension_guid_filter_guid);
801                 if (!NT_STATUS_IS_OK(status)) {
802                         return status;
803                 }
804         }
805
806         for (ext = extensions; ext; ext = ext->next) {
807
808                 struct GROUP_POLICY_OBJECT *deleted_gpo_list_filtered = NULL;
809                 struct GROUP_POLICY_OBJECT *changed_gpo_list_filtered = NULL;
810
811                 if (extension_guid_filter) {
812                         if (!GUID_equal(&extension_guid_filter_guid, ext->guid)) {
813                                 continue;
814                         }
815                 }
816
817                 for (gpo = deleted_gpo_list; gpo; gpo = gpo->next) {
818
819                         bool is_present = false;
820
821                         status = gpext_check_gpo_for_gpext_presence(mem_ctx,
822                                                                     flags,
823                                                                     gpo,
824                                                                     ext->guid,
825                                                                     &is_present);
826                         if (!NT_STATUS_IS_OK(status)) {
827                                 return status;
828                         }
829
830                         if (is_present) {
831                                 struct GROUP_POLICY_OBJECT *new_gpo;
832
833                                 status = gpo_copy(mem_ctx, gpo, &new_gpo);
834                                 if (!NT_STATUS_IS_OK(status)) {
835                                         return status;
836                                 }
837
838                                 DLIST_ADD(deleted_gpo_list_filtered, new_gpo);
839                         }
840                 }
841
842                 for (gpo = changed_gpo_list; gpo; gpo = gpo->next) {
843
844                         bool is_present = false;
845
846                         status = gpext_check_gpo_for_gpext_presence(mem_ctx,
847                                                                     flags,
848                                                                     gpo,
849                                                                     ext->guid,
850                                                                     &is_present);
851                         if (!NT_STATUS_IS_OK(status)) {
852                                 return status;
853                         }
854
855                         if (is_present) {
856                                 struct GROUP_POLICY_OBJECT *new_gpo;
857
858                                 status = gpo_copy(mem_ctx, gpo, &new_gpo);
859                                 if (!NT_STATUS_IS_OK(status)) {
860                                         return status;
861                                 }
862
863                                 DLIST_ADD(changed_gpo_list_filtered, new_gpo);
864                         }
865                 }
866
867                 status = ext->methods->initialize(mem_ctx);
868                 NT_STATUS_NOT_OK_RETURN(status);
869
870                 status = ext->methods->process_group_policy(mem_ctx,
871                                                             flags,
872                                                             root_key,
873                                                             token,
874                                                             deleted_gpo_list_filtered,
875                                                             changed_gpo_list_filtered);
876                 if (!NT_STATUS_IS_OK(status)) {
877                         ext->methods->shutdown();
878                 }
879         }
880
881         return status;
882 }