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. */
30 #define DBGC_CLASS DBGC_RPC_SRV
32 #define REGSTR_PRODUCTTYPE "ProductType"
33 #define REG_PT_WINNT "WinNT"
34 #define REG_PT_LANMANNT "LanmanNT"
35 #define REG_PT_SERVERNT "ServerNT"
37 #define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
38 ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
41 static REGISTRY_KEY
*regkeys_list
;
44 /******************************************************************
45 free() function for REGISTRY_KEY
46 *****************************************************************/
48 static void free_regkey_info(void *ptr
)
50 REGISTRY_KEY
*info
= (REGISTRY_KEY
*)ptr
;
52 DLIST_REMOVE(regkeys_list
, info
);
57 /******************************************************************
58 Find a registry key handle and return a REGISTRY_KEY
59 *****************************************************************/
61 static REGISTRY_KEY
*find_regkey_index_by_hnd(pipes_struct
*p
, POLICY_HND
*hnd
)
63 REGISTRY_KEY
*regkey
= NULL
;
65 if(!find_policy_by_hnd(p
,hnd
,(void **)®key
)) {
66 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
74 /*******************************************************************
75 Function for open a new registry handle and creating a handle
76 Note that P should be valid & hnd should already have space
78 When we open a key, we store the full path to the key as
79 HK[LM|U]\<key>\<key>\...
80 *******************************************************************/
82 static WERROR
open_registry_key(pipes_struct
*p
, POLICY_HND
*hnd
, REGISTRY_KEY
*parent
,
83 const char *subkeyname
, uint32 access_granted
)
85 REGISTRY_KEY
*regkey
= NULL
;
86 WERROR result
= WERR_OK
;
87 REGSUBKEY_CTR subkeys
;
91 DEBUG(7,("open_registry_key: name = [%s][%s]\n",
92 parent
? parent
->name
: "NULL", subkeyname
));
94 /* strip any trailing '\'s */
95 pstrcpy( subkeyname2
, subkeyname
);
96 subkey_len
= strlen ( subkeyname2
);
97 if ( subkey_len
&& subkeyname2
[subkey_len
-1] == '\\' )
98 subkeyname2
[subkey_len
-1] = '\0';
100 if ((regkey
=SMB_MALLOC_P(REGISTRY_KEY
)) == NULL
)
103 ZERO_STRUCTP( regkey
);
106 * very crazy, but regedit.exe on Win2k will attempt to call
107 * REG_OPEN_ENTRY with a keyname of "". We should return a new
108 * (second) handle here on the key->name. regedt32.exe does
109 * not do this stupidity. --jerry
113 pstrcpy( regkey
->name
, parent
->name
);
116 pstrcpy( regkey
->name
, "" );
118 pstrcat( regkey
->name
, parent
->name
);
119 pstrcat( regkey
->name
, "\\" );
121 pstrcat( regkey
->name
, subkeyname2
);
124 /* Look up the table of registry I/O operations */
126 if ( !(regkey
->hook
= reghook_cache_find( regkey
->name
)) ) {
127 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
132 /* check if the path really exists; failed is indicated by -1 */
133 /* if the subkey count failed, bail out */
135 ZERO_STRUCTP( &subkeys
);
137 regsubkey_ctr_init( &subkeys
);
139 if ( fetch_reg_keys( regkey
, &subkeys
) == -1 ) {
141 /* don't really know what to return here */
142 result
= WERR_BADFILE
;
146 * This would previously return NT_STATUS_TOO_MANY_SECRETS
147 * that doesn't sound quite right to me --jerry
150 if ( !create_policy_hnd( p
, hnd
, free_regkey_info
, regkey
) )
151 result
= WERR_BADFILE
;
156 regsubkey_ctr_destroy( &subkeys
);
158 if ( ! NT_STATUS_IS_OK(result
) )
161 DLIST_ADD( regkeys_list
, regkey
);
164 DEBUG(7,("open_registry_key: exit\n"));
169 /*******************************************************************
170 Function for open a new registry handle and creating a handle
171 Note that P should be valid & hnd should already have space
172 *******************************************************************/
174 static BOOL
close_registry_key(pipes_struct
*p
, POLICY_HND
*hnd
)
176 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd(p
, hnd
);
179 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd
)));
183 close_policy_hnd(p
, hnd
);
188 /********************************************************************
189 retrieve information about the subkeys
190 *******************************************************************/
192 static BOOL
get_subkey_information( REGISTRY_KEY
*key
, uint32
*maxnum
, uint32
*maxlen
)
196 REGSUBKEY_CTR subkeys
;
202 ZERO_STRUCTP( &subkeys
);
204 regsubkey_ctr_init( &subkeys
);
206 if ( fetch_reg_keys( key
, &subkeys
) == -1 )
209 /* find the longest string */
212 num_subkeys
= regsubkey_ctr_numkeys( &subkeys
);
214 for ( i
=0; i
<num_subkeys
; i
++ ) {
215 len
= strlen( regsubkey_ctr_specific_key(&subkeys
, i
) );
216 max_len
= MAX(max_len
, len
);
219 *maxnum
= num_subkeys
;
222 regsubkey_ctr_destroy( &subkeys
);
227 /********************************************************************
228 retrieve information about the values. We don't store values
229 here. The registry tdb is intended to be a frontend to oether
230 Samba tdb's (such as ntdrivers.tdb).
231 *******************************************************************/
233 static BOOL
get_value_information( REGISTRY_KEY
*key
, uint32
*maxnum
,
234 uint32
*maxlen
, uint32
*maxsize
)
238 uint32 sizemax
, lenmax
;
245 ZERO_STRUCTP( &values
);
247 regval_ctr_init( &values
);
249 if ( fetch_reg_values( key
, &values
) == -1 )
252 lenmax
= sizemax
= 0;
253 num_values
= regval_ctr_numvals( &values
);
255 val
= regval_ctr_specific_value( &values
, 0 );
257 for ( i
=0; i
<num_values
&& val
; i
++ )
259 lenmax
= MAX(lenmax
, strlen(val
->valuename
)+1 );
260 sizemax
= MAX(sizemax
, val
->size
);
262 val
= regval_ctr_specific_value( &values
, i
);
265 *maxnum
= num_values
;
269 regval_ctr_destroy( &values
);
275 /********************************************************************
277 ********************************************************************/
279 WERROR
_reg_close(pipes_struct
*p
, REG_Q_CLOSE
*q_u
, REG_R_CLOSE
*r_u
)
281 /* set up the REG unknown_1 response */
282 ZERO_STRUCT(r_u
->pol
);
284 /* close the policy handle */
285 if (!close_registry_key(p
, &q_u
->pol
))
286 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
291 /*******************************************************************
292 ********************************************************************/
294 WERROR
_reg_open_hklm(pipes_struct
*p
, REG_Q_OPEN_HIVE
*q_u
, REG_R_OPEN_HIVE
*r_u
)
296 return open_registry_key( p
, &r_u
->pol
, NULL
, KEY_HKLM
, 0x0 );
299 /*******************************************************************
300 ********************************************************************/
302 WERROR
_reg_open_hkcr(pipes_struct
*p
, REG_Q_OPEN_HIVE
*q_u
, REG_R_OPEN_HIVE
*r_u
)
304 return open_registry_key( p
, &r_u
->pol
, NULL
, KEY_HKCR
, 0x0 );
307 /*******************************************************************
308 ********************************************************************/
310 WERROR
_reg_open_hku(pipes_struct
*p
, REG_Q_OPEN_HIVE
*q_u
, REG_R_OPEN_HIVE
*r_u
)
312 return open_registry_key( p
, &r_u
->pol
, NULL
, KEY_HKU
, 0x0 );
315 /*******************************************************************
317 ********************************************************************/
319 WERROR
_reg_open_entry(pipes_struct
*p
, REG_Q_OPEN_ENTRY
*q_u
, REG_R_OPEN_ENTRY
*r_u
)
323 REGISTRY_KEY
*key
= find_regkey_index_by_hnd(p
, &q_u
->pol
);
326 DEBUG(5,("reg_open_entry: Enter\n"));
329 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
331 rpcstr_pull( name
, q_u
->name
.string
->buffer
, sizeof(name
), q_u
->name
.string
->uni_str_len
*2, 0 );
333 result
= open_registry_key( p
, &pol
, key
, name
, 0x0 );
335 init_reg_r_open_entry( r_u
, &pol
, result
);
337 DEBUG(5,("reg_open_entry: Exit\n"));
342 /*******************************************************************
344 ********************************************************************/
346 WERROR
_reg_info(pipes_struct
*p
, REG_Q_INFO
*q_u
, REG_R_INFO
*r_u
)
348 WERROR status
= WERR_BADFILE
;
350 const char *value_ascii
= "";
353 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
354 REGISTRY_VALUE
*val
= NULL
;
358 DEBUG(5,("_reg_info: Enter\n"));
361 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
363 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey
->name
));
365 rpcstr_pull(name
, q_u
->name
.string
->buffer
, sizeof(name
), q_u
->name
.string
->uni_str_len
*2, 0);
367 DEBUG(5,("reg_info: looking up value: [%s]\n", name
));
369 ZERO_STRUCTP( ®vals
);
371 regval_ctr_init( ®vals
);
373 /* couple of hard coded registry values */
375 if ( strequal(name
, "RefusePasswordChange") ) {
378 if ( (val
= SMB_MALLOC_P(REGISTRY_VALUE
)) == NULL
) {
379 DEBUG(0,("_reg_info: malloc() failed!\n"));
383 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE
, &dwValue
))
385 regval_ctr_addvalue(®vals
, "RefusePasswordChange",
387 (const char*)&dwValue
, sizeof(dwValue
));
388 val
= dup_registry_value(
389 regval_ctr_specific_value( ®vals
, 0 ) );
396 if ( strequal(name
, REGSTR_PRODUCTTYPE
) ) {
397 /* This makes the server look like a member server to clients */
398 /* which tells clients that we have our own local user and */
399 /* group databases and helps with ACL support. */
401 switch (lp_server_role()) {
402 case ROLE_DOMAIN_PDC
:
403 case ROLE_DOMAIN_BDC
:
404 value_ascii
= REG_PT_LANMANNT
;
406 case ROLE_STANDALONE
:
407 value_ascii
= REG_PT_SERVERNT
;
409 case ROLE_DOMAIN_MEMBER
:
410 value_ascii
= REG_PT_WINNT
;
413 value_length
= push_ucs2(value
, value
, value_ascii
,
415 STR_TERMINATE
|STR_NOALIGN
);
416 regval_ctr_addvalue(®vals
, REGSTR_PRODUCTTYPE
, REG_SZ
,
417 value
, value_length
);
419 val
= dup_registry_value( regval_ctr_specific_value( ®vals
, 0 ) );
426 /* else fall back to actually looking up the value */
428 for ( i
=0; fetch_reg_values_specific(regkey
, &val
, i
); i
++ )
430 DEBUG(10,("_reg_info: Testing value [%s]\n", val
->valuename
));
431 if ( StrCaseCmp( val
->valuename
, name
) == 0 ) {
432 DEBUG(10,("_reg_info: Found match for value [%s]\n", name
));
437 free_registry_value( val
);
442 init_reg_r_info(q_u
->ptr_buf
, r_u
, val
, status
);
444 regval_ctr_destroy( ®vals
);
445 free_registry_value( val
);
447 DEBUG(5,("_reg_info: Exit\n"));
453 /*****************************************************************************
454 Implementation of REG_QUERY_KEY
455 ****************************************************************************/
457 WERROR
_reg_query_key(pipes_struct
*p
, REG_Q_QUERY_KEY
*q_u
, REG_R_QUERY_KEY
*r_u
)
459 WERROR status
= WERR_OK
;
460 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
462 DEBUG(5,("_reg_query_key: Enter\n"));
465 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
467 if ( !get_subkey_information( regkey
, &r_u
->num_subkeys
, &r_u
->max_subkeylen
) )
468 return WERR_ACCESS_DENIED
;
470 if ( !get_value_information( regkey
, &r_u
->num_values
, &r_u
->max_valnamelen
, &r_u
->max_valbufsize
) )
471 return WERR_ACCESS_DENIED
;
474 r_u
->sec_desc
= 0x00000078; /* size for key's sec_desc */
476 /* Win9x set this to 0x0 since it does not keep timestamps.
477 Doing the same here for simplicity --jerry */
479 ZERO_STRUCT(r_u
->mod_time
);
481 DEBUG(5,("_reg_query_key: Exit\n"));
487 /*****************************************************************************
488 Implementation of REG_GETVERSION
489 ****************************************************************************/
491 WERROR
_reg_getversion(pipes_struct
*p
, REG_Q_GETVERSION
*q_u
, REG_R_GETVERSION
*r_u
)
493 WERROR status
= WERR_OK
;
494 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
496 DEBUG(5,("_reg_getversion: Enter\n"));
499 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
501 r_u
->unknown
= 0x00000005; /* seems to be consistent...no idea what it means */
503 DEBUG(5,("_reg_getversion: Exit\n"));
509 /*****************************************************************************
510 Implementation of REG_ENUM_KEY
511 ****************************************************************************/
513 WERROR
_reg_enum_key(pipes_struct
*p
, REG_Q_ENUM_KEY
*q_u
, REG_R_ENUM_KEY
*r_u
)
515 WERROR status
= WERR_OK
;
516 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
520 DEBUG(5,("_reg_enum_key: Enter\n"));
523 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
525 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey
->name
));
527 if ( !fetch_reg_keys_specific( regkey
, &subkey
, q_u
->key_index
) )
529 status
= WERR_NO_MORE_ITEMS
;
533 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey
));
535 /* subkey has the string name now */
537 init_reg_r_enum_key( r_u
, subkey
, q_u
->unknown_1
, q_u
->unknown_2
);
539 DEBUG(5,("_reg_enum_key: Exit\n"));
546 /*****************************************************************************
547 Implementation of REG_ENUM_VALUE
548 ****************************************************************************/
550 WERROR
_reg_enum_value(pipes_struct
*p
, REG_Q_ENUM_VALUE
*q_u
, REG_R_ENUM_VALUE
*r_u
)
552 WERROR status
= WERR_OK
;
553 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
557 DEBUG(5,("_reg_enum_value: Enter\n"));
560 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
562 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey
->name
));
564 if ( !fetch_reg_values_specific( regkey
, &val
, q_u
->val_index
) ) {
565 status
= WERR_NO_MORE_ITEMS
;
569 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val
->valuename
));
571 /* subkey has the string name now */
573 init_reg_r_enum_val( r_u
, val
);
576 DEBUG(5,("_reg_enum_value: Exit\n"));
579 free_registry_value( val
);
585 /*******************************************************************
587 ********************************************************************/
589 WERROR
_reg_shutdown(pipes_struct
*p
, REG_Q_SHUTDOWN
*q_u
, REG_R_SHUTDOWN
*r_u
)
591 REG_Q_SHUTDOWN_EX q_u_ex
;
592 REG_R_SHUTDOWN_EX r_u_ex
;
594 /* copy fields (including stealing memory) */
596 q_u_ex
.server
= q_u
->server
;
597 q_u_ex
.message
= q_u
->message
;
598 q_u_ex
.timeout
= q_u
->timeout
;
599 q_u_ex
.force
= q_u
->force
;
600 q_u_ex
.reboot
= q_u
->reboot
;
601 q_u_ex
.reason
= 0x0; /* don't care for now */
603 /* thunk down to _reg_shutdown_ex() (just returns a status) */
605 return _reg_shutdown_ex( p
, &q_u_ex
, &r_u_ex
);
608 /*******************************************************************
610 ********************************************************************/
612 #define SHUTDOWN_R_STRING "-r"
613 #define SHUTDOWN_F_STRING "-f"
616 WERROR
_reg_shutdown_ex(pipes_struct
*p
, REG_Q_SHUTDOWN_EX
*q_u
, REG_R_SHUTDOWN_EX
*r_u
)
618 pstring shutdown_script
;
628 pstrcpy(shutdown_script
, lp_shutdown_script());
630 if ( !*shutdown_script
)
631 return WERR_ACCESS_DENIED
;
633 /* pull the message string and perform necessary sanity checks on it */
635 pstrcpy( message
, "" );
636 if ( q_u
->message
) {
637 UNISTR2
*msg_string
= q_u
->message
->string
;
639 rpcstr_pull( message
, msg_string
->buffer
, sizeof(message
), msg_string
->uni_str_len
*2, 0 );
641 alpha_strcpy (chkmsg
, message
, NULL
, sizeof(message
));
643 fstr_sprintf(timeout
, "%d", q_u
->timeout
);
644 fstr_sprintf(r
, (q_u
->reboot
) ? SHUTDOWN_R_STRING
: "");
645 fstr_sprintf(f
, (q_u
->force
) ? SHUTDOWN_F_STRING
: "");
646 fstr_sprintf( reason
, "%d", q_u
->reason
);
648 all_string_sub( shutdown_script
, "%z", chkmsg
, sizeof(shutdown_script
) );
649 all_string_sub( shutdown_script
, "%t", timeout
, sizeof(shutdown_script
) );
650 all_string_sub( shutdown_script
, "%r", r
, sizeof(shutdown_script
) );
651 all_string_sub( shutdown_script
, "%f", f
, sizeof(shutdown_script
) );
652 all_string_sub( shutdown_script
, "%x", reason
, sizeof(shutdown_script
) );
654 can_shutdown
= user_has_privileges( p
->pipe_user
.nt_user_token
, &se_remote_shutdown
);
656 /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
657 Take the error return from the script and provide it as the Windows return code. */
659 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
664 ret
= smbrun( shutdown_script
, NULL
);
669 /********** END SeRemoteShutdownPrivilege BLOCK **********/
671 DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
672 shutdown_script
, ret
));
675 return (ret
== 0) ? WERR_OK
: WERR_ACCESS_DENIED
;
681 /*******************************************************************
683 ********************************************************************/
685 WERROR
_reg_abort_shutdown(pipes_struct
*p
, REG_Q_ABORT_SHUTDOWN
*q_u
, REG_R_ABORT_SHUTDOWN
*r_u
)
687 pstring abort_shutdown_script
;
691 pstrcpy(abort_shutdown_script
, lp_abort_shutdown_script());
693 if ( !*abort_shutdown_script
)
694 return WERR_ACCESS_DENIED
;
696 can_shutdown
= user_has_privileges( p
->pipe_user
.nt_user_token
, &se_remote_shutdown
);
698 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
703 ret
= smbrun( abort_shutdown_script
, NULL
);
708 /********** END SeRemoteShutdownPrivilege BLOCK **********/
710 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
711 abort_shutdown_script
, ret
));
714 return (ret
== 0) ? WERR_OK
: WERR_ACCESS_DENIED
;
717 /*******************************************************************
718 ********************************************************************/
720 WERROR
_reg_restore_key(pipes_struct
*p
, REG_Q_RESTORE_KEY
*q_u
, REG_R_RESTORE_KEY
*r_u
)
722 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
725 DEBUG(5,("_reg_restore_key: Enter\n"));
728 * basically this is a no op function which just verifies
729 * that the client gave us a valid registry key handle
735 rpcstr_pull(filename
, q_u
->filename
.string
->buffer
, sizeof(filename
), q_u
->filename
.string
->uni_str_len
*2, STR_TERMINATE
);
737 DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey
->name
, filename
));
740 validate_reg_filemame( filename
);
741 return restore_registry_key( regkey
, filename
);
747 /*******************************************************************
748 ********************************************************************/
750 WERROR
_reg_save_key(pipes_struct
*p
, REG_Q_SAVE_KEY
*q_u
, REG_R_SAVE_KEY
*r_u
)
752 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
755 DEBUG(5,("_reg_save_key: Enter\n"));
758 * basically this is a no op function which just verifies
759 * that the client gave us a valid registry key handle
765 rpcstr_pull(filename
, q_u
->filename
.string
->buffer
, sizeof(filename
), q_u
->filename
.string
->uni_str_len
*2, STR_TERMINATE
);
767 DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey
->name
, filename
));
770 validate_reg_filemame( filename
);
771 return backup_registry_key( regkey
, filename
);