/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ /* * Windows Registry RPC (WINREG) server-side interface. * * The registry is a database with a hierarchical structure similar to * a file system, with keys in place of directories and values in place * of files. The top level keys are known as root keys and each key can * contain subkeys and values. As with directories and sub-directories, * the terms key and subkey are used interchangeably. Values, analogous * to files, contain data. * * A specific subkey can be identifies by its fully qualified name (FQN), * which is analogous to a file system path. In the registry, the key * separator is the '\' character, which is reserved and cannot appear * in key or value names. Registry names are case-insensitive. * * For example: HKEY_LOCAL_MACHINE\System\CurrentControlSet * * The HKEY_LOCAL_MACHINE root key contains a subkey called System, and * System contains a subkey called CurrentControlSet. * * The WINREG RPC interface returns Win32 error codes. */ #include #include #include #include #include #include /* * List of supported registry keys (case-insensitive). */ static char *winreg_keys[] = { "HKLM", "HKU", "HKLM\\SOFTWARE", "HKLM\\SYSTEM", "System", "CurrentControlSet", "SunOS", "Solaris", "System\\CurrentControlSet\\Services\\Eventlog", "System\\CurrentControlSet\\Control\\ProductOptions", "SOFTWARE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" }; static char *winreg_eventlog = "System\\CurrentControlSet\\Services\\Eventlog"; static char *winreg_log[] = { "Application", "Security", "System", "smbd", "smbrdr" }; typedef struct winreg_subkey { list_node_t sk_lnd; ndr_hdid_t sk_handle; char sk_name[MAXPATHLEN]; boolean_t sk_predefined; } winreg_subkey_t; typedef struct winreg_keylist { list_t kl_list; int kl_count; } winreg_keylist_t; static winreg_keylist_t winreg_keylist; static mutex_t winreg_mutex; static void winreg_add_predefined(const char *); static ndr_hdid_t *winreg_alloc_id(ndr_xa_t *, const char *); static void winreg_dealloc_id(ndr_xa_t *, ndr_hdid_t *); static boolean_t winreg_key_has_subkey(const char *); static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t); static char *winreg_lookup_value(const char *); static uint32_t winreg_sd_format(smb_sd_t *); uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); static int winreg_s_OpenHKCR(void *, ndr_xa_t *); static int winreg_s_OpenHKCU(void *, ndr_xa_t *); static int winreg_s_OpenHKLM(void *, ndr_xa_t *); static int winreg_s_OpenHKPD(void *, ndr_xa_t *); static int winreg_s_OpenHKU(void *, ndr_xa_t *); static int winreg_s_OpenHKCC(void *, ndr_xa_t *); static int winreg_s_OpenHKDD(void *, ndr_xa_t *); static int winreg_s_OpenHKPT(void *, ndr_xa_t *); static int winreg_s_OpenHKPN(void *, ndr_xa_t *); static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *); static int winreg_s_Close(void *, ndr_xa_t *); static int winreg_s_CreateKey(void *, ndr_xa_t *); static int winreg_s_DeleteKey(void *, ndr_xa_t *); static int winreg_s_DeleteValue(void *, ndr_xa_t *); static int winreg_s_EnumKey(void *, ndr_xa_t *); static int winreg_s_EnumValue(void *, ndr_xa_t *); static int winreg_s_FlushKey(void *, ndr_xa_t *); static int winreg_s_GetKeySec(void *, ndr_xa_t *); static int winreg_s_NotifyChange(void *, ndr_xa_t *); static int winreg_s_OpenKey(void *, ndr_xa_t *); static int winreg_s_QueryKey(void *, ndr_xa_t *); static int winreg_s_QueryValue(void *, ndr_xa_t *); static int winreg_s_SetKeySec(void *, ndr_xa_t *); static int winreg_s_CreateValue(void *, ndr_xa_t *); static int winreg_s_Shutdown(void *, ndr_xa_t *); static int winreg_s_AbortShutdown(void *, ndr_xa_t *); static int winreg_s_GetVersion(void *, ndr_xa_t *); static ndr_stub_table_t winreg_stub_table[] = { { winreg_s_OpenHKCR, WINREG_OPNUM_OpenHKCR }, { winreg_s_OpenHKCU, WINREG_OPNUM_OpenHKCU }, { winreg_s_OpenHKLM, WINREG_OPNUM_OpenHKLM }, { winreg_s_OpenHKPD, WINREG_OPNUM_OpenHKPD }, { winreg_s_OpenHKU, WINREG_OPNUM_OpenHKUsers }, { winreg_s_Close, WINREG_OPNUM_Close }, { winreg_s_CreateKey, WINREG_OPNUM_CreateKey }, { winreg_s_DeleteKey, WINREG_OPNUM_DeleteKey }, { winreg_s_DeleteValue, WINREG_OPNUM_DeleteValue }, { winreg_s_EnumKey, WINREG_OPNUM_EnumKey }, { winreg_s_EnumValue, WINREG_OPNUM_EnumValue }, { winreg_s_FlushKey, WINREG_OPNUM_FlushKey }, { winreg_s_GetKeySec, WINREG_OPNUM_GetKeySec }, { winreg_s_NotifyChange, WINREG_OPNUM_NotifyChange }, { winreg_s_OpenKey, WINREG_OPNUM_OpenKey }, { winreg_s_QueryKey, WINREG_OPNUM_QueryKey }, { winreg_s_QueryValue, WINREG_OPNUM_QueryValue }, { winreg_s_SetKeySec, WINREG_OPNUM_SetKeySec }, { winreg_s_CreateValue, WINREG_OPNUM_CreateValue }, { winreg_s_Shutdown, WINREG_OPNUM_Shutdown }, { winreg_s_AbortShutdown, WINREG_OPNUM_AbortShutdown }, { winreg_s_GetVersion, WINREG_OPNUM_GetVersion }, { winreg_s_OpenHKCC, WINREG_OPNUM_OpenHKCC }, { winreg_s_OpenHKDD, WINREG_OPNUM_OpenHKDD }, { winreg_s_OpenHKPT, WINREG_OPNUM_OpenHKPT }, { winreg_s_OpenHKPN, WINREG_OPNUM_OpenHKPN }, {0} }; static ndr_service_t winreg_service = { "Winreg", /* name */ "Windows Registry", /* desc */ "\\winreg", /* endpoint */ PIPE_WINREG, /* sec_addr_port */ "338cd001-2244-31f1-aaaa-900038001003", 1, /* abstract */ NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 0, /* no bind_instance_size */ 0, /* no bind_req() */ 0, /* no unbind_and_close() */ 0, /* use generic_call_stub() */ &TYPEINFO(winreg_interface), /* interface ti */ winreg_stub_table /* stub_table */ }; static char winreg_sysname[SYS_NMLN]; static char winreg_sysver[SMB_VERSTR_LEN]; /* * winreg_initialize * * Initialize and register the WINREG RPC interface with the RPC runtime * library. It must be called in order to use either the client side * or the server side functions. */ void winreg_initialize(void) { smb_version_t version; struct utsname name; char subkey[MAXPATHLEN]; char *sysname; int i; (void) mutex_lock(&winreg_mutex); list_create(&winreg_keylist.kl_list, sizeof (winreg_subkey_t), offsetof(winreg_subkey_t, sk_lnd)); winreg_keylist.kl_count = 0; for (i = 0; i < sizeof (winreg_keys)/sizeof (winreg_keys[0]); ++i) winreg_add_predefined(winreg_keys[i]); for (i = 0; i < sizeof (winreg_log)/sizeof (winreg_log[0]); ++i) { (void) snprintf(subkey, MAXPATHLEN, "%s", winreg_log[i]); winreg_add_predefined(subkey); (void) snprintf(subkey, MAXPATHLEN, "%s\\%s", winreg_eventlog, winreg_log[i]); winreg_add_predefined(subkey); (void) snprintf(subkey, MAXPATHLEN, "%s\\%s\\%s", winreg_eventlog, winreg_log[i], winreg_log[i]); winreg_add_predefined(subkey); } (void) mutex_unlock(&winreg_mutex); if (uname(&name) < 0) sysname = "Solaris"; else sysname = name.sysname; (void) strlcpy(winreg_sysname, sysname, SYS_NMLN); smb_config_get_version(&version); (void) snprintf(winreg_sysver, SMB_VERSTR_LEN, "%d.%d", version.sv_major, version.sv_minor); (void) ndr_svc_register(&winreg_service); } static void winreg_add_predefined(const char *subkey) { winreg_subkey_t *key; if ((key = malloc(sizeof (winreg_subkey_t))) != NULL) { bzero(key, sizeof (winreg_subkey_t)); (void) strlcpy(key->sk_name, subkey, MAXPATHLEN); key->sk_predefined = B_TRUE; list_insert_tail(&winreg_keylist.kl_list, key); ++winreg_keylist.kl_count; } } static int winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKCR")); } static int winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKCU")); } static int winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKLM")); } static int winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKPD")); } static int winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKU")); } static int winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKCC")); } static int winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKDD")); } static int winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKPT")); } static int winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa) { return (winreg_s_OpenHK(arg, mxa, "HKPN")); } /* * winreg_s_OpenHK * * Common code to open root HKEYs. */ static int winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey) { struct winreg_OpenHKCR *param = arg; ndr_hdid_t *id; (void) mutex_lock(&winreg_mutex); if ((id = winreg_alloc_id(mxa, hkey)) == NULL) { bzero(¶m->handle, sizeof (winreg_handle_t)); param->status = ERROR_ACCESS_DENIED; } else { bcopy(id, ¶m->handle, sizeof (winreg_handle_t)); param->status = ERROR_SUCCESS; } (void) mutex_unlock(&winreg_mutex); return (NDR_DRC_OK); } /* * winreg_s_Close * * This is a request to close the WINREG interface specified by the * handle. We don't track handles (yet), so just zero out the handle * and return NDR_DRC_OK. Setting the handle to zero appears to be * standard behaviour. */ static int winreg_s_Close(void *arg, ndr_xa_t *mxa) { struct winreg_Close *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; (void) mutex_lock(&winreg_mutex); winreg_dealloc_id(mxa, id); (void) mutex_unlock(&winreg_mutex); bzero(¶m->result_handle, sizeof (winreg_handle_t)); param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } static ndr_hdid_t * winreg_alloc_id(ndr_xa_t *mxa, const char *key) { ndr_handle_t *hd; ndr_hdid_t *id; char *data; if ((data = strdup(key)) == NULL) return (NULL); if ((id = ndr_hdalloc(mxa, data)) == NULL) { free(data); return (NULL); } if ((hd = ndr_hdlookup(mxa, id)) != NULL) hd->nh_data_free = free; return (id); } static void winreg_dealloc_id(ndr_xa_t *mxa, ndr_hdid_t *id) { ndr_handle_t *hd; if ((hd = ndr_hdlookup(mxa, id)) != NULL) { free(hd->nh_data); hd->nh_data = NULL; } ndr_hdfree(mxa, id); } /* * winreg_s_CreateKey */ static int winreg_s_CreateKey(void *arg, ndr_xa_t *mxa) { struct winreg_CreateKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; ndr_handle_t *hd; winreg_subkey_t *key; char *subkey; DWORD *action; subkey = (char *)param->subkey.str; if (!ndr_is_admin(mxa) || (subkey == NULL)) { bzero(param, sizeof (struct winreg_CreateKey)); param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } (void) mutex_lock(&winreg_mutex); hd = ndr_hdlookup(mxa, id); if (hd == NULL) { (void) mutex_unlock(&winreg_mutex); bzero(param, sizeof (struct winreg_CreateKey)); param->status = ERROR_INVALID_HANDLE; return (NDR_DRC_OK); } if ((action = NDR_NEW(mxa, DWORD)) == NULL) { (void) mutex_unlock(&winreg_mutex); bzero(param, sizeof (struct winreg_CreateKey)); param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); } if (list_is_empty(&winreg_keylist.kl_list)) goto new_key; /* * Check for an existing key. */ key = list_head(&winreg_keylist.kl_list); do { if (strcasecmp(subkey, key->sk_name) == 0) { bcopy(&key->sk_handle, ¶m->result_handle, sizeof (winreg_handle_t)); (void) mutex_unlock(&winreg_mutex); *action = WINREG_ACTION_EXISTING_KEY; param->action = action; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); new_key: /* * Create a new key. */ if ((id = winreg_alloc_id(mxa, subkey)) == NULL) goto no_memory; if ((key = malloc(sizeof (winreg_subkey_t))) == NULL) { winreg_dealloc_id(mxa, id); goto no_memory; } bcopy(id, &key->sk_handle, sizeof (ndr_hdid_t)); (void) strlcpy(key->sk_name, subkey, MAXPATHLEN); key->sk_predefined = B_FALSE; list_insert_tail(&winreg_keylist.kl_list, key); ++winreg_keylist.kl_count; bcopy(id, ¶m->result_handle, sizeof (winreg_handle_t)); (void) mutex_unlock(&winreg_mutex); *action = WINREG_ACTION_NEW_KEY; param->action = action; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); no_memory: (void) mutex_unlock(&winreg_mutex); bzero(param, sizeof (struct winreg_CreateKey)); param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); } /* * winreg_s_DeleteKey */ static int winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa) { struct winreg_DeleteKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; winreg_subkey_t *key; char *subkey; subkey = (char *)param->subkey.str; if (!ndr_is_admin(mxa) || (subkey == NULL)) { param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } (void) mutex_lock(&winreg_mutex); if ((ndr_hdlookup(mxa, id) == NULL) || list_is_empty(&winreg_keylist.kl_list) || winreg_key_has_subkey(subkey)) { (void) mutex_unlock(&winreg_mutex); param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } key = list_head(&winreg_keylist.kl_list); do { if (strcasecmp(subkey, key->sk_name) == 0) { if (key->sk_predefined == B_TRUE) { /* Predefined keys cannot be deleted */ break; } list_remove(&winreg_keylist.kl_list, key); --winreg_keylist.kl_count; winreg_dealloc_id(mxa, &key->sk_handle); free(key); (void) mutex_unlock(&winreg_mutex); param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); (void) mutex_unlock(&winreg_mutex); param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * Call with the winreg_mutex held. */ static boolean_t winreg_key_has_subkey(const char *subkey) { winreg_subkey_t *key; int keylen; if (list_is_empty(&winreg_keylist.kl_list)) return (B_FALSE); keylen = strlen(subkey); key = list_head(&winreg_keylist.kl_list); do { if (strncasecmp(subkey, key->sk_name, keylen) == 0) { /* * Potential match. If sk_name is longer than * subkey, then sk_name is a subkey of our key. */ if (keylen < strlen(key->sk_name)) return (B_TRUE); } } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); return (B_FALSE); } /* * Call with the winreg_mutex held. */ static char * winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index) { winreg_subkey_t *key; char *entry; char *p; int subkeylen; int count = 0; if (subkey == NULL) return (NULL); if (list_is_empty(&winreg_keylist.kl_list)) return (NULL); subkeylen = strlen(subkey); for (key = list_head(&winreg_keylist.kl_list); key != NULL; key = list_next(&winreg_keylist.kl_list, key)) { if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) { p = key->sk_name + subkeylen; if ((*p != '\\') || (*p == '\0')) { /* * Not the same subkey or an exact match. * We're looking for children of subkey. */ continue; } ++p; if (count < index) { ++count; continue; } if ((entry = NDR_STRDUP(mxa, p)) == NULL) return (NULL); if ((p = strchr(entry, '\\')) != NULL) *p = '\0'; return (entry); } } return (NULL); } /* * winreg_s_DeleteValue */ /*ARGSUSED*/ static int winreg_s_DeleteValue(void *arg, ndr_xa_t *mxa) { struct winreg_DeleteValue *param = arg; param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * winreg_s_EnumKey */ static int winreg_s_EnumKey(void *arg, ndr_xa_t *mxa) { struct winreg_EnumKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; ndr_handle_t *hd; char *subkey; char *name = NULL; (void) mutex_lock(&winreg_mutex); if ((hd = ndr_hdlookup(mxa, id)) != NULL) name = hd->nh_data; if (hd == NULL || name == NULL) { (void) mutex_unlock(&winreg_mutex); bzero(param, sizeof (struct winreg_EnumKey)); param->status = ERROR_NO_MORE_ITEMS; return (NDR_DRC_OK); } subkey = winreg_enum_subkey(mxa, name, param->index); if (subkey == NULL) { (void) mutex_unlock(&winreg_mutex); bzero(param, sizeof (struct winreg_EnumKey)); param->status = ERROR_NO_MORE_ITEMS; return (NDR_DRC_OK); } if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)¶m->name_out) == -1) { (void) mutex_unlock(&winreg_mutex); bzero(param, sizeof (struct winreg_EnumKey)); param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); } (void) mutex_unlock(&winreg_mutex); /* * This request requires that the length includes the null. */ param->name_out.length = param->name_out.allosize; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } /* * winreg_s_EnumValue */ static int winreg_s_EnumValue(void *arg, ndr_xa_t *mxa) { struct winreg_EnumValue *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; if (ndr_hdlookup(mxa, id) == NULL) { bzero(param, sizeof (struct winreg_EnumValue)); param->status = ERROR_NO_MORE_ITEMS; return (NDR_DRC_OK); } bzero(param, sizeof (struct winreg_EnumValue)); param->status = ERROR_NO_MORE_ITEMS; return (NDR_DRC_OK); } /* * winreg_s_FlushKey * * Flush the attributes associated with the specified open key to disk. */ static int winreg_s_FlushKey(void *arg, ndr_xa_t *mxa) { struct winreg_FlushKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; if (ndr_hdlookup(mxa, id) == NULL) param->status = ERROR_INVALID_HANDLE; else param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } /* * winreg_s_GetKeySec */ static int winreg_s_GetKeySec(void *arg, ndr_xa_t *mxa) { static struct winreg_secdesc error_sd; struct winreg_GetKeySec *param = arg; struct winreg_value *sd_buf; smb_sd_t sd; uint32_t sd_len; uint32_t status; bzero(&sd, sizeof (smb_sd_t)); if ((status = winreg_sd_format(&sd)) != ERROR_SUCCESS) goto winreg_getkeysec_error; sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO); sd_buf = NDR_MALLOC(mxa, sd_len + sizeof (struct winreg_value)); param->sd = NDR_MALLOC(mxa, sizeof (struct winreg_secdesc)); if ((param->sd == NULL) || (sd_buf == NULL)) { status = ERROR_NOT_ENOUGH_MEMORY; goto winreg_getkeysec_error; } param->sd->sd_len = sd_len; param->sd->sd_size = sd_len; param->sd->sd_buf = sd_buf; sd_buf->vc_first_is = 0; sd_buf->vc_length_is = sd_len; param->status = srvsvc_sd_set_relative(&sd, sd_buf->value); smb_sd_term(&sd); return (NDR_DRC_OK); winreg_getkeysec_error: smb_sd_term(&sd); bzero(param, sizeof (struct winreg_GetKeySec)); param->sd = &error_sd; param->status = status; return (NDR_DRC_OK); } static uint32_t winreg_sd_format(smb_sd_t *sd) { smb_fssd_t fs_sd; acl_t *acl; uint32_t status = ERROR_SUCCESS; if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0) return (ERROR_NOT_ENOUGH_MEMORY); smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); fs_sd.sd_uid = 0; fs_sd.sd_gid = 0; fs_sd.sd_zdacl = acl; fs_sd.sd_zsacl = NULL; if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) status = ERROR_ACCESS_DENIED; smb_fssd_term(&fs_sd); return (status); } /* * winreg_s_NotifyChange */ static int winreg_s_NotifyChange(void *arg, ndr_xa_t *mxa) { struct winreg_NotifyChange *param = arg; if (ndr_is_admin(mxa)) param->status = ERROR_SUCCESS; else param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * winreg_s_OpenKey * * This is a request to open a windows registry key. * If we recognize the key, we return a handle. * * Returns: * ERROR_SUCCESS Valid handle returned. * ERROR_FILE_NOT_FOUND No key or unable to allocate a handle. */ static int winreg_s_OpenKey(void *arg, ndr_xa_t *mxa) { struct winreg_OpenKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; ndr_handle_t *hd; char *subkey = (char *)param->name.str; winreg_subkey_t *key; (void) mutex_lock(&winreg_mutex); if (subkey == NULL || *subkey == '\0') { if ((hd = ndr_hdlookup(mxa, id)) != NULL) subkey = hd->nh_data; } id = NULL; if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) { (void) mutex_unlock(&winreg_mutex); bzero(¶m->result_handle, sizeof (winreg_handle_t)); param->status = ERROR_FILE_NOT_FOUND; return (NDR_DRC_OK); } key = list_head(&winreg_keylist.kl_list); do { if (strcasecmp(subkey, key->sk_name) == 0) { if (key->sk_predefined == B_TRUE) id = winreg_alloc_id(mxa, subkey); else id = &key->sk_handle; if (id == NULL) break; bcopy(id, ¶m->result_handle, sizeof (winreg_handle_t)); (void) mutex_unlock(&winreg_mutex); param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); (void) mutex_unlock(&winreg_mutex); bzero(¶m->result_handle, sizeof (winreg_handle_t)); param->status = ERROR_FILE_NOT_FOUND; return (NDR_DRC_OK); } /* * winreg_s_QueryKey */ /*ARGSUSED*/ static int winreg_s_QueryKey(void *arg, ndr_xa_t *mxa) { struct winreg_QueryKey *param = arg; int rc; winreg_string_t *name; name = (winreg_string_t *)¶m->name; bzero(param, sizeof (struct winreg_QueryKey)); if ((name = NDR_NEW(mxa, winreg_string_t)) != NULL) rc = NDR_MSTRING(mxa, "", (ndr_mstring_t *)name); if ((name == NULL) || (rc != 0)) { bzero(param, sizeof (struct winreg_QueryKey)); param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); } param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } /* * winreg_s_QueryValue * * This is a request to get the value associated with a specified name. * * Returns: * ERROR_SUCCESS Value returned. * ERROR_FILE_NOT_FOUND PrimaryModule is not supported. * ERROR_CANTREAD No such name or memory problem. */ static int winreg_s_QueryValue(void *arg, ndr_xa_t *mxa) { struct winreg_QueryValue *param = arg; struct winreg_value *pv; char *name; char *value; DWORD slen; DWORD msize; name = (char *)param->value_name.str; if (name == NULL || strcasecmp(name, "PrimaryModule") == 0) { param->status = ERROR_FILE_NOT_FOUND; return (NDR_DRC_OK); } if ((value = winreg_lookup_value(name)) == NULL) { param->status = ERROR_CANTREAD; return (NDR_DRC_OK); } slen = smb_wcequiv_strlen(value) + sizeof (smb_wchar_t); msize = sizeof (struct winreg_value) + slen; param->value = (struct winreg_value *)NDR_MALLOC(mxa, msize); param->type = NDR_NEW(mxa, DWORD); param->value_size = NDR_NEW(mxa, DWORD); param->value_size_total = NDR_NEW(mxa, DWORD); if (param->value == NULL || param->type == NULL || param->value_size == NULL || param->value_size_total == NULL) { param->status = ERROR_CANTREAD; return (NDR_DRC_OK); } bzero(param->value, msize); pv = param->value; pv->vc_first_is = 0; pv->vc_length_is = slen; /*LINTED E_BAD_PTR_CAST_ALIGN*/ (void) ndr_mbstowcs(NULL, (smb_wchar_t *)pv->value, value, slen); *param->type = 1; *param->value_size = slen; *param->value_size_total = slen; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } /* * Lookup a name in the registry and return the associated value. * Our registry is a case-insensitive, name-value pair table. * * Windows ProductType: WinNT, ServerNT, LanmanNT. * Windows NT4.0 workstation: WinNT * Windows NT4.0 server: ServerNT * * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy * with info level 6, which we don't support. If we use ServerNT * (as reported by NT4.0 Server) Windows 2000 send requests for * levels 3 and 5, which are support. * * On success, returns a pointer to the value. Otherwise returns * a null pointer. */ static char * winreg_lookup_value(const char *name) { static struct registry { char *name; char *value; } registry[] = { { "SystemRoot", "C:\\" }, { "CurrentVersion", winreg_sysver }, { "ProductType", "ServerNT" }, { "Sources", winreg_sysname }, /* product name */ { "EventMessageFile", "C:\\windows\\system32\\eventlog.dll" } }; int i; for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) { if (strcasecmp(registry[i].name, name) == 0) return (registry[i].value); } return (NULL); } /* * winreg_s_SetKeySec */ /*ARGSUSED*/ static int winreg_s_SetKeySec(void *arg, ndr_xa_t *mxa) { struct winreg_SetKeySec *param = arg; param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * winreg_s_CreateValue */ /*ARGSUSED*/ static int winreg_s_CreateValue(void *arg, ndr_xa_t *mxa) { struct winreg_CreateValue *param = arg; param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * winreg_s_Shutdown * * Attempt to shutdown or reboot the system: access denied. */ /*ARGSUSED*/ static int winreg_s_Shutdown(void *arg, ndr_xa_t *mxa) { struct winreg_Shutdown *param = arg; param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * winreg_s_AbortShutdown * * Abort a shutdown request. */ static int winreg_s_AbortShutdown(void *arg, ndr_xa_t *mxa) { struct winreg_AbortShutdown *param = arg; if (ndr_is_admin(mxa)) param->status = ERROR_SUCCESS; else param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } /* * winreg_s_GetVersion * * Return the windows registry version. The current version is 5. * This call is usually made prior to enumerating or querying registry * keys or values. */ /*ARGSUSED*/ static int winreg_s_GetVersion(void *arg, ndr_xa_t *mxa) { struct winreg_GetVersion *param = arg; param->version = 5; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); }