2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Guenther Deschner 2007-2008
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.
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.
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/>.
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"
28 #include "registry/reg_api.h"
29 #include "lib/util/util_paths.h"
31 static struct gp_extension
*extensions
= NULL
;
33 /****************************************************************
34 ****************************************************************/
36 struct gp_extension
*gpext_get_gp_extension_list(void)
41 /****************************************************************
42 ****************************************************************/
45 struct gp_extension_reg_table gpext_reg_vals
[] = {
48 .type
= REG_EXPAND_SZ
,
51 .val
= "ProcessGroupPolicy",
55 .val
= "NoMachinePolicy",
59 .val
= "NoUserPolicy",
67 .val
= "NoBackgroundPolicy",
71 .val
= "NoGPOListChanges",
75 .val
= "PerUserLocalSettings",
79 .val
= "RequiresSuccessfulRegistry",
83 .val
= "EnableAsynchronousProcessing",
87 .val
= "ExtensionDebugLevel",
92 .val
= "GenerateGroupPolicy", /* not supported on w2k */
96 .val
= "NotifyLinkTransition",
100 .val
= "ProcessGroupPolicyEx", /* not supported on w2k */
104 .val
= "ExtensionEventSource", /* not supported on w2k */
105 .type
= REG_MULTI_SZ
,
108 .val
= "MaxNoGPOListChangesInterval",
114 /****************************************************************
115 ****************************************************************/
117 static struct gp_extension
*get_extension_by_name(struct gp_extension
*be
,
120 struct gp_extension
*b
;
122 for (b
= be
; b
; b
= b
->next
) {
123 if (strequal(b
->name
, name
)) {
131 /****************************************************************
132 ****************************************************************/
134 static struct gp_extension_methods
*get_methods_by_name(struct gp_extension
*be
,
137 struct gp_extension
*b
;
139 for (b
= be
; b
; b
= b
->next
) {
140 if (strequal(b
->name
, name
)) {
148 /****************************************************************
149 ****************************************************************/
151 NTSTATUS
gpext_unregister_gp_extension(const char *name
)
153 struct gp_extension
*ext
;
155 ext
= get_extension_by_name(extensions
, name
);
160 DLIST_REMOVE(extensions
, ext
);
163 DEBUG(2,("Successfully removed GP extension '%s'\n", name
));
168 /****************************************************************
169 ****************************************************************/
171 NTSTATUS
gpext_register_gp_extension(TALLOC_CTX
*gpext_ctx
,
175 struct gp_extension_methods
*methods
)
177 struct gp_extension_methods
*test
;
178 struct gp_extension
*entry
;
182 return NT_STATUS_INTERNAL_DB_ERROR
;
185 if ((version
!= SMB_GPEXT_INTERFACE_VERSION
)) {
186 DEBUG(0,("Failed to register gp extension.\n"
187 "The module was compiled against "
188 "SMB_GPEXT_INTERFACE_VERSION %d,\n"
189 "current SMB_GPEXT_INTERFACE_VERSION is %d.\n"
190 "Please recompile against the current "
191 "version of samba!\n",
192 version
, SMB_GPEXT_INTERFACE_VERSION
));
193 return NT_STATUS_OBJECT_TYPE_MISMATCH
;
196 if (!guid
|| !name
|| !name
[0] || !methods
) {
197 DEBUG(0,("Called with NULL pointer or empty name!\n"));
198 return NT_STATUS_INVALID_PARAMETER
;
201 test
= get_methods_by_name(extensions
, name
);
203 DEBUG(0,("GP extension module %s already registered!\n",
205 return NT_STATUS_OBJECT_NAME_COLLISION
;
208 entry
= talloc_zero(gpext_ctx
, struct gp_extension
);
209 NT_STATUS_HAVE_NO_MEMORY(entry
);
211 entry
->name
= talloc_strdup(gpext_ctx
, name
);
212 NT_STATUS_HAVE_NO_MEMORY(entry
->name
);
214 entry
->guid
= talloc_zero(gpext_ctx
, struct GUID
);
215 NT_STATUS_HAVE_NO_MEMORY(entry
->guid
);
216 status
= GUID_from_string(guid
, entry
->guid
);
217 NT_STATUS_NOT_OK_RETURN(status
);
219 entry
->methods
= methods
;
220 DLIST_ADD(extensions
, entry
);
222 DEBUG(2,("Successfully added GP extension '%s' %s\n",
223 name
, GUID_string2(gpext_ctx
, entry
->guid
)));
228 /****************************************************************
229 ****************************************************************/
231 static NTSTATUS
gp_extension_init_module(TALLOC_CTX
*mem_ctx
,
233 struct gp_extension
**gpext
)
236 struct gp_extension
*ext
= NULL
;
238 ext
= talloc_zero(mem_ctx
, struct gp_extension
);
239 NT_STATUS_HAVE_NO_MEMORY(gpext
);
241 ext
->methods
= get_methods_by_name(extensions
, name
);
244 status
= smb_probe_module(SAMBA_SUBSYSTEM_GPEXT
,
246 if (!NT_STATUS_IS_OK(status
)) {
250 ext
->methods
= get_methods_by_name(extensions
, name
);
252 return NT_STATUS_DLL_INIT_FAILED
;
261 /****************************************************************
262 ****************************************************************/
264 static bool add_gp_extension_reg_entry_to_array(TALLOC_CTX
*mem_ctx
,
265 struct gp_extension_reg_entry
*entry
,
266 struct gp_extension_reg_entry
**entries
,
269 *entries
= talloc_realloc(mem_ctx
, *entries
,
270 struct gp_extension_reg_entry
,
272 if (*entries
== NULL
) {
277 (*entries
)[*num
].value
= entry
->value
;
278 (*entries
)[*num
].data
= entry
->data
;
284 /****************************************************************
285 ****************************************************************/
287 static bool add_gp_extension_reg_info_entry_to_array(TALLOC_CTX
*mem_ctx
,
288 struct gp_extension_reg_info_entry
*entry
,
289 struct gp_extension_reg_info_entry
**entries
,
292 *entries
= talloc_realloc(mem_ctx
, *entries
,
293 struct gp_extension_reg_info_entry
,
295 if (*entries
== NULL
) {
300 (*entries
)[*num
].guid
= entry
->guid
;
301 (*entries
)[*num
].num_entries
= entry
->num_entries
;
302 (*entries
)[*num
].entries
= entry
->entries
;
308 /****************************************************************
309 ****************************************************************/
311 static NTSTATUS
gp_ext_info_add_reg(TALLOC_CTX
*mem_ctx
,
312 struct gp_extension_reg_info_entry
*entry
,
314 enum winreg_Type type
,
317 struct gp_extension_reg_entry
*reg_entry
= NULL
;
318 struct registry_value
*data
= NULL
;
320 reg_entry
= talloc_zero(mem_ctx
, struct gp_extension_reg_entry
);
321 NT_STATUS_HAVE_NO_MEMORY(reg_entry
);
323 data
= talloc_zero(mem_ctx
, struct registry_value
);
324 NT_STATUS_HAVE_NO_MEMORY(data
);
331 if (!push_reg_sz(mem_ctx
, &data
->data
, data_s
)) {
332 return NT_STATUS_NO_MEMORY
;
336 uint32_t v
= atoi(data_s
);
337 data
->data
= data_blob_talloc(mem_ctx
, NULL
, 4);
338 SIVAL(data
->data
.data
, 0, v
);
342 return NT_STATUS_NOT_SUPPORTED
;
345 reg_entry
->value
= value
;
346 reg_entry
->data
= data
;
348 if (!add_gp_extension_reg_entry_to_array(mem_ctx
, reg_entry
,
350 &entry
->num_entries
)) {
351 return NT_STATUS_NO_MEMORY
;
357 /****************************************************************
358 ****************************************************************/
360 static NTSTATUS
gp_ext_info_add_reg_table(TALLOC_CTX
*mem_ctx
,
362 struct gp_extension_reg_info_entry
*entry
,
363 struct gp_extension_reg_table
*table
)
366 const char *module_name
= NULL
;
369 module_name
= talloc_asprintf(mem_ctx
, "%s.%s", module
, shlib_ext());
370 NT_STATUS_HAVE_NO_MEMORY(module_name
);
372 status
= gp_ext_info_add_reg(mem_ctx
, entry
,
373 "DllName", REG_EXPAND_SZ
, module_name
);
374 NT_STATUS_NOT_OK_RETURN(status
);
376 for (i
=0; table
[i
].val
; i
++) {
377 status
= gp_ext_info_add_reg(mem_ctx
, entry
,
381 NT_STATUS_NOT_OK_RETURN(status
);
387 /****************************************************************
388 ****************************************************************/
390 NTSTATUS
gpext_info_add_entry(TALLOC_CTX
*mem_ctx
,
392 const char *ext_guid
,
393 struct gp_extension_reg_table
*table
,
394 struct gp_extension_reg_info
*info
)
397 struct gp_extension_reg_info_entry
*entry
= NULL
;
399 entry
= talloc_zero(mem_ctx
, struct gp_extension_reg_info_entry
);
400 NT_STATUS_HAVE_NO_MEMORY(entry
);
402 status
= GUID_from_string(ext_guid
, &entry
->guid
);
403 NT_STATUS_NOT_OK_RETURN(status
);
405 status
= gp_ext_info_add_reg_table(mem_ctx
, module
, entry
, table
);
406 NT_STATUS_NOT_OK_RETURN(status
);
408 if (!add_gp_extension_reg_info_entry_to_array(mem_ctx
, entry
,
410 &info
->num_entries
)) {
411 return NT_STATUS_NO_MEMORY
;
417 /****************************************************************
418 ****************************************************************/
420 static bool gp_extension_reg_info_verify_entry(struct gp_extension_reg_entry
*entry
)
424 for (i
=0; gpext_reg_vals
[i
].val
; i
++) {
426 if ((strequal(entry
->value
, gpext_reg_vals
[i
].val
)) &&
427 (entry
->data
->type
== gpext_reg_vals
[i
].type
)) {
435 /****************************************************************
436 ****************************************************************/
438 static bool gp_extension_reg_info_verify(struct gp_extension_reg_info_entry
*entry
)
442 for (i
=0; i
< entry
->num_entries
; i
++) {
443 if (!gp_extension_reg_info_verify_entry(&entry
->entries
[i
])) {
451 /****************************************************************
452 ****************************************************************/
454 static WERROR
gp_extension_store_reg_vals(TALLOC_CTX
*mem_ctx
,
455 struct registry_key
*key
,
456 struct gp_extension_reg_info_entry
*entry
)
458 WERROR werr
= WERR_OK
;
461 for (i
=0; i
< entry
->num_entries
; i
++) {
463 werr
= reg_setvalue(key
,
464 entry
->entries
[i
].value
,
465 entry
->entries
[i
].data
);
466 W_ERROR_NOT_OK_RETURN(werr
);
472 /****************************************************************
473 ****************************************************************/
475 static WERROR
gp_extension_store_reg_entry(TALLOC_CTX
*mem_ctx
,
476 struct gp_registry_context
*reg_ctx
,
477 struct gp_extension_reg_info_entry
*entry
)
480 struct registry_key
*key
= NULL
;
481 const char *subkeyname
= NULL
;
483 if (!gp_extension_reg_info_verify(entry
)) {
484 return WERR_INVALID_PARAMETER
;
487 subkeyname
= GUID_string2(mem_ctx
, &entry
->guid
);
488 W_ERROR_HAVE_NO_MEMORY(subkeyname
);
490 if (!strupper_m(discard_const_p(char, subkeyname
))) {
491 return WERR_INVALID_PARAMETER
;
494 werr
= gp_store_reg_subkey(mem_ctx
,
498 W_ERROR_NOT_OK_RETURN(werr
);
500 werr
= gp_extension_store_reg_vals(mem_ctx
,
503 W_ERROR_NOT_OK_RETURN(werr
);
508 /****************************************************************
509 ****************************************************************/
511 static WERROR
gp_extension_store_reg(TALLOC_CTX
*mem_ctx
,
512 struct gp_registry_context
*reg_ctx
,
513 struct gp_extension_reg_info
*info
)
515 WERROR werr
= WERR_OK
;
522 for (i
=0; i
< info
->num_entries
; i
++) {
523 werr
= gp_extension_store_reg_entry(mem_ctx
,
526 W_ERROR_NOT_OK_RETURN(werr
);
532 /****************************************************************
533 ****************************************************************/
535 static NTSTATUS
gp_glob_ext_list(TALLOC_CTX
*mem_ctx
,
536 const char ***ext_list
,
537 size_t *ext_list_len
)
540 struct dirent
*dirent
= NULL
;
542 dir
= opendir(modules_path(talloc_tos(),
543 SAMBA_SUBSYSTEM_GPEXT
));
545 return map_nt_error_from_unix_common(errno
);
548 while ((dirent
= readdir(dir
))) {
550 fstring name
; /* forgive me... */
553 if ((strequal(dirent
->d_name
, ".")) ||
554 (strequal(dirent
->d_name
, ".."))) {
558 p
= strrchr(dirent
->d_name
, '.');
561 return NT_STATUS_NO_MEMORY
;
564 if (!strcsequal(p
+1, shlib_ext())) {
565 DEBUG(10,("gp_glob_ext_list: not a *.so file: %s\n",
570 fstrcpy(name
, dirent
->d_name
);
571 name
[PTR_DIFF(p
, dirent
->d_name
)] = 0;
573 if (!add_string_to_array(mem_ctx
, name
, ext_list
,
576 return NT_STATUS_NO_MEMORY
;
585 /****************************************************************
586 ****************************************************************/
588 NTSTATUS
gpext_shutdown_gp_extensions(void)
590 struct gp_extension
*ext
= NULL
;
592 for (ext
= extensions
; ext
; ext
= ext
->next
) {
593 if (ext
->methods
&& ext
->methods
->shutdown
) {
594 ext
->methods
->shutdown();
601 /****************************************************************
602 ****************************************************************/
604 NTSTATUS
gpext_init_gp_extensions(TALLOC_CTX
*mem_ctx
)
609 const char **ext_array
= NULL
;
610 size_t ext_array_len
= 0;
611 struct gp_extension
*gpext
= NULL
;
612 struct gp_registry_context
*reg_ctx
= NULL
;
614 if (gpext_get_gp_extension_list()) {
618 status
= gp_glob_ext_list(mem_ctx
, &ext_array
, &ext_array_len
);
619 NT_STATUS_NOT_OK_RETURN(status
);
621 for (i
=0; i
<ext_array_len
; i
++) {
623 struct gp_extension_reg_info
*info
= NULL
;
625 status
= gp_extension_init_module(mem_ctx
, ext_array
[i
],
627 if (!NT_STATUS_IS_OK(status
)) {
631 if (gpext
->methods
->get_reg_config
) {
633 status
= gpext
->methods
->initialize(mem_ctx
);
634 if (!NT_STATUS_IS_OK(status
)) {
635 gpext
->methods
->shutdown();
639 status
= gpext
->methods
->get_reg_config(mem_ctx
,
641 if (!NT_STATUS_IS_OK(status
)) {
642 gpext
->methods
->shutdown();
647 struct security_token
*token
;
649 token
= registry_create_system_token(mem_ctx
);
650 NT_STATUS_HAVE_NO_MEMORY(token
);
652 werr
= gp_init_reg_ctx(mem_ctx
,
653 KEY_WINLOGON_GPEXT_PATH
,
657 if (!W_ERROR_IS_OK(werr
)) {
658 status
= werror_to_ntstatus(werr
);
659 gpext
->methods
->shutdown();
664 werr
= gp_extension_store_reg(mem_ctx
, reg_ctx
, info
);
665 if (!W_ERROR_IS_OK(werr
)) {
666 DEBUG(1,("gp_extension_store_reg failed: %s\n",
669 gpext
->methods
->shutdown();
670 status
= werror_to_ntstatus(werr
);
679 TALLOC_FREE(reg_ctx
);
684 /****************************************************************
685 ****************************************************************/
687 NTSTATUS
gpext_free_gp_extensions(void)
689 struct gp_extension
*ext
, *ext_next
= NULL
;
691 for (ext
= extensions
; ext
; ext
= ext_next
) {
692 ext_next
= ext
->next
;
693 DLIST_REMOVE(extensions
, ext
);
702 /****************************************************************
703 ****************************************************************/
705 void gpext_debug_header(int lvl
,
708 const struct GROUP_POLICY_OBJECT
*gpo
,
709 const char *extension_guid
,
710 const char *snapin_guid
)
712 char *flags_str
= NULL
;
714 DEBUG(lvl
,("%s\n", name
));
715 DEBUGADD(lvl
,("\tgpo: %s (%s)\n", gpo
->name
,
717 DEBUGADD(lvl
,("\tcse extension: %s (%s)\n", extension_guid
,
718 cse_gpo_guid_string_to_name(extension_guid
)));
719 DEBUGADD(lvl
,("\tgplink: %s\n", gpo
->link
));
720 DEBUGADD(lvl
,("\tsnapin: %s (%s)\n", snapin_guid
,
721 cse_snapin_gpo_guid_string_to_name(snapin_guid
)));
723 flags_str
= gpo_flag_str(NULL
, flags
);
724 DEBUGADD(lvl
,("\tflags: 0x%08x %s\n", flags
, flags_str
));
725 TALLOC_FREE(flags_str
);
728 /****************************************************************
729 ****************************************************************/
731 static NTSTATUS
gpext_check_gpo_for_gpext_presence(TALLOC_CTX
*mem_ctx
,
733 const struct GROUP_POLICY_OBJECT
*gpo
,
734 const struct GUID
*guid
,
735 bool *gpext_guid_present
)
737 struct GP_EXT
*gp_ext
= NULL
;
741 *gpext_guid_present
= false;
744 if (gpo
->link_type
== GP_LINK_LOCAL
) {
748 ok
= gpo_get_gp_ext_from_gpo(mem_ctx
, flags
, gpo
, &gp_ext
);
750 return NT_STATUS_INVALID_PARAMETER
;
753 if (gp_ext
== NULL
) {
757 for (i
= 0; i
< gp_ext
->num_exts
; i
++) {
761 status
= GUID_from_string(gp_ext
->extensions_guid
[i
], &guid2
);
762 if (!NT_STATUS_IS_OK(status
)) {
765 if (GUID_equal(guid
, &guid2
)) {
766 *gpext_guid_present
= true;
774 /****************************************************************
775 ****************************************************************/
777 NTSTATUS
gpext_process_extension(TALLOC_CTX
*mem_ctx
,
779 const struct security_token
*token
,
780 struct registry_key
*root_key
,
781 const struct GROUP_POLICY_OBJECT
*deleted_gpo_list
,
782 const struct GROUP_POLICY_OBJECT
*changed_gpo_list
,
783 const char *extension_guid_filter
)
786 struct gp_extension
*ext
= NULL
;
787 const struct GROUP_POLICY_OBJECT
*gpo
;
788 struct GUID extension_guid_filter_guid
;
790 status
= gpext_init_gp_extensions(mem_ctx
);
791 if (!NT_STATUS_IS_OK(status
)) {
792 DEBUG(1,("gpext_init_gp_extensions failed: %s\n",
797 if (extension_guid_filter
) {
798 status
= GUID_from_string(extension_guid_filter
,
799 &extension_guid_filter_guid
);
800 if (!NT_STATUS_IS_OK(status
)) {
805 for (ext
= extensions
; ext
; ext
= ext
->next
) {
807 struct GROUP_POLICY_OBJECT
*deleted_gpo_list_filtered
= NULL
;
808 struct GROUP_POLICY_OBJECT
*changed_gpo_list_filtered
= NULL
;
810 if (extension_guid_filter
) {
811 if (!GUID_equal(&extension_guid_filter_guid
, ext
->guid
)) {
816 for (gpo
= deleted_gpo_list
; gpo
; gpo
= gpo
->next
) {
818 bool is_present
= false;
820 status
= gpext_check_gpo_for_gpext_presence(mem_ctx
,
825 if (!NT_STATUS_IS_OK(status
)) {
830 struct GROUP_POLICY_OBJECT
*new_gpo
;
832 status
= gpo_copy(mem_ctx
, gpo
, &new_gpo
);
833 if (!NT_STATUS_IS_OK(status
)) {
837 DLIST_ADD(deleted_gpo_list_filtered
, new_gpo
);
841 for (gpo
= changed_gpo_list
; gpo
; gpo
= gpo
->next
) {
843 bool is_present
= false;
845 status
= gpext_check_gpo_for_gpext_presence(mem_ctx
,
850 if (!NT_STATUS_IS_OK(status
)) {
855 struct GROUP_POLICY_OBJECT
*new_gpo
;
857 status
= gpo_copy(mem_ctx
, gpo
, &new_gpo
);
858 if (!NT_STATUS_IS_OK(status
)) {
862 DLIST_ADD(changed_gpo_list_filtered
, new_gpo
);
866 status
= ext
->methods
->initialize(mem_ctx
);
867 NT_STATUS_NOT_OK_RETURN(status
);
869 status
= ext
->methods
->process_group_policy(mem_ctx
,
873 deleted_gpo_list_filtered
,
874 changed_gpo_list_filtered
);
875 if (!NT_STATUS_IS_OK(status
)) {
876 ext
->methods
->shutdown();