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 static 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 static SEC_DESC
* construct_reg_hive_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 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
;
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
;
203 regsubkey_ctr_destroy( &subkeys
);
205 if ( ! NT_STATUS_IS_OK(result
) )
208 DEBUG(7,("open_registry_key: exit\n"));
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
);
223 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd
)));
227 close_policy_hnd(p
, hnd
);
232 /********************************************************************
233 retrieve information about the subkeys
234 *******************************************************************/
236 static BOOL
get_subkey_information( REGISTRY_KEY
*key
, uint32
*maxnum
, uint32
*maxlen
)
240 REGSUBKEY_CTR subkeys
;
246 ZERO_STRUCTP( &subkeys
);
248 regsubkey_ctr_init( &subkeys
);
250 if ( fetch_reg_keys( key
, &subkeys
) == -1 )
253 /* find the longest string */
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
;
266 regsubkey_ctr_destroy( &subkeys
);
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
)
282 uint32 sizemax
, lenmax
;
289 ZERO_STRUCTP( &values
);
291 regval_ctr_init( &values
);
293 if ( fetch_reg_values( key
, &values
) == -1 )
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
;
313 regval_ctr_destroy( &values
);
319 /********************************************************************
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. */
335 /*******************************************************************
336 ********************************************************************/
338 WERROR
_reg_open_hklm(pipes_struct
*p
, REG_Q_OPEN_HIVE
*q_u
, REG_R_OPEN_HIVE
*r_u
)
341 uint32 access_granted
= 0;
344 /* perform access checks */
346 if ( !(sec_desc
= construct_reg_hive_sd( p
->mem_ctx
)) )
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
)
362 uint32 access_granted
= 0;
365 /* perform access checks */
367 if ( !(sec_desc
= construct_reg_hive_sd( p
->mem_ctx
)) )
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
)
383 uint32 access_granted
= 0;
386 /* perform access checks */
388 if ( !(sec_desc
= construct_reg_hive_sd( p
->mem_ctx
)) )
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 /*******************************************************************
400 ********************************************************************/
402 WERROR
_reg_open_entry(pipes_struct
*p
, REG_Q_OPEN_ENTRY
*q_u
, REG_R_OPEN_ENTRY
*r_u
)
406 REGISTRY_KEY
*key
= find_regkey_index_by_hnd(p
, &q_u
->pol
);
409 DEBUG(5,("reg_open_entry: Enter\n"));
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"));
425 /*******************************************************************
427 ********************************************************************/
429 WERROR
_reg_info(pipes_struct
*p
, REG_Q_INFO
*q_u
, REG_R_INFO
*r_u
)
431 WERROR status
= WERR_BADFILE
;
433 const char *value_ascii
= "";
436 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
437 REGISTRY_VALUE
*val
= NULL
;
441 DEBUG(5,("_reg_info: Enter\n"));
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( ®vals
);
454 regval_ctr_init( ®vals
);
456 /* couple of hard coded registry values */
458 if ( strequal(name
, "RefusePasswordChange") ) {
461 if ( (val
= SMB_MALLOC_P(REGISTRY_VALUE
)) == NULL
) {
462 DEBUG(0,("_reg_info: malloc() failed!\n"));
466 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE
, &dwValue
))
468 regval_ctr_addvalue(®vals
, "RefusePasswordChange",
470 (const char*)&dwValue
, sizeof(dwValue
));
471 val
= dup_registry_value(
472 regval_ctr_specific_value( ®vals
, 0 ) );
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
;
489 case ROLE_STANDALONE
:
490 value_ascii
= REG_PT_SERVERNT
;
492 case ROLE_DOMAIN_MEMBER
:
493 value_ascii
= REG_PT_WINNT
;
496 value_length
= push_ucs2(value
, value
, value_ascii
,
498 STR_TERMINATE
|STR_NOALIGN
);
499 regval_ctr_addvalue(®vals
, REGSTR_PRODUCTTYPE
, REG_SZ
,
500 value
, value_length
);
502 val
= dup_registry_value( regval_ctr_specific_value( ®vals
, 0 ) );
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
));
520 free_registry_value( val
);
525 init_reg_r_info(q_u
->ptr_buf
, r_u
, val
, status
);
527 regval_ctr_destroy( ®vals
);
528 free_registry_value( val
);
530 DEBUG(5,("_reg_info: Exit\n"));
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"));
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"));
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"));
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"));
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
);
603 DEBUG(5,("_reg_enum_key: Enter\n"));
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
;
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"));
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
);
640 DEBUG(5,("_reg_enum_value: Enter\n"));
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
;
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"));
662 free_registry_value( val
);
668 /*******************************************************************
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 /*******************************************************************
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
;
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 **********/
748 ret
= smbrun( shutdown_script
, NULL
);
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 /*******************************************************************
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
;
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 **********/
787 ret
= smbrun( abort_shutdown_script
, NULL
);
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
)
807 int num_services
= lp_numservices();
812 /* convert to a unix path, stripping the C:\ along the way */
814 if ( !(p
= valid_share_pathname( fname
) ))
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
) )
824 pstrcpy( share_path
, lp_pathname(snum
) );
826 /* make sure we have a path (e.g. [homes] ) */
828 if ( strlen( share_path
) == 0 )
831 if ( strncmp( share_path
, p
, strlen( share_path
)) == 0 )
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
,
852 REGISTRY_KEY registry_key
;
854 REGSUBKEY_CTR subkeys
;
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",
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( ®istry_key
, &values
)
893 || !store_reg_keys( ®istry_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
) )
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
) )
918 /*******************************************************************
919 ********************************************************************/
921 static WERROR
restore_registry_key ( REGISTRY_KEY
*krecord
, const char *fname
)
924 REGF_NK_REC
*rootkey
;
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
);
945 regfio_close( regfile
);
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
);
959 DEBUG(5,("_reg_restore_key: Enter\n"));
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
)
989 REGSUBKEY_CTR subkeys
;
992 char *keyname
, *parentpath
;
995 REGISTRY_KEY registry_key
;
996 WERROR result
= WERR_OK
;
999 return WERR_GENERAL_FAILURE
;
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
;
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( ®istry_key
, &subkeys
);
1030 fetch_reg_values( ®istry_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
;
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
) )
1050 DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath
));
1053 regval_ctr_destroy( &values
);
1054 regsubkey_ctr_destroy( &subkeys
);
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 */
1067 SEC_ACL
*psa
= NULL
;
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
)
1093 if ((*psd
= make_sec_desc(ctx
, SEC_DESC_REVISION
, SEC_DESC_SELF_RELATIVE
, &owner_sid
, NULL
, NULL
, psa
, &sd_size
)) == NULL
)
1099 /*******************************************************************
1100 ********************************************************************/
1102 static WERROR
backup_registry_key ( REGISTRY_KEY
*krecord
, const char *fname
)
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
);
1121 /* write the registry tree to the file */
1123 result
= reg_write_tree( regfile
, krecord
->name
, NULL
, sd
);
1127 regfio_close( regfile
);
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
);
1141 DEBUG(5,("_reg_save_key: Enter\n"));
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
);
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
;