summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorTim Potter <tpot@samba.org>2001-08-28 06:43:43 +0000
committerTim Potter <tpot@samba.org>2001-08-28 06:43:43 +0000
commitd5c9172adadb83283e437578be7bad4368ad9f20 (patch)
treef21c0e6d07b15375bced92c0e3a96cdf653642a4 /source3
parent49dff249fc3f9155037016dd131cbaa41e5306bc (diff)
downloadsamba-d5c9172adadb83283e437578be7bad4368ad9f20.tar.gz
samba-d5c9172adadb83283e437578be7bad4368ad9f20.tar.bz2
samba-d5c9172adadb83283e437578be7bad4368ad9f20.zip
Merge of sam sync code from TNG.
Reverse-engineered the sam replication protocol from staring at hex dumps for a while. It's pretty similar to the sam sync protocol with a couple of different delta header types. I wasn't able to figure out the format of the privilege stuff - needs more time and a whiteboard. (-: The impressive bit is that the sam sync stuff from tng basically just worked thanks mainly to Luke Leighton's efforts in this area. (This used to be commit 3a60cb44f22d5f3f8c78a56ed8f5ea4794cd7ab3)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/rpc_misc.h19
-rw-r--r--source3/libsmb/cli_netlogon.c145
-rw-r--r--source3/rpc_parse/parse_misc.c64
-rw-r--r--source3/rpc_parse/parse_net.c834
-rw-r--r--source3/rpcclient/cmd_netlogon.c220
5 files changed, 1276 insertions, 6 deletions
diff --git a/source3/include/rpc_misc.h b/source3/include/rpc_misc.h
index 428db938de..558c28459e 100644
--- a/source3/include/rpc_misc.h
+++ b/source3/include/rpc_misc.h
@@ -348,5 +348,24 @@ typedef struct uint64_s
uint32 high;
} UINT64_S;
+/* BUFHDR2 - another buffer header, with info level */
+typedef struct bufhdr2_info
+{
+ uint32 info_level;
+ uint32 length; /* uint8 chars */
+ uint32 buffer;
+
+}
+BUFHDR2;
+
+/* BUFFER4 - simple length and buffer */
+typedef struct buffer4_info
+{
+ uint32 buf_len;
+ uint8 buffer[MAX_BUFFERLEN];
+
+}
+BUFFER4;
+
#endif /* _RPC_MISC_H */
diff --git a/source3/libsmb/cli_netlogon.c b/source3/libsmb/cli_netlogon.c
index 63a2f4a5b1..b608398aa3 100644
--- a/source3/libsmb/cli_netlogon.c
+++ b/source3/libsmb/cli_netlogon.c
@@ -34,13 +34,13 @@ struct cli_state *cli_netlogon_initialise(struct cli_state *cli,
/* Logon Control 2 */
-uint32 cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
- uint32 query_level)
+NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 query_level)
{
prs_struct qbuf, rbuf;
NET_Q_LOGON_CTRL2 q;
NET_R_LOGON_CTRL2 r;
- uint32 result = NT_STATUS_UNSUCCESSFUL;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
ZERO_STRUCT(q);
ZERO_STRUCT(r);
@@ -77,3 +77,142 @@ uint32 cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result;
}
+
+/****************************************************************************
+Generate the next creds to use. Yuck - this is a cut&paste from another
+file. They should be combined at some stage. )-:
+****************************************************************************/
+
+static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
+{
+ /*
+ * Create the new client credentials.
+ */
+
+ cli->clnt_cred.timestamp.time = time(NULL);
+
+ memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
+
+ /* Calculate the new credentials. */
+ cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
+ new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
+
+}
+
+/* Sam synchronisation */
+
+NTSTATUS cli_netlogon_sam_sync(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 database_id, uint32 *num_deltas,
+ SAM_DELTA_HDR **hdr_deltas,
+ SAM_DELTA_CTR **deltas)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_SYNC q;
+ NET_R_SAM_SYNC r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds;
+ char sess_key[16];
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ init_net_q_sam_sync(&q, cli->srv_name_slash, cli->clnt_name_slash + 2,
+ &clnt_creds, database_id);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_sync("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAM_SYNC, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_sam_sync("", sess_key, &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+ *num_deltas = r.num_deltas2;
+ *hdr_deltas = r.hdr_deltas;
+ *deltas = r.deltas;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Sam synchronisation */
+
+NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 database_id, UINT64_S seqnum,
+ uint32 *num_deltas,
+ SAM_DELTA_HDR **hdr_deltas,
+ SAM_DELTA_CTR **deltas)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_DELTAS q;
+ NET_R_SAM_DELTAS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds;
+ char sess_key[16];
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ init_net_q_sam_deltas(&q, cli->srv_name_slash,
+ cli->clnt_name_slash + 2, &clnt_creds,
+ database_id, seqnum);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_deltas("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAM_DELTAS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_sam_deltas("", sess_key, &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+ *num_deltas = r.num_deltas2;
+ *hdr_deltas = r.hdr_deltas;
+ *deltas = r.deltas;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source3/rpc_parse/parse_misc.c b/source3/rpc_parse/parse_misc.c
index 1a30d3d7a1..2a6560f8ce 100644
--- a/source3/rpc_parse/parse_misc.c
+++ b/source3/rpc_parse/parse_misc.c
@@ -1528,4 +1528,68 @@ BOOL prs_uint64(char *name, prs_struct *ps, int depth, UINT64_S *data64)
prs_uint32(name, ps, depth+1, &data64->high);
}
+/*******************************************************************
+reads or writes a BUFHDR2 structure.
+********************************************************************/
+BOOL smb_io_bufhdr2(char *desc, BUFHDR2 *hdr, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_bufhdr2");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("info_level", ps, depth, &(hdr->info_level));
+ prs_uint32("length ", ps, depth, &(hdr->length ));
+ prs_uint32("buffer ", ps, depth, &(hdr->buffer ));
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a BUFFER4 structure.
+********************************************************************/
+BOOL smb_io_buffer4(char *desc, BUFFER4 *buf4, uint32 buffer, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_buffer4");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("buf_len", ps, depth, &(buf4->buf_len));
+
+ if (buf4->buf_len > MAX_BUFFERLEN)
+ {
+ buf4->buf_len = MAX_BUFFERLEN;
+ }
+
+ prs_uint8s(True, "buffer", ps, depth, buf4->buffer, buf4->buf_len);
+
+ return True;
+}
+
+/*******************************************************************
+creates a UNIHDR structure.
+********************************************************************/
+
+BOOL make_uni_hdr(UNIHDR *hdr, int len)
+{
+ if (hdr == NULL)
+ {
+ return False;
+ }
+ hdr->uni_str_len = 2 * len;
+ hdr->uni_max_len = 2 * len;
+ hdr->buffer = len != 0 ? 1 : 0;
+
+ return True;
+}
+/*******************************************************************
+creates a BUFHDR2 structure.
+********************************************************************/
+BOOL make_bufhdr2(BUFHDR2 *hdr, uint32 info_level, uint32 length, uint32 buffer)
+{
+ hdr->info_level = info_level;
+ hdr->length = length;
+ hdr->buffer = buffer;
+
+ return True;
+}
diff --git a/source3/rpc_parse/parse_net.c b/source3/rpc_parse/parse_net.c
index e8f0c02a52..37bf6755b7 100644
--- a/source3/rpc_parse/parse_net.c
+++ b/source3/rpc_parse/parse_net.c
@@ -1589,3 +1589,837 @@ BOOL net_io_r_sam_logoff(char *desc, NET_R_SAM_LOGOFF *r_l, prs_struct *ps, int
return True;
}
+
+/*******************************************************************
+makes a NET_Q_SAM_SYNC structure.
+********************************************************************/
+BOOL init_net_q_sam_sync(NET_Q_SAM_SYNC * q_s, const char *srv_name,
+ const char *cli_name, DOM_CRED * cli_creds,
+ uint32 database_id)
+{
+ DEBUG(5, ("init_q_sam_sync\n"));
+
+ init_unistr2(&q_s->uni_srv_name, srv_name, strlen(srv_name) + 1);
+ init_unistr2(&q_s->uni_cli_name, cli_name, strlen(cli_name) + 1);
+
+ if (cli_creds) {
+ memcpy(&q_s->cli_creds, cli_creds, sizeof(q_s->cli_creds));
+ memset(&q_s->ret_creds, 0, sizeof(q_s->ret_creds));
+ }
+
+ q_s->database_id = database_id;
+ q_s->restart_state = 0;
+ q_s->sync_context = 0;
+ q_s->max_size = 0xffff;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_q_sam_sync(char *desc, NET_Q_SAM_SYNC * q_s, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_q_sam_sync");
+ depth++;
+
+ smb_io_unistr2("", &(q_s->uni_srv_name), True, ps, depth);
+ smb_io_unistr2("", &(q_s->uni_cli_name), True, ps, depth);
+
+ smb_io_cred("", &(q_s->cli_creds), ps, depth);
+ smb_io_cred("", &(q_s->ret_creds), ps, depth);
+
+ prs_uint32("database_id ", ps, depth, &(q_s->database_id));
+ prs_uint32("restart_state", ps, depth, &(q_s->restart_state));
+ prs_uint32("sync_context ", ps, depth, &(q_s->sync_context));
+
+ prs_uint32("max_size", ps, depth, &(q_s->max_size));
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_hdr(char *desc, SAM_DELTA_HDR * delta,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_delta_hdr");
+ depth++;
+
+ prs_uint16("type", ps, depth, &(delta->type));
+ prs_uint16("type2", ps, depth, &(delta->type2));
+ prs_uint32("target_rid", ps, depth, &(delta->target_rid));
+
+ prs_uint32("type3", ps, depth, &(delta->type3));
+
+ /* Not sure why we need this but it seems to be necessary to get
+ sam deltas working. */
+
+ if (delta->type != 0x16)
+ prs_uint32("ptr_delta", ps, depth, &(delta->ptr_delta));
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_hdr2(char *desc, SAM_DELTA_HDR *delta,
+ prs_struct *ps, int depth)
+{
+ uint32 unk;
+
+ prs_debug(ps, depth, desc, "net_io_sam_delta_stamp");
+ depth++;
+
+ prs_uint16("type", ps, depth, &(delta->type));
+ prs_uint16("type2", ps, depth, &(delta->type2));
+ prs_uint32("rid", ps, depth, &unk);
+
+
+ prs_uint32("unknown_ptr", ps, depth, &unk);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_stamp(char *desc, SAM_DELTA_STAMP *info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_delta_stamp");
+ depth++;
+
+ prs_uint32("seqnum", ps, depth, &info->seqnum);
+ prs_uint32("dom_mod_count_ptr", ps, depth, &info->dom_mod_count_ptr);
+ if (info->dom_mod_count_ptr)
+ prs_uint64("dom_mod_count", ps, depth, &info->dom_mod_count);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_domain_info(char *desc, SAM_DOMAIN_INFO * info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_domain_info");
+ depth++;
+
+ smb_io_unihdr("hdr_dom_name", &(info->hdr_dom_name), ps, depth);
+ smb_io_unihdr("hdr_oem_info", &(info->hdr_oem_info), ps, depth);
+
+ prs_uint64("force_logoff", ps, depth, &info->force_logoff);
+ prs_uint16("min_pwd_len", ps, depth, &(info->min_pwd_len));
+ prs_uint16("pwd_history_len", ps, depth, &info->pwd_history_len);
+ prs_uint64("max_pwd_age", ps, depth, &info->max_pwd_age);
+ prs_uint64("min_pwd_age", ps, depth, &info->min_pwd_age);
+ prs_uint64("dom_mod_count", ps, depth, &info->dom_mod_count);
+ smb_io_time("creation_time", &info->creation_time, ps, depth);
+
+ smb_io_bufhdr2("hdr_sec_desc", &(info->hdr_sec_desc), ps, depth);
+ smb_io_unihdr("hdr_unknown", &(info->hdr_unknown), ps, depth);
+ ps->data_offset += 40;
+
+ smb_io_unistr2("uni_dom_name", &(info->uni_dom_name),
+ info->hdr_dom_name.buffer, ps, depth);
+ smb_io_unistr2("buf_oem_info", &(info->buf_oem_info),
+ info->hdr_oem_info.buffer, ps, depth);
+
+ smb_io_buffer4("buf_sec_desc", &(info->buf_sec_desc),
+ info->hdr_sec_desc.buffer, ps, depth);
+ smb_io_unistr2("buf_unknown", &(info->buf_unknown),
+ info->hdr_unknown.buffer, ps, depth);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_group_info(char *desc, SAM_GROUP_INFO * info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_group_info");
+ depth++;
+
+ smb_io_unihdr("hdr_grp_name", &(info->hdr_grp_name), ps, depth);
+ smb_io_gid("gid", &(info->gid), ps, depth);
+ smb_io_unihdr("hdr_grp_desc", &(info->hdr_grp_desc), ps, depth);
+ smb_io_bufhdr2("hdr_sec_desc", &(info->hdr_sec_desc), ps, depth);
+ ps->data_offset += 48;
+
+ smb_io_unistr2("uni_grp_name", &(info->uni_grp_name),
+ info->hdr_grp_name.buffer, ps, depth);
+ smb_io_unistr2("uni_grp_desc", &(info->uni_grp_desc),
+ info->hdr_grp_desc.buffer, ps, depth);
+ smb_io_buffer4("buf_sec_desc", &(info->buf_sec_desc),
+ info->hdr_sec_desc.buffer, ps, depth);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_passwd_info(char *desc, SAM_PWD * pwd,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_passwd_info");
+ depth++;
+
+ prs_uint32("unk_0 ", ps, depth, &(pwd->unk_0));
+
+ smb_io_unihdr("hdr_lm_pwd", &(pwd->hdr_lm_pwd), ps, depth);
+ prs_uint8s(False, "buf_lm_pwd", ps, depth, pwd->buf_lm_pwd, 16);
+
+ smb_io_unihdr("hdr_nt_pwd", &(pwd->hdr_nt_pwd), ps, depth);
+ prs_uint8s(False, "buf_nt_pwd", ps, depth, pwd->buf_nt_pwd, 16);
+
+ smb_io_unihdr("", &(pwd->hdr_empty_lm), ps, depth);
+ smb_io_unihdr("", &(pwd->hdr_empty_nt), ps, depth);
+
+ return True;
+}
+
+/*******************************************************************
+makes a SAM_ACCOUNT_INFO structure.
+********************************************************************/
+BOOL make_sam_account_info(SAM_ACCOUNT_INFO * info,
+ const UNISTR2 *user_name,
+ const UNISTR2 *full_name,
+ uint32 user_rid, uint32 group_rid,
+ const UNISTR2 *home_dir,
+ const UNISTR2 *dir_drive,
+ const UNISTR2 *log_scr,
+ const UNISTR2 *desc,
+ uint32 acb_info,
+ const UNISTR2 *prof_path,
+ const UNISTR2 *wkstas,
+ const UNISTR2 *unk_str, const UNISTR2 *mung_dial)
+{
+ int len_user_name = user_name != NULL ? user_name->uni_str_len : 0;
+ int len_full_name = full_name != NULL ? full_name->uni_str_len : 0;
+ int len_home_dir = home_dir != NULL ? home_dir->uni_str_len : 0;
+ int len_dir_drive = dir_drive != NULL ? dir_drive->uni_str_len : 0;
+ int len_logon_script = log_scr != NULL ? log_scr->uni_str_len : 0;
+ int len_profile_path = prof_path != NULL ? prof_path->uni_str_len : 0;
+ int len_description = desc != NULL ? desc->uni_str_len : 0;
+ int len_workstations = wkstas != NULL ? wkstas->uni_str_len : 0;
+ int len_unknown_str = unk_str != NULL ? unk_str->uni_str_len : 0;
+ int len_munged_dial = mung_dial != NULL ? mung_dial->uni_str_len : 0;
+
+ DEBUG(5, ("make_sam_account_info\n"));
+
+ make_uni_hdr(&(info->hdr_acct_name), len_user_name);
+ make_uni_hdr(&(info->hdr_full_name), len_full_name);
+ make_uni_hdr(&(info->hdr_home_dir), len_home_dir);
+ make_uni_hdr(&(info->hdr_dir_drive), len_dir_drive);
+ make_uni_hdr(&(info->hdr_logon_script), len_logon_script);
+ make_uni_hdr(&(info->hdr_profile), len_profile_path);
+ make_uni_hdr(&(info->hdr_acct_desc), len_description);
+ make_uni_hdr(&(info->hdr_workstations), len_workstations);
+ make_uni_hdr(&(info->hdr_comment), len_unknown_str);
+ make_uni_hdr(&(info->hdr_parameters), len_munged_dial);
+
+ /* not present */
+ make_bufhdr2(&(info->hdr_sec_desc), 0, 0, 0);
+
+ info->user_rid = user_rid;
+ info->group_rid = group_rid;
+
+ init_nt_time(&(info->logon_time));
+ init_nt_time(&(info->logoff_time));
+ init_nt_time(&(info->pwd_last_set_time));
+ init_nt_time(&(info->acct_expiry_time));
+
+ info->logon_divs = 0xA8;
+ info->ptr_logon_hrs = 0; /* Don't care right now */
+
+ info->bad_pwd_count = 0;
+ info->logon_count = 0;
+ info->acb_info = acb_info;
+ info->nt_pwd_present = 0;
+ info->lm_pwd_present = 0;
+ info->pwd_expired = 0;
+ info->country = 0;
+ info->codepage = 0;
+
+ info->unknown1 = 0x4EC;
+ info->unknown2 = 0;
+
+ copy_unistr2(&(info->uni_acct_name), user_name);
+ copy_unistr2(&(info->uni_full_name), full_name);
+ copy_unistr2(&(info->uni_home_dir), home_dir);
+ copy_unistr2(&(info->uni_dir_drive), dir_drive);
+ copy_unistr2(&(info->uni_logon_script), log_scr);
+ copy_unistr2(&(info->uni_profile), prof_path);
+ copy_unistr2(&(info->uni_acct_desc), desc);
+ copy_unistr2(&(info->uni_workstations), wkstas);
+ copy_unistr2(&(info->uni_comment), unk_str);
+ copy_unistr2(&(info->uni_parameters), mung_dial);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_account_info(char *desc, uint8 sess_key[16],
+ SAM_ACCOUNT_INFO * info, prs_struct *ps,
+ int depth)
+{
+ BUFHDR2 hdr_priv_data;
+ uint32 i;
+
+ prs_debug(ps, depth, desc, "net_io_sam_account_info");
+ depth++;
+
+ smb_io_unihdr("hdr_acct_name", &(info->hdr_acct_name), ps, depth);
+ smb_io_unihdr("hdr_full_name", &(info->hdr_full_name), ps, depth);
+
+ prs_uint32("user_rid ", ps, depth, &(info->user_rid));
+ prs_uint32("group_rid", ps, depth, &(info->group_rid));
+
+ smb_io_unihdr("hdr_home_dir ", &(info->hdr_home_dir), ps, depth);
+ smb_io_unihdr("hdr_dir_drive", &(info->hdr_dir_drive), ps, depth);
+ smb_io_unihdr("hdr_logon_script", &(info->hdr_logon_script), ps,
+ depth);
+ smb_io_unihdr("hdr_acct_desc", &(info->hdr_acct_desc), ps, depth);
+ smb_io_unihdr("hdr_workstations", &(info->hdr_workstations), ps,
+ depth);
+
+ smb_io_time("logon_time", &(info->logon_time), ps, depth);
+ smb_io_time("logoff_time", &(info->logoff_time), ps, depth);
+
+ prs_uint32("logon_divs ", ps, depth, &(info->logon_divs));
+ prs_uint32("ptr_logon_hrs", ps, depth, &(info->ptr_logon_hrs));
+
+ prs_uint16("bad_pwd_count", ps, depth, &(info->bad_pwd_count));
+ prs_uint16("logon_count", ps, depth, &(info->logon_count));
+ smb_io_time("pwd_last_set_time", &(info->pwd_last_set_time), ps,
+ depth);
+ smb_io_time("acct_expiry_time", &(info->acct_expiry_time), ps, depth);
+
+ prs_uint32("acb_info", ps, depth, &(info->acb_info));
+ prs_uint8s(False, "nt_pwd", ps, depth, info->nt_pwd, 16);
+ prs_uint8s(False, "lm_pwd", ps, depth, info->lm_pwd, 16);
+ prs_uint8("lm_pwd_present", ps, depth, &(info->lm_pwd_present));
+ prs_uint8("nt_pwd_present", ps, depth, &(info->nt_pwd_present));
+ prs_uint8("pwd_expired", ps, depth, &(info->pwd_expired));
+
+ smb_io_unihdr("hdr_comment", &(info->hdr_comment), ps, depth);
+ smb_io_unihdr("hdr_parameters", &(info->hdr_parameters), ps, depth);
+ prs_uint16("country", ps, depth, &(info->country));
+ prs_uint16("codepage", ps, depth, &(info->codepage));
+
+ smb_io_bufhdr2("hdr_priv_data", &(hdr_priv_data), ps, depth);
+ smb_io_bufhdr2("hdr_sec_desc", &(info->hdr_sec_desc), ps, depth);
+ smb_io_unihdr("hdr_profile", &(info->hdr_profile), ps, depth);
+
+ for (i = 0; i < 3; i++)
+ {
+ smb_io_unihdr("hdr_reserved", &(info->hdr_reserved[i]), ps,
+ depth);
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ prs_uint32("dw_reserved", ps, depth, &(info->dw_reserved[i]));
+ }
+
+ smb_io_unistr2("uni_acct_name", &(info->uni_acct_name),
+ info->hdr_acct_name.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_full_name", &(info->uni_full_name),
+ info->hdr_full_name.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_home_dir ", &(info->uni_home_dir),
+ info->hdr_home_dir.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_dir_drive", &(info->uni_dir_drive),
+ info->hdr_dir_drive.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_logon_script", &(info->uni_logon_script),
+ info->hdr_logon_script.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_acct_desc", &(info->uni_acct_desc),
+ info->hdr_acct_desc.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_workstations", &(info->uni_workstations),
+ info->hdr_workstations.buffer, ps, depth);
+ prs_align(ps);
+
+ prs_uint32("unknown1", ps, depth, &(info->unknown1));
+ prs_uint32("unknown2", ps, depth, &(info->unknown2));
+
+ smb_io_buffer4("buf_logon_hrs", &(info->buf_logon_hrs),
+ info->ptr_logon_hrs, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_comment", &(info->uni_comment),
+ info->hdr_comment.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_parameters", &(info->uni_parameters),
+ info->hdr_parameters.buffer, ps, depth);
+ prs_align(ps);
+ if (hdr_priv_data.buffer != 0)
+ {
+ int old_offset = 0;
+ uint32 len = 0x44;
+ prs_uint32("pwd_len", ps, depth, &len);
+ old_offset = ps->data_offset;
+ if (len == 0x44)
+ {
+ if (ps->io)
+ {
+ /* reading */
+// FIXME prs_hash1(ps, ps->offset, sess_key);
+ }
+ net_io_sam_passwd_info("pass", &(info->pass), ps,
+ depth);
+ if (!ps->io)
+ {
+ /* writing */
+// FIXME TOO prs_hash1(ps, old_offset, sess_key);
+ }
+ }
+ ps->data_offset = old_offset + len;
+ }
+ smb_io_buffer4("buf_sec_desc", &(info->buf_sec_desc),
+ info->hdr_sec_desc.buffer, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_profile", &(info->uni_profile),
+ info->hdr_profile.buffer, ps, depth);
+ prs_align(ps);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_group_mem_info(char *desc, SAM_GROUP_MEM_INFO * info,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+
+ prs_debug(ps, depth, desc, "net_io_sam_group_mem_info");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("ptr_rids ", ps, depth, &(info->ptr_rids));
+ prs_uint32("ptr_attribs", ps, depth, &(info->ptr_attribs));
+ prs_uint32("num_members", ps, depth, &(info->num_members));
+ ps->data_offset += 16;
+
+ if (info->ptr_rids != 0)
+ {
+ prs_uint32("num_members2", ps, depth, &(info->num_members2));
+ if (info->num_members2 != info->num_members)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ info->rids = talloc(ps->mem_ctx, sizeof(uint32) *
+ info->num_members2);
+
+ if (info->rids == NULL) {
+ DEBUG(0, ("out of memory allocating %d rids\n",
+ info->num_members2));
+ return False;
+ }
+
+ for (i = 0; i < info->num_members2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "rids[%02d]", i);
+ prs_uint32(tmp, ps, depth, &(info->rids[i]));
+ }
+ }
+
+ if (info->ptr_attribs != 0)
+ {
+ prs_uint32("num_members3", ps, depth, &(info->num_members3));
+ if (info->num_members3 != info->num_members)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ info->attribs = talloc(ps->mem_ctx, sizeof(uint32) *
+ info->num_members3);
+
+ if (info->attribs == NULL) {
+ DEBUG(0, ("out of memory allocating %d attribs\n",
+ info->num_members3));
+ return False;
+ }
+
+ for (i = 0; i < info->num_members3; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "attribs[%02d]", i);
+ prs_uint32(tmp, ps, depth, &(info->attribs[i]));
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_alias_info(char *desc, SAM_ALIAS_INFO * info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_alias_info");
+ depth++;
+
+ smb_io_unihdr("hdr_als_name", &(info->hdr_als_name), ps, depth);
+ prs_uint32("als_rid", ps, depth, &(info->als_rid));
+ smb_io_bufhdr2("hdr_sec_desc", &(info->hdr_sec_desc), ps, depth);
+ smb_io_unihdr("hdr_als_desc", &(info->hdr_als_desc), ps, depth);
+ ps->data_offset += 40;
+
+ smb_io_unistr2("uni_als_name", &(info->uni_als_name),
+ info->hdr_als_name.buffer, ps, depth);
+ smb_io_buffer4("buf_sec_desc", &(info->buf_sec_desc),
+ info->hdr_sec_desc.buffer, ps, depth);
+ smb_io_unistr2("uni_als_desc", &(info->uni_als_desc),
+ info->hdr_als_name.buffer, ps, depth);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_alias_mem_info(char *desc, SAM_ALIAS_MEM_INFO * info,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+
+ prs_debug(ps, depth, desc, "net_io_sam_alias_mem_info");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("num_members", ps, depth, &(info->num_members));
+ prs_uint32("ptr_members", ps, depth, &(info->ptr_members));
+ ps->data_offset += 16;
+
+ if (info->ptr_members != 0)
+ {
+ prs_uint32("num_sids", ps, depth, &(info->num_sids));
+ if (info->num_sids != info->num_members)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ info->ptr_sids = talloc(ps->mem_ctx, sizeof(uint32) *
+ info->num_sids);
+
+ if (info->ptr_sids == NULL) {
+ DEBUG(0, ("out of memory allocating %d ptr_sids\n",
+ info->num_sids));
+ return False;
+ }
+
+ for (i = 0; i < info->num_sids; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "ptr_sids[%02d]", i);
+ prs_uint32(tmp, ps, depth, &(info->ptr_sids[i]));
+ }
+
+ info->sids = talloc(ps->mem_ctx, sizeof(DOM_SID2) *
+ info->num_sids);
+
+ if (info->sids == NULL) {
+ DEBUG(0, ("error allocating %d sids\n",
+ info->num_sids));
+ return False;
+ }
+
+ for (i = 0; i < info->num_sids; i++)
+ {
+ if (info->ptr_sids[i] != 0)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "sids[%02d]",
+ i);
+ smb_io_dom_sid2(tmp, &(info->sids[i]), ps,
+ depth);
+ }
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_ctr(char *desc, uint8 sess_key[16],
+ SAM_DELTA_CTR * delta, uint16 type,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_delta_ctr");
+ depth++;
+
+ switch (type)
+ {
+ /* Seen in sam deltas */
+
+ case SAM_DELTA_SAM_STAMP:
+ {
+ net_io_sam_delta_stamp("", &delta->stamp,
+ ps, depth);
+ break;
+ }
+
+ case SAM_DELTA_DOMAIN_INFO:
+ {
+ net_io_sam_domain_info("", &delta->domain_info,
+ ps, depth);
+ break;
+ }
+ case SAM_DELTA_GROUP_INFO:
+ {
+ net_io_sam_group_info("", &delta->group_info,
+ ps, depth);
+ break;
+ }
+ case SAM_DELTA_ACCOUNT_INFO:
+ {
+ net_io_sam_account_info("", sess_key,
+ &delta->account_info,
+ ps, depth);
+ break;
+ }
+ case SAM_DELTA_GROUP_MEM:
+ {
+ net_io_sam_group_mem_info("", &delta->grp_mem_info,
+ ps, depth);
+ break;
+ }
+ case SAM_DELTA_ALIAS_INFO:
+ {
+ net_io_sam_alias_info("", &delta->alias_info,
+ ps, depth);
+ break;
+ }
+ case SAM_DELTA_ALIAS_MEM:
+ {
+ net_io_sam_alias_mem_info("", &delta->als_mem_info,
+ ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(0,
+ ("Replication error: Unknown delta type 0x%x\n",
+ type));
+ break;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_r_sam_sync(char *desc, uint8 sess_key[16],
+ NET_R_SAM_SYNC * r_s, prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_sync");
+ depth++;
+
+ smb_io_cred("srv_creds", &(r_s->srv_creds), ps, depth);
+ prs_uint32("sync_context", ps, depth, &(r_s->sync_context));
+
+ prs_uint32("ptr_deltas", ps, depth, &(r_s->ptr_deltas));
+ if (r_s->ptr_deltas != 0)
+ {
+ prs_uint32("num_deltas ", ps, depth, &(r_s->num_deltas));
+ prs_uint32("ptr_deltas2", ps, depth, &(r_s->ptr_deltas2));
+ if (r_s->ptr_deltas2 != 0)
+ {
+ prs_uint32("num_deltas2", ps, depth,
+ &(r_s->num_deltas2));
+
+ if (r_s->num_deltas2 != r_s->num_deltas)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ if (r_s->num_deltas2 > 0) {
+ r_s->hdr_deltas = (SAM_DELTA_HDR *)
+ talloc(ps->mem_ctx, r_s->num_deltas2 *
+ sizeof(SAM_DELTA_HDR));
+
+ if (r_s->hdr_deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d delta headers\n",
+ r_s->num_deltas2));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas2; i++)
+ {
+ net_io_sam_delta_hdr("", &r_s->hdr_deltas[i],
+ ps, depth);
+ }
+
+ if (r_s->num_deltas2 > 0) {
+ r_s->deltas = (SAM_DELTA_CTR *)
+ talloc(ps->mem_ctx, r_s->num_deltas2 *
+ sizeof(SAM_DELTA_CTR));
+
+ if (r_s->deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d deltas\n",
+ r_s->num_deltas2));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas2; i++)
+ {
+ net_io_sam_delta_ctr("", sess_key,
+ &r_s->deltas[i],
+ r_s->hdr_deltas[i].type3,
+ ps, depth);
+ }
+ }
+ }
+
+ prs_align(ps);
+ prs_uint32("status", ps, depth, &(r_s->status));
+
+ return True;
+}
+
+/*******************************************************************
+makes a NET_Q_SAM_DELTAS structure.
+********************************************************************/
+BOOL init_net_q_sam_deltas(NET_Q_SAM_DELTAS *q_s, const char *srv_name,
+ const char *cli_name, DOM_CRED *cli_creds,
+ uint32 database_id, UINT64_S dom_mod_count)
+{
+ DEBUG(5, ("init_net_q_sam_deltas\n"));
+
+ init_unistr2(&q_s->uni_srv_name, srv_name, strlen(srv_name) + 1);
+ init_unistr2(&q_s->uni_cli_name, cli_name, strlen(cli_name) + 1);
+
+ memcpy(&q_s->cli_creds, cli_creds, sizeof(q_s->cli_creds));
+ memset(&q_s->ret_creds, 0, sizeof(q_s->ret_creds));
+
+ q_s->database_id = database_id;
+ q_s->dom_mod_count.low = dom_mod_count.low;
+ q_s->dom_mod_count.high = dom_mod_count.high;
+ q_s->max_size = 0xffff;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_q_sam_deltas(char *desc, NET_Q_SAM_DELTAS *q_s, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_q_sam_deltas");
+ depth++;
+
+ smb_io_unistr2("", &q_s->uni_srv_name, True, ps, depth);
+ smb_io_unistr2("", &q_s->uni_cli_name, True, ps, depth);
+
+ smb_io_cred("", &q_s->cli_creds, ps, depth);
+ smb_io_cred("", &q_s->ret_creds, ps, depth);
+
+ prs_uint32("database_id ", ps, depth, &q_s->database_id);
+ prs_uint64("dom_mod_count", ps, depth, &q_s->dom_mod_count);
+ prs_uint32("max_size", ps, depth, &q_s->max_size);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_r_sam_deltas(char *desc, uint8 sess_key[16],
+ NET_R_SAM_DELTAS *r_s, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_deltas");
+ depth++;
+
+ smb_io_cred("srv_creds", &r_s->srv_creds, ps, depth);
+ prs_uint64("dom_mod_count", ps, depth, &r_s->dom_mod_count);
+
+ prs_uint32("ptr_deltas", ps, depth, &r_s->ptr_deltas);
+ prs_uint32("num_deltas", ps, depth, &r_s->num_deltas);
+ prs_uint32("ptr_deltas2", ps, depth, &r_s->num_deltas2);
+
+ if (r_s->num_deltas2 != 0)
+ {
+ prs_uint32("num_deltas2 ", ps, depth, &(r_s->num_deltas2));
+
+ if (r_s->ptr_deltas != 0)
+ {
+ if (r_s->num_deltas > 0) {
+ r_s->hdr_deltas = (SAM_DELTA_HDR *)
+ talloc(ps->mem_ctx, r_s->num_deltas *
+ sizeof(SAM_DELTA_HDR));
+ if (r_s->hdr_deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d delta headers\n",
+ r_s->num_deltas));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas; i++)
+ {
+ net_io_sam_delta_hdr("", &r_s->hdr_deltas[i],
+ ps, depth);
+ }
+
+ if (r_s->num_deltas > 0) {
+ r_s->deltas = (SAM_DELTA_CTR *)
+ talloc(ps->mem_ctx, r_s->num_deltas *
+ sizeof(SAM_DELTA_CTR));
+
+ if (r_s->deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d deltas\n",
+ r_s->num_deltas));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas; i++)
+ {
+ net_io_sam_delta_ctr("", sess_key,
+ &r_s->deltas[i],
+ r_s->hdr_deltas[i].type2,
+ ps, depth);
+ }
+ }
+ }
+
+ prs_align(ps);
+ prs_uint32("status", ps, depth, &(r_s->status));
+
+ return True;
+}
diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c
index 410fd7fb0a..1b49387558 100644
--- a/source3/rpcclient/cmd_netlogon.c
+++ b/source3/rpcclient/cmd_netlogon.c
@@ -81,7 +81,7 @@ static uint32 cmd_netlogon_logon_ctrl(struct cli_state *cli, int argc,
/* Initialise RPC connection */
if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
- DEBUG(0, ("Could not initialize srvsvc pipe!\n"));
+ DEBUG(0, ("Could not initialize netlogon pipe!\n"));
goto done;
}
@@ -98,14 +98,228 @@ static uint32 cmd_netlogon_logon_ctrl(struct cli_state *cli, int argc,
return result;
}
+/* Display sam synchronisation information */
+
+static void display_sam_sync(uint32 num_deltas, SAM_DELTA_HDR *hdr_deltas,
+ SAM_DELTA_CTR *deltas)
+{
+ fstring name;
+ uint32 i, j;
+
+ for (i = 0; i < num_deltas; i++) {
+ switch (hdr_deltas[i].type) {
+ case SAM_DELTA_DOMAIN_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].domain_info.uni_dom_name,
+ sizeof(name) - 1);
+ DEBUG(0, ("Domain: %s\n", name));
+ break;
+ case SAM_DELTA_GROUP_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].group_info.uni_grp_name,
+ sizeof(name) - 1);
+ DEBUG(0, ("Group: %s\n", name));
+ break;
+ case SAM_DELTA_ACCOUNT_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].account_info.uni_acct_name,
+ sizeof(name) - 1);
+ DEBUG(0, ("Account: %s\n", name));
+ break;
+ case SAM_DELTA_ALIAS_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].alias_info.uni_als_name,
+ sizeof(name) - 1);
+ DEBUG(0, ("Alias: %s\n", name));
+ break;
+ case SAM_DELTA_ALIAS_MEM: {
+ SAM_ALIAS_MEM_INFO *alias = &deltas[i].als_mem_info;
+
+ for (j = 0; j < alias->num_members; j++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &alias->sids[j].sid);
+
+ DEBUG(0, ("%s\n", sid_str));
+ }
+ break;
+ }
+ case SAM_DELTA_GROUP_MEM: {
+ SAM_GROUP_MEM_INFO *group = &deltas[i].grp_mem_info;
+
+ for (j = 0; j < group->num_members; j++)
+ DEBUG(0, ("rid 0x%x, attrib 0x%08x\n",
+ group->rids[j], group->attribs[j]));
+ break;
+ }
+ case SAM_DELTA_SAM_STAMP: {
+ SAM_DELTA_STAMP *stamp = &deltas[i].stamp;
+
+ DEBUG(0, ("sam sequence update: 0x%04x\n",
+ stamp->seqnum));
+ break;
+ }
+ default:
+ DEBUG(0, ("unknown delta type 0x%02x\n",
+ hdr_deltas[i].type));
+ break;
+ }
+ }
+}
+
+/* Perform sam synchronisation */
+
+static uint32 cmd_netlogon_sam_sync(struct cli_state *cli, int argc,
+ char **argv)
+{
+ uint32 result = NT_STATUS_UNSUCCESSFUL;
+ unsigned char trust_passwd[16];
+ TALLOC_CTX *mem_ctx;
+ uint32 database_id = 0, num_deltas;
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+
+ if (argc > 2) {
+ printf("Usage: %s [database_id]\n", argv[0]);
+ return 0;
+ }
+
+ if (argc == 2)
+ database_id = atoi(argv[1]);
+
+ if (!secrets_init()) {
+ DEBUG(0, ("Unable to initialise secrets database\n"));
+ return result;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0,("talloc_init failed\n"));
+ return result;
+ }
+
+ /* Initialise RPC connection */
+
+ if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
+ DEBUG(0, ("Could not initialize netlogon pipe!\n"));
+ goto done;
+ }
+
+ /* Initialise session credentials */
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ DEBUG(0, ("could not fetch trust account password\n"));
+ goto done;
+ }
+
+ if (!cli_nt_setup_creds(cli, trust_passwd)) {
+ DEBUG(0, ("Error initialising session creds\n"));
+ goto done;
+ }
+
+ /* Synchronise sam database */
+
+ if ((result = cli_netlogon_sam_sync(cli, mem_ctx, database_id,
+ &num_deltas, &hdr_deltas, &deltas))
+ != NT_STATUS_OK) {
+ goto done;
+ }
+
+ /* Display results */
+
+ display_sam_sync(num_deltas, hdr_deltas, deltas);
+
+ done:
+ cli_nt_session_close(cli);
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Perform sam delta synchronisation */
+
+static uint32 cmd_netlogon_sam_deltas(struct cli_state *cli, int argc,
+ char **argv)
+{
+ uint32 result = NT_STATUS_UNSUCCESSFUL;
+ unsigned char trust_passwd[16];
+ TALLOC_CTX *mem_ctx = NULL;
+ uint32 database_id, num_deltas, tmp;
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+ UINT64_S seqnum;
+
+ if (argc != 3) {
+ printf("Usage: %s database_id seqnum\n", argv[0]);
+ return 0;
+ }
+
+ database_id = atoi(argv[1]);
+ tmp = atoi(argv[2]);
+
+ seqnum.low = tmp & 0xffff;
+ seqnum.high = 0;
+
+ if (!secrets_init()) {
+ DEBUG(0, ("Unable to initialise secrets database\n"));
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0,("talloc_init failed\n"));
+ goto done;
+ }
+
+ /* Initialise RPC connection */
+
+ if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
+ DEBUG(0, ("Could not initialize netlogon pipe!\n"));
+ goto done;
+ }
+
+ /* Initialise session credentials */
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ DEBUG(0, ("could not fetch trust account password\n"));
+ goto done;
+ }
+
+ if (!cli_nt_setup_creds(cli, trust_passwd)) {
+ DEBUG(0, ("Error initialising session creds\n"));
+ goto done;
+ }
+
+ /* Synchronise sam database */
+
+ if ((result = cli_netlogon_sam_deltas(cli, mem_ctx, database_id,
+ seqnum, &num_deltas,
+ &hdr_deltas, &deltas))
+ != NT_STATUS_OK) {
+ goto done;
+ }
+
+ /* Display results */
+
+ display_sam_sync(num_deltas, hdr_deltas, deltas);
+
+ done:
+ cli_nt_session_close(cli);
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
/* List of commands exported by this module */
struct cmd_set netlogon_commands[] = {
{ "NETLOGON" },
- { "logonctrl2", cmd_netlogon_logon_ctrl2, "Logon Control 2", "" },
- { "logonctrl", cmd_netlogon_logon_ctrl, "Logon Control", "" },
+ { "logonctrl2", cmd_netlogon_logon_ctrl2, "Logon Control 2", "" },
+ { "logonctrl", cmd_netlogon_logon_ctrl, "Logon Control", "" },
+ { "samsync", cmd_netlogon_sam_sync, "Sam Synchronisation", "" },
+ { "samdeltas", cmd_netlogon_sam_deltas, "Query Sam Deltas", "" },
{ NULL }
};