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 char *cac_unistr_to_str( TALLOC_CTX
* mem_ctx
, uint16
* src
, int num_bytes
);
27 char *talloc_unistr2_to_ascii( TALLOC_CTX
* mem_ctx
, UNISTR2 str
);
28 char *cac_unistr_ascii( TALLOC_CTX
* mem_ctx
, UNISTR src
);
30 /*used to get a struct rpc_pipe_client* to be passed into rpccli* calls*/
31 struct rpc_pipe_client
*cac_GetPipe( CacServerHandle
* hnd
, int pi_idx
)
34 struct rpc_pipe_client
*pipe_hnd
= NULL
;
40 if ( hnd
->_internal
.pipes
[pi_idx
] == False
) {
41 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
45 srv
= cac_GetServer( hnd
);
47 hnd
->status
= NT_STATUS_INVALID_CONNECTION
;
51 pipe_hnd
= srv
->cli
->pipe_list
;
53 while ( pipe_hnd
!= NULL
&& pipe_hnd
->pipe_idx
!= pi_idx
) {
54 pipe_hnd
= pipe_hnd
->next
;
60 /*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)*/
61 int cac_ParseRegPath( char *path
, uint32
* reg_type
, char **key_name
)
67 if ( strncmp( path
, "HKLM", 4 ) == 0 ) {
68 *reg_type
= HKEY_LOCAL_MACHINE
;
69 *key_name
= ( path
[4] == '\\' ) ? path
+ 5 : NULL
;
70 } else if ( strncmp( path
, "HKEY_LOCAL_MACHINE", 18 ) == 0 ) {
71 *reg_type
= HKEY_LOCAL_MACHINE
;
72 *key_name
= ( path
[18] == '\\' ) ? path
+ 19 : NULL
;
73 } else if ( strncmp( path
, "HKCR", 4 ) == 0 ) {
74 *reg_type
= HKEY_CLASSES_ROOT
;
75 *key_name
= ( path
[4] == '\\' ) ? path
+ 5 : NULL
;
76 } else if ( strncmp( path
, "HKEY_CLASSES_ROOT", 17 ) == 0 ) {
77 *reg_type
= HKEY_CLASSES_ROOT
;
78 *key_name
= ( path
[17] == '\\' ) ? path
+ 18 : NULL
;
79 } else if ( strncmp( path
, "HKU", 3 ) == 0 ) {
80 *reg_type
= HKEY_USERS
;
81 *key_name
= ( path
[3] == '\\' ) ? path
+ 4 : NULL
;
82 } else if ( strncmp( path
, "HKEY_USERS", 10 ) == 0 ) {
83 *reg_type
= HKEY_USERS
;
84 *key_name
= ( path
[10] == '\\' ) ? path
+ 11 : NULL
;
85 } else if ( strncmp( path
, "HKPD", 4 ) == 0 ) {
86 *reg_type
= HKEY_PERFORMANCE_DATA
;
87 *key_name
= ( path
[4] == '\\' ) ? path
+ 5 : NULL
;
88 } else if ( strncmp( path
, "HKEY_PERFORMANCE_DATA", 21 ) == 0 ) {
89 *reg_type
= HKEY_PERFORMANCE_DATA
;
90 *key_name
= ( path
[21] == '\\' ) ? path
+ 22 : NULL
;
100 RPC_DATA_BLOB
*cac_MakeRpcDataBlob( TALLOC_CTX
* mem_ctx
, uint32 data_type
,
101 REG_VALUE_DATA data
)
103 RPC_DATA_BLOB
*blob
= NULL
;
107 uint32 multi_idx
= 0;
109 blob
= talloc( mem_ctx
, RPC_DATA_BLOB
);
116 switch ( data_type
) {
118 init_rpc_blob_str( blob
, data
.reg_sz
,
119 strlen( data
.reg_sz
) + 1 );
123 init_rpc_blob_str( blob
, data
.reg_expand_sz
,
124 strlen( data
.reg_sz
) + 1 );
128 init_rpc_blob_bytes( blob
, data
.reg_binary
.data
,
129 data
.reg_binary
.data_length
);
133 init_rpc_blob_uint32( blob
, data
.reg_dword
);
137 init_rpc_blob_uint32( blob
, data
.reg_dword_be
);
141 /*need to find the size */
142 for ( i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++ ) {
143 size
+= strlen( data
.reg_multi_sz
.strings
[i
] ) + 1;
146 /**need a whole bunch of unicode strings in a row (seperated by null characters), with an extra null-character on the end*/
148 multi
= TALLOC_ZERO_ARRAY( mem_ctx
, uint8
, ( size
+ 1 ) * 2 ); /*size +1 for the extra null character */
154 /*do it using rpcstr_push() */
156 for ( i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++ ) {
158 strlen( data
.reg_multi_sz
.strings
[i
] ) + 1;
160 rpcstr_push( ( multi
+ multi_idx
),
161 data
.reg_multi_sz
.strings
[i
], len
* 2,
164 /* x2 becuase it is a uint8 buffer */
165 multi_idx
+= len
* 2;
168 /*now initialize the buffer as binary data */
169 init_rpc_blob_bytes( blob
, multi
, ( size
+ 1 ) * 2 );
179 if ( !( blob
->buffer
) ) {
187 /*turns a string in a uint16 array to a char array*/
188 char *cac_unistr_to_str( TALLOC_CTX
* mem_ctx
, uint16
* src
, int num_bytes
)
196 /*don't allocate more space than we need */
197 while ( ( str_len
) < num_bytes
/ 2 && src
[str_len
] != 0x0000 )
200 /*need room for a '\0' */
203 buf
= TALLOC_ARRAY( mem_ctx
, char, str_len
);
209 for ( i
= 0; i
< num_bytes
/ 2; i
++ ) {
210 buf
[i
] = ( ( char * ) src
)[2 * i
];
213 buf
[str_len
- 1] = '\0';
218 REG_VALUE_DATA
*cac_MakeRegValueData( TALLOC_CTX
* mem_ctx
, uint32 data_type
,
221 REG_VALUE_DATA
*data
;
225 /*all of the following used for MULTI_SZ data */
228 uint32 multi_idx
= 0;
229 uint32 num_strings
= 0;
230 char **strings
= NULL
;
232 data
= talloc( mem_ctx
, REG_VALUE_DATA
);
238 switch ( data_type
) {
241 cac_unistr_to_str( mem_ctx
, buf
.buffer
, buf
.buf_len
);
242 if ( !data
->reg_sz
) {
251 data
->reg_expand_sz
=
252 cac_unistr_to_str( mem_ctx
, buf
.buffer
, buf
.buf_len
);
254 if ( !data
->reg_expand_sz
) {
265 data
->reg_binary
.data_length
= size
;
268 data
->reg_binary
.data
=
269 ( uint8
* ) TALLOC_MEMDUP( mem_ctx
, buf
.buffer
, size
);
270 if ( !data
->reg_binary
.data
) {
276 data
->reg_binary
.data
= NULL
;
281 data
->reg_dword
= *( ( uint32
* ) buf
.buffer
);
285 data
->reg_dword_be
= *( ( uint32
* ) buf
.buffer
);
291 /*find out how many strings there are. size is # of bytes and we want to work uint16 */
292 for ( i
= 0; i
< ( size
/ 2 - 1 ); i
++ ) {
293 if ( buf
.buffer
[i
] == 0x0000 )
296 /*buffer is suppsed to be terminated with \0\0, but it might not be */
297 if ( buf
.buffer
[i
] == 0x0000
298 && buf
.buffer
[i
+ 1] == 0x0000 )
303 strings
= TALLOC_ARRAY( mem_ctx
, char *, num_strings
);
314 if ( num_strings
== 0 ) /*then our work here is done */
317 for ( i
= 0; i
< num_strings
; i
++ ) {
318 /*find out how many characters are in this string */
320 /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0 */
321 while ( multi_idx
+ len
< size
/ 2
322 && buf
.buffer
[multi_idx
+ len
] != 0x0000 )
325 /*stay aware of the \0\0 */
328 strings
[i
] = TALLOC_ZERO_ARRAY( mem_ctx
, char, len
);
330 /*pull out the unicode string */
331 rpcstr_pull( strings
[i
], ( buf
.buffer
+ multi_idx
),
332 len
, -1, STR_TERMINATE
);
334 /*keep track of where we are in the bigger array */
338 data
->reg_multi_sz
.num_strings
= num_strings
;
339 data
->reg_multi_sz
.strings
= strings
;
351 SAM_USERINFO_CTR
*cac_MakeUserInfoCtr( TALLOC_CTX
* mem_ctx
,
354 SAM_USERINFO_CTR
*ctr
= NULL
;
356 /*the flags we are 'setting'- include/passdb.h */
358 ACCT_USERNAME
| ACCT_FULL_NAME
| ACCT_PRIMARY_GID
|
359 ACCT_DESCRIPTION
| ACCT_COMMENT
| ACCT_HOME_DIR
|
360 ACCT_HOME_DRIVE
| ACCT_LOGON_SCRIPT
| ACCT_PROFILE
|
361 ACCT_WORKSTATIONS
| ACCT_FLAGS
;
366 NTTIME pass_last_set_time
;
367 NTTIME pass_can_change_time
;
368 NTTIME pass_must_change_time
;
381 ctr
= talloc( mem_ctx
, SAM_USERINFO_CTR
);
385 ZERO_STRUCTP( ctr
->info
.id23
);
387 ctr
->info
.id21
= talloc( mem_ctx
, SAM_USER_INFO_21
);
388 if ( !ctr
->info
.id21
)
391 ctr
->switch_value
= 21;
393 ZERO_STRUCTP( ctr
->info
.id21
);
395 unix_to_nt_time( &logon_time
, info
->logon_time
);
396 unix_to_nt_time( &logoff_time
, info
->logoff_time
);
397 unix_to_nt_time( &kickoff_time
, info
->kickoff_time
);
398 unix_to_nt_time( &pass_last_set_time
, info
->pass_last_set_time
);
399 unix_to_nt_time( &pass_can_change_time
, info
->pass_can_change_time
);
400 unix_to_nt_time( &pass_must_change_time
,
401 info
->pass_must_change_time
);
403 /*initialize the strings */
404 init_unistr2( &user_name
, info
->username
, UNI_STR_TERMINATE
);
405 init_unistr2( &full_name
, info
->full_name
, UNI_STR_TERMINATE
);
406 init_unistr2( &home_dir
, info
->home_dir
, UNI_STR_TERMINATE
);
407 init_unistr2( &dir_drive
, info
->home_drive
, UNI_STR_TERMINATE
);
408 init_unistr2( &log_scr
, info
->logon_script
, UNI_STR_TERMINATE
);
409 init_unistr2( &prof_path
, info
->profile_path
, UNI_STR_TERMINATE
);
410 init_unistr2( &desc
, info
->description
, UNI_STR_TERMINATE
);
411 init_unistr2( &wkstas
, info
->workstations
, UNI_STR_TERMINATE
);
412 init_unistr2( &unk
, "\0", UNI_STR_TERMINATE
);
413 init_unistr2( &mung_dial
, info
->dial
, UNI_STR_TERMINATE
);
415 /*manually set passmustchange */
416 ctr
->info
.id21
->passmustchange
=
417 ( info
->pass_must_change
) ? 0x01 : 0x00;
419 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 */
421 info
->bad_passwd_count
, info
->logon_count
);
427 char *talloc_unistr2_to_ascii( TALLOC_CTX
* mem_ctx
, UNISTR2 str
)
434 buf
= TALLOC_ARRAY( mem_ctx
, char, ( str
.uni_str_len
+ 1 ) );
438 unistr2_to_ascii( buf
, &str
, str
.uni_str_len
+ 1 );
443 CacUserInfo
*cac_MakeUserInfo( TALLOC_CTX
* mem_ctx
, SAM_USERINFO_CTR
* ctr
)
445 CacUserInfo
*info
= NULL
;
446 SAM_USER_INFO_21
*id21
= NULL
;
448 if ( !ctr
|| ctr
->switch_value
!= 21 )
451 info
= talloc( mem_ctx
, CacUserInfo
);
455 id21
= ctr
->info
.id21
;
457 ZERO_STRUCTP( info
);
459 info
->logon_time
= nt_time_to_unix( id21
->logon_time
);
460 info
->logoff_time
= nt_time_to_unix( id21
->logoff_time
);
461 info
->kickoff_time
= nt_time_to_unix( id21
->kickoff_time
);
462 info
->pass_last_set_time
=
463 nt_time_to_unix( id21
->pass_last_set_time
);
464 info
->pass_can_change_time
=
465 nt_time_to_unix( id21
->pass_can_change_time
);
466 info
->pass_must_change_time
=
467 nt_time_to_unix( id21
->pass_must_change_time
);
470 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_user_name
);
471 if ( !info
->username
)
475 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_full_name
);
476 if ( !info
->full_name
)
480 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_home_dir
);
481 if ( !info
->home_dir
)
485 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_dir_drive
);
486 if ( !info
->home_drive
)
490 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_logon_script
);
491 if ( !info
->logon_script
)
495 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_profile_path
);
496 if ( !info
->profile_path
)
500 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_acct_desc
);
501 if ( !info
->description
)
505 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_workstations
);
506 if ( !info
->workstations
)
510 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_munged_dial
);
514 info
->rid
= id21
->user_rid
;
515 info
->group_rid
= id21
->group_rid
;
516 info
->acb_mask
= id21
->acb_info
;
517 info
->bad_passwd_count
= id21
->bad_password_count
;
518 info
->logon_count
= id21
->logon_count
;
520 memcpy( info
->nt_password
, id21
->nt_pwd
, 8 );
521 memcpy( info
->lm_password
, id21
->lm_pwd
, 8 );
524 ( LOGON_HRS
* ) TALLOC_MEMDUP( mem_ctx
, &( id21
->logon_hrs
),
525 sizeof( LOGON_HRS
) );
526 if ( !info
->logon_hours
)
529 info
->pass_must_change
= ( id21
->passmustchange
) ? True
: False
;
534 CacGroupInfo
*cac_MakeGroupInfo( TALLOC_CTX
* mem_ctx
, GROUP_INFO_CTR
* ctr
)
536 CacGroupInfo
*info
= NULL
;
538 if ( !mem_ctx
|| !ctr
|| ctr
->switch_value1
!= 1 )
541 info
= talloc( mem_ctx
, CacGroupInfo
);
546 talloc_unistr2_to_ascii( mem_ctx
,
547 ctr
->group
.info1
.uni_acct_name
);
552 talloc_unistr2_to_ascii( mem_ctx
,
553 ctr
->group
.info1
.uni_acct_desc
);
554 if ( !info
->description
)
557 info
->num_members
= ctr
->group
.info1
.num_members
;
562 GROUP_INFO_CTR
*cac_MakeGroupInfoCtr( TALLOC_CTX
* mem_ctx
,
563 CacGroupInfo
* info
)
565 GROUP_INFO_CTR
*ctr
= NULL
;
567 if ( !mem_ctx
|| !info
)
570 ctr
= talloc( mem_ctx
, GROUP_INFO_CTR
);
574 ctr
->switch_value1
= 1;
576 init_samr_group_info1( &( ctr
->group
.info1
), info
->name
,
577 info
->description
, info
->num_members
);
582 CacAliasInfo
*cac_MakeAliasInfo( TALLOC_CTX
* mem_ctx
, ALIAS_INFO_CTR ctr
)
584 CacGroupInfo
*info
= NULL
;
586 if ( !mem_ctx
|| ctr
.level
!= 1 )
589 info
= talloc( mem_ctx
, CacAliasInfo
);
594 talloc_unistr2_to_ascii( mem_ctx
,
595 *( ctr
.alias
.info1
.name
.string
) );
600 talloc_unistr2_to_ascii( mem_ctx
,
601 *( ctr
.alias
.info1
.description
.
606 info
->num_members
= ctr
.alias
.info1
.num_member
;
611 ALIAS_INFO_CTR
*cac_MakeAliasInfoCtr( TALLOC_CTX
* mem_ctx
,
612 CacAliasInfo
* info
)
614 ALIAS_INFO_CTR
*ctr
= NULL
;
616 if ( !mem_ctx
|| !info
)
619 ctr
= talloc( mem_ctx
, ALIAS_INFO_CTR
);
625 init_samr_alias_info1( &( ctr
->alias
.info1
), info
->name
,
626 info
->num_members
, info
->description
);
631 CacDomainInfo
*cac_MakeDomainInfo( TALLOC_CTX
* mem_ctx
,
632 SAM_UNK_INFO_1
* info1
,
633 SAM_UNK_INFO_2
* info2
,
634 SAM_UNK_INFO_12
* info12
)
636 CacDomainInfo
*info
= NULL
;
638 if ( !mem_ctx
|| !info1
|| !info2
|| !info12
)
641 info
= talloc( mem_ctx
, CacDomainInfo
);
645 info
->min_pass_length
= info1
->min_length_password
;
646 info
->pass_history
= info1
->password_history
;
648 cac_InitCacTime( &( info
->expire
), info1
->expire
);
649 cac_InitCacTime( &( info
->min_pass_age
), info1
->min_passwordage
);
651 info
->server_role
= info2
->server_role
;
652 info
->num_users
= info2
->num_domain_usrs
;
653 info
->num_domain_groups
= info2
->num_domain_grps
;
654 info
->num_local_groups
= info2
->num_local_grps
;
656 /*if these have been ZERO'd out we need to know. uni_str_len will be 0 */
657 if ( info2
->uni_comment
.uni_str_len
== 0 ) {
658 info
->comment
= talloc_strdup( mem_ctx
, "\0" );
661 talloc_unistr2_to_ascii( mem_ctx
,
662 info2
->uni_comment
);
665 if ( info2
->uni_domain
.uni_str_len
== 0 ) {
666 info
->domain_name
= talloc_strdup( mem_ctx
, "\0" );
669 talloc_unistr2_to_ascii( mem_ctx
, info2
->uni_domain
);
672 if ( info2
->uni_server
.uni_str_len
== 0 ) {
673 info
->server_name
= talloc_strdup( mem_ctx
, "\0" );
676 talloc_unistr2_to_ascii( mem_ctx
, info2
->uni_server
);
680 cac_InitCacTime( &( info
->lockout_duration
), info12
->duration
);
681 cac_InitCacTime( &( info
->lockout_reset
), info12
->reset_count
);
682 info
->num_bad_attempts
= info12
->bad_attempt_lockout
;
687 char *cac_unistr_ascii( TALLOC_CTX
* mem_ctx
, UNISTR src
)
692 if ( !mem_ctx
|| !src
.buffer
)
695 len
= unistrlen( src
.buffer
) + 1;
697 buf
= TALLOC_ZERO_ARRAY( mem_ctx
, char, len
);
701 rpcstr_pull( buf
, src
.buffer
, len
, -1, STR_TERMINATE
);
706 CacService
*cac_MakeServiceArray( TALLOC_CTX
* mem_ctx
,
707 ENUM_SERVICES_STATUS
* svc
,
708 uint32 num_services
)
711 CacService
*services
= NULL
;
713 if ( !mem_ctx
|| !svc
)
717 services
= TALLOC_ZERO_ARRAY( mem_ctx
, CacService
, num_services
);
724 for ( i
= 0; i
< num_services
; i
++ ) {
725 services
[i
].service_name
=
726 cac_unistr_ascii( mem_ctx
, svc
[i
].servicename
);
727 services
[i
].display_name
=
728 cac_unistr_ascii( mem_ctx
, svc
[i
].displayname
);
730 if ( !services
[i
].service_name
|| !services
[i
].display_name
)
733 services
[i
].status
= svc
[i
].status
;
739 int cac_InitCacServiceConfig( TALLOC_CTX
* mem_ctx
, SERVICE_CONFIG
* src
,
740 CacServiceConfig
* dest
)
746 talloc_unistr2_to_ascii( mem_ctx
, *src
->executablepath
);
747 if ( !dest
->exe_path
)
750 dest
->load_order_group
=
751 talloc_unistr2_to_ascii( mem_ctx
, *src
->loadordergroup
);
752 if ( !dest
->load_order_group
)
756 talloc_unistr2_to_ascii( mem_ctx
, *src
->dependencies
);
757 if ( !dest
->dependencies
)
761 talloc_unistr2_to_ascii( mem_ctx
, *src
->startname
);
762 if ( !dest
->start_name
)
766 talloc_unistr2_to_ascii( mem_ctx
, *src
->displayname
);
767 if ( !dest
->display_name
)
770 dest
->type
= src
->service_type
;
771 dest
->start_type
= src
->start_type
;
772 dest
->error_control
= src
->error_control
;
773 dest
->tag_id
= src
->tag_id
;