r6303: Setting up for 3.0.15pre1
[Samba.git] / source / rpc_server / srv_reg_nt.c
blobf031a3213f2a167f6970d68cefddcf5ab4805fd0
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1997.
5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
6 * Copyright (C) Paul Ashton 1997.
7 * Copyright (C) Jeremy Allison 2001.
8 * Copyright (C) Gerald Carter 2002-2005.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* Implementation of registry functions. */
27 #include "includes.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_RPC_SRV
32 #define REGSTR_PRODUCTTYPE "ProductType"
33 #define REG_PT_WINNT "WinNT"
34 #define REG_PT_LANMANNT "LanmanNT"
35 #define REG_PT_SERVERNT "ServerNT"
37 #define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
38 ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
41 static REGISTRY_KEY *regkeys_list;
44 /******************************************************************
45 free() function for REGISTRY_KEY
46 *****************************************************************/
48 static void free_regkey_info(void *ptr)
50 REGISTRY_KEY *info = (REGISTRY_KEY*)ptr;
52 DLIST_REMOVE(regkeys_list, info);
54 SAFE_FREE(info);
57 /******************************************************************
58 Find a registry key handle and return a REGISTRY_KEY
59 *****************************************************************/
61 static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
63 REGISTRY_KEY *regkey = NULL;
65 if(!find_policy_by_hnd(p,hnd,(void **)&regkey)) {
66 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
67 return NULL;
70 return regkey;
74 /*******************************************************************
75 Function for open a new registry handle and creating a handle
76 Note that P should be valid & hnd should already have space
78 When we open a key, we store the full path to the key as
79 HK[LM|U]\<key>\<key>\...
80 *******************************************************************/
82 static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY *parent,
83 const char *subkeyname, uint32 access_granted )
85 REGISTRY_KEY *regkey = NULL;
86 WERROR result = WERR_OK;
87 REGSUBKEY_CTR subkeys;
88 pstring subkeyname2;
89 int subkey_len;
91 DEBUG(7,("open_registry_key: name = [%s][%s]\n",
92 parent ? parent->name : "NULL", subkeyname));
94 /* strip any trailing '\'s */
95 pstrcpy( subkeyname2, subkeyname );
96 subkey_len = strlen ( subkeyname2 );
97 if ( subkey_len && subkeyname2[subkey_len-1] == '\\' )
98 subkeyname2[subkey_len-1] = '\0';
100 if ((regkey=SMB_MALLOC_P(REGISTRY_KEY)) == NULL)
101 return WERR_NOMEM;
103 ZERO_STRUCTP( regkey );
106 * very crazy, but regedit.exe on Win2k will attempt to call
107 * REG_OPEN_ENTRY with a keyname of "". We should return a new
108 * (second) handle here on the key->name. regedt32.exe does
109 * not do this stupidity. --jerry
112 if ( !subkey_len ) {
113 pstrcpy( regkey->name, parent->name );
115 else {
116 pstrcpy( regkey->name, "" );
117 if ( parent ) {
118 pstrcat( regkey->name, parent->name );
119 pstrcat( regkey->name, "\\" );
121 pstrcat( regkey->name, subkeyname2 );
124 /* Look up the table of registry I/O operations */
126 if ( !(regkey->hook = reghook_cache_find( regkey->name )) ) {
127 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
128 regkey->name ));
129 return WERR_BADFILE;
132 /* check if the path really exists; failed is indicated by -1 */
133 /* if the subkey count failed, bail out */
135 ZERO_STRUCTP( &subkeys );
137 regsubkey_ctr_init( &subkeys );
139 if ( fetch_reg_keys( regkey, &subkeys ) == -1 ) {
141 /* don't really know what to return here */
142 result = WERR_BADFILE;
144 else {
146 * This would previously return NT_STATUS_TOO_MANY_SECRETS
147 * that doesn't sound quite right to me --jerry
150 if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) )
151 result = WERR_BADFILE;
154 /* clean up */
156 regsubkey_ctr_destroy( &subkeys );
158 if ( ! NT_STATUS_IS_OK(result) )
159 SAFE_FREE( regkey );
160 else
161 DLIST_ADD( regkeys_list, regkey );
164 DEBUG(7,("open_registry_key: exit\n"));
166 return result;
169 /*******************************************************************
170 Function for open a new registry handle and creating a handle
171 Note that P should be valid & hnd should already have space
172 *******************************************************************/
174 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
176 REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd);
178 if ( !regkey ) {
179 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
180 return False;
183 close_policy_hnd(p, hnd);
185 return True;
188 /********************************************************************
189 retrieve information about the subkeys
190 *******************************************************************/
192 static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen )
194 int num_subkeys, i;
195 uint32 max_len;
196 REGSUBKEY_CTR subkeys;
197 uint32 len;
199 if ( !key )
200 return False;
202 ZERO_STRUCTP( &subkeys );
204 regsubkey_ctr_init( &subkeys );
206 if ( fetch_reg_keys( key, &subkeys ) == -1 )
207 return False;
209 /* find the longest string */
211 max_len = 0;
212 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
214 for ( i=0; i<num_subkeys; i++ ) {
215 len = strlen( regsubkey_ctr_specific_key(&subkeys, i) );
216 max_len = MAX(max_len, len);
219 *maxnum = num_subkeys;
220 *maxlen = max_len*2;
222 regsubkey_ctr_destroy( &subkeys );
224 return True;
227 /********************************************************************
228 retrieve information about the values. We don't store values
229 here. The registry tdb is intended to be a frontend to oether
230 Samba tdb's (such as ntdrivers.tdb).
231 *******************************************************************/
233 static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum,
234 uint32 *maxlen, uint32 *maxsize )
236 REGVAL_CTR values;
237 REGISTRY_VALUE *val;
238 uint32 sizemax, lenmax;
239 int i, num_values;
241 if ( !key )
242 return False;
245 ZERO_STRUCTP( &values );
247 regval_ctr_init( &values );
249 if ( fetch_reg_values( key, &values ) == -1 )
250 return False;
252 lenmax = sizemax = 0;
253 num_values = regval_ctr_numvals( &values );
255 val = regval_ctr_specific_value( &values, 0 );
257 for ( i=0; i<num_values && val; i++ )
259 lenmax = MAX(lenmax, strlen(val->valuename)+1 );
260 sizemax = MAX(sizemax, val->size );
262 val = regval_ctr_specific_value( &values, i );
265 *maxnum = num_values;
266 *maxlen = lenmax;
267 *maxsize = sizemax;
269 regval_ctr_destroy( &values );
271 return True;
275 /********************************************************************
276 reg_close
277 ********************************************************************/
279 WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
281 /* set up the REG unknown_1 response */
282 ZERO_STRUCT(r_u->pol);
284 /* close the policy handle */
285 if (!close_registry_key(p, &q_u->pol))
286 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
288 return WERR_OK;
291 /*******************************************************************
292 ********************************************************************/
294 WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
296 return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, 0x0 );
299 /*******************************************************************
300 ********************************************************************/
302 WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
304 return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, 0x0 );
307 /*******************************************************************
308 ********************************************************************/
310 WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
312 return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, 0x0 );
315 /*******************************************************************
316 reg_reply_open_entry
317 ********************************************************************/
319 WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
321 POLICY_HND pol;
322 fstring name;
323 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->pol);
324 WERROR result;
326 DEBUG(5,("reg_open_entry: Enter\n"));
328 if ( !key )
329 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
331 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
333 result = open_registry_key( p, &pol, key, name, 0x0 );
335 init_reg_r_open_entry( r_u, &pol, result );
337 DEBUG(5,("reg_open_entry: Exit\n"));
339 return r_u->status;
342 /*******************************************************************
343 reg_reply_info
344 ********************************************************************/
346 WERROR _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u)
348 WERROR status = WERR_BADFILE;
349 fstring name;
350 const char *value_ascii = "";
351 fstring value;
352 int value_length;
353 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
354 REGISTRY_VALUE *val = NULL;
355 REGVAL_CTR regvals;
356 int i;
358 DEBUG(5,("_reg_info: Enter\n"));
360 if ( !regkey )
361 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
363 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
365 rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
367 DEBUG(5,("reg_info: looking up value: [%s]\n", name));
369 ZERO_STRUCTP( &regvals );
371 regval_ctr_init( &regvals );
373 /* couple of hard coded registry values */
375 if ( strequal(name, "RefusePasswordChange") ) {
376 uint32 dwValue;
378 if ( (val = SMB_MALLOC_P(REGISTRY_VALUE)) == NULL ) {
379 DEBUG(0,("_reg_info: malloc() failed!\n"));
380 return WERR_NOMEM;
383 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue))
384 dwValue = 0;
385 regval_ctr_addvalue(&regvals, "RefusePasswordChange",
386 REG_DWORD,
387 (const char*)&dwValue, sizeof(dwValue));
388 val = dup_registry_value(
389 regval_ctr_specific_value( &regvals, 0 ) );
391 status = WERR_OK;
393 goto out;
396 if ( strequal(name, REGSTR_PRODUCTTYPE) ) {
397 /* This makes the server look like a member server to clients */
398 /* which tells clients that we have our own local user and */
399 /* group databases and helps with ACL support. */
401 switch (lp_server_role()) {
402 case ROLE_DOMAIN_PDC:
403 case ROLE_DOMAIN_BDC:
404 value_ascii = REG_PT_LANMANNT;
405 break;
406 case ROLE_STANDALONE:
407 value_ascii = REG_PT_SERVERNT;
408 break;
409 case ROLE_DOMAIN_MEMBER:
410 value_ascii = REG_PT_WINNT;
411 break;
413 value_length = push_ucs2(value, value, value_ascii,
414 sizeof(value),
415 STR_TERMINATE|STR_NOALIGN);
416 regval_ctr_addvalue(&regvals, REGSTR_PRODUCTTYPE, REG_SZ,
417 value, value_length);
419 val = dup_registry_value( regval_ctr_specific_value( &regvals, 0 ) );
421 status = WERR_OK;
423 goto out;
426 /* else fall back to actually looking up the value */
428 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
430 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
431 if ( StrCaseCmp( val->valuename, name ) == 0 ) {
432 DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
433 status = WERR_OK;
434 break;
437 free_registry_value( val );
441 out:
442 init_reg_r_info(q_u->ptr_buf, r_u, val, status);
444 regval_ctr_destroy( &regvals );
445 free_registry_value( val );
447 DEBUG(5,("_reg_info: Exit\n"));
449 return status;
453 /*****************************************************************************
454 Implementation of REG_QUERY_KEY
455 ****************************************************************************/
457 WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
459 WERROR status = WERR_OK;
460 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
462 DEBUG(5,("_reg_query_key: Enter\n"));
464 if ( !regkey )
465 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
467 if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) )
468 return WERR_ACCESS_DENIED;
470 if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) )
471 return WERR_ACCESS_DENIED;
474 r_u->sec_desc = 0x00000078; /* size for key's sec_desc */
476 /* Win9x set this to 0x0 since it does not keep timestamps.
477 Doing the same here for simplicity --jerry */
479 ZERO_STRUCT(r_u->mod_time);
481 DEBUG(5,("_reg_query_key: Exit\n"));
483 return status;
487 /*****************************************************************************
488 Implementation of REG_GETVERSION
489 ****************************************************************************/
491 WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u)
493 WERROR status = WERR_OK;
494 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
496 DEBUG(5,("_reg_getversion: Enter\n"));
498 if ( !regkey )
499 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
501 r_u->unknown = 0x00000005; /* seems to be consistent...no idea what it means */
503 DEBUG(5,("_reg_getversion: Exit\n"));
505 return status;
509 /*****************************************************************************
510 Implementation of REG_ENUM_KEY
511 ****************************************************************************/
513 WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
515 WERROR status = WERR_OK;
516 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
517 char *subkey = NULL;
520 DEBUG(5,("_reg_enum_key: Enter\n"));
522 if ( !regkey )
523 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
525 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
527 if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) )
529 status = WERR_NO_MORE_ITEMS;
530 goto done;
533 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
535 /* subkey has the string name now */
537 init_reg_r_enum_key( r_u, subkey, q_u->unknown_1, q_u->unknown_2 );
539 DEBUG(5,("_reg_enum_key: Exit\n"));
541 done:
542 SAFE_FREE( subkey );
543 return status;
546 /*****************************************************************************
547 Implementation of REG_ENUM_VALUE
548 ****************************************************************************/
550 WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u)
552 WERROR status = WERR_OK;
553 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
554 REGISTRY_VALUE *val;
557 DEBUG(5,("_reg_enum_value: Enter\n"));
559 if ( !regkey )
560 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
562 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey->name));
564 if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) {
565 status = WERR_NO_MORE_ITEMS;
566 goto done;
569 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val->valuename));
571 /* subkey has the string name now */
573 init_reg_r_enum_val( r_u, val );
576 DEBUG(5,("_reg_enum_value: Exit\n"));
578 done:
579 free_registry_value( val );
581 return status;
585 /*******************************************************************
586 reg_shutdwon
587 ********************************************************************/
589 WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
591 REG_Q_SHUTDOWN_EX q_u_ex;
592 REG_R_SHUTDOWN_EX r_u_ex;
594 /* copy fields (including stealing memory) */
596 q_u_ex.server = q_u->server;
597 q_u_ex.message = q_u->message;
598 q_u_ex.timeout = q_u->timeout;
599 q_u_ex.force = q_u->force;
600 q_u_ex.reboot = q_u->reboot;
601 q_u_ex.reason = 0x0; /* don't care for now */
603 /* thunk down to _reg_shutdown_ex() (just returns a status) */
605 return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex );
608 /*******************************************************************
609 reg_shutdown_ex
610 ********************************************************************/
612 #define SHUTDOWN_R_STRING "-r"
613 #define SHUTDOWN_F_STRING "-f"
616 WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u)
618 pstring shutdown_script;
619 pstring message;
620 pstring chkmsg;
621 fstring timeout;
622 fstring reason;
623 fstring r;
624 fstring f;
625 int ret;
626 BOOL can_shutdown;
628 pstrcpy(shutdown_script, lp_shutdown_script());
630 if ( !*shutdown_script )
631 return WERR_ACCESS_DENIED;
633 /* pull the message string and perform necessary sanity checks on it */
635 pstrcpy( message, "" );
636 if ( q_u->message ) {
637 UNISTR2 *msg_string = q_u->message->string;
639 rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 );
641 alpha_strcpy (chkmsg, message, NULL, sizeof(message));
643 fstr_sprintf(timeout, "%d", q_u->timeout);
644 fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : "");
645 fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : "");
646 fstr_sprintf( reason, "%d", q_u->reason );
648 all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
649 all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) );
650 all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
651 all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
652 all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) );
654 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
656 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
657 Take the error return from the script and provide it as the Windows return code. */
659 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
661 if ( can_shutdown )
662 become_root();
664 ret = smbrun( shutdown_script, NULL );
666 if ( can_shutdown )
667 unbecome_root();
669 /********** END SeRemoteShutdownPrivilege BLOCK **********/
671 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
672 shutdown_script, ret));
675 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
681 /*******************************************************************
682 reg_abort_shutdwon
683 ********************************************************************/
685 WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
687 pstring abort_shutdown_script;
688 int ret;
689 BOOL can_shutdown;
691 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
693 if ( !*abort_shutdown_script )
694 return WERR_ACCESS_DENIED;
696 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
698 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
700 if ( can_shutdown )
701 become_root();
703 ret = smbrun( abort_shutdown_script, NULL );
705 if ( can_shutdown )
706 unbecome_root();
708 /********** END SeRemoteShutdownPrivilege BLOCK **********/
710 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
711 abort_shutdown_script, ret));
714 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
717 /*******************************************************************
718 ********************************************************************/
720 WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY *q_u, REG_R_RESTORE_KEY *r_u)
722 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
723 pstring filename;
725 DEBUG(5,("_reg_restore_key: Enter\n"));
728 * basically this is a no op function which just verifies
729 * that the client gave us a valid registry key handle
732 if ( !regkey )
733 return WERR_BADFID;
735 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
737 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
739 #if 0
740 validate_reg_filemame( filename );
741 return restore_registry_key( regkey, filename );
742 #endif
744 return WERR_OK;
747 /*******************************************************************
748 ********************************************************************/
750 WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u)
752 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
753 pstring filename;
755 DEBUG(5,("_reg_save_key: Enter\n"));
758 * basically this is a no op function which just verifies
759 * that the client gave us a valid registry key handle
762 if ( !regkey )
763 return WERR_BADFID;
765 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
767 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
769 #if 0
770 validate_reg_filemame( filename );
771 return backup_registry_key( regkey, filename );
772 #endif
774 return WERR_OK;