summaryrefslogtreecommitdiff
path: root/source4/wrepld
diff options
context:
space:
mode:
Diffstat (limited to 'source4/wrepld')
-rw-r--r--source4/wrepld/parser.c759
-rw-r--r--source4/wrepld/partners.c200
-rw-r--r--source4/wrepld/process.c983
-rw-r--r--source4/wrepld/server.c737
-rw-r--r--source4/wrepld/socket.c69
-rw-r--r--source4/wrepld/wins_repl.h161
6 files changed, 2909 insertions, 0 deletions
diff --git a/source4/wrepld/parser.c b/source4/wrepld/parser.c
new file mode 100644
index 0000000000..b619cb0cef
--- /dev/null
+++ b/source4/wrepld/parser.c
@@ -0,0 +1,759 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Jean François Micouleau 1998-2002.
+ *
+ * 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 "wins_repl.h"
+
+extern TALLOC_CTX *mem_ctx;
+
+/****************************************************************************
+grow the send buffer if necessary
+****************************************************************************/
+BOOL grow_buffer(struct BUFFER *buffer, int more)
+{
+ char *temp;
+
+ DEBUG(10,("grow_buffer: size is: %d offet is:%d growing by %d\n", buffer->length, buffer->offset, more));
+
+ /* grow by at least 256 bytes */
+ if (more<256)
+ more=256;
+
+ if (buffer->offset+more >= buffer->length) {
+ temp=(char *)talloc_realloc(mem_ctx, buffer->buffer, sizeof(char)* (buffer->length+more) );
+ if (temp==NULL) {
+ DEBUG(0,("grow_buffer: can't grow buffer\n"));
+ return False;
+ }
+ buffer->length+=more;
+ buffer->buffer=temp;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+check if the buffer has that much data
+****************************************************************************/
+static BOOL check_buffer(struct BUFFER *buffer, int more)
+{
+ DEBUG(10,("check_buffer: size is: %d offet is:%d growing by %d\n", buffer->length, buffer->offset, more));
+
+ if (buffer->offset+more > buffer->length) {
+ DEBUG(10,("check_buffer: buffer smaller than requested, size is: %d needed: %d\n", buffer->length, buffer->offset+more));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+decode a WINS_OWNER struct
+****************************************************************************/
+static void decode_wins_owner(struct BUFFER *inbuf, WINS_OWNER *wins_owner)
+{
+ if(!check_buffer(inbuf, 24))
+ return;
+
+ wins_owner->address.s_addr=IVAL(inbuf->buffer, inbuf->offset);
+ wins_owner->max_version=((SMB_BIG_UINT)RIVAL(inbuf->buffer, inbuf->offset+4))<<32;
+ wins_owner->max_version|=RIVAL(inbuf->buffer, inbuf->offset+8);
+ wins_owner->min_version=((SMB_BIG_UINT)RIVAL(inbuf->buffer, inbuf->offset+12))<<32;
+ wins_owner->min_version|=RIVAL(inbuf->buffer, inbuf->offset+16);
+ wins_owner->type=RIVAL(inbuf->buffer, inbuf->offset+20);
+ inbuf->offset+=24;
+
+}
+
+/****************************************************************************
+decode a WINS_NAME struct
+****************************************************************************/
+static void decode_wins_name(struct BUFFER *outbuf, WINS_NAME *wins_name)
+{
+ char *p;
+ int i;
+
+ if(!check_buffer(outbuf, 40))
+ return;
+
+ wins_name->name_len=RIVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+ memcpy(wins_name->name,outbuf->buffer+outbuf->offset, 15);
+ wins_name->name[15]='\0';
+ if((p = strchr(wins_name->name,' ')) != NULL)
+ *p = 0;
+
+ outbuf->offset+=15;
+
+ wins_name->type=(int)outbuf->buffer[outbuf->offset++];
+
+ /*
+ * fix to bug in WINS replication,
+ * present in all versions including W2K SP2 !
+ */
+ if (wins_name->name[0]==0x1B) {
+ wins_name->name[0]=(char)wins_name->type;
+ wins_name->type=0x1B;
+ }
+
+ wins_name->empty=RIVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+
+ wins_name->name_flag=RIVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+ wins_name->group_flag=RIVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+ wins_name->id=((SMB_BIG_UINT)RIVAL(outbuf->buffer, outbuf->offset))<<32;
+ outbuf->offset+=4;
+ wins_name->id|=RIVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+
+ /* special groups have multiple address */
+ if (wins_name->name_flag & 2) {
+ if(!check_buffer(outbuf, 4))
+ return;
+ wins_name->num_ip=IVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+ }
+ else
+ wins_name->num_ip=1;
+
+ if(!check_buffer(outbuf, 4))
+ return;
+ wins_name->owner.s_addr=IVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+
+ if (wins_name->name_flag & 2) {
+ wins_name->others=(struct in_addr *)talloc(mem_ctx, sizeof(struct in_addr)*wins_name->num_ip);
+ if (wins_name->others==NULL)
+ return;
+
+ if(!check_buffer(outbuf, 4*wins_name->num_ip))
+ return;
+ for (i=0; i<wins_name->num_ip; i++) {
+ wins_name->others[i].s_addr=IVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+ }
+ }
+
+ if(!check_buffer(outbuf, 4))
+ return;
+ wins_name->foo=RIVAL(outbuf->buffer, outbuf->offset);
+ outbuf->offset+=4;
+
+}
+
+/****************************************************************************
+decode a update notification request
+****************************************************************************/
+static void decode_update_notify_request(struct BUFFER *inbuf, UPDATE_NOTIFY_REQUEST *un_rq)
+{
+ int i;
+
+ if(!check_buffer(inbuf, 4))
+ return;
+ un_rq->partner_count=RIVAL(inbuf->buffer, inbuf->offset);
+ inbuf->offset+=4;
+
+ un_rq->wins_owner=(WINS_OWNER *)talloc(mem_ctx, un_rq->partner_count*sizeof(WINS_OWNER));
+ if (un_rq->wins_owner==NULL)
+ return;
+
+ for (i=0; i<un_rq->partner_count; i++)
+ decode_wins_owner(inbuf, &un_rq->wins_owner[i]);
+
+ if(!check_buffer(inbuf, 4))
+ return;
+ un_rq->initiating_wins_server.s_addr=IVAL(inbuf->buffer, inbuf->offset);
+ inbuf->offset+=4;
+}
+
+/****************************************************************************
+decode a send entries request
+****************************************************************************/
+static void decode_send_entries_request(struct BUFFER *inbuf, SEND_ENTRIES_REQUEST *se_rq)
+{
+ decode_wins_owner(inbuf, &se_rq->wins_owner);
+}
+
+/****************************************************************************
+decode a send entries reply
+****************************************************************************/
+static void decode_send_entries_reply(struct BUFFER *inbuf, SEND_ENTRIES_REPLY *se_rp)
+{
+ int i;
+
+ if(!check_buffer(inbuf, 4))
+ return;
+ se_rp->max_names = RIVAL(inbuf->buffer, inbuf->offset);
+ inbuf->offset+=4;
+
+ se_rp->wins_name=(WINS_NAME *)talloc(mem_ctx, se_rp->max_names*sizeof(WINS_NAME));
+ if (se_rp->wins_name==NULL)
+ return;
+
+ for (i=0; i<se_rp->max_names; i++)
+ decode_wins_name(inbuf, &se_rp->wins_name[i]);
+}
+
+/****************************************************************************
+decode a add version number map table reply
+****************************************************************************/
+static void decode_add_version_number_map_table_reply(struct BUFFER *inbuf, AVMT_REP *avmt_rep)
+{
+ int i;
+
+ if(!check_buffer(inbuf, 4))
+ return;
+
+ avmt_rep->partner_count=RIVAL(inbuf->buffer, inbuf->offset);
+ inbuf->offset+=4;
+
+ avmt_rep->wins_owner=(WINS_OWNER *)talloc(mem_ctx, avmt_rep->partner_count*sizeof(WINS_OWNER));
+ if (avmt_rep->wins_owner==NULL)
+ return;
+
+ for (i=0; i<avmt_rep->partner_count; i++)
+ decode_wins_owner(inbuf, &avmt_rep->wins_owner[i]);
+
+ if(!check_buffer(inbuf, 4))
+ return;
+ avmt_rep->initiating_wins_server.s_addr=IVAL(inbuf->buffer, inbuf->offset);
+ inbuf->offset+=4;
+}
+
+/****************************************************************************
+decode a replicate packet and fill a structure
+****************************************************************************/
+static void decode_replicate(struct BUFFER *inbuf, REPLICATE *rep)
+{
+ if(!check_buffer(inbuf, 4))
+ return;
+
+ rep->msg_type = RIVAL(inbuf->buffer, inbuf->offset);
+
+ inbuf->offset+=4;
+
+ switch (rep->msg_type) {
+ case 0:
+ break;
+ case 1:
+ /* add version number map table reply */
+ decode_add_version_number_map_table_reply(inbuf, &rep->avmt_rep);
+ break;
+ case 2:
+ /* send entry request */
+ decode_send_entries_request(inbuf, &rep->se_rq);
+ break;
+ case 3:
+ /* send entry request */
+ decode_send_entries_reply(inbuf, &rep->se_rp);
+ break;
+ case 4:
+ /* update notification request */
+ decode_update_notify_request(inbuf, &rep->un_rq);
+ break;
+ default:
+ DEBUG(0,("decode_replicate: unknown message type:%d\n", rep->msg_type));
+ break;
+ }
+}
+
+/****************************************************************************
+read the generic header and fill the struct.
+****************************************************************************/
+static void read_generic_header(struct BUFFER *inbuf, generic_header *q)
+{
+ if(!check_buffer(inbuf, 16))
+ return;
+
+ q->data_size = RIVAL(inbuf->buffer, inbuf->offset+0);
+ q->opcode = RIVAL(inbuf->buffer, inbuf->offset+4);
+ q->assoc_ctx = RIVAL(inbuf->buffer, inbuf->offset+8);
+ q->mess_type = RIVAL(inbuf->buffer, inbuf->offset+12);
+}
+
+/*******************************************************************
+decode a start association request
+********************************************************************/
+static void decode_start_assoc_request(struct BUFFER *inbuf, START_ASSOC_REQUEST *q)
+{
+ if(!check_buffer(inbuf, 8))
+ return;
+
+ q->assoc_ctx = RIVAL(inbuf->buffer, inbuf->offset+0);
+ q->min_ver = RSVAL(inbuf->buffer, inbuf->offset+4);
+ q->maj_ver = RSVAL(inbuf->buffer, inbuf->offset+6);
+}
+
+/*******************************************************************
+decode a start association reply
+********************************************************************/
+static void decode_start_assoc_reply(struct BUFFER *inbuf, START_ASSOC_REPLY *r)
+{
+ if(!check_buffer(inbuf, 8))
+ return;
+
+ r->assoc_ctx=RIVAL(inbuf->buffer, inbuf->offset+0);
+ r->min_ver = RSVAL(inbuf->buffer, inbuf->offset+4);
+ r->maj_ver = RSVAL(inbuf->buffer, inbuf->offset+6);
+}
+
+/*******************************************************************
+decode a start association reply
+********************************************************************/
+static void decode_stop_assoc(struct BUFFER *inbuf, STOP_ASSOC *r)
+{
+ if(!check_buffer(inbuf, 4))
+ return;
+
+ r->reason=RIVAL(inbuf->buffer, inbuf->offset);
+}
+
+/****************************************************************************
+decode a packet and fill a generic structure
+****************************************************************************/
+void decode_generic_packet(struct BUFFER *inbuf, GENERIC_PACKET *q)
+{
+ read_generic_header(inbuf, &q->header);
+
+ inbuf->offset+=16;
+
+ switch (q->header.mess_type) {
+ case 0:
+ decode_start_assoc_request(inbuf, &q->sa_rq);
+ break;
+ case 1:
+ decode_start_assoc_reply(inbuf, &q->sa_rp);
+ break;
+ case 2:
+ decode_stop_assoc(inbuf, &q->so);
+ break;
+ case 3:
+ decode_replicate(inbuf, &q->rep);
+ break;
+ default:
+ DEBUG(0,("decode_generic_packet: unknown message type:%d\n", q->header.mess_type));
+ break;
+ }
+}
+
+/****************************************************************************
+encode a WINS_OWNER struct
+****************************************************************************/
+static void encode_wins_owner(struct BUFFER *outbuf, WINS_OWNER *wins_owner)
+{
+ if (!grow_buffer(outbuf, 24))
+ return;
+
+ SIVAL(outbuf->buffer, outbuf->offset, wins_owner->address.s_addr);
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, (int)(wins_owner->max_version>>32));
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, (int)(wins_owner->max_version&0xffffffff));
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_owner->min_version>>32);
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_owner->min_version&0xffffffff);
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_owner->type);
+ outbuf->offset+=4;
+
+}
+
+/****************************************************************************
+encode a WINS_NAME struct
+****************************************************************************/
+static void encode_wins_name(struct BUFFER *outbuf, WINS_NAME *wins_name)
+{
+ int i;
+
+ if (!grow_buffer(outbuf, 48+(4*wins_name->num_ip)))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->name_len);
+ outbuf->offset+=4;
+
+ memset(outbuf->buffer+outbuf->offset, ' ', 15);
+
+ /* to prevent copying the leading \0 */
+ memcpy(outbuf->buffer+outbuf->offset, wins_name->name, strlen(wins_name->name));
+ outbuf->offset+=15;
+
+ outbuf->buffer[outbuf->offset++]=(char)wins_name->type;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->empty);
+ outbuf->offset+=4;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->name_flag);
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->group_flag);
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->id>>32);
+ outbuf->offset+=4;
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->id);
+ outbuf->offset+=4;
+
+ if (wins_name->name_flag & 2) {
+ SIVAL(outbuf->buffer, outbuf->offset, wins_name->num_ip);
+ outbuf->offset+=4;
+ }
+
+ SIVAL(outbuf->buffer, outbuf->offset, wins_name->owner.s_addr);
+ outbuf->offset+=4;
+
+ if (wins_name->name_flag & 2) {
+ for (i=0;i<wins_name->num_ip;i++) {
+ SIVAL(outbuf->buffer, outbuf->offset, wins_name->others[i].s_addr);
+ outbuf->offset+=4;
+ }
+ }
+
+ RSIVAL(outbuf->buffer, outbuf->offset, wins_name->foo);
+ outbuf->offset+=4;
+}
+
+/****************************************************************************
+encode a update notification request
+****************************************************************************/
+static void encode_update_notify_request(struct BUFFER *outbuf, UPDATE_NOTIFY_REQUEST *un_rq)
+{
+ int i;
+
+ if (!grow_buffer(outbuf, 8))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, un_rq->partner_count);
+ outbuf->offset+=4;
+
+ for (i=0; i<un_rq->partner_count; i++)
+ encode_wins_owner(outbuf, &un_rq->wins_owner[i]);
+
+ SIVAL(outbuf->buffer, outbuf->offset, un_rq->initiating_wins_server.s_addr);
+ outbuf->offset+=4;
+
+}
+
+/****************************************************************************
+decode a send entries request
+****************************************************************************/
+static void encode_send_entries_request(struct BUFFER *outbuf, SEND_ENTRIES_REQUEST *se_rq)
+{
+ encode_wins_owner(outbuf, &se_rq->wins_owner);
+}
+
+/****************************************************************************
+decode a send entries reply
+****************************************************************************/
+static void encode_send_entries_reply(struct BUFFER *outbuf, SEND_ENTRIES_REPLY *se_rp)
+{
+ int i;
+
+ if (!grow_buffer(outbuf, 4))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, se_rp->max_names);
+ outbuf->offset+=4;
+
+ for (i=0; i<se_rp->max_names; i++)
+ encode_wins_name(outbuf, &se_rp->wins_name[i]);
+
+}
+
+/****************************************************************************
+encode a add version number map table reply
+****************************************************************************/
+static void encode_add_version_number_map_table_reply(struct BUFFER *outbuf, AVMT_REP *avmt_rep)
+{
+ int i;
+
+ if (!grow_buffer(outbuf, 8))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, avmt_rep->partner_count);
+ outbuf->offset+=4;
+
+ for (i=0; i<avmt_rep->partner_count; i++)
+ encode_wins_owner(outbuf, &avmt_rep->wins_owner[i]);
+
+ SIVAL(outbuf->buffer, outbuf->offset, avmt_rep->initiating_wins_server.s_addr);
+ outbuf->offset+=4;
+
+}
+
+/****************************************************************************
+decode a replicate packet and fill a structure
+****************************************************************************/
+static void encode_replicate(struct BUFFER *outbuf, REPLICATE *rep)
+{
+ if (!grow_buffer(outbuf, 4))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, rep->msg_type);
+ outbuf->offset+=4;
+
+ switch (rep->msg_type) {
+ case 0:
+ break;
+ case 1:
+ /* add version number map table reply */
+ encode_add_version_number_map_table_reply(outbuf, &rep->avmt_rep);
+ break;
+ case 2:
+ /* send entry request */
+ encode_send_entries_request(outbuf, &rep->se_rq);
+ break;
+ case 3:
+ /* send entry request */
+ encode_send_entries_reply(outbuf, &rep->se_rp);
+ break;
+ case 4:
+ /* update notification request */
+ encode_update_notify_request(outbuf, &rep->un_rq);
+ break;
+ default:
+ DEBUG(0,("encode_replicate: unknown message type:%d\n", rep->msg_type));
+ break;
+ }
+}
+
+/****************************************************************************
+write the generic header.
+****************************************************************************/
+static void write_generic_header(struct BUFFER *outbuf, generic_header *r)
+{
+ RSIVAL(outbuf->buffer, 0, r->data_size);
+ RSIVAL(outbuf->buffer, 4, r->opcode);
+ RSIVAL(outbuf->buffer, 8, r->assoc_ctx);
+ RSIVAL(outbuf->buffer,12, r->mess_type);
+}
+
+/*******************************************************************
+decode a start association request
+********************************************************************/
+static void encode_start_assoc_request(struct BUFFER *outbuf, START_ASSOC_REQUEST *q)
+{
+ if (!grow_buffer(outbuf, 45))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, q->assoc_ctx);
+ RSSVAL(outbuf->buffer, outbuf->offset+4, q->min_ver);
+ RSSVAL(outbuf->buffer, outbuf->offset+6, q->maj_ver);
+
+ outbuf->offset=45;
+}
+
+/*******************************************************************
+decode a start association reply
+********************************************************************/
+static void encode_start_assoc_reply(struct BUFFER *outbuf, START_ASSOC_REPLY *r)
+{
+ if (!grow_buffer(outbuf, 45))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, r->assoc_ctx);
+ RSSVAL(outbuf->buffer, outbuf->offset+4, r->min_ver);
+ RSSVAL(outbuf->buffer, outbuf->offset+6, r->maj_ver);
+
+ outbuf->offset=45;
+}
+
+/*******************************************************************
+decode a start association reply
+********************************************************************/
+static void encode_stop_assoc(struct BUFFER *outbuf, STOP_ASSOC *r)
+{
+ if (!grow_buffer(outbuf, 44))
+ return;
+
+ RSIVAL(outbuf->buffer, outbuf->offset, r->reason);
+
+ outbuf->offset=44;
+}
+
+/****************************************************************************
+write the generic header size.
+****************************************************************************/
+static void write_generic_header_size(generic_header *r, int size)
+{
+ /* the buffer size is the total size minus the size field */
+ r->data_size=size-4;
+}
+
+/****************************************************************************
+encode a packet and read a generic structure
+****************************************************************************/
+void encode_generic_packet(struct BUFFER *outbuf, GENERIC_PACKET *q)
+{
+ if (!grow_buffer(outbuf, 16))
+ return;
+
+ outbuf->offset=16;
+
+ switch (q->header.mess_type) {
+ case 0:
+ encode_start_assoc_request(outbuf, &q->sa_rq);
+ break;
+ case 1:
+ encode_start_assoc_reply(outbuf, &q->sa_rp);
+ break;
+ case 2:
+ encode_stop_assoc(outbuf, &q->so);
+ break;
+ case 3:
+ encode_replicate(outbuf, &q->rep);
+ break;
+ default:
+ DEBUG(0,("encode_generic_packet: unknown message type:%d\n", q->header.mess_type));
+ break;
+ }
+
+ write_generic_header_size(&q->header, outbuf->offset);
+ write_generic_header(outbuf, &q->header);
+}
+
+
+/****************************************************************************
+dump a WINS_OWNER structure
+****************************************************************************/
+static void dump_wins_owner(WINS_OWNER *wins_owner)
+{
+ DEBUGADD(10,("\t\t\t\taddress : %s\n", inet_ntoa(wins_owner->address)));
+ DEBUGADD(10,("\t\t\t\tmax version: %d\n", (int)wins_owner->max_version));
+ DEBUGADD(10,("\t\t\t\tmin version: %d\n", (int)wins_owner->min_version));
+ DEBUGADD(10,("\t\t\t\ttype : %d\n", wins_owner->type));
+}
+
+/****************************************************************************
+dump a WINS_NAME structure
+****************************************************************************/
+static void dump_wins_name(WINS_NAME *wins_name)
+{
+ fstring name;
+ int i;
+
+ strncpy(name, wins_name->name, 15);
+
+ DEBUGADD(10,("name: %d, %s<%02x> %x,%x, %d %s %d ", wins_name->name_len, name, wins_name->type,
+ wins_name->name_flag, wins_name->group_flag, (int)wins_name->id,
+ inet_ntoa(wins_name->owner), wins_name->num_ip));
+
+ if (wins_name->num_ip!=1)
+ for (i=0; i<wins_name->num_ip; i++)
+ DEBUGADD(10,("%s ", inet_ntoa(wins_name->others[i])));
+
+ DEBUGADD(10,("\n"));
+}
+
+/****************************************************************************
+dump a replicate structure
+****************************************************************************/
+static void dump_replicate(REPLICATE *rep)
+{
+ int i;
+
+ DEBUGADD(5,("\t\tmsg_type: %d ", rep->msg_type));
+
+ switch (rep->msg_type) {
+ case 0:
+ DEBUGADD(5,("(Add Version Map Table Request)\n"));
+ break;
+ case 1:
+ DEBUGADD(5,("(Add Version Map Table Reply)\n"));
+ DEBUGADD(5,("\t\t\tpartner_count : %d\n", rep->avmt_rep.partner_count));
+ for (i=0; i<rep->avmt_rep.partner_count; i++)
+ dump_wins_owner(&rep->avmt_rep.wins_owner[i]);
+ DEBUGADD(5,("\t\t\tinitiating_wins_server: %s\n", inet_ntoa(rep->avmt_rep.initiating_wins_server)));
+ break;
+ case 2:
+ DEBUGADD(5,("(Send Entries Request)\n"));
+ dump_wins_owner(&rep->se_rq.wins_owner);
+ break;
+ case 3:
+ DEBUGADD(5,("(Send Entries Reply)\n"));
+ DEBUGADD(5,("\t\t\tmax_names : %d\n", rep->se_rp.max_names));
+ for (i=0; i<rep->se_rp.max_names; i++)
+ dump_wins_name(&rep->se_rp.wins_name[i]);
+ break;
+ case 4:
+ DEBUGADD(5,("(Update Notify Request)\n"));
+ DEBUGADD(5,("\t\t\tpartner_count : %d\n", rep->un_rq.partner_count));
+ for (i=0; i<rep->un_rq.partner_count; i++)
+ dump_wins_owner(&rep->un_rq.wins_owner[i]);
+ DEBUGADD(5,("\t\t\tinitiating_wins_server: %s\n", inet_ntoa(rep->un_rq.initiating_wins_server)));
+ break;
+ default:
+ DEBUG(5,("\n"));
+ break;
+ }
+}
+
+/****************************************************************************
+dump a generic structure
+****************************************************************************/
+void dump_generic_packet(GENERIC_PACKET *q)
+{
+ DEBUG(5,("dump_generic_packet:\n"));
+ DEBUGADD(5,("\tdata_size: %08x\n", q->header.data_size));
+ DEBUGADD(5,("\topcode : %08x\n", q->header.opcode));
+ DEBUGADD(5,("\tassoc_ctx: %08x\n", q->header.assoc_ctx));
+ DEBUGADD(5,("\tmess_type: %08x ", q->header.mess_type));
+
+ switch (q->header.mess_type) {
+ case 0:
+ DEBUGADD(5,("(Start Association Request)\n"));
+ DEBUGADD(5,("\t\tassoc_ctx: %08x\n", q->sa_rq.assoc_ctx));
+ DEBUGADD(5,("\t\tmin_ver : %04x\n", q->sa_rq.min_ver));
+ DEBUGADD(5,("\t\tmaj_ver : %04x\n", q->sa_rq.maj_ver));
+ break;
+ case 1:
+ DEBUGADD(5,("(Start Association Reply)\n"));
+ DEBUGADD(5,("\t\tassoc_ctx: %08x\n", q->sa_rp.assoc_ctx));
+ DEBUGADD(5,("\t\tmin_ver : %04x\n", q->sa_rp.min_ver));
+ DEBUGADD(5,("\t\tmaj_ver : %04x\n", q->sa_rp.maj_ver));
+ break;
+ case 2:
+ DEBUGADD(5,("(Stop Association)\n"));
+ DEBUGADD(5,("\t\treason: %08x\n", q->so.reason));
+ break;
+ case 3:
+ DEBUGADD(5,("(Replication Message)\n"));
+ dump_replicate(&q->rep);
+ break;
+ default:
+ DEBUG(5,("\n"));
+ break;
+ }
+
+}
+
+/****************************************************************************
+generate a stop packet
+****************************************************************************/
+void stop_packet(GENERIC_PACKET *q, GENERIC_PACKET *r, int reason)
+{
+ r->header.opcode=OPCODE_NON_NBT;
+ r->header.assoc_ctx=get_server_assoc(q->header.assoc_ctx);
+ r->header.mess_type=MESSAGE_TYPE_STOP_ASSOC;
+ r->so.reason=reason;
+
+}
+
+
diff --git a/source4/wrepld/partners.c b/source4/wrepld/partners.c
new file mode 100644
index 0000000000..2387f5b45f
--- /dev/null
+++ b/source4/wrepld/partners.c
@@ -0,0 +1,200 @@
+/*
+ Unix SMB/CIFS implementation.
+ process incoming packets - main loop
+ Copyright (C) Jean François Micouleau 1998-2002.
+
+ 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 "wins_repl.h"
+
+/* we can exchange info with 64 partners at any given time */
+WINS_PARTNER current_partners[64];
+int total_current_partners;
+
+/*******************************************************************
+verify if we know this partner
+********************************************************************/
+BOOL check_partner(int assoc)
+{
+ int i;
+
+ DEBUG(5,("check_partner: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==assoc)
+ return True;
+
+ return False;
+}
+
+/*******************************************************************
+add a new entry to the list
+********************************************************************/
+BOOL add_partner(int client_assoc, int server_assoc, BOOL pull, BOOL push)
+{
+ DEBUG(5,("add_partner: total_current_partners: %d\n", total_current_partners));
+
+ if (total_current_partners==64)
+ return False;
+
+ current_partners[total_current_partners].client_assoc=client_assoc;
+ current_partners[total_current_partners].server_assoc=server_assoc;
+ current_partners[total_current_partners].pull_partner=pull;
+ current_partners[total_current_partners].push_partner=push;
+
+ total_current_partners++;
+
+ return True;
+}
+
+/*******************************************************************
+remove an entry to the list
+********************************************************************/
+BOOL remove_partner(int client_assoc)
+{
+ int i,j;
+
+ DEBUG(5,("remove_partner: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; current_partners[i].client_assoc!=client_assoc && i<total_current_partners; i++)
+ ;
+
+ if (i==total_current_partners)
+ return False;
+
+ for (j=i+1; j<total_current_partners; j++) {
+ current_partners[j-1].client_assoc=current_partners[j].client_assoc;
+ current_partners[j-1].server_assoc=current_partners[j].server_assoc;
+ current_partners[j-1].pull_partner=current_partners[j].pull_partner;
+ current_partners[j-1].push_partner=current_partners[j].push_partner;
+ current_partners[j-1].partner_server.s_addr=current_partners[j].partner_server.s_addr;
+ current_partners[j-1].other_server.s_addr=current_partners[j].other_server.s_addr;
+ }
+
+ total_current_partners--;
+
+ return True;
+}
+
+/*******************************************************************
+link the client and server context
+********************************************************************/
+BOOL update_server_partner(int client_assoc, int server_assoc)
+{
+ int i;
+
+ DEBUG(5,("update_server_partner: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==client_assoc) {
+ current_partners[i].server_assoc=server_assoc;
+ return True;
+ }
+
+ return False;
+}
+
+/*******************************************************************
+verify if it's a pull partner
+********************************************************************/
+BOOL check_pull_partner(int assoc)
+{
+ int i;
+
+ DEBUG(5,("check_pull_partner: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==assoc &&
+ current_partners[i].pull_partner==True)
+ return True;
+
+ return False;
+}
+
+/*******************************************************************
+verify if it's a push partner
+********************************************************************/
+BOOL check_push_partner(int assoc)
+{
+ int i;
+
+ DEBUG(5,("check_push_partner: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==assoc &&
+ current_partners[i].push_partner==True)
+ return True;
+
+ return False;
+}
+
+/*******************************************************************
+return the server ctx linked to the client ctx
+********************************************************************/
+int get_server_assoc(int assoc)
+{
+ int i;
+
+ DEBUG(5,("get_server_assoc: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==assoc)
+ return current_partners[i].server_assoc;
+
+ return 0;
+}
+
+
+/*******************************************************************
+link the client and server context
+********************************************************************/
+BOOL write_server_assoc_table(int client_assoc, struct in_addr partner, struct in_addr server)
+{
+ int i;
+
+ DEBUG(5,("write_server_assoc_table: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==client_assoc) {
+ current_partners[i].partner_server=partner;
+ current_partners[i].other_server=server;
+ return True;
+ }
+
+ return False;
+}
+
+/*******************************************************************
+link the client and server context
+********************************************************************/
+BOOL get_server_assoc_table(int client_assoc, struct in_addr *partner, struct in_addr *server)
+{
+ int i;
+
+ DEBUG(5,("get_server_assoc_table: total_current_partners: %d\n", total_current_partners));
+
+ for (i=0; i<total_current_partners; i++)
+ if (current_partners[i].client_assoc==client_assoc) {
+ partner->s_addr=current_partners[i].partner_server.s_addr;
+ server->s_addr=current_partners[i].other_server.s_addr;
+ return True;
+ }
+
+ return False;
+}
+
+
diff --git a/source4/wrepld/process.c b/source4/wrepld/process.c
new file mode 100644
index 0000000000..1f96dc996c
--- /dev/null
+++ b/source4/wrepld/process.c
@@ -0,0 +1,983 @@
+/*
+ Unix SMB/CIFS implementation.
+ process incoming packets - main loop
+ Copyright (C) Jean François Micouleau 1998-2002.
+
+ 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 "wins_repl.h"
+
+extern fd_set *listen_set;
+extern int listen_number;
+extern int *sock_array;
+
+WINS_OWNER global_wins_table[64][64];
+int partner_count;
+
+TALLOC_CTX *mem_ctx;
+
+#define WINS_LIST "wins.tdb"
+#define INFO_VERSION "INFO/version"
+#define INFO_COUNT "INFO/num_entries"
+#define INFO_ID_HIGH "INFO/id_high"
+#define INFO_ID_LOW "INFO/id_low"
+#define ENTRY_PREFIX "ENTRY/"
+
+
+/*******************************************************************
+fill the header of a reply.
+********************************************************************/
+static void fill_header(GENERIC_PACKET *g, int opcode, int ctx, int mess)
+{
+ if (g==NULL)
+ return;
+
+ g->header.opcode=opcode;
+ g->header.assoc_ctx=ctx;
+ g->header.mess_type=mess;
+}
+
+/*******************************************************************
+dump the global table, that's a debug code.
+********************************************************************/
+static void dump_global_table(void)
+{
+ int i,j;
+
+ for (i=0;i<partner_count;i++) {
+ DEBUG(10,("\n%d ", i));
+ for (j=0; global_wins_table[i][j].address.s_addr!=0; j++)
+ DEBUG(10,("%s:%d \t", inet_ntoa(global_wins_table[i][j].address),
+ (int)global_wins_table[i][j].max_version));
+ }
+ DEBUG(10,("\n"));
+}
+
+/*******************************************************************
+start association
+********************************************************************/
+static void start_assoc_process(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ /*
+ * add this request to our current wins partners list
+ * this list is used to know with who we are in contact
+ *
+ */
+ r->sa_rp.assoc_ctx=time(NULL);
+ fill_header(r, OPCODE_NON_NBT, q->sa_rq.assoc_ctx, MESSAGE_TYPE_START_ASSOC_REPLY);
+
+ /* reply we are a NT4 server */
+
+ /* w2K is min=2, maj=5 */
+
+ r->sa_rp.min_ver=1;
+ r->sa_rp.maj_ver=1;
+
+ add_partner(r->sa_rp.assoc_ctx, q->sa_rq.assoc_ctx, False, False);
+}
+
+/*******************************************************************
+start association reply
+********************************************************************/
+static void start_assoc_reply(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ int i;
+
+ /* check if we have already registered this client */
+ if (!check_partner(q->header.assoc_ctx)) {
+ DEBUG(0,("start_assoc_reply: unknown client\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ if (!update_server_partner(q->header.assoc_ctx, q->sa_rp.assoc_ctx)) {
+ DEBUG(0,("start_assoc_reply: can't update server ctx\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ /* if pull, request map table */
+ if (check_pull_partner(q->header.assoc_ctx)) {
+ fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);
+
+ r->rep.msg_type=MESSAGE_REP_ADD_VERSION_REQUEST;
+ DEBUG(5,("start_assoc_reply: requesting map table\n"));
+
+ return;
+ }
+
+ /* if push, send our table */
+ if (check_push_partner(q->header.assoc_ctx)) {
+ fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);
+ r->rep.msg_type=MESSAGE_REP_UPDATE_NOTIFY_REQUEST;
+ r->rep.un_rq.partner_count=partner_count;
+
+ r->rep.un_rq.wins_owner=(WINS_OWNER *)talloc(mem_ctx, partner_count*sizeof(WINS_OWNER));
+ if (r->rep.un_rq.wins_owner==NULL) {
+ DEBUG(0,("start_assoc_reply: can't alloc memory\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ for (i=0; i<partner_count; i++)
+ r->rep.un_rq.wins_owner[i]=global_wins_table[0][i];
+
+ DEBUG(5,("start_assoc_reply: sending update table\n"));
+ return;
+ }
+
+ /* neither push/pull, stop */
+ /* we should not come here */
+ DEBUG(0,("we have a partner which is neither push nor pull !\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+}
+
+/****************************************************************************
+initialise and fill the in-memory partner table.
+****************************************************************************/
+int init_wins_partner_table(void)
+{
+ int i=1,j=0,k;
+ char **partner = str_list_make(lp_wins_partners(), NULL);
+
+ if (partner==NULL) {
+ DEBUG(0,("wrepld: no partner list in smb.conf, exiting\n"));
+ exit_server("normal exit");
+ return(0);
+ }
+
+ DEBUG(4, ("init_wins_partner_table: partners: %s\n", lp_wins_partners()));
+
+ global_wins_table[0][0].address=*iface_n_ip(0);
+ global_wins_table[0][0].max_version=0;
+ global_wins_table[0][0].min_version=0;
+ global_wins_table[0][0].type=0;
+
+ while (partner[j]!=NULL) {
+ DEBUG(3,("init_wins_partner_table, adding partner: %s\n", partner[j]));
+
+ global_wins_table[0][i].address=*interpret_addr2(partner[j]);
+ global_wins_table[0][i].max_version=0;
+ global_wins_table[0][i].min_version=0;
+ global_wins_table[0][i].type=0;
+ global_wins_table[0][i].last_pull=0;
+ global_wins_table[0][i].last_push=0;
+
+ i++;
+ j++;
+ }
+
+ for (k=1; k<i;k++)
+ for (j=0; j<i; j++)
+ global_wins_table[k][j]=global_wins_table[0][j];
+
+ str_list_free (&partner);
+
+ return i;
+}
+
+/****************************************************************************
+read the last ID from the wins tdb file.
+****************************************************************************/
+static void get_our_last_id(WINS_OWNER *wins_owner)
+{
+ TDB_CONTEXT *tdb;
+
+ tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);
+ if (!tdb) {
+ DEBUG(2,("get_our_last_id: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));
+ return;
+ }
+
+ wins_owner->max_version=((SMB_BIG_UINT)tdb_fetch_int32(tdb, INFO_ID_HIGH))<<32 |
+ (SMB_BIG_UINT)tdb_fetch_int32(tdb, INFO_ID_LOW);
+
+ tdb_close(tdb);
+}
+
+/****************************************************************************
+send the list of wins server we know.
+****************************************************************************/
+static void send_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ int i;
+ int s_ctx=get_server_assoc(q->header.assoc_ctx);
+
+ if (s_ctx==0) {
+ DEBUG(5, ("send_version_number_map_table: request for a partner not in our table\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ /*
+ * return an array of wins servers, we are partner with.
+ * each entry contains the IP address and the version info
+ * version: ID of the last entry we've got
+ */
+
+ /* the first wins server must be self */
+
+ /*
+ * get our last ID from the wins database
+ * it can have been updated since last read
+ * as nmbd got registration/release.
+ */
+ get_our_last_id(&global_wins_table[0][0]);
+
+ r->rep.avmt_rep.wins_owner=(WINS_OWNER *)talloc(mem_ctx, partner_count*sizeof(WINS_OWNER));
+ if (r->rep.avmt_rep.wins_owner==NULL) {
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ DEBUG(5,("send_version_number_map_table: partner_count: %d\n", partner_count));
+
+ for (i=0; i<partner_count; i++) {
+ DEBUG(5,("send_version_number_map_table, partner: %d -> %s, \n", i, inet_ntoa(global_wins_table[0][i].address)));
+ r->rep.avmt_rep.wins_owner[i]=global_wins_table[0][i];
+ }
+
+ r->rep.msg_type=1;
+ r->rep.avmt_rep.partner_count=partner_count;
+ r->rep.avmt_rep.initiating_wins_server.s_addr=0; /* blatant lie, NT4/w2K do the same ! */
+ fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);
+}
+
+/****************************************************************************
+for a given partner, ask it to send entries we don't have.
+****************************************************************************/
+static BOOL check_partners_and_send_entries(GENERIC_PACKET *q, GENERIC_PACKET *r, int partner)
+{
+ int server;
+ int other;
+ SMB_BIG_UINT temp;
+ SMB_BIG_UINT current;
+
+
+ /*
+ * we check if our partner has more records than us.
+ * we need to check more than our direct partners as
+ * we can have this case:
+ * us: A, partners: B,C, indirect partner: D
+ * A<->B, A<->C, B<->D, C<->D
+ *
+ * So if we're talking to B, we need to check if between
+ * B and C, which one have more records about D.
+ * and also check if we don't already have the records.
+ */
+
+
+ /* check all servers even indirect */
+ for (server=1; global_wins_table[0][server].address.s_addr!=0; server++) {
+ current = global_wins_table[partner][server].max_version;
+
+ temp=0;
+
+ for (other=1; other<partner_count; other++) {
+ /* skip the partner itself */
+ if (other==partner)
+ continue;
+
+ if (global_wins_table[other][server].max_version > temp)
+ temp=global_wins_table[other][server].max_version;
+ }
+
+ if (current >= temp && current > global_wins_table[0][server].max_version) {
+ /*
+ * it has more records than every body else and more than us,
+ * ask it the difference between what we have and what it has
+ */
+ fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);
+
+ r->rep.msg_type=MESSAGE_REP_SEND_ENTRIES_REQUEST;
+ r->rep.se_rq.wins_owner.address=global_wins_table[partner][server].address;
+
+ r->rep.se_rq.wins_owner.max_version=global_wins_table[partner][server].max_version;
+ r->rep.se_rq.wins_owner.min_version=global_wins_table[0][server].max_version;
+ r->rep.se_rq.wins_owner.type=0;
+
+ write_server_assoc_table(q->header.assoc_ctx, global_wins_table[0][partner].address, global_wins_table[partner][server].address);
+
+ /*
+ * and we update our version for this server
+ * as we can't use the IDs returned in the send_entries function
+ * the max ID can be larger than the largest ID returned
+ */
+
+ global_wins_table[0][server].max_version=global_wins_table[partner][server].max_version;
+
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+receive the list of wins server we know.
+****************************************************************************/
+static void receive_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ fstring peer;
+ struct in_addr addr;
+ int i,j,k,l;
+ int s_ctx=get_server_assoc(q->header.assoc_ctx);
+
+ if (s_ctx==0) {
+ DEBUG(5, ("receive_version_number_map_table: request for a partner not in our table\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ fstrcpy(peer,get_socket_addr(q->fd));
+ addr=*interpret_addr2(peer);
+
+ get_our_last_id(&global_wins_table[0][0]);
+
+ DEBUG(5,("receive_version_number_map_table: received a map of %d server from: %s\n",
+ q->rep.avmt_rep.partner_count ,inet_ntoa(q->rep.avmt_rep.initiating_wins_server)));
+ DEBUG(5,("real peer is: %s\n", peer));
+
+ for (i=0; global_wins_table[0][i].address.s_addr!=addr.s_addr && i<partner_count;i++)
+ ;
+
+ if (i==partner_count) {
+ DEBUG(5,("receive_version_number_map_table: unknown partner: %s\n", peer));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ for (j=0; j<q->rep.avmt_rep.partner_count;j++) {
+ /*
+ * search if we already have this entry or if it's a new one
+ * it can be a new one in case of propagation
+ */
+ for (k=0; global_wins_table[0][k].address.s_addr!=0 &&
+ global_wins_table[0][k].address.s_addr!=q->rep.avmt_rep.wins_owner[j].address.s_addr; k++);
+
+ global_wins_table[i][k].address.s_addr=q->rep.avmt_rep.wins_owner[j].address.s_addr;
+ global_wins_table[i][k].max_version=q->rep.avmt_rep.wins_owner[j].max_version;
+ global_wins_table[i][k].min_version=q->rep.avmt_rep.wins_owner[j].min_version;
+ global_wins_table[i][k].type=q->rep.avmt_rep.wins_owner[j].type;
+
+ /*
+ * in case it's a new one, rewrite the address for all the partner
+ * to reserve the slot.
+ */
+
+ for(l=0; l<partner_count; l++)
+ global_wins_table[l][k].address.s_addr=q->rep.avmt_rep.wins_owner[j].address.s_addr;
+ }
+
+ dump_global_table();
+
+ /*
+ * if this server have newer records than what we have
+ * for several wins servers, we need to ask it.
+ * Alas a send entry request is only on one server.
+ * So in the send entry reply, we'll ask for the next server if required.
+ */
+
+ if (check_partners_and_send_entries(q, r, i))
+ return;
+
+ /* it doesn't have more entries than us */
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+}
+
+/****************************************************************************
+add an entry to the wins list we'll send.
+****************************************************************************/
+static BOOL add_record_to_winsname(WINS_NAME **wins_name, int *max_names, char *name, int type, int wins_flags, int id, struct in_addr *ip_list, int num_ips)
+{
+ WINS_NAME *temp_list;
+ int i;
+ int current=*max_names;
+
+ temp_list=talloc_realloc(mem_ctx, *wins_name, (current+1)*sizeof(WINS_NAME));
+ if (temp_list==NULL)
+ return False;
+
+ temp_list[current].name_len=0x11;
+
+ safe_strcpy(temp_list[current].name, name, 15);
+
+ temp_list[current].type=type;
+ temp_list[current].empty=0;
+
+ temp_list[current].name_flag=wins_flags;
+
+ if ( (wins_flags&0x03) == 1 || (wins_flags&0x03)==2)
+ temp_list[current].group_flag=0x01000000;
+ else
+ temp_list[current].group_flag=0x00000000;
+
+ temp_list[current].id=id;
+
+ temp_list[current].owner.s_addr=ip_list[0].s_addr;
+
+ if (temp_list[current].name_flag & 2) {
+ temp_list[current].num_ip=num_ips;
+ temp_list[current].others=(struct in_addr *)talloc(mem_ctx, sizeof(struct in_addr)*num_ips);
+ if (temp_list[current].others==NULL)
+ return False;
+
+ for (i=0; i<num_ips; i++)
+ temp_list[current].others[i].s_addr=ip_list[i].s_addr;
+
+ } else
+ temp_list[current].num_ip=1;
+
+ temp_list[current].foo=0xffffffff;
+
+ *wins_name=temp_list;
+
+ return True;
+}
+
+/****************************************************************************
+send the list of name we have.
+****************************************************************************/
+static void send_entry_request(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ int max_names=0;
+ int i;
+ time_t time_now = time(NULL);
+ WINS_OWNER *wins_owner;
+ TDB_CONTEXT *tdb;
+ TDB_DATA kbuf, dbuf, newkey;
+ int s_ctx=get_server_assoc(q->header.assoc_ctx);
+ int num_interfaces = iface_count();
+
+ if (s_ctx==0) {
+ DEBUG(1, ("send_entry_request: request for a partner not in our table\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+
+ wins_owner=&q->rep.se_rq.wins_owner;
+ r->rep.se_rp.wins_name=NULL;
+
+ DEBUG(3,("send_entry_request: we have been asked to send the list of wins records\n"));
+ DEBUGADD(3,("owned by: %s and between min: %d and max: %d\n", inet_ntoa(wins_owner->address),
+ (int)wins_owner->min_version, (int)wins_owner->max_version));
+
+ /*
+ * if we are asked to send records owned by us
+ * we overwrite the wins ip with 0.0.0.0
+ * to make it easy in case of multihomed
+ */
+
+ for (i=0; i<num_interfaces; i++)
+ if (ip_equal(wins_owner->address, *iface_n_ip(i))) {
+ wins_owner->address=*interpret_addr2("0.0.0.0");
+ break;
+ }
+
+
+ tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);
+ if (!tdb) {
+ DEBUG(2,("send_entry_request: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));
+ return;
+ }
+
+ for (kbuf = tdb_firstkey(tdb);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+ fstring name_type;
+ pstring name, ip_str;
+ char *p;
+ int type = 0;
+ int nb_flags;
+ int ttl;
+ unsigned int num_ips;
+ int low, high;
+ SMB_BIG_UINT version;
+ struct in_addr wins_ip;
+ struct in_addr *ip_list;
+ int wins_flags;
+ int len;
+
+ if (strncmp(kbuf.dptr, ENTRY_PREFIX, strlen(ENTRY_PREFIX)) != 0)
+ continue;
+
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr)
+ continue;
+
+ fstrcpy(name_type, kbuf.dptr+strlen(ENTRY_PREFIX));
+ pstrcpy(name, name_type);
+
+ if((p = strchr(name,'#')) != NULL) {
+ *p = 0;
+ sscanf(p+1,"%x",&type);
+ }
+
+ len = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddfddd",
+ &nb_flags,
+ &high,
+ &low,
+ ip_str,
+ &ttl,
+ &num_ips,
+ &wins_flags);
+
+ wins_ip=*interpret_addr2(ip_str);
+
+ /* Allocate the space for the ip_list. */
+ if((ip_list = (struct in_addr *)talloc(mem_ctx, num_ips * sizeof(struct in_addr))) == NULL) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("initialise_wins: talloc fail !\n"));
+ return;
+ }
+
+ for (i = 0; i < num_ips; i++) {
+ len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", ip_str);
+ ip_list[i] = *interpret_addr2(ip_str);
+ }
+
+ SAFE_FREE(dbuf.dptr);
+
+ /* add all entries that have 60 seconds or more to live */
+ if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
+ if(ttl != PERMANENT_TTL)
+ ttl -= time_now;
+
+ DEBUG( 4, ("send_entry_request: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
+ name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
+
+ /* add the record to the list to send */
+ version=((SMB_BIG_UINT)high)<<32 | low;
+
+ if (wins_owner->min_version<=version && wins_owner->max_version>=version &&
+ wins_owner->address.s_addr==wins_ip.s_addr) {
+ if(!add_record_to_winsname(&r->rep.se_rp.wins_name, &max_names, name, type, wins_flags, version, ip_list, num_ips))
+ return;
+ max_names++;
+ }
+
+ } else {
+ DEBUG(4, ("send_entry_request: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n",
+ name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
+ }
+ }
+
+ tdb_close(tdb);
+
+ DEBUG(4,("send_entry_request, sending %d records\n", max_names));
+ fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);
+ r->rep.msg_type=MESSAGE_REP_SEND_ENTRIES_REPLY; /* reply */
+ r->rep.se_rp.max_names=max_names;
+}
+
+
+/****************************************************************************
+.
+****************************************************************************/
+static void update_notify_request(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ int i,j,k,l;
+ UPDATE_NOTIFY_REQUEST *u;
+ int s_ctx=get_server_assoc(q->header.assoc_ctx);
+
+ if (s_ctx==0) {
+ DEBUG(4, ("update_notify_request: request for a partner not in our table\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ u=&q->rep.un_rq;
+
+ /* check if we already have the range of records */
+
+ DEBUG(5,("update_notify_request: wins server: %s offered this list of %d records:\n",
+ inet_ntoa(u->initiating_wins_server), u->partner_count));
+
+ get_our_last_id(&global_wins_table[0][0]);
+
+ for (i=0; i<partner_count; i++) {
+ if (global_wins_table[0][i].address.s_addr==u->initiating_wins_server.s_addr) {
+ DEBUG(5,("update_notify_request: found initiator at index %d\n", i));
+ break;
+ }
+ }
+
+ /*
+ * some explanation is required, before someone say it's crap.
+ *
+ * let's take an example, we have 2 wins partners, we already now
+ * that our max id is 10, partner 1 ID is 20 and partner 2 ID is 30
+ * the array looks like:
+ *
+ * 0 1 2
+ * 0 10 20 30
+ * 1
+ * 2
+ *
+ * we receive an update from partner 2 saying he has: 1:15, 2:40, 3:50
+ * we must enlarge the array to add partner 3, it will look like:
+ *
+ * 0 1 2 3
+ * 0 10 20 30
+ * 1
+ * 2 15 40 50
+ *
+ * now we know, we should pull from partner 2, the records 30->40 of 2 and 0->50 of 3.
+ * once the pull will be over, our table will look like:
+ *
+ * 0 1 2 3
+ * 0 10 20 40 50
+ * 1
+ * 2 15 40 50
+ *
+ *
+ */
+
+ for (j=0; j<u->partner_count;j++) {
+ /*
+ * search if we already have this entry or if it's a new one
+ * it can be a new one in case of propagation
+ */
+
+ for (k=0; global_wins_table[0][k].address.s_addr!=0 &&
+ global_wins_table[0][k].address.s_addr!=u->wins_owner[j].address.s_addr; k++);
+
+ global_wins_table[i][k].address.s_addr=u->wins_owner[j].address.s_addr;
+ global_wins_table[i][k].max_version=u->wins_owner[j].max_version;
+ global_wins_table[i][k].min_version=u->wins_owner[j].min_version;
+ global_wins_table[i][k].type=u->wins_owner[j].type;
+
+ /*
+ * in case it's a new one, rewrite the address for all the partner
+ * to reserve the slot.
+ */
+
+ for(l=0; l<partner_count; l++)
+ global_wins_table[l][k].address.s_addr=u->wins_owner[j].address.s_addr;
+ }
+
+ dump_global_table();
+
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+}
+
+/****************************************************************************
+.
+****************************************************************************/
+static void send_entry_reply(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ int i,j,k;
+ struct in_addr partner, server;
+ pid_t pid;
+ int s_ctx=get_server_assoc(q->header.assoc_ctx);
+ WINS_RECORD record;
+
+ if (s_ctx==0) {
+ DEBUG(1, ("send_entry_reply: request for a partner not in our table\n"));
+ stop_packet(q, r, STOP_REASON_USER_REASON);
+ return;
+ }
+
+ DEBUG(5,("send_entry_reply:got %d new records\n", q->rep.se_rp.max_names));
+
+ /* we got records from a wins partner but that can be from another wins server */
+ /* hopefully we track that */
+
+ /* and the only doc available from MS is wrong ! */
+
+ get_server_assoc_table(q->header.assoc_ctx, &partner, &server);
+
+ for (j=0; global_wins_table[0][j].address.s_addr!=0; j++) {
+ if (global_wins_table[0][j].address.s_addr==server.s_addr) {
+ DEBUG(5,("send_entry_reply: found server at index %d\n", j));
+ break;
+ }
+ }
+
+ pid = pidfile_pid("nmbd");
+ if (pid == 0) {
+ DEBUG(0,("send_entry_reply: Can't find pid for nmbd\n"));
+ return;
+ }
+
+ for (k=0; k<q->rep.se_rp.max_names; k++) {
+ DEBUG(5,("send_entry_reply: %s<%02x> %d\n", q->rep.se_rp.wins_name[k].name, q->rep.se_rp.wins_name[k].type,
+ (int)q->rep.se_rp.wins_name[k].id));
+
+ safe_strcpy(record.name, q->rep.se_rp.wins_name[k].name, 16);
+ record.type=q->rep.se_rp.wins_name[k].type;
+ record.id=q->rep.se_rp.wins_name[k].id;
+ record.wins_flags=q->rep.se_rp.wins_name[k].name_flag&0x00ff;
+ record.num_ips=q->rep.se_rp.wins_name[k].num_ip;
+
+ record.wins_ip.s_addr=server.s_addr;
+
+ if (record.num_ips==1)
+ record.ip[0]=q->rep.se_rp.wins_name[k].owner;
+ else
+ for (i=0; i<record.num_ips; i++)
+ record.ip[i]=q->rep.se_rp.wins_name[k].others[i];
+
+ record.nb_flags=0;
+
+ if (record.wins_flags&WINS_NGROUP || record.wins_flags&WINS_SGROUP)
+ record.nb_flags|=NB_GROUP;
+
+ if (record.wins_flags&WINS_ACTIVE)
+ record.nb_flags|=NB_ACTIVE;
+
+ record.nb_flags|=record.wins_flags&WINS_HNODE;
+
+ message_send_pid(pid, MSG_WINS_NEW_ENTRY, &record, sizeof(record), False);
+
+ }
+
+ dump_global_table();
+
+ /*
+ * we got some entries,
+ * ask the partner to send us the map table again
+ * to get the other servers entries.
+ *
+ * we're getting the map table 1 time more than really
+ * required. We could remove that call, but that
+ * would complexify the code. I prefer this trade-of.
+ */
+ fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);
+
+ r->rep.msg_type=MESSAGE_REP_ADD_VERSION_REQUEST;
+}
+
+/****************************************************************************
+decode the replication message and reply.
+****************************************************************************/
+static void replicate(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ switch (q->rep.msg_type) {
+ case 0:
+ /* add version number map table request */
+ send_version_number_map_table(q, r);
+ break;
+ case 1:
+ receive_version_number_map_table(q, r);
+ break;
+ case 2:
+ /* send entry request */
+ send_entry_request(q, r);
+ break;
+ case 3:
+ /* send entry reply */
+ send_entry_reply(q, r);
+ break;
+ case 4:
+ /* update notification request */
+ update_notify_request(q, r);
+ break;
+ }
+}
+
+/****************************************************************************
+do a switch on the message type, and return the response size
+****************************************************************************/
+static BOOL switch_message(GENERIC_PACKET *q, GENERIC_PACKET *r)
+{
+ switch (q->header.mess_type) {
+ case 0:
+ /* Start association type */
+ start_assoc_process(q, r);
+ return True;
+ break;
+ case 1:
+ /* start association reply */
+ start_assoc_reply(q, r);
+ return True;
+ break;
+ case 2:
+ /* stop association message */
+ return False;
+ break;
+ case 3:
+ /* replication message */
+ replicate(q, r);
+ return True;
+ break;
+ }
+
+ return False;
+}
+
+
+/****************************************************************************
+ construct a reply to the incoming packet
+****************************************************************************/
+void construct_reply(struct wins_packet_struct *p)
+{
+ GENERIC_PACKET r;
+ struct BUFFER buffer;
+
+ buffer.buffer=NULL;
+ buffer.offset=0;
+ buffer.length=0;
+
+ DEBUG(5,("dump: received packet\n"));
+ dump_generic_packet(p->packet);
+
+ /* Verify if the request we got is from a listed partner */
+ if (!check_partner(p->packet->header.assoc_ctx)) {
+ fstring peer;
+ struct in_addr addr;
+ int i;
+ fstrcpy(peer,get_socket_addr(p->fd));
+ addr=*interpret_addr2(peer);
+
+ for (i=1; i<partner_count; i++)
+ if (ip_equal(addr, global_wins_table[0][i].address))
+ break;
+
+ if (i==partner_count) {
+ DEBUG(1,("construct_reply: got a request from a non peer machine: %s\n", peer));
+ stop_packet(p->packet, &r, STOP_REASON_AUTH_FAILED);
+ p->stop_packet=True;
+ encode_generic_packet(&buffer, &r);
+ if (!send_smb(p->fd, buffer.buffer))
+ exit_server("process_smb: send_smb failed.");
+ return;
+ }
+ }
+
+ if (switch_message(p->packet, &r)) {
+ encode_generic_packet(&buffer, &r);
+ DEBUG(5,("dump: sending packet\n"));
+ dump_generic_packet(&r);
+
+ if(buffer.offset > 0) {
+ if (!send_smb(p->fd, buffer.buffer))
+ exit_server("process_smb: send_smb failed.");
+ }
+ }
+
+ /* if we got a stop assoc or if we send a stop assoc, close the fd after */
+ if (p->packet->header.mess_type==MESSAGE_TYPE_STOP_ASSOC ||
+ r.header.mess_type==MESSAGE_TYPE_STOP_ASSOC) {
+ remove_partner(p->packet->header.assoc_ctx);
+ p->stop_packet=True;
+ }
+}
+
+/****************************************************************************
+ contact periodically our wins partner to do a pull replication
+****************************************************************************/
+void run_pull_replication(time_t t)
+{
+ /* we pull every 30 minutes to query about new records*/
+ int i, s;
+ struct BUFFER buffer;
+ GENERIC_PACKET p;
+
+ buffer.buffer=NULL;
+ buffer.offset=0;
+ buffer.length=0;
+
+ for (i=1; i<partner_count; i++) {
+ if (global_wins_table[0][i].last_pull < t) {
+ global_wins_table[0][i].last_pull=t+30*60; /* next in 30 minutes */
+
+ /* contact the wins server */
+ p.header.mess_type=MESSAGE_TYPE_START_ASSOC_REQUEST;
+ p.header.opcode=OPCODE_NON_NBT;
+ p.header.assoc_ctx=0;
+ p.sa_rq.assoc_ctx=(int)t;
+ p.sa_rq.min_ver=1;
+ p.sa_rq.maj_ver=1;
+
+ DEBUG(3,("run_pull_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
+ encode_generic_packet(&buffer, &p);
+ dump_generic_packet(&p);
+
+ /* send the packet to the server and add the descriptor to receive answers */
+ s=open_socket_out(SOCK_STREAM, &global_wins_table[0][i].address, 42, LONG_CONNECT_TIMEOUT);
+ if (s==-1) {
+ DEBUG(0,("run_pull_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
+ return;
+ }
+
+ if(buffer.offset > 0) {
+ if (!send_smb(s, buffer.buffer))
+ exit_server("run_pull_replication: send_smb failed.");
+ }
+
+ add_fd_to_sock_array(s);
+ FD_SET(s, listen_set);
+
+ /* add ourself as a client */
+ add_partner((int)t, 0, True, False);
+ }
+ }
+}
+
+/****************************************************************************
+ contact periodically our wins partner to do a push replication
+****************************************************************************/
+void run_push_replication(time_t t)
+{
+ /* we push every 30 minutes or 25 new entries */
+ int i, s;
+ struct BUFFER buffer;
+ GENERIC_PACKET p;
+
+ buffer.buffer=NULL;
+ buffer.offset=0;
+ buffer.length=0;
+
+ for (i=1; i<partner_count; i++) {
+ if (global_wins_table[0][i].last_pull < t) {
+ global_wins_table[0][i].last_pull=t+30*60; /* next in 30 minutes */
+
+ /* contact the wins server */
+ p.header.mess_type=MESSAGE_TYPE_START_ASSOC_REQUEST;
+ p.header.opcode=OPCODE_NON_NBT;
+ p.header.assoc_ctx=0;
+ p.sa_rq.assoc_ctx=(int)t;
+ p.sa_rq.min_ver=1;
+ p.sa_rq.maj_ver=1;
+
+ DEBUG(3,("run_push_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
+ encode_generic_packet(&buffer, &p);
+ dump_generic_packet(&p);
+
+ /* send the packet to the server and add the descriptor to receive answers */
+ s=open_socket_out(SOCK_STREAM, &global_wins_table[0][i].address, 42, LONG_CONNECT_TIMEOUT);
+ if (s==-1) {
+ DEBUG(0,("run_push_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
+ return;
+ }
+
+ if(buffer.offset > 0) {
+ if (!send_smb(s, buffer.buffer))
+ exit_server("run_push_replication: send_smb failed.");
+ }
+
+ add_fd_to_sock_array(s);
+ FD_SET(s, listen_set);
+
+ /* add ourself as a client */
+ add_partner((int)t, 0, False, True);
+ }
+ }
+}
+
diff --git a/source4/wrepld/server.c b/source4/wrepld/server.c
new file mode 100644
index 0000000000..afeec3402b
--- /dev/null
+++ b/source4/wrepld/server.c
@@ -0,0 +1,737 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main SMB server routines
+ Copyright (C) Jean François Micouleau 1998-2002.
+
+ 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 "wins_repl.h"
+
+extern WINS_OWNER *global_wins_table;
+extern int partner_count;
+
+extern fd_set *listen_set;
+extern int listen_number;
+extern int *sock_array;
+
+extern TALLOC_CTX *mem_ctx;
+
+int wins_port = 42;
+
+/****************************************************************************
+ when exiting, take the whole family
+****************************************************************************/
+static void *dflt_sig(void)
+{
+ exit_server("caught signal");
+ return NULL;
+}
+
+/****************************************************************************
+ reload the services file
+ **************************************************************************/
+BOOL reload_services(BOOL test)
+{
+ BOOL ret;
+
+ if (lp_loaded()) {
+ pstring fname;
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) {
+ pstrcpy(dyn_CONFIGFILE,fname);
+ test = False;
+ }
+ }
+
+ reopen_logs();
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ ret = lp_load(dyn_CONFIGFILE,False,False,True);
+
+
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(True);
+
+ reopen_logs();
+
+ load_interfaces();
+
+ return(ret);
+}
+
+/****************************************************************************
+ Catch a sighup.
+****************************************************************************/
+
+VOLATILE sig_atomic_t reload_after_sighup = False;
+
+static void sig_hup(int sig)
+{
+ BlockSignals(True,SIGHUP);
+ DEBUG(0,("Got SIGHUP\n"));
+
+ sys_select_signal();
+ reload_after_sighup = True;
+ BlockSignals(False,SIGHUP);
+}
+
+#if DUMP_CORE
+/*******************************************************************
+prepare to dump a core file - carefully!
+********************************************************************/
+static BOOL dump_core(void)
+{
+ char *p;
+ pstring dname;
+ pstrcpy(dname,lp_logfile());
+ if ((p=strrchr_m(dname,'/'))) *p=0;
+ pstrcat(dname,"/corefiles");
+ mkdir(dname,0700);
+ sys_chown(dname,getuid(),getgid());
+ chmod(dname,0700);
+ if (chdir(dname)) return(False);
+ umask(~(0700));
+
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_CORE, &rlp);
+ rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
+ setrlimit(RLIMIT_CORE, &rlp);
+ getrlimit(RLIMIT_CORE, &rlp);
+ DEBUG(3,("Core limits now %d %d\n",
+ (int)rlp.rlim_cur,(int)rlp.rlim_max));
+ }
+#endif
+#endif
+
+
+ DEBUG(0,("Dumping core in %s\n",dname));
+ abort();
+ return(True);
+}
+#endif
+
+/****************************************************************************
+exit the server
+****************************************************************************/
+void exit_server(const char *reason)
+{
+ static int firsttime=1;
+
+ if (!firsttime)
+ exit(0);
+ firsttime = 0;
+
+ DEBUG(2,("Closing connections\n"));
+
+ if (!reason) {
+ int oldlevel = DEBUGLEVEL;
+ DEBUGLEVEL = 10;
+ DEBUGLEVEL = oldlevel;
+ DEBUG(0,("===============================================================\n"));
+#if DUMP_CORE
+ if (dump_core()) return;
+#endif
+ }
+
+ DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
+ exit(0);
+}
+
+/****************************************************************************
+ Usage of the program.
+****************************************************************************/
+
+static void usage(char *pname)
+{
+
+ d_printf("Usage: %s [-DFSaioPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname);
+ d_printf(" [-O socket options] [-s services file]\n");
+ d_printf("\t-D Become a daemon (default)\n");
+ d_printf("\t-F Run daemon in foreground (for daemontools, etc)\n");
+ d_printf("\t-S Log to stdout\n");
+ d_printf("\t-a Append to log file (default)\n");
+ d_printf("\t-i Run interactive (not a daemon)\n" );
+ d_printf("\t-o Overwrite log file, don't append\n");
+ d_printf("\t-h Print usage\n");
+ d_printf("\t-? Print usage\n");
+ d_printf("\t-V Print version\n");
+ d_printf("\t-d debuglevel Set the debuglevel\n");
+ d_printf("\t-l log basename. Basename for log/debug files\n");
+ d_printf("\t-p port Listen on the specified port\n");
+ d_printf("\t-O socket options Socket options\n");
+ d_printf("\t-s services file. Filename of services file\n");
+ d_printf("\n");
+}
+
+/****************************************************************************
+ Create an fd_set containing all the sockets in the subnet structures,
+ plus the broadcast sockets.
+***************************************************************************/
+
+static BOOL create_listen_fdset(void)
+{
+ int i;
+ int num_interfaces = iface_count();
+ int s;
+
+ listen_set = (fd_set *)malloc(sizeof(fd_set));
+ if(listen_set == NULL) {
+ DEBUG(0,("create_listen_fdset: malloc fail !\n"));
+ return True;
+ }
+
+#ifdef HAVE_ATEXIT
+ {
+ static int atexit_set;
+ if(atexit_set == 0) {
+ atexit_set=1;
+ }
+ }
+#endif
+
+ FD_ZERO(listen_set);
+
+ if(lp_interfaces() && lp_bind_interfaces_only()) {
+ /* We have been given an interfaces line, and been
+ told to only bind to those interfaces. Create a
+ socket per interface and bind to only these.
+ */
+
+ if(num_interfaces > FD_SETSIZE) {
+ DEBUG(0,("create_listen_fdset: Too many interfaces specified to bind to. Number was %d max can be %d\n", num_interfaces, FD_SETSIZE));
+ return False;
+ }
+
+ /* Now open a listen socket for each of the interfaces. */
+ for(i = 0; i < num_interfaces; i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+
+ if(ifip == NULL) {
+ DEBUG(0,("create_listen_fdset: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+ s = open_socket_in(SOCK_STREAM, wins_port, 0, ifip->s_addr, True);
+ if(s == -1)
+ return False;
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,lp_socket_options());
+
+ if (listen(s, 5) == -1) {
+ DEBUG(5,("listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
+ add_fd_to_sock_array(s);
+ FD_SET(s, listen_set);
+ }
+ } else {
+ /* Just bind to 0.0.0.0 - accept connections from anywhere. */
+ num_interfaces = 1;
+
+ /* open an incoming socket */
+ s = open_socket_in(SOCK_STREAM, wins_port, 0, interpret_addr(lp_socket_address()),True);
+ if (s == -1)
+ return(False);
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s, lp_socket_options());
+
+ if (listen(s, 5) == -1) {
+ DEBUG(0,("create_listen_fdset: listen: %s\n", strerror(errno)));
+ close(s);
+ return False;
+ }
+
+ add_fd_to_sock_array(s);
+ FD_SET(s, listen_set);
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ read a packet from a socket and parse it, returning a packet ready
+ to be used or put on the queue. This assumes a UDP socket
+ ******************************************************************/
+static struct wins_packet_struct *read_wins_packet(int fd, int timeout)
+{
+ struct wins_packet_struct *p;
+ GENERIC_PACKET *q;
+ struct BUFFER inbuf;
+ ssize_t len=0;
+ size_t total=0;
+ ssize_t ret;
+ BOOL ok = False;
+
+ inbuf.buffer=NULL;
+ inbuf.length=0;
+ inbuf.offset=0;
+
+ if(!grow_buffer(&inbuf, 4))
+ return NULL;
+
+ ok = (read(fd, inbuf.buffer,4) == 4);
+ if (!ok)
+ return NULL;
+ len = smb_len(inbuf.buffer);
+
+ if (len<=0)
+ return NULL;
+
+ if(!grow_buffer(&inbuf, len))
+ return NULL;
+
+ while (total < len) {
+ ret = read(fd, inbuf.buffer + total + 4, len - total);
+ if (ret == 0) {
+ DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(len - total), strerror(errno) ));
+ return NULL;
+ }
+ if (ret == -1) {
+ DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(len - total), strerror(errno) ));
+ return NULL;
+ }
+ total += ret;
+ }
+
+ q = (GENERIC_PACKET *)talloc(mem_ctx, sizeof(GENERIC_PACKET));
+ p = (struct wins_packet_struct *)talloc(mem_ctx, sizeof(*p));
+ if (q==NULL || p==NULL)
+ return NULL;
+
+ decode_generic_packet(&inbuf, q);
+
+ q->fd=fd;
+
+ p->next = NULL;
+ p->prev = NULL;
+ p->stop_packet = False;
+ p->timestamp = time(NULL);
+ p->fd = fd;
+ p->packet=q;
+
+ return p;
+}
+
+static struct wins_packet_struct *packet_queue = NULL;
+
+/*******************************************************************
+ Queue a packet into a packet queue
+******************************************************************/
+static void queue_packet(struct wins_packet_struct *packet)
+{
+ struct wins_packet_struct *p;
+
+ if (!packet_queue) {
+ packet->prev = NULL;
+ packet->next = NULL;
+ packet_queue = packet;
+ return;
+ }
+
+ /* find the bottom */
+ for (p=packet_queue;p->next;p=p->next)
+ ;
+
+ p->next = packet;
+ packet->next = NULL;
+ packet->prev = p;
+}
+
+/****************************************************************************
+ Listens for NMB or DGRAM packets, and queues them.
+ return True if the socket is dead
+***************************************************************************/
+static BOOL listen_for_wins_packets(void)
+{
+ int num_interfaces = iface_count();
+ fd_set fds;
+ int i, num, s, new_s;
+ struct timeval timeout;
+
+ if(listen_set == NULL) {
+ if(!create_listen_fdset()) {
+ DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
+ return True;
+ }
+ }
+
+ memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+
+ timeout.tv_sec = NMBD_SELECT_LOOP;
+ timeout.tv_usec = 0;
+
+ /* Prepare for the select - allow certain signals. */
+
+ BlockSignals(False, SIGTERM);
+
+ num = sys_select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
+
+ /* We can only take signals when we are in the select - block them again here. */
+
+ BlockSignals(True, SIGTERM);
+
+ if(num == -1)
+ return False;
+
+ for (; num > 0; num--) {
+ s = -1;
+ /* check the sockets we are only listening on, waiting to accept */
+ for (i=0; i<num_interfaces; i++) {
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+
+ if(FD_ISSET(sock_array[i], &fds)) {
+ s = sock_array[i];
+ /* Clear this so we don't look at it again. */
+ FD_CLR(sock_array[i], &fds);
+
+ /* accept and add the new socket to the listen set */
+ new_s=accept(s, &addr, &in_addrlen);
+
+ if (new_s < 0)
+ continue;
+
+ DEBUG(5,("listen_for_wins_packets: new connection, old: %d, new : %d\n", s, new_s));
+
+ set_socket_options(new_s, "SO_KEEPALIVE");
+ set_socket_options(new_s, lp_socket_options());
+ FD_SET(new_s, listen_set);
+ add_fd_to_sock_array(new_s);
+ }
+ }
+
+ /*
+ * check for the sockets we are waiting data from
+ * either client sending datas
+ * or reply to our requests
+ */
+ for (i=num_interfaces; i<listen_number; i++) {
+ if(FD_ISSET(sock_array[i], &fds)) {
+ struct wins_packet_struct *packet = read_wins_packet(sock_array[i], timeout.tv_sec);
+ if (packet) {
+ packet->fd = sock_array[i];
+ queue_packet(packet);
+ }
+ DEBUG(2,("listen_for_wins_packets: some data on fd %d\n", sock_array[i]));
+ FD_CLR(sock_array[i], &fds);
+ break;
+ }
+
+ }
+
+ }
+
+ return False;
+}
+
+
+/*******************************************************************
+ Run elements off the packet queue till its empty
+******************************************************************/
+
+static void run_wins_packet_queue(void)
+{
+ struct wins_packet_struct *p;
+
+ while ((p = packet_queue)) {
+ packet_queue = p->next;
+ if (packet_queue)
+ packet_queue->prev = NULL;
+ p->next = p->prev = NULL;
+
+ construct_reply(p);
+
+ /* if it was a stop assoc, close the connection */
+ if (p->stop_packet) {
+ FD_CLR(p->fd, listen_set);
+ remove_fd_from_sock_array(p->fd);
+ close(p->fd);
+ }
+ }
+}
+
+/**************************************************************************** **
+ The main select loop.
+ **************************************************************************** */
+static void process(void)
+{
+
+ while( True ) {
+ time_t t = time(NULL);
+
+ /* check for internal messages */
+ message_dispatch();
+
+ if(listen_for_wins_packets())
+ return;
+
+ run_wins_packet_queue();
+
+ run_pull_replication(t);
+
+ run_push_replication(t);
+
+ /*
+ * Reload the services file if we got a sighup.
+ */
+
+ if(reload_after_sighup) {
+ reload_services( True );
+ reopen_logs();
+ reload_after_sighup = False;
+ }
+
+ /* free temp memory */
+ talloc_destroy_pool(mem_ctx);
+
+ /* free up temp memory */
+ lp_talloc_free();
+ }
+} /* process */
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ extern char *optarg;
+ /* shall I run as a daemon */
+ BOOL is_daemon = False;
+ BOOL interactive = False;
+ BOOL specified_logfile = False;
+ BOOL Fork = True;
+ BOOL log_stdout = False;
+ int opt;
+ pstring logfile;
+
+#ifdef HAVE_SET_AUTH_PARAMETERS
+ set_auth_parameters(argc,argv);
+#endif
+
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-')) {
+ argv++;
+ argc--;
+ }
+
+ while ( EOF != (opt = getopt(argc, argv, "FSO:l:s:d:Dp:h?Vaiof:")) )
+ switch (opt) {
+ case 'F':
+ Fork = False;
+ break;
+ case 'S':
+ log_stdout = True;
+ break;
+ case 'O':
+ lp_set_cmdline("socket options", optarg);
+ break;
+
+ case 's':
+ pstrcpy(dyn_CONFIGFILE,optarg);
+ break;
+
+ case 'l':
+ specified_logfile = True;
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld", optarg);
+ lp_set_logfile(logfile);
+ break;
+
+ case 'i':
+ interactive = True;
+ Fork = False;
+ log_stdout = True;
+ break;
+
+ case 'D':
+ is_daemon = True;
+ break;
+
+ case 'd':
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
+
+ case 'p':
+ wins_port = atoi(optarg);
+ break;
+
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(0);
+ break;
+
+ case 'V':
+ d_printf("Version %s\n",VERSION);
+ exit(0);
+ break;
+ default:
+ DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
+ usage(argv[0]);
+ exit(1);
+ }
+ if (log_stdout && Fork) {
+ d_printf("Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n");
+ usage(argv[0]);
+ exit(1);
+ }
+
+#ifdef HAVE_SETLUID
+ /* needed for SecureWare on SCO */
+ setluid(0);
+#endif
+
+ sec_init();
+
+ load_case_tables();
+
+ if(!specified_logfile) {
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld",
+ dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+ }
+
+ set_remote_machine_name("wrepld");
+
+ setup_logging(argv[0],log_stdout);
+
+ /* we want to re-seed early to prevent time delays causing
+ client problems at a later date. (tridge) */
+ generate_random_buffer(NULL, 0, False);
+
+ /* make absolutely sure we run as root - to handle cases where people
+ are crazy enough to have it setuid */
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+
+ fault_setup((void (*)(void *))exit_server);
+ CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
+
+#if defined(SIGUSR2)
+ /* We are no longer interested in USR2 */
+ BlockSignals(True,SIGUSR2);
+#endif
+
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't recieve them. */
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGUSR1);
+
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
+
+ reopen_logs();
+
+ DEBUG(1,( "wrepld version %s started.\n", VERSION));
+ DEBUGADD(1,( "Copyright Andrew Tridgell and the Samba Team 1992-2002\n"));
+
+ DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
+ (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
+
+ if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
+ DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
+ exit(1);
+ }
+
+ /*
+ * Do this before reload_services.
+ */
+
+ if (!reload_services(False))
+ return(-1);
+
+ if (!init_names())
+ return -1;
+
+#ifdef WITH_PROFILE
+ if (!profile_setup(False)) {
+ DEBUG(0,("ERROR: failed to setup profiling\n"));
+ return -1;
+ }
+#endif
+
+ CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
+
+ DEBUG(3,( "loaded services\n"));
+
+ if (!is_daemon && !is_a_socket(0)) {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
+
+ if (is_daemon && !interactive) {
+ DEBUG( 3, ( "Becoming a daemon.\n" ) );
+ become_daemon(Fork);
+ }
+
+#if HAVE_SETPGID
+ /*
+ * If we're interactive we want to set our own process group for
+ * signal management.
+ */
+ if (interactive)
+ setpgid( (pid_t)0, (pid_t)0);
+#endif
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ if (is_daemon) {
+ pidfile_create("wrepld");
+ }
+
+ if (!message_init()) {
+ exit(1);
+ }
+
+ /* Initialise the memory context */
+ mem_ctx=talloc_init("wins repl talloc ctx");
+
+ /* initialise the global partners table */
+ partner_count=init_wins_partner_table();
+
+ /* We can only take signals in the select. */
+ BlockSignals( True, SIGTERM );
+
+ process();
+
+ exit_server("normal exit");
+ return(0);
+}
diff --git a/source4/wrepld/socket.c b/source4/wrepld/socket.c
new file mode 100644
index 0000000000..3d759f0ab8
--- /dev/null
+++ b/source4/wrepld/socket.c
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/CIFS implementation.
+ process incoming packets - main loop
+ Copyright (C) Jean François Micouleau 1998-2002.
+
+ 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 "wins_repl.h"
+
+fd_set *listen_set = NULL;
+int listen_number = 0;
+int *sock_array = NULL;
+
+/*******************************************************************
+ Add an fd from the sock_array
+******************************************************************/
+void add_fd_to_sock_array(int fd)
+{
+ int *temp_sock=NULL;
+
+ temp_sock=(int *)Realloc(sock_array, (listen_number+1)*sizeof(int));
+ if (temp_sock==NULL)
+ return;
+
+ sock_array=temp_sock;
+ sock_array[listen_number]=fd;
+ listen_number++;
+}
+
+
+/*******************************************************************
+ Remove an fd from the sock_array
+******************************************************************/
+void remove_fd_from_sock_array(int fd)
+{
+ int i,j;
+
+ for (i=0; sock_array[i]!=fd && i<listen_number; i++)
+ ;
+
+ if (i==listen_number) {
+ DEBUG(0,("remove_fd_from_sock_array: unknown fd: %d\n", fd));
+ return;
+ }
+
+ if (i==listen_number-1) {
+ sock_array=(int *)Realloc(sock_array, --listen_number*sizeof(int));
+ return;
+ }
+
+ for (j=i; j<listen_number-1; j++)
+ sock_array[j]=sock_array[j+1];
+
+ sock_array=(int *)Realloc(sock_array, --listen_number*sizeof(int));
+}
diff --git a/source4/wrepld/wins_repl.h b/source4/wrepld/wins_repl.h
new file mode 100644
index 0000000000..25b4442212
--- /dev/null
+++ b/source4/wrepld/wins_repl.h
@@ -0,0 +1,161 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Jean François Micouleau 1998-2002.
+ *
+ * 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.
+ */
+
+#define OPCODE_NON_NBT 0x00007800
+
+/* the messages */
+#define MESSAGE_TYPE_START_ASSOC_REQUEST 0
+#define MESSAGE_TYPE_START_ASSOC_REPLY 1
+#define MESSAGE_TYPE_STOP_ASSOC 2
+#define MESSAGE_TYPE_REPLICATE 3
+
+/* the replication sub-message */
+#define MESSAGE_REP_ADD_VERSION_REQUEST 0
+#define MESSAGE_REP_ADD_VERSION_REPLY 1
+#define MESSAGE_REP_SEND_ENTRIES_REQUEST 2
+#define MESSAGE_REP_SEND_ENTRIES_REPLY 3
+#define MESSAGE_REP_UPDATE_NOTIFY_REQUEST 4
+
+/* stop reasons */
+#define STOP_REASON_USER_REASON 0
+#define STOP_REASON_AUTH_FAILED 1
+#define STOP_REASON_INCOMPLETE_VERSION 2
+#define STOP_REASON_BUG_CHECK 3
+#define STOP_REASON_MESSAGE_ERROR 4
+
+
+typedef struct _WINS_OWNER {
+ struct in_addr address;
+ SMB_BIG_UINT max_version;
+ SMB_BIG_UINT min_version;
+ int type;
+ time_t last_pull;
+ time_t last_push;
+} WINS_OWNER;
+
+typedef struct _WINS_NAME {
+ int name_len; /* always 0x11 */
+ char name[16];
+ char type;
+ int empty;
+ int name_flag;
+ int group_flag;
+ SMB_BIG_UINT id;
+ int num_ip;
+ struct in_addr owner;
+ struct in_addr *others;
+ int foo; /* 0xffffff */
+} WINS_NAME;
+
+typedef struct _WINS_PARTNERS
+{
+ int client_assoc;
+ int server_assoc;
+ BOOL pull_partner;
+ BOOL push_partner;
+ struct in_addr partner_server;
+ struct in_addr other_server;
+} WINS_PARTNER;
+
+typedef struct _generic_header{
+ int data_size;
+ int opcode;
+ int assoc_ctx;
+ int mess_type;
+} generic_header;
+
+typedef struct _START_ASSOC_REQUEST {
+ int assoc_ctx;
+ int min_ver;
+ int maj_ver;
+} START_ASSOC_REQUEST;
+
+typedef struct _START_ASSOC_REPLY {
+ int assoc_ctx;
+ int min_ver;
+ int maj_ver;
+} START_ASSOC_REPLY;
+
+typedef struct _STOP_ASSOC {
+ int reason;
+} STOP_ASSOC;
+
+typedef struct _AVMT_REP {
+ int partner_count;
+ WINS_OWNER *wins_owner;
+ struct in_addr initiating_wins_server;
+} AVMT_REP;
+
+typedef struct _SEND_ENTRIES_REQUEST {
+ WINS_OWNER wins_owner;
+} SEND_ENTRIES_REQUEST;
+
+typedef struct _SEND_ENTRIES_REPLY {
+ int max_names;
+ WINS_NAME *wins_name;
+} SEND_ENTRIES_REPLY;
+
+typedef struct _UPDATE_NOTIFY_REQUEST {
+ int partner_count;
+ WINS_OWNER *wins_owner;
+ struct in_addr initiating_wins_server;
+} UPDATE_NOTIFY_REQUEST;
+
+typedef struct _REPLICATE {
+ int msg_type;
+
+ AVMT_REP avmt_rep;
+ SEND_ENTRIES_REQUEST se_rq;
+ SEND_ENTRIES_REPLY se_rp;
+ UPDATE_NOTIFY_REQUEST un_rq;
+} REPLICATE;
+
+
+typedef struct _GENERIC_PACKET {
+ int fd;
+
+ generic_header header;
+
+ START_ASSOC_REQUEST sa_rq;
+ START_ASSOC_REPLY sa_rp;
+ STOP_ASSOC so;
+ REPLICATE rep;
+} GENERIC_PACKET;
+
+struct wins_packet_struct
+{
+ struct wins_packet_struct *next;
+ struct wins_packet_struct *prev;
+ BOOL stop_packet;
+ int fd;
+ time_t timestamp;
+ GENERIC_PACKET *packet;
+};
+
+struct BUFFER {
+ char *buffer;
+ int offset;
+ int length;
+};
+
+
+
+#include "wrepld_proto.h"
+