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
) {
28 struct rpc_pipe_client
*pipe_hnd
= NULL
;
33 if(hnd
->_internal
.pipes
[pi_idx
] == False
) {
34 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
38 srv
= cac_GetServer(hnd
);
40 hnd
->status
= NT_STATUS_INVALID_CONNECTION
;
44 pipe_hnd
= srv
->cli
.pipe_list
;
46 while(pipe_hnd
!= NULL
&& pipe_hnd
->pipe_idx
!= pi_idx
)
47 pipe_hnd
= pipe_hnd
->next
;
52 /*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)*/
53 int cac_ParseRegPath(char *path
, uint32
*reg_type
, char **key_name
) {
58 if(strncmp(path
, "HKLM", 4) == 0) {
59 *reg_type
= HKEY_LOCAL_MACHINE
;
60 *key_name
= (path
[4] == '\\') ? path
+ 5 : NULL
;
62 else if(strncmp(path
, "HKEY_LOCAL_MACHINE", 18) == 0) {
63 *reg_type
= HKEY_LOCAL_MACHINE
;
64 *key_name
= (path
[18] == '\\') ? path
+ 19 : NULL
;
66 else if(strncmp(path
, "HKCR", 4) == 0) {
67 *reg_type
= HKEY_CLASSES_ROOT
;
68 *key_name
= (path
[4] == '\\') ? path
+ 5 : NULL
;
70 else if(strncmp(path
, "HKEY_CLASSES_ROOT", 17) == 0) {
71 *reg_type
= HKEY_CLASSES_ROOT
;
72 *key_name
= (path
[17] == '\\') ? path
+ 18 : NULL
;
74 else if(strncmp(path
, "HKU", 3) == 0) {
75 *reg_type
= HKEY_USERS
;
76 *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
;
82 else if(strncmp(path
, "HKPD", 4) == 0) {
83 *reg_type
= HKEY_PERFORMANCE_DATA
;
84 *key_name
= (path
[4] == '\\') ? path
+ 5 : NULL
;
86 else if(strncmp(path
, "HKEY_PERFORMANCE_DATA", 21) == 0) {
87 *reg_type
= HKEY_PERFORMANCE_DATA
;
88 *key_name
= (path
[21] == '\\') ? path
+ 22 : NULL
;
99 RPC_DATA_BLOB
*cac_MakeRpcDataBlob(TALLOC_CTX
*mem_ctx
, uint32 data_type
, REG_VALUE_DATA data
) {
100 RPC_DATA_BLOB
*blob
= NULL
;
105 uint32 multi_idx
= 0;
107 blob
= talloc(mem_ctx
, RPC_DATA_BLOB
);
116 init_rpc_blob_str(blob
, data
.reg_sz
, strlen(data
.reg_sz
) + 1);
120 init_rpc_blob_str(blob
, data
.reg_expand_sz
, strlen(data
.reg_sz
) + 1);
124 init_rpc_blob_bytes(blob
, data
.reg_binary
.data
, data
.reg_binary
.data_length
);
128 init_rpc_blob_uint32(blob
, data
.reg_dword
);
132 init_rpc_blob_uint32(blob
, data
.reg_dword_be
);
136 /*need to find the size*/
137 for(i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++) {
138 size
+= strlen(data
.reg_multi_sz
.strings
[i
]) + 1;
141 /**need a whole bunch of unicode strings in a row (seperated by null characters), with an extra null-character on the end*/
143 multi
= TALLOC_ZERO_ARRAY(mem_ctx
, uint8
, (size
+ 1)*2); /*size +1 for the extra null character*/
149 /*do it using rpcstr_push()*/
151 for(i
= 0; i
< data
.reg_multi_sz
.num_strings
; i
++) {
152 len
= strlen(data
.reg_multi_sz
.strings
[i
]) + 1;
154 rpcstr_push((multi
+ multi_idx
), data
.reg_multi_sz
.strings
[i
], len
* 2, STR_TERMINATE
);
156 /* x2 becuase it is a uint8 buffer*/
157 multi_idx
+= len
* 2;
160 /*now initialize the buffer as binary data*/
161 init_rpc_blob_bytes(blob
, multi
, (size
+ 1)*2);
170 if(!(blob
->buffer
)) {
178 /*turns a string in a uint16 array to a char array*/
179 char *cac_unistr_to_str(TALLOC_CTX
*mem_ctx
, uint16
*src
, int num_bytes
) {
186 /*don't allocate more space than we need*/
187 while( (str_len
) < num_bytes
/2 && src
[str_len
] != 0x0000)
190 /*need room for a '\0'*/
193 buf
= talloc_array(mem_ctx
, char, str_len
);
198 for(i
= 0; i
< num_bytes
/2; i
++) {
199 buf
[i
] = ((char *)src
)[2*i
];
202 buf
[str_len
- 1] = '\0';
207 REG_VALUE_DATA
*cac_MakeRegValueData(TALLOC_CTX
*mem_ctx
, uint32 data_type
, REGVAL_BUFFER buf
) {
208 REG_VALUE_DATA
*data
;
212 /*all of the following used for MULTI_SZ data*/
215 uint32 multi_idx
= 0;
216 uint32 num_strings
= 0;
217 char **strings
= NULL
;
219 data
= talloc(mem_ctx
, REG_VALUE_DATA
);
227 data
->reg_sz
= cac_unistr_to_str(mem_ctx
, buf
.buffer
, buf
.buf_len
);
237 data
->reg_expand_sz
= cac_unistr_to_str(mem_ctx
, buf
.buffer
, buf
.buf_len
);
239 if(!data
->reg_expand_sz
) {
250 data
->reg_binary
.data_length
= size
;
252 data
->reg_binary
.data
= talloc_memdup(mem_ctx
, buf
.buffer
, size
);
253 if(!data
->reg_binary
.data
) {
261 data
->reg_dword
= *((uint32
*)buf
.buffer
);
265 data
->reg_dword_be
= *((uint32
*)buf
.buffer
);
271 /*find out how many strings there are. size is # of bytes and we want to work uint16*/
272 for(i
= 0; i
< (size
/2 - 1); i
++) {
273 if(buf
.buffer
[i
] == 0x0000)
276 /*buffer is suppsed to be terminated with \0\0, but it might not be*/
277 if(buf
.buffer
[i
] == 0x0000 && buf
.buffer
[i
+ 1] == 0x0000)
281 strings
= talloc_array(mem_ctx
, char *, num_strings
);
288 if(num_strings
== 0) /*then our work here is done*/
291 for(i
= 0; i
< num_strings
; i
++) {
292 /*find out how many characters are in this string*/
294 /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0*/
295 while( multi_idx
+ len
< size
/2 && buf
.buffer
[multi_idx
+ len
] != 0x0000)
298 /*stay aware of the \0\0*/
301 strings
[i
] = TALLOC_ZERO_ARRAY(mem_ctx
, char, len
);
303 /*pull out the unicode string*/
304 rpcstr_pull(strings
[i
], (buf
.buffer
+ multi_idx
) , len
, -1, STR_TERMINATE
);
306 /*keep track of where we are in the bigger array*/
310 data
->reg_multi_sz
.num_strings
= num_strings
;
311 data
->reg_multi_sz
.strings
= strings
;
323 SAM_USERINFO_CTR
*cac_MakeUserInfoCtr(TALLOC_CTX
*mem_ctx
, CacUserInfo
*info
) {
324 SAM_USERINFO_CTR
*ctr
= NULL
;
326 /*the flags we are 'setting'- include/passdb.h*/
327 uint32 flags
= ACCT_USERNAME
| ACCT_FULL_NAME
| ACCT_PRIMARY_GID
| ACCT_ADMIN_DESC
| ACCT_DESCRIPTION
|
328 ACCT_HOME_DIR
| ACCT_HOME_DRIVE
| ACCT_LOGON_SCRIPT
| ACCT_PROFILE
| ACCT_WORKSTATIONS
|
334 NTTIME pass_last_set_time
;
335 NTTIME pass_can_change_time
;
336 NTTIME pass_must_change_time
;
349 ctr
= talloc(mem_ctx
, SAM_USERINFO_CTR
);
353 ZERO_STRUCTP(ctr
->info
.id23
);
355 ctr
->info
.id21
= talloc(mem_ctx
, SAM_USER_INFO_21
);
359 ctr
->switch_value
= 21;
361 ZERO_STRUCTP(ctr
->info
.id21
);
363 unix_to_nt_time(&logon_time
, info
->logon_time
);
364 unix_to_nt_time(&logoff_time
, info
->logoff_time
);
365 unix_to_nt_time(&kickoff_time
, info
->kickoff_time
);
366 unix_to_nt_time(&pass_last_set_time
, info
->pass_last_set_time
);
367 unix_to_nt_time(&pass_can_change_time
, info
->pass_can_change_time
);
368 unix_to_nt_time(&pass_must_change_time
, info
->pass_must_change_time
);
370 /*initialize the strings*/
371 init_unistr2(&user_name
, info
->username
, STR_TERMINATE
);
372 init_unistr2(&full_name
, info
->full_name
, STR_TERMINATE
);
373 init_unistr2(&home_dir
, info
->home_dir
, STR_TERMINATE
);
374 init_unistr2(&dir_drive
, info
->home_drive
, STR_TERMINATE
);
375 init_unistr2(&log_scr
, info
->logon_script
, STR_TERMINATE
);
376 init_unistr2(&prof_path
, info
->profile_path
, STR_TERMINATE
);
377 init_unistr2(&desc
, info
->description
, STR_TERMINATE
);
378 init_unistr2(&wkstas
, info
->workstations
, STR_TERMINATE
);
379 init_unistr2(&unk
, "\0", STR_TERMINATE
);
380 init_unistr2(&mung_dial
, info
->dial
, STR_TERMINATE
);
382 /*manually set passmustchange*/
383 ctr
->info
.id21
->passmustchange
= (info
->pass_must_change
) ? 0x01 : 0x00;
385 init_sam_user_info21W(ctr
->info
.id21
,
390 &pass_can_change_time
,
391 &pass_must_change_time
,
410 info
->bad_passwd_count
,
417 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
) {
433 CacUserInfo
*info
= NULL
;
434 SAM_USER_INFO_21
*id21
= NULL
;
436 if(!ctr
|| ctr
->switch_value
!= 21)
439 info
= talloc(mem_ctx
, CacUserInfo
);
443 id21
= ctr
->info
.id21
;
447 info
->logon_time
= nt_time_to_unix(&id21
->logon_time
);
448 info
->logoff_time
= nt_time_to_unix(&id21
->logoff_time
);
449 info
->kickoff_time
= nt_time_to_unix(&id21
->kickoff_time
);
450 info
->pass_last_set_time
= nt_time_to_unix(&id21
->pass_last_set_time
);
451 info
->pass_can_change_time
= nt_time_to_unix(&id21
->pass_can_change_time
);
452 info
->pass_must_change_time
= nt_time_to_unix(&id21
->pass_must_change_time
);
454 info
->username
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_user_name
);
458 info
->full_name
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_full_name
);
462 info
->home_dir
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_home_dir
);
466 info
->home_drive
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_dir_drive
);
467 if(!info
->home_drive
)
470 info
->logon_script
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_logon_script
);
471 if(!info
->logon_script
)
474 info
->profile_path
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_profile_path
);
475 if(!info
->profile_path
)
478 info
->description
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_acct_desc
);
479 if(!info
->description
)
482 info
->workstations
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_workstations
);
483 if(!info
->workstations
)
486 info
->dial
= talloc_unistr2_to_ascii(mem_ctx
, id21
->uni_munged_dial
);
490 info
->rid
= id21
->user_rid
;
491 info
->group_rid
= id21
->group_rid
;
492 info
->acb_mask
= id21
->acb_info
;
493 info
->bad_passwd_count
= id21
->bad_password_count
;
494 info
->logon_count
= id21
->logon_count
;
496 memcpy(info
->nt_password
, id21
->nt_pwd
, 8);
497 memcpy(info
->lm_password
, id21
->lm_pwd
, 8);
499 info
->logon_hours
= talloc_memdup(mem_ctx
, &(id21
->logon_hrs
), sizeof(LOGON_HRS
));
500 if(!info
->logon_hours
)
503 info
->pass_must_change
= (id21
->passmustchange
) ? True
: False
;
508 CacGroupInfo
*cac_MakeGroupInfo(TALLOC_CTX
*mem_ctx
, GROUP_INFO_CTR
*ctr
) {
509 CacGroupInfo
*info
= NULL
;
511 if(!mem_ctx
|| !ctr
|| ctr
->switch_value1
!= 1)
514 info
= talloc(mem_ctx
, CacGroupInfo
);
518 info
->name
= talloc_unistr2_to_ascii(mem_ctx
, ctr
->group
.info1
.uni_acct_name
);
522 info
->description
= talloc_unistr2_to_ascii(mem_ctx
, ctr
->group
.info1
.uni_acct_desc
);
523 if(!info
->description
)
526 info
->num_members
= ctr
->group
.info1
.num_members
;
531 GROUP_INFO_CTR
*cac_MakeGroupInfoCtr(TALLOC_CTX
*mem_ctx
, CacGroupInfo
*info
) {
532 GROUP_INFO_CTR
*ctr
= NULL
;
534 if(!mem_ctx
|| !info
)
537 ctr
= talloc(mem_ctx
, GROUP_INFO_CTR
);
541 ctr
->switch_value1
= 1;
543 init_samr_group_info1(&(ctr
->group
.info1
), info
->name
, info
->description
, info
->num_members
);
548 CacAliasInfo
*cac_MakeAliasInfo(TALLOC_CTX
*mem_ctx
, ALIAS_INFO_CTR ctr
) {
549 CacGroupInfo
*info
= NULL
;
551 if(!mem_ctx
|| ctr
.level
!= 1)
554 info
= talloc(mem_ctx
, CacAliasInfo
);
558 info
->name
= talloc_unistr2_to_ascii(mem_ctx
, *(ctr
.alias
.info1
.name
.string
));
562 info
->description
= talloc_unistr2_to_ascii(mem_ctx
, *(ctr
.alias
.info1
.description
.string
));
566 info
->num_members
= ctr
.alias
.info1
.num_member
;
571 ALIAS_INFO_CTR
*cac_MakeAliasInfoCtr(TALLOC_CTX
*mem_ctx
, CacAliasInfo
*info
) {
572 ALIAS_INFO_CTR
*ctr
= NULL
;
574 if(!mem_ctx
|| !info
)
577 ctr
= talloc(mem_ctx
, ALIAS_INFO_CTR
);
583 init_samr_alias_info1(&(ctr
->alias
.info1
), info
->name
, info
->num_members
, info
->description
);
588 CacDomainInfo
*cac_MakeDomainInfo(TALLOC_CTX
*mem_ctx
, SAM_UNK_INFO_1
*info1
, SAM_UNK_INFO_2
*info2
, SAM_UNK_INFO_12
*info12
) {
589 CacDomainInfo
*info
= NULL
;
591 if(!mem_ctx
|| !info1
|| !info2
|| !info12
)
594 info
= talloc(mem_ctx
, CacDomainInfo
);
598 info
->min_pass_length
= info1
->min_length_password
;
599 info
->pass_history
= info1
->password_history
;
601 cac_InitCacTime(&(info
->expire
), info1
->expire
);
602 cac_InitCacTime(&(info
->min_pass_age
), info1
->min_passwordage
);
604 info
->server_role
= info2
->server_role
;
605 info
->num_users
= info2
->num_domain_usrs
;
606 info
->num_domain_groups
= info2
->num_domain_grps
;
607 info
->num_local_groups
= info2
->num_local_grps
;
609 /*if these have been ZERO'd out we need to know. uni_str_len will be 0*/
610 if(info2
->uni_comment
.uni_str_len
== 0) {
611 info
->comment
= talloc_strdup(mem_ctx
, "\0");
614 info
->comment
= talloc_unistr2_to_ascii(mem_ctx
, info2
->uni_comment
);
617 if(info2
->uni_domain
.uni_str_len
== 0) {
618 info
->domain_name
= talloc_strdup(mem_ctx
, "\0");
621 info
->domain_name
= talloc_unistr2_to_ascii(mem_ctx
, info2
->uni_domain
);
624 if(info2
->uni_server
.uni_str_len
== 0) {
625 info
->server_name
= talloc_strdup(mem_ctx
, "\0");
628 info
->server_name
= talloc_unistr2_to_ascii(mem_ctx
, info2
->uni_server
);
632 cac_InitCacTime(&(info
->lockout_duration
), info12
->duration
);
633 cac_InitCacTime(&(info
->lockout_reset
), info12
->reset_count
);
634 info
->num_bad_attempts
= info12
->bad_attempt_lockout
;
639 char *cac_unistr_ascii(TALLOC_CTX
*mem_ctx
, UNISTR src
) {
643 if(!mem_ctx
|| !src
.buffer
)
646 len
= unistrlen(src
.buffer
) + 1;
648 buf
= TALLOC_ZERO_ARRAY(mem_ctx
, char, len
);
652 rpcstr_pull(buf
, src
.buffer
, len
, -1, STR_TERMINATE
);
657 CacService
*cac_MakeServiceArray(TALLOC_CTX
*mem_ctx
, ENUM_SERVICES_STATUS
*svc
, uint32 num_services
) {
659 CacService
*services
= NULL
;
664 services
= TALLOC_ZERO_ARRAY(mem_ctx
, CacService
, num_services
);
668 for(i
= 0; i
< num_services
; i
++) {
669 services
[i
].service_name
= cac_unistr_ascii(mem_ctx
, svc
[i
].servicename
);
670 services
[i
].display_name
= cac_unistr_ascii(mem_ctx
, svc
[i
].displayname
);
672 if(!services
[i
].service_name
|| !services
[i
].display_name
)
675 services
[i
].status
= svc
[i
].status
;
681 int cac_InitCacServiceConfig(TALLOC_CTX
*mem_ctx
, SERVICE_CONFIG
*src
, CacServiceConfig
*dest
) {
685 dest
->exe_path
= talloc_unistr2_to_ascii(mem_ctx
, *src
->executablepath
);
689 dest
->load_order_group
= talloc_unistr2_to_ascii(mem_ctx
, *src
->loadordergroup
);
690 if(!dest
->load_order_group
)
693 dest
->dependencies
= talloc_unistr2_to_ascii(mem_ctx
, *src
->dependencies
);
694 if(!dest
->dependencies
)
697 dest
->start_name
= talloc_unistr2_to_ascii(mem_ctx
, *src
->startname
);
698 if(!dest
->start_name
)
701 dest
->display_name
= talloc_unistr2_to_ascii(mem_ctx
, *src
->displayname
);
702 if(!dest
->display_name
)
705 dest
->type
= src
->service_type
;
706 dest
->start_type
= src
->start_type
;
707 dest
->error_control
= src
->error_control
;
708 dest
->tag_id
= src
->tag_id
;