2 Unix SMB/CIFS implementation.
3 dump the remote SAM using rpc samsync operations
5 Copyright (C) Andrew Tridgell 2002
6 Copyright (C) Tim Potter 2001,2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "../utils/net.h"
26 extern DOM_SID global_sid_Builtin
;
28 static void display_group_mem_info(uint32 rid
, SAM_GROUP_MEM_INFO
*g
)
31 d_printf("Group mem %u: ", rid
);
32 for (i
=0;i
<g
->num_members
;i
++) {
33 d_printf("%u ", g
->rids
[i
]);
38 static void display_alias_info(uint32 rid
, SAM_ALIAS_INFO
*a
)
40 d_printf("Alias '%s' ", unistr2_static(&a
->uni_als_name
));
41 d_printf("desc='%s' rid=%u\n", unistr2_static(&a
->uni_als_desc
), a
->als_rid
);
44 static void display_alias_mem(uint32 rid
, SAM_ALIAS_MEM_INFO
*a
)
47 d_printf("Alias rid %u: ", rid
);
48 for (i
=0;i
<a
->num_members
;i
++) {
49 d_printf("%s ", sid_string_static(&a
->sids
[i
].sid
));
54 static void display_account_info(uint32 rid
, SAM_ACCOUNT_INFO
*a
)
56 fstring hex_nt_passwd
, hex_lm_passwd
;
57 uchar lm_passwd
[16], nt_passwd
[16];
59 /* Decode hashes from password hash */
60 sam_pwd_hash(a
->user_rid
, a
->pass
.buf_lm_pwd
, lm_passwd
, 0);
61 sam_pwd_hash(a
->user_rid
, a
->pass
.buf_nt_pwd
, nt_passwd
, 0);
63 /* Encode as strings */
64 smbpasswd_sethexpwd(hex_lm_passwd
, lm_passwd
, a
->acb_info
);
65 smbpasswd_sethexpwd(hex_nt_passwd
, nt_passwd
, a
->acb_info
);
67 printf("%s:%d:%s:%s:%s:LCT-0\n", unistr2_static(&a
->uni_acct_name
),
68 a
->user_rid
, hex_lm_passwd
, hex_nt_passwd
,
69 smbpasswd_encode_acb_info(a
->acb_info
));
72 static void display_domain_info(SAM_DOMAIN_INFO
*a
)
74 d_printf("Domain name: %s\n", unistr2_static(&a
->uni_dom_name
));
77 static void display_group_info(uint32 rid
, SAM_GROUP_INFO
*a
)
79 d_printf("Group '%s' ", unistr2_static(&a
->uni_grp_name
));
80 d_printf("desc='%s', rid=%u\n", unistr2_static(&a
->uni_grp_desc
), rid
);
83 static void display_sam_entry(SAM_DELTA_HDR
*hdr_delta
, SAM_DELTA_CTR
*delta
)
85 switch (hdr_delta
->type
) {
86 case SAM_DELTA_ACCOUNT_INFO
:
87 display_account_info(hdr_delta
->target_rid
, &delta
->account_info
);
89 case SAM_DELTA_GROUP_MEM
:
90 display_group_mem_info(hdr_delta
->target_rid
, &delta
->grp_mem_info
);
92 case SAM_DELTA_ALIAS_INFO
:
93 display_alias_info(hdr_delta
->target_rid
, &delta
->alias_info
);
95 case SAM_DELTA_ALIAS_MEM
:
96 display_alias_mem(hdr_delta
->target_rid
, &delta
->als_mem_info
);
98 case SAM_DELTA_DOMAIN_INFO
:
99 display_domain_info(&delta
->domain_info
);
101 case SAM_DELTA_GROUP_INFO
:
102 display_group_info(hdr_delta
->target_rid
, &delta
->group_info
);
105 d_printf("Unknown delta record type %d\n", hdr_delta
->type
);
111 static void dump_database(struct cli_state
*cli
, unsigned db_type
, DOM_CRED
*ret_creds
)
113 unsigned last_rid
= -1;
117 SAM_DELTA_HDR
*hdr_deltas
;
118 SAM_DELTA_CTR
*deltas
;
121 if (!(mem_ctx
= talloc_init())) {
125 d_printf("Dumping database %u\n", db_type
);
128 result
= cli_netlogon_sam_sync(cli
, mem_ctx
, ret_creds
, db_type
, last_rid
+1,
129 &num_deltas
, &hdr_deltas
, &deltas
);
130 clnt_deal_with_creds(cli
->sess_key
, &(cli
->clnt_cred
), ret_creds
);
132 for (i
= 0; i
< num_deltas
; i
++) {
133 display_sam_entry(&hdr_deltas
[i
], &deltas
[i
]);
134 last_rid
= hdr_deltas
[i
].target_rid
;
136 } while (last_rid
&& NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
138 talloc_destroy(mem_ctx
);
141 /* dump sam database via samsync rpc calls */
142 int rpc_samdump(int argc
, const char **argv
)
145 struct cli_state
*cli
= NULL
;
146 uchar trust_password
[16];
148 uint32 neg_flags
= 0x000001ff;
151 ZERO_STRUCT(ret_creds
);
153 /* Connect to remote machine */
154 if (!(cli
= net_make_ipc_connection(NET_FLAGS_ANONYMOUS
| NET_FLAGS_PDC
))) {
158 if (!cli_nt_session_open(cli
, PIPE_NETLOGON
)) {
159 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
163 if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_password
, NULL
)) {
164 d_printf("Could not retrieve domain trust secret");
168 result
= cli_nt_setup_creds(cli
, SEC_CHAN_BDC
, trust_password
, &neg_flags
, 2);
169 if (!NT_STATUS_IS_OK(result
)) {
170 d_printf("Failed to setup BDC creds\n");
174 dump_database(cli
, SAM_DATABASE_DOMAIN
, &ret_creds
);
175 dump_database(cli
, SAM_DATABASE_BUILTIN
, &ret_creds
);
176 dump_database(cli
, SAM_DATABASE_PRIVS
, &ret_creds
);
178 cli_nt_session_close(cli
);
184 cli_nt_session_close(cli
);
189 /* Convert a SAM_ACCOUNT_DELTA to a SAM_ACCOUNT. */
192 sam_account_from_delta(SAM_ACCOUNT
*account
, SAM_ACCOUNT_INFO
*delta
)
196 uchar lm_passwd
[16], nt_passwd
[16];
198 /* Username, fullname, home dir, dir drive, logon script, acct
199 desc, workstations, profile. */
201 unistr2_to_ascii(s
, &delta
->uni_acct_name
, sizeof(s
) - 1);
202 pdb_set_nt_username(account
, s
);
204 /* Unix username is the same - for sainity */
205 pdb_set_username(account
, s
);
207 unistr2_to_ascii(s
, &delta
->uni_full_name
, sizeof(s
) - 1);
208 pdb_set_fullname(account
, s
);
210 unistr2_to_ascii(s
, &delta
->uni_home_dir
, sizeof(s
) - 1);
211 pdb_set_homedir(account
, s
, True
);
213 unistr2_to_ascii(s
, &delta
->uni_dir_drive
, sizeof(s
) - 1);
214 pdb_set_dir_drive(account
, s
, True
);
216 unistr2_to_ascii(s
, &delta
->uni_logon_script
, sizeof(s
) - 1);
217 pdb_set_logon_script(account
, s
, True
);
219 unistr2_to_ascii(s
, &delta
->uni_acct_desc
, sizeof(s
) - 1);
220 pdb_set_acct_desc(account
, s
);
222 unistr2_to_ascii(s
, &delta
->uni_workstations
, sizeof(s
) - 1);
223 pdb_set_workstations(account
, s
);
225 unistr2_to_ascii(s
, &delta
->uni_profile
, sizeof(s
) - 1);
226 pdb_set_profile_path(account
, s
, True
);
228 /* User and group sid */
230 sid_copy(&sid
, get_global_sam_sid());
231 sid_append_rid(&sid
, delta
->user_rid
);
232 pdb_set_user_sid(account
, &sid
);
234 sid_copy(&sid
, get_global_sam_sid());
235 sid_append_rid(&sid
, delta
->group_rid
);
236 pdb_set_group_sid(account
, &sid
);
238 /* Logon and password information */
240 pdb_set_logon_time(account
, nt_time_to_unix(&delta
->logon_time
), True
);
241 pdb_set_logoff_time(account
, nt_time_to_unix(&delta
->logoff_time
),
243 pdb_set_logon_divs(account
, delta
->logon_divs
);
245 /* TODO: logon hours */
246 /* TODO: bad password count */
247 /* TODO: logon count */
249 pdb_set_pass_last_set_time(
250 account
, nt_time_to_unix(&delta
->pwd_last_set_time
));
252 pdb_set_kickoff_time(account
, get_time_t_max(), True
);
254 /* Decode hashes from password hash */
255 sam_pwd_hash(delta
->user_rid
, delta
->pass
.buf_lm_pwd
, lm_passwd
, 0);
256 sam_pwd_hash(delta
->user_rid
, delta
->pass
.buf_nt_pwd
, nt_passwd
, 0);
257 pdb_set_nt_passwd(account
, nt_passwd
);
258 pdb_set_lanman_passwd(account
, lm_passwd
);
260 /* TODO: account expiry time */
262 pdb_set_acct_ctrl(account
, delta
->acb_info
);
267 fetch_account_info(uint32 rid
, SAM_ACCOUNT_INFO
*delta
)
272 SAM_ACCOUNT
*sam_account
=NULL
;
276 fstrcpy(account
, unistr2_static(&delta
->uni_acct_name
));
277 d_printf("Creating account: %s\n", account
);
279 if (!NT_STATUS_IS_OK(nt_ret
= pdb_init_sam(&sam_account
)))
282 if (!pdb_getsampwnam(sam_account
, account
)) {
285 pdb_free_sam(&sam_account
);
287 /* Create appropriate user */
288 if (delta
->acb_info
& ACB_NORMAL
) {
289 pstrcpy(add_script
, lp_adduser_script());
290 } else if ( (delta
->acb_info
& ACB_WSTRUST
) ||
291 (delta
->acb_info
& ACB_SVRTRUST
) ) {
292 pstrcpy(add_script
, lp_addmachine_script());
294 DEBUG(1, ("Unknown user type: %s\n",
295 smbpasswd_encode_acb_info(delta
->acb_info
)));
296 pdb_free_sam(&sam_account
);
297 return NT_STATUS_NO_SUCH_USER
;
301 all_string_sub(add_script
, "%u", account
,
303 add_ret
= smbrun(add_script
,NULL
);
304 DEBUG(1,("fetch_account: Running the command `%s' "
305 "gave %d\n", add_script
, add_ret
));
307 pw
= getpwnam_alloc(account
);
309 nt_ret
= pdb_init_sam_pw(&sam_account
, pw
);
311 if (!NT_STATUS_IS_OK(nt_ret
)) {
313 pdb_free_sam(&sam_account
);
318 DEBUG(3, ("Could not create account %s\n", account
));
319 pdb_free_sam(&sam_account
);
320 return NT_STATUS_NO_SUCH_USER
;
324 sam_account_from_delta(sam_account
, delta
);
326 if (!pdb_add_sam_account(sam_account
)) {
327 DEBUG(1, ("SAM Account for %s already existed, updating\n",
329 pdb_update_sam_account(sam_account
);
332 if (!get_group_map_from_sid(*pdb_get_group_sid(sam_account
),
334 DEBUG(0, ("Primary group of %s has no mapping!\n",
335 pdb_get_username(sam_account
)));
336 pdb_free_sam(&sam_account
);
337 return NT_STATUS_NO_SUCH_GROUP
;
340 if (!(grp
= getgrgid(map
.gid
))) {
341 DEBUG(0, ("Could not find unix group %d\n", map
.gid
));
342 pdb_free_sam(&sam_account
);
343 return NT_STATUS_NO_SUCH_GROUP
;
346 smb_set_primary_group(grp
->gr_name
, pdb_get_username(sam_account
));
348 pdb_free_sam(&sam_account
);
353 fetch_group_info(uint32 rid
, SAM_GROUP_INFO
*delta
)
357 struct group
*grp
= NULL
;
361 int flag
= TDB_INSERT
;
364 unistr2_to_ascii(name
, &delta
->uni_grp_name
, sizeof(name
)-1);
365 unistr2_to_ascii(comment
, &delta
->uni_grp_desc
, sizeof(comment
)-1);
367 if ((grp
= getgrnam(name
)) == NULL
)
368 smb_create_group(name
, &gid
);
370 if ((grp
= getgrgid(gid
)) == NULL
)
371 return NT_STATUS_ACCESS_DENIED
;
373 /* add the group to the mapping table */
374 sid_copy(&group_sid
, get_global_sam_sid());
375 sid_append_rid(&group_sid
, rid
);
376 sid_to_string(sid_string
, &group_sid
);
378 if (get_group_map_from_sid(group_sid
, &map
, False
)) {
379 grp
= getgrgid(map
.gid
);
380 flag
= 0; /* Don't TDB_INSERT, mapping exists */
386 /* No group found from mapping, find it from its name. */
387 if ((grp
= getgrnam(name
)) == NULL
) {
388 /* No appropriate group found, create one */
389 d_printf("Creating unix group: '%s'\n", name
);
390 if (smb_create_group(name
, &new_gid
) != 0)
391 return NT_STATUS_ACCESS_DENIED
;
394 if ((grp
= getgrgid(new_gid
)) == NULL
)
395 return NT_STATUS_ACCESS_DENIED
;
398 map
.gid
= grp
->gr_gid
;
400 map
.sid_name_use
= SID_NAME_DOM_GRP
;
401 fstrcpy(map
.nt_name
, name
);
402 fstrcpy(map
.comment
, comment
);
404 map
.priv_set
.count
= 0;
405 map
.priv_set
.set
= NULL
;
407 add_mapping_entry(&map
, flag
);
413 fetch_group_mem_info(uint32 rid
, SAM_GROUP_MEM_INFO
*delta
)
416 TALLOC_CTX
*t
= NULL
;
417 char **nt_members
= NULL
;
423 if (delta
->num_members
== 0) {
427 sid_copy(&group_sid
, get_global_sam_sid());
428 sid_append_rid(&group_sid
, rid
);
430 if (!get_domain_group_from_sid(group_sid
, &map
, False
)) {
431 DEBUG(0, ("Could not find global group %d\n", rid
));
432 return NT_STATUS_NO_SUCH_GROUP
;
435 if (!(grp
= getgrgid(map
.gid
))) {
436 DEBUG(0, ("Could not find unix group %d\n", map
.gid
));
437 return NT_STATUS_NO_SUCH_GROUP
;
440 d_printf("Group members of %s: ", grp
->gr_name
);
442 if (!(t
= talloc_init())) {
443 DEBUG(0, ("could not talloc_init\n"));
444 return NT_STATUS_NO_MEMORY
;
447 nt_members
= talloc_zero(t
, sizeof(char *) * delta
->num_members
);
449 for (i
=0; i
<delta
->num_members
; i
++) {
451 SAM_ACCOUNT
*member
= NULL
;
454 if (!NT_STATUS_IS_OK(nt_status
= pdb_init_sam_talloc(t
, &member
))) {
459 sid_copy(&member_sid
, get_global_sam_sid());
460 sid_append_rid(&member_sid
, delta
->rids
[i
]);
462 if (!pdb_getsampwsid(member
, &member_sid
)) {
463 DEBUG(1, ("Found bogus group member: %d\n",
465 pdb_free_sam(&member
);
469 if (pdb_get_group_rid(member
) == rid
) {
470 d_printf("%s(primary),", pdb_get_username(member
));
471 pdb_free_sam(&member
);
475 d_printf("%s,", pdb_get_username(member
));
476 nt_members
[i
] = talloc_strdup(t
, pdb_get_username(member
));
477 pdb_free_sam(&member
);
482 unix_members
= grp
->gr_mem
;
484 while (*unix_members
) {
485 BOOL is_nt_member
= False
;
486 for (i
=0; i
<delta
->num_members
; i
++) {
487 if (nt_members
[i
] == NULL
) {
488 /* This was a primary group */
492 if (strcmp(*unix_members
, nt_members
[i
]) == 0) {
498 /* We look at a unix group member that is not
499 an nt group member. So, remove it. NT is
501 smb_delete_user_group(grp
->gr_name
, *unix_members
);
506 for (i
=0; i
<delta
->num_members
; i
++) {
507 BOOL is_unix_member
= False
;
509 if (nt_members
[i
] == NULL
) {
510 /* This was the primary group */
514 unix_members
= grp
->gr_mem
;
516 while (*unix_members
) {
517 if (strcmp(*unix_members
, nt_members
[i
]) == 0) {
518 is_unix_member
= True
;
524 if (!is_unix_member
) {
525 /* We look at a nt group member that is not a
526 unix group member currently. So, add the nt
528 smb_add_user_group(grp
->gr_name
, nt_members
[i
]);
536 static NTSTATUS
fetch_alias_info(uint32 rid
, SAM_ALIAS_INFO
*delta
,
541 struct group
*grp
= NULL
;
545 int insert_flag
= TDB_INSERT
;
547 unistr2_to_ascii(name
, &delta
->uni_als_name
, sizeof(name
)-1);
548 unistr2_to_ascii(comment
, &delta
->uni_als_desc
, sizeof(comment
)-1);
550 /* Find out whether the group is already mapped */
551 sid_copy(&alias_sid
, &dom_sid
);
552 sid_append_rid(&alias_sid
, rid
);
553 sid_to_string(sid_string
, &alias_sid
);
555 if (get_group_map_from_sid(alias_sid
, &map
, False
)) {
556 grp
= getgrgid(map
.gid
);
557 insert_flag
= 0; /* Don't TDB_INSERT, mapping exists */
562 /* No group found from mapping, find it from its name. */
563 if ((grp
= getgrnam(name
)) == NULL
) {
564 /* No appropriate group found, create one */
565 d_printf("Creating unix group: '%s'\n", name
);
566 if (smb_create_group(name
, &new_gid
) != 0)
567 return NT_STATUS_ACCESS_DENIED
;
570 if ((grp
= getgrgid(new_gid
)) == NULL
)
571 return NT_STATUS_ACCESS_DENIED
;
574 map
.gid
= grp
->gr_gid
;
576 map
.sid_name_use
= SID_NAME_ALIAS
;
578 fstrcpy(map
.nt_name
, name
);
579 fstrcpy(map
.comment
, comment
);
581 map
.priv_set
.count
= 0;
582 map
.priv_set
.set
= NULL
;
584 add_mapping_entry(&map
, insert_flag
);
590 fetch_alias_mem(uint32 rid
, SAM_ALIAS_MEM_INFO
*delta
, DOM_SID dom_sid
)
597 fetch_sam_entry(SAM_DELTA_HDR
*hdr_delta
, SAM_DELTA_CTR
*delta
,
600 switch(hdr_delta
->type
) {
601 case SAM_DELTA_ACCOUNT_INFO
:
602 fetch_account_info(hdr_delta
->target_rid
,
603 &delta
->account_info
);
605 case SAM_DELTA_GROUP_INFO
:
606 fetch_group_info(hdr_delta
->target_rid
,
609 case SAM_DELTA_GROUP_MEM
:
610 fetch_group_mem_info(hdr_delta
->target_rid
,
611 &delta
->grp_mem_info
);
613 case SAM_DELTA_ALIAS_INFO
:
614 fetch_alias_info(hdr_delta
->target_rid
,
615 &delta
->alias_info
, dom_sid
);
617 case SAM_DELTA_ALIAS_MEM
:
618 fetch_alias_mem(hdr_delta
->target_rid
,
619 &delta
->als_mem_info
, dom_sid
);
622 d_printf("Unknown delta record type %d\n", hdr_delta
->type
);
628 fetch_database(struct cli_state
*cli
, unsigned db_type
, DOM_CRED
*ret_creds
,
631 unsigned last_rid
= -1;
635 SAM_DELTA_HDR
*hdr_deltas
;
636 SAM_DELTA_CTR
*deltas
;
639 if (!(mem_ctx
= talloc_init())) {
643 d_printf("Fetching database %u\n", db_type
);
646 result
= cli_netlogon_sam_sync(cli
, mem_ctx
, ret_creds
,
649 &hdr_deltas
, &deltas
);
650 clnt_deal_with_creds(cli
->sess_key
, &(cli
->clnt_cred
),
653 for (i
= 0; i
< num_deltas
; i
++) {
654 fetch_sam_entry(&hdr_deltas
[i
], &deltas
[i
], dom_sid
);
655 last_rid
= hdr_deltas
[i
].target_rid
;
657 } while (last_rid
&& NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
659 talloc_destroy(mem_ctx
);
662 /* dump sam database via samsync rpc calls */
663 int rpc_vampire(int argc
, const char **argv
)
666 struct cli_state
*cli
= NULL
;
667 uchar trust_password
[16];
669 uint32 neg_flags
= 0x000001ff;
672 ZERO_STRUCT(ret_creds
);
674 /* Connect to remote machine */
675 if (!(cli
= net_make_ipc_connection(NET_FLAGS_ANONYMOUS
|
680 if (!cli_nt_session_open(cli
, PIPE_NETLOGON
)) {
681 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
685 if (!secrets_fetch_trust_account_password(lp_workgroup(),
686 trust_password
, NULL
)) {
687 d_printf("Could not retrieve domain trust secret");
691 result
= cli_nt_setup_creds(cli
, SEC_CHAN_BDC
, trust_password
,
693 if (!NT_STATUS_IS_OK(result
)) {
694 d_printf("Failed to setup BDC creds\n");
698 dom_sid
= *get_global_sam_sid();
699 fetch_database(cli
, SAM_DATABASE_DOMAIN
, &ret_creds
, dom_sid
);
701 sid_copy(&dom_sid
, &global_sid_Builtin
);
702 fetch_database(cli
, SAM_DATABASE_BUILTIN
, &ret_creds
, dom_sid
);
704 /* Currently we crash on PRIVS somewhere in unmarshalling */
705 /* Dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds); */
707 cli_nt_session_close(cli
);
713 cli_nt_session_close(cli
);