3 * Unix SMB/CIFS implementation.
4 * MS-RPC client internal functions
5 * Copyright (C) Chris Nicholls 2005.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libmsrpc_internal.h"
26 /*used to get a struct rpc_pipe_client* to be passed into rpccli* calls*/
27 struct rpc_pipe_client
*cac_GetPipe( CacServerHandle
* hnd
, int pi_idx
)
30 struct rpc_pipe_client
*pipe_hnd
= NULL
;
36 if ( hnd
->_internal
.pipes
[pi_idx
] == False
) {
37 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
41 srv
= cac_GetServer( hnd
);
43 hnd
->status
= NT_STATUS_INVALID_CONNECTION
;
47 pipe_hnd
= srv
->cli
->pipe_list
;
49 while ( pipe_hnd
!= NULL
&& pipe_hnd
->pipe_idx
!= pi_idx
) {
50 pipe_hnd
= pipe_hnd
->next
;
56 /*takes a string like HKEY_LOCAL_MACHINE\HARDWARE\ACPI and returns the reg_type code and then a pointer to the start of the path (HARDWARE)*/
57 int cac_ParseRegPath( char *path
, uint32
* reg_type
, char **key_name
)
63 if ( strncmp( path
, "HKLM", 4 ) == 0 ) {
64 *reg_type
= HKEY_LOCAL_MACHINE
;
65 *key_name
= ( path
[4] == '\\' ) ? path
+ 5 : NULL
;
66 } else if ( strncmp( path
, "HKEY_LOCAL_MACHINE", 18 ) == 0 ) {
67 *reg_type
= HKEY_LOCAL_MACHINE
;
68 *key_name
= ( path
[18] == '\\' ) ? path
+ 19 : NULL
;
69 } else if ( strncmp( path
, "HKCR", 4 ) == 0 ) {
70 *reg_type
= HKEY_CLASSES_ROOT
;
71 *key_name
= ( path
[4] == '\\' ) ? path
+ 5 : NULL
;
72 } else if ( strncmp( path
, "HKEY_CLASSES_ROOT", 17 ) == 0 ) {
73 *reg_type
= HKEY_CLASSES_ROOT
;
74 *key_name
= ( path
[17] == '\\' ) ? path
+ 18 : NULL
;
75 } else if ( strncmp( path
, "HKU", 3 ) == 0 ) {
76 *reg_type
= HKEY_USERS
;
77 *key_name
= ( path
[3] == '\\' ) ? path
+ 4 : NULL
;
78 } else if ( strncmp( path
, "HKEY_USERS", 10 ) == 0 ) {
79 *reg_type
= HKEY_USERS
;
80 *key_name
= ( path
[10] == '\\' ) ? path
+ 11 : NULL
;
81 } else if ( strncmp( path
, "HKPD", 4 ) == 0 ) {
82 *reg_type
= HKEY_PERFORMANCE_DATA
;
83 *key_name
= ( path
[4] == '\\' ) ? path
+ 5 : NULL
;
84 } else if ( strncmp( path
, "HKEY_PERFORMANCE_DATA", 21 ) == 0 ) {
85 *reg_type
= HKEY_PERFORMANCE_DATA
;
86 *key_name
= ( path
[21] == '\\' ) ? path
+ 22 : NULL
;
96 RPC_DATA_BLOB
*cac_MakeRpcDataBlob( TALLOC_CTX
* mem_ctx
, uint32 data_type
,
99 RPC_DATA_BLOB
*blob
= NULL
;
103 uint32 multi_idx
= 0;
105 blob
= talloc( mem_ctx
, RPC_DATA_BLOB
);
112 switch ( data_type
) {
114 init_rpc_blob_str( blob
, data
.reg_sz
,
115 strlen( data
.reg_sz
) + 1 );
119 init_rpc_blob_str( blob
, data
.reg_expand_sz
,
120 strlen( data
.reg_sz
) + 1 );
124 init_rpc_blob_bytes( blob
, data
.reg_binary
.data
,
125 data
.reg_binary
.data_length
);
129 init_rpc_blob_uint32( blob
, data
.reg_dword
);
132 case REG_DWORD_BIG_ENDIAN
:
133 init_rpc_blob_uint32( blob
, data
.reg_dword_be
);
137 /*need to find the size */
138 for ( i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++ ) {
139 size
+= strlen( data
.reg_multi_sz
.strings
[i
] ) + 1;
142 /**need a whole bunch of unicode strings in a row (seperated by null characters), with an extra null-character on the end*/
144 multi
= TALLOC_ZERO_ARRAY( mem_ctx
, uint8
, ( size
+ 1 ) * 2 ); /*size +1 for the extra null character */
150 /*do it using rpcstr_push() */
152 for ( i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++ ) {
154 strlen( data
.reg_multi_sz
.strings
[i
] ) + 1;
156 rpcstr_push( ( multi
+ multi_idx
),
157 data
.reg_multi_sz
.strings
[i
], len
* 2,
160 /* x2 becuase it is a uint8 buffer */
161 multi_idx
+= len
* 2;
164 /*now initialize the buffer as binary data */
165 init_rpc_blob_bytes( blob
, multi
, ( size
+ 1 ) * 2 );
175 if ( !( blob
->buffer
) ) {
183 /*turns a string in a uint16 array to a char array*/
184 char *cac_unistr_to_str( TALLOC_CTX
* mem_ctx
, uint16
* src
, int num_bytes
)
192 /*don't allocate more space than we need */
193 while ( ( str_len
) < num_bytes
/ 2 && src
[str_len
] != 0x0000 )
196 /*need room for a '\0' */
199 buf
= talloc_array( mem_ctx
, char, str_len
);
205 for ( i
= 0; i
< num_bytes
/ 2; i
++ ) {
206 buf
[i
] = ( ( char * ) src
)[2 * i
];
209 buf
[str_len
- 1] = '\0';
214 REG_VALUE_DATA
*cac_MakeRegValueData( TALLOC_CTX
* mem_ctx
, uint32 data_type
,
217 REG_VALUE_DATA
*data
;
221 /*all of the following used for MULTI_SZ data */
224 uint32 multi_idx
= 0;
225 uint32 num_strings
= 0;
226 char **strings
= NULL
;
228 data
= talloc( mem_ctx
, REG_VALUE_DATA
);
234 switch ( data_type
) {
237 cac_unistr_to_str( mem_ctx
, buf
.buffer
, buf
.buf_len
);
238 if ( !data
->reg_sz
) {
247 data
->reg_expand_sz
=
248 cac_unistr_to_str( mem_ctx
, buf
.buffer
, buf
.buf_len
);
250 if ( !data
->reg_expand_sz
) {
261 data
->reg_binary
.data_length
= size
;
263 data
->reg_binary
.data
=
264 ( uint8
* ) talloc_memdup( mem_ctx
, buf
.buffer
,
266 if ( !data
->reg_binary
.data
) {
274 data
->reg_dword
= *( ( uint32
* ) buf
.buffer
);
277 case REG_DWORD_BIG_ENDIAN
:
278 data
->reg_dword_be
= *( ( uint32
* ) buf
.buffer
);
284 /*find out how many strings there are. size is # of bytes and we want to work uint16 */
285 for ( i
= 0; i
< ( size
/ 2 - 1 ); i
++ ) {
286 if ( buf
.buffer
[i
] == 0x0000 )
289 /*buffer is suppsed to be terminated with \0\0, but it might not be */
290 if ( buf
.buffer
[i
] == 0x0000
291 && buf
.buffer
[i
+ 1] == 0x0000 )
295 strings
= talloc_array( mem_ctx
, char *, num_strings
);
303 if ( num_strings
== 0 ) /*then our work here is done */
306 for ( i
= 0; i
< num_strings
; i
++ ) {
307 /*find out how many characters are in this string */
309 /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0 */
310 while ( multi_idx
+ len
< size
/ 2
311 && buf
.buffer
[multi_idx
+ len
] != 0x0000 )
314 /*stay aware of the \0\0 */
317 strings
[i
] = TALLOC_ZERO_ARRAY( mem_ctx
, char, len
);
319 /*pull out the unicode string */
320 rpcstr_pull( strings
[i
], ( buf
.buffer
+ multi_idx
),
321 len
, -1, STR_TERMINATE
);
323 /*keep track of where we are in the bigger array */
327 data
->reg_multi_sz
.num_strings
= num_strings
;
328 data
->reg_multi_sz
.strings
= strings
;
340 SAM_USERINFO_CTR
*cac_MakeUserInfoCtr( TALLOC_CTX
* mem_ctx
,
343 SAM_USERINFO_CTR
*ctr
= NULL
;
345 /*the flags we are 'setting'- include/passdb.h */
347 ACCT_USERNAME
| ACCT_FULL_NAME
| ACCT_PRIMARY_GID
|
348 ACCT_DESCRIPTION
| ACCT_COMMENT
| ACCT_HOME_DIR
|
349 ACCT_HOME_DRIVE
| ACCT_LOGON_SCRIPT
| ACCT_PROFILE
|
350 ACCT_WORKSTATIONS
| ACCT_FLAGS
;
355 NTTIME pass_last_set_time
;
356 NTTIME pass_can_change_time
;
357 NTTIME pass_must_change_time
;
370 ctr
= talloc( mem_ctx
, SAM_USERINFO_CTR
);
374 ZERO_STRUCTP( ctr
->info
.id23
);
376 ctr
->info
.id21
= talloc( mem_ctx
, SAM_USER_INFO_21
);
377 if ( !ctr
->info
.id21
)
380 ctr
->switch_value
= 21;
382 ZERO_STRUCTP( ctr
->info
.id21
);
384 unix_to_nt_time( &logon_time
, info
->logon_time
);
385 unix_to_nt_time( &logoff_time
, info
->logoff_time
);
386 unix_to_nt_time( &kickoff_time
, info
->kickoff_time
);
387 unix_to_nt_time( &pass_last_set_time
, info
->pass_last_set_time
);
388 unix_to_nt_time( &pass_can_change_time
, info
->pass_can_change_time
);
389 unix_to_nt_time( &pass_must_change_time
,
390 info
->pass_must_change_time
);
392 /*initialize the strings */
393 init_unistr2( &user_name
, info
->username
, UNI_STR_TERMINATE
);
394 init_unistr2( &full_name
, info
->full_name
, UNI_STR_TERMINATE
);
395 init_unistr2( &home_dir
, info
->home_dir
, UNI_STR_TERMINATE
);
396 init_unistr2( &dir_drive
, info
->home_drive
, UNI_STR_TERMINATE
);
397 init_unistr2( &log_scr
, info
->logon_script
, UNI_STR_TERMINATE
);
398 init_unistr2( &prof_path
, info
->profile_path
, UNI_STR_TERMINATE
);
399 init_unistr2( &desc
, info
->description
, UNI_STR_TERMINATE
);
400 init_unistr2( &wkstas
, info
->workstations
, UNI_STR_TERMINATE
);
401 init_unistr2( &unk
, "\0", UNI_STR_TERMINATE
);
402 init_unistr2( &mung_dial
, info
->dial
, UNI_STR_TERMINATE
);
404 /*manually set passmustchange */
405 ctr
->info
.id21
->passmustchange
=
406 ( info
->pass_must_change
) ? 0x01 : 0x00;
408 init_sam_user_info21W( ctr
->info
.id21
, &logon_time
, &logoff_time
, &kickoff_time
, &pass_last_set_time
, &pass_can_change_time
, &pass_must_change_time
, &user_name
, &full_name
, &home_dir
, &dir_drive
, &log_scr
, &prof_path
, &desc
, &wkstas
, &unk
, &mung_dial
, info
->lm_password
, info
->nt_password
, info
->rid
, info
->group_rid
, info
->acb_mask
, flags
, 168, /*logon divs */
410 info
->bad_passwd_count
, info
->logon_count
);
416 char *talloc_unistr2_to_ascii( TALLOC_CTX
* mem_ctx
, UNISTR2 str
)
423 buf
= talloc_array( mem_ctx
, char, ( str
.uni_str_len
+ 1 ) );
427 unistr2_to_ascii( buf
, &str
, str
.uni_str_len
+ 1 );
432 CacUserInfo
*cac_MakeUserInfo( TALLOC_CTX
* mem_ctx
, SAM_USERINFO_CTR
* ctr
)
434 CacUserInfo
*info
= NULL
;
435 SAM_USER_INFO_21
*id21
= NULL
;
437 if ( !ctr
|| ctr
->switch_value
!= 21 )
440 info
= talloc( mem_ctx
, CacUserInfo
);
444 id21
= ctr
->info
.id21
;
446 ZERO_STRUCTP( info
);
448 info
->logon_time
= nt_time_to_unix( id21
->logon_time
);
449 info
->logoff_time
= nt_time_to_unix( id21
->logoff_time
);
450 info
->kickoff_time
= nt_time_to_unix( id21
->kickoff_time
);
451 info
->pass_last_set_time
=
452 nt_time_to_unix( id21
->pass_last_set_time
);
453 info
->pass_can_change_time
=
454 nt_time_to_unix( id21
->pass_can_change_time
);
455 info
->pass_must_change_time
=
456 nt_time_to_unix( id21
->pass_must_change_time
);
459 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_user_name
);
460 if ( !info
->username
)
464 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_full_name
);
465 if ( !info
->full_name
)
469 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_home_dir
);
470 if ( !info
->home_dir
)
474 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_dir_drive
);
475 if ( !info
->home_drive
)
479 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_logon_script
);
480 if ( !info
->logon_script
)
484 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_profile_path
);
485 if ( !info
->profile_path
)
489 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_acct_desc
);
490 if ( !info
->description
)
494 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_workstations
);
495 if ( !info
->workstations
)
499 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_munged_dial
);
503 info
->rid
= id21
->user_rid
;
504 info
->group_rid
= id21
->group_rid
;
505 info
->acb_mask
= id21
->acb_info
;
506 info
->bad_passwd_count
= id21
->bad_password_count
;
507 info
->logon_count
= id21
->logon_count
;
509 memcpy( info
->nt_password
, id21
->nt_pwd
, 8 );
510 memcpy( info
->lm_password
, id21
->lm_pwd
, 8 );
513 ( LOGON_HRS
* ) talloc_memdup( mem_ctx
, &( id21
->logon_hrs
),
514 sizeof( LOGON_HRS
) );
515 if ( !info
->logon_hours
)
518 info
->pass_must_change
= ( id21
->passmustchange
) ? True
: False
;
523 CacGroupInfo
*cac_MakeGroupInfo( TALLOC_CTX
* mem_ctx
, GROUP_INFO_CTR
* ctr
)
525 CacGroupInfo
*info
= NULL
;
527 if ( !mem_ctx
|| !ctr
|| ctr
->switch_value1
!= 1 )
530 info
= talloc( mem_ctx
, CacGroupInfo
);
535 talloc_unistr2_to_ascii( mem_ctx
,
536 ctr
->group
.info1
.uni_acct_name
);
541 talloc_unistr2_to_ascii( mem_ctx
,
542 ctr
->group
.info1
.uni_acct_desc
);
543 if ( !info
->description
)
546 info
->num_members
= ctr
->group
.info1
.num_members
;
551 GROUP_INFO_CTR
*cac_MakeGroupInfoCtr( TALLOC_CTX
* mem_ctx
,
552 CacGroupInfo
* info
)
554 GROUP_INFO_CTR
*ctr
= NULL
;
556 if ( !mem_ctx
|| !info
)
559 ctr
= talloc( mem_ctx
, GROUP_INFO_CTR
);
563 ctr
->switch_value1
= 1;
565 init_samr_group_info1( &( ctr
->group
.info1
), info
->name
,
566 info
->description
, info
->num_members
);
571 CacAliasInfo
*cac_MakeAliasInfo( TALLOC_CTX
* mem_ctx
, ALIAS_INFO_CTR ctr
)
573 CacGroupInfo
*info
= NULL
;
575 if ( !mem_ctx
|| ctr
.level
!= 1 )
578 info
= talloc( mem_ctx
, CacAliasInfo
);
583 talloc_unistr2_to_ascii( mem_ctx
,
584 *( ctr
.alias
.info1
.name
.string
) );
589 talloc_unistr2_to_ascii( mem_ctx
,
590 *( ctr
.alias
.info1
.description
.
595 info
->num_members
= ctr
.alias
.info1
.num_member
;
600 ALIAS_INFO_CTR
*cac_MakeAliasInfoCtr( TALLOC_CTX
* mem_ctx
,
601 CacAliasInfo
* info
)
603 ALIAS_INFO_CTR
*ctr
= NULL
;
605 if ( !mem_ctx
|| !info
)
608 ctr
= talloc( mem_ctx
, ALIAS_INFO_CTR
);
614 init_samr_alias_info1( &( ctr
->alias
.info1
), info
->name
,
615 info
->num_members
, info
->description
);
620 CacDomainInfo
*cac_MakeDomainInfo( TALLOC_CTX
* mem_ctx
,
621 SAM_UNK_INFO_1
* info1
,
622 SAM_UNK_INFO_2
* info2
,
623 SAM_UNK_INFO_12
* info12
)
625 CacDomainInfo
*info
= NULL
;
627 if ( !mem_ctx
|| !info1
|| !info2
|| !info12
)
630 info
= talloc( mem_ctx
, CacDomainInfo
);
634 info
->min_pass_length
= info1
->min_length_password
;
635 info
->pass_history
= info1
->password_history
;
637 cac_InitCacTime( &( info
->expire
), info1
->expire
);
638 cac_InitCacTime( &( info
->min_pass_age
), info1
->min_passwordage
);
640 info
->server_role
= info2
->server_role
;
641 info
->num_users
= info2
->num_domain_usrs
;
642 info
->num_domain_groups
= info2
->num_domain_grps
;
643 info
->num_local_groups
= info2
->num_local_grps
;
645 /*if these have been ZERO'd out we need to know. uni_str_len will be 0 */
646 if ( info2
->uni_comment
.uni_str_len
== 0 ) {
647 info
->comment
= talloc_strdup( mem_ctx
, "\0" );
650 talloc_unistr2_to_ascii( mem_ctx
,
651 info2
->uni_comment
);
654 if ( info2
->uni_domain
.uni_str_len
== 0 ) {
655 info
->domain_name
= talloc_strdup( mem_ctx
, "\0" );
658 talloc_unistr2_to_ascii( mem_ctx
, info2
->uni_domain
);
661 if ( info2
->uni_server
.uni_str_len
== 0 ) {
662 info
->server_name
= talloc_strdup( mem_ctx
, "\0" );
665 talloc_unistr2_to_ascii( mem_ctx
, info2
->uni_server
);
669 cac_InitCacTime( &( info
->lockout_duration
), info12
->duration
);
670 cac_InitCacTime( &( info
->lockout_reset
), info12
->reset_count
);
671 info
->num_bad_attempts
= info12
->bad_attempt_lockout
;
676 char *cac_unistr_ascii( TALLOC_CTX
* mem_ctx
, UNISTR src
)
681 if ( !mem_ctx
|| !src
.buffer
)
684 len
= unistrlen( src
.buffer
) + 1;
686 buf
= TALLOC_ZERO_ARRAY( mem_ctx
, char, len
);
690 rpcstr_pull( buf
, src
.buffer
, len
, -1, STR_TERMINATE
);
695 CacService
*cac_MakeServiceArray( TALLOC_CTX
* mem_ctx
,
696 ENUM_SERVICES_STATUS
* svc
,
697 uint32 num_services
)
700 CacService
*services
= NULL
;
702 if ( !mem_ctx
|| !svc
)
705 services
= TALLOC_ZERO_ARRAY( mem_ctx
, CacService
, num_services
);
709 for ( i
= 0; i
< num_services
; i
++ ) {
710 services
[i
].service_name
=
711 cac_unistr_ascii( mem_ctx
, svc
[i
].servicename
);
712 services
[i
].display_name
=
713 cac_unistr_ascii( mem_ctx
, svc
[i
].displayname
);
715 if ( !services
[i
].service_name
|| !services
[i
].display_name
)
718 services
[i
].status
= svc
[i
].status
;
724 int cac_InitCacServiceConfig( TALLOC_CTX
* mem_ctx
, SERVICE_CONFIG
* src
,
725 CacServiceConfig
* dest
)
731 talloc_unistr2_to_ascii( mem_ctx
, *src
->executablepath
);
732 if ( !dest
->exe_path
)
735 dest
->load_order_group
=
736 talloc_unistr2_to_ascii( mem_ctx
, *src
->loadordergroup
);
737 if ( !dest
->load_order_group
)
741 talloc_unistr2_to_ascii( mem_ctx
, *src
->dependencies
);
742 if ( !dest
->dependencies
)
746 talloc_unistr2_to_ascii( mem_ctx
, *src
->startname
);
747 if ( !dest
->start_name
)
751 talloc_unistr2_to_ascii( mem_ctx
, *src
->displayname
);
752 if ( !dest
->display_name
)
755 dest
->type
= src
->service_type
;
756 dest
->start_type
= src
->start_type
;
757 dest
->error_control
= src
->error_control
;
758 dest
->tag_id
= src
->tag_id
;