2 * Unix SMB/CIFS implementation.
3 * MS-RPC client internal functions
4 * Copyright (C) Chris Nicholls 2005.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "libmsrpc_internal.h"
25 /*used to get a struct rpc_pipe_client* to be passed into rpccli* calls*/
26 struct rpc_pipe_client
*cac_GetPipe(CacServerHandle
*hnd
, int pi_idx
)
29 struct rpc_pipe_client
*pipe_hnd
= NULL
;
35 if(hnd
->_internal
.pipes
[pi_idx
] == False
) {
36 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
40 srv
= cac_GetServer(hnd
);
42 hnd
->status
= NT_STATUS_INVALID_CONNECTION
;
46 pipe_hnd
= srv
->cli
->pipe_list
;
48 while(pipe_hnd
!= NULL
&& pipe_hnd
->pipe_idx
!= pi_idx
) {
49 pipe_hnd
= pipe_hnd
->next
;
55 /*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)*/
56 int cac_ParseRegPath(char *path
, uint32
*reg_type
, char **key_name
) {
61 if(strncmp(path
, "HKLM", 4) == 0) {
62 *reg_type
= HKEY_LOCAL_MACHINE
;
63 *key_name
= (path
[4] == '\\') ? path
+ 5 : NULL
;
65 else if(strncmp(path
, "HKEY_LOCAL_MACHINE", 18) == 0) {
66 *reg_type
= HKEY_LOCAL_MACHINE
;
67 *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
;
73 else if(strncmp(path
, "HKEY_CLASSES_ROOT", 17) == 0) {
74 *reg_type
= HKEY_CLASSES_ROOT
;
75 *key_name
= (path
[17] == '\\') ? path
+ 18 : NULL
;
77 else if(strncmp(path
, "HKU", 3) == 0) {
78 *reg_type
= HKEY_USERS
;
79 *key_name
= (path
[3] == '\\') ? path
+ 4 : NULL
;
81 else if(strncmp(path
, "HKEY_USERS", 10) == 0) {
82 *reg_type
= HKEY_USERS
;
83 *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
;
89 else if(strncmp(path
, "HKEY_PERFORMANCE_DATA", 21) == 0) {
90 *reg_type
= HKEY_PERFORMANCE_DATA
;
91 *key_name
= (path
[21] == '\\') ? path
+ 22 : NULL
;
102 RPC_DATA_BLOB
*cac_MakeRpcDataBlob(TALLOC_CTX
*mem_ctx
, uint32 data_type
, REG_VALUE_DATA data
) {
103 RPC_DATA_BLOB
*blob
= NULL
;
107 uint32 multi_idx
= 0;
109 blob
= talloc(mem_ctx
, RPC_DATA_BLOB
);
118 init_rpc_blob_str(blob
, data
.reg_sz
, strlen(data
.reg_sz
) + 1);
122 init_rpc_blob_str(blob
, data
.reg_expand_sz
, strlen(data
.reg_sz
) + 1);
126 init_rpc_blob_bytes(blob
, data
.reg_binary
.data
, data
.reg_binary
.data_length
);
130 init_rpc_blob_uint32(blob
, data
.reg_dword
);
134 init_rpc_blob_uint32(blob
, data
.reg_dword_be
);
138 /*need to find the size*/
139 for(i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++) {
140 size
+= strlen(data
.reg_multi_sz
.strings
[i
]) + 1;
143 /**need a whole bunch of unicode strings in a row (seperated by null characters), with an extra null-character on the end*/
145 multi
= TALLOC_ZERO_ARRAY(mem_ctx
, uint8
, (size
+ 1)*2); /*size +1 for the extra null character*/
151 /*do it using rpcstr_push()*/
153 for(i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++) {
154 size_t len
= strlen(data
.reg_multi_sz
.strings
[i
]) + 1;
156 rpcstr_push((multi
+ multi_idx
), data
.reg_multi_sz
.strings
[i
], len
* 2, STR_TERMINATE
);
158 /* x2 becuase it is a uint8 buffer*/
159 multi_idx
+= len
* 2;
162 /*now initialize the buffer as binary data*/
163 init_rpc_blob_bytes(blob
, multi
, (size
+ 1)*2);
173 if(!(blob
->buffer
)) {
181 /*turns a string in a uint16 array to a char array*/
182 char *cac_unistr_to_str(TALLOC_CTX
*mem_ctx
, uint16
*src
, int num_bytes
) {
189 /*don't allocate more space than we need*/
190 while( (str_len
) < num_bytes
/2 && src
[str_len
] != 0x0000)
193 /*need room for a '\0'*/
196 buf
= talloc_array(mem_ctx
, char, str_len
);
201 for(i
= 0; i
< num_bytes
/2; i
++) {
202 buf
[i
] = ((char *)src
)[2*i
];
205 buf
[str_len
- 1] = '\0';
210 REG_VALUE_DATA
*cac_MakeRegValueData(TALLOC_CTX
*mem_ctx
, uint32 data_type
, REGVAL_BUFFER buf
) {
211 REG_VALUE_DATA
*data
;
215 /*all of the following used for MULTI_SZ data*/
218 uint32 multi_idx
= 0;
219 uint32 num_strings
= 0;
220 char **strings
= NULL
;
222 data
= talloc(mem_ctx
, REG_VALUE_DATA
);
230 data
->reg_sz
= cac_unistr_to_str(mem_ctx
, buf
.buffer
, buf
.buf_len
);
240 data
->reg_expand_sz
= cac_unistr_to_str(mem_ctx
, buf
.buffer
, buf
.buf_len
);
242 if(!data
->reg_expand_sz
) {
253 data
->reg_binary
.data_length
= size
;
255 data
->reg_binary
.data
= (uint8
*)talloc_memdup(mem_ctx
, buf
.buffer
,
257 if(!data
->reg_binary
.data
) {
265 data
->reg_dword
= *((uint32
*)buf
.buffer
);
269 data
->reg_dword_be
= *((uint32
*)buf
.buffer
);
275 /*find out how many strings there are. size is # of bytes and we want to work uint16*/
276 for(i
= 0; i
< (size
/2 - 1); i
++) {
277 if(buf
.buffer
[i
] == 0x0000)
280 /*buffer is suppsed to be terminated with \0\0, but it might not be*/
281 if(buf
.buffer
[i
] == 0x0000 && buf
.buffer
[i
+ 1] == 0x0000)
285 strings
= talloc_array(mem_ctx
, char *, num_strings
);
292 if(num_strings
== 0) /*then our work here is done*/
295 for(i
= 0; i
< num_strings
; i
++) {
296 /*find out how many characters are in this string*/
298 /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0*/
299 while( multi_idx
+ len
< size
/2 && buf
.buffer
[multi_idx
+ len
] != 0x0000)
302 /*stay aware of the \0\0*/
305 strings
[i
] = TALLOC_ZERO_ARRAY(mem_ctx
, char, len
);
307 /*pull out the unicode string*/
308 rpcstr_pull(strings
[i
], (buf
.buffer
+ multi_idx
) , len
, -1, STR_TERMINATE
);
310 /*keep track of where we are in the bigger array*/
314 data
->reg_multi_sz
.num_strings
= num_strings
;
315 data
->reg_multi_sz
.strings
= strings
;
327 SAM_USERINFO_CTR
*cac_MakeUserInfoCtr(TALLOC_CTX
*mem_ctx
, CacUserInfo
*info
) {
328 SAM_USERINFO_CTR
*ctr
= NULL
;
330 /*the flags we are 'setting'- include/passdb.h*/
331 uint32 flags
= ACCT_USERNAME
| ACCT_FULL_NAME
| ACCT_PRIMARY_GID
| ACCT_DESCRIPTION
| ACCT_COMMENT
|
332 ACCT_HOME_DIR
| ACCT_HOME_DRIVE
| ACCT_LOGON_SCRIPT
| ACCT_PROFILE
| ACCT_WORKSTATIONS
|
338 NTTIME pass_last_set_time
;
339 NTTIME pass_can_change_time
;
340 NTTIME pass_must_change_time
;
353 ctr
= talloc(mem_ctx
, SAM_USERINFO_CTR
);
357 ZERO_STRUCTP(ctr
->info
.id23
);
359 ctr
->info
.id21
= talloc(mem_ctx
, SAM_USER_INFO_21
);
363 ctr
->switch_value
= 21;
365 ZERO_STRUCTP(ctr
->info
.id21
);
367 unix_to_nt_time(&logon_time
, info
->logon_time
);
368 unix_to_nt_time(&logoff_time
, info
->logoff_time
);
369 unix_to_nt_time(&kickoff_time
, info
->kickoff_time
);
370 unix_to_nt_time(&pass_last_set_time
, info
->pass_last_set_time
);
371 unix_to_nt_time(&pass_can_change_time
, info
->pass_can_change_time
);
372 unix_to_nt_time(&pass_must_change_time
, info
->pass_must_change_time
);
374 /*initialize the strings*/
375 init_unistr2(&user_name
, info
->username
, UNI_STR_TERMINATE
);
376 init_unistr2(&full_name
, info
->full_name
, UNI_STR_TERMINATE
);
377 init_unistr2(&home_dir
, info
->home_dir
, UNI_STR_TERMINATE
);
378 init_unistr2(&dir_drive
, info
->home_drive
, UNI_STR_TERMINATE
);
379 init_unistr2(&log_scr
, info
->logon_script
, UNI_STR_TERMINATE
);
380 init_unistr2(&prof_path
, info
->profile_path
, UNI_STR_TERMINATE
);
381 init_unistr2(&desc
, info
->description
, UNI_STR_TERMINATE
);
382 init_unistr2(&wkstas
, info
->workstations
, UNI_STR_TERMINATE
);
383 init_unistr2(&unk
, "\0", UNI_STR_TERMINATE
);
384 init_unistr2(&mung_dial
, info
->dial
, UNI_STR_TERMINATE
);
386 /*manually set passmustchange*/
387 ctr
->info
.id21
->passmustchange
= (info
->pass_must_change
) ? 0x01 : 0x00;
389 init_sam_user_info21W(ctr
->info
.id21
,
394 &pass_can_change_time
,
395 &pass_must_change_time
,
414 info
->bad_passwd_count
,
421 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
) {
437 CacUserInfo
*info
= NULL
;
438 SAM_USER_INFO_21
*id21
= NULL
;
440 if(!ctr
|| ctr
->switch_value
!= 21)
443 info
= talloc(mem_ctx
, CacUserInfo
);
447 id21
= ctr
->info
.id21
;
451 info
->logon_time
= nt_time_to_unix(&id21
->logon_time
);
452 info
->logoff_time
= nt_time_to_unix(&id21
->logoff_time
);
453 info
->kickoff_time
= nt_time_to_unix(&id21
->kickoff_time
);
454 info
->pass_last_set_time
= nt_time_to_unix(&id21
->pass_last_set_time
);
455 info
->pass_can_change_time
= nt_time_to_unix(&id21
->pass_can_change_time
);
456 info
->pass_must_change_time
= nt_time_to_unix(&id21
->pass_must_change_time
);
458 info
->username
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_user_name
);
462 info
->full_name
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_full_name
);
466 info
->home_dir
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_home_dir
);
470 info
->home_drive
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_dir_drive
);
471 if(!info
->home_drive
)
474 info
->logon_script
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_logon_script
);
475 if(!info
->logon_script
)
478 info
->profile_path
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_profile_path
);
479 if(!info
->profile_path
)
482 info
->description
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_acct_desc
);
483 if(!info
->description
)
486 info
->workstations
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_workstations
);
487 if(!info
->workstations
)
490 info
->dial
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_munged_dial
);
494 info
->rid
= id21
->user_rid
;
495 info
->group_rid
= id21
->group_rid
;
496 info
->acb_mask
= id21
->acb_info
;
497 info
->bad_passwd_count
= id21
->bad_password_count
;
498 info
->logon_count
= id21
->logon_count
;
500 memcpy(info
->nt_password
, id21
->nt_pwd
, 8);
501 memcpy(info
->lm_password
, id21
->lm_pwd
, 8);
503 info
->logon_hours
= (LOGON_HRS
*)talloc_memdup(mem_ctx
, &(id21
->logon_hrs
),
505 if(!info
->logon_hours
)
508 info
->pass_must_change
= (id21
->passmustchange
) ? True
: False
;
513 CacGroupInfo
*cac_MakeGroupInfo(TALLOC_CTX
*mem_ctx
, GROUP_INFO_CTR
*ctr
) {
514 CacGroupInfo
*info
= NULL
;
516 if(!mem_ctx
|| !ctr
|| ctr
->switch_value1
!= 1)
519 info
= talloc(mem_ctx
, CacGroupInfo
);
523 info
->name
= talloc_unistr2_to_ascii(mem_ctx
, ctr
->group
.info1
.uni_acct_name
);
527 info
->description
= talloc_unistr2_to_ascii(mem_ctx
, ctr
->group
.info1
.uni_acct_desc
);
528 if(!info
->description
)
531 info
->num_members
= ctr
->group
.info1
.num_members
;
536 GROUP_INFO_CTR
*cac_MakeGroupInfoCtr(TALLOC_CTX
*mem_ctx
, CacGroupInfo
*info
) {
537 GROUP_INFO_CTR
*ctr
= NULL
;
539 if(!mem_ctx
|| !info
)
542 ctr
= talloc(mem_ctx
, GROUP_INFO_CTR
);
546 ctr
->switch_value1
= 1;
548 init_samr_group_info1(&(ctr
->group
.info1
), info
->name
, info
->description
, info
->num_members
);
553 CacAliasInfo
*cac_MakeAliasInfo(TALLOC_CTX
*mem_ctx
, ALIAS_INFO_CTR ctr
) {
554 CacGroupInfo
*info
= NULL
;
556 if(!mem_ctx
|| ctr
.level
!= 1)
559 info
= talloc(mem_ctx
, CacAliasInfo
);
563 info
->name
= talloc_unistr2_to_ascii(mem_ctx
, *(ctr
.alias
.info1
.name
.string
));
567 info
->description
= talloc_unistr2_to_ascii(mem_ctx
, *(ctr
.alias
.info1
.description
.string
));
571 info
->num_members
= ctr
.alias
.info1
.num_member
;
576 ALIAS_INFO_CTR
*cac_MakeAliasInfoCtr(TALLOC_CTX
*mem_ctx
, CacAliasInfo
*info
) {
577 ALIAS_INFO_CTR
*ctr
= NULL
;
579 if(!mem_ctx
|| !info
)
582 ctr
= talloc(mem_ctx
, ALIAS_INFO_CTR
);
588 init_samr_alias_info1(&(ctr
->alias
.info1
), info
->name
, info
->num_members
, info
->description
);
593 CacDomainInfo
*cac_MakeDomainInfo(TALLOC_CTX
*mem_ctx
, SAM_UNK_INFO_1
*info1
, SAM_UNK_INFO_2
*info2
, SAM_UNK_INFO_12
*info12
) {
594 CacDomainInfo
*info
= NULL
;
596 if(!mem_ctx
|| !info1
|| !info2
|| !info12
)
599 info
= talloc(mem_ctx
, CacDomainInfo
);
603 info
->min_pass_length
= info1
->min_length_password
;
604 info
->pass_history
= info1
->password_history
;
606 cac_InitCacTime(&(info
->expire
), info1
->expire
);
607 cac_InitCacTime(&(info
->min_pass_age
), info1
->min_passwordage
);
609 info
->server_role
= info2
->server_role
;
610 info
->num_users
= info2
->num_domain_usrs
;
611 info
->num_domain_groups
= info2
->num_domain_grps
;
612 info
->num_local_groups
= info2
->num_local_grps
;
614 /*if these have been ZERO'd out we need to know. uni_str_len will be 0*/
615 if(info2
->uni_comment
.uni_str_len
== 0) {
616 info
->comment
= talloc_strdup(mem_ctx
, "\0");
619 info
->comment
= talloc_unistr2_to_ascii(mem_ctx
, info2
->uni_comment
);
622 if(info2
->uni_domain
.uni_str_len
== 0) {
623 info
->domain_name
= talloc_strdup(mem_ctx
, "\0");
626 info
->domain_name
= talloc_unistr2_to_ascii(mem_ctx
, info2
->uni_domain
);
629 if(info2
->uni_server
.uni_str_len
== 0) {
630 info
->server_name
= talloc_strdup(mem_ctx
, "\0");
633 info
->server_name
= talloc_unistr2_to_ascii(mem_ctx
, info2
->uni_server
);
637 cac_InitCacTime(&(info
->lockout_duration
), info12
->duration
);
638 cac_InitCacTime(&(info
->lockout_reset
), info12
->reset_count
);
639 info
->num_bad_attempts
= info12
->bad_attempt_lockout
;
644 char *cac_unistr_ascii(TALLOC_CTX
*mem_ctx
, UNISTR src
) {
648 if(!mem_ctx
|| !src
.buffer
)
651 len
= unistrlen(src
.buffer
) + 1;
653 buf
= TALLOC_ZERO_ARRAY(mem_ctx
, char, len
);
657 rpcstr_pull(buf
, src
.buffer
, len
, -1, STR_TERMINATE
);
662 CacService
*cac_MakeServiceArray(TALLOC_CTX
*mem_ctx
, ENUM_SERVICES_STATUS
*svc
, uint32 num_services
) {
664 CacService
*services
= NULL
;
669 services
= TALLOC_ZERO_ARRAY(mem_ctx
, CacService
, num_services
);
673 for(i
= 0; i
< num_services
; i
++) {
674 services
[i
].service_name
= cac_unistr_ascii(mem_ctx
, svc
[i
].servicename
);
675 services
[i
].display_name
= cac_unistr_ascii(mem_ctx
, svc
[i
].displayname
);
677 if(!services
[i
].service_name
|| !services
[i
].display_name
)
680 services
[i
].status
= svc
[i
].status
;
686 int cac_InitCacServiceConfig(TALLOC_CTX
*mem_ctx
, SERVICE_CONFIG
*src
, CacServiceConfig
*dest
) {
690 dest
->exe_path
= talloc_unistr2_to_ascii(mem_ctx
, *src
->executablepath
);
694 dest
->load_order_group
= talloc_unistr2_to_ascii(mem_ctx
, *src
->loadordergroup
);
695 if(!dest
->load_order_group
)
698 dest
->dependencies
= talloc_unistr2_to_ascii(mem_ctx
, *src
->dependencies
);
699 if(!dest
->dependencies
)
702 dest
->start_name
= talloc_unistr2_to_ascii(mem_ctx
, *src
->startname
);
703 if(!dest
->start_name
)
706 dest
->display_name
= talloc_unistr2_to_ascii(mem_ctx
, *src
->displayname
);
707 if(!dest
->display_name
)
710 dest
->type
= src
->service_type
;
711 dest
->start_type
= src
->start_type
;
712 dest
->error_control
= src
->error_control
;
713 dest
->tag_id
= src
->tag_id
;