r18954: Fix segv in QueryValue and Enumvalue. regedit.exe now
[Samba/bb.git] / source / rpc_server / srv_winreg_nt.c
blobc5e42307069d2e2deca25ba899db618c6f0a81be
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1997.
5 * Copyright (C) Jeremy Allison 2001.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* Implementation of registry functions. */
25 #include "includes.h"
26 #include "regfio.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_RPC_SRV
31 #if 0 /* temporaily disabled */
32 static struct generic_mapping reg_generic_map =
33 { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
34 #endif
36 /******************************************************************
37 free() function for REGISTRY_KEY
38 *****************************************************************/
40 static void free_regkey_info(void *ptr)
42 regkey_close_internal( (REGISTRY_KEY*)ptr );
45 /******************************************************************
46 Find a registry key handle and return a REGISTRY_KEY
47 *****************************************************************/
49 static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
51 REGISTRY_KEY *regkey = NULL;
53 if(!find_policy_by_hnd(p,hnd,(void **)(void *)&regkey)) {
54 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
55 return NULL;
58 return regkey;
62 /*******************************************************************
63 Function for open a new registry handle and creating a handle
64 Note that P should be valid & hnd should already have space
66 When we open a key, we store the full path to the key as
67 HK[LM|U]\<key>\<key>\...
68 *******************************************************************/
70 static WERROR open_registry_key( pipes_struct *p, POLICY_HND *hnd,
71 REGISTRY_KEY **keyinfo, REGISTRY_KEY *parent,
72 const char *subkeyname, uint32 access_desired )
74 pstring keypath;
75 int path_len;
76 WERROR result = WERR_OK;
78 /* create a full registry path and strip any trailing '\'
79 characters */
81 pstr_sprintf( keypath, "%s%s%s",
82 parent ? parent->name : "",
83 parent ? "\\" : "",
84 subkeyname );
86 path_len = strlen( keypath );
87 if ( path_len && keypath[path_len-1] == '\\' )
88 keypath[path_len-1] = '\0';
90 /* now do the internal open */
92 result = regkey_open_internal( keyinfo, keypath, p->pipe_user.nt_user_token, access_desired );
93 if ( !W_ERROR_IS_OK(result) )
94 return result;
96 if ( !create_policy_hnd( p, hnd, free_regkey_info, *keyinfo ) ) {
97 result = WERR_BADFILE;
98 regkey_close_internal( *keyinfo );
101 return result;
104 /*******************************************************************
105 Function for open a new registry handle and creating a handle
106 Note that P should be valid & hnd should already have space
107 *******************************************************************/
109 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
111 REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd);
113 if ( !regkey ) {
114 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
115 return False;
118 close_policy_hnd(p, hnd);
120 return True;
123 /********************************************************************
124 retrieve information about the subkeys
125 *******************************************************************/
127 static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen )
129 int num_subkeys, i;
130 uint32 max_len;
131 REGSUBKEY_CTR *subkeys;
132 uint32 len;
134 if ( !key )
135 return False;
137 if ( !(subkeys = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) )
138 return False;
140 if ( fetch_reg_keys( key, subkeys ) == -1 )
141 return False;
143 /* find the longest string */
145 max_len = 0;
146 num_subkeys = regsubkey_ctr_numkeys( subkeys );
148 for ( i=0; i<num_subkeys; i++ ) {
149 len = strlen( regsubkey_ctr_specific_key(subkeys, i) );
150 max_len = MAX(max_len, len);
153 *maxnum = num_subkeys;
154 *maxlen = max_len*2;
156 TALLOC_FREE( subkeys );
158 return True;
161 /********************************************************************
162 retrieve information about the values.
163 *******************************************************************/
165 static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum,
166 uint32 *maxlen, uint32 *maxsize )
168 REGVAL_CTR *values;
169 REGISTRY_VALUE *val;
170 uint32 sizemax, lenmax;
171 int i, num_values;
173 if ( !key )
174 return False;
176 if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) )
177 return False;
179 if ( fetch_reg_values( key, values ) == -1 )
180 return False;
182 lenmax = sizemax = 0;
183 num_values = regval_ctr_numvals( values );
185 val = regval_ctr_specific_value( values, 0 );
187 for ( i=0; i<num_values && val; i++ )
189 lenmax = MAX(lenmax, val->valuename ? strlen(val->valuename)+1 : 0 );
190 sizemax = MAX(sizemax, val->size );
192 val = regval_ctr_specific_value( values, i );
195 *maxnum = num_values;
196 *maxlen = lenmax;
197 *maxsize = sizemax;
199 TALLOC_FREE( values );
201 return True;
205 /********************************************************************
206 reg_close
207 ********************************************************************/
209 WERROR _winreg_CloseKey(pipes_struct *p, struct policy_handle *handle)
211 /* close the policy handle */
213 if (!close_registry_key(p, handle))
214 return WERR_BADFID;
216 return WERR_OK;
219 /*******************************************************************
220 ********************************************************************/
222 WERROR _winreg_OpenHKLM(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
224 REGISTRY_KEY *keyinfo;
226 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKLM, access_mask );
229 /*******************************************************************
230 ********************************************************************/
232 WERROR _winreg_OpenHKPD(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
234 REGISTRY_KEY *keyinfo;
236 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKPD, access_mask );
239 /*******************************************************************
240 ********************************************************************/
242 WERROR _winreg_OpenHKPT(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
244 REGISTRY_KEY *keyinfo;
246 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKPT, access_mask );
249 /*******************************************************************
250 ********************************************************************/
252 WERROR _winreg_OpenHKCR(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
254 REGISTRY_KEY *keyinfo;
256 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKCR, access_mask );
259 /*******************************************************************
260 ********************************************************************/
262 WERROR _winreg_OpenHKU(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
264 REGISTRY_KEY *keyinfo;
266 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKU, access_mask );
269 /*******************************************************************
270 ********************************************************************/
272 WERROR _winreg_OpenHKCU(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
274 REGISTRY_KEY *keyinfo;
276 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKCU, access_mask );
279 /*******************************************************************
280 ********************************************************************/
282 WERROR _winreg_OpenHKCC(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
284 REGISTRY_KEY *keyinfo;
286 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKCC, access_mask );
289 /*******************************************************************
290 ********************************************************************/
292 WERROR _winreg_OpenHKDD(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
294 REGISTRY_KEY *keyinfo;
296 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKDD, access_mask );
299 /*******************************************************************
300 ********************************************************************/
302 WERROR _winreg_OpenHKPN(pipes_struct *p, uint16_t *system_name, uint32_t access_mask, struct policy_handle *handle)
304 REGISTRY_KEY *keyinfo;
306 return open_registry_key( p, handle, &keyinfo, NULL, KEY_HKPN, access_mask );
309 /*******************************************************************
310 reg_reply_open_entry
311 ********************************************************************/
313 WERROR _winreg_OpenKey(pipes_struct *p, struct policy_handle *parent_handle, struct winreg_String keyname, uint32_t unknown, uint32_t access_mask, struct policy_handle *handle)
315 char *name;
316 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, parent_handle );
317 REGISTRY_KEY *newkey = NULL;
318 uint32 check_rights;
320 if ( !parent )
321 return WERR_BADFID;
323 if ( (name = talloc_strdup( p->mem_ctx, keyname.name )) == NULL ) {
324 return WERR_INVALID_PARAM;
327 /* check granted access first; what is the correct mask here? */
329 check_rights = ( SEC_RIGHTS_ENUM_SUBKEYS|
330 SEC_RIGHTS_CREATE_SUBKEY|
331 SEC_RIGHTS_QUERY_VALUE|
332 SEC_RIGHTS_SET_VALUE);
334 if ( !(parent->access_granted & check_rights) ) {
335 DEBUG(8,("Rights check failed, parent had %04x, check_rights %04x\n",parent->access_granted, check_rights));
336 return WERR_ACCESS_DENIED;
340 * very crazy, but regedit.exe on Win2k will attempt to call
341 * REG_OPEN_ENTRY with a keyname of "". We should return a new
342 * (second) handle here on the key->name. regedt32.exe does
343 * not do this stupidity. --jerry
346 return open_registry_key( p, handle, &newkey, parent, name, access_mask );
349 /*******************************************************************
350 reg_reply_info
351 ********************************************************************/
353 WERROR _winreg_QueryValue(pipes_struct *p, struct policy_handle *handle, struct winreg_String value_name, enum winreg_Type *type, uint8_t *data, uint32_t *data_size, uint32_t *value_length)
355 WERROR status = WERR_BADFILE;
356 char *name;
357 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, handle );
358 REGISTRY_VALUE *val = NULL;
359 REGVAL_CTR *regvals;
360 int i;
362 if ( !regkey )
363 return WERR_BADFID;
365 *value_length = *type = 0;
367 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
368 DEBUG(7,("_reg_info: policy key type = [%08x]\n", regkey->type));
370 if ( (name = talloc_strdup( p->mem_ctx, value_name.name )) == NULL ) {
371 return WERR_NOMEM;
374 DEBUG(5,("_reg_info: looking up value: [%s]\n", name));
376 if ( !(regvals = TALLOC_ZERO_P( p->mem_ctx, REGVAL_CTR )) )
377 return WERR_NOMEM;
379 /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */
380 if(regkey->type == REG_KEY_HKPD)
382 if(strequal(name, "Global"))
384 uint32 outbuf_len;
385 prs_struct prs_hkpd;
386 prs_init(&prs_hkpd, *data_size, p->mem_ctx, MARSHALL);
387 status = reg_perfcount_get_hkpd(&prs_hkpd, *data_size, &outbuf_len, NULL);
388 regval_ctr_addvalue(regvals, "HKPD", REG_BINARY,
389 prs_hkpd.data_p, outbuf_len);
390 val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
391 prs_mem_free(&prs_hkpd);
393 else if(strequal(name, "Counter 009"))
395 uint32 base_index;
396 uint32 buffer_size;
397 char *buffer;
399 buffer = NULL;
400 base_index = reg_perfcount_get_base_index();
401 buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
402 regval_ctr_addvalue(regvals, "Counter 009",
403 REG_MULTI_SZ, buffer, buffer_size);
405 val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
407 if(buffer_size > 0)
409 SAFE_FREE(buffer);
410 status = WERR_OK;
413 else if(strequal(name, "Explain 009"))
415 uint32 base_index;
416 uint32 buffer_size;
417 char *buffer;
419 buffer = NULL;
420 base_index = reg_perfcount_get_base_index();
421 buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
422 regval_ctr_addvalue(regvals, "Explain 009",
423 REG_MULTI_SZ, buffer, buffer_size);
425 val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
427 if(buffer_size > 0)
429 SAFE_FREE(buffer);
430 status = WERR_OK;
433 else if(isdigit(name[0]))
435 /* we probably have a request for a specific object here */
436 uint32 outbuf_len;
437 prs_struct prs_hkpd;
438 prs_init(&prs_hkpd, *data_size, p->mem_ctx, MARSHALL);
439 status = reg_perfcount_get_hkpd(&prs_hkpd, *data_size, &outbuf_len, name);
440 regval_ctr_addvalue(regvals, "HKPD", REG_BINARY,
441 prs_hkpd.data_p, outbuf_len);
443 val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
444 prs_mem_free(&prs_hkpd);
446 else
448 DEBUG(3,("Unsupported key name [%s] for HKPD.\n", name));
449 return WERR_BADFILE;
452 /* HKPT calls can be handled out of reg_dynamic.c with the hkpt_params handler */
453 else
455 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
457 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
458 if ( strequal( val->valuename, name ) ) {
459 DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
460 status = WERR_OK;
461 break;
464 free_registry_value( val );
468 /* if we have a value then copy it to the output */
470 if ( val ) {
471 *value_length = regval_size( val );
472 *type = val->type;
474 if ( *data_size == 0 || !data ) {
475 status = WERR_OK;
476 } else if ( *value_length > *data_size ) {
477 status = WERR_MORE_DATA;
478 } else {
479 memcpy( data, regval_data_p(val), *value_length );
480 status = WERR_OK;
483 *data_size = *value_length;
486 TALLOC_FREE( regvals );
487 free_registry_value( val );
489 return status;
492 /*****************************************************************************
493 Implementation of REG_QUERY_KEY
494 ****************************************************************************/
496 WERROR _winreg_QueryInfoKey(pipes_struct *p, struct policy_handle *handle,
497 struct winreg_String *classname,
498 uint32_t *num_subkeys, uint32_t *max_subkeylen,
499 uint32_t *max_subkeysize,
500 uint32_t *num_values, uint32_t *max_valnamelen,
501 uint32_t *max_valbufsize,
502 uint32_t *secdescsize, NTTIME *last_changed_time)
504 WERROR status = WERR_OK;
505 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, handle );
507 if ( !regkey )
508 return WERR_BADFID;
510 if ( !get_subkey_information( regkey, num_subkeys, max_subkeylen) ) {
511 DEBUG(0,("_winreg_QueryInfoKey: get_subkey_information() failed!\n"));
512 return WERR_ACCESS_DENIED;
515 if ( !get_value_information( regkey, num_values, max_valnamelen, max_valbufsize) ) {
516 DEBUG(0,("_winreg_QueryInfoKey: get_value_information() failed!\n"));
517 return WERR_ACCESS_DENIED;
520 *secdescsize = 0; /* used to be hard coded for 0x00000078 */
521 *last_changed_time = 0;
522 *max_subkeysize = 0; /* maybe this is the classname length ? */
524 /* don't bother with class names for now */
526 classname->name = NULL;
528 return status;
532 /*****************************************************************************
533 Implementation of REG_GETVERSION
534 ****************************************************************************/
536 WERROR _winreg_GetVersion(pipes_struct *p, struct policy_handle *handle, uint32_t *version)
538 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, handle );
540 if ( !regkey )
541 return WERR_BADFID;
543 *version = 0x00000005; /* Windows 2000 registry API version */
545 return WERR_OK;
549 /*****************************************************************************
550 Implementation of REG_ENUM_KEY
551 ****************************************************************************/
553 WERROR _winreg_EnumKey(pipes_struct *p, struct policy_handle *handle, uint32_t enum_index, struct winreg_StringBuf *name, struct winreg_StringBuf *keyclass, NTTIME *last_changed_time)
555 WERROR status = WERR_OK;
556 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, handle );
557 char *subkey = NULL;
560 if ( !regkey )
561 return WERR_BADFID;
563 if ( !name || !keyclass )
564 return WERR_INVALID_PARAM;
566 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
568 if ( !fetch_reg_keys_specific( regkey, &subkey, enum_index ) ) {
569 status = WERR_NO_MORE_ITEMS;
570 goto done;
573 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
575 if ( last_changed_time ) {
576 *last_changed_time = 0;
578 keyclass->name = NULL;
579 if ( (name->name = talloc_strdup( p->mem_ctx, subkey )) == NULL ) {
580 status = WERR_NOMEM;
583 done:
584 SAFE_FREE( subkey );
585 return status;
588 /*****************************************************************************
589 Implementation of REG_ENUM_VALUE
590 ****************************************************************************/
592 WERROR _winreg_EnumValue(pipes_struct *p, struct policy_handle *handle, uint32_t enum_index, struct winreg_StringBuf *name, enum winreg_Type *type, uint8_t *data, uint32_t *data_size, uint32_t *value_length)
594 WERROR status = WERR_OK;
595 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, handle );
596 REGISTRY_VALUE *val;
598 if ( !regkey )
599 return WERR_BADFID;
601 if ( !name )
602 return WERR_INVALID_PARAM;
604 DEBUG(8,("_winreg_EnumValue: enumerating values for key [%s]\n", regkey->name));
606 if ( !fetch_reg_values_specific( regkey, &val, enum_index ) ) {
607 status = WERR_NO_MORE_ITEMS;
608 goto done;
611 DEBUG(10,("_winreg_EnumValue: retrieved value named [%s]\n", val->valuename));
613 /* subkey has the string name now */
615 if ( (name->name = talloc_strdup( p->mem_ctx, val->valuename )) == NULL ) {
616 status = WERR_NOMEM;
619 *value_length = regval_size( val );
620 *type = val->type;
622 if ( *data_size == 0 || !data ) {
623 status = WERR_OK;
624 } else if ( *value_length > *data_size ) {
625 status = WERR_MORE_DATA;
626 } else {
627 memcpy( data, regval_data_p(val), *value_length );
628 status = WERR_OK;
631 *data_size = *value_length;
633 done:
634 free_registry_value( val );
636 return status;
640 /*******************************************************************
641 reg_shutdwon
642 ********************************************************************/
644 WERROR _winreg_InitiateSystemShutdown(pipes_struct *p, uint16_t *hostname, struct initshutdown_String *message, uint32_t timeout, uint8_t force_apps, uint8_t reboot)
646 uint32_t reason = 0;
648 /* thunk down to _winreg_InitiateSystemShutdownEx()
649 (just returns a status) */
651 return _winreg_InitiateSystemShutdownEx( p, hostname, message, timeout,
652 force_apps, reboot, reason );
655 /*******************************************************************
656 reg_shutdown_ex
657 ********************************************************************/
659 #define SHUTDOWN_R_STRING "-r"
660 #define SHUTDOWN_F_STRING "-f"
663 WERROR _winreg_InitiateSystemShutdownEx(pipes_struct *p, uint16_t *hostname, struct initshutdown_String *message, uint32_t timeout, uint8_t force_apps, uint8_t reboot, uint32_t reason)
665 pstring shutdown_script;
666 char *msg = NULL;
667 pstring chkmsg;
668 fstring str_timeout;
669 fstring str_reason;
670 fstring r;
671 fstring f;
672 int ret;
673 BOOL can_shutdown;
676 pstrcpy(shutdown_script, lp_shutdown_script());
678 if ( !*shutdown_script )
679 return WERR_ACCESS_DENIED;
681 /* pull the message string and perform necessary sanity checks on it */
683 if ( message && message->name && message->name->name ) {
684 if ( (msg = talloc_strdup(p->mem_ctx, message->name->name )) == NULL ) {
685 return WERR_NOMEM;
688 alpha_strcpy (chkmsg, msg?msg:"", NULL, strlen(msg));
690 fstr_sprintf(str_timeout, "%d", timeout);
691 fstr_sprintf(r, reboot ? SHUTDOWN_R_STRING : "");
692 fstr_sprintf(f, force_apps ? SHUTDOWN_F_STRING : "");
693 fstr_sprintf(str_reason, "%d", reason );
695 all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
696 all_string_sub( shutdown_script, "%t", str_timeout, sizeof(shutdown_script) );
697 all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
698 all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
699 all_string_sub( shutdown_script, "%x", str_reason, sizeof(shutdown_script) );
701 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
703 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
704 Take the error return from the script and provide it as the Windows return code. */
706 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
708 if ( can_shutdown )
709 become_root();
711 ret = smbrun( shutdown_script, NULL );
713 if ( can_shutdown )
714 unbecome_root();
716 /********** END SeRemoteShutdownPrivilege BLOCK **********/
718 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
719 shutdown_script, ret));
722 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
728 /*******************************************************************
729 reg_abort_shutdwon
730 ********************************************************************/
732 WERROR _winreg_AbortSystemShutdown(pipes_struct *p, uint16_t *server)
734 pstring abort_shutdown_script;
735 int ret;
736 BOOL can_shutdown;
738 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
740 if ( !*abort_shutdown_script )
741 return WERR_ACCESS_DENIED;
743 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
745 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
747 if ( can_shutdown )
748 become_root();
750 ret = smbrun( abort_shutdown_script, NULL );
752 if ( can_shutdown )
753 unbecome_root();
755 /********** END SeRemoteShutdownPrivilege BLOCK **********/
757 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
758 abort_shutdown_script, ret));
761 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
764 #if 0 /* This code works but is disabled for now until I
765 fix the WinReg IDL file -- jerry */
767 /*******************************************************************
768 ********************************************************************/
770 static int validate_reg_filename( pstring fname )
772 char *p;
773 int num_services = lp_numservices();
774 int snum;
775 pstring share_path;
776 pstring unix_fname;
778 /* convert to a unix path, stripping the C:\ along the way */
780 if ( !(p = valid_share_pathname( fname ) ))
781 return -1;
783 /* has to exist within a valid file share */
785 for ( snum=0; snum<num_services; snum++ ) {
787 if ( !lp_snum_ok(snum) || lp_print_ok(snum) )
788 continue;
790 pstrcpy( share_path, lp_pathname(snum) );
792 /* make sure we have a path (e.g. [homes] ) */
794 if ( strlen( share_path ) == 0 )
795 continue;
797 if ( strncmp( share_path, p, strlen( share_path )) == 0 )
798 break;
801 /* p and fname are overlapping memory so copy out and back in again */
803 pstrcpy( unix_fname, p );
804 pstrcpy( fname, unix_fname );
806 return (snum < num_services) ? snum : -1;
809 /*******************************************************************
810 Note: topkeypat is the *full* path that this *key will be
811 loaded into (including the name of the key)
812 ********************************************************************/
814 static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath,
815 REGF_NK_REC *key )
817 REGF_NK_REC *subkey;
818 REGISTRY_KEY registry_key;
819 REGVAL_CTR *values;
820 REGSUBKEY_CTR *subkeys;
821 int i;
822 pstring path;
823 WERROR result = WERR_OK;
825 /* initialize the REGISTRY_KEY structure */
827 if ( !(registry_key.hook = reghook_cache_find(topkeypath)) ) {
828 DEBUG(0,("reg_load_tree: Failed to assigned a REGISTRY_HOOK to [%s]\n",
829 topkeypath ));
830 return WERR_BADFILE;
832 pstrcpy( registry_key.name, topkeypath );
834 /* now start parsing the values and subkeys */
836 if ( !(subkeys = TALLOC_ZERO_P( regfile->mem_ctx, REGSUBKEY_CTR )) )
837 return WERR_NOMEM;
839 if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) )
840 return WERR_NOMEM;
842 /* copy values into the REGVAL_CTR */
844 for ( i=0; i<key->num_values; i++ ) {
845 regval_ctr_addvalue( values, key->values[i].valuename, key->values[i].type,
846 (char*)key->values[i].data, (key->values[i].data_size & ~VK_DATA_IN_OFFSET) );
849 /* copy subkeys into the REGSUBKEY_CTR */
851 key->subkey_index = 0;
852 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
853 regsubkey_ctr_addkey( subkeys, subkey->keyname );
856 /* write this key and values out */
858 if ( !store_reg_values( &registry_key, values )
859 || !store_reg_keys( &registry_key, subkeys ) )
861 DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
862 result = WERR_REG_IO_FAILURE;
865 TALLOC_FREE( subkeys );
867 if ( !W_ERROR_IS_OK(result) )
868 return result;
870 /* now continue to load each subkey registry tree */
872 key->subkey_index = 0;
873 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
874 pstr_sprintf( path, "%s%s%s", topkeypath, "\\", subkey->keyname );
875 result = reg_load_tree( regfile, path, subkey );
876 if ( !W_ERROR_IS_OK(result) )
877 break;
880 return result;
883 /*******************************************************************
884 ********************************************************************/
886 static WERROR restore_registry_key ( REGISTRY_KEY *krecord, const char *fname )
888 REGF_FILE *regfile;
889 REGF_NK_REC *rootkey;
890 WERROR result;
892 /* open the registry file....fail if the file already exists */
894 if ( !(regfile = regfio_open( fname, (O_RDONLY), 0 )) ) {
895 DEBUG(0,("restore_registry_key: failed to open \"%s\" (%s)\n",
896 fname, strerror(errno) ));
897 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
900 /* get the rootkey from the regf file and then load the tree
901 via recursive calls */
903 if ( !(rootkey = regfio_rootkey( regfile )) ) {
904 regfio_close( regfile );
905 return WERR_REG_FILE_INVALID;
908 result = reg_load_tree( regfile, krecord->name, rootkey );
910 /* cleanup */
912 regfio_close( regfile );
914 return result;
917 #endif
919 /*******************************************************************
920 ********************************************************************/
922 WERROR _winreg_RestoreKey(pipes_struct *p)
924 #if 0 /* temporarily disabled */
925 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
926 pstring filename;
927 int snum;
929 if ( !regkey )
930 return WERR_BADFID;
932 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
934 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
936 if ( (snum = validate_reg_filename( filename )) == -1 )
937 return WERR_OBJECT_PATH_INVALID;
939 /* user must posses SeRestorePrivilege for this this proceed */
941 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
942 return WERR_ACCESS_DENIED;
944 DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
946 return restore_registry_key( regkey, filename );
947 #endif
949 return WERR_NOT_SUPPORTED;
952 #if 0 /* this code works but has been disable until I fix
953 the winreg IDL -- jerry */
955 /********************************************************************
956 ********************************************************************/
958 static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath,
959 REGF_NK_REC *parent, SEC_DESC *sec_desc )
961 REGF_NK_REC *key;
962 REGVAL_CTR *values;
963 REGSUBKEY_CTR *subkeys;
964 int i, num_subkeys;
965 pstring key_tmp;
966 char *keyname, *parentpath;
967 pstring subkeypath;
968 char *subkeyname;
969 REGISTRY_KEY registry_key;
970 WERROR result = WERR_OK;
972 if ( !regfile )
973 return WERR_GENERAL_FAILURE;
975 if ( !keypath )
976 return WERR_OBJECT_PATH_INVALID;
978 /* split up the registry key path */
980 pstrcpy( key_tmp, keypath );
981 if ( !reg_split_key( key_tmp, &parentpath, &keyname ) )
982 return WERR_OBJECT_PATH_INVALID;
984 if ( !keyname )
985 keyname = parentpath;
987 /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
989 ZERO_STRUCT( registry_key );
990 pstrcpy( registry_key.name, keypath );
991 if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) )
992 return WERR_BADFILE;
995 /* lookup the values and subkeys */
997 if ( !(subkeys = TALLOC_ZERO_P( regfile->mem_ctx, REGSUBKEY_CTR )) )
998 return WERR_NOMEM;
1000 if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) )
1001 return WERR_NOMEM;
1003 fetch_reg_keys( &registry_key, subkeys );
1004 fetch_reg_values( &registry_key, values );
1006 /* write out this key */
1008 if ( !(key = regfio_write_key( regfile, keyname, values, subkeys, sec_desc, parent )) ) {
1009 result = WERR_CAN_NOT_COMPLETE;
1010 goto done;
1013 /* write each one of the subkeys out */
1015 num_subkeys = regsubkey_ctr_numkeys( subkeys );
1016 for ( i=0; i<num_subkeys; i++ ) {
1017 subkeyname = regsubkey_ctr_specific_key( subkeys, i );
1018 pstr_sprintf( subkeypath, "%s\\%s", keypath, subkeyname );
1019 result = reg_write_tree( regfile, subkeypath, key, sec_desc );
1020 if ( !W_ERROR_IS_OK(result) )
1021 goto done;
1024 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath ));
1026 done:
1027 TALLOC_FREE( subkeys );
1029 return result;
1032 /*******************************************************************
1033 ********************************************************************/
1035 static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
1037 DOM_SID adm_sid, owner_sid;
1038 SEC_ACE ace[2]; /* at most 2 entries */
1039 SEC_ACCESS mask;
1040 SEC_ACL *psa = NULL;
1041 size_t sd_size;
1043 /* set the owner to BUILTIN\Administrator */
1045 sid_copy(&owner_sid, &global_sid_Builtin);
1046 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
1049 /* basic access for Everyone */
1051 init_sec_access(&mask, reg_generic_map.generic_execute | reg_generic_map.generic_read );
1052 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1054 /* add Full Access 'BUILTIN\Administrators' */
1056 init_sec_access(&mask, reg_generic_map.generic_all);
1057 sid_copy(&adm_sid, &global_sid_Builtin);
1058 sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
1059 init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1061 /* create the security descriptor */
1063 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace)) == NULL)
1064 return WERR_NOMEM;
1066 if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &owner_sid, NULL, NULL, psa, &sd_size)) == NULL)
1067 return WERR_NOMEM;
1069 return WERR_OK;
1072 /*******************************************************************
1073 ********************************************************************/
1075 static WERROR backup_registry_key ( REGISTRY_KEY *krecord, const char *fname )
1077 REGF_FILE *regfile;
1078 WERROR result;
1079 SEC_DESC *sd = NULL;
1081 /* open the registry file....fail if the file already exists */
1083 if ( !(regfile = regfio_open( fname, (O_RDWR|O_CREAT|O_EXCL), (S_IREAD|S_IWRITE) )) ) {
1084 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
1085 fname, strerror(errno) ));
1086 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
1089 if ( !W_ERROR_IS_OK(result = make_default_reg_sd( regfile->mem_ctx, &sd )) ) {
1090 regfio_close( regfile );
1091 return result;
1094 /* write the registry tree to the file */
1096 result = reg_write_tree( regfile, krecord->name, NULL, sd );
1098 /* cleanup */
1100 regfio_close( regfile );
1102 return result;
1104 #endif
1106 /*******************************************************************
1107 ********************************************************************/
1109 WERROR _winreg_SaveKey(pipes_struct *p)
1111 #if 0
1112 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
1113 pstring filename;
1114 int snum;
1116 if ( !regkey )
1117 return WERR_BADFID;
1119 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
1121 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
1123 if ( (snum = validate_reg_filename( filename )) == -1 )
1124 return WERR_OBJECT_PATH_INVALID;
1126 DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
1128 return backup_registry_key( regkey, filename );
1129 #endif
1131 /* disabled for now until I fix the IDL --jerry */
1132 return WERR_NOT_SUPPORTED;
1135 /*******************************************************************
1136 ********************************************************************/
1138 WERROR _winreg_SaveKeyEx(pipes_struct *p)
1140 /* disabled for now until I fix the IDL --jerry */
1141 return WERR_NOT_SUPPORTED;
1144 /*******************************************************************
1145 ********************************************************************/
1147 WERROR _winreg_CreateKey( pipes_struct *p, struct policy_handle *handle, struct winreg_String keyname,
1148 struct winreg_String keyclass, uint32_t options, uint32_t access_mask,
1149 struct winreg_SecBuf *secdesc, struct policy_handle *new_handle,
1150 enum winreg_CreateAction *action_taken )
1152 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, handle);
1153 REGISTRY_KEY *newparentinfo, *keyinfo;
1154 POLICY_HND newparent_handle;
1155 REGSUBKEY_CTR *subkeys;
1156 BOOL write_result;
1157 char *name;
1158 WERROR result;
1160 if ( !parent )
1161 return WERR_BADFID;
1163 if ( (name = talloc_strdup( p->mem_ctx, keyname.name )) == NULL ) {
1164 return WERR_NOMEM;
1167 /* ok. Here's what we do. */
1169 if ( strrchr( name, '\\' ) ) {
1170 pstring newkeyname;
1171 char *ptr;
1173 /* (1) check for enumerate rights on the parent handle. CLients can try
1174 create things like 'SOFTWARE\Samba' on the HKLM handle.
1175 (2) open the path to the child parent key if necessary */
1177 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1178 return WERR_ACCESS_DENIED;
1180 pstrcpy( newkeyname, name );
1181 ptr = strrchr( newkeyname, '\\' );
1182 *ptr = '\0';
1184 result = open_registry_key( p, &newparent_handle, &newparentinfo,
1185 parent, newkeyname, (REG_KEY_READ|REG_KEY_WRITE) );
1187 if ( !W_ERROR_IS_OK(result) )
1188 return result;
1190 /* copy the new key name (just the lower most keyname) */
1192 if ( (name = talloc_strdup( p->mem_ctx, ptr+1 )) == NULL ) {
1193 return WERR_NOMEM;
1196 else {
1197 /* use the existing open key information */
1198 newparentinfo = parent;
1199 memcpy( &newparent_handle, handle, sizeof(POLICY_HND) );
1202 /* (3) check for create subkey rights on the correct parent */
1204 if ( !(newparentinfo->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
1205 result = WERR_ACCESS_DENIED;
1206 goto done;
1209 if ( !(subkeys = TALLOC_ZERO_P( p->mem_ctx, REGSUBKEY_CTR )) ) {
1210 result = WERR_NOMEM;
1211 goto done;
1214 /* (4) lookup the current keys and add the new one */
1216 fetch_reg_keys( newparentinfo, subkeys );
1217 regsubkey_ctr_addkey( subkeys, name );
1219 /* now write to the registry backend */
1221 write_result = store_reg_keys( newparentinfo, subkeys );
1223 TALLOC_FREE( subkeys );
1225 if ( !write_result )
1226 return WERR_REG_IO_FAILURE;
1228 /* (5) open the new key and return the handle. Note that it is probably
1229 not correct to grant full access on this open handle. */
1231 result = open_registry_key( p, new_handle, &keyinfo, newparentinfo, name, REG_KEY_READ );
1232 keyinfo->access_granted = REG_KEY_ALL;
1234 /* FIXME: report the truth here */
1236 if ( action_taken ) {
1237 *action_taken = REG_CREATED_NEW_KEY;
1240 done:
1241 /* close any intermediate key handles */
1243 if ( newparentinfo != parent )
1244 close_registry_key( p, &newparent_handle );
1246 return result;
1250 /*******************************************************************
1251 ********************************************************************/
1253 WERROR _winreg_SetValue(pipes_struct *p, struct policy_handle *handle, struct winreg_String name, enum winreg_Type type, uint8_t *data, uint32_t size)
1255 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, handle);
1256 REGVAL_CTR *values;
1257 BOOL write_result;
1258 char *valuename;
1260 if ( !key )
1261 return WERR_BADFID;
1263 /* access checks first */
1265 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1266 return WERR_ACCESS_DENIED;
1268 /* verify the name */
1270 if ( (valuename = talloc_strdup(p->mem_ctx, name.name)) == NULL ) {
1271 return WERR_INVALID_PARAM;
1274 DEBUG(8,("_reg_set_value: Setting value for [%s:%s]\n", key->name, valuename));
1276 if ( !(values = TALLOC_ZERO_P( p->mem_ctx, REGVAL_CTR )) )
1277 return WERR_NOMEM;
1279 /* lookup the current values and add the new one */
1281 fetch_reg_values( key, values );
1283 regval_ctr_addvalue( values, valuename, type, (const char *)data, size );
1285 /* now write to the registry backend */
1287 write_result = store_reg_values( key, values );
1289 TALLOC_FREE( values );
1291 if ( !write_result )
1292 return WERR_REG_IO_FAILURE;
1294 return WERR_OK;
1297 /*******************************************************************
1298 ********************************************************************/
1300 WERROR _winreg_DeleteKey(pipes_struct *p, struct policy_handle *handle, struct winreg_String key)
1302 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, handle);
1303 REGISTRY_KEY *newparentinfo = NULL;
1304 POLICY_HND newparent_handle;
1305 REGSUBKEY_CTR *subkeys;
1306 BOOL write_result;
1307 char *name;
1308 WERROR result;
1310 if ( !parent )
1311 return WERR_BADFID;
1313 /* MSDN says parent the handle must have been opened with DELETE access */
1315 /* (1) check for delete rights on the parent */
1317 if ( !(parent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
1318 result = WERR_ACCESS_DENIED;
1319 goto done;
1322 if ( (name = talloc_strdup( p->mem_ctx, key.name )) == NULL ) {
1323 result = WERR_INVALID_PARAM;
1324 goto done;
1327 /* ok. Here's what we do. */
1329 if ( strrchr( name, '\\' ) ) {
1330 pstring newkeyname;
1331 char *ptr;
1333 /* (2) open the path to the child parent key if necessary */
1334 /* split the registry path and save the subkeyname */
1336 pstrcpy( newkeyname, name );
1337 ptr = strrchr( newkeyname, '\\' );
1338 *ptr = '\0';
1339 if ( (name = talloc_strdup( p->mem_ctx, ptr+1 )) == NULL ) {
1340 result = WERR_NOMEM;
1341 goto done;
1344 result = open_registry_key( p, &newparent_handle, &newparentinfo, parent, newkeyname, (REG_KEY_READ|REG_KEY_WRITE) );
1345 if ( !W_ERROR_IS_OK(result) ) {
1346 goto done;
1349 else {
1350 /* use the existing open key information */
1351 newparentinfo = parent;
1354 if ( !(subkeys = TALLOC_ZERO_P( p->mem_ctx, REGSUBKEY_CTR )) ) {
1355 result = WERR_NOMEM;
1356 goto done;
1359 /* lookup the current keys and delete the new one */
1361 fetch_reg_keys( newparentinfo, subkeys );
1363 regsubkey_ctr_delkey( subkeys, name );
1365 /* now write to the registry backend */
1367 write_result = store_reg_keys( newparentinfo, subkeys );
1369 TALLOC_FREE( subkeys );
1371 result = write_result ? WERR_OK : WERR_REG_IO_FAILURE;
1373 done:
1374 /* close any intermediate key handles */
1376 if ( newparentinfo != parent )
1377 close_registry_key( p, &newparent_handle );
1379 return result;
1383 /*******************************************************************
1384 ********************************************************************/
1386 WERROR _winreg_DeleteValue(pipes_struct *p, struct policy_handle *handle, struct winreg_String value)
1388 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, handle);
1389 REGVAL_CTR *values;
1390 BOOL write_result;
1391 char *valuename;
1393 if ( !key )
1394 return WERR_BADFID;
1396 /* access checks first */
1398 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1399 return WERR_ACCESS_DENIED;
1401 if ( (valuename = talloc_strdup( p->mem_ctx, value.name )) == NULL ) {
1402 return WERR_INVALID_PARAM;
1405 DEBUG(8,("_reg_delete_value: Setting value for [%s:%s]\n", key->name, valuename));
1407 if ( !(values = TALLOC_ZERO_P( p->mem_ctx, REGVAL_CTR )) )
1408 return WERR_NOMEM;
1410 /* lookup the current values and add the new one */
1412 fetch_reg_values( key, values );
1414 regval_ctr_delvalue( values, valuename );
1416 /* now write to the registry backend */
1418 write_result = store_reg_values( key, values );
1420 TALLOC_FREE( values );
1422 if ( !write_result )
1423 return WERR_REG_IO_FAILURE;
1425 return WERR_OK;
1428 /*******************************************************************
1429 ********************************************************************/
1431 WERROR _winreg_GetKeySecurity(pipes_struct *p, struct policy_handle *handle, uint32_t sec_info, struct KeySecurityData *sd)
1433 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, handle);
1435 if ( !key )
1436 return WERR_BADFID;
1438 /* access checks first */
1440 if ( !(key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
1441 return WERR_ACCESS_DENIED;
1443 return WERR_ACCESS_DENIED;
1446 /*******************************************************************
1447 ********************************************************************/
1449 WERROR _winreg_SetKeySecurity(pipes_struct *p, struct policy_handle *handle, uint32_t access_mask, struct KeySecurityData *sd)
1451 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, handle);
1453 if ( !key )
1454 return WERR_BADFID;
1456 /* access checks first */
1458 if ( !(key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
1459 return WERR_ACCESS_DENIED;
1461 return WERR_ACCESS_DENIED;
1464 /*******************************************************************
1465 ********************************************************************/
1467 WERROR _winreg_FlushKey(pipes_struct *p, struct policy_handle *handle)
1469 /* I'm just replying OK because there's not a lot
1470 here I see to do i --jerry */
1472 return WERR_OK;
1475 /*******************************************************************
1476 ********************************************************************/
1478 WERROR _winreg_UnLoadKey(pipes_struct *p)
1480 /* fill in your code here if you think this call should
1481 do anything */
1483 return WERR_NOT_SUPPORTED;
1486 /*******************************************************************
1487 ********************************************************************/
1489 WERROR _winreg_ReplaceKey(pipes_struct *p)
1491 /* fill in your code here if you think this call should
1492 do anything */
1494 return WERR_NOT_SUPPORTED;
1497 /*******************************************************************
1498 ********************************************************************/
1500 WERROR _winreg_LoadKey(pipes_struct *p, struct policy_handle *handle, struct winreg_String *keyname, struct winreg_String *filename)
1502 /* fill in your code here if you think this call should
1503 do anything */
1505 return WERR_NOT_SUPPORTED;
1508 /*******************************************************************
1509 ********************************************************************/
1511 WERROR _winreg_NotifyChangeKeyValue(pipes_struct *p, struct policy_handle *handle, uint8_t watch_subtree, uint32_t notify_filter, uint32_t unknown, struct winreg_String string1, struct winreg_String string2, uint32_t unknown2)
1513 /* fill in your code here if you think this call should
1514 do anything */
1516 return WERR_NOT_SUPPORTED;
1519 /*******************************************************************
1520 ********************************************************************/
1522 WERROR _winreg_QueryMultipleValues(pipes_struct *p, struct policy_handle *key_handle, struct QueryMultipleValue *values, uint32_t num_values, uint8_t *buffer, uint32_t *buffer_size)
1524 /* fill in your code here if you think this call should
1525 do anything */
1527 return WERR_NOT_SUPPORTED;
1530 /*******************************************************************
1531 ********************************************************************/
1533 WERROR _winreg_QueryMultipleValues2(pipes_struct *p)
1535 /* fill in your code here if you think this call should
1536 do anything */
1538 return WERR_NOT_SUPPORTED;