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 #if _SAMBA_BUILD_ == 3
27 #include "libgpo/gpo_proto.h"
29 #include "registry/reg_api.h"
32 static struct gp_extension
*extensions
= NULL
;
34 /****************************************************************
35 ****************************************************************/
37 struct gp_extension
*get_gp_extension_list(void)
42 /****************************************************************
43 ****************************************************************/
45 /* see http://support.microsoft.com/kb/216358/en-us/ for more info */
47 struct gp_extension_reg_table gpext_reg_vals
[] = {
48 { "DllName", REG_EXPAND_SZ
},
49 { "ProcessGroupPolicy", REG_SZ
},
50 { "NoMachinePolicy", REG_DWORD
},
51 { "NoUserPolicy", REG_DWORD
},
52 { "NoSlowLink", REG_DWORD
},
53 { "NoBackgroundPolicy", REG_DWORD
},
54 { "NoGPOListChanges", REG_DWORD
},
55 { "PerUserLocalSettings", REG_DWORD
},
56 { "RequiresSuccessfulRegistry", REG_DWORD
},
57 { "EnableAsynchronousProcessing", REG_DWORD
},
58 { "ExtensionDebugLevel", REG_DWORD
},
60 { "GenerateGroupPolicy", REG_SZ
}, /* not supported on w2k */
61 { "NotifyLinkTransition", REG_DWORD
},
62 { "ProcessGroupPolicyEx", REG_SZ
}, /* not supported on w2k */
63 { "ExtensionEventSource", REG_MULTI_SZ
}, /* not supported on w2k */
64 { "GenerateGroupPolicy", REG_SZ
},
65 { "MaxNoGPOListChangesInterval", REG_DWORD
},
69 /****************************************************************
70 ****************************************************************/
72 static struct gp_extension
*get_extension_by_name(struct gp_extension
*be
,
75 struct gp_extension
*b
;
77 for (b
= be
; b
; b
= b
->next
) {
78 if (strequal(b
->name
, name
)) {
86 /****************************************************************
87 ****************************************************************/
89 static struct gp_extension_methods
*get_methods_by_name(struct gp_extension
*be
,
92 struct gp_extension
*b
;
94 for (b
= be
; b
; b
= b
->next
) {
95 if (strequal(b
->name
, name
)) {
103 /****************************************************************
104 ****************************************************************/
106 NTSTATUS
unregister_gp_extension(const char *name
)
108 struct gp_extension
*ext
;
110 ext
= get_extension_by_name(extensions
, name
);
115 DLIST_REMOVE(extensions
, ext
);
118 DEBUG(2,("Successfully removed GP extension '%s'\n", name
));
123 /****************************************************************
124 ****************************************************************/
126 NTSTATUS
register_gp_extension(TALLOC_CTX
*gpext_ctx
,
130 struct gp_extension_methods
*methods
)
132 struct gp_extension_methods
*test
;
133 struct gp_extension
*entry
;
137 return NT_STATUS_INTERNAL_DB_ERROR
;
140 if ((version
!= SMB_GPEXT_INTERFACE_VERSION
)) {
141 DEBUG(0,("Failed to register gp extension.\n"
142 "The module was compiled against "
143 "SMB_GPEXT_INTERFACE_VERSION %d,\n"
144 "current SMB_GPEXT_INTERFACE_VERSION is %d.\n"
145 "Please recompile against the current "
146 "version of samba!\n",
147 version
, SMB_GPEXT_INTERFACE_VERSION
));
148 return NT_STATUS_OBJECT_TYPE_MISMATCH
;
151 if (!guid
|| !name
|| !name
[0] || !methods
) {
152 DEBUG(0,("Called with NULL pointer or empty name!\n"));
153 return NT_STATUS_INVALID_PARAMETER
;
156 test
= get_methods_by_name(extensions
, name
);
158 DEBUG(0,("GP extension module %s already registered!\n",
160 return NT_STATUS_OBJECT_NAME_COLLISION
;
163 entry
= talloc_zero(gpext_ctx
, struct gp_extension
);
164 NT_STATUS_HAVE_NO_MEMORY(entry
);
166 entry
->name
= talloc_strdup(gpext_ctx
, name
);
167 NT_STATUS_HAVE_NO_MEMORY(entry
->name
);
169 entry
->guid
= talloc_zero(gpext_ctx
, struct GUID
);
170 NT_STATUS_HAVE_NO_MEMORY(entry
->guid
);
171 status
= GUID_from_string(guid
, entry
->guid
);
172 NT_STATUS_NOT_OK_RETURN(status
);
174 entry
->methods
= methods
;
175 DLIST_ADD(extensions
, entry
);
177 DEBUG(2,("Successfully added GP extension '%s' %s\n",
178 name
, GUID_string2(gpext_ctx
, entry
->guid
)));
183 /****************************************************************
184 ****************************************************************/
186 static NTSTATUS
gp_extension_init_module(TALLOC_CTX
*mem_ctx
,
188 struct gp_extension
**gpext
)
191 struct gp_extension
*ext
= NULL
;
193 ext
= talloc_zero(mem_ctx
, struct gp_extension
);
194 NT_STATUS_HAVE_NO_MEMORY(gpext
);
196 ext
->methods
= get_methods_by_name(extensions
, name
);
199 status
= smb_probe_module(SAMBA_SUBSYSTEM_GPEXT
,
201 if (!NT_STATUS_IS_OK(status
)) {
205 ext
->methods
= get_methods_by_name(extensions
, name
);
207 return NT_STATUS_DLL_INIT_FAILED
;
216 /****************************************************************
217 ****************************************************************/
219 static bool add_gp_extension_reg_entry_to_array(TALLOC_CTX
*mem_ctx
,
220 struct gp_extension_reg_entry
*entry
,
221 struct gp_extension_reg_entry
**entries
,
224 *entries
= talloc_realloc(mem_ctx
, *entries
,
225 struct gp_extension_reg_entry
,
227 if (*entries
== NULL
) {
232 (*entries
)[*num
].value
= entry
->value
;
233 (*entries
)[*num
].data
= entry
->data
;
239 /****************************************************************
240 ****************************************************************/
242 static bool add_gp_extension_reg_info_entry_to_array(TALLOC_CTX
*mem_ctx
,
243 struct gp_extension_reg_info_entry
*entry
,
244 struct gp_extension_reg_info_entry
**entries
,
247 *entries
= talloc_realloc(mem_ctx
, *entries
,
248 struct gp_extension_reg_info_entry
,
250 if (*entries
== NULL
) {
255 (*entries
)[*num
].guid
= entry
->guid
;
256 (*entries
)[*num
].num_entries
= entry
->num_entries
;
257 (*entries
)[*num
].entries
= entry
->entries
;
263 /****************************************************************
264 ****************************************************************/
266 static NTSTATUS
gp_ext_info_add_reg(TALLOC_CTX
*mem_ctx
,
267 struct gp_extension_reg_info_entry
*entry
,
269 enum winreg_Type type
,
272 struct gp_extension_reg_entry
*reg_entry
= NULL
;
273 struct registry_value
*data
= NULL
;
275 reg_entry
= talloc_zero(mem_ctx
, struct gp_extension_reg_entry
);
276 NT_STATUS_HAVE_NO_MEMORY(reg_entry
);
278 data
= talloc_zero(mem_ctx
, struct registry_value
);
279 NT_STATUS_HAVE_NO_MEMORY(data
);
286 if (!push_reg_sz(mem_ctx
, &data
->data
, data_s
)) {
287 return NT_STATUS_NO_MEMORY
;
291 uint32_t v
= atoi(data_s
);
292 data
->data
= data_blob_talloc(mem_ctx
, NULL
, 4);
293 SIVAL(data
->data
.data
, 0, v
);
297 return NT_STATUS_NOT_SUPPORTED
;
300 reg_entry
->value
= value
;
301 reg_entry
->data
= data
;
303 if (!add_gp_extension_reg_entry_to_array(mem_ctx
, reg_entry
,
305 &entry
->num_entries
)) {
306 return NT_STATUS_NO_MEMORY
;
312 /****************************************************************
313 ****************************************************************/
315 static NTSTATUS
gp_ext_info_add_reg_table(TALLOC_CTX
*mem_ctx
,
317 struct gp_extension_reg_info_entry
*entry
,
318 struct gp_extension_reg_table
*table
)
321 const char *module_name
= NULL
;
324 module_name
= talloc_asprintf(mem_ctx
, "%s.%s", module
, shlib_ext());
325 NT_STATUS_HAVE_NO_MEMORY(module_name
);
327 status
= gp_ext_info_add_reg(mem_ctx
, entry
,
328 "DllName", REG_EXPAND_SZ
, module_name
);
329 NT_STATUS_NOT_OK_RETURN(status
);
331 for (i
=0; table
[i
].val
; i
++) {
332 status
= gp_ext_info_add_reg(mem_ctx
, entry
,
336 NT_STATUS_NOT_OK_RETURN(status
);
342 /****************************************************************
343 ****************************************************************/
345 NTSTATUS
gp_ext_info_add_entry(TALLOC_CTX
*mem_ctx
,
347 const char *ext_guid
,
348 struct gp_extension_reg_table
*table
,
349 struct gp_extension_reg_info
*info
)
352 struct gp_extension_reg_info_entry
*entry
= NULL
;
354 entry
= TALLOC_ZERO_P(mem_ctx
, struct gp_extension_reg_info_entry
);
355 NT_STATUS_HAVE_NO_MEMORY(entry
);
357 status
= GUID_from_string(ext_guid
, &entry
->guid
);
358 NT_STATUS_NOT_OK_RETURN(status
);
360 status
= gp_ext_info_add_reg_table(mem_ctx
, module
, entry
, table
);
361 NT_STATUS_NOT_OK_RETURN(status
);
363 if (!add_gp_extension_reg_info_entry_to_array(mem_ctx
, entry
,
365 &info
->num_entries
)) {
366 return NT_STATUS_NO_MEMORY
;
372 /****************************************************************
373 ****************************************************************/
375 static bool gp_extension_reg_info_verify_entry(struct gp_extension_reg_entry
*entry
)
379 for (i
=0; gpext_reg_vals
[i
].val
; i
++) {
381 if ((strequal(entry
->value
, gpext_reg_vals
[i
].val
)) &&
382 (entry
->data
->type
== gpext_reg_vals
[i
].type
)) {
390 /****************************************************************
391 ****************************************************************/
393 static bool gp_extension_reg_info_verify(struct gp_extension_reg_info_entry
*entry
)
397 for (i
=0; i
< entry
->num_entries
; i
++) {
398 if (!gp_extension_reg_info_verify_entry(&entry
->entries
[i
])) {
406 /****************************************************************
407 ****************************************************************/
409 static WERROR
gp_extension_store_reg_vals(TALLOC_CTX
*mem_ctx
,
410 struct registry_key
*key
,
411 struct gp_extension_reg_info_entry
*entry
)
413 WERROR werr
= WERR_OK
;
416 for (i
=0; i
< entry
->num_entries
; i
++) {
418 werr
= reg_setvalue(key
,
419 entry
->entries
[i
].value
,
420 entry
->entries
[i
].data
);
421 W_ERROR_NOT_OK_RETURN(werr
);
427 /****************************************************************
428 ****************************************************************/
430 static WERROR
gp_extension_store_reg_entry(TALLOC_CTX
*mem_ctx
,
431 struct gp_registry_context
*reg_ctx
,
432 struct gp_extension_reg_info_entry
*entry
)
435 struct registry_key
*key
= NULL
;
436 const char *subkeyname
= NULL
;
438 if (!gp_extension_reg_info_verify(entry
)) {
439 return WERR_INVALID_PARAM
;
442 subkeyname
= GUID_string2(mem_ctx
, &entry
->guid
);
443 W_ERROR_HAVE_NO_MEMORY(subkeyname
);
445 strupper_m(discard_const_p(char, subkeyname
));
447 werr
= gp_store_reg_subkey(mem_ctx
,
451 W_ERROR_NOT_OK_RETURN(werr
);
453 werr
= gp_extension_store_reg_vals(mem_ctx
,
456 W_ERROR_NOT_OK_RETURN(werr
);
461 /****************************************************************
462 ****************************************************************/
464 static WERROR
gp_extension_store_reg(TALLOC_CTX
*mem_ctx
,
465 struct gp_registry_context
*reg_ctx
,
466 struct gp_extension_reg_info
*info
)
468 WERROR werr
= WERR_OK
;
475 for (i
=0; i
< info
->num_entries
; i
++) {
476 werr
= gp_extension_store_reg_entry(mem_ctx
,
479 W_ERROR_NOT_OK_RETURN(werr
);
485 /****************************************************************
486 ****************************************************************/
488 static NTSTATUS
gp_glob_ext_list(TALLOC_CTX
*mem_ctx
,
489 const char ***ext_list
,
490 size_t *ext_list_len
)
492 SMB_STRUCT_DIR
*dir
= NULL
;
493 SMB_STRUCT_DIRENT
*dirent
= NULL
;
495 dir
= sys_opendir(modules_path(SAMBA_SUBSYSTEM_GPEXT
));
497 return map_nt_error_from_unix(errno
);
500 while ((dirent
= sys_readdir(dir
))) {
502 fstring name
; /* forgive me... */
505 if ((strequal(dirent
->d_name
, ".")) ||
506 (strequal(dirent
->d_name
, ".."))) {
510 p
= strrchr(dirent
->d_name
, '.');
513 return NT_STATUS_NO_MEMORY
;
516 if (!strcsequal(p
+1, shlib_ext())) {
517 DEBUG(10,("gp_glob_ext_list: not a *.so file: %s\n",
522 fstrcpy(name
, dirent
->d_name
);
523 name
[PTR_DIFF(p
, dirent
->d_name
)] = 0;
525 if (!add_string_to_array(mem_ctx
, name
, ext_list
,
526 (int *)ext_list_len
)) {
528 return NT_STATUS_NO_MEMORY
;
537 /****************************************************************
538 ****************************************************************/
540 NTSTATUS
shutdown_gp_extensions(void)
542 struct gp_extension
*ext
= NULL
;
544 for (ext
= extensions
; ext
; ext
= ext
->next
) {
545 if (ext
->methods
&& ext
->methods
->shutdown
) {
546 ext
->methods
->shutdown();
553 /****************************************************************
554 ****************************************************************/
556 NTSTATUS
init_gp_extensions(TALLOC_CTX
*mem_ctx
)
561 const char **ext_array
= NULL
;
562 size_t ext_array_len
= 0;
563 struct gp_extension
*gpext
= NULL
;
564 struct gp_registry_context
*reg_ctx
= NULL
;
566 if (get_gp_extension_list()) {
570 status
= gp_glob_ext_list(mem_ctx
, &ext_array
, &ext_array_len
);
571 NT_STATUS_NOT_OK_RETURN(status
);
573 for (i
=0; i
<ext_array_len
; i
++) {
575 struct gp_extension_reg_info
*info
= NULL
;
577 status
= gp_extension_init_module(mem_ctx
, ext_array
[i
],
579 if (!NT_STATUS_IS_OK(status
)) {
583 if (gpext
->methods
->get_reg_config
) {
585 status
= gpext
->methods
->initialize(mem_ctx
);
586 if (!NT_STATUS_IS_OK(status
)) {
587 gpext
->methods
->shutdown();
591 status
= gpext
->methods
->get_reg_config(mem_ctx
,
593 if (!NT_STATUS_IS_OK(status
)) {
594 gpext
->methods
->shutdown();
599 struct security_token
*token
;
601 token
= registry_create_system_token(mem_ctx
);
602 NT_STATUS_HAVE_NO_MEMORY(token
);
604 werr
= gp_init_reg_ctx(mem_ctx
,
605 KEY_WINLOGON_GPEXT_PATH
,
609 if (!W_ERROR_IS_OK(werr
)) {
610 status
= werror_to_ntstatus(werr
);
611 gpext
->methods
->shutdown();
616 werr
= gp_extension_store_reg(mem_ctx
, reg_ctx
, info
);
617 if (!W_ERROR_IS_OK(werr
)) {
618 DEBUG(1,("gp_extension_store_reg failed: %s\n",
621 gpext
->methods
->shutdown();
622 status
= werror_to_ntstatus(werr
);
631 TALLOC_FREE(reg_ctx
);
636 /****************************************************************
637 ****************************************************************/
639 NTSTATUS
free_gp_extensions(void)
641 struct gp_extension
*ext
, *ext_next
= NULL
;
643 for (ext
= extensions
; ext
; ext
= ext_next
) {
644 ext_next
= ext
->next
;
645 DLIST_REMOVE(extensions
, ext
);
654 /****************************************************************
655 ****************************************************************/
657 void debug_gpext_header(int lvl
,
660 struct GROUP_POLICY_OBJECT
*gpo
,
661 const char *extension_guid
,
662 const char *snapin_guid
)
664 char *flags_str
= NULL
;
666 DEBUG(lvl
,("%s\n", name
));
667 DEBUGADD(lvl
,("\tgpo: %s (%s)\n", gpo
->name
,
669 DEBUGADD(lvl
,("\tcse extension: %s (%s)\n", extension_guid
,
670 cse_gpo_guid_string_to_name(extension_guid
)));
671 DEBUGADD(lvl
,("\tgplink: %s\n", gpo
->link
));
672 DEBUGADD(lvl
,("\tsnapin: %s (%s)\n", snapin_guid
,
673 cse_snapin_gpo_guid_string_to_name(snapin_guid
)));
675 flags_str
= gpo_flag_str(NULL
, flags
);
676 DEBUGADD(lvl
,("\tflags: 0x%08x %s\n", flags
, flags_str
));
677 TALLOC_FREE(flags_str
);
680 NTSTATUS
process_gpo_list_with_extension(ADS_STRUCT
*ads
,
683 const struct security_token
*token
,
684 struct GROUP_POLICY_OBJECT
*gpo_list
,
685 const char *extension_guid
,
686 const char *snapin_guid
)
691 /****************************************************************
692 ****************************************************************/
694 NTSTATUS
gpext_process_extension(ADS_STRUCT
*ads
,
697 const struct security_token
*token
,
698 struct registry_key
*root_key
,
699 struct GROUP_POLICY_OBJECT
*gpo
,
700 const char *extension_guid
,
701 const char *snapin_guid
)
704 struct gp_extension
*ext
= NULL
;
706 bool cse_found
= false;
708 status
= init_gp_extensions(mem_ctx
);
709 if (!NT_STATUS_IS_OK(status
)) {
710 DEBUG(1,("init_gp_extensions failed: %s\n",
715 status
= GUID_from_string(extension_guid
, &guid
);
716 if (!NT_STATUS_IS_OK(status
)) {
720 for (ext
= extensions
; ext
; ext
= ext
->next
) {
722 if (GUID_equal(ext
->guid
, &guid
)) {
732 status
= ext
->methods
->initialize(mem_ctx
);
733 NT_STATUS_NOT_OK_RETURN(status
);
735 status
= ext
->methods
->process_group_policy(ads
,
743 if (!NT_STATUS_IS_OK(status
)) {
744 ext
->methods
->shutdown();
750 if (flags
& GPO_INFO_FLAG_VERBOSE
) {
751 DEBUG(0,("process_extension: no extension available for:\n"));
752 DEBUGADD(0,("%s (%s) (snapin: %s)\n",
754 cse_gpo_guid_string_to_name(extension_guid
),