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 */
511 if ( r->in.message && r->in.message->name && r->in.message->name->name ) {
512 if ( (msg = talloc_strdup(p->mem_ctx, r->in.message->name->name )) == NULL ) {
515 chkmsg = TALLOC_ARRAY(p->mem_ctx, char, strlen(msg)+1);
519 alpha_strcpy(chkmsg, msg, NULL, strlen(msg)+1);
522 fstr_sprintf(str_timeout, "%d", r->in.timeout);
523 fstr_sprintf(reboot, r->in.reboot ? SHUTDOWN_R_STRING : "");
524 fstr_sprintf(f, r->in.force_apps ? SHUTDOWN_F_STRING : "");
525 fstr_sprintf(str_reason, "%d", r->in.reason );
527 shutdown_script = talloc_all_string_sub(p->mem_ctx,
528 shutdown_script, "%z", chkmsg ? chkmsg : "");
529 if (!shutdown_script) {
532 shutdown_script = talloc_all_string_sub(p->mem_ctx,
533 shutdown_script, "%t", str_timeout);
534 if (!shutdown_script) {
537 shutdown_script = talloc_all_string_sub(p->mem_ctx,
538 shutdown_script, "%r", reboot);
539 if (!shutdown_script) {
542 shutdown_script = talloc_all_string_sub(p->mem_ctx,
543 shutdown_script, "%f", f);
544 if (!shutdown_script) {
547 shutdown_script = talloc_all_string_sub(p->mem_ctx,
548 shutdown_script, "%x", str_reason);
549 if (!shutdown_script) {
553 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
555 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
556 Take the error return from the script and provide it as the Windows return code. */
558 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
563 ret = smbrun( shutdown_script, NULL );
568 /********** END SeRemoteShutdownPrivilege BLOCK **********/
570 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
571 shutdown_script, ret));
573 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
576 /*******************************************************************
578 ********************************************************************/
580 WERROR _winreg_AbortSystemShutdown(pipes_struct *p, struct winreg_AbortSystemShutdown *r)
582 const char *abort_shutdown_script;
586 abort_shutdown_script = lp_abort_shutdown_script();
588 if (!*abort_shutdown_script)
589 return WERR_ACCESS_DENIED;
591 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
593 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
598 ret = smbrun( abort_shutdown_script, NULL );
603 /********** END SeRemoteShutdownPrivilege BLOCK **********/
605 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
606 abort_shutdown_script, ret));
608 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
611 /*******************************************************************
612 ********************************************************************/
614 static int validate_reg_filename(TALLOC_CTX *ctx, char **pp_fname )
617 int num_services = lp_numservices();
619 const char *share_path;
620 char *fname = *pp_fname;
622 /* convert to a unix path, stripping the C:\ along the way */
624 if (!(p = valid_share_pathname(ctx, fname))) {
628 /* has to exist within a valid file share */
630 for (snum=0; snum<num_services; snum++) {
631 if (!lp_snum_ok(snum) || lp_print_ok(snum)) {
635 share_path = lp_pathname(snum);
637 /* make sure we have a path (e.g. [homes] ) */
638 if (strlen(share_path) == 0) {
642 if (strncmp(share_path, p, strlen(share_path)) == 0) {
648 return (snum < num_services) ? snum : -1;
651 /*******************************************************************
652 ********************************************************************/
654 WERROR _winreg_RestoreKey(pipes_struct *p, struct winreg_RestoreKey *r)
656 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
663 if ( !r->in.filename || !r->in.filename->name )
664 return WERR_INVALID_PARAM;
666 fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
671 DEBUG(8,("_winreg_RestoreKey: verifying restore of key [%s] from "
672 "\"%s\"\n", regkey->key->name, fname));
674 if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1)
675 return WERR_OBJECT_PATH_INVALID;
677 /* user must posses SeRestorePrivilege for this this proceed */
679 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
680 return WERR_ACCESS_DENIED;
682 DEBUG(2,("_winreg_RestoreKey: Restoring [%s] from %s in share %s\n",
683 regkey->key->name, fname, lp_servicename(snum) ));
685 return reg_restorekey(regkey, fname);
688 WERROR _winreg_SaveKey(pipes_struct *p, struct winreg_SaveKey *r)
690 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
697 if ( !r->in.filename || !r->in.filename->name )
698 return WERR_INVALID_PARAM;
700 fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
705 DEBUG(8,("_winreg_SaveKey: verifying backup of key [%s] to \"%s\"\n",
706 regkey->key->name, fname));
708 if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1 )
709 return WERR_OBJECT_PATH_INVALID;
711 DEBUG(2,("_winreg_SaveKey: Saving [%s] to %s in share %s\n",
712 regkey->key->name, fname, lp_servicename(snum) ));
714 return reg_savekey(regkey, fname);
717 /*******************************************************************
718 ********************************************************************/
720 WERROR _winreg_SaveKeyEx(pipes_struct *p, struct winreg_SaveKeyEx *r)
722 /* fill in your code here if you think this call should
725 p->rng_fault_state = True;
726 return WERR_NOT_SUPPORTED;
729 /*******************************************************************
730 ********************************************************************/
732 WERROR _winreg_CreateKey( pipes_struct *p, struct winreg_CreateKey *r)
734 struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
735 struct registry_key *new_key;
741 result = reg_createkey(NULL, parent, r->in.name.name, r->in.access_mask,
742 &new_key, r->out.action_taken);
743 if (!W_ERROR_IS_OK(result)) {
747 if (!create_policy_hnd(p, r->out.new_handle, free_regkey, new_key)) {
748 TALLOC_FREE(new_key);
755 /*******************************************************************
756 ********************************************************************/
758 WERROR _winreg_SetValue(pipes_struct *p, struct winreg_SetValue *r)
760 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
761 struct registry_value *val;
767 DEBUG(8,("_reg_set_value: Setting value for [%s:%s]\n",
768 key->key->name, r->in.name.name));
770 status = registry_pull_value(p->mem_ctx, &val, r->in.type, r->in.data,
771 r->in.size, r->in.size);
772 if (!W_ERROR_IS_OK(status)) {
776 return reg_setvalue(key, r->in.name.name, val);
779 /*******************************************************************
780 ********************************************************************/
782 WERROR _winreg_DeleteKey(pipes_struct *p, struct winreg_DeleteKey *r)
784 struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
789 return reg_deletekey(parent, r->in.key.name);
793 /*******************************************************************
794 ********************************************************************/
796 WERROR _winreg_DeleteValue(pipes_struct *p, struct winreg_DeleteValue *r)
798 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
803 return reg_deletevalue(key, r->in.value.name);
806 /*******************************************************************
807 ********************************************************************/
809 WERROR _winreg_GetKeySecurity(pipes_struct *p, struct winreg_GetKeySecurity *r)
811 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
813 struct security_descriptor *secdesc;
820 /* access checks first */
822 if ( !(key->key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
823 return WERR_ACCESS_DENIED;
825 err = reg_getkeysecurity(p->mem_ctx, key, &secdesc);
826 if (!W_ERROR_IS_OK(err)) {
830 err = ntstatus_to_werror(marshall_sec_desc(p->mem_ctx, secdesc,
832 if (!W_ERROR_IS_OK(err)) {
836 if (len > r->out.sd->size) {
837 r->out.sd->size = len;
838 return WERR_INSUFFICIENT_BUFFER;
841 r->out.sd->size = len;
842 r->out.sd->len = len;
843 r->out.sd->data = data;
848 /*******************************************************************
849 ********************************************************************/
851 WERROR _winreg_SetKeySecurity(pipes_struct *p, struct winreg_SetKeySecurity *r)
853 struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
854 struct security_descriptor *secdesc;
860 /* access checks first */
862 if ( !(key->key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
863 return WERR_ACCESS_DENIED;
865 err = ntstatus_to_werror(unmarshall_sec_desc(p->mem_ctx, r->in.sd->data,
866 r->in.sd->len, &secdesc));
867 if (!W_ERROR_IS_OK(err)) {
871 return reg_setkeysecurity(key, secdesc);
874 /*******************************************************************
875 ********************************************************************/
877 WERROR _winreg_FlushKey(pipes_struct *p, struct winreg_FlushKey *r)
879 /* I'm just replying OK because there's not a lot
880 here I see to do i --jerry */
885 /*******************************************************************
886 ********************************************************************/
888 WERROR _winreg_UnLoadKey(pipes_struct *p, struct winreg_UnLoadKey *r)
890 /* fill in your code here if you think this call should
893 p->rng_fault_state = True;
894 return WERR_NOT_SUPPORTED;
897 /*******************************************************************
898 ********************************************************************/
900 WERROR _winreg_ReplaceKey(pipes_struct *p, struct winreg_ReplaceKey *r)
902 /* fill in your code here if you think this call should
905 p->rng_fault_state = True;
906 return WERR_NOT_SUPPORTED;
909 /*******************************************************************
910 ********************************************************************/
912 WERROR _winreg_LoadKey(pipes_struct *p, struct winreg_LoadKey *r)
914 /* fill in your code here if you think this call should
917 p->rng_fault_state = True;
918 return WERR_NOT_SUPPORTED;
921 /*******************************************************************
922 ********************************************************************/
924 WERROR _winreg_NotifyChangeKeyValue(pipes_struct *p, struct winreg_NotifyChangeKeyValue *r)
926 /* fill in your code here if you think this call should
929 p->rng_fault_state = True;
930 return WERR_NOT_SUPPORTED;
933 /*******************************************************************
934 ********************************************************************/
936 WERROR _winreg_QueryMultipleValues(pipes_struct *p, struct winreg_QueryMultipleValues *r)
938 /* fill in your code here if you think this call should
941 p->rng_fault_state = True;
942 return WERR_NOT_SUPPORTED;
945 /*******************************************************************
946 ********************************************************************/
948 WERROR _winreg_QueryMultipleValues2(pipes_struct *p, struct winreg_QueryMultipleValues2 *r)
950 /* fill in your code here if you think this call should
953 p->rng_fault_state = True;
954 return WERR_NOT_SUPPORTED;