2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
5 * Copyright (C) Gerald Carter 2002-2006.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 /* Implementation of registry functions. */
26 #define DBGC_CLASS DBGC_RPC_SRV
28 /******************************************************************
29 free() function for struct registry_key
30 *****************************************************************/
32 static void free_regkey(void *ptr)
34 struct registry_key *key = (struct registry_key *)ptr;
38 /******************************************************************
39 Find a registry key handle and return a struct registry_key *
40 *****************************************************************/
42 static struct registry_key *find_regkey_by_hnd(pipes_struct *p,
45 struct registry_key *regkey = NULL;
47 if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) {
48 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
55 /*******************************************************************
56 Function for open a new registry handle and creating a handle
57 Note that P should be valid & hnd should already have space
59 When we open a key, we store the full path to the key as
60 HK[LM|U]\<key>\<key>\...
61 *******************************************************************/
63 static WERROR open_registry_key( pipes_struct *p, POLICY_HND *hnd,
64 struct registry_key *parent,
65 const char *subkeyname,
66 uint32 access_desired )
68 WERROR result = WERR_OK;
69 struct registry_key *key;
72 result = reg_openhive(NULL, subkeyname, access_desired,
73 p->pipe_user.nt_user_token, &key);
76 result = reg_openkey(NULL, parent, subkeyname, access_desired,
80 if ( !W_ERROR_IS_OK(result) ) {
84 if ( !create_policy_hnd( p, hnd, free_regkey, key ) ) {
91 /*******************************************************************
92 Function for open a new registry handle and creating a handle
93 Note that P should be valid & hnd should already have space
94 *******************************************************************/
96 static bool close_registry_key(pipes_struct *p, POLICY_HND *hnd)
98 struct registry_key *regkey = find_regkey_by_hnd(p, hnd);
101 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n",
106 close_policy_hnd(p, hnd);
111 /********************************************************************
113 ********************************************************************/
115 WERROR _winreg_CloseKey(pipes_struct *p, struct winreg_CloseKey *r)
117 /* close the policy handle */
119 if (!close_registry_key(p, r->in.handle))
122 ZERO_STRUCTP(r->out.handle);
127 /*******************************************************************
128 ********************************************************************/
130 WERROR _winreg_OpenHKLM(pipes_struct *p, struct winreg_OpenHKLM *r)
132 return open_registry_key(p, r->out.handle, NULL, KEY_HKLM, r->in.access_mask);
135 /*******************************************************************
136 ********************************************************************/
138 WERROR _winreg_OpenHKPD(pipes_struct *p, struct winreg_OpenHKPD *r)
140 return open_registry_key(p, r->out.handle, NULL, KEY_HKPD, r->in.access_mask);
143 /*******************************************************************
144 ********************************************************************/
146 WERROR _winreg_OpenHKPT(pipes_struct *p, struct winreg_OpenHKPT *r)
148 return open_registry_key(p, r->out.handle, NULL, KEY_HKPT, r->in.access_mask);
151 /*******************************************************************
152 ********************************************************************/
154 WERROR _winreg_OpenHKCR(pipes_struct *p, struct winreg_OpenHKCR *r)
156 return open_registry_key(p, r->out.handle, NULL, KEY_HKCR, r->in.access_mask);
159 /*******************************************************************
160 ********************************************************************/
162 WERROR _winreg_OpenHKU(pipes_struct *p, struct winreg_OpenHKU *r)
164 return open_registry_key(p, r->out.handle, NULL, KEY_HKU, r->in.access_mask);
167 /*******************************************************************
168 ********************************************************************/
170 WERROR _winreg_OpenHKCU(pipes_struct *p, struct winreg_OpenHKCU *r)
172 return open_registry_key(p, r->out.handle, NULL, KEY_HKCU, r->in.access_mask);
175 /*******************************************************************
176 ********************************************************************/
178 WERROR _winreg_OpenHKCC(pipes_struct *p, struct winreg_OpenHKCC *r)
180 return open_registry_key(p, r->out.handle, NULL, KEY_HKCC, r->in.access_mask);
183 /*******************************************************************
184 ********************************************************************/
186 WERROR _winreg_OpenHKDD(pipes_struct *p, struct winreg_OpenHKDD *r)
188 return open_registry_key(p, r->out.handle, NULL, KEY_HKDD, r->in.access_mask);
191 /*******************************************************************
192 ********************************************************************/
194 WERROR _winreg_OpenHKPN(pipes_struct *p, struct winreg_OpenHKPN *r)
196 return open_registry_key(p, r->out.handle, NULL, KEY_HKPN, r->in.access_mask);
199 /*******************************************************************
201 ********************************************************************/
203 WERROR _winreg_OpenKey(pipes_struct *p, struct winreg_OpenKey *r)
205 struct registry_key *parent = find_regkey_by_hnd(p, r->in.parent_handle );
210 return open_registry_key(p, r->out.handle, parent, r->in.keyname.name, r->in.access_mask);
213 /*******************************************************************
215 ********************************************************************/
217 WERROR _winreg_QueryValue(pipes_struct *p, struct winreg_QueryValue *r)
219 WERROR status = WERR_BADFILE;
220 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
224 uint32_t outbuf_size;
227 bool free_buf = False;
228 bool free_prs = False;
233 *r->out.value_length = *r->out.type = REG_NONE;
235 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->key->name));
236 DEBUG(7,("_reg_info: policy key type = [%08x]\n", regkey->key->type));
238 /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */
239 if(regkey->key->type == REG_KEY_HKPD)
241 if(strequal(r->in.value_name.name, "Global")) {
242 prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL);
243 status = reg_perfcount_get_hkpd(
244 &prs_hkpd, *r->in.data_size, &outbuf_size, NULL);
245 outbuf = (uint8_t *)prs_hkpd.data_p;
248 else if(strequal(r->in.value_name.name, "Counter 009")) {
249 outbuf_size = reg_perfcount_get_counter_names(
250 reg_perfcount_get_base_index(),
251 (char **)(void *)&outbuf);
254 else if(strequal(r->in.value_name.name, "Explain 009")) {
255 outbuf_size = reg_perfcount_get_counter_help(
256 reg_perfcount_get_base_index(),
257 (char **)(void *)&outbuf);
260 else if(isdigit(r->in.value_name.name[0])) {
261 /* we probably have a request for a specific object
263 prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL);
264 status = reg_perfcount_get_hkpd(
265 &prs_hkpd, *r->in.data_size, &outbuf_size,
266 r->in.value_name.name);
267 outbuf = (uint8_t *)prs_hkpd.data_p;
271 DEBUG(3,("Unsupported key name [%s] for HKPD.\n",
272 r->in.value_name.name));
276 *r->out.type = REG_BINARY;
279 struct registry_value *val;
281 status = reg_queryvalue(p->mem_ctx, regkey, r->in.value_name.name,
283 if (!W_ERROR_IS_OK(status)) {
284 if (r->out.data_size) {
285 *r->out.data_size = 0;
287 if (r->out.value_length) {
288 *r->out.value_length = 0;
293 status = registry_push_value(p->mem_ctx, val, &val_blob);
294 if (!W_ERROR_IS_OK(status)) {
298 outbuf = val_blob.data;
299 outbuf_size = val_blob.length;
300 *r->out.type = val->type;
303 *r->out.value_length = outbuf_size;
305 if ( *r->in.data_size == 0 || !r->out.data ) {
307 } else if ( *r->out.value_length > *r->in.data_size ) {
308 status = WERR_MORE_DATA;
310 memcpy( r->out.data, outbuf, *r->out.value_length );
314 *r->out.data_size = *r->out.value_length;
316 if (free_prs) prs_mem_free(&prs_hkpd);
317 if (free_buf) SAFE_FREE(outbuf);
322 /*****************************************************************************
323 Implementation of REG_QUERY_KEY
324 ****************************************************************************/
326 WERROR _winreg_QueryInfoKey(pipes_struct *p, struct winreg_QueryInfoKey *r)
328 WERROR status = WERR_OK;
329 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
334 r->out.classname->name = NULL;
336 status = reg_queryinfokey(regkey, r->out.num_subkeys, r->out.max_subkeylen,
337 r->out.max_classlen, r->out.num_values, r->out.max_valnamelen,
338 r->out.max_valbufsize, r->out.secdescsize,
339 r->out.last_changed_time);
340 if (!W_ERROR_IS_OK(status)) {
345 * These calculations account for the registry buffers being
346 * UTF-16. They are inexact at best, but so far they worked.
349 *r->out.max_subkeylen *= 2;
351 *r->out.max_valnamelen += 1;
352 *r->out.max_valnamelen *= 2;
358 /*****************************************************************************
359 Implementation of REG_GETVERSION
360 ****************************************************************************/
362 WERROR _winreg_GetVersion(pipes_struct *p, struct winreg_GetVersion *r)
364 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
369 return reg_getversion(r->out.version);
373 /*****************************************************************************
374 Implementation of REG_ENUM_KEY
375 ****************************************************************************/
377 WERROR _winreg_EnumKey(pipes_struct *p, struct winreg_EnumKey *r)
380 struct registry_key *key = find_regkey_by_hnd( p, r->in.handle );
385 if ( !r->in.name || !r->in.keyclass )
386 return WERR_INVALID_PARAM;
388 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", key->key->name));
390 err = reg_enumkey(p->mem_ctx, key, r->in.enum_index, (char **)&r->out.name->name,
391 r->out.last_changed_time);
392 if (!W_ERROR_IS_OK(err)) {
395 r->out.keyclass->name = "";
399 /*****************************************************************************
400 Implementation of REG_ENUM_VALUE
401 ****************************************************************************/
403 WERROR _winreg_EnumValue(pipes_struct *p, struct winreg_EnumValue *r)
406 struct registry_key *key = find_regkey_by_hnd( p, r->in.handle );
408 struct registry_value *val;
409 DATA_BLOB value_blob;
415 return WERR_INVALID_PARAM;
417 DEBUG(8,("_winreg_EnumValue: enumerating values for key [%s]\n",
420 err = reg_enumvalue(p->mem_ctx, key, r->in.enum_index, &valname, &val);
421 if (!W_ERROR_IS_OK(err)) {
425 err = registry_push_value(p->mem_ctx, val, &value_blob);
426 if (!W_ERROR_IS_OK(err)) {
430 if (r->out.name != NULL) {
431 r->out.name->name = valname;
434 if (r->out.type != NULL) {
435 *r->out.type = val->type;
438 if (r->out.value != NULL) {
439 if ((r->out.size == NULL) || (r->out.length == NULL)) {
440 return WERR_INVALID_PARAM;
443 if (value_blob.length > *r->out.size) {
444 return WERR_MORE_DATA;
447 memcpy( r->out.value, value_blob.data, value_blob.length );
450 if (r->out.length != NULL) {
451 *r->out.length = value_blob.length;
453 if (r->out.size != NULL) {
454 *r->out.size = value_blob.length;
460 /*******************************************************************
462 ********************************************************************/
464 WERROR _winreg_InitiateSystemShutdown(pipes_struct *p, struct winreg_InitiateSystemShutdown *r)
466 struct winreg_InitiateSystemShutdownEx s;
468 s.in.hostname = r->in.hostname;
469 s.in.message = r->in.message;
470 s.in.timeout = r->in.timeout;
471 s.in.force_apps = r->in.force_apps;
472 s.in.reboot = r->in.reboot;
475 /* thunk down to _winreg_InitiateSystemShutdownEx()
476 (just returns a status) */
478 return _winreg_InitiateSystemShutdownEx( p, &s );
481 /*******************************************************************
483 ********************************************************************/
485 #define SHUTDOWN_R_STRING "-r"
486 #define SHUTDOWN_F_STRING "-f"
489 WERROR _winreg_InitiateSystemShutdownEx(pipes_struct *p, struct winreg_InitiateSystemShutdownEx *r)
491 char *shutdown_script = NULL;
501 shutdown_script = talloc_strdup(p->mem_ctx, lp_shutdown_script());
502 if (!shutdown_script) {
505 if (!*shutdown_script) {
506 return WERR_ACCESS_DENIED;
509 /* pull the message string and perform necessary sanity checks on it */
513 if ( r->in.message && r->in.message->name && r->in.message->name->name ) {
514 if ( (msg = talloc_strdup(p->mem_ctx, r->in.message->name->name )) == NULL ) {
517 chkmsg = TALLOC_ARRAY(p->mem_ctx, char, strlen(msg)+1);
521 alpha_strcpy(chkmsg, msg, NULL, strlen(msg)+1);
524 fstr_sprintf(str_timeout, "%d", r->in.timeout);
525 fstr_sprintf(reboot, r->in.reboot ? SHUTDOWN_R_STRING : "");
526 fstr_sprintf(f, r->in.force_apps ? SHUTDOWN_F_STRING : "");
527 fstr_sprintf(str_reason, "%d", r->in.reason );
529 shutdown_script = talloc_all_string_sub(p->mem_ctx,
530 shutdown_script, "%z", chkmsg ? chkmsg : "");
531 if (!shutdown_script) {
534 shutdown_script = talloc_all_string_sub(p->mem_ctx,
535 shutdown_script, "%t", str_timeout);
536 if (!shutdown_script) {
539 shutdown_script = talloc_all_string_sub(p->mem_ctx,
540 shutdown_script, "%r", reboot);
541 if (!shutdown_script) {
544 shutdown_script = talloc_all_string_sub(p->mem_ctx,
545 shutdown_script, "%f", f);
546 if (!shutdown_script) {
549 shutdown_script = talloc_all_string_sub(p->mem_ctx,
550 shutdown_script, "%x", str_reason);
551 if (!shutdown_script) {
555 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
557 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
558 Take the error return from the script and provide it as the Windows return code. */
560 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
565 ret = smbrun( shutdown_script, NULL );
570 /********** END SeRemoteShutdownPrivilege BLOCK **********/
572 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
573 shutdown_script, ret));
575 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
578 /*******************************************************************
580 ********************************************************************/
582 WERROR _winreg_AbortSystemShutdown(pipes_struct *p, struct winreg_AbortSystemShutdown *r)
584 const char *abort_shutdown_script;
588 abort_shutdown_script = lp_abort_shutdown_script();
590 if (!*abort_shutdown_script)
591 return WERR_ACCESS_DENIED;
593 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
595 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
600 ret = smbrun( abort_shutdown_script, NULL );
605 /********** END SeRemoteShutdownPrivilege BLOCK **********/
607 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
608 abort_shutdown_script, ret));
610 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
613 /*******************************************************************
614 ********************************************************************/
616 static int validate_reg_filename(TALLOC_CTX *ctx, char **pp_fname )
619 int num_services = lp_numservices();
621 const char *share_path;
622 char *fname = *pp_fname;
624 /* convert to a unix path, stripping the C:\ along the way */
626 if (!(p = valid_share_pathname(ctx, fname))) {
630 /* has to exist within a valid file share */
632 for (snum=0; snum<num_services; snum++) {
633 if (!lp_snum_ok(snum) || lp_print_ok(snum)) {
637 share_path = lp_pathname(snum);
639 /* make sure we have a path (e.g. [homes] ) */
640 if (strlen(share_path) == 0) {
644 if (strncmp(share_path, p, strlen(share_path)) == 0) {
650 return (snum < num_services) ? snum : -1;
653 /*******************************************************************
654 ********************************************************************/
656 WERROR _winreg_RestoreKey(pipes_struct *p, struct winreg_RestoreKey *r)
658 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
665 if ( !r->in.filename || !r->in.filename->name )
666 return WERR_INVALID_PARAM;
668 fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
673 DEBUG(8,("_winreg_RestoreKey: verifying restore of key [%s] from "
674 "\"%s\"\n", regkey->key->name, fname));
676 if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1)
677 return WERR_OBJECT_PATH_INVALID;
679 /* user must posses SeRestorePrivilege for this this proceed */
681 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
682 return WERR_ACCESS_DENIED;
684 DEBUG(2,("_winreg_RestoreKey: Restoring [%s] from %s in share %s\n",
685 regkey->key->name, fname, lp_servicename(snum) ));
687 return reg_restorekey(regkey, fname);
690 WERROR _winreg_SaveKey(pipes_struct *p, struct winreg_SaveKey *r)
692 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
699 if ( !r->in.filename || !r->in.filename->name )
700 return WERR_INVALID_PARAM;
702 fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
707 DEBUG(8,("_winreg_SaveKey: verifying backup of key [%s] to \"%s\"\n",
708 regkey->key->name, fname));
710 if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1 )
711 return WERR_OBJECT_PATH_INVALID;
713 DEBUG(2,("_winreg_SaveKey: Saving [%s] to %s in share %s\n",
714 regkey->key->name, fname, lp_servicename(snum) ));
716 return reg_savekey(regkey, fname);
719 /*******************************************************************
720 ********************************************************************/
722 WERROR _winreg_SaveKeyEx(pipes_struct *p, struct winreg_SaveKeyEx *r)
724 /* fill in your code here if you think this call should
727 p->rng_fault_state = True;
728 return WERR_NOT_SUPPORTED;
731 /*******************************************************************
732 ********************************************************************/
734 WERROR _winreg_CreateKey( pipes_struct *p, struct winreg_CreateKey *r)
736 struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
737 struct registry_key *new_key;
743 result = reg_createkey(NULL, parent, r->in.name.name, r->in.access_mask,
744 &new_key, r->out.action_taken);
745 if (!W_ERROR_IS_OK(result)) {
749 if (!create_policy_hnd(p, r->out.new_handle, free_regkey, new_key)) {
750 TALLOC_FREE(new_key);
757 /*******************************************************************
758 ********************************************************************/
760 WERROR _winreg_SetValue(pipes_struct *p, struct winreg_SetValue *r)
762 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
763 struct registry_value *val;
769 DEBUG(8,("_reg_set_value: Setting value for [%s:%s]\n",
770 key->key->name, r->in.name.name));
772 status = registry_pull_value(p->mem_ctx, &val, r->in.type, r->in.data,
773 r->in.size, r->in.size);
774 if (!W_ERROR_IS_OK(status)) {
778 return reg_setvalue(key, r->in.name.name, val);
781 /*******************************************************************
782 ********************************************************************/
784 WERROR _winreg_DeleteKey(pipes_struct *p, struct winreg_DeleteKey *r)
786 struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
791 return reg_deletekey(parent, r->in.key.name);
795 /*******************************************************************
796 ********************************************************************/
798 WERROR _winreg_DeleteValue(pipes_struct *p, struct winreg_DeleteValue *r)
800 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
805 return reg_deletevalue(key, r->in.value.name);
808 /*******************************************************************
809 ********************************************************************/
811 WERROR _winreg_GetKeySecurity(pipes_struct *p, struct winreg_GetKeySecurity *r)
813 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
815 struct security_descriptor *secdesc;
822 /* access checks first */
824 if ( !(key->key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
825 return WERR_ACCESS_DENIED;
827 err = reg_getkeysecurity(p->mem_ctx, key, &secdesc);
828 if (!W_ERROR_IS_OK(err)) {
832 err = ntstatus_to_werror(marshall_sec_desc(p->mem_ctx, secdesc,
834 if (!W_ERROR_IS_OK(err)) {
838 if (len > r->out.sd->size) {
839 r->out.sd->size = len;
840 return WERR_INSUFFICIENT_BUFFER;
843 r->out.sd->size = len;
844 r->out.sd->len = len;
845 r->out.sd->data = data;
850 /*******************************************************************
851 ********************************************************************/
853 WERROR _winreg_SetKeySecurity(pipes_struct *p, struct winreg_SetKeySecurity *r)
855 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
856 struct security_descriptor *secdesc;
862 /* access checks first */
864 if ( !(key->key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
865 return WERR_ACCESS_DENIED;
867 err = ntstatus_to_werror(unmarshall_sec_desc(p->mem_ctx, r->in.sd->data,
868 r->in.sd->len, &secdesc));
869 if (!W_ERROR_IS_OK(err)) {
873 return reg_setkeysecurity(key, secdesc);
876 /*******************************************************************
877 ********************************************************************/
879 WERROR _winreg_FlushKey(pipes_struct *p, struct winreg_FlushKey *r)
881 /* I'm just replying OK because there's not a lot
882 here I see to do i --jerry */
887 /*******************************************************************
888 ********************************************************************/
890 WERROR _winreg_UnLoadKey(pipes_struct *p, struct winreg_UnLoadKey *r)
892 /* fill in your code here if you think this call should
895 p->rng_fault_state = True;
896 return WERR_NOT_SUPPORTED;
899 /*******************************************************************
900 ********************************************************************/
902 WERROR _winreg_ReplaceKey(pipes_struct *p, struct winreg_ReplaceKey *r)
904 /* fill in your code here if you think this call should
907 p->rng_fault_state = True;
908 return WERR_NOT_SUPPORTED;
911 /*******************************************************************
912 ********************************************************************/
914 WERROR _winreg_LoadKey(pipes_struct *p, struct winreg_LoadKey *r)
916 /* fill in your code here if you think this call should
919 p->rng_fault_state = True;
920 return WERR_NOT_SUPPORTED;
923 /*******************************************************************
924 ********************************************************************/
926 WERROR _winreg_NotifyChangeKeyValue(pipes_struct *p, struct winreg_NotifyChangeKeyValue *r)
928 /* fill in your code here if you think this call should
931 p->rng_fault_state = True;
932 return WERR_NOT_SUPPORTED;
935 /*******************************************************************
936 ********************************************************************/
938 WERROR _winreg_QueryMultipleValues(pipes_struct *p, struct winreg_QueryMultipleValues *r)
940 /* fill in your code here if you think this call should
943 p->rng_fault_state = True;
944 return WERR_NOT_SUPPORTED;
947 /*******************************************************************
948 ********************************************************************/
950 WERROR _winreg_QueryMultipleValues2(pipes_struct *p, struct winreg_QueryMultipleValues2 *r)
952 /* fill in your code here if you think this call should
955 p->rng_fault_state = True;
956 return WERR_NOT_SUPPORTED;