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. */
24 #include "../librpc/gen_ndr/srv_winreg.h"
27 #define DBGC_CLASS DBGC_RPC_SRV
29 /******************************************************************
30 Find a registry key handle and return a struct registry_key *
31 *****************************************************************/
33 static struct registry_key *find_regkey_by_hnd(pipes_struct *p,
34 struct policy_handle *hnd)
36 struct registry_key *regkey = NULL;
38 if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) {
39 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
46 /*******************************************************************
47 Function for open a new registry handle and creating a handle
48 Note that P should be valid & hnd should already have space
50 When we open a key, we store the full path to the key as
51 HK[LM|U]\<key>\<key>\...
52 *******************************************************************/
54 static WERROR open_registry_key( pipes_struct *p, struct policy_handle *hnd,
55 struct registry_key *parent,
56 const char *subkeyname,
57 uint32 access_desired )
59 WERROR result = WERR_OK;
60 struct registry_key *key;
63 result = reg_openhive(p->mem_ctx, subkeyname, access_desired,
64 p->server_info->ptok, &key);
67 result = reg_openkey(p->mem_ctx, parent, subkeyname,
68 access_desired, &key);
71 if ( !W_ERROR_IS_OK(result) ) {
75 if ( !create_policy_hnd( p, hnd, key ) ) {
82 /*******************************************************************
83 Function for open a new registry handle and creating a handle
84 Note that P should be valid & hnd should already have space
85 *******************************************************************/
87 static bool close_registry_key(pipes_struct *p, struct policy_handle *hnd)
89 struct registry_key *regkey = find_regkey_by_hnd(p, hnd);
92 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n",
97 close_policy_hnd(p, hnd);
102 /********************************************************************
104 ********************************************************************/
106 WERROR _winreg_CloseKey(pipes_struct *p, struct winreg_CloseKey *r)
108 /* close the policy handle */
110 if (!close_registry_key(p, r->in.handle))
113 ZERO_STRUCTP(r->out.handle);
118 /*******************************************************************
119 ********************************************************************/
121 WERROR _winreg_OpenHKLM(pipes_struct *p, struct winreg_OpenHKLM *r)
123 return open_registry_key(p, r->out.handle, NULL, KEY_HKLM, r->in.access_mask);
126 /*******************************************************************
127 ********************************************************************/
129 WERROR _winreg_OpenHKPD(pipes_struct *p, struct winreg_OpenHKPD *r)
131 return open_registry_key(p, r->out.handle, NULL, KEY_HKPD, r->in.access_mask);
134 /*******************************************************************
135 ********************************************************************/
137 WERROR _winreg_OpenHKPT(pipes_struct *p, struct winreg_OpenHKPT *r)
139 return open_registry_key(p, r->out.handle, NULL, KEY_HKPT, r->in.access_mask);
142 /*******************************************************************
143 ********************************************************************/
145 WERROR _winreg_OpenHKCR(pipes_struct *p, struct winreg_OpenHKCR *r)
147 return open_registry_key(p, r->out.handle, NULL, KEY_HKCR, r->in.access_mask);
150 /*******************************************************************
151 ********************************************************************/
153 WERROR _winreg_OpenHKU(pipes_struct *p, struct winreg_OpenHKU *r)
155 return open_registry_key(p, r->out.handle, NULL, KEY_HKU, r->in.access_mask);
158 /*******************************************************************
159 ********************************************************************/
161 WERROR _winreg_OpenHKCU(pipes_struct *p, struct winreg_OpenHKCU *r)
163 return open_registry_key(p, r->out.handle, NULL, KEY_HKCU, r->in.access_mask);
166 /*******************************************************************
167 ********************************************************************/
169 WERROR _winreg_OpenHKCC(pipes_struct *p, struct winreg_OpenHKCC *r)
171 return open_registry_key(p, r->out.handle, NULL, KEY_HKCC, r->in.access_mask);
174 /*******************************************************************
175 ********************************************************************/
177 WERROR _winreg_OpenHKDD(pipes_struct *p, struct winreg_OpenHKDD *r)
179 return open_registry_key(p, r->out.handle, NULL, KEY_HKDD, r->in.access_mask);
182 /*******************************************************************
183 ********************************************************************/
185 WERROR _winreg_OpenHKPN(pipes_struct *p, struct winreg_OpenHKPN *r)
187 return open_registry_key(p, r->out.handle, NULL, KEY_HKPN, r->in.access_mask);
190 /*******************************************************************
192 ********************************************************************/
194 WERROR _winreg_OpenKey(pipes_struct *p, struct winreg_OpenKey *r)
196 struct registry_key *parent = find_regkey_by_hnd(p, r->in.parent_handle );
201 return open_registry_key(p, r->out.handle, parent, r->in.keyname.name, r->in.access_mask);
204 /*******************************************************************
206 ********************************************************************/
208 WERROR _winreg_QueryValue(pipes_struct *p, struct winreg_QueryValue *r)
210 WERROR status = WERR_BADFILE;
211 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
215 uint32_t outbuf_size;
218 bool free_buf = False;
219 bool free_prs = False;
224 if ((r->out.data_length == NULL) || (r->out.type == NULL)) {
225 return WERR_INVALID_PARAM;
228 *r->out.data_length = *r->out.type = REG_NONE;
230 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->key->name));
231 DEBUG(7,("_reg_info: policy key type = [%08x]\n", regkey->key->type));
233 /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */
234 if(regkey->key->type == REG_KEY_HKPD)
236 if (strequal(r->in.value_name->name, "Global")) {
237 if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL))
239 status = reg_perfcount_get_hkpd(
240 &prs_hkpd, *r->in.data_size, &outbuf_size, NULL);
241 outbuf = (uint8_t *)prs_hkpd.data_p;
244 else if (strequal(r->in.value_name->name, "Counter 009")) {
245 outbuf_size = reg_perfcount_get_counter_names(
246 reg_perfcount_get_base_index(),
247 (char **)(void *)&outbuf);
250 else if (strequal(r->in.value_name->name, "Explain 009")) {
251 outbuf_size = reg_perfcount_get_counter_help(
252 reg_perfcount_get_base_index(),
253 (char **)(void *)&outbuf);
256 else if (isdigit(r->in.value_name->name[0])) {
257 /* we probably have a request for a specific object
259 if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL))
261 status = reg_perfcount_get_hkpd(
262 &prs_hkpd, *r->in.data_size, &outbuf_size,
263 r->in.value_name->name);
264 outbuf = (uint8_t *)prs_hkpd.data_p;
268 DEBUG(3,("Unsupported key name [%s] for HKPD.\n",
269 r->in.value_name->name));
273 *r->out.type = REG_BINARY;
276 struct registry_value *val;
278 status = reg_queryvalue(p->mem_ctx, regkey, r->in.value_name->name,
280 if (!W_ERROR_IS_OK(status)) {
281 if (r->out.data_size) {
282 *r->out.data_size = 0;
284 if (r->out.data_length) {
285 *r->out.data_length = 0;
290 status = registry_push_value(p->mem_ctx, val, &val_blob);
291 if (!W_ERROR_IS_OK(status)) {
295 outbuf = val_blob.data;
296 outbuf_size = val_blob.length;
297 *r->out.type = val->type;
300 *r->out.data_length = outbuf_size;
302 if ( *r->in.data_size == 0 || !r->out.data ) {
304 } else if ( *r->out.data_length > *r->in.data_size ) {
305 status = WERR_MORE_DATA;
307 memcpy( r->out.data, outbuf, *r->out.data_length );
311 *r->out.data_size = *r->out.data_length;
313 if (free_prs) prs_mem_free(&prs_hkpd);
314 if (free_buf) SAFE_FREE(outbuf);
319 /*****************************************************************************
320 Implementation of REG_QUERY_KEY
321 ****************************************************************************/
323 WERROR _winreg_QueryInfoKey(pipes_struct *p, struct winreg_QueryInfoKey *r)
325 WERROR status = WERR_OK;
326 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
331 r->out.classname->name = NULL;
333 status = reg_queryinfokey(regkey, r->out.num_subkeys, r->out.max_subkeylen,
334 r->out.max_classlen, r->out.num_values, r->out.max_valnamelen,
335 r->out.max_valbufsize, r->out.secdescsize,
336 r->out.last_changed_time);
337 if (!W_ERROR_IS_OK(status)) {
342 * These calculations account for the registry buffers being
343 * UTF-16. They are inexact at best, but so far they worked.
346 *r->out.max_subkeylen *= 2;
348 *r->out.max_valnamelen += 1;
349 *r->out.max_valnamelen *= 2;
355 /*****************************************************************************
356 Implementation of REG_GETVERSION
357 ****************************************************************************/
359 WERROR _winreg_GetVersion(pipes_struct *p, struct winreg_GetVersion *r)
361 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
366 return reg_getversion(r->out.version);
370 /*****************************************************************************
371 Implementation of REG_ENUM_KEY
372 ****************************************************************************/
374 WERROR _winreg_EnumKey(pipes_struct *p, struct winreg_EnumKey *r)
377 struct registry_key *key = find_regkey_by_hnd( p, r->in.handle );
382 if ( !r->in.name || !r->in.keyclass )
383 return WERR_INVALID_PARAM;
385 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", key->key->name));
387 err = reg_enumkey(p->mem_ctx, key, r->in.enum_index, (char **)&r->out.name->name,
388 r->out.last_changed_time);
389 if (!W_ERROR_IS_OK(err)) {
392 r->out.keyclass->name = "";
396 /*****************************************************************************
397 Implementation of REG_ENUM_VALUE
398 ****************************************************************************/
400 WERROR _winreg_EnumValue(pipes_struct *p, struct winreg_EnumValue *r)
403 struct registry_key *key = find_regkey_by_hnd( p, r->in.handle );
405 struct registry_value *val;
406 DATA_BLOB value_blob;
412 return WERR_INVALID_PARAM;
414 DEBUG(8,("_winreg_EnumValue: enumerating values for key [%s]\n",
417 err = reg_enumvalue(p->mem_ctx, key, r->in.enum_index, &valname, &val);
418 if (!W_ERROR_IS_OK(err)) {
422 err = registry_push_value(p->mem_ctx, val, &value_blob);
423 if (!W_ERROR_IS_OK(err)) {
427 if (r->out.name != NULL) {
428 r->out.name->name = valname;
431 if (r->out.type != NULL) {
432 *r->out.type = val->type;
435 if (r->out.value != NULL) {
436 if ((r->out.size == NULL) || (r->out.length == NULL)) {
437 return WERR_INVALID_PARAM;
440 if (value_blob.length > *r->out.size) {
441 return WERR_MORE_DATA;
444 memcpy( r->out.value, value_blob.data, value_blob.length );
447 if (r->out.length != NULL) {
448 *r->out.length = value_blob.length;
450 if (r->out.size != NULL) {
451 *r->out.size = value_blob.length;
457 /*******************************************************************
459 ********************************************************************/
461 WERROR _winreg_InitiateSystemShutdown(pipes_struct *p, struct winreg_InitiateSystemShutdown *r)
463 struct winreg_InitiateSystemShutdownEx s;
465 s.in.hostname = r->in.hostname;
466 s.in.message = r->in.message;
467 s.in.timeout = r->in.timeout;
468 s.in.force_apps = r->in.force_apps;
469 s.in.do_reboot = r->in.do_reboot;
472 /* thunk down to _winreg_InitiateSystemShutdownEx()
473 (just returns a status) */
475 return _winreg_InitiateSystemShutdownEx( p, &s );
478 /*******************************************************************
480 ********************************************************************/
482 #define SHUTDOWN_R_STRING "-r"
483 #define SHUTDOWN_F_STRING "-f"
486 WERROR _winreg_InitiateSystemShutdownEx(pipes_struct *p, struct winreg_InitiateSystemShutdownEx *r)
488 char *shutdown_script = NULL;
498 shutdown_script = talloc_strdup(p->mem_ctx, lp_shutdown_script());
499 if (!shutdown_script) {
502 if (!*shutdown_script) {
503 return WERR_ACCESS_DENIED;
506 /* pull the message string and perform necessary sanity checks on it */
508 if ( r->in.message && r->in.message->string ) {
509 if ( (msg = talloc_strdup(p->mem_ctx, r->in.message->string )) == NULL ) {
512 chkmsg = TALLOC_ARRAY(p->mem_ctx, char, strlen(msg)+1);
516 alpha_strcpy(chkmsg, msg, NULL, strlen(msg)+1);
519 fstr_sprintf(str_timeout, "%d", r->in.timeout);
520 fstr_sprintf(do_reboot, r->in.do_reboot ? SHUTDOWN_R_STRING : "");
521 fstr_sprintf(f, r->in.force_apps ? SHUTDOWN_F_STRING : "");
522 fstr_sprintf(str_reason, "%d", r->in.reason );
524 shutdown_script = talloc_all_string_sub(p->mem_ctx,
525 shutdown_script, "%z", chkmsg ? chkmsg : "");
526 if (!shutdown_script) {
529 shutdown_script = talloc_all_string_sub(p->mem_ctx,
530 shutdown_script, "%t", str_timeout);
531 if (!shutdown_script) {
534 shutdown_script = talloc_all_string_sub(p->mem_ctx,
535 shutdown_script, "%r", do_reboot);
536 if (!shutdown_script) {
539 shutdown_script = talloc_all_string_sub(p->mem_ctx,
540 shutdown_script, "%f", f);
541 if (!shutdown_script) {
544 shutdown_script = talloc_all_string_sub(p->mem_ctx,
545 shutdown_script, "%x", str_reason);
546 if (!shutdown_script) {
550 can_shutdown = user_has_privileges( p->server_info->ptok,
551 &se_remote_shutdown );
553 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
554 Take the error return from the script and provide it as the Windows return code. */
556 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
561 ret = smbrun( shutdown_script, NULL );
566 /********** END SeRemoteShutdownPrivilege BLOCK **********/
568 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
569 shutdown_script, ret));
571 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
574 /*******************************************************************
576 ********************************************************************/
578 WERROR _winreg_AbortSystemShutdown(pipes_struct *p, struct winreg_AbortSystemShutdown *r)
580 const char *abort_shutdown_script;
584 abort_shutdown_script = lp_abort_shutdown_script();
586 if (!*abort_shutdown_script)
587 return WERR_ACCESS_DENIED;
589 can_shutdown = user_has_privileges( p->server_info->ptok,
590 &se_remote_shutdown );
592 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
597 ret = smbrun( abort_shutdown_script, NULL );
602 /********** END SeRemoteShutdownPrivilege BLOCK **********/
604 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
605 abort_shutdown_script, ret));
607 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
610 /*******************************************************************
611 ********************************************************************/
613 static int validate_reg_filename(TALLOC_CTX *ctx, char **pp_fname )
616 int num_services = lp_numservices();
618 const char *share_path;
619 char *fname = *pp_fname;
621 /* convert to a unix path, stripping the C:\ along the way */
623 if (!(p = valid_share_pathname(ctx, fname))) {
627 /* has to exist within a valid file share */
629 for (snum=0; snum<num_services; snum++) {
630 if (!lp_snum_ok(snum) || lp_print_ok(snum)) {
634 share_path = lp_pathname(snum);
636 /* make sure we have a path (e.g. [homes] ) */
637 if (strlen(share_path) == 0) {
641 if (strncmp(share_path, p, strlen(share_path)) == 0) {
647 return (snum < num_services) ? snum : -1;
650 /*******************************************************************
651 ********************************************************************/
653 WERROR _winreg_RestoreKey(pipes_struct *p, struct winreg_RestoreKey *r)
655 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
662 if ( !r->in.filename || !r->in.filename->name )
663 return WERR_INVALID_PARAM;
665 fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
670 DEBUG(8,("_winreg_RestoreKey: verifying restore of key [%s] from "
671 "\"%s\"\n", regkey->key->name, fname));
673 if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1)
674 return WERR_OBJECT_PATH_INVALID;
676 /* user must posses SeRestorePrivilege for this this proceed */
678 if ( !user_has_privileges( p->server_info->ptok, &se_restore ) )
679 return WERR_ACCESS_DENIED;
681 DEBUG(2,("_winreg_RestoreKey: Restoring [%s] from %s in share %s\n",
682 regkey->key->name, fname, lp_servicename(snum) ));
684 return reg_restorekey(regkey, fname);
687 WERROR _winreg_SaveKey(pipes_struct *p, struct winreg_SaveKey *r)
689 struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
696 if ( !r->in.filename || !r->in.filename->name )
697 return WERR_INVALID_PARAM;
699 fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
704 DEBUG(8,("_winreg_SaveKey: verifying backup of key [%s] to \"%s\"\n",
705 regkey->key->name, fname));
707 if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1 )
708 return WERR_OBJECT_PATH_INVALID;
710 DEBUG(2,("_winreg_SaveKey: Saving [%s] to %s in share %s\n",
711 regkey->key->name, fname, lp_servicename(snum) ));
713 return reg_savekey(regkey, fname);
716 /*******************************************************************
717 ********************************************************************/
719 WERROR _winreg_SaveKeyEx(pipes_struct *p, struct winreg_SaveKeyEx *r)
721 /* fill in your code here if you think this call should
724 p->rng_fault_state = True;
725 return WERR_NOT_SUPPORTED;
728 /*******************************************************************
729 ********************************************************************/
731 WERROR _winreg_CreateKey( pipes_struct *p, struct winreg_CreateKey *r)
733 struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
734 struct registry_key *new_key;
740 DEBUG(10, ("_winreg_CreateKey called with parent key '%s' and "
741 "subkey name '%s'\n", parent->key->name, r->in.name.name));
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, 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;