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
);
136 case REG_DWORD_BIG_ENDIAN
:
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
;
267 data
->reg_binary
.data
=
268 ( uint8
* ) talloc_memdup( mem_ctx
, buf
.buffer
,
270 if ( !data
->reg_binary
.data
) {
278 data
->reg_dword
= *( ( uint32
* ) buf
.buffer
);
281 case REG_DWORD_BIG_ENDIAN
:
282 data
->reg_dword_be
= *( ( uint32
* ) buf
.buffer
);
288 /*find out how many strings there are. size is # of bytes and we want to work uint16 */
289 for ( i
= 0; i
< ( size
/ 2 - 1 ); i
++ ) {
290 if ( buf
.buffer
[i
] == 0x0000 )
293 /*buffer is suppsed to be terminated with \0\0, but it might not be */
294 if ( buf
.buffer
[i
] == 0x0000
295 && buf
.buffer
[i
+ 1] == 0x0000 )
299 strings
= talloc_array( mem_ctx
, char *, num_strings
);
307 if ( num_strings
== 0 ) /*then our work here is done */
310 for ( i
= 0; i
< num_strings
; i
++ ) {
311 /*find out how many characters are in this string */
313 /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0 */
314 while ( multi_idx
+ len
< size
/ 2
315 && buf
.buffer
[multi_idx
+ len
] != 0x0000 )
318 /*stay aware of the \0\0 */
321 strings
[i
] = TALLOC_ZERO_ARRAY( mem_ctx
, char, len
);
323 /*pull out the unicode string */
324 rpcstr_pull( strings
[i
], ( buf
.buffer
+ multi_idx
),
325 len
, -1, STR_TERMINATE
);
327 /*keep track of where we are in the bigger array */
331 data
->reg_multi_sz
.num_strings
= num_strings
;
332 data
->reg_multi_sz
.strings
= strings
;
344 SAM_USERINFO_CTR
*cac_MakeUserInfoCtr( TALLOC_CTX
* mem_ctx
,
347 SAM_USERINFO_CTR
*ctr
= NULL
;
349 /*the flags we are 'setting'- include/passdb.h */
351 ACCT_USERNAME
| ACCT_FULL_NAME
| ACCT_PRIMARY_GID
|
352 ACCT_DESCRIPTION
| ACCT_COMMENT
| ACCT_HOME_DIR
|
353 ACCT_HOME_DRIVE
| ACCT_LOGON_SCRIPT
| ACCT_PROFILE
|
354 ACCT_WORKSTATIONS
| ACCT_FLAGS
;
359 NTTIME pass_last_set_time
;
360 NTTIME pass_can_change_time
;
361 NTTIME pass_must_change_time
;
374 ctr
= talloc( mem_ctx
, SAM_USERINFO_CTR
);
378 ZERO_STRUCTP( ctr
->info
.id23
);
380 ctr
->info
.id21
= talloc( mem_ctx
, SAM_USER_INFO_21
);
381 if ( !ctr
->info
.id21
)
384 ctr
->switch_value
= 21;
386 ZERO_STRUCTP( ctr
->info
.id21
);
388 unix_to_nt_time( &logon_time
, info
->logon_time
);
389 unix_to_nt_time( &logoff_time
, info
->logoff_time
);
390 unix_to_nt_time( &kickoff_time
, info
->kickoff_time
);
391 unix_to_nt_time( &pass_last_set_time
, info
->pass_last_set_time
);
392 unix_to_nt_time( &pass_can_change_time
, info
->pass_can_change_time
);
393 unix_to_nt_time( &pass_must_change_time
,
394 info
->pass_must_change_time
);
396 /*initialize the strings */
397 init_unistr2( &user_name
, info
->username
, UNI_STR_TERMINATE
);
398 init_unistr2( &full_name
, info
->full_name
, UNI_STR_TERMINATE
);
399 init_unistr2( &home_dir
, info
->home_dir
, UNI_STR_TERMINATE
);
400 init_unistr2( &dir_drive
, info
->home_drive
, UNI_STR_TERMINATE
);
401 init_unistr2( &log_scr
, info
->logon_script
, UNI_STR_TERMINATE
);
402 init_unistr2( &prof_path
, info
->profile_path
, UNI_STR_TERMINATE
);
403 init_unistr2( &desc
, info
->description
, UNI_STR_TERMINATE
);
404 init_unistr2( &wkstas
, info
->workstations
, UNI_STR_TERMINATE
);
405 init_unistr2( &unk
, "\0", UNI_STR_TERMINATE
);
406 init_unistr2( &mung_dial
, info
->dial
, UNI_STR_TERMINATE
);
408 /*manually set passmustchange */
409 ctr
->info
.id21
->passmustchange
=
410 ( info
->pass_must_change
) ? 0x01 : 0x00;
412 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 */
414 info
->bad_passwd_count
, info
->logon_count
);
420 char *talloc_unistr2_to_ascii( TALLOC_CTX
* mem_ctx
, UNISTR2 str
)
427 buf
= talloc_array( mem_ctx
, char, ( str
.uni_str_len
+ 1 ) );
431 unistr2_to_ascii( buf
, &str
, str
.uni_str_len
+ 1 );
436 CacUserInfo
*cac_MakeUserInfo( TALLOC_CTX
* mem_ctx
, SAM_USERINFO_CTR
* ctr
)
438 CacUserInfo
*info
= NULL
;
439 SAM_USER_INFO_21
*id21
= NULL
;
441 if ( !ctr
|| ctr
->switch_value
!= 21 )
444 info
= talloc( mem_ctx
, CacUserInfo
);
448 id21
= ctr
->info
.id21
;
450 ZERO_STRUCTP( info
);
452 info
->logon_time
= nt_time_to_unix( id21
->logon_time
);
453 info
->logoff_time
= nt_time_to_unix( id21
->logoff_time
);
454 info
->kickoff_time
= nt_time_to_unix( id21
->kickoff_time
);
455 info
->pass_last_set_time
=
456 nt_time_to_unix( id21
->pass_last_set_time
);
457 info
->pass_can_change_time
=
458 nt_time_to_unix( id21
->pass_can_change_time
);
459 info
->pass_must_change_time
=
460 nt_time_to_unix( id21
->pass_must_change_time
);
463 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_user_name
);
464 if ( !info
->username
)
468 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_full_name
);
469 if ( !info
->full_name
)
473 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_home_dir
);
474 if ( !info
->home_dir
)
478 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_dir_drive
);
479 if ( !info
->home_drive
)
483 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_logon_script
);
484 if ( !info
->logon_script
)
488 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_profile_path
);
489 if ( !info
->profile_path
)
493 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_acct_desc
);
494 if ( !info
->description
)
498 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_workstations
);
499 if ( !info
->workstations
)
503 talloc_unistr2_to_ascii( mem_ctx
, id21
->uni_munged_dial
);
507 info
->rid
= id21
->user_rid
;
508 info
->group_rid
= id21
->group_rid
;
509 info
->acb_mask
= id21
->acb_info
;
510 info
->bad_passwd_count
= id21
->bad_password_count
;
511 info
->logon_count
= id21
->logon_count
;
513 memcpy( info
->nt_password
, id21
->nt_pwd
, 8 );
514 memcpy( info
->lm_password
, id21
->lm_pwd
, 8 );
517 ( LOGON_HRS
* ) talloc_memdup( mem_ctx
, &( id21
->logon_hrs
),
518 sizeof( LOGON_HRS
) );
519 if ( !info
->logon_hours
)
522 info
->pass_must_change
= ( id21
->passmustchange
) ? True
: False
;
527 CacGroupInfo
*cac_MakeGroupInfo( TALLOC_CTX
* mem_ctx
, GROUP_INFO_CTR
* ctr
)
529 CacGroupInfo
*info
= NULL
;
531 if ( !mem_ctx
|| !ctr
|| ctr
->switch_value1
!= 1 )
534 info
= talloc( mem_ctx
, CacGroupInfo
);
539 talloc_unistr2_to_ascii( mem_ctx
,
540 ctr
->group
.info1
.uni_acct_name
);
545 talloc_unistr2_to_ascii( mem_ctx
,
546 ctr
->group
.info1
.uni_acct_desc
);
547 if ( !info
->description
)
550 info
->num_members
= ctr
->group
.info1
.num_members
;
555 GROUP_INFO_CTR
*cac_MakeGroupInfoCtr( TALLOC_CTX
* mem_ctx
,
556 CacGroupInfo
* info
)
558 GROUP_INFO_CTR
*ctr
= NULL
;
560 if ( !mem_ctx
|| !info
)
563 ctr
= talloc( mem_ctx
, GROUP_INFO_CTR
);
567 ctr
->switch_value1
= 1;
569 init_samr_group_info1( &( ctr
->group
.info1
), info
->name
,
570 info
->description
, info
->num_members
);
575 CacAliasInfo
*cac_MakeAliasInfo( TALLOC_CTX
* mem_ctx
, ALIAS_INFO_CTR ctr
)
577 CacGroupInfo
*info
= NULL
;
579 if ( !mem_ctx
|| ctr
.level
!= 1 )
582 info
= talloc( mem_ctx
, CacAliasInfo
);
587 talloc_unistr2_to_ascii( mem_ctx
,
588 *( ctr
.alias
.info1
.name
.string
) );
593 talloc_unistr2_to_ascii( mem_ctx
,
594 *( ctr
.alias
.info1
.description
.
599 info
->num_members
= ctr
.alias
.info1
.num_member
;
604 ALIAS_INFO_CTR
*cac_MakeAliasInfoCtr( TALLOC_CTX
* mem_ctx
,
605 CacAliasInfo
* info
)
607 ALIAS_INFO_CTR
*ctr
= NULL
;
609 if ( !mem_ctx
|| !info
)
612 ctr
= talloc( mem_ctx
, ALIAS_INFO_CTR
);
618 init_samr_alias_info1( &( ctr
->alias
.info1
), info
->name
,
619 info
->num_members
, info
->description
);
624 CacDomainInfo
*cac_MakeDomainInfo( TALLOC_CTX
* mem_ctx
,
625 SAM_UNK_INFO_1
* info1
,
626 SAM_UNK_INFO_2
* info2
,
627 SAM_UNK_INFO_12
* info12
)
629 CacDomainInfo
*info
= NULL
;
631 if ( !mem_ctx
|| !info1
|| !info2
|| !info12
)
634 info
= talloc( mem_ctx
, CacDomainInfo
);
638 info
->min_pass_length
= info1
->min_length_password
;
639 info
->pass_history
= info1
->password_history
;
641 cac_InitCacTime( &( info
->expire
), info1
->expire
);
642 cac_InitCacTime( &( info
->min_pass_age
), info1
->min_passwordage
);
644 info
->server_role
= info2
->server_role
;
645 info
->num_users
= info2
->num_domain_usrs
;
646 info
->num_domain_groups
= info2
->num_domain_grps
;
647 info
->num_local_groups
= info2
->num_local_grps
;
649 /*if these have been ZERO'd out we need to know. uni_str_len will be 0 */
650 if ( info2
->uni_comment
.uni_str_len
== 0 ) {
651 info
->comment
= talloc_strdup( mem_ctx
, "\0" );
654 talloc_unistr2_to_ascii( mem_ctx
,
655 info2
->uni_comment
);
658 if ( info2
->uni_domain
.uni_str_len
== 0 ) {
659 info
->domain_name
= talloc_strdup( mem_ctx
, "\0" );
662 talloc_unistr2_to_ascii( mem_ctx
, info2
->uni_domain
);
665 if ( info2
->uni_server
.uni_str_len
== 0 ) {
666 info
->server_name
= talloc_strdup( mem_ctx
, "\0" );
669 talloc_unistr2_to_ascii( mem_ctx
, info2
->uni_server
);
673 cac_InitCacTime( &( info
->lockout_duration
), info12
->duration
);
674 cac_InitCacTime( &( info
->lockout_reset
), info12
->reset_count
);
675 info
->num_bad_attempts
= info12
->bad_attempt_lockout
;
680 char *cac_unistr_ascii( TALLOC_CTX
* mem_ctx
, UNISTR src
)
685 if ( !mem_ctx
|| !src
.buffer
)
688 len
= unistrlen( src
.buffer
) + 1;
690 buf
= TALLOC_ZERO_ARRAY( mem_ctx
, char, len
);
694 rpcstr_pull( buf
, src
.buffer
, len
, -1, STR_TERMINATE
);
699 CacService
*cac_MakeServiceArray( TALLOC_CTX
* mem_ctx
,
700 ENUM_SERVICES_STATUS
* svc
,
701 uint32 num_services
)
704 CacService
*services
= NULL
;
706 if ( !mem_ctx
|| !svc
)
709 services
= TALLOC_ZERO_ARRAY( mem_ctx
, CacService
, num_services
);
713 for ( i
= 0; i
< num_services
; i
++ ) {
714 services
[i
].service_name
=
715 cac_unistr_ascii( mem_ctx
, svc
[i
].servicename
);
716 services
[i
].display_name
=
717 cac_unistr_ascii( mem_ctx
, svc
[i
].displayname
);
719 if ( !services
[i
].service_name
|| !services
[i
].display_name
)
722 services
[i
].status
= svc
[i
].status
;
728 int cac_InitCacServiceConfig( TALLOC_CTX
* mem_ctx
, SERVICE_CONFIG
* src
,
729 CacServiceConfig
* dest
)
735 talloc_unistr2_to_ascii( mem_ctx
, *src
->executablepath
);
736 if ( !dest
->exe_path
)
739 dest
->load_order_group
=
740 talloc_unistr2_to_ascii( mem_ctx
, *src
->loadordergroup
);
741 if ( !dest
->load_order_group
)
745 talloc_unistr2_to_ascii( mem_ctx
, *src
->dependencies
);
746 if ( !dest
->dependencies
)
750 talloc_unistr2_to_ascii( mem_ctx
, *src
->startname
);
751 if ( !dest
->start_name
)
755 talloc_unistr2_to_ascii( mem_ctx
, *src
->displayname
);
756 if ( !dest
->display_name
)
759 dest
->type
= src
->service_type
;
760 dest
->start_type
= src
->start_type
;
761 dest
->error_control
= src
->error_control
;
762 dest
->tag_id
= src
->tag_id
;