r7938: * move the hardcoded registry value names from _reg_query_value()
[Samba/gbeck.git] / source / rpc_server / srv_reg_nt.c
blob4603bb077bd310213f26cf5b58e0f451770074d7
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"
28 #include "regfio.h"
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
33 #define REGSTR_PRODUCTTYPE "ProductType"
34 #define REG_PT_WINNT "WinNT"
35 #define REG_PT_LANMANNT "LanmanNT"
36 #define REG_PT_SERVERNT "ServerNT"
38 #define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
39 ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
42 /* no idea if this is correct, just use the file access bits for now */
44 struct generic_mapping reg_map = { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
46 /********************************************************************
47 ********************************************************************/
49 NTSTATUS registry_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
50 uint32 access_desired, uint32 *access_granted )
52 NTSTATUS result;
54 se_access_check( sec_desc, token, access_desired, access_granted, &result );
56 return result;
59 /********************************************************************
60 ********************************************************************/
62 SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
64 SEC_ACE ace[2];
65 SEC_ACCESS mask;
66 size_t i = 0;
67 SEC_DESC *sd;
68 SEC_ACL *acl;
69 uint32 sd_size;
71 /* basic access for Everyone */
73 init_sec_access(&mask, REG_KEY_READ );
74 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
76 /* Full Access 'BUILTIN\Administrators' */
78 init_sec_access(&mask, REG_KEY_ALL );
79 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
82 /* create the security descriptor */
84 if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
85 return NULL;
87 if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
88 return NULL;
90 return sd;
93 /******************************************************************
94 free() function for REGISTRY_KEY
95 *****************************************************************/
97 static void free_regkey_info(void *ptr)
99 REGISTRY_KEY *info = (REGISTRY_KEY*)ptr;
101 SAFE_FREE(info);
104 /******************************************************************
105 Find a registry key handle and return a REGISTRY_KEY
106 *****************************************************************/
108 static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
110 REGISTRY_KEY *regkey = NULL;
112 if(!find_policy_by_hnd(p,hnd,(void **)&regkey)) {
113 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
114 return NULL;
117 return regkey;
121 /*******************************************************************
122 Function for open a new registry handle and creating a handle
123 Note that P should be valid & hnd should already have space
125 When we open a key, we store the full path to the key as
126 HK[LM|U]\<key>\<key>\...
127 *******************************************************************/
129 static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY *parent,
130 const char *subkeyname, uint32 access_granted )
132 REGISTRY_KEY *regkey = NULL;
133 WERROR result = WERR_OK;
134 REGSUBKEY_CTR subkeys;
135 pstring subkeyname2;
136 int subkey_len;
138 DEBUG(7,("open_registry_key: name = [%s][%s]\n",
139 parent ? parent->name : "NULL", subkeyname));
141 /* strip any trailing '\'s */
142 pstrcpy( subkeyname2, subkeyname );
143 subkey_len = strlen ( subkeyname2 );
144 if ( subkey_len && subkeyname2[subkey_len-1] == '\\' )
145 subkeyname2[subkey_len-1] = '\0';
147 if ((regkey=SMB_MALLOC_P(REGISTRY_KEY)) == NULL)
148 return WERR_NOMEM;
150 ZERO_STRUCTP( regkey );
153 * very crazy, but regedit.exe on Win2k will attempt to call
154 * REG_OPEN_ENTRY with a keyname of "". We should return a new
155 * (second) handle here on the key->name. regedt32.exe does
156 * not do this stupidity. --jerry
159 if ( !subkey_len ) {
160 pstrcpy( regkey->name, parent->name );
162 else {
163 pstrcpy( regkey->name, "" );
164 if ( parent ) {
165 pstrcat( regkey->name, parent->name );
166 pstrcat( regkey->name, "\\" );
168 pstrcat( regkey->name, subkeyname2 );
171 /* Look up the table of registry I/O operations */
173 if ( !(regkey->hook = reghook_cache_find( regkey->name )) ) {
174 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
175 regkey->name ));
176 return WERR_BADFILE;
179 /* check if the path really exists; failed is indicated by -1 */
180 /* if the subkey count failed, bail out */
182 regsubkey_ctr_init( &subkeys );
184 if ( fetch_reg_keys( regkey, &subkeys ) == -1 ) {
185 result = WERR_BADFILE;
186 goto done;
189 if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) {
190 result = WERR_BADFILE;
191 goto done;
194 /* save the access mask */
196 regkey->access_granted = access_granted;
198 done:
199 /* clean up */
201 regsubkey_ctr_destroy( &subkeys );
203 if ( ! NT_STATUS_IS_OK(result) )
204 SAFE_FREE( regkey );
206 DEBUG(7,("open_registry_key: exit\n"));
208 return result;
211 /*******************************************************************
212 Function for open a new registry handle and creating a handle
213 Note that P should be valid & hnd should already have space
214 *******************************************************************/
216 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
218 REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd);
220 if ( !regkey ) {
221 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
222 return False;
225 close_policy_hnd(p, hnd);
227 return True;
230 /********************************************************************
231 retrieve information about the subkeys
232 *******************************************************************/
234 static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen )
236 int num_subkeys, i;
237 uint32 max_len;
238 REGSUBKEY_CTR subkeys;
239 uint32 len;
241 if ( !key )
242 return False;
244 regsubkey_ctr_init( &subkeys );
246 if ( fetch_reg_keys( key, &subkeys ) == -1 )
247 return False;
249 /* find the longest string */
251 max_len = 0;
252 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
254 for ( i=0; i<num_subkeys; i++ ) {
255 len = strlen( regsubkey_ctr_specific_key(&subkeys, i) );
256 max_len = MAX(max_len, len);
259 *maxnum = num_subkeys;
260 *maxlen = max_len*2;
262 regsubkey_ctr_destroy( &subkeys );
264 return True;
267 /********************************************************************
268 retrieve information about the values. We don't store values
269 here. The registry tdb is intended to be a frontend to oether
270 Samba tdb's (such as ntdrivers.tdb).
271 *******************************************************************/
273 static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum,
274 uint32 *maxlen, uint32 *maxsize )
276 REGVAL_CTR values;
277 REGISTRY_VALUE *val;
278 uint32 sizemax, lenmax;
279 int i, num_values;
281 if ( !key )
282 return False;
284 regval_ctr_init( &values );
286 if ( fetch_reg_values( key, &values ) == -1 )
287 return False;
289 lenmax = sizemax = 0;
290 num_values = regval_ctr_numvals( &values );
292 val = regval_ctr_specific_value( &values, 0 );
294 for ( i=0; i<num_values && val; i++ )
296 lenmax = MAX(lenmax, strlen(val->valuename)+1 );
297 sizemax = MAX(sizemax, val->size );
299 val = regval_ctr_specific_value( &values, i );
302 *maxnum = num_values;
303 *maxlen = lenmax;
304 *maxsize = sizemax;
306 regval_ctr_destroy( &values );
308 return True;
312 /********************************************************************
313 reg_close
314 ********************************************************************/
316 WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
318 /* close the policy handle */
320 if (!close_registry_key(p, &q_u->pol))
321 return WERR_BADFID;
323 return WERR_OK;
326 /*******************************************************************
327 ********************************************************************/
329 WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
331 SEC_DESC *sec_desc;
332 uint32 access_granted = 0;
333 NTSTATUS status;
335 /* perform access checks */
336 /* top level keys are done here without passing through the REGISTRY_HOOK api */
338 if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
339 return WERR_NOMEM;
341 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
342 if ( !NT_STATUS_IS_OK(status) )
343 return ntstatus_to_werror( status );
345 return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, access_granted );
348 /*******************************************************************
349 ********************************************************************/
351 WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
353 SEC_DESC *sec_desc;
354 uint32 access_granted = 0;
355 NTSTATUS status;
357 /* perform access checks */
358 /* top level keys are done here without passing through the REGISTRY_HOOK api */
360 if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
361 return WERR_NOMEM;
363 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
364 if ( !NT_STATUS_IS_OK(status) )
365 return ntstatus_to_werror( status );
367 return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, access_granted );
370 /*******************************************************************
371 ********************************************************************/
373 WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
375 SEC_DESC *sec_desc;
376 uint32 access_granted = 0;
377 NTSTATUS status;
379 /* perform access checks */
380 /* top level keys are done here without passing through the REGISTRY_HOOK api */
382 if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
383 return WERR_NOMEM;
385 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
386 if ( !NT_STATUS_IS_OK(status) )
387 return ntstatus_to_werror( status );
389 return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, access_granted );
392 /*******************************************************************
393 reg_reply_open_entry
394 ********************************************************************/
396 WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
398 fstring name;
399 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->pol);
400 REGISTRY_KEY *newkey;
401 uint32 access_granted;
402 WERROR result;
404 DEBUG(5,("reg_open_entry: Enter\n"));
406 if ( !parent )
407 return WERR_BADFID;
409 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
411 /* check granted access first; what is the correct mask here? */
413 if ( !(parent->access_granted & (SEC_RIGHTS_ENUM_SUBKEYS|SEC_RIGHTS_CREATE_SUBKEY)) )
414 return WERR_ACCESS_DENIED;
416 /* open the key first to get the appropriate REGISTRY_HOOK
417 and then check the premissions */
419 if ( !W_ERROR_IS_OK(result = open_registry_key( p, &r_u->handle, parent, name, 0 )) )
420 return result;
422 newkey = find_regkey_index_by_hnd(p, &r_u->handle);
424 /* finally allow the backend to check the access for the requested key */
426 if ( !regkey_access_check( newkey, q_u->access, &access_granted, p->pipe_user.nt_user_token ) ) {
427 close_registry_key( p, &r_u->handle );
428 return WERR_ACCESS_DENIED;
431 /* if successful, save the granted access mask */
433 newkey->access_granted = access_granted;
435 return WERR_OK;
438 /*******************************************************************
439 reg_reply_info
440 ********************************************************************/
442 WERROR _reg_query_value(pipes_struct *p, REG_Q_QUERY_VALUE *q_u, REG_R_QUERY_VALUE *r_u)
444 WERROR status = WERR_BADFILE;
445 fstring name;
446 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
447 REGISTRY_VALUE *val = NULL;
448 REGVAL_CTR regvals;
449 int i;
451 DEBUG(5,("_reg_info: Enter\n"));
453 if ( !regkey )
454 return WERR_BADFID;
456 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
458 rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
460 DEBUG(5,("reg_info: looking up value: [%s]\n", name));
462 regval_ctr_init( &regvals );
464 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
466 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
467 if ( strequal( val->valuename, name ) ) {
468 DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
469 status = WERR_OK;
470 break;
473 free_registry_value( val );
476 init_reg_r_query_value(q_u->ptr_buf, r_u, val, status);
478 regval_ctr_destroy( &regvals );
479 free_registry_value( val );
481 DEBUG(5,("_reg_info: Exit\n"));
483 return status;
487 /*****************************************************************************
488 Implementation of REG_QUERY_KEY
489 ****************************************************************************/
491 WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
493 WERROR status = WERR_OK;
494 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
496 DEBUG(5,("_reg_query_key: Enter\n"));
498 if ( !regkey )
499 return WERR_BADFID;
501 if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) )
502 return WERR_ACCESS_DENIED;
504 if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) )
505 return WERR_ACCESS_DENIED;
508 r_u->sec_desc = 0x00000078; /* size for key's sec_desc */
510 /* Win9x set this to 0x0 since it does not keep timestamps.
511 Doing the same here for simplicity --jerry */
513 ZERO_STRUCT(r_u->mod_time);
515 DEBUG(5,("_reg_query_key: Exit\n"));
517 return status;
521 /*****************************************************************************
522 Implementation of REG_GETVERSION
523 ****************************************************************************/
525 WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u)
527 WERROR status = WERR_OK;
528 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
530 DEBUG(5,("_reg_getversion: Enter\n"));
532 if ( !regkey )
533 return WERR_BADFID;
535 r_u->win_version = 0x00000005; /* Windows 2000 registry API version */
537 DEBUG(5,("_reg_getversion: Exit\n"));
539 return status;
543 /*****************************************************************************
544 Implementation of REG_ENUM_KEY
545 ****************************************************************************/
547 WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
549 WERROR status = WERR_OK;
550 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
551 char *subkey = NULL;
554 DEBUG(5,("_reg_enum_key: Enter\n"));
556 if ( !regkey )
557 return WERR_BADFID;
559 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
561 if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) )
563 status = WERR_NO_MORE_ITEMS;
564 goto done;
567 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
569 /* subkey has the string name now */
571 init_reg_r_enum_key( r_u, subkey );
573 DEBUG(5,("_reg_enum_key: Exit\n"));
575 done:
576 SAFE_FREE( subkey );
577 return status;
580 /*****************************************************************************
581 Implementation of REG_ENUM_VALUE
582 ****************************************************************************/
584 WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u)
586 WERROR status = WERR_OK;
587 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
588 REGISTRY_VALUE *val;
591 DEBUG(5,("_reg_enum_value: Enter\n"));
593 if ( !regkey )
594 return WERR_BADFID;
596 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey->name));
598 if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) {
599 status = WERR_NO_MORE_ITEMS;
600 goto done;
603 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val->valuename));
605 /* subkey has the string name now */
607 init_reg_r_enum_val( r_u, val );
610 DEBUG(5,("_reg_enum_value: Exit\n"));
612 done:
613 free_registry_value( val );
615 return status;
619 /*******************************************************************
620 reg_shutdwon
621 ********************************************************************/
623 WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
625 REG_Q_SHUTDOWN_EX q_u_ex;
626 REG_R_SHUTDOWN_EX r_u_ex;
628 /* copy fields (including stealing memory) */
630 q_u_ex.server = q_u->server;
631 q_u_ex.message = q_u->message;
632 q_u_ex.timeout = q_u->timeout;
633 q_u_ex.force = q_u->force;
634 q_u_ex.reboot = q_u->reboot;
635 q_u_ex.reason = 0x0; /* don't care for now */
637 /* thunk down to _reg_shutdown_ex() (just returns a status) */
639 return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex );
642 /*******************************************************************
643 reg_shutdown_ex
644 ********************************************************************/
646 #define SHUTDOWN_R_STRING "-r"
647 #define SHUTDOWN_F_STRING "-f"
650 WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u)
652 pstring shutdown_script;
653 pstring message;
654 pstring chkmsg;
655 fstring timeout;
656 fstring reason;
657 fstring r;
658 fstring f;
659 int ret;
660 BOOL can_shutdown;
663 pstrcpy(shutdown_script, lp_shutdown_script());
665 if ( !*shutdown_script )
666 return WERR_ACCESS_DENIED;
668 /* pull the message string and perform necessary sanity checks on it */
670 pstrcpy( message, "" );
671 if ( q_u->message ) {
672 UNISTR2 *msg_string = q_u->message->string;
674 rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 );
676 alpha_strcpy (chkmsg, message, NULL, sizeof(message));
678 fstr_sprintf(timeout, "%d", q_u->timeout);
679 fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : "");
680 fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : "");
681 fstr_sprintf( reason, "%d", q_u->reason );
683 all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
684 all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) );
685 all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
686 all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
687 all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) );
689 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
691 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
692 Take the error return from the script and provide it as the Windows return code. */
694 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
696 if ( can_shutdown )
697 become_root();
699 ret = smbrun( shutdown_script, NULL );
701 if ( can_shutdown )
702 unbecome_root();
704 /********** END SeRemoteShutdownPrivilege BLOCK **********/
706 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
707 shutdown_script, ret));
710 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
716 /*******************************************************************
717 reg_abort_shutdwon
718 ********************************************************************/
720 WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
722 pstring abort_shutdown_script;
723 int ret;
724 BOOL can_shutdown;
726 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
728 if ( !*abort_shutdown_script )
729 return WERR_ACCESS_DENIED;
731 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
733 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
735 if ( can_shutdown )
736 become_root();
738 ret = smbrun( abort_shutdown_script, NULL );
740 if ( can_shutdown )
741 unbecome_root();
743 /********** END SeRemoteShutdownPrivilege BLOCK **********/
745 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
746 abort_shutdown_script, ret));
749 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
752 /*******************************************************************
753 ********************************************************************/
755 static int validate_reg_filename( pstring fname )
757 char *p;
758 int num_services = lp_numservices();
759 int snum;
760 pstring share_path;
761 pstring unix_fname;
763 /* convert to a unix path, stripping the C:\ along the way */
765 if ( !(p = valid_share_pathname( fname ) ))
766 return -1;
768 /* has to exist within a valid file share */
770 for ( snum=0; snum<num_services; snum++ ) {
772 if ( !lp_snum_ok(snum) || lp_print_ok(snum) )
773 continue;
775 pstrcpy( share_path, lp_pathname(snum) );
777 /* make sure we have a path (e.g. [homes] ) */
779 if ( strlen( share_path ) == 0 )
780 continue;
782 if ( strncmp( share_path, p, strlen( share_path )) == 0 )
783 break;
786 /* p and fname are overlapping memory so copy out and back in again */
788 pstrcpy( unix_fname, p );
789 pstrcpy( fname, unix_fname );
791 return (snum < num_services) ? snum : -1;
794 /*******************************************************************
795 Note: topkeypat is the *full* path that this *key will be
796 loaded into (including the name of the key)
797 ********************************************************************/
799 static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath,
800 REGF_NK_REC *key )
802 REGF_NK_REC *subkey;
803 REGISTRY_KEY registry_key;
804 REGVAL_CTR values;
805 REGSUBKEY_CTR subkeys;
806 int i;
807 pstring path;
808 WERROR result = WERR_OK;
810 /* initialize the REGISTRY_KEY structure */
812 if ( !(registry_key.hook = reghook_cache_find(topkeypath)) ) {
813 DEBUG(0,("reg_load_tree: Failed to assigned a REGISTRY_HOOK to [%s]\n",
814 topkeypath ));
815 return WERR_BADFILE;
817 pstrcpy( registry_key.name, topkeypath );
819 /* now start parsing the values and subkeys */
821 regsubkey_ctr_init( &subkeys );
822 regval_ctr_init( &values );
824 /* copy values into the REGVAL_CTR */
826 for ( i=0; i<key->num_values; i++ ) {
827 regval_ctr_addvalue( &values, key->values[i].valuename, key->values[i].type,
828 key->values[i].data, (key->values[i].data_size & ~VK_DATA_IN_OFFSET) );
831 /* copy subkeys into the REGSUBKEY_CTR */
833 key->subkey_index = 0;
834 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
835 regsubkey_ctr_addkey( &subkeys, subkey->keyname );
838 /* write this key and values out */
840 if ( !store_reg_values( &registry_key, &values )
841 || !store_reg_keys( &registry_key, &subkeys ) )
843 DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
844 result = WERR_REG_IO_FAILURE;
847 regval_ctr_destroy( &values );
848 regsubkey_ctr_destroy( &subkeys );
850 if ( !W_ERROR_IS_OK(result) )
851 return result;
853 /* now continue to load each subkey registry tree */
855 key->subkey_index = 0;
856 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
857 pstr_sprintf( path, "%s%s%s", topkeypath, "\\", subkey->keyname );
858 result = reg_load_tree( regfile, path, subkey );
859 if ( !W_ERROR_IS_OK(result) )
860 break;
863 return result;
866 /*******************************************************************
867 ********************************************************************/
869 static WERROR restore_registry_key ( REGISTRY_KEY *krecord, const char *fname )
871 REGF_FILE *regfile;
872 REGF_NK_REC *rootkey;
873 WERROR result;
875 /* open the registry file....fail if the file already exists */
877 if ( !(regfile = regfio_open( fname, (O_RDONLY), 0 )) ) {
878 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
879 fname, strerror(errno) ));
880 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
883 /* get the rootkey from the regf file and then load the tree
884 via recursive calls */
886 if ( !(rootkey = regfio_rootkey( regfile )) )
887 return WERR_REG_FILE_INVALID;
889 result = reg_load_tree( regfile, krecord->name, rootkey );
891 /* cleanup */
893 regfio_close( regfile );
895 return result;
898 /*******************************************************************
899 ********************************************************************/
901 WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY *q_u, REG_R_RESTORE_KEY *r_u)
903 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
904 pstring filename;
905 int snum;
907 DEBUG(5,("_reg_restore_key: Enter\n"));
909 if ( !regkey )
910 return WERR_BADFID;
912 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
914 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
916 if ( (snum = validate_reg_filename( filename )) == -1 )
917 return WERR_OBJECT_PATH_INVALID;
919 /* user must posses SeRestorePrivilege for this this proceed */
921 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
922 return WERR_ACCESS_DENIED;
924 DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
926 return restore_registry_key( regkey, filename );
929 /********************************************************************
930 ********************************************************************/
932 static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath,
933 REGF_NK_REC *parent, SEC_DESC *sec_desc )
935 REGF_NK_REC *key;
936 REGVAL_CTR values;
937 REGSUBKEY_CTR subkeys;
938 int i, num_subkeys;
939 pstring key_tmp;
940 char *keyname, *parentpath;
941 pstring subkeypath;
942 char *subkeyname;
943 REGISTRY_KEY registry_key;
944 WERROR result = WERR_OK;
946 if ( !regfile )
947 return WERR_GENERAL_FAILURE;
949 if ( !keypath )
950 return WERR_OBJECT_PATH_INVALID;
952 /* split up the registry key path */
954 pstrcpy( key_tmp, keypath );
955 if ( !reg_split_key( key_tmp, &parentpath, &keyname ) )
956 return WERR_OBJECT_PATH_INVALID;
958 if ( !keyname )
959 keyname = parentpath;
961 /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
963 ZERO_STRUCT( registry_key );
964 pstrcpy( registry_key.name, keypath );
965 if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) )
966 return WERR_BADFILE;
969 /* lookup the values and subkeys */
971 regsubkey_ctr_init( &subkeys );
972 regval_ctr_init( &values );
974 fetch_reg_keys( &registry_key, &subkeys );
975 fetch_reg_values( &registry_key, &values );
977 /* write out this key */
979 if ( !(key = regfio_write_key( regfile, keyname, &values, &subkeys, sec_desc, parent )) ) {
980 result = WERR_CAN_NOT_COMPLETE;
981 goto done;
984 /* write each one of the subkeys out */
986 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
987 for ( i=0; i<num_subkeys; i++ ) {
988 subkeyname = regsubkey_ctr_specific_key( &subkeys, i );
989 pstr_sprintf( subkeypath, "%s\\%s", keypath, subkeyname );
990 result = reg_write_tree( regfile, subkeypath, key, sec_desc );
991 if ( !W_ERROR_IS_OK(result) )
992 goto done;
995 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath ));
997 done:
998 regval_ctr_destroy( &values );
999 regsubkey_ctr_destroy( &subkeys );
1001 return result;
1004 /*******************************************************************
1005 ********************************************************************/
1007 static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
1009 DOM_SID adm_sid, owner_sid;
1010 SEC_ACE ace[2]; /* at most 2 entries */
1011 SEC_ACCESS mask;
1012 SEC_ACL *psa = NULL;
1013 uint32 sd_size;
1015 /* set the owner to BUILTIN\Administrator */
1017 sid_copy(&owner_sid, &global_sid_Builtin);
1018 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
1021 /* basic access for Everyone */
1023 init_sec_access(&mask, reg_map.generic_execute | reg_map.generic_read );
1024 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1026 /* add Full Access 'BUILTIN\Administrators' */
1028 init_sec_access(&mask, reg_map.generic_all);
1029 sid_copy(&adm_sid, &global_sid_Builtin);
1030 sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
1031 init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1033 /* create the security descriptor */
1035 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace)) == NULL)
1036 return WERR_NOMEM;
1038 if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &owner_sid, NULL, NULL, psa, &sd_size)) == NULL)
1039 return WERR_NOMEM;
1041 return WERR_OK;
1044 /*******************************************************************
1045 ********************************************************************/
1047 static WERROR backup_registry_key ( REGISTRY_KEY *krecord, const char *fname )
1049 REGF_FILE *regfile;
1050 WERROR result;
1051 SEC_DESC *sd = NULL;
1053 /* open the registry file....fail if the file already exists */
1055 if ( !(regfile = regfio_open( fname, (O_RDWR|O_CREAT|O_EXCL), (S_IREAD|S_IWRITE) )) ) {
1056 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
1057 fname, strerror(errno) ));
1058 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
1061 if ( !W_ERROR_IS_OK(result = make_default_reg_sd( regfile->mem_ctx, &sd )) ) {
1062 regfio_close( regfile );
1063 return result;
1066 /* write the registry tree to the file */
1068 result = reg_write_tree( regfile, krecord->name, NULL, sd );
1070 /* cleanup */
1072 regfio_close( regfile );
1074 return result;
1077 /*******************************************************************
1078 ********************************************************************/
1080 WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u)
1082 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
1083 pstring filename;
1084 int snum;
1086 DEBUG(5,("_reg_save_key: Enter\n"));
1088 if ( !regkey )
1089 return WERR_BADFID;
1091 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
1093 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
1095 if ( (snum = validate_reg_filename( filename )) == -1 )
1096 return WERR_OBJECT_PATH_INVALID;
1098 DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
1100 return backup_registry_key( regkey, filename );
1102 return WERR_OK;
1105 /*******************************************************************
1106 ********************************************************************/
1108 WERROR _reg_create_key(pipes_struct *p, REG_Q_CREATE_KEY *q_u, REG_R_CREATE_KEY *r_u)
1110 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1111 REGISTRY_KEY *newparent;
1112 POLICY_HND newparent_handle;
1113 REGSUBKEY_CTR subkeys;
1114 BOOL write_result;
1115 pstring name;
1116 WERROR result;
1118 if ( !parent )
1119 return WERR_BADFID;
1121 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1123 /* ok. Here's what we do. */
1125 if ( strrchr( name, '\\' ) ) {
1126 pstring newkeyname;
1127 char *ptr;
1128 uint32 access_granted;
1130 /* (1) check for enumerate rights on the parent handle. CLients can try
1131 create things like 'SOFTWARE\Samba' on the HKLM handle.
1132 (2) open the path to the child parent key if necessary */
1134 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1135 return WERR_ACCESS_DENIED;
1137 pstrcpy( newkeyname, name );
1138 ptr = strrchr( newkeyname, '\\' );
1139 *ptr = '\0';
1141 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1142 if ( !W_ERROR_IS_OK(result) )
1143 return result;
1145 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1146 SMB_ASSERT( newparent != NULL );
1148 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1149 result = WERR_ACCESS_DENIED;
1150 goto done;
1153 newparent->access_granted = access_granted;
1155 /* copy the new key name (just the lower most keyname) */
1157 pstrcpy( name, ptr+1 );
1159 else {
1160 /* use the existing open key information */
1161 newparent = parent;
1162 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1165 /* (3) check for create subkey rights on the correct parent */
1167 if ( !(newparent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
1168 result = WERR_ACCESS_DENIED;
1169 goto done;
1172 regsubkey_ctr_init( &subkeys );
1174 /* (4) lookup the current keys and add the new one */
1176 fetch_reg_keys( newparent, &subkeys );
1177 regsubkey_ctr_addkey( &subkeys, name );
1179 /* now write to the registry backend */
1181 write_result = store_reg_keys( newparent, &subkeys );
1183 regsubkey_ctr_destroy( &subkeys );
1185 if ( !write_result )
1186 return WERR_REG_IO_FAILURE;
1188 /* (5) open the new key and return the handle. Note that it is probably
1189 not correct to grant full access on this open handle. We should pass
1190 the new open through the regkey_access_check() like we do for
1191 _reg_open_entry() but this is ok for now. */
1193 result = open_registry_key( p, &r_u->handle, newparent, name, REG_KEY_ALL );
1195 done:
1196 /* close any intermediate key handles */
1198 if ( newparent != parent )
1199 close_registry_key( p, &newparent_handle );
1201 return result;
1205 /*******************************************************************
1206 ********************************************************************/
1208 WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r_u)
1210 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1211 REGVAL_CTR values;
1212 BOOL write_result;
1213 fstring valuename;
1215 if ( !key )
1216 return WERR_BADFID;
1218 /* access checks first */
1220 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1221 return WERR_ACCESS_DENIED;
1223 rpcstr_pull( valuename, q_u->name.string->buffer, sizeof(valuename), q_u->name.string->uni_str_len*2, 0 );
1226 regval_ctr_init( &values );
1228 /* lookup the current values and add the new one */
1230 fetch_reg_values( key, &values );
1232 regval_ctr_addvalue( &values, valuename, q_u->type, q_u->value.buffer, q_u->value.buf_len );
1234 /* now write to the registry backend */
1236 write_result = store_reg_values( key, &values );
1238 regval_ctr_destroy( &values );
1240 if ( !write_result )
1241 return WERR_REG_IO_FAILURE;
1243 return WERR_OK;
1246 /*******************************************************************
1247 ********************************************************************/
1249 WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY *r_u)
1251 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1252 REGISTRY_KEY *newparent;
1253 POLICY_HND newparent_handle;
1254 REGSUBKEY_CTR subkeys;
1255 BOOL write_result;
1256 pstring name;
1257 WERROR result;
1259 if ( !parent )
1260 return WERR_BADFID;
1262 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1264 /* ok. Here's what we do. */
1266 if ( strrchr( name, '\\' ) ) {
1267 pstring newkeyname;
1268 char *ptr;
1269 uint32 access_granted;
1271 /* (1) check for enumerate rights on the parent handle. CLients can try
1272 create things like 'SOFTWARE\Samba' on the HKLM handle.
1273 (2) open the path to the child parent key if necessary */
1275 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1276 return WERR_ACCESS_DENIED;
1278 pstrcpy( newkeyname, name );
1279 ptr = strrchr( newkeyname, '\\' );
1280 *ptr = '\0';
1282 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1283 if ( !W_ERROR_IS_OK(result) )
1284 return result;
1286 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1287 SMB_ASSERT( newparent != NULL );
1289 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1290 result = WERR_ACCESS_DENIED;
1291 goto done;
1294 newparent->access_granted = access_granted;
1296 /* copy the new key name (just the lower most keyname) */
1298 pstrcpy( name, ptr+1 );
1300 else {
1301 /* use the existing open key information */
1302 newparent = parent;
1303 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1306 /* (3) check for create subkey rights on the correct parent */
1308 if ( !(newparent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
1309 result = WERR_ACCESS_DENIED;
1310 goto done;
1313 regsubkey_ctr_init( &subkeys );
1315 /* lookup the current keys and delete the new one */
1317 fetch_reg_keys( newparent, &subkeys );
1319 regsubkey_ctr_delkey( &subkeys, name );
1321 /* now write to the registry backend */
1323 write_result = store_reg_keys( newparent, &subkeys );
1325 regsubkey_ctr_destroy( &subkeys );
1327 result = write_result ? WERR_OK : WERR_REG_IO_FAILURE;
1329 done:
1330 /* close any intermediate key handles */
1332 if ( newparent != parent )
1333 close_registry_key( p, &newparent_handle );
1335 return result;
1339 /*******************************************************************
1340 ********************************************************************/
1342 WERROR _reg_delete_value(pipes_struct *p, REG_Q_DELETE_VALUE *q_u, REG_R_DELETE_VALUE *r_u)
1344 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1345 REGVAL_CTR values;
1346 BOOL write_result;
1347 fstring valuename;
1349 if ( !key )
1350 return WERR_BADFID;
1352 /* access checks first */
1354 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1355 return WERR_ACCESS_DENIED;
1357 rpcstr_pull( valuename, q_u->name.string->buffer, sizeof(valuename), q_u->name.string->uni_str_len*2, 0 );
1359 regval_ctr_init( &values );
1361 /* lookup the current values and add the new one */
1363 fetch_reg_values( key, &values );
1365 regval_ctr_delvalue( &values, valuename );
1367 /* now write to the registry backend */
1369 write_result = store_reg_values( key, &values );
1371 regval_ctr_destroy( &values );
1373 if ( !write_result )
1374 return WERR_REG_IO_FAILURE;
1376 return WERR_OK;
1379 /*******************************************************************
1380 ********************************************************************/
1382 WERROR _reg_get_key_sec(pipes_struct *p, REG_Q_GET_KEY_SEC *q_u, REG_R_GET_KEY_SEC *r_u)
1384 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1386 if ( !key )
1387 return WERR_BADFID;
1389 /* access checks first */
1391 if ( !(key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
1392 return WERR_ACCESS_DENIED;
1394 return WERR_ACCESS_DENIED;
1397 /*******************************************************************
1398 ********************************************************************/
1400 WERROR _reg_set_key_sec(pipes_struct *p, REG_Q_SET_KEY_SEC *q_u, REG_R_SET_KEY_SEC *r_u)
1402 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1404 if ( !key )
1405 return WERR_BADFID;
1407 /* access checks first */
1409 if ( !(key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
1410 return WERR_ACCESS_DENIED;
1412 return WERR_ACCESS_DENIED;