r10391: * setting version to 3.0.20a
[Samba.git] / source / rpc_server / srv_reg_nt.c
blobfeb89be542405d8b6bcae6b4e6c4381a6e9e049a
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 OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
34 ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
37 static struct generic_mapping reg_generic_map = { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
39 /********************************************************************
40 ********************************************************************/
42 NTSTATUS registry_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
43 uint32 access_desired, uint32 *access_granted )
45 NTSTATUS result;
47 se_map_generic( &access_desired, &reg_generic_map );
48 se_access_check( sec_desc, token, access_desired, access_granted, &result );
50 return result;
53 /********************************************************************
54 ********************************************************************/
56 SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
58 SEC_ACE ace[2];
59 SEC_ACCESS mask;
60 size_t i = 0;
61 SEC_DESC *sd;
62 SEC_ACL *acl;
63 uint32 sd_size;
65 /* basic access for Everyone */
67 init_sec_access(&mask, REG_KEY_READ );
68 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
70 /* Full Access 'BUILTIN\Administrators' */
72 init_sec_access(&mask, REG_KEY_ALL );
73 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
76 /* create the security descriptor */
78 if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
79 return NULL;
81 if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
82 return NULL;
84 return sd;
87 /******************************************************************
88 free() function for REGISTRY_KEY
89 *****************************************************************/
91 static void free_regkey_info(void *ptr)
93 REGISTRY_KEY *info = (REGISTRY_KEY*)ptr;
95 SAFE_FREE(info);
98 /******************************************************************
99 Find a registry key handle and return a REGISTRY_KEY
100 *****************************************************************/
102 static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
104 REGISTRY_KEY *regkey = NULL;
106 if(!find_policy_by_hnd(p,hnd,(void **)&regkey)) {
107 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
108 return NULL;
111 return regkey;
115 /*******************************************************************
116 Function for open a new registry handle and creating a handle
117 Note that P should be valid & hnd should already have space
119 When we open a key, we store the full path to the key as
120 HK[LM|U]\<key>\<key>\...
121 *******************************************************************/
123 static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY *parent,
124 const char *subkeyname, uint32 access_granted )
126 REGISTRY_KEY *regkey = NULL;
127 WERROR result = WERR_OK;
128 REGSUBKEY_CTR subkeys;
129 pstring subkeyname2;
130 int subkey_len;
132 DEBUG(7,("open_registry_key: name = [%s][%s]\n",
133 parent ? parent->name : "NULL", subkeyname));
135 /* strip any trailing '\'s */
136 pstrcpy( subkeyname2, subkeyname );
137 subkey_len = strlen ( subkeyname2 );
138 if ( subkey_len && subkeyname2[subkey_len-1] == '\\' )
139 subkeyname2[subkey_len-1] = '\0';
141 if ((regkey=SMB_MALLOC_P(REGISTRY_KEY)) == NULL)
142 return WERR_NOMEM;
144 ZERO_STRUCTP( regkey );
147 * very crazy, but regedit.exe on Win2k will attempt to call
148 * REG_OPEN_ENTRY with a keyname of "". We should return a new
149 * (second) handle here on the key->name. regedt32.exe does
150 * not do this stupidity. --jerry
153 if ( !subkey_len ) {
154 pstrcpy( regkey->name, parent->name );
156 else {
157 pstrcpy( regkey->name, "" );
158 if ( parent ) {
159 pstrcat( regkey->name, parent->name );
160 pstrcat( regkey->name, "\\" );
162 pstrcat( regkey->name, subkeyname2 );
165 /* Look up the table of registry I/O operations */
167 if ( !(regkey->hook = reghook_cache_find( regkey->name )) ) {
168 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
169 regkey->name ));
170 return WERR_BADFILE;
173 /* check if the path really exists; failed is indicated by -1 */
174 /* if the subkey count failed, bail out */
176 regsubkey_ctr_init( &subkeys );
178 if ( fetch_reg_keys( regkey, &subkeys ) == -1 ) {
179 result = WERR_BADFILE;
180 goto done;
183 if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) {
184 result = WERR_BADFILE;
185 goto done;
188 /* save the access mask */
190 regkey->access_granted = access_granted;
192 done:
193 /* clean up */
195 regsubkey_ctr_destroy( &subkeys );
197 if ( ! NT_STATUS_IS_OK(result) )
198 SAFE_FREE( regkey );
200 DEBUG(7,("open_registry_key: exit\n"));
202 return result;
205 /*******************************************************************
206 Function for open a new registry handle and creating a handle
207 Note that P should be valid & hnd should already have space
208 *******************************************************************/
210 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
212 REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd);
214 if ( !regkey ) {
215 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
216 return False;
219 close_policy_hnd(p, hnd);
221 return True;
224 /********************************************************************
225 retrieve information about the subkeys
226 *******************************************************************/
228 static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen )
230 int num_subkeys, i;
231 uint32 max_len;
232 REGSUBKEY_CTR subkeys;
233 uint32 len;
235 if ( !key )
236 return False;
238 regsubkey_ctr_init( &subkeys );
240 if ( fetch_reg_keys( key, &subkeys ) == -1 )
241 return False;
243 /* find the longest string */
245 max_len = 0;
246 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
248 for ( i=0; i<num_subkeys; i++ ) {
249 len = strlen( regsubkey_ctr_specific_key(&subkeys, i) );
250 max_len = MAX(max_len, len);
253 *maxnum = num_subkeys;
254 *maxlen = max_len*2;
256 regsubkey_ctr_destroy( &subkeys );
258 return True;
261 /********************************************************************
262 retrieve information about the values.
263 *******************************************************************/
265 static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum,
266 uint32 *maxlen, uint32 *maxsize )
268 REGVAL_CTR values;
269 REGISTRY_VALUE *val;
270 uint32 sizemax, lenmax;
271 int i, num_values;
273 if ( !key )
274 return False;
276 regval_ctr_init( &values );
278 if ( fetch_reg_values( key, &values ) == -1 )
279 return False;
281 lenmax = sizemax = 0;
282 num_values = regval_ctr_numvals( &values );
284 val = regval_ctr_specific_value( &values, 0 );
286 for ( i=0; i<num_values && val; i++ )
288 lenmax = MAX(lenmax, val->valuename ? strlen(val->valuename)+1 : 0 );
289 sizemax = MAX(sizemax, val->size );
291 val = regval_ctr_specific_value( &values, i );
294 *maxnum = num_values;
295 *maxlen = lenmax;
296 *maxsize = sizemax;
298 regval_ctr_destroy( &values );
300 return True;
304 /********************************************************************
305 reg_close
306 ********************************************************************/
308 WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
310 /* close the policy handle */
312 if (!close_registry_key(p, &q_u->pol))
313 return WERR_BADFID;
315 return WERR_OK;
318 /*******************************************************************
319 ********************************************************************/
321 WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
323 SEC_DESC *sec_desc;
324 uint32 access_granted = 0;
325 NTSTATUS status;
327 /* perform access checks */
328 /* top level keys are done here without passing through the REGISTRY_HOOK api */
330 if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
331 return WERR_NOMEM;
333 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
334 if ( !NT_STATUS_IS_OK(status) )
335 return ntstatus_to_werror( status );
337 return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, access_granted );
340 /*******************************************************************
341 ********************************************************************/
343 WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
345 SEC_DESC *sec_desc;
346 uint32 access_granted = 0;
347 NTSTATUS status;
349 /* perform access checks */
350 /* top level keys are done here without passing through the REGISTRY_HOOK api */
352 if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
353 return WERR_NOMEM;
355 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
356 if ( !NT_STATUS_IS_OK(status) )
357 return ntstatus_to_werror( status );
359 return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, access_granted );
362 /*******************************************************************
363 ********************************************************************/
365 WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
367 SEC_DESC *sec_desc;
368 uint32 access_granted = 0;
369 NTSTATUS status;
371 /* perform access checks */
372 /* top level keys are done here without passing through the REGISTRY_HOOK api */
374 if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
375 return WERR_NOMEM;
377 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
378 if ( !NT_STATUS_IS_OK(status) )
379 return ntstatus_to_werror( status );
381 return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, access_granted );
384 /*******************************************************************
385 reg_reply_open_entry
386 ********************************************************************/
388 WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
390 fstring name;
391 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->pol);
392 REGISTRY_KEY *newkey;
393 uint32 access_granted;
394 WERROR result;
396 if ( !parent )
397 return WERR_BADFID;
399 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
401 /* check granted access first; what is the correct mask here? */
403 if ( !(parent->access_granted & (SEC_RIGHTS_ENUM_SUBKEYS|SEC_RIGHTS_CREATE_SUBKEY)) )
404 return WERR_ACCESS_DENIED;
406 /* open the key first to get the appropriate REGISTRY_HOOK
407 and then check the premissions */
409 if ( !W_ERROR_IS_OK(result = open_registry_key( p, &r_u->handle, parent, name, 0 )) )
410 return result;
412 newkey = find_regkey_index_by_hnd(p, &r_u->handle);
414 /* finally allow the backend to check the access for the requested key */
416 if ( !regkey_access_check( newkey, q_u->access, &access_granted, p->pipe_user.nt_user_token ) ) {
417 close_registry_key( p, &r_u->handle );
418 return WERR_ACCESS_DENIED;
421 /* if successful, save the granted access mask */
423 newkey->access_granted = access_granted;
425 return WERR_OK;
428 /*******************************************************************
429 reg_reply_info
430 ********************************************************************/
432 WERROR _reg_query_value(pipes_struct *p, REG_Q_QUERY_VALUE *q_u, REG_R_QUERY_VALUE *r_u)
434 WERROR status = WERR_BADFILE;
435 fstring name;
436 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
437 REGISTRY_VALUE *val = NULL;
438 REGVAL_CTR regvals;
439 int i;
441 if ( !regkey )
442 return WERR_BADFID;
444 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
446 rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
448 DEBUG(5,("reg_info: looking up value: [%s]\n", name));
450 regval_ctr_init( &regvals );
452 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
454 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
455 if ( strequal( val->valuename, name ) ) {
456 DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
457 status = WERR_OK;
458 break;
461 free_registry_value( val );
464 init_reg_r_query_value(q_u->ptr_buf, r_u, val, status);
466 regval_ctr_destroy( &regvals );
467 free_registry_value( val );
469 return status;
473 /*****************************************************************************
474 Implementation of REG_QUERY_KEY
475 ****************************************************************************/
477 WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
479 WERROR status = WERR_OK;
480 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
482 if ( !regkey )
483 return WERR_BADFID;
485 if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) ) {
486 DEBUG(0,("_reg_query_key: get_subkey_information() failed!\n"));
487 return WERR_ACCESS_DENIED;
490 if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) ) {
491 DEBUG(0,("_reg_query_key: get_value_information() failed!\n"));
492 return WERR_ACCESS_DENIED;
496 r_u->sec_desc = 0x00000078; /* size for key's sec_desc */
498 /* Win9x set this to 0x0 since it does not keep timestamps.
499 Doing the same here for simplicity --jerry */
501 ZERO_STRUCT(r_u->mod_time);
503 return status;
507 /*****************************************************************************
508 Implementation of REG_GETVERSION
509 ****************************************************************************/
511 WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u)
513 WERROR status = WERR_OK;
514 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
516 if ( !regkey )
517 return WERR_BADFID;
519 r_u->win_version = 0x00000005; /* Windows 2000 registry API version */
521 return status;
525 /*****************************************************************************
526 Implementation of REG_ENUM_KEY
527 ****************************************************************************/
529 WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
531 WERROR status = WERR_OK;
532 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
533 char *subkey = NULL;
536 if ( !regkey )
537 return WERR_BADFID;
539 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
541 if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) )
543 status = WERR_NO_MORE_ITEMS;
544 goto done;
547 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
549 /* subkey has the string name now */
551 init_reg_r_enum_key( r_u, subkey );
553 done:
554 SAFE_FREE( subkey );
555 return status;
558 /*****************************************************************************
559 Implementation of REG_ENUM_VALUE
560 ****************************************************************************/
562 WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u)
564 WERROR status = WERR_OK;
565 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
566 REGISTRY_VALUE *val;
569 if ( !regkey )
570 return WERR_BADFID;
572 DEBUG(8,("_reg_enum_value: enumerating values for key [%s]\n", regkey->name));
574 if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) {
575 status = WERR_NO_MORE_ITEMS;
576 goto done;
579 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val->valuename));
581 /* subkey has the string name now */
583 init_reg_r_enum_val( r_u, val );
585 done:
586 free_registry_value( val );
588 return status;
592 /*******************************************************************
593 reg_shutdwon
594 ********************************************************************/
596 WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
598 REG_Q_SHUTDOWN_EX q_u_ex;
599 REG_R_SHUTDOWN_EX r_u_ex;
601 /* copy fields (including stealing memory) */
603 q_u_ex.server = q_u->server;
604 q_u_ex.message = q_u->message;
605 q_u_ex.timeout = q_u->timeout;
606 q_u_ex.force = q_u->force;
607 q_u_ex.reboot = q_u->reboot;
608 q_u_ex.reason = 0x0; /* don't care for now */
610 /* thunk down to _reg_shutdown_ex() (just returns a status) */
612 return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex );
615 /*******************************************************************
616 reg_shutdown_ex
617 ********************************************************************/
619 #define SHUTDOWN_R_STRING "-r"
620 #define SHUTDOWN_F_STRING "-f"
623 WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u)
625 pstring shutdown_script;
626 pstring message;
627 pstring chkmsg;
628 fstring timeout;
629 fstring reason;
630 fstring r;
631 fstring f;
632 int ret;
633 BOOL can_shutdown;
636 pstrcpy(shutdown_script, lp_shutdown_script());
638 if ( !*shutdown_script )
639 return WERR_ACCESS_DENIED;
641 /* pull the message string and perform necessary sanity checks on it */
643 pstrcpy( message, "" );
644 if ( q_u->message ) {
645 UNISTR2 *msg_string = q_u->message->string;
647 rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 );
649 alpha_strcpy (chkmsg, message, NULL, sizeof(message));
651 fstr_sprintf(timeout, "%d", q_u->timeout);
652 fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : "");
653 fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : "");
654 fstr_sprintf( reason, "%d", q_u->reason );
656 all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
657 all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) );
658 all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
659 all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
660 all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) );
662 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
664 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
665 Take the error return from the script and provide it as the Windows return code. */
667 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
669 if ( can_shutdown )
670 become_root();
672 ret = smbrun( shutdown_script, NULL );
674 if ( can_shutdown )
675 unbecome_root();
677 /********** END SeRemoteShutdownPrivilege BLOCK **********/
679 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
680 shutdown_script, ret));
683 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
689 /*******************************************************************
690 reg_abort_shutdwon
691 ********************************************************************/
693 WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
695 pstring abort_shutdown_script;
696 int ret;
697 BOOL can_shutdown;
699 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
701 if ( !*abort_shutdown_script )
702 return WERR_ACCESS_DENIED;
704 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
706 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
708 if ( can_shutdown )
709 become_root();
711 ret = smbrun( abort_shutdown_script, NULL );
713 if ( can_shutdown )
714 unbecome_root();
716 /********** END SeRemoteShutdownPrivilege BLOCK **********/
718 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
719 abort_shutdown_script, ret));
722 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
725 /*******************************************************************
726 ********************************************************************/
728 static int validate_reg_filename( pstring fname )
730 char *p;
731 int num_services = lp_numservices();
732 int snum;
733 pstring share_path;
734 pstring unix_fname;
736 /* convert to a unix path, stripping the C:\ along the way */
738 if ( !(p = valid_share_pathname( fname ) ))
739 return -1;
741 /* has to exist within a valid file share */
743 for ( snum=0; snum<num_services; snum++ ) {
745 if ( !lp_snum_ok(snum) || lp_print_ok(snum) )
746 continue;
748 pstrcpy( share_path, lp_pathname(snum) );
750 /* make sure we have a path (e.g. [homes] ) */
752 if ( strlen( share_path ) == 0 )
753 continue;
755 if ( strncmp( share_path, p, strlen( share_path )) == 0 )
756 break;
759 /* p and fname are overlapping memory so copy out and back in again */
761 pstrcpy( unix_fname, p );
762 pstrcpy( fname, unix_fname );
764 return (snum < num_services) ? snum : -1;
767 /*******************************************************************
768 Note: topkeypat is the *full* path that this *key will be
769 loaded into (including the name of the key)
770 ********************************************************************/
772 static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath,
773 REGF_NK_REC *key )
775 REGF_NK_REC *subkey;
776 REGISTRY_KEY registry_key;
777 REGVAL_CTR values;
778 REGSUBKEY_CTR subkeys;
779 int i;
780 pstring path;
781 WERROR result = WERR_OK;
783 /* initialize the REGISTRY_KEY structure */
785 if ( !(registry_key.hook = reghook_cache_find(topkeypath)) ) {
786 DEBUG(0,("reg_load_tree: Failed to assigned a REGISTRY_HOOK to [%s]\n",
787 topkeypath ));
788 return WERR_BADFILE;
790 pstrcpy( registry_key.name, topkeypath );
792 /* now start parsing the values and subkeys */
794 regsubkey_ctr_init( &subkeys );
795 regval_ctr_init( &values );
797 /* copy values into the REGVAL_CTR */
799 for ( i=0; i<key->num_values; i++ ) {
800 regval_ctr_addvalue( &values, key->values[i].valuename, key->values[i].type,
801 key->values[i].data, (key->values[i].data_size & ~VK_DATA_IN_OFFSET) );
804 /* copy subkeys into the REGSUBKEY_CTR */
806 key->subkey_index = 0;
807 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
808 regsubkey_ctr_addkey( &subkeys, subkey->keyname );
811 /* write this key and values out */
813 if ( !store_reg_values( &registry_key, &values )
814 || !store_reg_keys( &registry_key, &subkeys ) )
816 DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
817 result = WERR_REG_IO_FAILURE;
820 regval_ctr_destroy( &values );
821 regsubkey_ctr_destroy( &subkeys );
823 if ( !W_ERROR_IS_OK(result) )
824 return result;
826 /* now continue to load each subkey registry tree */
828 key->subkey_index = 0;
829 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
830 pstr_sprintf( path, "%s%s%s", topkeypath, "\\", subkey->keyname );
831 result = reg_load_tree( regfile, path, subkey );
832 if ( !W_ERROR_IS_OK(result) )
833 break;
836 return result;
839 /*******************************************************************
840 ********************************************************************/
842 static WERROR restore_registry_key ( REGISTRY_KEY *krecord, const char *fname )
844 REGF_FILE *regfile;
845 REGF_NK_REC *rootkey;
846 WERROR result;
848 /* open the registry file....fail if the file already exists */
850 if ( !(regfile = regfio_open( fname, (O_RDONLY), 0 )) ) {
851 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
852 fname, strerror(errno) ));
853 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
856 /* get the rootkey from the regf file and then load the tree
857 via recursive calls */
859 if ( !(rootkey = regfio_rootkey( regfile )) )
860 return WERR_REG_FILE_INVALID;
862 result = reg_load_tree( regfile, krecord->name, rootkey );
864 /* cleanup */
866 regfio_close( regfile );
868 return result;
871 /*******************************************************************
872 ********************************************************************/
874 WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY *q_u, REG_R_RESTORE_KEY *r_u)
876 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
877 pstring filename;
878 int snum;
880 if ( !regkey )
881 return WERR_BADFID;
883 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
885 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
887 if ( (snum = validate_reg_filename( filename )) == -1 )
888 return WERR_OBJECT_PATH_INVALID;
890 /* user must posses SeRestorePrivilege for this this proceed */
892 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
893 return WERR_ACCESS_DENIED;
895 DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
897 return restore_registry_key( regkey, filename );
900 /********************************************************************
901 ********************************************************************/
903 static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath,
904 REGF_NK_REC *parent, SEC_DESC *sec_desc )
906 REGF_NK_REC *key;
907 REGVAL_CTR values;
908 REGSUBKEY_CTR subkeys;
909 int i, num_subkeys;
910 pstring key_tmp;
911 char *keyname, *parentpath;
912 pstring subkeypath;
913 char *subkeyname;
914 REGISTRY_KEY registry_key;
915 WERROR result = WERR_OK;
917 if ( !regfile )
918 return WERR_GENERAL_FAILURE;
920 if ( !keypath )
921 return WERR_OBJECT_PATH_INVALID;
923 /* split up the registry key path */
925 pstrcpy( key_tmp, keypath );
926 if ( !reg_split_key( key_tmp, &parentpath, &keyname ) )
927 return WERR_OBJECT_PATH_INVALID;
929 if ( !keyname )
930 keyname = parentpath;
932 /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
934 ZERO_STRUCT( registry_key );
935 pstrcpy( registry_key.name, keypath );
936 if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) )
937 return WERR_BADFILE;
940 /* lookup the values and subkeys */
942 regsubkey_ctr_init( &subkeys );
943 regval_ctr_init( &values );
945 fetch_reg_keys( &registry_key, &subkeys );
946 fetch_reg_values( &registry_key, &values );
948 /* write out this key */
950 if ( !(key = regfio_write_key( regfile, keyname, &values, &subkeys, sec_desc, parent )) ) {
951 result = WERR_CAN_NOT_COMPLETE;
952 goto done;
955 /* write each one of the subkeys out */
957 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
958 for ( i=0; i<num_subkeys; i++ ) {
959 subkeyname = regsubkey_ctr_specific_key( &subkeys, i );
960 pstr_sprintf( subkeypath, "%s\\%s", keypath, subkeyname );
961 result = reg_write_tree( regfile, subkeypath, key, sec_desc );
962 if ( !W_ERROR_IS_OK(result) )
963 goto done;
966 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath ));
968 done:
969 regval_ctr_destroy( &values );
970 regsubkey_ctr_destroy( &subkeys );
972 return result;
975 /*******************************************************************
976 ********************************************************************/
978 static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
980 DOM_SID adm_sid, owner_sid;
981 SEC_ACE ace[2]; /* at most 2 entries */
982 SEC_ACCESS mask;
983 SEC_ACL *psa = NULL;
984 uint32 sd_size;
986 /* set the owner to BUILTIN\Administrator */
988 sid_copy(&owner_sid, &global_sid_Builtin);
989 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
992 /* basic access for Everyone */
994 init_sec_access(&mask, reg_generic_map.generic_execute | reg_generic_map.generic_read );
995 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
997 /* add Full Access 'BUILTIN\Administrators' */
999 init_sec_access(&mask, reg_generic_map.generic_all);
1000 sid_copy(&adm_sid, &global_sid_Builtin);
1001 sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
1002 init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1004 /* create the security descriptor */
1006 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace)) == NULL)
1007 return WERR_NOMEM;
1009 if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &owner_sid, NULL, NULL, psa, &sd_size)) == NULL)
1010 return WERR_NOMEM;
1012 return WERR_OK;
1015 /*******************************************************************
1016 ********************************************************************/
1018 static WERROR backup_registry_key ( REGISTRY_KEY *krecord, const char *fname )
1020 REGF_FILE *regfile;
1021 WERROR result;
1022 SEC_DESC *sd = NULL;
1024 /* open the registry file....fail if the file already exists */
1026 if ( !(regfile = regfio_open( fname, (O_RDWR|O_CREAT|O_EXCL), (S_IREAD|S_IWRITE) )) ) {
1027 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
1028 fname, strerror(errno) ));
1029 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
1032 if ( !W_ERROR_IS_OK(result = make_default_reg_sd( regfile->mem_ctx, &sd )) ) {
1033 regfio_close( regfile );
1034 return result;
1037 /* write the registry tree to the file */
1039 result = reg_write_tree( regfile, krecord->name, NULL, sd );
1041 /* cleanup */
1043 regfio_close( regfile );
1045 return result;
1048 /*******************************************************************
1049 ********************************************************************/
1051 WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u)
1053 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
1054 pstring filename;
1055 int snum;
1057 if ( !regkey )
1058 return WERR_BADFID;
1060 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
1062 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
1064 if ( (snum = validate_reg_filename( filename )) == -1 )
1065 return WERR_OBJECT_PATH_INVALID;
1067 DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
1069 return backup_registry_key( regkey, filename );
1071 return WERR_OK;
1074 /*******************************************************************
1075 ********************************************************************/
1077 WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREATE_KEY_EX *r_u)
1079 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1080 REGISTRY_KEY *newparent;
1081 POLICY_HND newparent_handle;
1082 REGSUBKEY_CTR subkeys;
1083 BOOL write_result;
1084 pstring name;
1085 WERROR result;
1087 if ( !parent )
1088 return WERR_BADFID;
1090 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1092 /* ok. Here's what we do. */
1094 if ( strrchr( name, '\\' ) ) {
1095 pstring newkeyname;
1096 char *ptr;
1097 uint32 access_granted;
1099 /* (1) check for enumerate rights on the parent handle. CLients can try
1100 create things like 'SOFTWARE\Samba' on the HKLM handle.
1101 (2) open the path to the child parent key if necessary */
1103 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1104 return WERR_ACCESS_DENIED;
1106 pstrcpy( newkeyname, name );
1107 ptr = strrchr( newkeyname, '\\' );
1108 *ptr = '\0';
1110 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1111 if ( !W_ERROR_IS_OK(result) )
1112 return result;
1114 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1115 SMB_ASSERT( newparent != NULL );
1117 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1118 result = WERR_ACCESS_DENIED;
1119 goto done;
1122 newparent->access_granted = access_granted;
1124 /* copy the new key name (just the lower most keyname) */
1126 pstrcpy( name, ptr+1 );
1128 else {
1129 /* use the existing open key information */
1130 newparent = parent;
1131 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1134 /* (3) check for create subkey rights on the correct parent */
1136 if ( !(newparent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
1137 result = WERR_ACCESS_DENIED;
1138 goto done;
1141 regsubkey_ctr_init( &subkeys );
1143 /* (4) lookup the current keys and add the new one */
1145 fetch_reg_keys( newparent, &subkeys );
1146 regsubkey_ctr_addkey( &subkeys, name );
1148 /* now write to the registry backend */
1150 write_result = store_reg_keys( newparent, &subkeys );
1152 regsubkey_ctr_destroy( &subkeys );
1154 if ( !write_result )
1155 return WERR_REG_IO_FAILURE;
1157 /* (5) open the new key and return the handle. Note that it is probably
1158 not correct to grant full access on this open handle. We should pass
1159 the new open through the regkey_access_check() like we do for
1160 _reg_open_entry() but this is ok for now. */
1162 result = open_registry_key( p, &r_u->handle, newparent, name, REG_KEY_ALL );
1164 done:
1165 /* close any intermediate key handles */
1167 if ( newparent != parent )
1168 close_registry_key( p, &newparent_handle );
1170 return result;
1174 /*******************************************************************
1175 ********************************************************************/
1177 WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r_u)
1179 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1180 REGVAL_CTR values;
1181 BOOL write_result;
1182 fstring valuename;
1184 if ( !key )
1185 return WERR_BADFID;
1187 /* access checks first */
1189 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1190 return WERR_ACCESS_DENIED;
1192 rpcstr_pull( valuename, q_u->name.string->buffer, sizeof(valuename), q_u->name.string->uni_str_len*2, 0 );
1194 /* verify the name */
1196 if ( !*valuename )
1197 return WERR_INVALID_PARAM;
1199 DEBUG(8,("_reg_set_value: Setting value for [%s:%s]\n", key->name, valuename));
1201 regval_ctr_init( &values );
1203 /* lookup the current values and add the new one */
1205 fetch_reg_values( key, &values );
1207 regval_ctr_addvalue( &values, valuename, q_u->type, q_u->value.buffer, q_u->value.buf_len );
1209 /* now write to the registry backend */
1211 write_result = store_reg_values( key, &values );
1213 regval_ctr_destroy( &values );
1215 if ( !write_result )
1216 return WERR_REG_IO_FAILURE;
1218 return WERR_OK;
1221 /*******************************************************************
1222 ********************************************************************/
1224 WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY *r_u)
1226 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1227 REGISTRY_KEY *newparent;
1228 POLICY_HND newparent_handle;
1229 REGSUBKEY_CTR subkeys;
1230 BOOL write_result;
1231 pstring name;
1232 WERROR result;
1234 if ( !parent )
1235 return WERR_BADFID;
1237 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1239 /* ok. Here's what we do. */
1241 if ( strrchr( name, '\\' ) ) {
1242 pstring newkeyname;
1243 char *ptr;
1244 uint32 access_granted;
1246 /* (1) check for enumerate rights on the parent handle. CLients can try
1247 create things like 'SOFTWARE\Samba' on the HKLM handle.
1248 (2) open the path to the child parent key if necessary */
1250 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1251 return WERR_ACCESS_DENIED;
1253 pstrcpy( newkeyname, name );
1254 ptr = strrchr( newkeyname, '\\' );
1255 *ptr = '\0';
1257 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1258 if ( !W_ERROR_IS_OK(result) )
1259 return result;
1261 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1262 SMB_ASSERT( newparent != NULL );
1264 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1265 result = WERR_ACCESS_DENIED;
1266 goto done;
1269 newparent->access_granted = access_granted;
1271 /* copy the new key name (just the lower most keyname) */
1273 pstrcpy( name, ptr+1 );
1275 else {
1276 /* use the existing open key information */
1277 newparent = parent;
1278 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1281 /* (3) check for create subkey rights on the correct parent */
1283 if ( !(newparent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
1284 result = WERR_ACCESS_DENIED;
1285 goto done;
1288 regsubkey_ctr_init( &subkeys );
1290 /* lookup the current keys and delete the new one */
1292 fetch_reg_keys( newparent, &subkeys );
1294 regsubkey_ctr_delkey( &subkeys, name );
1296 /* now write to the registry backend */
1298 write_result = store_reg_keys( newparent, &subkeys );
1300 regsubkey_ctr_destroy( &subkeys );
1302 result = write_result ? WERR_OK : WERR_REG_IO_FAILURE;
1304 done:
1305 /* close any intermediate key handles */
1307 if ( newparent != parent )
1308 close_registry_key( p, &newparent_handle );
1310 return result;
1314 /*******************************************************************
1315 ********************************************************************/
1317 WERROR _reg_delete_value(pipes_struct *p, REG_Q_DELETE_VALUE *q_u, REG_R_DELETE_VALUE *r_u)
1319 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1320 REGVAL_CTR values;
1321 BOOL write_result;
1322 fstring valuename;
1324 if ( !key )
1325 return WERR_BADFID;
1327 /* access checks first */
1329 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1330 return WERR_ACCESS_DENIED;
1332 rpcstr_pull( valuename, q_u->name.string->buffer, sizeof(valuename), q_u->name.string->uni_str_len*2, 0 );
1334 if ( !*valuename )
1335 return WERR_INVALID_PARAM;
1337 DEBUG(8,("_reg_delete_value: Setting value for [%s:%s]\n", key->name, valuename));
1339 regval_ctr_init( &values );
1341 /* lookup the current values and add the new one */
1343 fetch_reg_values( key, &values );
1345 regval_ctr_delvalue( &values, valuename );
1347 /* now write to the registry backend */
1349 write_result = store_reg_values( key, &values );
1351 regval_ctr_destroy( &values );
1353 if ( !write_result )
1354 return WERR_REG_IO_FAILURE;
1356 return WERR_OK;
1359 /*******************************************************************
1360 ********************************************************************/
1362 WERROR _reg_get_key_sec(pipes_struct *p, REG_Q_GET_KEY_SEC *q_u, REG_R_GET_KEY_SEC *r_u)
1364 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1366 if ( !key )
1367 return WERR_BADFID;
1369 /* access checks first */
1371 if ( !(key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
1372 return WERR_ACCESS_DENIED;
1374 return WERR_ACCESS_DENIED;
1377 /*******************************************************************
1378 ********************************************************************/
1380 WERROR _reg_set_key_sec(pipes_struct *p, REG_Q_SET_KEY_SEC *q_u, REG_R_SET_KEY_SEC *r_u)
1382 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1384 if ( !key )
1385 return WERR_BADFID;
1387 /* access checks first */
1389 if ( !(key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
1390 return WERR_ACCESS_DENIED;
1392 return WERR_ACCESS_DENIED;