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