r7647: add access checks to the top level hive open calls; will need to pass the...
[Samba/gbeck.git] / source / rpc_server / srv_reg_nt.c
blob01c60a473fad1354b67a89990ae228b73a5a210e
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 static 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 static SEC_DESC* construct_reg_hive_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 ZERO_STRUCTP( &subkeys );
184 regsubkey_ctr_init( &subkeys );
186 if ( fetch_reg_keys( regkey, &subkeys ) == -1 ) {
188 /* don't really know what to return here */
189 result = WERR_BADFILE;
191 else {
193 * This would previously return NT_STATUS_TOO_MANY_SECRETS
194 * that doesn't sound quite right to me --jerry
197 if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) )
198 result = WERR_BADFILE;
201 /* clean up */
203 regsubkey_ctr_destroy( &subkeys );
205 if ( ! NT_STATUS_IS_OK(result) )
206 SAFE_FREE( regkey );
208 DEBUG(7,("open_registry_key: exit\n"));
210 return result;
213 /*******************************************************************
214 Function for open a new registry handle and creating a handle
215 Note that P should be valid & hnd should already have space
216 *******************************************************************/
218 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
220 REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd);
222 if ( !regkey ) {
223 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
224 return False;
227 close_policy_hnd(p, hnd);
229 return True;
232 /********************************************************************
233 retrieve information about the subkeys
234 *******************************************************************/
236 static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen )
238 int num_subkeys, i;
239 uint32 max_len;
240 REGSUBKEY_CTR subkeys;
241 uint32 len;
243 if ( !key )
244 return False;
246 ZERO_STRUCTP( &subkeys );
248 regsubkey_ctr_init( &subkeys );
250 if ( fetch_reg_keys( key, &subkeys ) == -1 )
251 return False;
253 /* find the longest string */
255 max_len = 0;
256 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
258 for ( i=0; i<num_subkeys; i++ ) {
259 len = strlen( regsubkey_ctr_specific_key(&subkeys, i) );
260 max_len = MAX(max_len, len);
263 *maxnum = num_subkeys;
264 *maxlen = max_len*2;
266 regsubkey_ctr_destroy( &subkeys );
268 return True;
271 /********************************************************************
272 retrieve information about the values. We don't store values
273 here. The registry tdb is intended to be a frontend to oether
274 Samba tdb's (such as ntdrivers.tdb).
275 *******************************************************************/
277 static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum,
278 uint32 *maxlen, uint32 *maxsize )
280 REGVAL_CTR values;
281 REGISTRY_VALUE *val;
282 uint32 sizemax, lenmax;
283 int i, num_values;
285 if ( !key )
286 return False;
289 ZERO_STRUCTP( &values );
291 regval_ctr_init( &values );
293 if ( fetch_reg_values( key, &values ) == -1 )
294 return False;
296 lenmax = sizemax = 0;
297 num_values = regval_ctr_numvals( &values );
299 val = regval_ctr_specific_value( &values, 0 );
301 for ( i=0; i<num_values && val; i++ )
303 lenmax = MAX(lenmax, strlen(val->valuename)+1 );
304 sizemax = MAX(sizemax, val->size );
306 val = regval_ctr_specific_value( &values, i );
309 *maxnum = num_values;
310 *maxlen = lenmax;
311 *maxsize = sizemax;
313 regval_ctr_destroy( &values );
315 return True;
319 /********************************************************************
320 reg_close
321 ********************************************************************/
323 WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
325 /* set up the REG unknown_1 response */
326 ZERO_STRUCT(r_u->pol);
328 /* close the policy handle */
329 if (!close_registry_key(p, &q_u->pol))
330 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
332 return WERR_OK;
335 /*******************************************************************
336 ********************************************************************/
338 WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
340 SEC_DESC *sec_desc;
341 uint32 access_granted = 0;
342 NTSTATUS status;
344 /* perform access checks */
346 if ( !(sec_desc = construct_reg_hive_sd( p->mem_ctx )) )
347 return WERR_NOMEM;
349 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
350 if ( !NT_STATUS_IS_OK(status) )
351 return ntstatus_to_werror( status );
353 return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, access_granted );
356 /*******************************************************************
357 ********************************************************************/
359 WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
361 SEC_DESC *sec_desc;
362 uint32 access_granted = 0;
363 NTSTATUS status;
365 /* perform access checks */
367 if ( !(sec_desc = construct_reg_hive_sd( p->mem_ctx )) )
368 return WERR_NOMEM;
370 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
371 if ( !NT_STATUS_IS_OK(status) )
372 return ntstatus_to_werror( status );
374 return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, access_granted );
377 /*******************************************************************
378 ********************************************************************/
380 WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
382 SEC_DESC *sec_desc;
383 uint32 access_granted = 0;
384 NTSTATUS status;
386 /* perform access checks */
388 if ( !(sec_desc = construct_reg_hive_sd( p->mem_ctx )) )
389 return WERR_NOMEM;
391 status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
392 if ( !NT_STATUS_IS_OK(status) )
393 return ntstatus_to_werror( status );
395 return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, access_granted );
398 /*******************************************************************
399 reg_reply_open_entry
400 ********************************************************************/
402 WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
404 POLICY_HND pol;
405 fstring name;
406 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->pol);
407 WERROR result;
409 DEBUG(5,("reg_open_entry: Enter\n"));
411 if ( !key )
412 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
414 rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
416 result = open_registry_key( p, &pol, key, name, 0x0 );
418 init_reg_r_open_entry( r_u, &pol, result );
420 DEBUG(5,("reg_open_entry: Exit\n"));
422 return r_u->status;
425 /*******************************************************************
426 reg_reply_info
427 ********************************************************************/
429 WERROR _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u)
431 WERROR status = WERR_BADFILE;
432 fstring name;
433 const char *value_ascii = "";
434 fstring value;
435 int value_length;
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 DEBUG(5,("_reg_info: Enter\n"));
443 if ( !regkey )
444 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
446 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
448 rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
450 DEBUG(5,("reg_info: looking up value: [%s]\n", name));
452 ZERO_STRUCTP( &regvals );
454 regval_ctr_init( &regvals );
456 /* couple of hard coded registry values */
458 if ( strequal(name, "RefusePasswordChange") ) {
459 uint32 dwValue;
461 if ( (val = SMB_MALLOC_P(REGISTRY_VALUE)) == NULL ) {
462 DEBUG(0,("_reg_info: malloc() failed!\n"));
463 return WERR_NOMEM;
466 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue))
467 dwValue = 0;
468 regval_ctr_addvalue(&regvals, "RefusePasswordChange",
469 REG_DWORD,
470 (const char*)&dwValue, sizeof(dwValue));
471 val = dup_registry_value(
472 regval_ctr_specific_value( &regvals, 0 ) );
474 status = WERR_OK;
476 goto out;
479 if ( strequal(name, REGSTR_PRODUCTTYPE) ) {
480 /* This makes the server look like a member server to clients */
481 /* which tells clients that we have our own local user and */
482 /* group databases and helps with ACL support. */
484 switch (lp_server_role()) {
485 case ROLE_DOMAIN_PDC:
486 case ROLE_DOMAIN_BDC:
487 value_ascii = REG_PT_LANMANNT;
488 break;
489 case ROLE_STANDALONE:
490 value_ascii = REG_PT_SERVERNT;
491 break;
492 case ROLE_DOMAIN_MEMBER:
493 value_ascii = REG_PT_WINNT;
494 break;
496 value_length = push_ucs2(value, value, value_ascii,
497 sizeof(value),
498 STR_TERMINATE|STR_NOALIGN);
499 regval_ctr_addvalue(&regvals, REGSTR_PRODUCTTYPE, REG_SZ,
500 value, value_length);
502 val = dup_registry_value( regval_ctr_specific_value( &regvals, 0 ) );
504 status = WERR_OK;
506 goto out;
509 /* else fall back to actually looking up the value */
511 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
513 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
514 if ( StrCaseCmp( val->valuename, name ) == 0 ) {
515 DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
516 status = WERR_OK;
517 break;
520 free_registry_value( val );
524 out:
525 init_reg_r_info(q_u->ptr_buf, r_u, val, status);
527 regval_ctr_destroy( &regvals );
528 free_registry_value( val );
530 DEBUG(5,("_reg_info: Exit\n"));
532 return status;
536 /*****************************************************************************
537 Implementation of REG_QUERY_KEY
538 ****************************************************************************/
540 WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
542 WERROR status = WERR_OK;
543 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
545 DEBUG(5,("_reg_query_key: Enter\n"));
547 if ( !regkey )
548 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
550 if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) )
551 return WERR_ACCESS_DENIED;
553 if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) )
554 return WERR_ACCESS_DENIED;
557 r_u->sec_desc = 0x00000078; /* size for key's sec_desc */
559 /* Win9x set this to 0x0 since it does not keep timestamps.
560 Doing the same here for simplicity --jerry */
562 ZERO_STRUCT(r_u->mod_time);
564 DEBUG(5,("_reg_query_key: Exit\n"));
566 return status;
570 /*****************************************************************************
571 Implementation of REG_GETVERSION
572 ****************************************************************************/
574 WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u)
576 WERROR status = WERR_OK;
577 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
579 DEBUG(5,("_reg_getversion: Enter\n"));
581 if ( !regkey )
582 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
584 r_u->unknown = 0x00000005; /* seems to be consistent...no idea what it means */
586 DEBUG(5,("_reg_getversion: Exit\n"));
588 return status;
592 /*****************************************************************************
593 Implementation of REG_ENUM_KEY
594 ****************************************************************************/
596 WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
598 WERROR status = WERR_OK;
599 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
600 char *subkey = NULL;
603 DEBUG(5,("_reg_enum_key: Enter\n"));
605 if ( !regkey )
606 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
608 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
610 if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) )
612 status = WERR_NO_MORE_ITEMS;
613 goto done;
616 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
618 /* subkey has the string name now */
620 init_reg_r_enum_key( r_u, subkey );
622 DEBUG(5,("_reg_enum_key: Exit\n"));
624 done:
625 SAFE_FREE( subkey );
626 return status;
629 /*****************************************************************************
630 Implementation of REG_ENUM_VALUE
631 ****************************************************************************/
633 WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u)
635 WERROR status = WERR_OK;
636 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
637 REGISTRY_VALUE *val;
640 DEBUG(5,("_reg_enum_value: Enter\n"));
642 if ( !regkey )
643 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */
645 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey->name));
647 if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) {
648 status = WERR_NO_MORE_ITEMS;
649 goto done;
652 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val->valuename));
654 /* subkey has the string name now */
656 init_reg_r_enum_val( r_u, val );
659 DEBUG(5,("_reg_enum_value: Exit\n"));
661 done:
662 free_registry_value( val );
664 return status;
668 /*******************************************************************
669 reg_shutdwon
670 ********************************************************************/
672 WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
674 REG_Q_SHUTDOWN_EX q_u_ex;
675 REG_R_SHUTDOWN_EX r_u_ex;
677 /* copy fields (including stealing memory) */
679 q_u_ex.server = q_u->server;
680 q_u_ex.message = q_u->message;
681 q_u_ex.timeout = q_u->timeout;
682 q_u_ex.force = q_u->force;
683 q_u_ex.reboot = q_u->reboot;
684 q_u_ex.reason = 0x0; /* don't care for now */
686 /* thunk down to _reg_shutdown_ex() (just returns a status) */
688 return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex );
691 /*******************************************************************
692 reg_shutdown_ex
693 ********************************************************************/
695 #define SHUTDOWN_R_STRING "-r"
696 #define SHUTDOWN_F_STRING "-f"
699 WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u)
701 pstring shutdown_script;
702 pstring message;
703 pstring chkmsg;
704 fstring timeout;
705 fstring reason;
706 fstring r;
707 fstring f;
708 int ret;
709 BOOL can_shutdown;
712 pstrcpy(shutdown_script, lp_shutdown_script());
714 if ( !*shutdown_script )
715 return WERR_ACCESS_DENIED;
717 /* pull the message string and perform necessary sanity checks on it */
719 pstrcpy( message, "" );
720 if ( q_u->message ) {
721 UNISTR2 *msg_string = q_u->message->string;
723 rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 );
725 alpha_strcpy (chkmsg, message, NULL, sizeof(message));
727 fstr_sprintf(timeout, "%d", q_u->timeout);
728 fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : "");
729 fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : "");
730 fstr_sprintf( reason, "%d", q_u->reason );
732 all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
733 all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) );
734 all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
735 all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
736 all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) );
738 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
740 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
741 Take the error return from the script and provide it as the Windows return code. */
743 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
745 if ( can_shutdown )
746 become_root();
748 ret = smbrun( shutdown_script, NULL );
750 if ( can_shutdown )
751 unbecome_root();
753 /********** END SeRemoteShutdownPrivilege BLOCK **********/
755 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
756 shutdown_script, ret));
759 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
765 /*******************************************************************
766 reg_abort_shutdwon
767 ********************************************************************/
769 WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
771 pstring abort_shutdown_script;
772 int ret;
773 BOOL can_shutdown;
775 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
777 if ( !*abort_shutdown_script )
778 return WERR_ACCESS_DENIED;
780 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
782 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
784 if ( can_shutdown )
785 become_root();
787 ret = smbrun( abort_shutdown_script, NULL );
789 if ( can_shutdown )
790 unbecome_root();
792 /********** END SeRemoteShutdownPrivilege BLOCK **********/
794 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
795 abort_shutdown_script, ret));
798 return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
801 /*******************************************************************
802 ********************************************************************/
804 static int validate_reg_filename( pstring fname )
806 char *p;
807 int num_services = lp_numservices();
808 int snum;
809 pstring share_path;
810 pstring unix_fname;
812 /* convert to a unix path, stripping the C:\ along the way */
814 if ( !(p = valid_share_pathname( fname ) ))
815 return -1;
817 /* has to exist within a valid file share */
819 for ( snum=0; snum<num_services; snum++ ) {
821 if ( !lp_snum_ok(snum) || lp_print_ok(snum) )
822 continue;
824 pstrcpy( share_path, lp_pathname(snum) );
826 /* make sure we have a path (e.g. [homes] ) */
828 if ( strlen( share_path ) == 0 )
829 continue;
831 if ( strncmp( share_path, p, strlen( share_path )) == 0 )
832 break;
835 /* p and fname are overlapping memory so copy out and back in again */
837 pstrcpy( unix_fname, p );
838 pstrcpy( fname, unix_fname );
840 return (snum < num_services) ? snum : -1;
843 /*******************************************************************
844 Note: topkeypaty is the *full* path that this *key will be
845 loaded into (including the name of the key)
846 ********************************************************************/
848 static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath,
849 REGF_NK_REC *key )
851 REGF_NK_REC *subkey;
852 REGISTRY_KEY registry_key;
853 REGVAL_CTR values;
854 REGSUBKEY_CTR subkeys;
855 int i;
856 pstring path;
857 WERROR result = WERR_OK;
859 /* initialize the REGISTRY_KEY structure */
861 if ( !(registry_key.hook = reghook_cache_find(topkeypath)) ) {
862 DEBUG(0,("reg_load_tree: Failed to assigned a REGISTRY_HOOK to [%s]\n",
863 topkeypath ));
864 return WERR_BADFILE;
866 pstrcpy( registry_key.name, topkeypath );
868 /* now start parsing the values and subkeys */
870 ZERO_STRUCT( values );
871 ZERO_STRUCT( subkeys );
873 regsubkey_ctr_init( &subkeys );
874 regval_ctr_init( &values );
876 /* copy values into the REGVAL_CTR */
878 for ( i=0; i<key->num_values; i++ ) {
879 regval_ctr_addvalue( &values, key->values[i].valuename, key->values[i].type,
880 key->values[i].data, (key->values[i].data_size & ~VK_DATA_IN_OFFSET) );
883 /* copy subkeys into the REGSUBKEY_CTR */
885 key->subkey_index = 0;
886 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
887 regsubkey_ctr_addkey( &subkeys, subkey->keyname );
890 /* write this key and values out */
892 if ( !store_reg_values( &registry_key, &values )
893 || !store_reg_keys( &registry_key, &subkeys ) )
895 DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
896 result = WERR_REG_IO_FAILURE;
899 regval_ctr_destroy( &values );
900 regsubkey_ctr_destroy( &subkeys );
902 if ( !W_ERROR_IS_OK(result) )
903 return result;
905 /* now continue to load each subkey registry tree */
907 key->subkey_index = 0;
908 while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
909 pstr_sprintf( path, "%s%s%s", topkeypath, "\\", subkey->keyname );
910 result = reg_load_tree( regfile, path, subkey );
911 if ( !W_ERROR_IS_OK(result) )
912 break;
915 return result;
918 /*******************************************************************
919 ********************************************************************/
921 static WERROR restore_registry_key ( REGISTRY_KEY *krecord, const char *fname )
923 REGF_FILE *regfile;
924 REGF_NK_REC *rootkey;
925 WERROR result;
927 /* open the registry file....fail if the file already exists */
929 if ( !(regfile = regfio_open( fname, (O_RDONLY), 0 )) ) {
930 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
931 fname, strerror(errno) ));
932 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
935 /* get the rootkey from the regf file and then load the tree
936 via recursive calls */
938 if ( !(rootkey = regfio_rootkey( regfile )) )
939 return WERR_REG_FILE_INVALID;
941 result = reg_load_tree( regfile, krecord->name, rootkey );
943 /* cleanup */
945 regfio_close( regfile );
947 return result;
950 /*******************************************************************
951 ********************************************************************/
953 WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY *q_u, REG_R_RESTORE_KEY *r_u)
955 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
956 pstring filename;
957 int snum;
959 DEBUG(5,("_reg_restore_key: Enter\n"));
961 if ( !regkey )
962 return WERR_BADFID;
964 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
966 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
968 if ( (snum = validate_reg_filename( filename )) == -1 )
969 return WERR_OBJECT_PATH_INVALID;
971 /* user must posses SeRestorePrivilege for this this proceed */
973 if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
974 return WERR_ACCESS_DENIED;
976 DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
978 return restore_registry_key( regkey, filename );
981 /********************************************************************
982 ********************************************************************/
984 static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath,
985 REGF_NK_REC *parent, SEC_DESC *sec_desc )
987 REGF_NK_REC *key;
988 REGVAL_CTR values;
989 REGSUBKEY_CTR subkeys;
990 int i, num_subkeys;
991 pstring key_tmp;
992 char *keyname, *parentpath;
993 pstring subkeypath;
994 char *subkeyname;
995 REGISTRY_KEY registry_key;
996 WERROR result = WERR_OK;
998 if ( !regfile )
999 return WERR_GENERAL_FAILURE;
1001 if ( !keypath )
1002 return WERR_OBJECT_PATH_INVALID;
1004 /* split up the registry key path */
1006 pstrcpy( key_tmp, keypath );
1007 if ( !reg_split_key( key_tmp, &parentpath, &keyname ) )
1008 return WERR_OBJECT_PATH_INVALID;
1010 if ( !keyname )
1011 keyname = parentpath;
1013 /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
1015 ZERO_STRUCT( registry_key );
1016 pstrcpy( registry_key.name, keypath );
1017 if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) )
1018 return WERR_BADFILE;
1021 /* lookup the values and subkeys */
1023 ZERO_STRUCT( values );
1024 ZERO_STRUCT( subkeys );
1026 regsubkey_ctr_init( &subkeys );
1027 regval_ctr_init( &values );
1029 fetch_reg_keys( &registry_key, &subkeys );
1030 fetch_reg_values( &registry_key, &values );
1032 /* write out this key */
1034 if ( !(key = regfio_write_key( regfile, keyname, &values, &subkeys, sec_desc, parent )) ) {
1035 result = WERR_CAN_NOT_COMPLETE;
1036 goto done;
1039 /* write each one of the subkeys out */
1041 num_subkeys = regsubkey_ctr_numkeys( &subkeys );
1042 for ( i=0; i<num_subkeys; i++ ) {
1043 subkeyname = regsubkey_ctr_specific_key( &subkeys, i );
1044 pstr_sprintf( subkeypath, "%s\\%s", keypath, subkeyname );
1045 result = reg_write_tree( regfile, subkeypath, key, sec_desc );
1046 if ( !W_ERROR_IS_OK(result) )
1047 goto done;
1050 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath ));
1052 done:
1053 regval_ctr_destroy( &values );
1054 regsubkey_ctr_destroy( &subkeys );
1056 return result;
1059 /*******************************************************************
1060 ********************************************************************/
1062 static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
1064 DOM_SID adm_sid, owner_sid;
1065 SEC_ACE ace[2]; /* at most 2 entries */
1066 SEC_ACCESS mask;
1067 SEC_ACL *psa = NULL;
1068 uint32 sd_size;
1070 /* set the owner to BUILTIN\Administrator */
1072 sid_copy(&owner_sid, &global_sid_Builtin);
1073 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
1076 /* basic access for Everyone */
1078 init_sec_access(&mask, reg_map.generic_execute | reg_map.generic_read );
1079 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1081 /* add Full Access 'BUILTIN\Administrators' */
1083 init_sec_access(&mask, reg_map.generic_all);
1084 sid_copy(&adm_sid, &global_sid_Builtin);
1085 sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
1086 init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1088 /* create the security descriptor */
1090 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace)) == NULL)
1091 return WERR_NOMEM;
1093 if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &owner_sid, NULL, NULL, psa, &sd_size)) == NULL)
1094 return WERR_NOMEM;
1096 return WERR_OK;
1099 /*******************************************************************
1100 ********************************************************************/
1102 static WERROR backup_registry_key ( REGISTRY_KEY *krecord, const char *fname )
1104 REGF_FILE *regfile;
1105 WERROR result;
1106 SEC_DESC *sd = NULL;
1108 /* open the registry file....fail if the file already exists */
1110 if ( !(regfile = regfio_open( fname, (O_RDWR|O_CREAT|O_EXCL), (S_IREAD|S_IWRITE) )) ) {
1111 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
1112 fname, strerror(errno) ));
1113 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
1116 if ( !W_ERROR_IS_OK(result = make_default_reg_sd( regfile->mem_ctx, &sd )) ) {
1117 regfio_close( regfile );
1118 return result;
1121 /* write the registry tree to the file */
1123 result = reg_write_tree( regfile, krecord->name, NULL, sd );
1125 /* cleanup */
1127 regfio_close( regfile );
1129 return result;
1132 /*******************************************************************
1133 ********************************************************************/
1135 WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u)
1137 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
1138 pstring filename;
1139 int snum;
1141 DEBUG(5,("_reg_save_key: Enter\n"));
1143 if ( !regkey )
1144 return WERR_BADFID;
1146 rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
1148 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
1150 if ( (snum = validate_reg_filename( filename )) == -1 )
1151 return WERR_OBJECT_PATH_INVALID;
1153 DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
1155 return backup_registry_key( regkey, filename );
1157 return WERR_OK;
1160 /*******************************************************************
1161 ********************************************************************/
1163 WERROR _reg_create_key(pipes_struct *p, REG_Q_CREATE_KEY *q_u, REG_R_CREATE_KEY *r_u)
1165 return WERR_ACCESS_DENIED;
1169 /*******************************************************************
1170 ********************************************************************/
1172 WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r_u)
1174 return WERR_ACCESS_DENIED;