r7698: * clean upserver frontend for RegDeleteKey()
[Samba.git] / source / rpc_server / srv_reg_nt.c
bloba3ab63d06ec1259c3c4578b19909f549095724ff
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_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u)
444 WERROR status = WERR_BADFILE;
445 fstring name;
446 const char *value_ascii = "";
447 fstring value;
448 int value_length;
449 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
450 REGISTRY_VALUE *val = NULL;
451 REGVAL_CTR regvals;
452 int i;
454 DEBUG(5,("_reg_info: Enter\n"));
456 if ( !regkey )
457 return WERR_BADFID;
459 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
461 rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
463 DEBUG(5,("reg_info: looking up value: [%s]\n", name));
465 regval_ctr_init( &regvals );
467 /* couple of hard coded registry values */
469 if ( strequal(name, "RefusePasswordChange") ) {
470 uint32 dwValue;
472 if ( (val = SMB_MALLOC_P(REGISTRY_VALUE)) == NULL ) {
473 DEBUG(0,("_reg_info: malloc() failed!\n"));
474 return WERR_NOMEM;
477 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue))
478 dwValue = 0;
479 regval_ctr_addvalue(&regvals, "RefusePasswordChange",
480 REG_DWORD,
481 (const char*)&dwValue, sizeof(dwValue));
482 val = dup_registry_value(
483 regval_ctr_specific_value( &regvals, 0 ) );
485 status = WERR_OK;
487 goto out;
490 if ( strequal(name, REGSTR_PRODUCTTYPE) ) {
491 /* This makes the server look like a member server to clients */
492 /* which tells clients that we have our own local user and */
493 /* group databases and helps with ACL support. */
495 switch (lp_server_role()) {
496 case ROLE_DOMAIN_PDC:
497 case ROLE_DOMAIN_BDC:
498 value_ascii = REG_PT_LANMANNT;
499 break;
500 case ROLE_STANDALONE:
501 value_ascii = REG_PT_SERVERNT;
502 break;
503 case ROLE_DOMAIN_MEMBER:
504 value_ascii = REG_PT_WINNT;
505 break;
507 value_length = push_ucs2(value, value, value_ascii,
508 sizeof(value),
509 STR_TERMINATE|STR_NOALIGN);
510 regval_ctr_addvalue(&regvals, REGSTR_PRODUCTTYPE, REG_SZ,
511 value, value_length);
513 val = dup_registry_value( regval_ctr_specific_value( &regvals, 0 ) );
515 status = WERR_OK;
517 goto out;
520 /* else fall back to actually looking up the value */
522 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
524 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
525 if ( StrCaseCmp( val->valuename, name ) == 0 ) {
526 DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
527 status = WERR_OK;
528 break;
531 free_registry_value( val );
535 out:
536 init_reg_r_info(q_u->ptr_buf, r_u, val, status);
538 regval_ctr_destroy( &regvals );
539 free_registry_value( val );
541 DEBUG(5,("_reg_info: Exit\n"));
543 return status;
547 /*****************************************************************************
548 Implementation of REG_QUERY_KEY
549 ****************************************************************************/
551 WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
553 WERROR status = WERR_OK;
554 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
556 DEBUG(5,("_reg_query_key: Enter\n"));
558 if ( !regkey )
559 return WERR_BADFID;
561 if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) )
562 return WERR_ACCESS_DENIED;
564 if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) )
565 return WERR_ACCESS_DENIED;
568 r_u->sec_desc = 0x00000078; /* size for key's sec_desc */
570 /* Win9x set this to 0x0 since it does not keep timestamps.
571 Doing the same here for simplicity --jerry */
573 ZERO_STRUCT(r_u->mod_time);
575 DEBUG(5,("_reg_query_key: Exit\n"));
577 return status;
581 /*****************************************************************************
582 Implementation of REG_GETVERSION
583 ****************************************************************************/
585 WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u)
587 WERROR status = WERR_OK;
588 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
590 DEBUG(5,("_reg_getversion: Enter\n"));
592 if ( !regkey )
593 return WERR_BADFID;
595 r_u->win_version = 0x00000005; /* Windows 2000 registry API version */
597 DEBUG(5,("_reg_getversion: Exit\n"));
599 return status;
603 /*****************************************************************************
604 Implementation of REG_ENUM_KEY
605 ****************************************************************************/
607 WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
609 WERROR status = WERR_OK;
610 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
611 char *subkey = NULL;
614 DEBUG(5,("_reg_enum_key: Enter\n"));
616 if ( !regkey )
617 return WERR_BADFID;
619 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
621 if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) )
623 status = WERR_NO_MORE_ITEMS;
624 goto done;
627 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
629 /* subkey has the string name now */
631 init_reg_r_enum_key( r_u, subkey );
633 DEBUG(5,("_reg_enum_key: Exit\n"));
635 done:
636 SAFE_FREE( subkey );
637 return status;
640 /*****************************************************************************
641 Implementation of REG_ENUM_VALUE
642 ****************************************************************************/
644 WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u)
646 WERROR status = WERR_OK;
647 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
648 REGISTRY_VALUE *val;
651 DEBUG(5,("_reg_enum_value: Enter\n"));
653 if ( !regkey )
654 return WERR_BADFID;
656 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey->name));
658 if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) {
659 status = WERR_NO_MORE_ITEMS;
660 goto done;
663 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val->valuename));
665 /* subkey has the string name now */
667 init_reg_r_enum_val( r_u, val );
670 DEBUG(5,("_reg_enum_value: Exit\n"));
672 done:
673 free_registry_value( val );
675 return status;
679 /*******************************************************************
680 reg_shutdwon
681 ********************************************************************/
683 WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
685 REG_Q_SHUTDOWN_EX q_u_ex;
686 REG_R_SHUTDOWN_EX r_u_ex;
688 /* copy fields (including stealing memory) */
690 q_u_ex.server = q_u->server;
691 q_u_ex.message = q_u->message;
692 q_u_ex.timeout = q_u->timeout;
693 q_u_ex.force = q_u->force;
694 q_u_ex.reboot = q_u->reboot;
695 q_u_ex.reason = 0x0; /* don't care for now */
697 /* thunk down to _reg_shutdown_ex() (just returns a status) */
699 return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex );
702 /*******************************************************************
703 reg_shutdown_ex
704 ********************************************************************/
706 #define SHUTDOWN_R_STRING "-r"
707 #define SHUTDOWN_F_STRING "-f"
710 WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u)
712 pstring shutdown_script;
713 pstring message;
714 pstring chkmsg;
715 fstring timeout;
716 fstring reason;
717 fstring r;
718 fstring f;
719 int ret;
720 BOOL can_shutdown;
723 pstrcpy(shutdown_script, lp_shutdown_script());
725 if ( !*shutdown_script )
726 return WERR_ACCESS_DENIED;
728 /* pull the message string and perform necessary sanity checks on it */
730 pstrcpy( message, "" );
731 if ( q_u->message ) {
732 UNISTR2 *msg_string = q_u->message->string;
734 rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 );
736 alpha_strcpy (chkmsg, message, NULL, sizeof(message));
738 fstr_sprintf(timeout, "%d", q_u->timeout);
739 fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : "");
740 fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : "");
741 fstr_sprintf( reason, "%d", q_u->reason );
743 all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
744 all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) );
745 all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
746 all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
747 all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) );
749 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
751 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
752 Take the error return from the script and provide it as the Windows return code. */
754 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
756 if ( can_shutdown )
757 become_root();
759 ret = smbrun( shutdown_script, NULL );
761 if ( can_shutdown )
762 unbecome_root();
764 /********** END SeRemoteShutdownPrivilege BLOCK **********/
766 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
767 shutdown_script, ret));
770 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
776 /*******************************************************************
777 reg_abort_shutdwon
778 ********************************************************************/
780 WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
782 pstring abort_shutdown_script;
783 int ret;
784 BOOL can_shutdown;
786 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
788 if ( !*abort_shutdown_script )
789 return WERR_ACCESS_DENIED;
791 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
793 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
795 if ( can_shutdown )
796 become_root();
798 ret = smbrun( abort_shutdown_script, NULL );
800 if ( can_shutdown )
801 unbecome_root();
803 /********** END SeRemoteShutdownPrivilege BLOCK **********/
805 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
806 abort_shutdown_script, ret));
809 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
812 /*******************************************************************
813 ********************************************************************/
815 static int validate_reg_filename( pstring fname )
817 char *p;
818 int num_services = lp_numservices();
819 int snum;
820 pstring share_path;
821 pstring unix_fname;
823 /* convert to a unix path, stripping the C:\ along the way */
825 if ( !(p = valid_share_pathname( fname ) ))
826 return -1;
828 /* has to exist within a valid file share */
830 for ( snum=0; snum<num_services; snum++ ) {
832 if ( !lp_snum_ok(snum) || lp_print_ok(snum) )
833 continue;
835 pstrcpy( share_path, lp_pathname(snum) );
837 /* make sure we have a path (e.g. [homes] ) */
839 if ( strlen( share_path ) == 0 )
840 continue;
842 if ( strncmp( share_path, p, strlen( share_path )) == 0 )
843 break;
846 /* p and fname are overlapping memory so copy out and back in again */
848 pstrcpy( unix_fname, p );
849 pstrcpy( fname, unix_fname );
851 return (snum < num_services) ? snum : -1;
854 /*******************************************************************
855 Note: topkeypaty is the *full* path that this *key will be
856 loaded into (including the name of the key)
857 ********************************************************************/
859 static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath,
860 REGF_NK_REC *key )
862 REGF_NK_REC *subkey;
863 REGISTRY_KEY registry_key;
864 REGVAL_CTR values;
865 REGSUBKEY_CTR subkeys;
866 int i;
867 pstring path;
868 WERROR result = WERR_OK;
870 /* initialize the REGISTRY_KEY structure */
872 if ( !(registry_key.hook = reghook_cache_find(topkeypath)) ) {
873 DEBUG(0,("reg_load_tree: Failed to assigned a REGISTRY_HOOK to [%s]\n",
874 topkeypath ));
875 return WERR_BADFILE;
877 pstrcpy( registry_key.name, topkeypath );
879 /* now start parsing the values and subkeys */
881 regsubkey_ctr_init( &subkeys );
882 regval_ctr_init( &values );
884 /* copy values into the REGVAL_CTR */
886 for ( i=0; i<key->num_values; i++ ) {
887 regval_ctr_addvalue( &values, key->values[i].valuename, key->values[i].type,
888 key->values[i].data, (key->values[i].data_size & ~VK_DATA_IN_OFFSET) );
891 /* copy subkeys into the REGSUBKEY_CTR */
893 key->subkey_index = 0;
894 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
895 regsubkey_ctr_addkey( &subkeys, subkey->keyname );
898 /* write this key and values out */
900 if ( !store_reg_values( &registry_key, &values )
901 || !store_reg_keys( &registry_key, &subkeys ) )
903 DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
904 result = WERR_REG_IO_FAILURE;
907 regval_ctr_destroy( &values );
908 regsubkey_ctr_destroy( &subkeys );
910 if ( !W_ERROR_IS_OK(result) )
911 return result;
913 /* now continue to load each subkey registry tree */
915 key->subkey_index = 0;
916 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
917 pstr_sprintf( path, "%s%s%s", topkeypath, "\\", subkey->keyname );
918 result = reg_load_tree( regfile, path, subkey );
919 if ( !W_ERROR_IS_OK(result) )
920 break;
923 return result;
926 /*******************************************************************
927 ********************************************************************/
929 static WERROR restore_registry_key ( REGISTRY_KEY *krecord, const char *fname )
931 REGF_FILE *regfile;
932 REGF_NK_REC *rootkey;
933 WERROR result;
935 /* open the registry file....fail if the file already exists */
937 if ( !(regfile = regfio_open( fname, (O_RDONLY), 0 )) ) {
938 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
939 fname, strerror(errno) ));
940 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
943 /* get the rootkey from the regf file and then load the tree
944 via recursive calls */
946 if ( !(rootkey = regfio_rootkey( regfile )) )
947 return WERR_REG_FILE_INVALID;
949 result = reg_load_tree( regfile, krecord->name, rootkey );
951 /* cleanup */
953 regfio_close( regfile );
955 return result;
958 /*******************************************************************
959 ********************************************************************/
961 WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY *q_u, REG_R_RESTORE_KEY *r_u)
963 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
964 pstring filename;
965 int snum;
967 DEBUG(5,("_reg_restore_key: Enter\n"));
969 if ( !regkey )
970 return WERR_BADFID;
972 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
974 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
976 if ( (snum = validate_reg_filename( filename )) == -1 )
977 return WERR_OBJECT_PATH_INVALID;
979 /* user must posses SeRestorePrivilege for this this proceed */
981 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
982 return WERR_ACCESS_DENIED;
984 DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
986 return restore_registry_key( regkey, filename );
989 /********************************************************************
990 ********************************************************************/
992 static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath,
993 REGF_NK_REC *parent, SEC_DESC *sec_desc )
995 REGF_NK_REC *key;
996 REGVAL_CTR values;
997 REGSUBKEY_CTR subkeys;
998 int i, num_subkeys;
999 pstring key_tmp;
1000 char *keyname, *parentpath;
1001 pstring subkeypath;
1002 char *subkeyname;
1003 REGISTRY_KEY registry_key;
1004 WERROR result = WERR_OK;
1006 if ( !regfile )
1007 return WERR_GENERAL_FAILURE;
1009 if ( !keypath )
1010 return WERR_OBJECT_PATH_INVALID;
1012 /* split up the registry key path */
1014 pstrcpy( key_tmp, keypath );
1015 if ( !reg_split_key( key_tmp, &parentpath, &keyname ) )
1016 return WERR_OBJECT_PATH_INVALID;
1018 if ( !keyname )
1019 keyname = parentpath;
1021 /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
1023 ZERO_STRUCT( registry_key );
1024 pstrcpy( registry_key.name, keypath );
1025 if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) )
1026 return WERR_BADFILE;
1029 /* lookup the values and subkeys */
1031 regsubkey_ctr_init( &subkeys );
1032 regval_ctr_init( &values );
1034 fetch_reg_keys( &registry_key, &subkeys );
1035 fetch_reg_values( &registry_key, &values );
1037 /* write out this key */
1039 if ( !(key = regfio_write_key( regfile, keyname, &values, &subkeys, sec_desc, parent )) ) {
1040 result = WERR_CAN_NOT_COMPLETE;
1041 goto done;
1044 /* write each one of the subkeys out */
1046 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
1047 for ( i=0; i<num_subkeys; i++ ) {
1048 subkeyname = regsubkey_ctr_specific_key( &subkeys, i );
1049 pstr_sprintf( subkeypath, "%s\\%s", keypath, subkeyname );
1050 result = reg_write_tree( regfile, subkeypath, key, sec_desc );
1051 if ( !W_ERROR_IS_OK(result) )
1052 goto done;
1055 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath ));
1057 done:
1058 regval_ctr_destroy( &values );
1059 regsubkey_ctr_destroy( &subkeys );
1061 return result;
1064 /*******************************************************************
1065 ********************************************************************/
1067 static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
1069 DOM_SID adm_sid, owner_sid;
1070 SEC_ACE ace[2]; /* at most 2 entries */
1071 SEC_ACCESS mask;
1072 SEC_ACL *psa = NULL;
1073 uint32 sd_size;
1075 /* set the owner to BUILTIN\Administrator */
1077 sid_copy(&owner_sid, &global_sid_Builtin);
1078 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
1081 /* basic access for Everyone */
1083 init_sec_access(&mask, reg_map.generic_execute | reg_map.generic_read );
1084 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1086 /* add Full Access 'BUILTIN\Administrators' */
1088 init_sec_access(&mask, reg_map.generic_all);
1089 sid_copy(&adm_sid, &global_sid_Builtin);
1090 sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
1091 init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1093 /* create the security descriptor */
1095 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace)) == NULL)
1096 return WERR_NOMEM;
1098 if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &owner_sid, NULL, NULL, psa, &sd_size)) == NULL)
1099 return WERR_NOMEM;
1101 return WERR_OK;
1104 /*******************************************************************
1105 ********************************************************************/
1107 static WERROR backup_registry_key ( REGISTRY_KEY *krecord, const char *fname )
1109 REGF_FILE *regfile;
1110 WERROR result;
1111 SEC_DESC *sd = NULL;
1113 /* open the registry file....fail if the file already exists */
1115 if ( !(regfile = regfio_open( fname, (O_RDWR|O_CREAT|O_EXCL), (S_IREAD|S_IWRITE) )) ) {
1116 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
1117 fname, strerror(errno) ));
1118 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
1121 if ( !W_ERROR_IS_OK(result = make_default_reg_sd( regfile->mem_ctx, &sd )) ) {
1122 regfio_close( regfile );
1123 return result;
1126 /* write the registry tree to the file */
1128 result = reg_write_tree( regfile, krecord->name, NULL, sd );
1130 /* cleanup */
1132 regfio_close( regfile );
1134 return result;
1137 /*******************************************************************
1138 ********************************************************************/
1140 WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u)
1142 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
1143 pstring filename;
1144 int snum;
1146 DEBUG(5,("_reg_save_key: Enter\n"));
1148 if ( !regkey )
1149 return WERR_BADFID;
1151 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
1153 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
1155 if ( (snum = validate_reg_filename( filename )) == -1 )
1156 return WERR_OBJECT_PATH_INVALID;
1158 DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
1160 return backup_registry_key( regkey, filename );
1162 return WERR_OK;
1165 /*******************************************************************
1166 ********************************************************************/
1168 WERROR _reg_create_key(pipes_struct *p, REG_Q_CREATE_KEY *q_u, REG_R_CREATE_KEY *r_u)
1170 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1171 REGISTRY_KEY *newparent;
1172 POLICY_HND newparent_handle;
1173 REGSUBKEY_CTR subkeys;
1174 BOOL write_result;
1175 pstring name;
1176 WERROR result;
1178 if ( !parent )
1179 return WERR_BADFID;
1181 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1183 /* ok. Here's what we do. */
1185 if ( strrchr( name, '\\' ) ) {
1186 pstring newkeyname;
1187 char *ptr;
1188 uint32 access_granted;
1190 /* (1) check for enumerate rights on the parent handle. CLients can try
1191 create things like 'SOFTWARE\Samba' on the HKLM handle.
1192 (2) open the path to the child parent key if necessary */
1194 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1195 return WERR_ACCESS_DENIED;
1197 pstrcpy( newkeyname, name );
1198 ptr = strrchr( newkeyname, '\\' );
1199 *ptr = '\0';
1201 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1202 if ( !W_ERROR_IS_OK(result) )
1203 return result;
1205 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1206 SMB_ASSERT( newparent != NULL );
1208 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1209 result = WERR_ACCESS_DENIED;
1210 goto done;
1213 newparent->access_granted = access_granted;
1215 /* copy the new key name (just the lower most keyname) */
1217 pstrcpy( name, ptr+1 );
1219 else {
1220 /* use the existing open key information */
1221 newparent = parent;
1222 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1225 /* (3) check for create subkey rights on the correct parent */
1227 if ( !(newparent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
1228 result = WERR_ACCESS_DENIED;
1229 goto done;
1232 regsubkey_ctr_init( &subkeys );
1234 /* (4) lookup the current keys and add the new one */
1236 fetch_reg_keys( newparent, &subkeys );
1237 regsubkey_ctr_addkey( &subkeys, name );
1239 /* now write to the registry backend */
1241 write_result = store_reg_keys( newparent, &subkeys );
1243 regsubkey_ctr_destroy( &subkeys );
1245 if ( !write_result )
1246 return WERR_REG_IO_FAILURE;
1248 /* (5) open the new key and return the handle. Note that it is probably
1249 not correct to grant full access on this open handle. We should pass
1250 the new open through the regkey_access_check() like we do for
1251 _reg_open_entry() but this is ok for now. */
1253 result = open_registry_key( p, &r_u->handle, newparent, name, REG_KEY_ALL );
1255 done:
1256 /* close any intermediate key handles */
1258 if ( newparent != parent )
1259 close_registry_key( p, &newparent_handle );
1261 return result;
1265 /*******************************************************************
1266 ********************************************************************/
1268 WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r_u)
1270 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1271 REGVAL_CTR values;
1272 BOOL write_result;
1274 if ( !key )
1275 return WERR_BADFID;
1277 /* access checks first */
1279 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1280 return WERR_ACCESS_DENIED;
1282 regval_ctr_init( &values );
1284 /* lookup the current values and add the new one */
1286 fetch_reg_values( key, &values );
1287 /* FIXME!!!! regval_ctr_addvalue( &values, .... ); */
1289 /* now write to the registry backend */
1291 write_result = store_reg_values( key, &values );
1293 regval_ctr_destroy( &values );
1295 if ( !write_result )
1296 return WERR_REG_IO_FAILURE;
1298 return WERR_OK;
1301 /*******************************************************************
1302 ********************************************************************/
1304 WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY *r_u)
1306 REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1307 REGISTRY_KEY *newparent;
1308 POLICY_HND newparent_handle;
1309 REGSUBKEY_CTR subkeys;
1310 BOOL write_result;
1311 pstring name;
1312 WERROR result;
1314 if ( !parent )
1315 return WERR_BADFID;
1317 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1319 /* ok. Here's what we do. */
1321 if ( strrchr( name, '\\' ) ) {
1322 pstring newkeyname;
1323 char *ptr;
1324 uint32 access_granted;
1326 /* (1) check for enumerate rights on the parent handle. CLients can try
1327 create things like 'SOFTWARE\Samba' on the HKLM handle.
1328 (2) open the path to the child parent key if necessary */
1330 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1331 return WERR_ACCESS_DENIED;
1333 pstrcpy( newkeyname, name );
1334 ptr = strrchr( newkeyname, '\\' );
1335 *ptr = '\0';
1337 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1338 if ( !W_ERROR_IS_OK(result) )
1339 return result;
1341 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1342 SMB_ASSERT( newparent != NULL );
1344 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1345 result = WERR_ACCESS_DENIED;
1346 goto done;
1349 newparent->access_granted = access_granted;
1351 /* copy the new key name (just the lower most keyname) */
1353 pstrcpy( name, ptr+1 );
1355 else {
1356 /* use the existing open key information */
1357 newparent = parent;
1358 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1361 /* (3) check for create subkey rights on the correct parent */
1363 if ( !(newparent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
1364 result = WERR_ACCESS_DENIED;
1365 goto done;
1368 regsubkey_ctr_init( &subkeys );
1370 /* lookup the current keys and delete the new one */
1372 fetch_reg_keys( newparent, &subkeys );
1374 regsubkey_ctr_delkey( &subkeys, name );
1376 /* now write to the registry backend */
1378 write_result = store_reg_keys( newparent, &subkeys );
1380 regsubkey_ctr_destroy( &subkeys );
1382 done:
1383 /* close any intermediate key handles */
1385 if ( newparent != parent )
1386 close_registry_key( p, &newparent_handle );
1388 /* rpc_reg.h says there is a POLICY_HDN in the reply...no idea if that is correct */
1390 return write_result ? WERR_OK : WERR_REG_IO_FAILURE;
1394 /*******************************************************************
1395 ********************************************************************/
1397 WERROR _reg_delete_value(pipes_struct *p, REG_Q_DELETE_VALUE *q_u, REG_R_DELETE_VALUE *r_u)
1399 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1400 REGVAL_CTR values;
1401 BOOL write_result;
1403 if ( !key )
1404 return WERR_BADFID;
1406 /* access checks first */
1408 if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1409 return WERR_ACCESS_DENIED;
1411 regval_ctr_init( &values );
1413 /* lookup the current values and add the new one */
1415 fetch_reg_values( key, &values );
1416 /* FIXME!!!! regval_ctr_delval( &values, .... ); */
1418 /* now write to the registry backend */
1420 write_result = store_reg_values( key, &values );
1422 regval_ctr_destroy( &values );
1424 if ( !write_result )
1425 return WERR_REG_IO_FAILURE;
1427 return WERR_OK;