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.
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_HKLM
*q_u
, REG_R_OPEN_HKLM
*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_HKCR
*q_u
, REG_R_OPEN_HKCR
*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_HKU
*q_u
, REG_R_OPEN_HKU
*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
->uni_name
.buffer
,sizeof(name
),q_u
->uni_name
.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
->uni_type
.buffer
, sizeof(name
), q_u
->uni_type
.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 new_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_UNKNOWN_1A
489 ****************************************************************************/
491 WERROR
_reg_unknown_1a(pipes_struct
*p
, REG_Q_UNKNOWN_1A
*q_u
, REG_R_UNKNOWN_1A
*r_u
)
493 WERROR status
= WERR_OK
;
494 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
496 DEBUG(5,("_reg_unknown_1a: 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_unknown_1a: 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
) )
566 status
= WERR_NO_MORE_ITEMS
;
570 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val
->valuename
));
572 /* subkey has the string name now */
574 init_reg_r_enum_val( r_u
, val
);
577 DEBUG(5,("_reg_enum_value: Exit\n"));
580 free_registry_value( val
);
586 /*******************************************************************
588 ********************************************************************/
590 #define SHUTDOWN_R_STRING "-r"
591 #define SHUTDOWN_F_STRING "-f"
594 WERROR
_reg_shutdown(pipes_struct
*p
, REG_Q_SHUTDOWN
*q_u
, REG_R_SHUTDOWN
*r_u
)
596 WERROR status
= WERR_OK
;
597 pstring shutdown_script
;
598 UNISTR2 unimsg
= q_u
->uni_msg
;
606 rpcstr_pull (message
, unimsg
.buffer
, sizeof(message
), unimsg
.uni_str_len
*2,0);
608 alpha_strcpy (chkmsg
, message
, NULL
, sizeof(message
));
610 fstr_sprintf(timeout
, "%d", q_u
->timeout
);
612 fstr_sprintf(r
, (q_u
->reboot
) ? SHUTDOWN_R_STRING
: "");
614 fstr_sprintf(f
, (q_u
->force
) ? SHUTDOWN_F_STRING
: "");
616 pstrcpy(shutdown_script
, lp_shutdown_script());
618 if(*shutdown_script
) {
620 SE_PRIV se_shutdown
= SE_REMOTE_SHUTDOWN
;
623 can_shutdown
= user_has_privileges( p
->pipe_user
.nt_user_token
, &se_shutdown
);
625 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
628 all_string_sub(shutdown_script
, "%m", chkmsg
, sizeof(shutdown_script
));
629 all_string_sub(shutdown_script
, "%t", timeout
, sizeof(shutdown_script
));
630 all_string_sub(shutdown_script
, "%r", r
, sizeof(shutdown_script
));
631 all_string_sub(shutdown_script
, "%f", f
, sizeof(shutdown_script
));
632 shutdown_ret
= smbrun(shutdown_script
,NULL
);
633 DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script
,shutdown_ret
));
636 /********** END SeRemoteShutdownPrivilege BLOCK **********/
642 /*******************************************************************
644 ********************************************************************/
646 WERROR
_reg_abort_shutdown(pipes_struct
*p
, REG_Q_ABORT_SHUTDOWN
*q_u
, REG_R_ABORT_SHUTDOWN
*r_u
)
648 WERROR status
= WERR_OK
;
649 pstring abort_shutdown_script
;
651 pstrcpy(abort_shutdown_script
, lp_abort_shutdown_script());
653 if(*abort_shutdown_script
) {
654 int abort_shutdown_ret
;
655 SE_PRIV se_shutdown
= SE_REMOTE_SHUTDOWN
;
658 can_shutdown
= user_has_privileges( p
->pipe_user
.nt_user_token
, &se_shutdown
);
660 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
663 abort_shutdown_ret
= smbrun(abort_shutdown_script
,NULL
);
664 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script
,abort_shutdown_ret
));
667 /********** END SeRemoteShutdownPrivilege BLOCK **********/
674 /*******************************************************************
676 ********************************************************************/
678 WERROR
_reg_save_key(pipes_struct
*p
, REG_Q_SAVE_KEY
*q_u
, REG_R_SAVE_KEY
*r_u
)
680 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
682 DEBUG(5,("_reg_save_key: Enter\n"));
685 * basically this is a no op function which just gverifies
686 * that the client gave us a valid registry key handle
690 return WERR_BADFID
; /* This will be reported as an RPC fault anyway. */
692 DEBUG(8,("_reg_save_key: berifying backup of key [%s]\n", regkey
->name
));