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 NTSTATUS
open_registry_key(pipes_struct
*p
, POLICY_HND
*hnd
, REGISTRY_KEY
*parent
,
83 char *subkeyname
, uint32 access_granted
)
85 REGISTRY_KEY
*regkey
= NULL
;
86 NTSTATUS result
= NT_STATUS_OK
;
87 REGSUBKEY_CTR subkeys
;
89 DEBUG(7,("open_registry_key: name = [%s][%s]\n",
90 parent
? parent
->name
: "NULL", subkeyname
));
92 if ((regkey
=(REGISTRY_KEY
*)malloc(sizeof(REGISTRY_KEY
))) == NULL
)
93 return NT_STATUS_NO_MEMORY
;
95 ZERO_STRUCTP( regkey
);
98 * very crazy, but regedit.exe on Win2k will attempt to call
99 * REG_OPEN_ENTRY with a keyname of "". We should return a new
100 * (second) handle here on the key->name. regedt32.exe does
101 * not do this stupidity. --jerry
104 if (!subkeyname
|| !*subkeyname
) {
105 pstrcpy( regkey
->name
, parent
->name
);
108 pstrcpy( regkey
->name
, "" );
110 pstrcat( regkey
->name
, parent
->name
);
111 pstrcat( regkey
->name
, "\\" );
113 pstrcat( regkey
->name
, subkeyname
);
116 /* Look up the table of registry I/O operations */
118 if ( !(regkey
->hook
= reghook_cache_find( regkey
->name
)) ) {
119 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
121 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
124 /* check if the path really exists; failed is indicated by -1 */
125 /* if the subkey count failed, bail out */
127 ZERO_STRUCTP( &subkeys
);
129 regsubkey_ctr_init( &subkeys
);
131 if ( fetch_reg_keys( regkey
, &subkeys
) == -1 ) {
133 /* don't really know what to return here */
135 result
= NT_STATUS_NO_SUCH_FILE
;
139 * This would previously return NT_STATUS_TOO_MANY_SECRETS
140 * that doesn't sound quite right to me --jerry
143 if ( !create_policy_hnd( p
, hnd
, free_regkey_info
, regkey
) )
144 result
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
149 regsubkey_ctr_destroy( &subkeys
);
151 if ( ! NT_STATUS_IS_OK(result
) )
154 DLIST_ADD( regkeys_list
, regkey
);
157 DEBUG(7,("open_registry_key: exit\n"));
162 /*******************************************************************
163 Function for open a new registry handle and creating a handle
164 Note that P should be valid & hnd should already have space
165 *******************************************************************/
167 static BOOL
close_registry_key(pipes_struct
*p
, POLICY_HND
*hnd
)
169 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd(p
, hnd
);
172 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd
)));
176 close_policy_hnd(p
, hnd
);
181 /********************************************************************
182 retrieve information about the subkeys
183 *******************************************************************/
185 static BOOL
get_subkey_information( REGISTRY_KEY
*key
, uint32
*maxnum
, uint32
*maxlen
)
189 REGSUBKEY_CTR subkeys
;
195 ZERO_STRUCTP( &subkeys
);
197 regsubkey_ctr_init( &subkeys
);
199 if ( fetch_reg_keys( key
, &subkeys
) == -1 )
202 /* find the longest string */
205 num_subkeys
= regsubkey_ctr_numkeys( &subkeys
);
207 for ( i
=0; i
<num_subkeys
; i
++ ) {
208 len
= strlen( regsubkey_ctr_specific_key(&subkeys
, i
) );
209 max_len
= MAX(max_len
, len
);
212 *maxnum
= num_subkeys
;
215 regsubkey_ctr_destroy( &subkeys
);
220 /********************************************************************
221 retrieve information about the values. We don't store values
222 here. The registry tdb is intended to be a frontend to oether
223 Samba tdb's (such as ntdrivers.tdb).
224 *******************************************************************/
226 static BOOL
get_value_information( REGISTRY_KEY
*key
, uint32
*maxnum
,
227 uint32
*maxlen
, uint32
*maxsize
)
231 uint32 sizemax
, lenmax
;
238 ZERO_STRUCTP( &values
);
240 regval_ctr_init( &values
);
242 if ( fetch_reg_values( key
, &values
) == -1 )
245 lenmax
= sizemax
= 0;
246 num_values
= regval_ctr_numvals( &values
);
248 val
= regval_ctr_specific_value( &values
, 0 );
250 for ( i
=0; i
<num_values
&& val
; i
++ )
252 lenmax
= MAX(lenmax
, strlen(val
->valuename
)+1 );
253 sizemax
= MAX(sizemax
, val
->size
);
255 val
= regval_ctr_specific_value( &values
, i
);
258 *maxnum
= num_values
;
262 regval_ctr_destroy( &values
);
268 /********************************************************************
270 ********************************************************************/
272 NTSTATUS
_reg_close(pipes_struct
*p
, REG_Q_CLOSE
*q_u
, REG_R_CLOSE
*r_u
)
274 /* set up the REG unknown_1 response */
275 ZERO_STRUCT(r_u
->pol
);
277 /* close the policy handle */
278 if (!close_registry_key(p
, &q_u
->pol
))
279 return NT_STATUS_OBJECT_NAME_INVALID
;
284 /*******************************************************************
285 ********************************************************************/
287 NTSTATUS
_reg_open_hklm(pipes_struct
*p
, REG_Q_OPEN_HKLM
*q_u
, REG_R_OPEN_HKLM
*r_u
)
289 return open_registry_key( p
, &r_u
->pol
, NULL
, KEY_HKLM
, 0x0 );
292 /*******************************************************************
293 ********************************************************************/
295 NTSTATUS
_reg_open_hkcr(pipes_struct
*p
, REG_Q_OPEN_HKCR
*q_u
, REG_R_OPEN_HKCR
*r_u
)
297 return open_registry_key( p
, &r_u
->pol
, NULL
, KEY_HKCR
, 0x0 );
300 /*******************************************************************
301 ********************************************************************/
303 NTSTATUS
_reg_open_hku(pipes_struct
*p
, REG_Q_OPEN_HKU
*q_u
, REG_R_OPEN_HKU
*r_u
)
305 return open_registry_key( p
, &r_u
->pol
, NULL
, KEY_HKU
, 0x0 );
308 /*******************************************************************
310 ********************************************************************/
312 NTSTATUS
_reg_open_entry(pipes_struct
*p
, REG_Q_OPEN_ENTRY
*q_u
, REG_R_OPEN_ENTRY
*r_u
)
316 REGISTRY_KEY
*key
= find_regkey_index_by_hnd(p
, &q_u
->pol
);
319 DEBUG(5,("reg_open_entry: Enter\n"));
322 return NT_STATUS_INVALID_HANDLE
;
324 rpcstr_pull(name
,q_u
->uni_name
.buffer
,sizeof(name
),q_u
->uni_name
.uni_str_len
*2,0);
326 DEBUG(5,("reg_open_entry: Enter\n"));
328 result
= open_registry_key( p
, &pol
, key
, name
, 0x0 );
330 init_reg_r_open_entry( r_u
, &pol
, result
);
332 DEBUG(5,("reg_open_entry: Exit\n"));
337 /*******************************************************************
339 ********************************************************************/
341 NTSTATUS
_reg_info(pipes_struct
*p
, REG_Q_INFO
*q_u
, REG_R_INFO
*r_u
)
343 NTSTATUS status
= NT_STATUS_NO_SUCH_FILE
;
345 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
346 REGISTRY_VALUE
*val
= NULL
;
347 REGISTRY_VALUE emptyval
;
351 DEBUG(5,("_reg_info: Enter\n"));
354 return NT_STATUS_INVALID_HANDLE
;
356 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey
->name
));
358 rpcstr_pull(name
, q_u
->uni_type
.buffer
, sizeof(name
), q_u
->uni_type
.uni_str_len
*2, 0);
360 DEBUG(5,("reg_info: looking up value: [%s]\n", name
));
362 ZERO_STRUCTP( ®vals
);
364 regval_ctr_init( ®vals
);
366 /* couple of hard coded registry values */
368 if ( strequal(name
, "RefusePasswordChange") ) {
369 ZERO_STRUCTP( &emptyval
);
375 if ( strequal(name
, REGSTR_PRODUCTTYPE
) ) {
376 /* This makes the server look like a member server to clients */
377 /* which tells clients that we have our own local user and */
378 /* group databases and helps with ACL support. */
380 switch (lp_server_role()) {
381 case ROLE_DOMAIN_PDC
:
382 case ROLE_DOMAIN_BDC
:
383 regval_ctr_addvalue( ®vals
, REGSTR_PRODUCTTYPE
, REG_SZ
, REG_PT_LANMANNT
, strlen(REG_PT_LANMANNT
)+1 );
385 case ROLE_STANDALONE
:
386 regval_ctr_addvalue( ®vals
, REGSTR_PRODUCTTYPE
, REG_SZ
, REG_PT_SERVERNT
, strlen(REG_PT_SERVERNT
)+1 );
388 case ROLE_DOMAIN_MEMBER
:
389 regval_ctr_addvalue( ®vals
, REGSTR_PRODUCTTYPE
, REG_SZ
, REG_PT_WINNT
, strlen(REG_PT_WINNT
)+1 );
393 val
= dup_registry_value( regval_ctr_specific_value( ®vals
, 0 ) );
395 status
= NT_STATUS_OK
;
400 /* else fall back to actually looking up the value */
402 for ( i
=0; fetch_reg_values_specific(regkey
, &val
, i
); i
++ )
404 DEBUG(10,("_reg_info: Testing value [%s]\n", val
->valuename
));
405 if ( StrCaseCmp( val
->valuename
, name
) == 0 ) {
406 DEBUG(10,("_reg_info: Found match for value [%s]\n", name
));
407 status
= NT_STATUS_OK
;
411 free_registry_value( val
);
416 new_init_reg_r_info(q_u
->ptr_buf
, r_u
, val
, status
);
418 regval_ctr_destroy( ®vals
);
419 free_registry_value( val
);
421 DEBUG(5,("_reg_info: Exit\n"));
427 /*****************************************************************************
428 Implementation of REG_QUERY_KEY
429 ****************************************************************************/
431 NTSTATUS
_reg_query_key(pipes_struct
*p
, REG_Q_QUERY_KEY
*q_u
, REG_R_QUERY_KEY
*r_u
)
433 NTSTATUS status
= NT_STATUS_OK
;
434 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
436 DEBUG(5,("_reg_query_key: Enter\n"));
439 return NT_STATUS_INVALID_HANDLE
;
441 if ( !get_subkey_information( regkey
, &r_u
->num_subkeys
, &r_u
->max_subkeylen
) )
442 return NT_STATUS_ACCESS_DENIED
;
444 if ( !get_value_information( regkey
, &r_u
->num_values
, &r_u
->max_valnamelen
, &r_u
->max_valbufsize
) )
445 return NT_STATUS_ACCESS_DENIED
;
448 r_u
->sec_desc
= 0x00000078; /* size for key's sec_desc */
450 /* Win9x set this to 0x0 since it does not keep timestamps.
451 Doing the same here for simplicity --jerry */
453 ZERO_STRUCT(r_u
->mod_time
);
455 DEBUG(5,("_reg_query_key: Exit\n"));
461 /*****************************************************************************
462 Implementation of REG_UNKNOWN_1A
463 ****************************************************************************/
465 NTSTATUS
_reg_unknown_1a(pipes_struct
*p
, REG_Q_UNKNOWN_1A
*q_u
, REG_R_UNKNOWN_1A
*r_u
)
467 NTSTATUS status
= NT_STATUS_OK
;
468 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
470 DEBUG(5,("_reg_unknown_1a: Enter\n"));
473 return NT_STATUS_INVALID_HANDLE
;
475 r_u
->unknown
= 0x00000005; /* seems to be consistent...no idea what it means */
477 DEBUG(5,("_reg_unknown_1a: Exit\n"));
483 /*****************************************************************************
484 Implementation of REG_ENUM_KEY
485 ****************************************************************************/
487 NTSTATUS
_reg_enum_key(pipes_struct
*p
, REG_Q_ENUM_KEY
*q_u
, REG_R_ENUM_KEY
*r_u
)
489 NTSTATUS status
= NT_STATUS_OK
;
490 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
494 DEBUG(5,("_reg_enum_key: Enter\n"));
497 return NT_STATUS_INVALID_HANDLE
;
499 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey
->name
));
501 if ( !fetch_reg_keys_specific( regkey
, &subkey
, q_u
->key_index
) )
503 status
= NT_STATUS_NO_MORE_ENTRIES
;
507 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey
));
509 /* subkey has the string name now */
511 init_reg_r_enum_key( r_u
, subkey
, q_u
->unknown_1
, q_u
->unknown_2
);
513 DEBUG(5,("_reg_enum_key: Exit\n"));
520 /*****************************************************************************
521 Implementation of REG_ENUM_VALUE
522 ****************************************************************************/
524 NTSTATUS
_reg_enum_value(pipes_struct
*p
, REG_Q_ENUM_VALUE
*q_u
, REG_R_ENUM_VALUE
*r_u
)
526 NTSTATUS status
= NT_STATUS_OK
;
527 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
531 DEBUG(5,("_reg_enum_value: Enter\n"));
534 return NT_STATUS_INVALID_HANDLE
;
536 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey
->name
));
538 if ( !fetch_reg_values_specific( regkey
, &val
, q_u
->val_index
) )
540 status
= NT_STATUS_NO_MORE_ENTRIES
;
544 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val
->valuename
));
546 /* subkey has the string name now */
548 init_reg_r_enum_val( r_u
, val
);
551 DEBUG(5,("_reg_enum_value: Exit\n"));
554 free_registry_value( val
);
560 /*******************************************************************
562 ********************************************************************/
564 #define SHUTDOWN_R_STRING "-r"
565 #define SHUTDOWN_F_STRING "-f"
568 NTSTATUS
_reg_shutdown(pipes_struct
*p
, REG_Q_SHUTDOWN
*q_u
, REG_R_SHUTDOWN
*r_u
)
570 NTSTATUS status
= NT_STATUS_OK
;
571 pstring shutdown_script
;
572 UNISTR2 unimsg
= q_u
->uni_msg
;
580 rpcstr_pull (message
, unimsg
.buffer
, sizeof(message
), unimsg
.uni_str_len
*2,0);
582 alpha_strcpy (chkmsg
, message
, NULL
, sizeof(message
));
584 snprintf(timeout
, sizeof(timeout
), "%d", q_u
->timeout
);
586 snprintf(r
, sizeof(r
), (q_u
->flags
& REG_REBOOT_ON_SHUTDOWN
)?SHUTDOWN_R_STRING
:"");
588 snprintf(f
, sizeof(f
), (q_u
->flags
& REG_FORCE_SHUTDOWN
)?SHUTDOWN_F_STRING
:"");
590 pstrcpy(shutdown_script
, lp_shutdown_script());
592 if(*shutdown_script
) {
594 all_string_sub(shutdown_script
, "%m", chkmsg
, sizeof(shutdown_script
));
595 all_string_sub(shutdown_script
, "%t", timeout
, sizeof(shutdown_script
));
596 all_string_sub(shutdown_script
, "%r", r
, sizeof(shutdown_script
));
597 all_string_sub(shutdown_script
, "%f", f
, sizeof(shutdown_script
));
598 shutdown_ret
= smbrun(shutdown_script
,NULL
);
599 DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script
,shutdown_ret
));
605 /*******************************************************************
607 ********************************************************************/
609 NTSTATUS
_reg_abort_shutdown(pipes_struct
*p
, REG_Q_ABORT_SHUTDOWN
*q_u
, REG_R_ABORT_SHUTDOWN
*r_u
)
611 NTSTATUS status
= NT_STATUS_OK
;
612 pstring abort_shutdown_script
;
614 pstrcpy(abort_shutdown_script
, lp_abort_shutdown_script());
616 if(*abort_shutdown_script
) {
617 int abort_shutdown_ret
;
618 abort_shutdown_ret
= smbrun(abort_shutdown_script
,NULL
);
619 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script
,abort_shutdown_ret
));
625 /*******************************************************************
627 ********************************************************************/
629 NTSTATUS
_reg_save_key(pipes_struct
*p
, REG_Q_SAVE_KEY
*q_u
, REG_R_SAVE_KEY
*r_u
)
631 REGISTRY_KEY
*regkey
= find_regkey_index_by_hnd( p
, &q_u
->pol
);
633 DEBUG(5,("_reg_save_key: Enter\n"));
636 * basically this is a no op function which just gverifies
637 * that the client gave us a valid registry key handle
641 return NT_STATUS_INVALID_HANDLE
;
643 DEBUG(8,("_reg_save_key: berifying backup of key [%s]\n", regkey
->name
));