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/>.
22 static struct gp_extension
*extensions
= NULL
;
24 /****************************************************************
25 ****************************************************************/
27 struct gp_extension
*get_gp_extension_list(void)
32 /****************************************************************
33 ****************************************************************/
35 /* see http://support.microsoft.com/kb/216358/en-us/ for more info */
37 struct gp_extension_reg_table gpext_reg_vals
[] = {
38 { "DllName", REG_EXPAND_SZ
},
39 { "ProcessGroupPolicy", REG_SZ
},
40 { "NoMachinePolicy", REG_DWORD
},
41 { "NoUserPolicy", REG_DWORD
},
42 { "NoSlowLink", REG_DWORD
},
43 { "NoBackgroundPolicy", REG_DWORD
},
44 { "NoGPOListChanges", REG_DWORD
},
45 { "PerUserLocalSettings", REG_DWORD
},
46 { "RequiresSuccessfulRegistry", REG_DWORD
},
47 { "EnableAsynchronousProcessing", REG_DWORD
},
48 { "ExtensionDebugLevel", REG_DWORD
},
50 { "GenerateGroupPolicy", REG_SZ
}, /* not supported on w2k */
51 { "NotifyLinkTransition", REG_DWORD
},
52 { "ProcessGroupPolicyEx", REG_SZ
}, /* not supported on w2k */
53 { "ExtensionEventSource", REG_MULTI_SZ
}, /* not supported on w2k */
54 { "GenerateGroupPolicy", REG_SZ
},
55 { "MaxNoGPOListChangesInterval", REG_DWORD
},
59 /****************************************************************
60 ****************************************************************/
62 static struct gp_extension
*get_extension_by_name(struct gp_extension
*be
,
65 struct gp_extension
*b
;
67 for (b
= be
; b
; b
= b
->next
) {
68 if (strequal(b
->name
, name
)) {
76 /****************************************************************
77 ****************************************************************/
79 static struct gp_extension_methods
*get_methods_by_name(struct gp_extension
*be
,
82 struct gp_extension
*b
;
84 for (b
= be
; b
; b
= b
->next
) {
85 if (strequal(b
->name
, name
)) {
93 /****************************************************************
94 ****************************************************************/
96 NTSTATUS
unregister_gp_extension(const char *name
)
98 struct gp_extension
*ext
;
100 ext
= get_extension_by_name(extensions
, name
);
105 DLIST_REMOVE(extensions
, ext
);
108 DEBUG(2,("Successfully removed GP extension '%s'\n", name
));
113 /****************************************************************
114 ****************************************************************/
116 NTSTATUS
register_gp_extension(TALLOC_CTX
*gpext_ctx
,
120 struct gp_extension_methods
*methods
)
122 struct gp_extension_methods
*test
;
123 struct gp_extension
*entry
;
127 return NT_STATUS_INTERNAL_DB_ERROR
;
130 if ((version
!= SMB_GPEXT_INTERFACE_VERSION
)) {
131 DEBUG(0,("Failed to register gp extension.\n"
132 "The module was compiled against "
133 "SMB_GPEXT_INTERFACE_VERSION %d,\n"
134 "current SMB_GPEXT_INTERFACE_VERSION is %d.\n"
135 "Please recompile against the current "
136 "version of samba!\n",
137 version
, SMB_GPEXT_INTERFACE_VERSION
));
138 return NT_STATUS_OBJECT_TYPE_MISMATCH
;
141 if (!guid
|| !name
|| !name
[0] || !methods
) {
142 DEBUG(0,("Called with NULL pointer or empty name!\n"));
143 return NT_STATUS_INVALID_PARAMETER
;
146 test
= get_methods_by_name(extensions
, name
);
148 DEBUG(0,("GP extension module %s already registered!\n",
150 return NT_STATUS_OBJECT_NAME_COLLISION
;
153 entry
= TALLOC_ZERO_P(gpext_ctx
, struct gp_extension
);
154 NT_STATUS_HAVE_NO_MEMORY(entry
);
156 entry
->name
= talloc_strdup(gpext_ctx
, name
);
157 NT_STATUS_HAVE_NO_MEMORY(entry
->name
);
159 entry
->guid
= TALLOC_ZERO_P(gpext_ctx
, struct GUID
);
160 NT_STATUS_HAVE_NO_MEMORY(entry
->guid
);
161 status
= GUID_from_string(guid
, entry
->guid
);
162 NT_STATUS_NOT_OK_RETURN(status
);
164 entry
->methods
= methods
;
165 DLIST_ADD(extensions
, entry
);
167 DEBUG(2,("Successfully added GP extension '%s' %s\n",
168 name
, GUID_string2(gpext_ctx
, entry
->guid
)));
173 /****************************************************************
174 ****************************************************************/
176 static NTSTATUS
gp_extension_init_module(TALLOC_CTX
*mem_ctx
,
178 struct gp_extension
**gpext
)
181 struct gp_extension
*ext
= NULL
;
183 ext
= TALLOC_ZERO_P(mem_ctx
, struct gp_extension
);
184 NT_STATUS_HAVE_NO_MEMORY(gpext
);
186 ext
->methods
= get_methods_by_name(extensions
, name
);
189 status
= smb_probe_module(SAMBA_SUBSYSTEM_GPEXT
,
191 if (!NT_STATUS_IS_OK(status
)) {
195 ext
->methods
= get_methods_by_name(extensions
, name
);
197 return NT_STATUS_DLL_INIT_FAILED
;
206 /****************************************************************
207 ****************************************************************/
209 static bool add_gp_extension_reg_entry_to_array(TALLOC_CTX
*mem_ctx
,
210 struct gp_extension_reg_entry
*entry
,
211 struct gp_extension_reg_entry
**entries
,
214 *entries
= TALLOC_REALLOC_ARRAY(mem_ctx
, *entries
,
215 struct gp_extension_reg_entry
,
217 if (*entries
== NULL
) {
222 (*entries
)[*num
].value
= entry
->value
;
223 (*entries
)[*num
].data
= entry
->data
;
229 /****************************************************************
230 ****************************************************************/
232 static bool add_gp_extension_reg_info_entry_to_array(TALLOC_CTX
*mem_ctx
,
233 struct gp_extension_reg_info_entry
*entry
,
234 struct gp_extension_reg_info_entry
**entries
,
237 *entries
= TALLOC_REALLOC_ARRAY(mem_ctx
, *entries
,
238 struct gp_extension_reg_info_entry
,
240 if (*entries
== NULL
) {
245 (*entries
)[*num
].guid
= entry
->guid
;
246 (*entries
)[*num
].num_entries
= entry
->num_entries
;
247 (*entries
)[*num
].entries
= entry
->entries
;
253 /****************************************************************
254 ****************************************************************/
256 static NTSTATUS
gp_ext_info_add_reg(TALLOC_CTX
*mem_ctx
,
257 struct gp_extension_reg_info_entry
*entry
,
259 enum winreg_Type type
,
262 struct gp_extension_reg_entry
*reg_entry
= NULL
;
263 struct registry_value
*data
= NULL
;
265 reg_entry
= TALLOC_ZERO_P(mem_ctx
, struct gp_extension_reg_entry
);
266 NT_STATUS_HAVE_NO_MEMORY(reg_entry
);
268 data
= TALLOC_ZERO_P(mem_ctx
, struct registry_value
);
269 NT_STATUS_HAVE_NO_MEMORY(data
);
276 data
->v
.sz
.str
= talloc_strdup(mem_ctx
, data_s
);
277 NT_STATUS_HAVE_NO_MEMORY(data
->v
.sz
.str
);
278 data
->v
.sz
.len
= strlen(data_s
);
281 data
->v
.dword
= atoi(data_s
);
284 return NT_STATUS_NOT_SUPPORTED
;
287 reg_entry
->value
= value
;
288 reg_entry
->data
= data
;
290 if (!add_gp_extension_reg_entry_to_array(mem_ctx
, reg_entry
,
292 &entry
->num_entries
)) {
293 return NT_STATUS_NO_MEMORY
;
299 /****************************************************************
300 ****************************************************************/
302 static NTSTATUS
gp_ext_info_add_reg_table(TALLOC_CTX
*mem_ctx
,
304 struct gp_extension_reg_info_entry
*entry
,
305 struct gp_extension_reg_table
*table
)
308 const char *module_name
= NULL
;
311 module_name
= talloc_asprintf(mem_ctx
, "%s.%s", module
, shlib_ext());
312 NT_STATUS_HAVE_NO_MEMORY(module_name
);
314 status
= gp_ext_info_add_reg(mem_ctx
, entry
,
315 "DllName", REG_EXPAND_SZ
, module_name
);
316 NT_STATUS_NOT_OK_RETURN(status
);
318 for (i
=0; table
[i
].val
; i
++) {
319 status
= gp_ext_info_add_reg(mem_ctx
, entry
,
323 NT_STATUS_NOT_OK_RETURN(status
);
329 /****************************************************************
330 ****************************************************************/
332 NTSTATUS
gp_ext_info_add_entry(TALLOC_CTX
*mem_ctx
,
334 const char *ext_guid
,
335 struct gp_extension_reg_table
*table
,
336 struct gp_extension_reg_info
*info
)
339 struct gp_extension_reg_info_entry
*entry
= NULL
;
341 entry
= TALLOC_ZERO_P(mem_ctx
, struct gp_extension_reg_info_entry
);
342 NT_STATUS_HAVE_NO_MEMORY(entry
);
344 status
= GUID_from_string(ext_guid
, &entry
->guid
);
345 NT_STATUS_NOT_OK_RETURN(status
);
347 status
= gp_ext_info_add_reg_table(mem_ctx
, module
, entry
, table
);
348 NT_STATUS_NOT_OK_RETURN(status
);
350 if (!add_gp_extension_reg_info_entry_to_array(mem_ctx
, entry
,
352 &info
->num_entries
)) {
353 return NT_STATUS_NO_MEMORY
;
359 /****************************************************************
360 ****************************************************************/
362 static bool gp_extension_reg_info_verify_entry(struct gp_extension_reg_entry
*entry
)
366 for (i
=0; gpext_reg_vals
[i
].val
; i
++) {
368 if ((strequal(entry
->value
, gpext_reg_vals
[i
].val
)) &&
369 (entry
->data
->type
== gpext_reg_vals
[i
].type
)) {
377 /****************************************************************
378 ****************************************************************/
380 static bool gp_extension_reg_info_verify(struct gp_extension_reg_info_entry
*entry
)
384 for (i
=0; i
< entry
->num_entries
; i
++) {
385 if (!gp_extension_reg_info_verify_entry(&entry
->entries
[i
])) {
393 /****************************************************************
394 ****************************************************************/
396 static WERROR
gp_extension_store_reg_vals(TALLOC_CTX
*mem_ctx
,
397 struct registry_key
*key
,
398 struct gp_extension_reg_info_entry
*entry
)
400 WERROR werr
= WERR_OK
;
403 for (i
=0; i
< entry
->num_entries
; i
++) {
405 werr
= reg_setvalue(key
,
406 entry
->entries
[i
].value
,
407 entry
->entries
[i
].data
);
408 W_ERROR_NOT_OK_RETURN(werr
);
414 /****************************************************************
415 ****************************************************************/
417 static WERROR
gp_extension_store_reg_entry(TALLOC_CTX
*mem_ctx
,
418 struct gp_registry_context
*reg_ctx
,
419 struct gp_extension_reg_info_entry
*entry
)
422 struct registry_key
*key
= NULL
;
423 const char *subkeyname
= NULL
;
425 if (!gp_extension_reg_info_verify(entry
)) {
426 return WERR_INVALID_PARAM
;
429 subkeyname
= GUID_string2(mem_ctx
, &entry
->guid
);
430 W_ERROR_HAVE_NO_MEMORY(subkeyname
);
432 strupper_m(CONST_DISCARD(char *,subkeyname
));
434 werr
= gp_store_reg_subkey(mem_ctx
,
438 W_ERROR_NOT_OK_RETURN(werr
);
440 werr
= gp_extension_store_reg_vals(mem_ctx
,
443 W_ERROR_NOT_OK_RETURN(werr
);
448 /****************************************************************
449 ****************************************************************/
451 static WERROR
gp_extension_store_reg(TALLOC_CTX
*mem_ctx
,
452 struct gp_registry_context
*reg_ctx
,
453 struct gp_extension_reg_info
*info
)
455 WERROR werr
= WERR_OK
;
462 for (i
=0; i
< info
->num_entries
; i
++) {
463 werr
= gp_extension_store_reg_entry(mem_ctx
,
466 W_ERROR_NOT_OK_RETURN(werr
);
472 /****************************************************************
473 ****************************************************************/
475 static NTSTATUS
gp_glob_ext_list(TALLOC_CTX
*mem_ctx
,
476 const char ***ext_list
,
477 size_t *ext_list_len
)
479 SMB_STRUCT_DIR
*dir
= NULL
;
480 SMB_STRUCT_DIRENT
*dirent
= NULL
;
482 dir
= sys_opendir(modules_path(SAMBA_SUBSYSTEM_GPEXT
));
484 return map_nt_error_from_unix(errno
);
487 while ((dirent
= sys_readdir(dir
))) {
489 fstring name
; /* forgive me... */
492 if ((strequal(dirent
->d_name
, ".")) ||
493 (strequal(dirent
->d_name
, ".."))) {
497 p
= strrchr(dirent
->d_name
, '.');
500 return NT_STATUS_NO_MEMORY
;
503 if (!strcsequal(p
+1, shlib_ext())) {
504 DEBUG(10,("gp_glob_ext_list: not a *.so file: %s\n",
509 fstrcpy(name
, dirent
->d_name
);
510 name
[PTR_DIFF(p
, dirent
->d_name
)] = 0;
512 if (!add_string_to_array(mem_ctx
, name
, ext_list
,
513 (int *)ext_list_len
)) {
515 return NT_STATUS_NO_MEMORY
;
524 /****************************************************************
525 ****************************************************************/
527 NTSTATUS
shutdown_gp_extensions(void)
529 struct gp_extension
*ext
= NULL
;
531 for (ext
= extensions
; ext
; ext
= ext
->next
) {
532 if (ext
->methods
&& ext
->methods
->shutdown
) {
533 ext
->methods
->shutdown();
540 /****************************************************************
541 ****************************************************************/
543 NTSTATUS
init_gp_extensions(TALLOC_CTX
*mem_ctx
)
548 const char **ext_array
= NULL
;
549 size_t ext_array_len
= 0;
550 struct gp_extension
*gpext
= NULL
;
551 struct gp_registry_context
*reg_ctx
= NULL
;
553 if (get_gp_extension_list()) {
557 status
= gp_glob_ext_list(mem_ctx
, &ext_array
, &ext_array_len
);
558 NT_STATUS_NOT_OK_RETURN(status
);
560 for (i
=0; i
<ext_array_len
; i
++) {
562 struct gp_extension_reg_info
*info
= NULL
;
564 status
= gp_extension_init_module(mem_ctx
, ext_array
[i
],
566 if (!NT_STATUS_IS_OK(status
)) {
570 if (gpext
->methods
->get_reg_config
) {
572 status
= gpext
->methods
->initialize(mem_ctx
);
573 if (!NT_STATUS_IS_OK(status
)) {
574 gpext
->methods
->shutdown();
578 status
= gpext
->methods
->get_reg_config(mem_ctx
,
580 if (!NT_STATUS_IS_OK(status
)) {
581 gpext
->methods
->shutdown();
586 struct nt_user_token
*token
;
588 token
= registry_create_system_token(mem_ctx
);
589 NT_STATUS_HAVE_NO_MEMORY(token
);
591 werr
= gp_init_reg_ctx(mem_ctx
,
592 KEY_WINLOGON_GPEXT_PATH
,
596 if (!W_ERROR_IS_OK(werr
)) {
597 status
= werror_to_ntstatus(werr
);
598 gpext
->methods
->shutdown();
603 werr
= gp_extension_store_reg(mem_ctx
, reg_ctx
, info
);
604 if (!W_ERROR_IS_OK(werr
)) {
605 DEBUG(1,("gp_extension_store_reg failed: %s\n",
608 gpext
->methods
->shutdown();
609 status
= werror_to_ntstatus(werr
);
618 TALLOC_FREE(reg_ctx
);
623 /****************************************************************
624 ****************************************************************/
626 NTSTATUS
free_gp_extensions(void)
628 struct gp_extension
*ext
, *ext_next
= NULL
;
630 for (ext
= extensions
; ext
; ext
= ext_next
) {
631 ext_next
= ext
->next
;
632 DLIST_REMOVE(extensions
, ext
);
641 /****************************************************************
642 ****************************************************************/
644 void debug_gpext_header(int lvl
,
647 struct GROUP_POLICY_OBJECT
*gpo
,
648 const char *extension_guid
,
649 const char *snapin_guid
)
651 char *flags_str
= NULL
;
653 DEBUG(lvl
,("%s\n", name
));
654 DEBUGADD(lvl
,("\tgpo: %s (%s)\n", gpo
->name
,
656 DEBUGADD(lvl
,("\tcse extension: %s (%s)\n", extension_guid
,
657 cse_gpo_guid_string_to_name(extension_guid
)));
658 DEBUGADD(lvl
,("\tgplink: %s\n", gpo
->link
));
659 DEBUGADD(lvl
,("\tsnapin: %s (%s)\n", snapin_guid
,
660 cse_snapin_gpo_guid_string_to_name(snapin_guid
)));
662 flags_str
= gpo_flag_str(flags
);
663 DEBUGADD(lvl
,("\tflags: 0x%08x %s\n", flags
, flags_str
));
664 SAFE_FREE(flags_str
);
667 NTSTATUS
process_gpo_list_with_extension(ADS_STRUCT
*ads
,
670 const struct nt_user_token
*token
,
671 struct GROUP_POLICY_OBJECT
*gpo_list
,
672 const char *extension_guid
,
673 const char *snapin_guid
)
678 /****************************************************************
679 ****************************************************************/
681 NTSTATUS
gpext_process_extension(ADS_STRUCT
*ads
,
684 const struct nt_user_token
*token
,
685 struct registry_key
*root_key
,
686 struct GROUP_POLICY_OBJECT
*gpo
,
687 const char *extension_guid
,
688 const char *snapin_guid
)
691 struct gp_extension
*ext
= NULL
;
693 bool cse_found
= false;
695 status
= init_gp_extensions(mem_ctx
);
696 if (!NT_STATUS_IS_OK(status
)) {
697 DEBUG(1,("init_gp_extensions failed: %s\n",
702 status
= GUID_from_string(extension_guid
, &guid
);
703 if (!NT_STATUS_IS_OK(status
)) {
707 for (ext
= extensions
; ext
; ext
= ext
->next
) {
709 if (GUID_equal(ext
->guid
, &guid
)) {
719 status
= ext
->methods
->initialize(mem_ctx
);
720 NT_STATUS_NOT_OK_RETURN(status
);
722 status
= ext
->methods
->process_group_policy(ads
,
730 if (!NT_STATUS_IS_OK(status
)) {
731 ext
->methods
->shutdown();
737 if (flags
& GPO_INFO_FLAG_VERBOSE
) {
738 DEBUG(0,("process_extension: no extension available for:\n"));
739 DEBUGADD(0,("%s (%s) (snapin: %s)\n",
741 cse_gpo_guid_string_to_name(extension_guid
),