Merge of sam sync code from TNG.
authorTim Potter <tpot@samba.org>
Tue, 28 Aug 2001 06:43:43 +0000 (06:43 +0000)
committerTim Potter <tpot@samba.org>
Tue, 28 Aug 2001 06:43:43 +0000 (06:43 +0000)
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.

source/include/rpc_misc.h
source/libsmb/cli_netlogon.c
source/rpc_parse/parse_misc.c
source/rpc_parse/parse_net.c
source/rpcclient/cmd_netlogon.c

index 428db938ded421c8f803051632b38fad65b8e683..558c28459e3cd7fe496bc07988398682fec18b2a 100644 (file)
@@ -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 */
index 63a2f4a5b1983bd3df6b4115fb5faf5cde37f672..b608398aa3c205937d8d290dda659244822f0276 100644 (file)
@@ -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;
+}
index 1a30d3d7a195dd396cd0d28dcedd8f430dfd839e..2a6560f8ceab4eac4d9e1afff2b510daba8f8021 100644 (file)
@@ -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;
+}
index e8f0c02a52f17ec737655820e0057b056cd2cfaa..37bf6755b7bbe1072a4385d95457d36772cbae42 100644 (file)
@@ -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;
+}
index 410fd7fb0a3a254dbfe16972d271a3f396354e7b..1b493875585ab73598bf5647714bfb051af9acd4 100644 (file)
@@ -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 }
 };