r5414: - added libcli/wins/, a basic client library for WINS replication
authorAndrew Tridgell <tridge@samba.org>
Wed, 16 Feb 2005 10:03:18 +0000 (10:03 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:10:43 +0000 (13:10 -0500)
- added a new IDL type "udlongr", which is like udlong, but with the
  two uint32 halves reversed

- modified the winsrepl.idl to cope with a wider range of packets
(This used to be commit bc8d60c918f2e268d591aac464fc6a78c38a4cf9)

source4/build/pidl/ndr.pm
source4/build/pidl/util.pm
source4/include/structs.h
source4/libcli/config.mk
source4/libcli/wins/winsrepl.c [new file with mode: 0644]
source4/libcli/wins/winsrepl.h [new file with mode: 0644]
source4/librpc/idl/idl_types.h
source4/librpc/idl/nbt.idl
source4/librpc/idl/winsrepl.idl
source4/librpc/ndr/ndr_basic.c

index 098729ad945965cd65c7ab1b0d21c1883f700192..81a909c472ebcfa5c40aef2585bcd1a1f7c3e8d6 100644 (file)
@@ -30,6 +30,7 @@ sub RegisterPrimitives()
      "uint32"         => 4,
      "dlong"          => 4,
      "udlong"         => 4,
+     "udlongr"        => 4,
      "NTTIME"         => 4,
      "NTTIME_1sec"    => 4,
      "time_t"         => 4,
index 02a7518ccf39fa256c53b55d80336e078c059c4e..8e87215fd879f85308730d5e8a01e8353d049882 100644 (file)
@@ -327,6 +327,7 @@ my %type_mappings =
      "uint64"       => "uint64_t",
      "dlong"        => "int64_t",
      "udlong"       => "uint64_t",
+     "udlongr"      => "uint64_t",
      "hyper"        => "uint64_t",
      "NTTIME_1sec"  => "NTTIME",
      "NTTIME_hyper" => "NTTIME",
index 8b566fd3f5febb018e3ab1d5c9cdccbdb61156e3..0804c90e7994f797d211b742cc190ad43120de56 100644 (file)
@@ -180,3 +180,4 @@ struct mutex_ops;
 
 struct ads_struct;
 
+struct wrepl_packet;
index 726d3f11845189cee55c9ab17261a92d86c1d674..e6be2ed05847ad69743fd9c1f88faa316bd7b1c0 100644 (file)
@@ -35,6 +35,11 @@ ADD_OBJ_FILES = \
        libcli/nbt/namerelease.o
 REQUIRED_SUBSYSTEMS = LIBNDR_RAW NDR_NBT SOCKET LIBCLI_COMPOSITE_BASE LIBEVENTS
 
+[SUBSYSTEM::LIBCLI_WINS]
+ADD_OBJ_FILES = \
+       libcli/wins/winsrepl.o
+REQUIRED_SUBSYSTEMS = LIBCLI_NBT NDR_WINS SOCKET LIBEVENTS
+
 [SUBSYSTEM::LIBCLI_RESOLVE]
 ADD_OBJ_FILES = \
        libcli/resolve/resolve.o \
diff --git a/source4/libcli/wins/winsrepl.c b/source4/libcli/wins/winsrepl.c
new file mode 100644 (file)
index 0000000..6ee9482
--- /dev/null
@@ -0,0 +1,436 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   low level WINS replication client code
+
+   Copyright (C) Andrew Tridgell 2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "dlinklist.h"
+#include "lib/socket/socket.h"
+#include "libcli/wins/winsrepl.h"
+
+/*
+  mark all pending requests as dead - called when a socket error happens
+*/
+static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket)
+{
+       event_set_fd_flags(wrepl_socket->fde, 0);
+
+       while (wrepl_socket->send_queue) {
+               struct wrepl_request *req = wrepl_socket->send_queue;
+               DLIST_REMOVE(wrepl_socket->send_queue, req);
+               req->state = WREPL_REQUEST_ERROR;
+               req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               if (req->async.fn) {
+                       req->async.fn(req);
+               }
+       }
+       while (wrepl_socket->recv_queue) {
+               struct wrepl_request *req = wrepl_socket->recv_queue;
+               DLIST_REMOVE(wrepl_socket->recv_queue, req);
+               req->state = WREPL_REQUEST_ERROR;
+               req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               if (req->async.fn) {
+                       req->async.fn(req);
+               }
+       }
+}
+
+/*
+  handle send events 
+*/
+static void wrepl_handler_send(struct wrepl_socket *wrepl_socket)
+{
+       while (wrepl_socket->send_queue) {
+               struct wrepl_request *req = wrepl_socket->send_queue;
+               size_t nsent;
+               NTSTATUS status;
+
+               status = socket_send(wrepl_socket->sock, &req->buffer, &nsent, 0);
+               if (NT_STATUS_IS_ERR(status)) {
+                       wrepl_socket_dead(wrepl_socket);
+                       return;
+               }
+               if (!NT_STATUS_IS_OK(status) || nsent == 0) return;
+
+               req->buffer.data   += nsent;
+               req->buffer.length -= nsent;
+               if (req->buffer.length != 0) {
+                       return;
+               }
+
+               DLIST_REMOVE(wrepl_socket->send_queue, req);
+               DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
+               req->state = WREPL_REQUEST_RECV;
+
+               EVENT_FD_READABLE(wrepl_socket->fde);
+       }
+
+       EVENT_FD_NOT_WRITEABLE(wrepl_socket->fde);
+}
+
+
+/*
+  handle recv events 
+*/
+static void wrepl_handler_recv(struct wrepl_socket *wrepl_socket)
+{
+       size_t nread;
+       struct wrepl_request *req = wrepl_socket->recv_queue;
+       DATA_BLOB blob;
+
+       if (req == NULL) {
+               EVENT_FD_NOT_READABLE(wrepl_socket->fde);
+               return;
+       }
+
+       if (req->buffer.length == 0) {
+               req->buffer = data_blob_talloc(req, NULL, 4);
+               if (req->buffer.data == NULL) {
+                       req->status = NT_STATUS_NO_MEMORY;
+                       goto failed;
+               }
+               req->num_read = 0;
+       }
+
+       /* read in the packet length */
+       if (req->num_read < 4) {
+               uint32_t req_length;
+
+               req->status = socket_recv(wrepl_socket->sock, 
+                                         req->buffer.data + req->num_read,
+                                         4 - req->num_read,
+                                         &nread, 0);
+               if (NT_STATUS_IS_ERR(req->status)) goto failed;
+               if (!NT_STATUS_IS_OK(req->status)) return;
+
+               req->num_read += nread;
+               if (req->num_read != 4) return;
+
+               req_length = RIVAL(req->buffer.data, 0) + 4;
+
+               req->buffer.data = talloc_realloc(req, req->buffer.data, 
+                                                 uint8_t, req_length);
+               if (req->buffer.data == NULL) {
+                       req->status = NT_STATUS_NO_MEMORY;
+                       goto failed;
+               }
+               req->buffer.length = req_length;
+       }
+
+       /* read in the body */
+       req->status = socket_recv(wrepl_socket->sock, 
+                                 req->buffer.data + req->num_read,
+                                 req->buffer.length - req->num_read,
+                                 &nread, 0);
+       if (NT_STATUS_IS_ERR(req->status)) goto failed;
+       if (!NT_STATUS_IS_OK(req->status)) return;
+
+       req->num_read += nread;
+       if (req->num_read != req->buffer.length) return;
+
+       req->packet = talloc(req, struct wrepl_packet);
+       if (req->packet == NULL) {
+               req->status = NT_STATUS_NO_MEMORY;
+               goto failed;
+       }
+
+       blob.data = req->buffer.data + 4;
+       blob.length = req->buffer.length - 4;
+       
+       /* we have a full request - parse it */
+       req->status = ndr_pull_struct_blob(&blob,
+                                          req->packet, req->packet,
+                                          (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
+       if (!NT_STATUS_IS_OK(req->status)) {
+               DEBUG(2,("Failed to parse incoming WINS packet - %s\n",
+                        nt_errstr(req->status)));
+               DEBUG(10,("packet length %d\n", req->buffer.length));
+               NDR_PRINT_DEBUG(wrepl_packet, req->packet);
+               goto failed;
+       }
+
+       if (DEBUGLVL(10)) {
+               DEBUG(10,("Received WINS packet of length %d\n", req->buffer.length));
+               NDR_PRINT_DEBUG(wrepl_packet, req->packet);
+       }
+
+       DLIST_REMOVE(wrepl_socket->recv_queue, req);
+       req->state = WREPL_REQUEST_DONE;
+       if (req->async.fn) {
+               req->async.fn(req);
+       }
+       return;
+
+failed:
+       if (req->state == WREPL_REQUEST_RECV) {
+               DLIST_REMOVE(wrepl_socket->recv_queue, req);
+       }
+       req->state = WREPL_REQUEST_ERROR;
+       if (req->async.fn) {
+               req->async.fn(req);
+       }
+}
+
+
+/*
+  handler for winrepl events
+*/
+static void wrepl_handler(struct event_context *ev, struct fd_event *fde, 
+                         uint16_t flags, void *private)
+{
+       struct wrepl_socket *wrepl_socket = talloc_get_type(private, 
+                                                           struct wrepl_socket);
+       if (flags & EVENT_FD_WRITE) {
+               wrepl_handler_send(wrepl_socket);
+               return;
+       }
+       if (flags & EVENT_FD_READ) {
+               wrepl_handler_recv(wrepl_socket);
+       }
+}
+
+
+/*
+  handler for winrepl connection completion
+*/
+static void wrepl_connect_handler(struct event_context *ev, struct fd_event *fde, 
+                                 uint16_t flags, void *private)
+{
+       struct wrepl_socket *wrepl_socket = talloc_get_type(private, 
+                                                           struct wrepl_socket);
+       struct wrepl_request *req = wrepl_socket->recv_queue;
+
+       talloc_free(fde);
+
+       if (req == NULL) return;
+
+       req->status = socket_connect_complete(wrepl_socket->sock, 0);
+       if (NT_STATUS_IS_ERR(req->status)) goto failed;
+
+       if (!NT_STATUS_IS_OK(req->status)) return;
+
+       wrepl_socket->fde = event_add_fd(wrepl_socket->event_ctx, wrepl_socket, 
+                                        socket_get_fd(wrepl_socket->sock), 
+                                        0,
+                                        wrepl_handler, wrepl_socket);
+       if (wrepl_socket->fde == NULL) {
+               req->status = NT_STATUS_NO_MEMORY;
+       }
+
+
+failed:
+       DLIST_REMOVE(wrepl_socket->recv_queue, req);
+       if (!NT_STATUS_IS_OK(req->status)) {
+               req->state = WREPL_REQUEST_ERROR;
+       } else {
+               req->state = WREPL_REQUEST_DONE;
+       }
+       if (req->async.fn) {
+               req->async.fn(req);
+       }
+}
+
+
+/*
+  initialise a wrepl_socket. The event_ctx is optional, if provided then
+  operations will use that event context
+*/
+struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, 
+                                      struct event_context *event_ctx)
+{
+       struct wrepl_socket *wrepl_socket;
+       NTSTATUS status;
+
+       wrepl_socket = talloc(mem_ctx, struct wrepl_socket);
+       if (wrepl_socket == NULL) goto failed;
+
+       if (event_ctx == NULL) {
+               wrepl_socket->event_ctx = event_context_init(wrepl_socket);
+       } else {
+               wrepl_socket->event_ctx = talloc_reference(wrepl_socket, event_ctx);
+       }
+       if (wrepl_socket->event_ctx == NULL) goto failed;
+
+       status = socket_create("ip", SOCKET_TYPE_STREAM, &wrepl_socket->sock, 0);
+       if (!NT_STATUS_IS_OK(status)) goto failed;
+
+       talloc_steal(wrepl_socket, wrepl_socket->sock);
+
+       wrepl_socket->send_queue = NULL;
+       wrepl_socket->recv_queue = NULL;
+
+       wrepl_socket->fde = event_add_fd(wrepl_socket->event_ctx, wrepl_socket, 
+                                        socket_get_fd(wrepl_socket->sock), 
+                                        EVENT_FD_WRITE,
+                                        wrepl_connect_handler, wrepl_socket);
+
+       set_blocking(socket_get_fd(wrepl_socket->sock), False);
+       
+       return wrepl_socket;
+
+failed:
+       talloc_free(wrepl_socket);
+       return NULL;
+}
+
+
+/*
+  destroy a wrepl_request
+*/
+static int wrepl_request_destructor(void *ptr)
+{
+       struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
+       if (req->state == WREPL_REQUEST_SEND) {
+               DLIST_REMOVE(req->wrepl_socket->send_queue, req);
+       }
+       if (req->state == WREPL_REQUEST_RECV) {
+               DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
+       }
+       req->state = WREPL_REQUEST_ERROR;
+       return 0;
+}
+
+/*
+  wait for a request to complete
+*/
+static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
+{
+       NT_STATUS_HAVE_NO_MEMORY(req);
+       while (req->state < WREPL_REQUEST_DONE) {
+               event_loop_once(req->wrepl_socket->event_ctx);
+       }
+       return req->status;
+}
+
+
+/*
+  connect a wrepl_socket to a WINS server
+*/
+struct wrepl_request *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
+                                        const char *address)
+{
+       struct wrepl_request *req;
+       NTSTATUS status;
+
+       req = talloc_zero(wrepl_socket, struct wrepl_request);
+       if (req == NULL) goto failed;
+
+       req->wrepl_socket = wrepl_socket;
+       req->state        = WREPL_REQUEST_RECV;
+
+       DLIST_ADD(wrepl_socket->recv_queue, req);
+
+       talloc_set_destructor(req, wrepl_request_destructor);
+       
+       status = socket_connect(wrepl_socket->sock, NULL, 0, address, 
+                               WINS_REPLICATION_PORT, 0);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) goto failed;
+
+       return req;
+
+failed:
+       talloc_free(req);
+       return NULL;
+}
+
+/*
+  connect a wrepl_socket to a WINS server - recv side
+*/
+NTSTATUS wrepl_connect_recv(struct wrepl_request *req)
+{
+       return wrepl_request_wait(req);
+}
+
+
+/*
+  connect a wrepl_socket to a WINS server - sync API
+*/
+NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, const char *address)
+{
+       struct wrepl_request *req = wrepl_connect_send(wrepl_socket, address);
+       return wrepl_connect_recv(req);
+}
+
+
+/*
+  send a generic wins replication request
+*/
+struct wrepl_request *wrepl_request_send(struct wrepl_socket *wrepl_socket,
+                                        struct wrepl_packet *packet)
+{
+       struct wrepl_request *req;
+       struct wrepl_wrap wrap;
+
+       req = talloc_zero(wrepl_socket, struct wrepl_request);
+       if (req == NULL) goto failed;
+
+       req->wrepl_socket = wrepl_socket;
+       req->state        = WREPL_REQUEST_SEND;
+
+       wrap.packet = *packet;
+       req->status = ndr_push_struct_blob(&req->buffer, req, &wrap,
+                                          (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);   
+       if (!NT_STATUS_IS_OK(req->status)) goto failed;
+
+       if (DEBUGLVL(10)) {
+               DEBUG(10,("Sending WINS packet of length %d\n", req->buffer.length));
+               NDR_PRINT_DEBUG(wrepl_packet, &wrap.packet);
+       }
+
+       DLIST_ADD(wrepl_socket->send_queue, req);
+
+       talloc_set_destructor(req, wrepl_request_destructor);
+
+       EVENT_FD_WRITEABLE(wrepl_socket->fde);
+       
+       return req;
+
+failed:
+       talloc_free(req);
+       return NULL;
+}
+
+/*
+  receive a generic WINS replication reply
+*/
+NTSTATUS wrepl_request_recv(struct wrepl_request *req,
+                           TALLOC_CTX *mem_ctx,
+                           struct wrepl_packet **packet)
+{
+       NTSTATUS status = wrepl_request_wait(req);
+       if (NT_STATUS_IS_OK(status)) {
+               *packet = talloc_steal(mem_ctx, req->packet);
+       }
+       talloc_free(req);
+       return status;
+}
+
+/*
+  a full WINS replication request/response
+*/
+NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
+                      TALLOC_CTX *mem_ctx,
+                      struct wrepl_packet *req_packet,
+                      struct wrepl_packet **reply_packet)
+{
+       struct wrepl_request *req = wrepl_request_send(wrepl_socket, req_packet);
+       return wrepl_request_recv(req, mem_ctx, reply_packet);
+}
diff --git a/source4/libcli/wins/winsrepl.h b/source4/libcli/wins/winsrepl.h
new file mode 100644 (file)
index 0000000..3fd1e54
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   structures for WINS replication client library
+
+   Copyright (C) Andrew Tridgell 2005
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "librpc/gen_ndr/ndr_winsrepl.h"
+
+/*
+  main context structure for the wins replication client library
+*/
+struct wrepl_socket {
+       struct socket_context *sock;
+       struct event_context *event_ctx;
+
+       /* a queue of requests pending to be sent */
+       struct wrepl_request *send_queue;
+
+       /* a queue of replies waiting to be received */
+       struct wrepl_request *recv_queue;
+
+       /* the fd event */
+       struct fd_event *fde;
+};
+
+enum wrepl_request_state {
+       WREPL_REQUEST_SEND  = 0,
+       WREPL_REQUEST_RECV  = 1,
+       WREPL_REQUEST_DONE  = 2,
+       WREPL_REQUEST_ERROR = 3
+};
+
+/*
+  a WINS replication request
+*/
+struct wrepl_request {
+       struct wrepl_request *next, *prev;
+       struct wrepl_socket *wrepl_socket;
+
+       enum wrepl_request_state state;
+       NTSTATUS status;
+
+       DATA_BLOB buffer;
+
+       size_t num_read;
+
+       struct wrepl_packet *packet;
+
+       struct {
+               void (*fn)(struct wrepl_request *);
+               void *private;
+       } async;
+};
index 1db778476c69d85d4cbfa0bf0aaffab28845d815..d4f2479d48944437d4c09cba49a90e0f21905bd1 100644 (file)
@@ -81,7 +81,6 @@
 */
 #define utf8string       [flag(STR_UTF8|STR_NULLTERM)]                string
 
-
 #define NDR_NOALIGN       LIBNDR_FLAG_NOALIGN
 #define NDR_REMAINING     LIBNDR_FLAG_REMAINING
 #define NDR_ALIGN2        LIBNDR_FLAG_ALIGN2
index a5c5f469621149dcf4a4d39e058391e981d4ca78..04fe0c4f90507e207ed86d14f5d37f4722e403b4 100644 (file)
@@ -50,7 +50,7 @@ interface nbt
 
        /* we support any 8bit name type, but by defining the common
           ones here we get better debug displays */
-       typedef [enum8bit,public] enum {
+       typedef [enum8bit] enum {
                NBT_NAME_CLIENT   = 0x00,
                NBT_NAME_MS       = 0x01,
                NBT_NAME_USER     = 0x03,
index 919d3a94bbba0b8c760611078a471c36f82f183a..cec82a51066820149397b60e9e60a02592dfe459 100644 (file)
 [
   uuid("0-1-2-3-4"),
   version(0.0),
-  pointer_default(unique),
-  depends(nbt)
+  pointer_default(unique)
 ]
 interface wrepl
 {
        const int WINS_REPLICATION_PORT = 42;
 
-       declare enum nbt_name_type;
-
        typedef [flag(NDR_BIG_ENDIAN)] struct {
                ipv4address owner;
                ipv4address ip;
        } wrepl_ip;
 
        typedef [flag(NDR_LITTLE_ENDIAN)] struct {
-               uint32 num_ips;
-               wrepl_ip ips[num_ips];
+               uint32      num_ips;
+               wrepl_ip    ips[num_ips];
                ipv4address unknown;
        } wrepl_address_list;
 
        typedef [nodiscriminant] union {
-               [case(0)] wrepl_ip address;
+               [case(0)] wrepl_ip           address;
                [case(2)] wrepl_address_list addresses;
        } wrepl_addresses;
 
        typedef struct {
-               uint32 id_high;
-               uint32 id_low;
-       } wrepl_id;
-
-       typedef struct {
-               uint32 name_len;
-               astring15 name;
-               nbt_name_type type;
-               uint32 unknown;
-               uint32 flags;
+               uint32    name_len;
+               uint8     name[name_len];
+               uint32    flags;
                [flag(NDR_LITTLE_ENDIAN)] uint32 group_flag;
-               wrepl_id id;
+               udlongr   id;
                [switch_is(flags & 2)] wrepl_addresses addresses;
        } wrepl_wins_name;
 
        typedef struct {
-               uint32 num_names;
+               uint32          num_names;
                wrepl_wins_name names[num_names];
        } wrepl_send_reply;
 
        typedef struct {
                ipv4address address;
-               wrepl_id max_version;
-               wrepl_id min_version;
-               uint32 type;
+               udlongr     max_version;
+               udlongr     min_version;
+               uint32      type;
        } wrepl_wins_owner;
 
        typedef struct {
-               uint32 partner_count;
+               uint32           partner_count;
                wrepl_wins_owner partners[partner_count];
-               ipv4address initiator;
+               ipv4address      initiator;
        } wrepl_table;
 
        typedef [v1_enum] enum {
@@ -82,11 +72,11 @@ interface wrepl
 
        typedef [nodiscriminant] union {
                [case(WREPL_REPL_TABLE_QUERY)] ;
-               [case(WREPL_REPL_TABLE_REPLY)] wrepl_table table;
+               [case(WREPL_REPL_TABLE_REPLY)]  wrepl_table      table;
                [case(WREPL_REPL_SEND_REQUEST)] wrepl_wins_owner owner;
-               [case(WREPL_REPL_SEND_REPLY)] wrepl_send_reply reply;
+               [case(WREPL_REPL_SEND_REPLY)]   wrepl_send_reply reply;
                [case(WREPL_REPL_UPDATE)] ;
-               [case(WREPL_REPL_INFORM)] wrepl_table table;
+               [case(WREPL_REPL_INFORM)]       wrepl_table      table;
        } wrepl_replication_info;
 
        typedef struct {
@@ -112,23 +102,30 @@ interface wrepl
        } wrepl_mess_type;
 
        typedef [nodiscriminant] union {
-               [case(WREPL_START_ASSOCIATION)] wrepl_start start;
+               [case(WREPL_START_ASSOCIATION)]       wrepl_start start;
                [case(WREPL_START_ASSOCIATION_REPLY)] wrepl_start start_reply;
-               [case(WREPL_STOP_ASSOCIATION)] wrepl_stop stop;
-               [case(WREPL_REPLICATION)] wrepl_replication replication;
+               [case(WREPL_STOP_ASSOCIATION)]        wrepl_stop stop;
+               [case(WREPL_REPLICATION)]             wrepl_replication replication;
        } wrepl_message;
 
+       /*
+         the opcode appears to be a bitfield, but as far as I can tell
+         you must always set the following bits. Additional bits don't
+         seem to matter. Very strange.
+       */
+       const int WREPL_OPCODE_BITS = 0x7800;
+
 
-       typedef [gensize,flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
-               uint32          opcode;
-               uint32          assoc_ctx;
-               wrepl_mess_type mess_type;
+       typedef [gensize,flag(NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+               uint32                 opcode;
+               uint32                 assoc_ctx;
+               wrepl_mess_type        mess_type;
                [switch_is(mess_type)] wrepl_message message;
                [flag(NDR_REMAINING)] DATA_BLOB padding;
        } wrepl_packet;
 
-       typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
-               [value(ndr_size_wrepl_packet(&r->packet, ndr->flags))] uint32          size;
+       typedef [flag(NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+               [value(ndr_size_wrepl_packet(&r->packet, ndr->flags))] uint32 size;
                wrepl_packet    packet;
        } wrepl_wrap;
 
index 5eecb1d60bb05499c3d0e50d6d97053fca15a261..5f91cef2e8add6de80441e2b402b2538ca48f651 100644 (file)
@@ -131,6 +131,19 @@ NTSTATUS ndr_pull_udlong(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
        return NT_STATUS_OK;
 }
 
+/*
+  parse a udlongr
+*/
+NTSTATUS ndr_pull_udlongr(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
+{
+       NDR_PULL_ALIGN(ndr, 4);
+       NDR_PULL_NEED_BYTES(ndr, 8);
+       *v = ((uint64_t)NDR_IVAL(ndr, ndr->offset)) << 32;
+       *v |= NDR_IVAL(ndr, ndr->offset+4);
+       ndr->offset += 8;
+       return NT_STATUS_OK;
+}
+
 /*
   parse a dlong
 */
@@ -329,7 +342,7 @@ NTSTATUS ndr_push_int32(struct ndr_push *ndr, int ndr_flags, int32_t v)
 }
 
 /*
-  push a uint64
+  push a udlong
 */
 NTSTATUS ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v)
 {
@@ -341,6 +354,19 @@ NTSTATUS ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v)
        return NT_STATUS_OK;
 }
 
+/*
+  push a udlongr
+*/
+NTSTATUS ndr_push_udlongr(struct ndr_push *ndr, int ndr_flags, uint64_t v)
+{
+       NDR_PUSH_ALIGN(ndr, 4);
+       NDR_PUSH_NEED_BYTES(ndr, 8);
+       NDR_SIVAL(ndr, ndr->offset+4, (v>>32));
+       NDR_SIVAL(ndr, ndr->offset, (v & 0xFFFFFFFF));
+       ndr->offset += 8;
+       return NT_STATUS_OK;
+}
+
 /*
   push a int64
 */
@@ -1107,6 +1133,11 @@ void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v)
                   v);
 }
 
+void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+       ndr_print_udlong(ndr, name, v);
+}
+
 void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v)
 {
        ndr->print(ndr, "%-25s: 0x%08x%08x (%lld)", name,