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