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
7 Modified by Volker Lendecke 2002
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "../utils/net.h"
27 extern DOM_SID global_sid_Builtin
;
29 static void display_group_mem_info(uint32 rid
, SAM_GROUP_MEM_INFO
*g
)
32 d_printf("Group mem %u: ", rid
);
33 for (i
=0;i
<g
->num_members
;i
++) {
34 d_printf("%u ", g
->rids
[i
]);
39 static void display_alias_info(uint32 rid
, SAM_ALIAS_INFO
*a
)
41 d_printf("Alias '%s' ", unistr2_static(&a
->uni_als_name
));
42 d_printf("desc='%s' rid=%u\n", unistr2_static(&a
->uni_als_desc
), a
->als_rid
);
45 static void display_alias_mem(uint32 rid
, SAM_ALIAS_MEM_INFO
*a
)
48 d_printf("Alias rid %u: ", rid
);
49 for (i
=0;i
<a
->num_members
;i
++) {
50 d_printf("%s ", sid_string_static(&a
->sids
[i
].sid
));
55 static void display_account_info(uint32 rid
, SAM_ACCOUNT_INFO
*a
)
57 fstring hex_nt_passwd
, hex_lm_passwd
;
58 uchar lm_passwd
[16], nt_passwd
[16];
59 static uchar zero_buf
[16];
61 /* Decode hashes from password hash (if they are not NULL) */
63 if (memcmp(a
->pass
.buf_lm_pwd
, zero_buf
, 16) != 0) {
64 sam_pwd_hash(a
->user_rid
, a
->pass
.buf_lm_pwd
, lm_passwd
, 0);
65 smbpasswd_sethexpwd(hex_lm_passwd
, lm_passwd
, a
->acb_info
);
67 smbpasswd_sethexpwd(hex_lm_passwd
, NULL
, 0);
70 if (memcmp(a
->pass
.buf_nt_pwd
, zero_buf
, 16) != 0) {
71 sam_pwd_hash(a
->user_rid
, a
->pass
.buf_nt_pwd
, nt_passwd
, 0);
72 smbpasswd_sethexpwd(hex_nt_passwd
, nt_passwd
, a
->acb_info
);
74 smbpasswd_sethexpwd(hex_nt_passwd
, NULL
, 0);
77 printf("%s:%d:%s:%s:%s:LCT-0\n", unistr2_static(&a
->uni_acct_name
),
78 a
->user_rid
, hex_lm_passwd
, hex_nt_passwd
,
79 smbpasswd_encode_acb_info(a
->acb_info
));
82 static void display_domain_info(SAM_DOMAIN_INFO
*a
)
84 d_printf("Domain name: %s\n", unistr2_static(&a
->uni_dom_name
));
87 static void display_group_info(uint32 rid
, SAM_GROUP_INFO
*a
)
89 d_printf("Group '%s' ", unistr2_static(&a
->uni_grp_name
));
90 d_printf("desc='%s', rid=%u\n", unistr2_static(&a
->uni_grp_desc
), rid
);
93 static void display_sam_entry(SAM_DELTA_HDR
*hdr_delta
, SAM_DELTA_CTR
*delta
)
95 switch (hdr_delta
->type
) {
96 case SAM_DELTA_ACCOUNT_INFO
:
97 display_account_info(hdr_delta
->target_rid
, &delta
->account_info
);
99 case SAM_DELTA_GROUP_MEM
:
100 display_group_mem_info(hdr_delta
->target_rid
, &delta
->grp_mem_info
);
102 case SAM_DELTA_ALIAS_INFO
:
103 display_alias_info(hdr_delta
->target_rid
, &delta
->alias_info
);
105 case SAM_DELTA_ALIAS_MEM
:
106 display_alias_mem(hdr_delta
->target_rid
, &delta
->als_mem_info
);
108 case SAM_DELTA_DOMAIN_INFO
:
109 display_domain_info(&delta
->domain_info
);
111 case SAM_DELTA_GROUP_INFO
:
112 display_group_info(hdr_delta
->target_rid
, &delta
->group_info
);
115 d_printf("Unknown delta record type %d\n", hdr_delta
->type
);
121 static void dump_database(struct cli_state
*cli
, unsigned db_type
, DOM_CRED
*ret_creds
)
123 unsigned sync_context
= 0;
127 SAM_DELTA_HDR
*hdr_deltas
;
128 SAM_DELTA_CTR
*deltas
;
131 if (!(mem_ctx
= talloc_init("dump_database"))) {
135 d_printf("Dumping database %u\n", db_type
);
138 result
= cli_netlogon_sam_sync(cli
, mem_ctx
, ret_creds
, db_type
,
140 &num_deltas
, &hdr_deltas
, &deltas
);
141 clnt_deal_with_creds(cli
->sess_key
, &(cli
->clnt_cred
), ret_creds
);
142 for (i
= 0; i
< num_deltas
; i
++) {
143 display_sam_entry(&hdr_deltas
[i
], &deltas
[i
]);
146 } while (NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
148 talloc_destroy(mem_ctx
);
151 /* dump sam database via samsync rpc calls */
152 int rpc_samdump(int argc
, const char **argv
)
155 struct cli_state
*cli
= NULL
;
156 uchar trust_password
[16];
158 uint32 neg_flags
= 0x000001ff;
161 ZERO_STRUCT(ret_creds
);
163 /* Connect to remote machine */
164 if (!(cli
= net_make_ipc_connection(NET_FLAGS_ANONYMOUS
| NET_FLAGS_PDC
))) {
168 if (!cli_nt_session_open(cli
, PI_NETLOGON
)) {
169 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
173 if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_password
, NULL
)) {
174 d_printf("Could not retrieve domain trust secret\n");
178 result
= cli_nt_setup_creds(cli
, SEC_CHAN_BDC
, trust_password
, &neg_flags
, 2);
179 if (!NT_STATUS_IS_OK(result
)) {
180 d_printf("Failed to setup BDC creds\n");
184 dump_database(cli
, SAM_DATABASE_DOMAIN
, &ret_creds
);
185 dump_database(cli
, SAM_DATABASE_BUILTIN
, &ret_creds
);
186 dump_database(cli
, SAM_DATABASE_PRIVS
, &ret_creds
);
188 cli_nt_session_close(cli
);
194 cli_nt_session_close(cli
);
199 /* Convert a SAM_ACCOUNT_DELTA to a SAM_ACCOUNT. */
202 sam_account_from_delta(SAM_ACCOUNT
*account
, SAM_ACCOUNT_INFO
*delta
)
205 uchar lm_passwd
[16], nt_passwd
[16];
206 static uchar zero_buf
[16];
208 /* Username, fullname, home dir, dir drive, logon script, acct
209 desc, workstations, profile. */
211 unistr2_to_ascii(s
, &delta
->uni_acct_name
, sizeof(s
) - 1);
212 pdb_set_nt_username(account
, s
, PDB_CHANGED
);
214 /* Unix username is the same - for sainity */
215 pdb_set_username(account
, s
, PDB_CHANGED
);
217 unistr2_to_ascii(s
, &delta
->uni_full_name
, sizeof(s
) - 1);
218 pdb_set_fullname(account
, s
, PDB_CHANGED
);
220 unistr2_to_ascii(s
, &delta
->uni_home_dir
, sizeof(s
) - 1);
221 pdb_set_homedir(account
, s
, PDB_CHANGED
);
223 unistr2_to_ascii(s
, &delta
->uni_dir_drive
, sizeof(s
) - 1);
224 pdb_set_dir_drive(account
, s
, PDB_CHANGED
);
226 unistr2_to_ascii(s
, &delta
->uni_logon_script
, sizeof(s
) - 1);
227 pdb_set_logon_script(account
, s
, PDB_CHANGED
);
229 unistr2_to_ascii(s
, &delta
->uni_acct_desc
, sizeof(s
) - 1);
230 pdb_set_acct_desc(account
, s
, PDB_CHANGED
);
232 unistr2_to_ascii(s
, &delta
->uni_workstations
, sizeof(s
) - 1);
233 pdb_set_workstations(account
, s
, PDB_CHANGED
);
235 unistr2_to_ascii(s
, &delta
->uni_profile
, sizeof(s
) - 1);
236 pdb_set_profile_path(account
, s
, PDB_CHANGED
);
238 /* User and group sid */
240 pdb_set_user_sid_from_rid(account
, delta
->user_rid
, PDB_CHANGED
);
241 pdb_set_group_sid_from_rid(account
, delta
->group_rid
, PDB_CHANGED
);
243 /* Logon and password information */
245 pdb_set_logon_time(account
, nt_time_to_unix(&delta
->logon_time
), PDB_CHANGED
);
246 pdb_set_logoff_time(account
, nt_time_to_unix(&delta
->logoff_time
),
248 pdb_set_logon_divs(account
, delta
->logon_divs
, PDB_CHANGED
);
250 /* TODO: logon hours */
251 /* TODO: bad password count */
252 /* TODO: logon count */
254 pdb_set_pass_last_set_time(
255 account
, nt_time_to_unix(&delta
->pwd_last_set_time
), PDB_CHANGED
);
257 pdb_set_kickoff_time(account
, get_time_t_max(), PDB_CHANGED
);
259 /* Decode hashes from password hash
260 Note that win2000 may send us all zeros for the hashes if it doesn't
261 think this channel is secure enough - don't set the passwords at all
264 if (memcmp(delta
->pass
.buf_lm_pwd
, zero_buf
, 16) != 0) {
265 sam_pwd_hash(delta
->user_rid
, delta
->pass
.buf_lm_pwd
, lm_passwd
, 0);
266 pdb_set_lanman_passwd(account
, lm_passwd
, PDB_CHANGED
);
269 if (memcmp(delta
->pass
.buf_nt_pwd
, zero_buf
, 16) != 0) {
270 sam_pwd_hash(delta
->user_rid
, delta
->pass
.buf_nt_pwd
, nt_passwd
, 0);
271 pdb_set_nt_passwd(account
, nt_passwd
, PDB_CHANGED
);
274 /* TODO: account expiry time */
276 pdb_set_acct_ctrl(account
, delta
->acb_info
, PDB_CHANGED
);
281 fetch_account_info(uint32 rid
, SAM_ACCOUNT_INFO
*delta
)
286 SAM_ACCOUNT
*sam_account
=NULL
;
291 fstrcpy(account
, unistr2_static(&delta
->uni_acct_name
));
292 d_printf("Creating account: %s\n", account
);
294 if (!NT_STATUS_IS_OK(nt_ret
= pdb_init_sam(&sam_account
)))
297 if (!pdb_getsampwnam(sam_account
, account
)) {
300 pdb_free_sam(&sam_account
);
302 /* Create appropriate user */
303 if (delta
->acb_info
& ACB_NORMAL
) {
304 pstrcpy(add_script
, lp_adduser_script());
305 } else if ( (delta
->acb_info
& ACB_WSTRUST
) ||
306 (delta
->acb_info
& ACB_SVRTRUST
) ) {
307 pstrcpy(add_script
, lp_addmachine_script());
309 DEBUG(1, ("Unknown user type: %s\n",
310 smbpasswd_encode_acb_info(delta
->acb_info
)));
311 pdb_free_sam(&sam_account
);
312 return NT_STATUS_NO_SUCH_USER
;
316 all_string_sub(add_script
, "%u", account
,
318 add_ret
= smbrun(add_script
,NULL
);
319 DEBUG(1,("fetch_account: Running the command `%s' "
320 "gave %d\n", add_script
, add_ret
));
322 pw
= getpwnam_alloc(account
);
324 nt_ret
= pdb_init_sam_pw(&sam_account
, pw
);
326 if (!NT_STATUS_IS_OK(nt_ret
)) {
328 pdb_free_sam(&sam_account
);
333 DEBUG(3, ("Could not create account %s\n", account
));
334 pdb_free_sam(&sam_account
);
335 return NT_STATUS_NO_SUCH_USER
;
339 sam_account_from_delta(sam_account
, delta
);
341 if (!pdb_add_sam_account(sam_account
)) {
342 DEBUG(1, ("SAM Account for %s already exists, updating\n",
344 pdb_update_sam_account(sam_account
);
347 sid
= *pdb_get_group_sid(sam_account
);
349 if (!pdb_getgrsid(&map
, sid
, False
)) {
350 DEBUG(0, ("Primary group of %s has no mapping!\n",
351 pdb_get_username(sam_account
)));
352 pdb_free_sam(&sam_account
);
353 return NT_STATUS_NO_SUCH_GROUP
;
356 if (!(grp
= getgrgid(map
.gid
))) {
357 DEBUG(0, ("Could not find unix group %d for user %s (group SID=%s)\n",
358 map
.gid
, pdb_get_username(sam_account
), sid_string_static(&sid
)));
359 pdb_free_sam(&sam_account
);
360 return NT_STATUS_NO_SUCH_GROUP
;
363 smb_set_primary_group(grp
->gr_name
, pdb_get_username(sam_account
));
365 pdb_free_sam(&sam_account
);
370 fetch_group_info(uint32 rid
, SAM_GROUP_INFO
*delta
)
374 struct group
*grp
= NULL
;
380 unistr2_to_ascii(name
, &delta
->uni_grp_name
, sizeof(name
)-1);
381 unistr2_to_ascii(comment
, &delta
->uni_grp_desc
, sizeof(comment
)-1);
383 /* add the group to the mapping table */
384 sid_copy(&group_sid
, get_global_sam_sid());
385 sid_append_rid(&group_sid
, rid
);
386 sid_to_string(sid_string
, &group_sid
);
388 if (pdb_getgrsid(&map
, group_sid
, False
)) {
389 grp
= getgrgid(map
.gid
);
397 /* No group found from mapping, find it from its name. */
398 if ((grp
= getgrnam(name
)) == NULL
) {
399 /* No appropriate group found, create one */
400 d_printf("Creating unix group: '%s'\n", name
);
401 if (smb_create_group(name
, &gid
) != 0)
402 return NT_STATUS_ACCESS_DENIED
;
403 if ((grp
= getgrgid(gid
)) == NULL
)
404 return NT_STATUS_ACCESS_DENIED
;
408 map
.gid
= grp
->gr_gid
;
410 map
.sid_name_use
= SID_NAME_DOM_GRP
;
411 fstrcpy(map
.nt_name
, name
);
412 fstrcpy(map
.comment
, comment
);
414 map
.priv_set
.count
= 0;
415 map
.priv_set
.set
= NULL
;
418 pdb_add_group_mapping_entry(&map
);
420 pdb_update_group_mapping_entry(&map
);
426 fetch_group_mem_info(uint32 rid
, SAM_GROUP_MEM_INFO
*delta
)
429 TALLOC_CTX
*t
= NULL
;
430 char **nt_members
= NULL
;
436 if (delta
->num_members
== 0) {
440 sid_copy(&group_sid
, get_global_sam_sid());
441 sid_append_rid(&group_sid
, rid
);
443 if (!get_domain_group_from_sid(group_sid
, &map
, False
)) {
444 DEBUG(0, ("Could not find global group %d\n", rid
));
445 return NT_STATUS_NO_SUCH_GROUP
;
448 if (!(grp
= getgrgid(map
.gid
))) {
449 DEBUG(0, ("Could not find unix group %d\n", map
.gid
));
450 return NT_STATUS_NO_SUCH_GROUP
;
453 d_printf("Group members of %s: ", grp
->gr_name
);
455 if (!(t
= talloc_init("fetch_group_mem_info"))) {
456 DEBUG(0, ("could not talloc_init\n"));
457 return NT_STATUS_NO_MEMORY
;
460 nt_members
= talloc_zero(t
, sizeof(char *) * delta
->num_members
);
462 for (i
=0; i
<delta
->num_members
; i
++) {
464 SAM_ACCOUNT
*member
= NULL
;
467 if (!NT_STATUS_IS_OK(nt_status
= pdb_init_sam_talloc(t
, &member
))) {
472 sid_copy(&member_sid
, get_global_sam_sid());
473 sid_append_rid(&member_sid
, delta
->rids
[i
]);
475 if (!pdb_getsampwsid(member
, &member_sid
)) {
476 DEBUG(1, ("Found bogus group member: %d (member_sid=%s group=%s)\n",
477 delta
->rids
[i
], sid_string_static(&member_sid
), grp
->gr_name
));
478 pdb_free_sam(&member
);
482 if (pdb_get_group_rid(member
) == rid
) {
483 d_printf("%s(primary),", pdb_get_username(member
));
484 pdb_free_sam(&member
);
488 d_printf("%s,", pdb_get_username(member
));
489 nt_members
[i
] = talloc_strdup(t
, pdb_get_username(member
));
490 pdb_free_sam(&member
);
495 unix_members
= grp
->gr_mem
;
497 while (*unix_members
) {
498 BOOL is_nt_member
= False
;
499 for (i
=0; i
<delta
->num_members
; i
++) {
500 if (nt_members
[i
] == NULL
) {
501 /* This was a primary group */
505 if (strcmp(*unix_members
, nt_members
[i
]) == 0) {
511 /* We look at a unix group member that is not
512 an nt group member. So, remove it. NT is
514 smb_delete_user_group(grp
->gr_name
, *unix_members
);
519 for (i
=0; i
<delta
->num_members
; i
++) {
520 BOOL is_unix_member
= False
;
522 if (nt_members
[i
] == NULL
) {
523 /* This was the primary group */
527 unix_members
= grp
->gr_mem
;
529 while (*unix_members
) {
530 if (strcmp(*unix_members
, nt_members
[i
]) == 0) {
531 is_unix_member
= True
;
537 if (!is_unix_member
) {
538 /* We look at a nt group member that is not a
539 unix group member currently. So, add the nt
541 smb_add_user_group(grp
->gr_name
, nt_members
[i
]);
549 static NTSTATUS
fetch_alias_info(uint32 rid
, SAM_ALIAS_INFO
*delta
,
554 struct group
*grp
= NULL
;
560 unistr2_to_ascii(name
, &delta
->uni_als_name
, sizeof(name
)-1);
561 unistr2_to_ascii(comment
, &delta
->uni_als_desc
, sizeof(comment
)-1);
563 /* Find out whether the group is already mapped */
564 sid_copy(&alias_sid
, &dom_sid
);
565 sid_append_rid(&alias_sid
, rid
);
566 sid_to_string(sid_string
, &alias_sid
);
568 if (pdb_getgrsid(&map
, alias_sid
, False
)) {
569 grp
= getgrgid(map
.gid
);
576 /* No group found from mapping, find it from its name. */
577 if ((grp
= getgrnam(name
)) == NULL
) {
578 /* No appropriate group found, create one */
579 d_printf("Creating unix group: '%s'\n", name
);
580 if (smb_create_group(name
, &gid
) != 0)
581 return NT_STATUS_ACCESS_DENIED
;
582 if ((grp
= getgrgid(gid
)) == NULL
)
583 return NT_STATUS_ACCESS_DENIED
;
587 map
.gid
= grp
->gr_gid
;
590 if (sid_equal(&dom_sid
, &global_sid_Builtin
))
591 map
.sid_name_use
= SID_NAME_WKN_GRP
;
593 map
.sid_name_use
= SID_NAME_ALIAS
;
595 fstrcpy(map
.nt_name
, name
);
596 fstrcpy(map
.comment
, comment
);
598 map
.priv_set
.count
= 0;
599 map
.priv_set
.set
= NULL
;
602 pdb_add_group_mapping_entry(&map
);
604 pdb_update_group_mapping_entry(&map
);
610 fetch_alias_mem(uint32 rid
, SAM_ALIAS_MEM_INFO
*delta
, DOM_SID dom_sid
)
617 fetch_sam_entry(SAM_DELTA_HDR
*hdr_delta
, SAM_DELTA_CTR
*delta
,
620 switch(hdr_delta
->type
) {
621 case SAM_DELTA_ACCOUNT_INFO
:
622 fetch_account_info(hdr_delta
->target_rid
,
623 &delta
->account_info
);
625 case SAM_DELTA_GROUP_INFO
:
626 fetch_group_info(hdr_delta
->target_rid
,
629 case SAM_DELTA_GROUP_MEM
:
630 fetch_group_mem_info(hdr_delta
->target_rid
,
631 &delta
->grp_mem_info
);
633 case SAM_DELTA_ALIAS_INFO
:
634 fetch_alias_info(hdr_delta
->target_rid
,
635 &delta
->alias_info
, dom_sid
);
637 case SAM_DELTA_ALIAS_MEM
:
638 fetch_alias_mem(hdr_delta
->target_rid
,
639 &delta
->als_mem_info
, dom_sid
);
642 d_printf("Unknown delta record type %d\n", hdr_delta
->type
);
648 fetch_database(struct cli_state
*cli
, unsigned db_type
, DOM_CRED
*ret_creds
,
651 unsigned sync_context
= 0;
655 SAM_DELTA_HDR
*hdr_deltas
;
656 SAM_DELTA_CTR
*deltas
;
659 if (!(mem_ctx
= talloc_init("fetch_database"))) {
663 d_printf("Fetching database %u\n", db_type
);
666 result
= cli_netlogon_sam_sync(cli
, mem_ctx
, ret_creds
,
667 db_type
, sync_context
,
669 &hdr_deltas
, &deltas
);
670 clnt_deal_with_creds(cli
->sess_key
, &(cli
->clnt_cred
),
672 for (i
= 0; i
< num_deltas
; i
++) {
673 fetch_sam_entry(&hdr_deltas
[i
], &deltas
[i
], dom_sid
);
676 } while (NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
678 talloc_destroy(mem_ctx
);
681 /* dump sam database via samsync rpc calls */
682 int rpc_vampire(int argc
, const char **argv
)
685 struct cli_state
*cli
= NULL
;
686 uchar trust_password
[16];
688 uint32 neg_flags
= 0x000001ff;
691 ZERO_STRUCT(ret_creds
);
693 /* Connect to remote machine */
694 if (!(cli
= net_make_ipc_connection(NET_FLAGS_ANONYMOUS
|
699 if (!cli_nt_session_open(cli
, PI_NETLOGON
)) {
700 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
704 if (!secrets_fetch_trust_account_password(lp_workgroup(),
705 trust_password
, NULL
)) {
706 d_printf("Could not retrieve domain trust secret\n");
710 result
= cli_nt_setup_creds(cli
, SEC_CHAN_BDC
, trust_password
,
712 if (!NT_STATUS_IS_OK(result
)) {
713 d_printf("Failed to setup BDC creds\n");
717 dom_sid
= *get_global_sam_sid();
718 fetch_database(cli
, SAM_DATABASE_DOMAIN
, &ret_creds
, dom_sid
);
720 sid_copy(&dom_sid
, &global_sid_Builtin
);
721 fetch_database(cli
, SAM_DATABASE_BUILTIN
, &ret_creds
, dom_sid
);
723 /* Currently we crash on PRIVS somewhere in unmarshalling */
724 /* Dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds); */
726 cli_nt_session_close(cli
);
732 cli_nt_session_close(cli
);