189dc44ceSjose borrego /*
289dc44ceSjose borrego  * CDDL HEADER START
389dc44ceSjose borrego  *
489dc44ceSjose borrego  * The contents of this file are subject to the terms of the
589dc44ceSjose borrego  * Common Development and Distribution License (the "License").
689dc44ceSjose borrego  * You may not use this file except in compliance with the License.
789dc44ceSjose borrego  *
889dc44ceSjose borrego  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
989dc44ceSjose borrego  * or http://www.opensolaris.org/os/licensing.
1089dc44ceSjose borrego  * See the License for the specific language governing permissions
1189dc44ceSjose borrego  * and limitations under the License.
1289dc44ceSjose borrego  *
1389dc44ceSjose borrego  * When distributing Covered Code, include this CDDL HEADER in each
1489dc44ceSjose borrego  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1589dc44ceSjose borrego  * If applicable, add the following below this CDDL HEADER, with the
1689dc44ceSjose borrego  * fields enclosed by brackets "[]" replaced with your own identifying
1789dc44ceSjose borrego  * information: Portions Copyright [yyyy] [name of copyright owner]
1889dc44ceSjose borrego  *
1989dc44ceSjose borrego  * CDDL HEADER END
2089dc44ceSjose borrego  */
2189dc44ceSjose borrego /*
2289dc44ceSjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2389dc44ceSjose borrego  * Use is subject to license terms.
2489dc44ceSjose borrego  */
2589dc44ceSjose borrego 
2689dc44ceSjose borrego /*
2789dc44ceSjose borrego  * Windows Registry RPC (WINREG) server-side interface.
2889dc44ceSjose borrego  *
297f667e74Sjose borrego  * The registry is a database with a hierarchical structure similar to
307f667e74Sjose borrego  * a file system, with keys in place of directories and values in place
317f667e74Sjose borrego  * of files.  The top level keys are known as root keys and each key can
327f667e74Sjose borrego  * contain subkeys and values.  As with directories and sub-directories,
337f667e74Sjose borrego  * the terms key and subkey are used interchangeably.  Values, analogous
347f667e74Sjose borrego  * to files, contain data.
3589dc44ceSjose borrego  *
367f667e74Sjose borrego  * A specific subkey can be identifies by its fully qualified name (FQN),
377f667e74Sjose borrego  * which is analogous to a file system path.  In the registry, the key
387f667e74Sjose borrego  * separator is the '\' character, which is reserved and cannot appear
397f667e74Sjose borrego  * in key or value names.  Registry names are case-insensitive.
407f667e74Sjose borrego  *
417f667e74Sjose borrego  * For example:  HKEY_LOCAL_MACHINE\System\CurrentControlSet
427f667e74Sjose borrego  *
43b1352070SAlan Wright  * The HKEY_LOCAL_MACHINE root key contains a subkey called System, and
447f667e74Sjose borrego  * System contains a subkey called CurrentControlSet.
457f667e74Sjose borrego  *
467f667e74Sjose borrego  * The WINREG RPC interface returns Win32 error codes.
4789dc44ceSjose borrego  */
4889dc44ceSjose borrego 
4989dc44ceSjose borrego #include <sys/utsname.h>
5089dc44ceSjose borrego #include <strings.h>
5189dc44ceSjose borrego 
5289dc44ceSjose borrego #include <smbsrv/libsmb.h>
5389dc44ceSjose borrego #include <smbsrv/ntstatus.h>
5489dc44ceSjose borrego #include <smbsrv/nterror.h>
5589dc44ceSjose borrego #include <smbsrv/nmpipes.h>
5689dc44ceSjose borrego #include <smbsrv/libmlsvc.h>
5789dc44ceSjose borrego #include <smbsrv/ndl/winreg.ndl>
5889dc44ceSjose borrego 
5989dc44ceSjose borrego /*
6089dc44ceSjose borrego  * List of supported registry keys (case-insensitive).
6189dc44ceSjose borrego  */
6289dc44ceSjose borrego static char *winreg_keys[] = {
63b1352070SAlan Wright 	"HKLM",
64b1352070SAlan Wright 	"HKU",
65b1352070SAlan Wright 	"HKLM\\SOFTWARE",
66b1352070SAlan Wright 	"HKLM\\SYSTEM",
67e3f2c991SKeyur Desai 	"Application",
68e3f2c991SKeyur Desai 	"Security",
69b1352070SAlan Wright 	"System",
70b1352070SAlan Wright 	"CurrentControlSet",
7189dc44ceSjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog",
727f667e74Sjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog\\Application",
737f667e74Sjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog\\Security",
7489dc44ceSjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog\\System",
7589dc44ceSjose borrego 	"System\\CurrentControlSet\\Control\\ProductOptions",
76b1352070SAlan Wright 	"SOFTWARE",
7789dc44ceSjose borrego 	"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
7889dc44ceSjose borrego };
7989dc44ceSjose borrego 
8089dc44ceSjose borrego typedef struct winreg_subkey {
8189dc44ceSjose borrego 	list_node_t sk_lnd;
8289dc44ceSjose borrego 	ndr_hdid_t sk_handle;
8389dc44ceSjose borrego 	char sk_name[MAXPATHLEN];
8489dc44ceSjose borrego 	boolean_t sk_predefined;
8589dc44ceSjose borrego } winreg_subkey_t;
8689dc44ceSjose borrego 
8789dc44ceSjose borrego typedef struct winreg_keylist {
8889dc44ceSjose borrego 	list_t kl_list;
8989dc44ceSjose borrego 	int kl_count;
9089dc44ceSjose borrego } winreg_keylist_t;
9189dc44ceSjose borrego 
9289dc44ceSjose borrego static winreg_keylist_t winreg_keylist;
9389dc44ceSjose borrego 
9489dc44ceSjose borrego static boolean_t winreg_key_has_subkey(const char *);
957f667e74Sjose borrego static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t);
9689dc44ceSjose borrego static char *winreg_lookup_value(const char *);
9789dc44ceSjose borrego 
987f667e74Sjose borrego static int winreg_s_OpenHKCR(void *, ndr_xa_t *);
997f667e74Sjose borrego static int winreg_s_OpenHKCU(void *, ndr_xa_t *);
10089dc44ceSjose borrego static int winreg_s_OpenHKLM(void *, ndr_xa_t *);
1017f667e74Sjose borrego static int winreg_s_OpenHKPD(void *, ndr_xa_t *);
1027f667e74Sjose borrego static int winreg_s_OpenHKU(void *, ndr_xa_t *);
1037f667e74Sjose borrego static int winreg_s_OpenHKCC(void *, ndr_xa_t *);
1047f667e74Sjose borrego static int winreg_s_OpenHKDD(void *, ndr_xa_t *);
1057f667e74Sjose borrego static int winreg_s_OpenHKPT(void *, ndr_xa_t *);
1067f667e74Sjose borrego static int winreg_s_OpenHKPN(void *, ndr_xa_t *);
1077f667e74Sjose borrego static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *);
10889dc44ceSjose borrego static int winreg_s_Close(void *, ndr_xa_t *);
10989dc44ceSjose borrego static int winreg_s_CreateKey(void *, ndr_xa_t *);
11089dc44ceSjose borrego static int winreg_s_DeleteKey(void *, ndr_xa_t *);
11189dc44ceSjose borrego static int winreg_s_DeleteValue(void *, ndr_xa_t *);
11289dc44ceSjose borrego static int winreg_s_EnumKey(void *, ndr_xa_t *);
11389dc44ceSjose borrego static int winreg_s_EnumValue(void *, ndr_xa_t *);
11489dc44ceSjose borrego static int winreg_s_FlushKey(void *, ndr_xa_t *);
11589dc44ceSjose borrego static int winreg_s_GetKeySec(void *, ndr_xa_t *);
11689dc44ceSjose borrego static int winreg_s_NotifyChange(void *, ndr_xa_t *);
11789dc44ceSjose borrego static int winreg_s_OpenKey(void *, ndr_xa_t *);
11889dc44ceSjose borrego static int winreg_s_QueryKey(void *, ndr_xa_t *);
11989dc44ceSjose borrego static int winreg_s_QueryValue(void *, ndr_xa_t *);
12089dc44ceSjose borrego static int winreg_s_SetKeySec(void *, ndr_xa_t *);
12189dc44ceSjose borrego static int winreg_s_CreateValue(void *, ndr_xa_t *);
12289dc44ceSjose borrego static int winreg_s_Shutdown(void *, ndr_xa_t *);
12389dc44ceSjose borrego static int winreg_s_AbortShutdown(void *, ndr_xa_t *);
12489dc44ceSjose borrego static int winreg_s_GetVersion(void *, ndr_xa_t *);
12589dc44ceSjose borrego 
12689dc44ceSjose borrego static ndr_stub_table_t winreg_stub_table[] = {
1277f667e74Sjose borrego 	{ winreg_s_OpenHKCR,	WINREG_OPNUM_OpenHKCR },
1287f667e74Sjose borrego 	{ winreg_s_OpenHKCU,	WINREG_OPNUM_OpenHKCU },
12989dc44ceSjose borrego 	{ winreg_s_OpenHKLM,	WINREG_OPNUM_OpenHKLM },
1307f667e74Sjose borrego 	{ winreg_s_OpenHKPD,	WINREG_OPNUM_OpenHKPD },
1317f667e74Sjose borrego 	{ winreg_s_OpenHKU,	WINREG_OPNUM_OpenHKUsers },
13289dc44ceSjose borrego 	{ winreg_s_Close,	WINREG_OPNUM_Close },
13389dc44ceSjose borrego 	{ winreg_s_CreateKey,	WINREG_OPNUM_CreateKey },
13489dc44ceSjose borrego 	{ winreg_s_DeleteKey,	WINREG_OPNUM_DeleteKey },
13589dc44ceSjose borrego 	{ winreg_s_DeleteValue,	WINREG_OPNUM_DeleteValue },
13689dc44ceSjose borrego 	{ winreg_s_EnumKey,	WINREG_OPNUM_EnumKey },
13789dc44ceSjose borrego 	{ winreg_s_EnumValue,	WINREG_OPNUM_EnumValue },
13889dc44ceSjose borrego 	{ winreg_s_FlushKey,	WINREG_OPNUM_FlushKey },
13989dc44ceSjose borrego 	{ winreg_s_GetKeySec,	WINREG_OPNUM_GetKeySec },
14089dc44ceSjose borrego 	{ winreg_s_NotifyChange,	WINREG_OPNUM_NotifyChange },
14189dc44ceSjose borrego 	{ winreg_s_OpenKey,	WINREG_OPNUM_OpenKey },
14289dc44ceSjose borrego 	{ winreg_s_QueryKey,	WINREG_OPNUM_QueryKey },
14389dc44ceSjose borrego 	{ winreg_s_QueryValue,	WINREG_OPNUM_QueryValue },
14489dc44ceSjose borrego 	{ winreg_s_SetKeySec,	WINREG_OPNUM_SetKeySec },
14589dc44ceSjose borrego 	{ winreg_s_CreateValue,	WINREG_OPNUM_CreateValue },
14689dc44ceSjose borrego 	{ winreg_s_Shutdown,	WINREG_OPNUM_Shutdown },
14789dc44ceSjose borrego 	{ winreg_s_AbortShutdown,	WINREG_OPNUM_AbortShutdown },
14889dc44ceSjose borrego 	{ winreg_s_GetVersion,	WINREG_OPNUM_GetVersion },
1497f667e74Sjose borrego 	{ winreg_s_OpenHKCC,	WINREG_OPNUM_OpenHKCC },
1507f667e74Sjose borrego 	{ winreg_s_OpenHKDD,	WINREG_OPNUM_OpenHKDD },
1517f667e74Sjose borrego 	{ winreg_s_OpenHKPT,	WINREG_OPNUM_OpenHKPT },
1527f667e74Sjose borrego 	{ winreg_s_OpenHKPN,	WINREG_OPNUM_OpenHKPN },
15389dc44ceSjose borrego 	{0}
15489dc44ceSjose borrego };
15589dc44ceSjose borrego 
15689dc44ceSjose borrego static ndr_service_t winreg_service = {
15789dc44ceSjose borrego 	"Winreg",			/* name */
15889dc44ceSjose borrego 	"Windows Registry",		/* desc */
15989dc44ceSjose borrego 	"\\winreg",			/* endpoint */
16089dc44ceSjose borrego 	PIPE_WINREG,			/* sec_addr_port */
16189dc44ceSjose borrego 	"338cd001-2244-31f1-aaaa-900038001003", 1,	/* abstract */
16289dc44ceSjose borrego 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
16389dc44ceSjose borrego 	0,				/* no bind_instance_size */
16489dc44ceSjose borrego 	0,				/* no bind_req() */
16589dc44ceSjose borrego 	0,				/* no unbind_and_close() */
16689dc44ceSjose borrego 	0,				/* use generic_call_stub() */
16789dc44ceSjose borrego 	&TYPEINFO(winreg_interface),	/* interface ti */
16889dc44ceSjose borrego 	winreg_stub_table		/* stub_table */
16989dc44ceSjose borrego };
17089dc44ceSjose borrego 
17189dc44ceSjose borrego static char winreg_sysname[SYS_NMLN];
17289dc44ceSjose borrego 
17389dc44ceSjose borrego /*
17489dc44ceSjose borrego  * winreg_initialize
17589dc44ceSjose borrego  *
17689dc44ceSjose borrego  * Initialize and register the WINREG RPC interface with the RPC runtime
17789dc44ceSjose borrego  * library. It must be called in order to use either the client side
17889dc44ceSjose borrego  * or the server side functions.
17989dc44ceSjose borrego  */
18089dc44ceSjose borrego void
18189dc44ceSjose borrego winreg_initialize(void)
18289dc44ceSjose borrego {
18389dc44ceSjose borrego 	winreg_subkey_t *key;
18489dc44ceSjose borrego 	struct utsname name;
18589dc44ceSjose borrego 	char *sysname;
18689dc44ceSjose borrego 	int i;
18789dc44ceSjose borrego 
18889dc44ceSjose borrego 	list_create(&winreg_keylist.kl_list, sizeof (winreg_subkey_t),
18989dc44ceSjose borrego 	    offsetof(winreg_subkey_t, sk_lnd));
19089dc44ceSjose borrego 	winreg_keylist.kl_count = 0;
19189dc44ceSjose borrego 
19289dc44ceSjose borrego 	for (i = 0; i < sizeof (winreg_keys)/sizeof (winreg_keys[0]); ++i) {
19389dc44ceSjose borrego 		if ((key = malloc(sizeof (winreg_subkey_t))) != NULL) {
19489dc44ceSjose borrego 			bzero(key, sizeof (winreg_subkey_t));
19589dc44ceSjose borrego 			(void) strlcpy(key->sk_name, winreg_keys[i],
19689dc44ceSjose borrego 			    MAXPATHLEN);
19789dc44ceSjose borrego 			key->sk_predefined = B_TRUE;
19889dc44ceSjose borrego 			list_insert_tail(&winreg_keylist.kl_list, key);
19989dc44ceSjose borrego 			++winreg_keylist.kl_count;
20089dc44ceSjose borrego 		}
20189dc44ceSjose borrego 	}
20289dc44ceSjose borrego 
20389dc44ceSjose borrego 	if (uname(&name) < 0)
20489dc44ceSjose borrego 		sysname = "Solaris";
20589dc44ceSjose borrego 	else
20689dc44ceSjose borrego 		sysname = name.sysname;
20789dc44ceSjose borrego 
20889dc44ceSjose borrego 	(void) strlcpy(winreg_sysname, sysname, SYS_NMLN);
20989dc44ceSjose borrego 	(void) ndr_svc_register(&winreg_service);
21089dc44ceSjose borrego }
21189dc44ceSjose borrego 
21289dc44ceSjose borrego static int
2137f667e74Sjose borrego winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa)
21489dc44ceSjose borrego {
2157f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKCR"));
21689dc44ceSjose borrego }
21789dc44ceSjose borrego 
2187f667e74Sjose borrego static int
2197f667e74Sjose borrego winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa)
2207f667e74Sjose borrego {
2217f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKCU"));
22289dc44ceSjose borrego }
22389dc44ceSjose borrego 
22489dc44ceSjose borrego static int
22589dc44ceSjose borrego winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa)
22689dc44ceSjose borrego {
2277f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKLM"));
22889dc44ceSjose borrego }
22989dc44ceSjose borrego 
2307f667e74Sjose borrego static int
2317f667e74Sjose borrego winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa)
2327f667e74Sjose borrego {
2337f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKPD"));
2347f667e74Sjose borrego }
2357f667e74Sjose borrego 
2367f667e74Sjose borrego static int
2377f667e74Sjose borrego winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa)
2387f667e74Sjose borrego {
2397f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKU"));
2407f667e74Sjose borrego }
2417f667e74Sjose borrego 
2427f667e74Sjose borrego static int
2437f667e74Sjose borrego winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa)
2447f667e74Sjose borrego {
2457f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKCC"));
2467f667e74Sjose borrego }
2477f667e74Sjose borrego 
2487f667e74Sjose borrego static int
2497f667e74Sjose borrego winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa)
2507f667e74Sjose borrego {
2517f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKDD"));
2527f667e74Sjose borrego }
2537f667e74Sjose borrego 
2547f667e74Sjose borrego static int
2557f667e74Sjose borrego winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa)
2567f667e74Sjose borrego {
2577f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKPT"));
2587f667e74Sjose borrego }
2597f667e74Sjose borrego 
2607f667e74Sjose borrego static int
2617f667e74Sjose borrego winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa)
2627f667e74Sjose borrego {
2637f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKPN"));
26489dc44ceSjose borrego }
26589dc44ceSjose borrego 
26689dc44ceSjose borrego /*
2677f667e74Sjose borrego  * winreg_s_OpenHK
26889dc44ceSjose borrego  *
2697f667e74Sjose borrego  * Common code to open root HKEYs.
27089dc44ceSjose borrego  */
27189dc44ceSjose borrego static int
2727f667e74Sjose borrego winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey)
27389dc44ceSjose borrego {
2747f667e74Sjose borrego 	struct winreg_OpenHKCR *param = arg;
27589dc44ceSjose borrego 	ndr_hdid_t *id;
2767f667e74Sjose borrego 	char *dupkey;
27789dc44ceSjose borrego 
2787f667e74Sjose borrego 	if ((dupkey = strdup(hkey)) == NULL) {
2797f667e74Sjose borrego 		bzero(&param->handle, sizeof (winreg_handle_t));
2807f667e74Sjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
2817f667e74Sjose borrego 		return (NDR_DRC_OK);
2827f667e74Sjose borrego 	}
2837f667e74Sjose borrego 
2847f667e74Sjose borrego 	if ((id = ndr_hdalloc(mxa, dupkey)) == NULL) {
2857f667e74Sjose borrego 		free(dupkey);
28689dc44ceSjose borrego 		bzero(&param->handle, sizeof (winreg_handle_t));
28789dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
28889dc44ceSjose borrego 	} else {
28989dc44ceSjose borrego 		bcopy(id, &param->handle, sizeof (winreg_handle_t));
29089dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
29189dc44ceSjose borrego 	}
29289dc44ceSjose borrego 
29389dc44ceSjose borrego 	return (NDR_DRC_OK);
29489dc44ceSjose borrego }
29589dc44ceSjose borrego 
29689dc44ceSjose borrego /*
29789dc44ceSjose borrego  * winreg_s_Close
29889dc44ceSjose borrego  *
29989dc44ceSjose borrego  * This is a request to close the WINREG interface specified by the
30089dc44ceSjose borrego  * handle. We don't track handles (yet), so just zero out the handle
30189dc44ceSjose borrego  * and return NDR_DRC_OK. Setting the handle to zero appears to be
30289dc44ceSjose borrego  * standard behaviour.
30389dc44ceSjose borrego  */
30489dc44ceSjose borrego static int
30589dc44ceSjose borrego winreg_s_Close(void *arg, ndr_xa_t *mxa)
30689dc44ceSjose borrego {
30789dc44ceSjose borrego 	struct winreg_Close *param = arg;
30889dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
3097f667e74Sjose borrego 	ndr_handle_t *hd;
3107f667e74Sjose borrego 
3117f667e74Sjose borrego 	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
3127f667e74Sjose borrego 		free(hd->nh_data);
3137f667e74Sjose borrego 		hd->nh_data = NULL;
3147f667e74Sjose borrego 	}
31589dc44ceSjose borrego 
31689dc44ceSjose borrego 	ndr_hdfree(mxa, id);
31789dc44ceSjose borrego 
31889dc44ceSjose borrego 	bzero(&param->result_handle, sizeof (winreg_handle_t));
31989dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
32089dc44ceSjose borrego 	return (NDR_DRC_OK);
32189dc44ceSjose borrego }
32289dc44ceSjose borrego 
32389dc44ceSjose borrego /*
32489dc44ceSjose borrego  * winreg_s_CreateKey
32589dc44ceSjose borrego  */
32689dc44ceSjose borrego static int
32789dc44ceSjose borrego winreg_s_CreateKey(void *arg, ndr_xa_t *mxa)
32889dc44ceSjose borrego {
32989dc44ceSjose borrego 	struct winreg_CreateKey *param = arg;
33089dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
33189dc44ceSjose borrego 	ndr_handle_t *hd;
33289dc44ceSjose borrego 	winreg_subkey_t *key;
33389dc44ceSjose borrego 	char *subkey;
3347f667e74Sjose borrego 	char *dupkey;
33589dc44ceSjose borrego 	DWORD *action;
33689dc44ceSjose borrego 
33789dc44ceSjose borrego 	subkey = (char *)param->subkey.str;
33889dc44ceSjose borrego 
33989dc44ceSjose borrego 	if (!ndr_is_admin(mxa) || (subkey == NULL)) {
34089dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
34189dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
34289dc44ceSjose borrego 		return (NDR_DRC_OK);
34389dc44ceSjose borrego 	}
34489dc44ceSjose borrego 
34589dc44ceSjose borrego 	hd = ndr_hdlookup(mxa, id);
34689dc44ceSjose borrego 	if (hd == NULL) {
34789dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
34889dc44ceSjose borrego 		param->status = ERROR_INVALID_HANDLE;
34989dc44ceSjose borrego 		return (NDR_DRC_OK);
35089dc44ceSjose borrego 	}
35189dc44ceSjose borrego 
35289dc44ceSjose borrego 	if ((action = NDR_NEW(mxa, DWORD)) == NULL) {
35389dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
35489dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
35589dc44ceSjose borrego 		return (NDR_DRC_OK);
35689dc44ceSjose borrego 	}
35789dc44ceSjose borrego 
35889dc44ceSjose borrego 	if (list_is_empty(&winreg_keylist.kl_list))
35989dc44ceSjose borrego 		goto new_key;
36089dc44ceSjose borrego 
36189dc44ceSjose borrego 	/*
36289dc44ceSjose borrego 	 * Check for an existing key.
36389dc44ceSjose borrego 	 */
36489dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
36589dc44ceSjose borrego 	do {
36689dc44ceSjose borrego 		if (strcasecmp(subkey, key->sk_name) == 0) {
36789dc44ceSjose borrego 			bcopy(&key->sk_handle, &param->result_handle,
36889dc44ceSjose borrego 			    sizeof (winreg_handle_t));
36989dc44ceSjose borrego 			*action = WINREG_ACTION_EXISTING_KEY;
37089dc44ceSjose borrego 			param->action = action;
37189dc44ceSjose borrego 			param->status = ERROR_SUCCESS;
37289dc44ceSjose borrego 			return (NDR_DRC_OK);
37389dc44ceSjose borrego 		}
37489dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
37589dc44ceSjose borrego 
37689dc44ceSjose borrego new_key:
37789dc44ceSjose borrego 	/*
37889dc44ceSjose borrego 	 * Create a new key.
37989dc44ceSjose borrego 	 */
3807f667e74Sjose borrego 	if ((dupkey = strdup(subkey)) == NULL) {
3817f667e74Sjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
3827f667e74Sjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
3837f667e74Sjose borrego 		return (NDR_DRC_OK);
3847f667e74Sjose borrego 	}
3857f667e74Sjose borrego 
3867f667e74Sjose borrego 	id = ndr_hdalloc(mxa, dupkey);
38789dc44ceSjose borrego 	key = malloc(sizeof (winreg_subkey_t));
38889dc44ceSjose borrego 
38989dc44ceSjose borrego 	if ((id == NULL) || (key == NULL)) {
3907f667e74Sjose borrego 		free(dupkey);
39189dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
39289dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
39389dc44ceSjose borrego 		return (NDR_DRC_OK);
39489dc44ceSjose borrego 	}
39589dc44ceSjose borrego 
39689dc44ceSjose borrego 	bcopy(id, &key->sk_handle, sizeof (ndr_hdid_t));
39789dc44ceSjose borrego 	(void) strlcpy(key->sk_name, subkey, MAXPATHLEN);
39889dc44ceSjose borrego 	key->sk_predefined = B_FALSE;
39989dc44ceSjose borrego 	list_insert_tail(&winreg_keylist.kl_list, key);
40089dc44ceSjose borrego 	++winreg_keylist.kl_count;
40189dc44ceSjose borrego 
40289dc44ceSjose borrego 	bcopy(id, &param->result_handle, sizeof (winreg_handle_t));
40389dc44ceSjose borrego 	*action = WINREG_ACTION_NEW_KEY;
40489dc44ceSjose borrego 	param->action = action;
40589dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
40689dc44ceSjose borrego 	return (NDR_DRC_OK);
40789dc44ceSjose borrego }
40889dc44ceSjose borrego 
40989dc44ceSjose borrego /*
41089dc44ceSjose borrego  * winreg_s_DeleteKey
41189dc44ceSjose borrego  */
41289dc44ceSjose borrego static int
41389dc44ceSjose borrego winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa)
41489dc44ceSjose borrego {
41589dc44ceSjose borrego 	struct winreg_DeleteKey *param = arg;
41689dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
4177f667e74Sjose borrego 	ndr_handle_t *hd;
41889dc44ceSjose borrego 	winreg_subkey_t *key;
41989dc44ceSjose borrego 	char *subkey;
42089dc44ceSjose borrego 
42189dc44ceSjose borrego 	subkey = (char *)param->subkey.str;
42289dc44ceSjose borrego 
42389dc44ceSjose borrego 	if (!ndr_is_admin(mxa) || (subkey == NULL)) {
42489dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
42589dc44ceSjose borrego 		return (NDR_DRC_OK);
42689dc44ceSjose borrego 	}
42789dc44ceSjose borrego 
42889dc44ceSjose borrego 	if ((ndr_hdlookup(mxa, id) == NULL) ||
42989dc44ceSjose borrego 	    list_is_empty(&winreg_keylist.kl_list) ||
43089dc44ceSjose borrego 	    winreg_key_has_subkey(subkey)) {
43189dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
43289dc44ceSjose borrego 		return (NDR_DRC_OK);
43389dc44ceSjose borrego 	}
43489dc44ceSjose borrego 
43589dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
43689dc44ceSjose borrego 	do {
43789dc44ceSjose borrego 		if (strcasecmp(subkey, key->sk_name) == 0) {
43889dc44ceSjose borrego 			if (key->sk_predefined == B_TRUE) {
43989dc44ceSjose borrego 				/* Predefined keys cannot be deleted */
44089dc44ceSjose borrego 				break;
44189dc44ceSjose borrego 			}
44289dc44ceSjose borrego 
44389dc44ceSjose borrego 			list_remove(&winreg_keylist.kl_list, key);
44489dc44ceSjose borrego 			--winreg_keylist.kl_count;
4457f667e74Sjose borrego 
4467f667e74Sjose borrego 			hd = ndr_hdlookup(mxa, &key->sk_handle);
4477f667e74Sjose borrego 			if (hd != NULL) {
4487f667e74Sjose borrego 				free(hd->nh_data);
4497f667e74Sjose borrego 				hd->nh_data = NULL;
4507f667e74Sjose borrego 			}
4517f667e74Sjose borrego 
45289dc44ceSjose borrego 			ndr_hdfree(mxa, &key->sk_handle);
45389dc44ceSjose borrego 			free(key);
45489dc44ceSjose borrego 			param->status = ERROR_SUCCESS;
45589dc44ceSjose borrego 			return (NDR_DRC_OK);
45689dc44ceSjose borrego 		}
45789dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
45889dc44ceSjose borrego 
45989dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
46089dc44ceSjose borrego 	return (NDR_DRC_OK);
46189dc44ceSjose borrego }
46289dc44ceSjose borrego 
46389dc44ceSjose borrego static boolean_t
46489dc44ceSjose borrego winreg_key_has_subkey(const char *subkey)
46589dc44ceSjose borrego {
46689dc44ceSjose borrego 	winreg_subkey_t *key;
46789dc44ceSjose borrego 	int keylen;
46889dc44ceSjose borrego 
46989dc44ceSjose borrego 	if (list_is_empty(&winreg_keylist.kl_list))
47089dc44ceSjose borrego 		return (B_FALSE);
47189dc44ceSjose borrego 
47289dc44ceSjose borrego 	keylen = strlen(subkey);
47389dc44ceSjose borrego 
47489dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
47589dc44ceSjose borrego 	do {
47689dc44ceSjose borrego 		if (strncasecmp(subkey, key->sk_name, keylen) == 0) {
47789dc44ceSjose borrego 			/*
47889dc44ceSjose borrego 			 * Potential match.  If sk_name is longer than
47989dc44ceSjose borrego 			 * subkey, then sk_name is a subkey of our key.
48089dc44ceSjose borrego 			 */
48189dc44ceSjose borrego 			if (keylen < strlen(key->sk_name))
48289dc44ceSjose borrego 				return (B_TRUE);
48389dc44ceSjose borrego 		}
48489dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
48589dc44ceSjose borrego 
48689dc44ceSjose borrego 	return (B_FALSE);
48789dc44ceSjose borrego }
48889dc44ceSjose borrego 
48989dc44ceSjose borrego static char *
4907f667e74Sjose borrego winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index)
49189dc44ceSjose borrego {
49289dc44ceSjose borrego 	winreg_subkey_t *key;
4937f667e74Sjose borrego 	char *entry;
4947f667e74Sjose borrego 	char *p;
4957f667e74Sjose borrego 	int subkeylen;
4967f667e74Sjose borrego 	int count = 0;
49789dc44ceSjose borrego 
49889dc44ceSjose borrego 	if (subkey == NULL)
49989dc44ceSjose borrego 		return (NULL);
50089dc44ceSjose borrego 
50189dc44ceSjose borrego 	if (list_is_empty(&winreg_keylist.kl_list))
50289dc44ceSjose borrego 		return (NULL);
50389dc44ceSjose borrego 
5047f667e74Sjose borrego 	subkeylen = strlen(subkey);
5057f667e74Sjose borrego 
5067f667e74Sjose borrego 	for (key = list_head(&winreg_keylist.kl_list);
5077f667e74Sjose borrego 	    key != NULL; key = list_next(&winreg_keylist.kl_list, key)) {
5087f667e74Sjose borrego 		if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) {
5097f667e74Sjose borrego 			p = key->sk_name + subkeylen;
5107f667e74Sjose borrego 
5117f667e74Sjose borrego 			if ((*p != '\\') || (*p == '\0')) {
5127f667e74Sjose borrego 				/*
5137f667e74Sjose borrego 				 * Not the same subkey or an exact match.
5147f667e74Sjose borrego 				 * We're looking for children of subkey.
5157f667e74Sjose borrego 				 */
5167f667e74Sjose borrego 				continue;
51789dc44ceSjose borrego 			}
5187f667e74Sjose borrego 
5197f667e74Sjose borrego 			++p;
5207f667e74Sjose borrego 
5217f667e74Sjose borrego 			if (count < index) {
5227f667e74Sjose borrego 				++count;
5237f667e74Sjose borrego 				continue;
5247f667e74Sjose borrego 			}
5257f667e74Sjose borrego 
5267f667e74Sjose borrego 			if ((entry = NDR_STRDUP(mxa, p)) == NULL)
5277f667e74Sjose borrego 				return (NULL);
5287f667e74Sjose borrego 
5297f667e74Sjose borrego 			if ((p = strchr(entry, '\\')) != NULL)
5307f667e74Sjose borrego 				*p = '\0';
5317f667e74Sjose borrego 
5327f667e74Sjose borrego 			return (entry);
5337f667e74Sjose borrego 		}
5347f667e74Sjose borrego 	}
53589dc44ceSjose borrego 
53689dc44ceSjose borrego 	return (NULL);
53789dc44ceSjose borrego }
53889dc44ceSjose borrego 
53989dc44ceSjose borrego /*
54089dc44ceSjose borrego  * winreg_s_DeleteValue
54189dc44ceSjose borrego  */
54289dc44ceSjose borrego /*ARGSUSED*/
54389dc44ceSjose borrego static int
54489dc44ceSjose borrego winreg_s_DeleteValue(void *arg, ndr_xa_t *mxa)
54589dc44ceSjose borrego {
54689dc44ceSjose borrego 	struct winreg_DeleteValue *param = arg;
54789dc44ceSjose borrego 
54889dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
54989dc44ceSjose borrego 	return (NDR_DRC_OK);
55089dc44ceSjose borrego }
55189dc44ceSjose borrego 
55289dc44ceSjose borrego /*
55389dc44ceSjose borrego  * winreg_s_EnumKey
55489dc44ceSjose borrego  */
55589dc44ceSjose borrego static int
55689dc44ceSjose borrego winreg_s_EnumKey(void *arg, ndr_xa_t *mxa)
55789dc44ceSjose borrego {
55889dc44ceSjose borrego 	struct winreg_EnumKey *param = arg;
55989dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
5607f667e74Sjose borrego 	ndr_handle_t *hd;
5617f667e74Sjose borrego 	char *subkey;
5627f667e74Sjose borrego 	char *name = NULL;
56389dc44ceSjose borrego 
5647f667e74Sjose borrego 	if ((hd = ndr_hdlookup(mxa, id)) != NULL)
5657f667e74Sjose borrego 		name = hd->nh_data;
5667f667e74Sjose borrego 
5677f667e74Sjose borrego 	if (hd == NULL || name == NULL) {
56889dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumKey));
56989dc44ceSjose borrego 		param->status = ERROR_NO_MORE_ITEMS;
57089dc44ceSjose borrego 		return (NDR_DRC_OK);
57189dc44ceSjose borrego 	}
57289dc44ceSjose borrego 
5737f667e74Sjose borrego 	subkey = winreg_enum_subkey(mxa, name, param->index);
5747f667e74Sjose borrego 	if (subkey == NULL) {
57589dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumKey));
57689dc44ceSjose borrego 		param->status = ERROR_NO_MORE_ITEMS;
57789dc44ceSjose borrego 		return (NDR_DRC_OK);
57889dc44ceSjose borrego 	}
57989dc44ceSjose borrego 
5807f667e74Sjose borrego 	if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)&param->name_out) == -1) {
58189dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumKey));
58289dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
58389dc44ceSjose borrego 		return (NDR_DRC_OK);
58489dc44ceSjose borrego 	}
5857f667e74Sjose borrego 	/*
5867f667e74Sjose borrego 	 * This request requires that the length includes the null.
5877f667e74Sjose borrego 	 */
5887f667e74Sjose borrego 	param->name_out.length = param->name_out.allosize;
58989dc44ceSjose borrego 
59089dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
59189dc44ceSjose borrego 	return (NDR_DRC_OK);
59289dc44ceSjose borrego }
59389dc44ceSjose borrego 
59489dc44ceSjose borrego /*
59589dc44ceSjose borrego  * winreg_s_EnumValue
59689dc44ceSjose borrego  */
59789dc44ceSjose borrego static int
59889dc44ceSjose borrego winreg_s_EnumValue(void *arg, ndr_xa_t *mxa)
59989dc44ceSjose borrego {
60089dc44ceSjose borrego 	struct winreg_EnumValue *param = arg;
60189dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
60289dc44ceSjose borrego 
60389dc44ceSjose borrego 	if (ndr_hdlookup(mxa, id) == NULL) {
60489dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumValue));
60589dc44ceSjose borrego 		param->status = ERROR_NO_MORE_ITEMS;
60689dc44ceSjose borrego 		return (NDR_DRC_OK);
60789dc44ceSjose borrego 	}
60889dc44ceSjose borrego 
60989dc44ceSjose borrego 	bzero(param, sizeof (struct winreg_EnumValue));
61089dc44ceSjose borrego 	param->status = ERROR_NO_MORE_ITEMS;
61189dc44ceSjose borrego 	return (NDR_DRC_OK);
61289dc44ceSjose borrego }
61389dc44ceSjose borrego 
61489dc44ceSjose borrego /*
61589dc44ceSjose borrego  * winreg_s_FlushKey
61689dc44ceSjose borrego  *
61789dc44ceSjose borrego  * Flush the attributes associated with the specified open key to disk.
61889dc44ceSjose borrego  */
61989dc44ceSjose borrego static int
62089dc44ceSjose borrego winreg_s_FlushKey(void *arg, ndr_xa_t *mxa)
62189dc44ceSjose borrego {
62289dc44ceSjose borrego 	struct winreg_FlushKey *param = arg;
62389dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
62489dc44ceSjose borrego 
62589dc44ceSjose borrego 	if (ndr_hdlookup(mxa, id) == NULL)
62689dc44ceSjose borrego 		param->status = ERROR_INVALID_HANDLE;
62789dc44ceSjose borrego 	else
62889dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
62989dc44ceSjose borrego 
63089dc44ceSjose borrego 	return (NDR_DRC_OK);
63189dc44ceSjose borrego }
63289dc44ceSjose borrego 
63389dc44ceSjose borrego /*
63489dc44ceSjose borrego  * winreg_s_GetKeySec
63589dc44ceSjose borrego  */
63689dc44ceSjose borrego /*ARGSUSED*/
63789dc44ceSjose borrego static int
63889dc44ceSjose borrego winreg_s_GetKeySec(void *arg, ndr_xa_t *mxa)
63989dc44ceSjose borrego {
64089dc44ceSjose borrego 	struct winreg_GetKeySec *param = arg;
64189dc44ceSjose borrego 
64289dc44ceSjose borrego 	bzero(param, sizeof (struct winreg_GetKeySec));
64389dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
64489dc44ceSjose borrego 	return (NDR_DRC_OK);
64589dc44ceSjose borrego }
64689dc44ceSjose borrego 
64789dc44ceSjose borrego /*
64889dc44ceSjose borrego  * winreg_s_NotifyChange
64989dc44ceSjose borrego  */
65089dc44ceSjose borrego static int
65189dc44ceSjose borrego winreg_s_NotifyChange(void *arg, ndr_xa_t *mxa)
65289dc44ceSjose borrego {
65389dc44ceSjose borrego 	struct winreg_NotifyChange *param = arg;
65489dc44ceSjose borrego 
65589dc44ceSjose borrego 	if (ndr_is_admin(mxa))
65689dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
65789dc44ceSjose borrego 	else
65889dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
65989dc44ceSjose borrego 
66089dc44ceSjose borrego 	return (NDR_DRC_OK);
66189dc44ceSjose borrego }
66289dc44ceSjose borrego 
66389dc44ceSjose borrego /*
66489dc44ceSjose borrego  * winreg_s_OpenKey
66589dc44ceSjose borrego  *
66689dc44ceSjose borrego  * This is a request to open a windows registry key.
66789dc44ceSjose borrego  * If we recognize the key, we return a handle.
66889dc44ceSjose borrego  *
66989dc44ceSjose borrego  * Returns:
67089dc44ceSjose borrego  *	ERROR_SUCCESS		Valid handle returned.
67189dc44ceSjose borrego  *	ERROR_FILE_NOT_FOUND	No key or unable to allocate a handle.
67289dc44ceSjose borrego  */
67389dc44ceSjose borrego static int
67489dc44ceSjose borrego winreg_s_OpenKey(void *arg, ndr_xa_t *mxa)
67589dc44ceSjose borrego {
67689dc44ceSjose borrego 	struct winreg_OpenKey *param = arg;
677b1352070SAlan Wright 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
678b1352070SAlan Wright 	ndr_handle_t *hd;
67989dc44ceSjose borrego 	char *subkey = (char *)param->name.str;
68089dc44ceSjose borrego 	winreg_subkey_t *key;
6817f667e74Sjose borrego 	char *dupkey;
68289dc44ceSjose borrego 
683b1352070SAlan Wright 	if (subkey == NULL || *subkey == '\0') {
684b1352070SAlan Wright 		if ((hd = ndr_hdlookup(mxa, id)) != NULL)
685b1352070SAlan Wright 			subkey = hd->nh_data;
686b1352070SAlan Wright 	}
687b1352070SAlan Wright 
688b1352070SAlan Wright 	id = NULL;
689b1352070SAlan Wright 
6907f667e74Sjose borrego 	if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) {
69189dc44ceSjose borrego 		bzero(&param->result_handle, sizeof (winreg_handle_t));
69289dc44ceSjose borrego 		param->status = ERROR_FILE_NOT_FOUND;
69389dc44ceSjose borrego 		return (NDR_DRC_OK);
69489dc44ceSjose borrego 	}
69589dc44ceSjose borrego 
69689dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
69789dc44ceSjose borrego 	do {
69889dc44ceSjose borrego 		if (strcasecmp(subkey, key->sk_name) == 0) {
6997f667e74Sjose borrego 			if (key->sk_predefined == B_TRUE) {
7007f667e74Sjose borrego 				if ((dupkey = strdup(subkey)) == NULL)
7017f667e74Sjose borrego 					break;
7027f667e74Sjose borrego 
7037f667e74Sjose borrego 				id = ndr_hdalloc(mxa, dupkey);
7047f667e74Sjose borrego 				if (id == NULL)
7057f667e74Sjose borrego 					free(dupkey);
7067f667e74Sjose borrego 			} else {
70789dc44ceSjose borrego 				id = &key->sk_handle;
7087f667e74Sjose borrego 			}
70989dc44ceSjose borrego 
71089dc44ceSjose borrego 			if (id == NULL)
71189dc44ceSjose borrego 				break;
71289dc44ceSjose borrego 
71389dc44ceSjose borrego 			bcopy(id, &param->result_handle,
71489dc44ceSjose borrego 			    sizeof (winreg_handle_t));
71589dc44ceSjose borrego 			param->status = ERROR_SUCCESS;
71689dc44ceSjose borrego 			return (NDR_DRC_OK);
71789dc44ceSjose borrego 		}
71889dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
71989dc44ceSjose borrego 
72089dc44ceSjose borrego 	bzero(&param->result_handle, sizeof (winreg_handle_t));
72189dc44ceSjose borrego 	param->status = ERROR_FILE_NOT_FOUND;
72289dc44ceSjose borrego 	return (NDR_DRC_OK);
72389dc44ceSjose borrego }
72489dc44ceSjose borrego 
72589dc44ceSjose borrego /*
72689dc44ceSjose borrego  * winreg_s_QueryKey
72789dc44ceSjose borrego  */
72889dc44ceSjose borrego /*ARGSUSED*/
72989dc44ceSjose borrego static int
73089dc44ceSjose borrego winreg_s_QueryKey(void *arg, ndr_xa_t *mxa)
73189dc44ceSjose borrego {
73289dc44ceSjose borrego 	struct winreg_QueryKey *param = arg;
73389dc44ceSjose borrego 	int rc;
73489dc44ceSjose borrego 	winreg_string_t	*name;
73589dc44ceSjose borrego 
73689dc44ceSjose borrego 	name = (winreg_string_t	*)&param->name;
73789dc44ceSjose borrego 	bzero(param, sizeof (struct winreg_QueryKey));
73889dc44ceSjose borrego 	if ((name = NDR_NEW(mxa, winreg_string_t)) != NULL)
73989dc44ceSjose borrego 		rc = NDR_MSTRING(mxa, "", (ndr_mstring_t *)name);
74089dc44ceSjose borrego 
74189dc44ceSjose borrego 	if ((name == NULL) || (rc != 0)) {
74289dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_QueryKey));
74389dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
74489dc44ceSjose borrego 		return (NDR_DRC_OK);
74589dc44ceSjose borrego 	}
74689dc44ceSjose borrego 
74789dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
74889dc44ceSjose borrego 	return (NDR_DRC_OK);
74989dc44ceSjose borrego }
75089dc44ceSjose borrego 
75189dc44ceSjose borrego /*
75289dc44ceSjose borrego  * winreg_s_QueryValue
75389dc44ceSjose borrego  *
75489dc44ceSjose borrego  * This is a request to get the value associated with a specified name.
75589dc44ceSjose borrego  *
75689dc44ceSjose borrego  * Returns:
75789dc44ceSjose borrego  *	ERROR_SUCCESS		Value returned.
75889dc44ceSjose borrego  *	ERROR_FILE_NOT_FOUND	PrimaryModule is not supported.
75989dc44ceSjose borrego  *	ERROR_CANTREAD          No such name or memory problem.
76089dc44ceSjose borrego  */
76189dc44ceSjose borrego static int
76289dc44ceSjose borrego winreg_s_QueryValue(void *arg, ndr_xa_t *mxa)
76389dc44ceSjose borrego {
76489dc44ceSjose borrego 	struct winreg_QueryValue *param = arg;
76589dc44ceSjose borrego 	struct winreg_value *pv;
76689dc44ceSjose borrego 	char *name;
76789dc44ceSjose borrego 	char *value;
76889dc44ceSjose borrego 	DWORD slen;
76989dc44ceSjose borrego 	DWORD msize;
77089dc44ceSjose borrego 
77189dc44ceSjose borrego 	name = (char *)param->value_name.str;
77289dc44ceSjose borrego 
77389dc44ceSjose borrego 	if (strcasecmp(name, "PrimaryModule") == 0) {
77489dc44ceSjose borrego 		param->status = ERROR_FILE_NOT_FOUND;
77589dc44ceSjose borrego 		return (NDR_DRC_OK);
77689dc44ceSjose borrego 	}
77789dc44ceSjose borrego 
77889dc44ceSjose borrego 	if ((value = winreg_lookup_value(name)) == NULL) {
77989dc44ceSjose borrego 		param->status = ERROR_CANTREAD;
78089dc44ceSjose borrego 		return (NDR_DRC_OK);
78189dc44ceSjose borrego 	}
78289dc44ceSjose borrego 
783*bbf6f00cSJordan Brown 	slen = smb_wcequiv_strlen(value) + sizeof (smb_wchar_t);
78489dc44ceSjose borrego 	msize = sizeof (struct winreg_value) + slen;
78589dc44ceSjose borrego 
78689dc44ceSjose borrego 	param->value = (struct winreg_value *)NDR_MALLOC(mxa, msize);
78789dc44ceSjose borrego 	param->type = NDR_NEW(mxa, DWORD);
78889dc44ceSjose borrego 	param->value_size = NDR_NEW(mxa, DWORD);
78989dc44ceSjose borrego 	param->value_size_total = NDR_NEW(mxa, DWORD);
79089dc44ceSjose borrego 
79189dc44ceSjose borrego 	if (param->value == NULL || param->type == NULL ||
79289dc44ceSjose borrego 	    param->value_size == NULL || param->value_size_total == NULL) {
79389dc44ceSjose borrego 		param->status = ERROR_CANTREAD;
79489dc44ceSjose borrego 		return (NDR_DRC_OK);
79589dc44ceSjose borrego 	}
79689dc44ceSjose borrego 
79789dc44ceSjose borrego 	bzero(param->value, msize);
79889dc44ceSjose borrego 	pv = param->value;
79989dc44ceSjose borrego 	pv->vc_first_is = 0;
80089dc44ceSjose borrego 	pv->vc_length_is = slen;
80189dc44ceSjose borrego 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
802*bbf6f00cSJordan Brown 	(void) ndr_mbstowcs(NULL, (smb_wchar_t *)pv->value, value, slen);
80389dc44ceSjose borrego 
80489dc44ceSjose borrego 	*param->type = 1;
80589dc44ceSjose borrego 	*param->value_size = slen;
80689dc44ceSjose borrego 	*param->value_size_total = slen;
80789dc44ceSjose borrego 
80889dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
80989dc44ceSjose borrego 	return (NDR_DRC_OK);
81089dc44ceSjose borrego }
81189dc44ceSjose borrego 
81289dc44ceSjose borrego /*
81389dc44ceSjose borrego  * Lookup a name in the registry and return the associated value.
81489dc44ceSjose borrego  * Our registry is a case-insensitive, name-value pair table.
81589dc44ceSjose borrego  *
81689dc44ceSjose borrego  * Windows ProductType: WinNT, ServerNT, LanmanNT.
81789dc44ceSjose borrego  *	Windows NT4.0 workstation: WinNT
81889dc44ceSjose borrego  *	Windows NT4.0 server:      ServerNT
81989dc44ceSjose borrego  *
82089dc44ceSjose borrego  * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy
82189dc44ceSjose borrego  * with info level 6, which we don't support.  If we use ServerNT
82289dc44ceSjose borrego  * (as reported by NT4.0 Server) Windows 2000 send requests for
82389dc44ceSjose borrego  * levels 3 and 5, which are support.
82489dc44ceSjose borrego  *
82589dc44ceSjose borrego  * On success, returns a pointer to the value.  Otherwise returns
82689dc44ceSjose borrego  * a null pointer.
82789dc44ceSjose borrego  */
82889dc44ceSjose borrego static char *
82989dc44ceSjose borrego winreg_lookup_value(const char *name)
83089dc44ceSjose borrego {
83189dc44ceSjose borrego 	static struct registry {
83289dc44ceSjose borrego 		char *name;
83389dc44ceSjose borrego 		char *value;
83489dc44ceSjose borrego 	} registry[] = {
835e3f2c991SKeyur Desai 		{ "CurrentVersion", "4.0" },
83689dc44ceSjose borrego 		{ "ProductType", "ServerNT" },
83789dc44ceSjose borrego 		{ "Sources",	 NULL }	/* product name */
83889dc44ceSjose borrego 	};
83989dc44ceSjose borrego 
84089dc44ceSjose borrego 	int i;
84189dc44ceSjose borrego 
84289dc44ceSjose borrego 	for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) {
84389dc44ceSjose borrego 		if (strcasecmp(registry[i].name, name) == 0) {
84489dc44ceSjose borrego 			if (registry[i].value == NULL)
84589dc44ceSjose borrego 				return (winreg_sysname);
84689dc44ceSjose borrego 			else
84789dc44ceSjose borrego 				return (registry[i].value);
84889dc44ceSjose borrego 		}
84989dc44ceSjose borrego 	}
85089dc44ceSjose borrego 
85189dc44ceSjose borrego 	return (NULL);
85289dc44ceSjose borrego }
85389dc44ceSjose borrego 
85489dc44ceSjose borrego /*
85589dc44ceSjose borrego  * winreg_s_SetKeySec
85689dc44ceSjose borrego  */
85789dc44ceSjose borrego /*ARGSUSED*/
85889dc44ceSjose borrego static int
85989dc44ceSjose borrego winreg_s_SetKeySec(void *arg, ndr_xa_t *mxa)
86089dc44ceSjose borrego {
86189dc44ceSjose borrego 	struct winreg_SetKeySec *param = arg;
86289dc44ceSjose borrego 
86389dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
86489dc44ceSjose borrego 	return (NDR_DRC_OK);
86589dc44ceSjose borrego }
86689dc44ceSjose borrego 
86789dc44ceSjose borrego /*
86889dc44ceSjose borrego  * winreg_s_CreateValue
86989dc44ceSjose borrego  */
87089dc44ceSjose borrego /*ARGSUSED*/
87189dc44ceSjose borrego static int
87289dc44ceSjose borrego winreg_s_CreateValue(void *arg, ndr_xa_t *mxa)
87389dc44ceSjose borrego {
87489dc44ceSjose borrego 	struct winreg_CreateValue *param = arg;
87589dc44ceSjose borrego 
87689dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
87789dc44ceSjose borrego 	return (NDR_DRC_OK);
87889dc44ceSjose borrego }
87989dc44ceSjose borrego 
88089dc44ceSjose borrego /*
88189dc44ceSjose borrego  * winreg_s_Shutdown
88289dc44ceSjose borrego  *
88389dc44ceSjose borrego  * Attempt to shutdown or reboot the system: access denied.
88489dc44ceSjose borrego  */
88589dc44ceSjose borrego /*ARGSUSED*/
88689dc44ceSjose borrego static int
88789dc44ceSjose borrego winreg_s_Shutdown(void *arg, ndr_xa_t *mxa)
88889dc44ceSjose borrego {
88989dc44ceSjose borrego 	struct winreg_Shutdown *param = arg;
89089dc44ceSjose borrego 
89189dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
89289dc44ceSjose borrego 	return (NDR_DRC_OK);
89389dc44ceSjose borrego }
89489dc44ceSjose borrego 
89589dc44ceSjose borrego /*
89689dc44ceSjose borrego  * winreg_s_AbortShutdown
89789dc44ceSjose borrego  *
89889dc44ceSjose borrego  * Abort a shutdown request.
89989dc44ceSjose borrego  */
90089dc44ceSjose borrego static int
90189dc44ceSjose borrego winreg_s_AbortShutdown(void *arg, ndr_xa_t *mxa)
90289dc44ceSjose borrego {
90389dc44ceSjose borrego 	struct winreg_AbortShutdown *param = arg;
90489dc44ceSjose borrego 
90589dc44ceSjose borrego 	if (ndr_is_admin(mxa))
90689dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
90789dc44ceSjose borrego 	else
90889dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
90989dc44ceSjose borrego 
91089dc44ceSjose borrego 	return (NDR_DRC_OK);
91189dc44ceSjose borrego }
91289dc44ceSjose borrego 
91389dc44ceSjose borrego /*
91489dc44ceSjose borrego  * winreg_s_GetVersion
91589dc44ceSjose borrego  *
91689dc44ceSjose borrego  * Return the windows registry version.  The current version is 5.
91789dc44ceSjose borrego  * This call is usually made prior to enumerating or querying registry
91889dc44ceSjose borrego  * keys or values.
91989dc44ceSjose borrego  */
92089dc44ceSjose borrego /*ARGSUSED*/
92189dc44ceSjose borrego static int
92289dc44ceSjose borrego winreg_s_GetVersion(void *arg, ndr_xa_t *mxa)
92389dc44ceSjose borrego {
92489dc44ceSjose borrego 	struct winreg_GetVersion *param = arg;
92589dc44ceSjose borrego 
92689dc44ceSjose borrego 	param->version = 5;
92789dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
92889dc44ceSjose borrego 	return (NDR_DRC_OK);
92989dc44ceSjose borrego }
930