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  *
29*7f667e74Sjose borrego  * The registry is a database with a hierarchical structure similar to
30*7f667e74Sjose borrego  * a file system, with keys in place of directories and values in place
31*7f667e74Sjose borrego  * of files.  The top level keys are known as root keys and each key can
32*7f667e74Sjose borrego  * contain subkeys and values.  As with directories and sub-directories,
33*7f667e74Sjose borrego  * the terms key and subkey are used interchangeably.  Values, analogous
34*7f667e74Sjose borrego  * to files, contain data.
3589dc44ceSjose borrego  *
36*7f667e74Sjose borrego  * A specific subkey can be identifies by its fully qualified name (FQN),
37*7f667e74Sjose borrego  * which is analogous to a file system path.  In the registry, the key
38*7f667e74Sjose borrego  * separator is the '\' character, which is reserved and cannot appear
39*7f667e74Sjose borrego  * in key or value names.  Registry names are case-insensitive.
40*7f667e74Sjose borrego  *
41*7f667e74Sjose borrego  * For example:  HKEY_LOCAL_MACHINE\System\CurrentControlSet
42*7f667e74Sjose borrego  *
43*7f667e74Sjose borrego  * The HKEY_LOCAL_MACHINE root key contains a subkey call System, and
44*7f667e74Sjose borrego  * System contains a subkey called CurrentControlSet.
45*7f667e74Sjose borrego  *
46*7f667e74Sjose 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[] = {
6389dc44ceSjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog",
64*7f667e74Sjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog\\Application",
65*7f667e74Sjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog\\Security",
6689dc44ceSjose borrego 	"System\\CurrentControlSet\\Services\\Eventlog\\System",
6789dc44ceSjose borrego 	"System\\CurrentControlSet\\Control\\ProductOptions",
6889dc44ceSjose borrego 	"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
6989dc44ceSjose borrego };
7089dc44ceSjose borrego 
7189dc44ceSjose borrego typedef struct winreg_subkey {
7289dc44ceSjose borrego 	list_node_t sk_lnd;
7389dc44ceSjose borrego 	ndr_hdid_t sk_handle;
7489dc44ceSjose borrego 	char sk_name[MAXPATHLEN];
7589dc44ceSjose borrego 	boolean_t sk_predefined;
7689dc44ceSjose borrego } winreg_subkey_t;
7789dc44ceSjose borrego 
7889dc44ceSjose borrego typedef struct winreg_keylist {
7989dc44ceSjose borrego 	list_t kl_list;
8089dc44ceSjose borrego 	int kl_count;
8189dc44ceSjose borrego } winreg_keylist_t;
8289dc44ceSjose borrego 
8389dc44ceSjose borrego static winreg_keylist_t winreg_keylist;
8489dc44ceSjose borrego 
8589dc44ceSjose borrego static boolean_t winreg_key_has_subkey(const char *);
86*7f667e74Sjose borrego static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t);
8789dc44ceSjose borrego static char *winreg_lookup_value(const char *);
8889dc44ceSjose borrego 
89*7f667e74Sjose borrego static int winreg_s_OpenHKCR(void *, ndr_xa_t *);
90*7f667e74Sjose borrego static int winreg_s_OpenHKCU(void *, ndr_xa_t *);
9189dc44ceSjose borrego static int winreg_s_OpenHKLM(void *, ndr_xa_t *);
92*7f667e74Sjose borrego static int winreg_s_OpenHKPD(void *, ndr_xa_t *);
93*7f667e74Sjose borrego static int winreg_s_OpenHKU(void *, ndr_xa_t *);
94*7f667e74Sjose borrego static int winreg_s_OpenHKCC(void *, ndr_xa_t *);
95*7f667e74Sjose borrego static int winreg_s_OpenHKDD(void *, ndr_xa_t *);
96*7f667e74Sjose borrego static int winreg_s_OpenHKPT(void *, ndr_xa_t *);
97*7f667e74Sjose borrego static int winreg_s_OpenHKPN(void *, ndr_xa_t *);
98*7f667e74Sjose borrego static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *);
9989dc44ceSjose borrego static int winreg_s_Close(void *, ndr_xa_t *);
10089dc44ceSjose borrego static int winreg_s_CreateKey(void *, ndr_xa_t *);
10189dc44ceSjose borrego static int winreg_s_DeleteKey(void *, ndr_xa_t *);
10289dc44ceSjose borrego static int winreg_s_DeleteValue(void *, ndr_xa_t *);
10389dc44ceSjose borrego static int winreg_s_EnumKey(void *, ndr_xa_t *);
10489dc44ceSjose borrego static int winreg_s_EnumValue(void *, ndr_xa_t *);
10589dc44ceSjose borrego static int winreg_s_FlushKey(void *, ndr_xa_t *);
10689dc44ceSjose borrego static int winreg_s_GetKeySec(void *, ndr_xa_t *);
10789dc44ceSjose borrego static int winreg_s_NotifyChange(void *, ndr_xa_t *);
10889dc44ceSjose borrego static int winreg_s_OpenKey(void *, ndr_xa_t *);
10989dc44ceSjose borrego static int winreg_s_QueryKey(void *, ndr_xa_t *);
11089dc44ceSjose borrego static int winreg_s_QueryValue(void *, ndr_xa_t *);
11189dc44ceSjose borrego static int winreg_s_SetKeySec(void *, ndr_xa_t *);
11289dc44ceSjose borrego static int winreg_s_CreateValue(void *, ndr_xa_t *);
11389dc44ceSjose borrego static int winreg_s_Shutdown(void *, ndr_xa_t *);
11489dc44ceSjose borrego static int winreg_s_AbortShutdown(void *, ndr_xa_t *);
11589dc44ceSjose borrego static int winreg_s_GetVersion(void *, ndr_xa_t *);
11689dc44ceSjose borrego 
11789dc44ceSjose borrego static ndr_stub_table_t winreg_stub_table[] = {
118*7f667e74Sjose borrego 	{ winreg_s_OpenHKCR,	WINREG_OPNUM_OpenHKCR },
119*7f667e74Sjose borrego 	{ winreg_s_OpenHKCU,	WINREG_OPNUM_OpenHKCU },
12089dc44ceSjose borrego 	{ winreg_s_OpenHKLM,	WINREG_OPNUM_OpenHKLM },
121*7f667e74Sjose borrego 	{ winreg_s_OpenHKPD,	WINREG_OPNUM_OpenHKPD },
122*7f667e74Sjose borrego 	{ winreg_s_OpenHKU,	WINREG_OPNUM_OpenHKUsers },
12389dc44ceSjose borrego 	{ winreg_s_Close,	WINREG_OPNUM_Close },
12489dc44ceSjose borrego 	{ winreg_s_CreateKey,	WINREG_OPNUM_CreateKey },
12589dc44ceSjose borrego 	{ winreg_s_DeleteKey,	WINREG_OPNUM_DeleteKey },
12689dc44ceSjose borrego 	{ winreg_s_DeleteValue,	WINREG_OPNUM_DeleteValue },
12789dc44ceSjose borrego 	{ winreg_s_EnumKey,	WINREG_OPNUM_EnumKey },
12889dc44ceSjose borrego 	{ winreg_s_EnumValue,	WINREG_OPNUM_EnumValue },
12989dc44ceSjose borrego 	{ winreg_s_FlushKey,	WINREG_OPNUM_FlushKey },
13089dc44ceSjose borrego 	{ winreg_s_GetKeySec,	WINREG_OPNUM_GetKeySec },
13189dc44ceSjose borrego 	{ winreg_s_NotifyChange,	WINREG_OPNUM_NotifyChange },
13289dc44ceSjose borrego 	{ winreg_s_OpenKey,	WINREG_OPNUM_OpenKey },
13389dc44ceSjose borrego 	{ winreg_s_QueryKey,	WINREG_OPNUM_QueryKey },
13489dc44ceSjose borrego 	{ winreg_s_QueryValue,	WINREG_OPNUM_QueryValue },
13589dc44ceSjose borrego 	{ winreg_s_SetKeySec,	WINREG_OPNUM_SetKeySec },
13689dc44ceSjose borrego 	{ winreg_s_CreateValue,	WINREG_OPNUM_CreateValue },
13789dc44ceSjose borrego 	{ winreg_s_Shutdown,	WINREG_OPNUM_Shutdown },
13889dc44ceSjose borrego 	{ winreg_s_AbortShutdown,	WINREG_OPNUM_AbortShutdown },
13989dc44ceSjose borrego 	{ winreg_s_GetVersion,	WINREG_OPNUM_GetVersion },
140*7f667e74Sjose borrego 	{ winreg_s_OpenHKCC,	WINREG_OPNUM_OpenHKCC },
141*7f667e74Sjose borrego 	{ winreg_s_OpenHKDD,	WINREG_OPNUM_OpenHKDD },
142*7f667e74Sjose borrego 	{ winreg_s_OpenHKPT,	WINREG_OPNUM_OpenHKPT },
143*7f667e74Sjose borrego 	{ winreg_s_OpenHKPN,	WINREG_OPNUM_OpenHKPN },
14489dc44ceSjose borrego 	{0}
14589dc44ceSjose borrego };
14689dc44ceSjose borrego 
14789dc44ceSjose borrego static ndr_service_t winreg_service = {
14889dc44ceSjose borrego 	"Winreg",			/* name */
14989dc44ceSjose borrego 	"Windows Registry",		/* desc */
15089dc44ceSjose borrego 	"\\winreg",			/* endpoint */
15189dc44ceSjose borrego 	PIPE_WINREG,			/* sec_addr_port */
15289dc44ceSjose borrego 	"338cd001-2244-31f1-aaaa-900038001003", 1,	/* abstract */
15389dc44ceSjose borrego 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
15489dc44ceSjose borrego 	0,				/* no bind_instance_size */
15589dc44ceSjose borrego 	0,				/* no bind_req() */
15689dc44ceSjose borrego 	0,				/* no unbind_and_close() */
15789dc44ceSjose borrego 	0,				/* use generic_call_stub() */
15889dc44ceSjose borrego 	&TYPEINFO(winreg_interface),	/* interface ti */
15989dc44ceSjose borrego 	winreg_stub_table		/* stub_table */
16089dc44ceSjose borrego };
16189dc44ceSjose borrego 
16289dc44ceSjose borrego static char winreg_sysname[SYS_NMLN];
16389dc44ceSjose borrego 
16489dc44ceSjose borrego /*
16589dc44ceSjose borrego  * winreg_initialize
16689dc44ceSjose borrego  *
16789dc44ceSjose borrego  * Initialize and register the WINREG RPC interface with the RPC runtime
16889dc44ceSjose borrego  * library. It must be called in order to use either the client side
16989dc44ceSjose borrego  * or the server side functions.
17089dc44ceSjose borrego  */
17189dc44ceSjose borrego void
17289dc44ceSjose borrego winreg_initialize(void)
17389dc44ceSjose borrego {
17489dc44ceSjose borrego 	winreg_subkey_t *key;
17589dc44ceSjose borrego 	struct utsname name;
17689dc44ceSjose borrego 	char *sysname;
17789dc44ceSjose borrego 	int i;
17889dc44ceSjose borrego 
17989dc44ceSjose borrego 	list_create(&winreg_keylist.kl_list, sizeof (winreg_subkey_t),
18089dc44ceSjose borrego 	    offsetof(winreg_subkey_t, sk_lnd));
18189dc44ceSjose borrego 	winreg_keylist.kl_count = 0;
18289dc44ceSjose borrego 
18389dc44ceSjose borrego 	for (i = 0; i < sizeof (winreg_keys)/sizeof (winreg_keys[0]); ++i) {
18489dc44ceSjose borrego 		if ((key = malloc(sizeof (winreg_subkey_t))) != NULL) {
18589dc44ceSjose borrego 			bzero(key, sizeof (winreg_subkey_t));
18689dc44ceSjose borrego 			(void) strlcpy(key->sk_name, winreg_keys[i],
18789dc44ceSjose borrego 			    MAXPATHLEN);
18889dc44ceSjose borrego 			key->sk_predefined = B_TRUE;
18989dc44ceSjose borrego 			list_insert_tail(&winreg_keylist.kl_list, key);
19089dc44ceSjose borrego 			++winreg_keylist.kl_count;
19189dc44ceSjose borrego 		}
19289dc44ceSjose borrego 	}
19389dc44ceSjose borrego 
19489dc44ceSjose borrego 	if (uname(&name) < 0)
19589dc44ceSjose borrego 		sysname = "Solaris";
19689dc44ceSjose borrego 	else
19789dc44ceSjose borrego 		sysname = name.sysname;
19889dc44ceSjose borrego 
19989dc44ceSjose borrego 	(void) strlcpy(winreg_sysname, sysname, SYS_NMLN);
20089dc44ceSjose borrego 	(void) ndr_svc_register(&winreg_service);
20189dc44ceSjose borrego }
20289dc44ceSjose borrego 
20389dc44ceSjose borrego static int
204*7f667e74Sjose borrego winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa)
20589dc44ceSjose borrego {
206*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKCR"));
20789dc44ceSjose borrego }
20889dc44ceSjose borrego 
209*7f667e74Sjose borrego static int
210*7f667e74Sjose borrego winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa)
211*7f667e74Sjose borrego {
212*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKCU"));
21389dc44ceSjose borrego }
21489dc44ceSjose borrego 
21589dc44ceSjose borrego static int
21689dc44ceSjose borrego winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa)
21789dc44ceSjose borrego {
218*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKLM"));
21989dc44ceSjose borrego }
22089dc44ceSjose borrego 
221*7f667e74Sjose borrego static int
222*7f667e74Sjose borrego winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa)
223*7f667e74Sjose borrego {
224*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKPD"));
225*7f667e74Sjose borrego }
226*7f667e74Sjose borrego 
227*7f667e74Sjose borrego static int
228*7f667e74Sjose borrego winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa)
229*7f667e74Sjose borrego {
230*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKU"));
231*7f667e74Sjose borrego }
232*7f667e74Sjose borrego 
233*7f667e74Sjose borrego static int
234*7f667e74Sjose borrego winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa)
235*7f667e74Sjose borrego {
236*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKCC"));
237*7f667e74Sjose borrego }
238*7f667e74Sjose borrego 
239*7f667e74Sjose borrego static int
240*7f667e74Sjose borrego winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa)
241*7f667e74Sjose borrego {
242*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKDD"));
243*7f667e74Sjose borrego }
244*7f667e74Sjose borrego 
245*7f667e74Sjose borrego static int
246*7f667e74Sjose borrego winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa)
247*7f667e74Sjose borrego {
248*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKPT"));
249*7f667e74Sjose borrego }
250*7f667e74Sjose borrego 
251*7f667e74Sjose borrego static int
252*7f667e74Sjose borrego winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa)
253*7f667e74Sjose borrego {
254*7f667e74Sjose borrego 	return (winreg_s_OpenHK(arg, mxa, "HKPN"));
25589dc44ceSjose borrego }
25689dc44ceSjose borrego 
25789dc44ceSjose borrego /*
258*7f667e74Sjose borrego  * winreg_s_OpenHK
25989dc44ceSjose borrego  *
260*7f667e74Sjose borrego  * Common code to open root HKEYs.
26189dc44ceSjose borrego  */
26289dc44ceSjose borrego static int
263*7f667e74Sjose borrego winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey)
26489dc44ceSjose borrego {
265*7f667e74Sjose borrego 	struct winreg_OpenHKCR *param = arg;
26689dc44ceSjose borrego 	ndr_hdid_t *id;
267*7f667e74Sjose borrego 	char *dupkey;
26889dc44ceSjose borrego 
269*7f667e74Sjose borrego 	if ((dupkey = strdup(hkey)) == NULL) {
270*7f667e74Sjose borrego 		bzero(&param->handle, sizeof (winreg_handle_t));
271*7f667e74Sjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
272*7f667e74Sjose borrego 		return (NDR_DRC_OK);
273*7f667e74Sjose borrego 	}
274*7f667e74Sjose borrego 
275*7f667e74Sjose borrego 	if ((id = ndr_hdalloc(mxa, dupkey)) == NULL) {
276*7f667e74Sjose borrego 		free(dupkey);
27789dc44ceSjose borrego 		bzero(&param->handle, sizeof (winreg_handle_t));
27889dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
27989dc44ceSjose borrego 	} else {
28089dc44ceSjose borrego 		bcopy(id, &param->handle, sizeof (winreg_handle_t));
28189dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
28289dc44ceSjose borrego 	}
28389dc44ceSjose borrego 
28489dc44ceSjose borrego 	return (NDR_DRC_OK);
28589dc44ceSjose borrego }
28689dc44ceSjose borrego 
28789dc44ceSjose borrego /*
28889dc44ceSjose borrego  * winreg_s_Close
28989dc44ceSjose borrego  *
29089dc44ceSjose borrego  * This is a request to close the WINREG interface specified by the
29189dc44ceSjose borrego  * handle. We don't track handles (yet), so just zero out the handle
29289dc44ceSjose borrego  * and return NDR_DRC_OK. Setting the handle to zero appears to be
29389dc44ceSjose borrego  * standard behaviour.
29489dc44ceSjose borrego  */
29589dc44ceSjose borrego static int
29689dc44ceSjose borrego winreg_s_Close(void *arg, ndr_xa_t *mxa)
29789dc44ceSjose borrego {
29889dc44ceSjose borrego 	struct winreg_Close *param = arg;
29989dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
300*7f667e74Sjose borrego 	ndr_handle_t *hd;
301*7f667e74Sjose borrego 
302*7f667e74Sjose borrego 	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
303*7f667e74Sjose borrego 		free(hd->nh_data);
304*7f667e74Sjose borrego 		hd->nh_data = NULL;
305*7f667e74Sjose borrego 	}
30689dc44ceSjose borrego 
30789dc44ceSjose borrego 	ndr_hdfree(mxa, id);
30889dc44ceSjose borrego 
30989dc44ceSjose borrego 	bzero(&param->result_handle, sizeof (winreg_handle_t));
31089dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
31189dc44ceSjose borrego 	return (NDR_DRC_OK);
31289dc44ceSjose borrego }
31389dc44ceSjose borrego 
31489dc44ceSjose borrego /*
31589dc44ceSjose borrego  * winreg_s_CreateKey
31689dc44ceSjose borrego  */
31789dc44ceSjose borrego static int
31889dc44ceSjose borrego winreg_s_CreateKey(void *arg, ndr_xa_t *mxa)
31989dc44ceSjose borrego {
32089dc44ceSjose borrego 	struct winreg_CreateKey *param = arg;
32189dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
32289dc44ceSjose borrego 	ndr_handle_t *hd;
32389dc44ceSjose borrego 	winreg_subkey_t *key;
32489dc44ceSjose borrego 	char *subkey;
325*7f667e74Sjose borrego 	char *dupkey;
32689dc44ceSjose borrego 	DWORD *action;
32789dc44ceSjose borrego 
32889dc44ceSjose borrego 	subkey = (char *)param->subkey.str;
32989dc44ceSjose borrego 
33089dc44ceSjose borrego 	if (!ndr_is_admin(mxa) || (subkey == NULL)) {
33189dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
33289dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
33389dc44ceSjose borrego 		return (NDR_DRC_OK);
33489dc44ceSjose borrego 	}
33589dc44ceSjose borrego 
33689dc44ceSjose borrego 	hd = ndr_hdlookup(mxa, id);
33789dc44ceSjose borrego 	if (hd == NULL) {
33889dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
33989dc44ceSjose borrego 		param->status = ERROR_INVALID_HANDLE;
34089dc44ceSjose borrego 		return (NDR_DRC_OK);
34189dc44ceSjose borrego 	}
34289dc44ceSjose borrego 
34389dc44ceSjose borrego 	if ((action = NDR_NEW(mxa, DWORD)) == NULL) {
34489dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
34589dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
34689dc44ceSjose borrego 		return (NDR_DRC_OK);
34789dc44ceSjose borrego 	}
34889dc44ceSjose borrego 
34989dc44ceSjose borrego 	if (list_is_empty(&winreg_keylist.kl_list))
35089dc44ceSjose borrego 		goto new_key;
35189dc44ceSjose borrego 
35289dc44ceSjose borrego 	/*
35389dc44ceSjose borrego 	 * Check for an existing key.
35489dc44ceSjose borrego 	 */
35589dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
35689dc44ceSjose borrego 	do {
35789dc44ceSjose borrego 		if (strcasecmp(subkey, key->sk_name) == 0) {
35889dc44ceSjose borrego 			bcopy(&key->sk_handle, &param->result_handle,
35989dc44ceSjose borrego 			    sizeof (winreg_handle_t));
36089dc44ceSjose borrego 			*action = WINREG_ACTION_EXISTING_KEY;
36189dc44ceSjose borrego 			param->action = action;
36289dc44ceSjose borrego 			param->status = ERROR_SUCCESS;
36389dc44ceSjose borrego 			return (NDR_DRC_OK);
36489dc44ceSjose borrego 		}
36589dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
36689dc44ceSjose borrego 
36789dc44ceSjose borrego new_key:
36889dc44ceSjose borrego 	/*
36989dc44ceSjose borrego 	 * Create a new key.
37089dc44ceSjose borrego 	 */
371*7f667e74Sjose borrego 	if ((dupkey = strdup(subkey)) == NULL) {
372*7f667e74Sjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
373*7f667e74Sjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
374*7f667e74Sjose borrego 		return (NDR_DRC_OK);
375*7f667e74Sjose borrego 	}
376*7f667e74Sjose borrego 
377*7f667e74Sjose borrego 	id = ndr_hdalloc(mxa, dupkey);
37889dc44ceSjose borrego 	key = malloc(sizeof (winreg_subkey_t));
37989dc44ceSjose borrego 
38089dc44ceSjose borrego 	if ((id == NULL) || (key == NULL)) {
381*7f667e74Sjose borrego 		free(dupkey);
38289dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_CreateKey));
38389dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
38489dc44ceSjose borrego 		return (NDR_DRC_OK);
38589dc44ceSjose borrego 	}
38689dc44ceSjose borrego 
38789dc44ceSjose borrego 	bcopy(id, &key->sk_handle, sizeof (ndr_hdid_t));
38889dc44ceSjose borrego 	(void) strlcpy(key->sk_name, subkey, MAXPATHLEN);
38989dc44ceSjose borrego 	key->sk_predefined = B_FALSE;
39089dc44ceSjose borrego 	list_insert_tail(&winreg_keylist.kl_list, key);
39189dc44ceSjose borrego 	++winreg_keylist.kl_count;
39289dc44ceSjose borrego 
39389dc44ceSjose borrego 	bcopy(id, &param->result_handle, sizeof (winreg_handle_t));
39489dc44ceSjose borrego 	*action = WINREG_ACTION_NEW_KEY;
39589dc44ceSjose borrego 	param->action = action;
39689dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
39789dc44ceSjose borrego 	return (NDR_DRC_OK);
39889dc44ceSjose borrego }
39989dc44ceSjose borrego 
40089dc44ceSjose borrego /*
40189dc44ceSjose borrego  * winreg_s_DeleteKey
40289dc44ceSjose borrego  */
40389dc44ceSjose borrego static int
40489dc44ceSjose borrego winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa)
40589dc44ceSjose borrego {
40689dc44ceSjose borrego 	struct winreg_DeleteKey *param = arg;
40789dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
408*7f667e74Sjose borrego 	ndr_handle_t *hd;
40989dc44ceSjose borrego 	winreg_subkey_t *key;
41089dc44ceSjose borrego 	char *subkey;
41189dc44ceSjose borrego 
41289dc44ceSjose borrego 	subkey = (char *)param->subkey.str;
41389dc44ceSjose borrego 
41489dc44ceSjose borrego 	if (!ndr_is_admin(mxa) || (subkey == NULL)) {
41589dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
41689dc44ceSjose borrego 		return (NDR_DRC_OK);
41789dc44ceSjose borrego 	}
41889dc44ceSjose borrego 
41989dc44ceSjose borrego 	if ((ndr_hdlookup(mxa, id) == NULL) ||
42089dc44ceSjose borrego 	    list_is_empty(&winreg_keylist.kl_list) ||
42189dc44ceSjose borrego 	    winreg_key_has_subkey(subkey)) {
42289dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
42389dc44ceSjose borrego 		return (NDR_DRC_OK);
42489dc44ceSjose borrego 	}
42589dc44ceSjose borrego 
42689dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
42789dc44ceSjose borrego 	do {
42889dc44ceSjose borrego 		if (strcasecmp(subkey, key->sk_name) == 0) {
42989dc44ceSjose borrego 			if (key->sk_predefined == B_TRUE) {
43089dc44ceSjose borrego 				/* Predefined keys cannot be deleted */
43189dc44ceSjose borrego 				break;
43289dc44ceSjose borrego 			}
43389dc44ceSjose borrego 
43489dc44ceSjose borrego 			list_remove(&winreg_keylist.kl_list, key);
43589dc44ceSjose borrego 			--winreg_keylist.kl_count;
436*7f667e74Sjose borrego 
437*7f667e74Sjose borrego 			hd = ndr_hdlookup(mxa, &key->sk_handle);
438*7f667e74Sjose borrego 			if (hd != NULL) {
439*7f667e74Sjose borrego 				free(hd->nh_data);
440*7f667e74Sjose borrego 				hd->nh_data = NULL;
441*7f667e74Sjose borrego 			}
442*7f667e74Sjose borrego 
44389dc44ceSjose borrego 			ndr_hdfree(mxa, &key->sk_handle);
44489dc44ceSjose borrego 			free(key);
44589dc44ceSjose borrego 			param->status = ERROR_SUCCESS;
44689dc44ceSjose borrego 			return (NDR_DRC_OK);
44789dc44ceSjose borrego 		}
44889dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
44989dc44ceSjose borrego 
45089dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
45189dc44ceSjose borrego 	return (NDR_DRC_OK);
45289dc44ceSjose borrego }
45389dc44ceSjose borrego 
45489dc44ceSjose borrego static boolean_t
45589dc44ceSjose borrego winreg_key_has_subkey(const char *subkey)
45689dc44ceSjose borrego {
45789dc44ceSjose borrego 	winreg_subkey_t *key;
45889dc44ceSjose borrego 	int keylen;
45989dc44ceSjose borrego 
46089dc44ceSjose borrego 	if (list_is_empty(&winreg_keylist.kl_list))
46189dc44ceSjose borrego 		return (B_FALSE);
46289dc44ceSjose borrego 
46389dc44ceSjose borrego 	keylen = strlen(subkey);
46489dc44ceSjose borrego 
46589dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
46689dc44ceSjose borrego 	do {
46789dc44ceSjose borrego 		if (strncasecmp(subkey, key->sk_name, keylen) == 0) {
46889dc44ceSjose borrego 			/*
46989dc44ceSjose borrego 			 * Potential match.  If sk_name is longer than
47089dc44ceSjose borrego 			 * subkey, then sk_name is a subkey of our key.
47189dc44ceSjose borrego 			 */
47289dc44ceSjose borrego 			if (keylen < strlen(key->sk_name))
47389dc44ceSjose borrego 				return (B_TRUE);
47489dc44ceSjose borrego 		}
47589dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
47689dc44ceSjose borrego 
47789dc44ceSjose borrego 	return (B_FALSE);
47889dc44ceSjose borrego }
47989dc44ceSjose borrego 
48089dc44ceSjose borrego static char *
481*7f667e74Sjose borrego winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index)
48289dc44ceSjose borrego {
48389dc44ceSjose borrego 	winreg_subkey_t *key;
484*7f667e74Sjose borrego 	char *entry;
485*7f667e74Sjose borrego 	char *p;
486*7f667e74Sjose borrego 	int subkeylen;
487*7f667e74Sjose borrego 	int count = 0;
48889dc44ceSjose borrego 
48989dc44ceSjose borrego 	if (subkey == NULL)
49089dc44ceSjose borrego 		return (NULL);
49189dc44ceSjose borrego 
49289dc44ceSjose borrego 	if (list_is_empty(&winreg_keylist.kl_list))
49389dc44ceSjose borrego 		return (NULL);
49489dc44ceSjose borrego 
495*7f667e74Sjose borrego 	subkeylen = strlen(subkey);
496*7f667e74Sjose borrego 
497*7f667e74Sjose borrego 	for (key = list_head(&winreg_keylist.kl_list);
498*7f667e74Sjose borrego 	    key != NULL; key = list_next(&winreg_keylist.kl_list, key)) {
499*7f667e74Sjose borrego 		if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) {
500*7f667e74Sjose borrego 			p = key->sk_name + subkeylen;
501*7f667e74Sjose borrego 
502*7f667e74Sjose borrego 			if ((*p != '\\') || (*p == '\0')) {
503*7f667e74Sjose borrego 				/*
504*7f667e74Sjose borrego 				 * Not the same subkey or an exact match.
505*7f667e74Sjose borrego 				 * We're looking for children of subkey.
506*7f667e74Sjose borrego 				 */
507*7f667e74Sjose borrego 				continue;
50889dc44ceSjose borrego 			}
509*7f667e74Sjose borrego 
510*7f667e74Sjose borrego 			++p;
511*7f667e74Sjose borrego 
512*7f667e74Sjose borrego 			if (count < index) {
513*7f667e74Sjose borrego 				++count;
514*7f667e74Sjose borrego 				continue;
515*7f667e74Sjose borrego 			}
516*7f667e74Sjose borrego 
517*7f667e74Sjose borrego 			if ((entry = NDR_STRDUP(mxa, p)) == NULL)
518*7f667e74Sjose borrego 				return (NULL);
519*7f667e74Sjose borrego 
520*7f667e74Sjose borrego 			if ((p = strchr(entry, '\\')) != NULL)
521*7f667e74Sjose borrego 				*p = '\0';
522*7f667e74Sjose borrego 
523*7f667e74Sjose borrego 			return (entry);
524*7f667e74Sjose borrego 		}
525*7f667e74Sjose borrego 	}
52689dc44ceSjose borrego 
52789dc44ceSjose borrego 	return (NULL);
52889dc44ceSjose borrego }
52989dc44ceSjose borrego 
53089dc44ceSjose borrego /*
53189dc44ceSjose borrego  * winreg_s_DeleteValue
53289dc44ceSjose borrego  */
53389dc44ceSjose borrego /*ARGSUSED*/
53489dc44ceSjose borrego static int
53589dc44ceSjose borrego winreg_s_DeleteValue(void *arg, ndr_xa_t *mxa)
53689dc44ceSjose borrego {
53789dc44ceSjose borrego 	struct winreg_DeleteValue *param = arg;
53889dc44ceSjose borrego 
53989dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
54089dc44ceSjose borrego 	return (NDR_DRC_OK);
54189dc44ceSjose borrego }
54289dc44ceSjose borrego 
54389dc44ceSjose borrego /*
54489dc44ceSjose borrego  * winreg_s_EnumKey
54589dc44ceSjose borrego  */
54689dc44ceSjose borrego static int
54789dc44ceSjose borrego winreg_s_EnumKey(void *arg, ndr_xa_t *mxa)
54889dc44ceSjose borrego {
54989dc44ceSjose borrego 	struct winreg_EnumKey *param = arg;
55089dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
551*7f667e74Sjose borrego 	ndr_handle_t *hd;
552*7f667e74Sjose borrego 	char *subkey;
553*7f667e74Sjose borrego 	char *name = NULL;
55489dc44ceSjose borrego 
555*7f667e74Sjose borrego 	if ((hd = ndr_hdlookup(mxa, id)) != NULL)
556*7f667e74Sjose borrego 		name = hd->nh_data;
557*7f667e74Sjose borrego 
558*7f667e74Sjose borrego 	if (hd == NULL || name == NULL) {
55989dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumKey));
56089dc44ceSjose borrego 		param->status = ERROR_NO_MORE_ITEMS;
56189dc44ceSjose borrego 		return (NDR_DRC_OK);
56289dc44ceSjose borrego 	}
56389dc44ceSjose borrego 
564*7f667e74Sjose borrego 	subkey = winreg_enum_subkey(mxa, name, param->index);
565*7f667e74Sjose borrego 	if (subkey == NULL) {
56689dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumKey));
56789dc44ceSjose borrego 		param->status = ERROR_NO_MORE_ITEMS;
56889dc44ceSjose borrego 		return (NDR_DRC_OK);
56989dc44ceSjose borrego 	}
57089dc44ceSjose borrego 
571*7f667e74Sjose borrego 	if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)&param->name_out) == -1) {
57289dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumKey));
57389dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
57489dc44ceSjose borrego 		return (NDR_DRC_OK);
57589dc44ceSjose borrego 	}
576*7f667e74Sjose borrego 	/*
577*7f667e74Sjose borrego 	 * This request requires that the length includes the null.
578*7f667e74Sjose borrego 	 */
579*7f667e74Sjose borrego 	param->name_out.length = param->name_out.allosize;
58089dc44ceSjose borrego 
58189dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
58289dc44ceSjose borrego 	return (NDR_DRC_OK);
58389dc44ceSjose borrego }
58489dc44ceSjose borrego 
58589dc44ceSjose borrego /*
58689dc44ceSjose borrego  * winreg_s_EnumValue
58789dc44ceSjose borrego  */
58889dc44ceSjose borrego static int
58989dc44ceSjose borrego winreg_s_EnumValue(void *arg, ndr_xa_t *mxa)
59089dc44ceSjose borrego {
59189dc44ceSjose borrego 	struct winreg_EnumValue *param = arg;
59289dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
59389dc44ceSjose borrego 
59489dc44ceSjose borrego 	if (ndr_hdlookup(mxa, id) == NULL) {
59589dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_EnumValue));
59689dc44ceSjose borrego 		param->status = ERROR_NO_MORE_ITEMS;
59789dc44ceSjose borrego 		return (NDR_DRC_OK);
59889dc44ceSjose borrego 	}
59989dc44ceSjose borrego 
60089dc44ceSjose borrego 	bzero(param, sizeof (struct winreg_EnumValue));
60189dc44ceSjose borrego 	param->status = ERROR_NO_MORE_ITEMS;
60289dc44ceSjose borrego 	return (NDR_DRC_OK);
60389dc44ceSjose borrego }
60489dc44ceSjose borrego 
60589dc44ceSjose borrego /*
60689dc44ceSjose borrego  * winreg_s_FlushKey
60789dc44ceSjose borrego  *
60889dc44ceSjose borrego  * Flush the attributes associated with the specified open key to disk.
60989dc44ceSjose borrego  */
61089dc44ceSjose borrego static int
61189dc44ceSjose borrego winreg_s_FlushKey(void *arg, ndr_xa_t *mxa)
61289dc44ceSjose borrego {
61389dc44ceSjose borrego 	struct winreg_FlushKey *param = arg;
61489dc44ceSjose borrego 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
61589dc44ceSjose borrego 
61689dc44ceSjose borrego 	if (ndr_hdlookup(mxa, id) == NULL)
61789dc44ceSjose borrego 		param->status = ERROR_INVALID_HANDLE;
61889dc44ceSjose borrego 	else
61989dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
62089dc44ceSjose borrego 
62189dc44ceSjose borrego 	return (NDR_DRC_OK);
62289dc44ceSjose borrego }
62389dc44ceSjose borrego 
62489dc44ceSjose borrego /*
62589dc44ceSjose borrego  * winreg_s_GetKeySec
62689dc44ceSjose borrego  */
62789dc44ceSjose borrego /*ARGSUSED*/
62889dc44ceSjose borrego static int
62989dc44ceSjose borrego winreg_s_GetKeySec(void *arg, ndr_xa_t *mxa)
63089dc44ceSjose borrego {
63189dc44ceSjose borrego 	struct winreg_GetKeySec *param = arg;
63289dc44ceSjose borrego 
63389dc44ceSjose borrego 	bzero(param, sizeof (struct winreg_GetKeySec));
63489dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
63589dc44ceSjose borrego 	return (NDR_DRC_OK);
63689dc44ceSjose borrego }
63789dc44ceSjose borrego 
63889dc44ceSjose borrego /*
63989dc44ceSjose borrego  * winreg_s_NotifyChange
64089dc44ceSjose borrego  */
64189dc44ceSjose borrego static int
64289dc44ceSjose borrego winreg_s_NotifyChange(void *arg, ndr_xa_t *mxa)
64389dc44ceSjose borrego {
64489dc44ceSjose borrego 	struct winreg_NotifyChange *param = arg;
64589dc44ceSjose borrego 
64689dc44ceSjose borrego 	if (ndr_is_admin(mxa))
64789dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
64889dc44ceSjose borrego 	else
64989dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
65089dc44ceSjose borrego 
65189dc44ceSjose borrego 	return (NDR_DRC_OK);
65289dc44ceSjose borrego }
65389dc44ceSjose borrego 
65489dc44ceSjose borrego /*
65589dc44ceSjose borrego  * winreg_s_OpenKey
65689dc44ceSjose borrego  *
65789dc44ceSjose borrego  * This is a request to open a windows registry key.
65889dc44ceSjose borrego  * If we recognize the key, we return a handle.
65989dc44ceSjose borrego  *
66089dc44ceSjose borrego  * Returns:
66189dc44ceSjose borrego  *	ERROR_SUCCESS		Valid handle returned.
66289dc44ceSjose borrego  *	ERROR_FILE_NOT_FOUND	No key or unable to allocate a handle.
66389dc44ceSjose borrego  */
66489dc44ceSjose borrego static int
66589dc44ceSjose borrego winreg_s_OpenKey(void *arg, ndr_xa_t *mxa)
66689dc44ceSjose borrego {
66789dc44ceSjose borrego 	struct winreg_OpenKey *param = arg;
66889dc44ceSjose borrego 	char *subkey = (char *)param->name.str;
66989dc44ceSjose borrego 	ndr_hdid_t *id = NULL;
67089dc44ceSjose borrego 	winreg_subkey_t *key;
671*7f667e74Sjose borrego 	char *dupkey;
67289dc44ceSjose borrego 
673*7f667e74Sjose borrego 	if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) {
67489dc44ceSjose borrego 		bzero(&param->result_handle, sizeof (winreg_handle_t));
67589dc44ceSjose borrego 		param->status = ERROR_FILE_NOT_FOUND;
67689dc44ceSjose borrego 		return (NDR_DRC_OK);
67789dc44ceSjose borrego 	}
67889dc44ceSjose borrego 
67989dc44ceSjose borrego 	key = list_head(&winreg_keylist.kl_list);
68089dc44ceSjose borrego 	do {
68189dc44ceSjose borrego 		if (strcasecmp(subkey, key->sk_name) == 0) {
682*7f667e74Sjose borrego 			if (key->sk_predefined == B_TRUE) {
683*7f667e74Sjose borrego 				if ((dupkey = strdup(subkey)) == NULL)
684*7f667e74Sjose borrego 					break;
685*7f667e74Sjose borrego 
686*7f667e74Sjose borrego 				id = ndr_hdalloc(mxa, dupkey);
687*7f667e74Sjose borrego 				if (id == NULL)
688*7f667e74Sjose borrego 					free(dupkey);
689*7f667e74Sjose borrego 			} else {
69089dc44ceSjose borrego 				id = &key->sk_handle;
691*7f667e74Sjose borrego 			}
69289dc44ceSjose borrego 
69389dc44ceSjose borrego 			if (id == NULL)
69489dc44ceSjose borrego 				break;
69589dc44ceSjose borrego 
69689dc44ceSjose borrego 			bcopy(id, &param->result_handle,
69789dc44ceSjose borrego 			    sizeof (winreg_handle_t));
69889dc44ceSjose borrego 			param->status = ERROR_SUCCESS;
69989dc44ceSjose borrego 			return (NDR_DRC_OK);
70089dc44ceSjose borrego 		}
70189dc44ceSjose borrego 	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
70289dc44ceSjose borrego 
70389dc44ceSjose borrego 	bzero(&param->result_handle, sizeof (winreg_handle_t));
70489dc44ceSjose borrego 	param->status = ERROR_FILE_NOT_FOUND;
70589dc44ceSjose borrego 	return (NDR_DRC_OK);
70689dc44ceSjose borrego }
70789dc44ceSjose borrego 
70889dc44ceSjose borrego /*
70989dc44ceSjose borrego  * winreg_s_QueryKey
71089dc44ceSjose borrego  */
71189dc44ceSjose borrego /*ARGSUSED*/
71289dc44ceSjose borrego static int
71389dc44ceSjose borrego winreg_s_QueryKey(void *arg, ndr_xa_t *mxa)
71489dc44ceSjose borrego {
71589dc44ceSjose borrego 	struct winreg_QueryKey *param = arg;
71689dc44ceSjose borrego 	int rc;
71789dc44ceSjose borrego 	winreg_string_t	*name;
71889dc44ceSjose borrego 
71989dc44ceSjose borrego 	name = (winreg_string_t	*)&param->name;
72089dc44ceSjose borrego 	bzero(param, sizeof (struct winreg_QueryKey));
72189dc44ceSjose borrego 	if ((name = NDR_NEW(mxa, winreg_string_t)) != NULL)
72289dc44ceSjose borrego 		rc = NDR_MSTRING(mxa, "", (ndr_mstring_t *)name);
72389dc44ceSjose borrego 
72489dc44ceSjose borrego 	if ((name == NULL) || (rc != 0)) {
72589dc44ceSjose borrego 		bzero(param, sizeof (struct winreg_QueryKey));
72689dc44ceSjose borrego 		param->status = ERROR_NOT_ENOUGH_MEMORY;
72789dc44ceSjose borrego 		return (NDR_DRC_OK);
72889dc44ceSjose borrego 	}
72989dc44ceSjose borrego 
73089dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
73189dc44ceSjose borrego 	return (NDR_DRC_OK);
73289dc44ceSjose borrego }
73389dc44ceSjose borrego 
73489dc44ceSjose borrego /*
73589dc44ceSjose borrego  * winreg_s_QueryValue
73689dc44ceSjose borrego  *
73789dc44ceSjose borrego  * This is a request to get the value associated with a specified name.
73889dc44ceSjose borrego  *
73989dc44ceSjose borrego  * Returns:
74089dc44ceSjose borrego  *	ERROR_SUCCESS		Value returned.
74189dc44ceSjose borrego  *	ERROR_FILE_NOT_FOUND	PrimaryModule is not supported.
74289dc44ceSjose borrego  *	ERROR_CANTREAD          No such name or memory problem.
74389dc44ceSjose borrego  */
74489dc44ceSjose borrego static int
74589dc44ceSjose borrego winreg_s_QueryValue(void *arg, ndr_xa_t *mxa)
74689dc44ceSjose borrego {
74789dc44ceSjose borrego 	struct winreg_QueryValue *param = arg;
74889dc44ceSjose borrego 	struct winreg_value *pv;
74989dc44ceSjose borrego 	char *name;
75089dc44ceSjose borrego 	char *value;
75189dc44ceSjose borrego 	DWORD slen;
75289dc44ceSjose borrego 	DWORD msize;
75389dc44ceSjose borrego 
75489dc44ceSjose borrego 	name = (char *)param->value_name.str;
75589dc44ceSjose borrego 
75689dc44ceSjose borrego 	if (strcasecmp(name, "PrimaryModule") == 0) {
75789dc44ceSjose borrego 		param->status = ERROR_FILE_NOT_FOUND;
75889dc44ceSjose borrego 		return (NDR_DRC_OK);
75989dc44ceSjose borrego 	}
76089dc44ceSjose borrego 
76189dc44ceSjose borrego 	if ((value = winreg_lookup_value(name)) == NULL) {
76289dc44ceSjose borrego 		param->status = ERROR_CANTREAD;
76389dc44ceSjose borrego 		return (NDR_DRC_OK);
76489dc44ceSjose borrego 	}
76589dc44ceSjose borrego 
76689dc44ceSjose borrego 	slen = mts_wcequiv_strlen(value) + sizeof (mts_wchar_t);
76789dc44ceSjose borrego 	msize = sizeof (struct winreg_value) + slen;
76889dc44ceSjose borrego 
76989dc44ceSjose borrego 	param->value = (struct winreg_value *)NDR_MALLOC(mxa, msize);
77089dc44ceSjose borrego 	param->type = NDR_NEW(mxa, DWORD);
77189dc44ceSjose borrego 	param->value_size = NDR_NEW(mxa, DWORD);
77289dc44ceSjose borrego 	param->value_size_total = NDR_NEW(mxa, DWORD);
77389dc44ceSjose borrego 
77489dc44ceSjose borrego 	if (param->value == NULL || param->type == NULL ||
77589dc44ceSjose borrego 	    param->value_size == NULL || param->value_size_total == NULL) {
77689dc44ceSjose borrego 		param->status = ERROR_CANTREAD;
77789dc44ceSjose borrego 		return (NDR_DRC_OK);
77889dc44ceSjose borrego 	}
77989dc44ceSjose borrego 
78089dc44ceSjose borrego 	bzero(param->value, msize);
78189dc44ceSjose borrego 	pv = param->value;
78289dc44ceSjose borrego 	pv->vc_first_is = 0;
78389dc44ceSjose borrego 	pv->vc_length_is = slen;
78489dc44ceSjose borrego 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
78589dc44ceSjose borrego 	(void) ndr_mbstowcs(NULL, (mts_wchar_t *)pv->value, value, slen);
78689dc44ceSjose borrego 
78789dc44ceSjose borrego 	*param->type = 1;
78889dc44ceSjose borrego 	*param->value_size = slen;
78989dc44ceSjose borrego 	*param->value_size_total = slen;
79089dc44ceSjose borrego 
79189dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
79289dc44ceSjose borrego 	return (NDR_DRC_OK);
79389dc44ceSjose borrego }
79489dc44ceSjose borrego 
79589dc44ceSjose borrego /*
79689dc44ceSjose borrego  * Lookup a name in the registry and return the associated value.
79789dc44ceSjose borrego  * Our registry is a case-insensitive, name-value pair table.
79889dc44ceSjose borrego  *
79989dc44ceSjose borrego  * Windows ProductType: WinNT, ServerNT, LanmanNT.
80089dc44ceSjose borrego  *	Windows NT4.0 workstation: WinNT
80189dc44ceSjose borrego  *	Windows NT4.0 server:      ServerNT
80289dc44ceSjose borrego  *
80389dc44ceSjose borrego  * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy
80489dc44ceSjose borrego  * with info level 6, which we don't support.  If we use ServerNT
80589dc44ceSjose borrego  * (as reported by NT4.0 Server) Windows 2000 send requests for
80689dc44ceSjose borrego  * levels 3 and 5, which are support.
80789dc44ceSjose borrego  *
80889dc44ceSjose borrego  * On success, returns a pointer to the value.  Otherwise returns
80989dc44ceSjose borrego  * a null pointer.
81089dc44ceSjose borrego  */
81189dc44ceSjose borrego static char *
81289dc44ceSjose borrego winreg_lookup_value(const char *name)
81389dc44ceSjose borrego {
81489dc44ceSjose borrego 	static struct registry {
81589dc44ceSjose borrego 		char *name;
81689dc44ceSjose borrego 		char *value;
81789dc44ceSjose borrego 	} registry[] = {
81889dc44ceSjose borrego 		{ "ProductType", "ServerNT" },
81989dc44ceSjose borrego 		{ "Sources",	 NULL }	/* product name */
82089dc44ceSjose borrego 	};
82189dc44ceSjose borrego 
82289dc44ceSjose borrego 	int i;
82389dc44ceSjose borrego 
82489dc44ceSjose borrego 	for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) {
82589dc44ceSjose borrego 		if (strcasecmp(registry[i].name, name) == 0) {
82689dc44ceSjose borrego 			if (registry[i].value == NULL)
82789dc44ceSjose borrego 				return (winreg_sysname);
82889dc44ceSjose borrego 			else
82989dc44ceSjose borrego 				return (registry[i].value);
83089dc44ceSjose borrego 		}
83189dc44ceSjose borrego 	}
83289dc44ceSjose borrego 
83389dc44ceSjose borrego 	return (NULL);
83489dc44ceSjose borrego }
83589dc44ceSjose borrego 
83689dc44ceSjose borrego /*
83789dc44ceSjose borrego  * winreg_s_SetKeySec
83889dc44ceSjose borrego  */
83989dc44ceSjose borrego /*ARGSUSED*/
84089dc44ceSjose borrego static int
84189dc44ceSjose borrego winreg_s_SetKeySec(void *arg, ndr_xa_t *mxa)
84289dc44ceSjose borrego {
84389dc44ceSjose borrego 	struct winreg_SetKeySec *param = arg;
84489dc44ceSjose borrego 
84589dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
84689dc44ceSjose borrego 	return (NDR_DRC_OK);
84789dc44ceSjose borrego }
84889dc44ceSjose borrego 
84989dc44ceSjose borrego /*
85089dc44ceSjose borrego  * winreg_s_CreateValue
85189dc44ceSjose borrego  */
85289dc44ceSjose borrego /*ARGSUSED*/
85389dc44ceSjose borrego static int
85489dc44ceSjose borrego winreg_s_CreateValue(void *arg, ndr_xa_t *mxa)
85589dc44ceSjose borrego {
85689dc44ceSjose borrego 	struct winreg_CreateValue *param = arg;
85789dc44ceSjose borrego 
85889dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
85989dc44ceSjose borrego 	return (NDR_DRC_OK);
86089dc44ceSjose borrego }
86189dc44ceSjose borrego 
86289dc44ceSjose borrego /*
86389dc44ceSjose borrego  * winreg_s_Shutdown
86489dc44ceSjose borrego  *
86589dc44ceSjose borrego  * Attempt to shutdown or reboot the system: access denied.
86689dc44ceSjose borrego  */
86789dc44ceSjose borrego /*ARGSUSED*/
86889dc44ceSjose borrego static int
86989dc44ceSjose borrego winreg_s_Shutdown(void *arg, ndr_xa_t *mxa)
87089dc44ceSjose borrego {
87189dc44ceSjose borrego 	struct winreg_Shutdown *param = arg;
87289dc44ceSjose borrego 
87389dc44ceSjose borrego 	param->status = ERROR_ACCESS_DENIED;
87489dc44ceSjose borrego 	return (NDR_DRC_OK);
87589dc44ceSjose borrego }
87689dc44ceSjose borrego 
87789dc44ceSjose borrego /*
87889dc44ceSjose borrego  * winreg_s_AbortShutdown
87989dc44ceSjose borrego  *
88089dc44ceSjose borrego  * Abort a shutdown request.
88189dc44ceSjose borrego  */
88289dc44ceSjose borrego static int
88389dc44ceSjose borrego winreg_s_AbortShutdown(void *arg, ndr_xa_t *mxa)
88489dc44ceSjose borrego {
88589dc44ceSjose borrego 	struct winreg_AbortShutdown *param = arg;
88689dc44ceSjose borrego 
88789dc44ceSjose borrego 	if (ndr_is_admin(mxa))
88889dc44ceSjose borrego 		param->status = ERROR_SUCCESS;
88989dc44ceSjose borrego 	else
89089dc44ceSjose borrego 		param->status = ERROR_ACCESS_DENIED;
89189dc44ceSjose borrego 
89289dc44ceSjose borrego 	return (NDR_DRC_OK);
89389dc44ceSjose borrego }
89489dc44ceSjose borrego 
89589dc44ceSjose borrego /*
89689dc44ceSjose borrego  * winreg_s_GetVersion
89789dc44ceSjose borrego  *
89889dc44ceSjose borrego  * Return the windows registry version.  The current version is 5.
89989dc44ceSjose borrego  * This call is usually made prior to enumerating or querying registry
90089dc44ceSjose borrego  * keys or values.
90189dc44ceSjose borrego  */
90289dc44ceSjose borrego /*ARGSUSED*/
90389dc44ceSjose borrego static int
90489dc44ceSjose borrego winreg_s_GetVersion(void *arg, ndr_xa_t *mxa)
90589dc44ceSjose borrego {
90689dc44ceSjose borrego 	struct winreg_GetVersion *param = arg;
90789dc44ceSjose borrego 
90889dc44ceSjose borrego 	param->version = 5;
90989dc44ceSjose borrego 	param->status = ERROR_SUCCESS;
91089dc44ceSjose borrego 	return (NDR_DRC_OK);
91189dc44ceSjose borrego }
912