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. */
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
)
54 se_access_check( sec_desc
, token
, access_desired
, access_granted
, &result
);
59 /********************************************************************
60 ********************************************************************/
62 SEC_DESC
* construct_registry_sd( TALLOC_CTX
*ctx
)
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
)) )
87 if ( !(sd
= make_sec_desc(ctx
, SEC_DESC_REVISION
, SEC_DESC_SELF_RELATIVE
, NULL
, NULL
, NULL
, acl
, &sd_size
)) )
93 /******************************************************************
94 free() function for REGISTRY_KEY
95 *****************************************************************/
97 static void free_regkey_info(void *ptr
)
99 REGISTRY_KEY
*info
= (REGISTRY_KEY
*)ptr
;
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 **)®key
)) {
113 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
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
;
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
)
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
160 pstrcpy( regkey
->name
, parent
->name
);
163 pstrcpy( regkey
->name
, "" );
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",
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
;
189 if ( !create_policy_hnd( p
, hnd
, free_regkey_info
, regkey
) ) {
190 result
= WERR_BADFILE
;
194 /* save the access mask */
196 regkey
->access_granted
= access_granted
;
201 regsubkey_ctr_destroy( &subkeys
);
203 if ( ! NT_STATUS_IS_OK(result
) )
206 DEBUG(7,("open_registry_key: exit\n"));
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
);
221 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd
)));
225 close_policy_hnd(p
, hnd
);
230 /********************************************************************
231 retrieve information about the subkeys
232 *******************************************************************/
234 static BOOL
get_subkey_information( REGISTRY_KEY
*key
, uint32
*maxnum
, uint32
*maxlen
)
238 REGSUBKEY_CTR subkeys
;
244 regsubkey_ctr_init( &subkeys
);
246 if ( fetch_reg_keys( key
, &subkeys
) == -1 )
249 /* find the longest string */
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
;
262 regsubkey_ctr_destroy( &subkeys
);
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
)
278 uint32 sizemax
, lenmax
;
284 regval_ctr_init( &values
);
286 if ( fetch_reg_values( key
, &values
) == -1 )
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
;
306 regval_ctr_destroy( &values
);
312 /********************************************************************
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
) )
326 /*******************************************************************
327 ********************************************************************/
329 WERROR
_reg_open_hklm(pipes_struct
*p
, REG_Q_OPEN_HIVE
*q_u
, REG_R_OPEN_HIVE
*r_u
)
332 uint32 access_granted
= 0;
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
)) )
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
)
354 uint32 access_granted
= 0;
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
)) )
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
)
376 uint32 access_granted
= 0;
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
)) )
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 /*******************************************************************
394 ********************************************************************/
396 WERROR
_reg_open_entry(pipes_struct
*p
, REG_Q_OPEN_ENTRY
*q_u
, REG_R_OPEN_ENTRY
*r_u
)
399 REGISTRY_KEY
*parent
= find_regkey_index_by_hnd(p
, &q_u
->pol
);
400 REGISTRY_KEY
*newkey
;
401 uint32 access_granted
;
404 DEBUG(5,("reg_open_entry: Enter\n"));
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 )) )
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
;
438 /*******************************************************************
440 ********************************************************************/
442 WERROR
_reg_info(pipes_struct
*p
, REG_Q_INFO
*q_u
, REG_R_INFO
*r_u
)
444 WERROR status
= WERR_BADFILE
;
446 const char *value_ascii
= "";
449 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
450 REGISTRY_VALUE
*val
= NULL
;
454 DEBUG(5,("_reg_info: Enter\n"));
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( ®vals
);
467 /* couple of hard coded registry values */
469 if ( strequal(name
, "RefusePasswordChange") ) {
472 if ( (val
= SMB_MALLOC_P(REGISTRY_VALUE
)) == NULL
) {
473 DEBUG(0,("_reg_info: malloc() failed!\n"));
477 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE
, &dwValue
))
479 regval_ctr_addvalue(®vals
, "RefusePasswordChange",
481 (const char*)&dwValue
, sizeof(dwValue
));
482 val
= dup_registry_value(
483 regval_ctr_specific_value( ®vals
, 0 ) );
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
;
500 case ROLE_STANDALONE
:
501 value_ascii
= REG_PT_SERVERNT
;
503 case ROLE_DOMAIN_MEMBER
:
504 value_ascii
= REG_PT_WINNT
;
507 value_length
= push_ucs2(value
, value
, value_ascii
,
509 STR_TERMINATE
|STR_NOALIGN
);
510 regval_ctr_addvalue(®vals
, REGSTR_PRODUCTTYPE
, REG_SZ
,
511 value
, value_length
);
513 val
= dup_registry_value( regval_ctr_specific_value( ®vals
, 0 ) );
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
));
531 free_registry_value( val
);
536 init_reg_r_info(q_u
->ptr_buf
, r_u
, val
, status
);
538 regval_ctr_destroy( ®vals
);
539 free_registry_value( val
);
541 DEBUG(5,("_reg_info: Exit\n"));
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"));
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"));
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"));
595 r_u
->win_version
= 0x00000005; /* Windows 2000 registry API version */
597 DEBUG(5,("_reg_getversion: Exit\n"));
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
);
614 DEBUG(5,("_reg_enum_key: Enter\n"));
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
;
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"));
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
);
651 DEBUG(5,("_reg_enum_value: Enter\n"));
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
;
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"));
673 free_registry_value( val
);
679 /*******************************************************************
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 /*******************************************************************
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
;
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 **********/
759 ret
= smbrun( shutdown_script
, NULL
);
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 /*******************************************************************
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
;
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 **********/
798 ret
= smbrun( abort_shutdown_script
, NULL
);
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
)
818 int num_services
= lp_numservices();
823 /* convert to a unix path, stripping the C:\ along the way */
825 if ( !(p
= valid_share_pathname( fname
) ))
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
) )
835 pstrcpy( share_path
, lp_pathname(snum
) );
837 /* make sure we have a path (e.g. [homes] ) */
839 if ( strlen( share_path
) == 0 )
842 if ( strncmp( share_path
, p
, strlen( share_path
)) == 0 )
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
,
863 REGISTRY_KEY registry_key
;
865 REGSUBKEY_CTR subkeys
;
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",
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( ®istry_key
, &values
)
901 || !store_reg_keys( ®istry_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
) )
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
) )
926 /*******************************************************************
927 ********************************************************************/
929 static WERROR
restore_registry_key ( REGISTRY_KEY
*krecord
, const char *fname
)
932 REGF_NK_REC
*rootkey
;
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
);
953 regfio_close( regfile
);
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
);
967 DEBUG(5,("_reg_restore_key: Enter\n"));
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
)
997 REGSUBKEY_CTR subkeys
;
1000 char *keyname
, *parentpath
;
1003 REGISTRY_KEY registry_key
;
1004 WERROR result
= WERR_OK
;
1007 return WERR_GENERAL_FAILURE
;
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
;
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( ®istry_key
, &subkeys
);
1035 fetch_reg_values( ®istry_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
;
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
) )
1055 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath
));
1058 regval_ctr_destroy( &values
);
1059 regsubkey_ctr_destroy( &subkeys
);
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 */
1072 SEC_ACL
*psa
= NULL
;
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
)
1098 if ((*psd
= make_sec_desc(ctx
, SEC_DESC_REVISION
, SEC_DESC_SELF_RELATIVE
, &owner_sid
, NULL
, NULL
, psa
, &sd_size
)) == NULL
)
1104 /*******************************************************************
1105 ********************************************************************/
1107 static WERROR
backup_registry_key ( REGISTRY_KEY
*krecord
, const char *fname
)
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
);
1126 /* write the registry tree to the file */
1128 result
= reg_write_tree( regfile
, krecord
->name
, NULL
, sd
);
1132 regfio_close( regfile
);
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
);
1146 DEBUG(5,("_reg_save_key: Enter\n"));
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
);
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
;
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
, '\\' ) ) {
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
, '\\' );
1201 result
= open_registry_key( p
, &newparent_handle
, parent
, newkeyname
, 0 );
1202 if ( !W_ERROR_IS_OK(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
;
1213 newparent
->access_granted
= access_granted
;
1215 /* copy the new key name (just the lower most keyname) */
1217 pstrcpy( name
, ptr
+1 );
1220 /* use the existing open key information */
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
;
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
);
1256 /* close any intermediate key handles */
1258 if ( newparent
!= parent
)
1259 close_registry_key( p
, &newparent_handle
);
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
);
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
;
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
;
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
, '\\' ) ) {
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
, '\\' );
1337 result
= open_registry_key( p
, &newparent_handle
, parent
, newkeyname
, 0 );
1338 if ( !W_ERROR_IS_OK(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
;
1349 newparent
->access_granted
= access_granted
;
1351 /* copy the new key name (just the lower most keyname) */
1353 pstrcpy( name
, ptr
+1 );
1356 /* use the existing open key information */
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
;
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
);
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
);
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
;