mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
that's the wins replication daemon !
there are still some work to do on it but it's already functionnal. J.F.
This commit is contained in:
parent
b902e087d0
commit
2506c98d19
@ -90,7 +90,7 @@ WINBIND_SPROGS = @WINBIND_STARGETS@
|
||||
WINBIND_PAM_PROGS = @WINBIND_PAM_TARGETS@
|
||||
WINBIND_LPROGS = @WINBIND_LTARGETS@
|
||||
|
||||
SPROGS = bin/smbd bin/nmbd bin/swat @WINBIND_STARGETS@
|
||||
SPROGS = bin/smbd bin/nmbd bin/swat bin/wrepld @WINBIND_STARGETS@
|
||||
PROGS1 = bin/smbclient bin/net bin/smbspool bin/testparm bin/testprns bin/smbstatus bin/smbcontrol bin/smbtree @RUNPROG@ @WINBIND_TARGETS@
|
||||
PROGS2 = bin/smbpasswd bin/rpcclient bin/smbcacls @WRAP@ @WRAP32@ @PAM_MOD@
|
||||
MPROGS = @MPROGS@
|
||||
@ -256,6 +256,12 @@ NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \
|
||||
NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
|
||||
$(PROFILE_OBJ) $(LIB_OBJ)
|
||||
|
||||
WREPL_OBJ1 = wrepld/server.o wrepld/process.o wrepld/parser.o wrepld/socket.o \
|
||||
wrepld/partners.o
|
||||
|
||||
WREPL_OBJ = $(WREPL_OBJ1) $(PARAM_OBJ) $(UBIQX_OBJ) \
|
||||
$(PROFILE_OBJ) $(LIB_OBJ)
|
||||
|
||||
SWAT_OBJ = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
|
||||
web/swat.o web/neg_lang.o $(PRINTING_OBJ) $(LIBSMB_OBJ) $(LOCKING_OBJ) \
|
||||
$(PARAM_OBJ) $(PASSDB_OBJ) \
|
||||
@ -554,6 +560,10 @@ bin/nmbd: $(NMBD_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(NMBD_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
bin/wrepld: $(WREPL_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(WREPL_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
bin/swat: $(SWAT_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(SWAT_OBJ) $(LDFLAGS) $(LIBS)
|
||||
@ -798,6 +808,11 @@ winbindd_proto:
|
||||
-h _WINBINDD_PROTO_H_ nsswitch/winbindd_proto.h \
|
||||
$(WINBINDD_OBJ1)
|
||||
|
||||
wrepld_proto:
|
||||
@cd $(srcdir) && $(SHELL) script/mkproto.sh $(AWK) \
|
||||
-h _WREPLD_PROTO_H_ $(builddir)/include/wrepld_proto.h \
|
||||
$(WREPL_OBJ1)
|
||||
|
||||
delheaders:
|
||||
@/bin/rm -f $(srcdir)/include/proto.h $(srcdir)/include/build_env.h
|
||||
@/bin/rm -f include/proto.h include/build_env.h
|
||||
@ -818,7 +833,7 @@ include/build_env.h:
|
||||
|
||||
headers: delheaders include/proto.h include/build_env.h .headers.stamp
|
||||
|
||||
proto: headers winbindd_proto
|
||||
proto: headers winbindd_proto wrepld_proto
|
||||
|
||||
etags:
|
||||
etags `find $(srcdir) -name "*.[ch]" | grep -v /CVS/`
|
||||
|
@ -143,6 +143,7 @@ typedef struct
|
||||
char *szShutdownScript;
|
||||
char *szAbortShutdownScript;
|
||||
char *szWINSHook;
|
||||
char *szWINSPartners;
|
||||
#ifdef WITH_UTMP
|
||||
char *szUtmpDir;
|
||||
char *szWtmpDir;
|
||||
@ -948,6 +949,7 @@ static struct parm_struct parm_table[] = {
|
||||
{"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, handle_wins_server_list, NULL, FLAG_BASIC},
|
||||
{"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC},
|
||||
{"wins hook", P_STRING, P_GLOBAL, &Globals.szWINSHook, NULL, NULL, 0},
|
||||
{"wins partners", P_STRING, P_GLOBAL, &Globals.szWINSPartners, NULL, NULL, 0},
|
||||
|
||||
{"Locking Options", P_SEP, P_SEPARATOR},
|
||||
|
||||
@ -1520,6 +1522,7 @@ FN_GLOBAL_STRING(lp_shutdown_script, &Globals.szShutdownScript)
|
||||
FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript)
|
||||
|
||||
FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
|
||||
FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners)
|
||||
FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
|
||||
FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell)
|
||||
FN_GLOBAL_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
|
||||
|
695
source/wrepld/parser.c
Normal file
695
source/wrepld/parser.c
Normal file
@ -0,0 +1,695 @@
|
||||
/*
|
||||
* Unix SMB/Netbios implementation.
|
||||
* Version 1.9.
|
||||
* 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
|
||||
****************************************************************************/
|
||||
static 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));
|
||||
|
||||
if (buffer->offset+more >= buffer->length) {
|
||||
temp=(char *)talloc_realloc(mem_ctx, buffer->buffer, sizeof(char)* (buffer->length+256) );
|
||||
if (temp==NULL) {
|
||||
DEBUG(0,("grow_buffer: can't grow buffer\n"));
|
||||
return False;
|
||||
}
|
||||
buffer->length+=256;
|
||||
buffer->buffer=temp;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a WINS_OWNER struct
|
||||
****************************************************************************/
|
||||
static int decode_wins_owner(char *inbuf, int offset, WINS_OWNER *wins_owner)
|
||||
{
|
||||
wins_owner->address.s_addr=IVAL(inbuf, offset);
|
||||
offset+=4;
|
||||
wins_owner->max_version=((SMB_BIG_UINT)RIVAL(inbuf, offset))<<32;
|
||||
offset+=4;
|
||||
wins_owner->max_version|=RIVAL(inbuf, offset);
|
||||
offset+=4;
|
||||
wins_owner->min_version=((SMB_BIG_UINT)RIVAL(inbuf, offset))<<32;
|
||||
offset+=4;
|
||||
wins_owner->min_version|=RIVAL(inbuf, offset);
|
||||
offset+=4;
|
||||
wins_owner->type=RIVAL(inbuf, offset);
|
||||
offset+=4;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a WINS_NAME struct
|
||||
****************************************************************************/
|
||||
static int decode_wins_name(char *outbuf, int offset, WINS_NAME *wins_name)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
wins_name->name_len=RIVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
memcpy(wins_name->name,outbuf+offset, 15);
|
||||
wins_name->name[16]='\0';
|
||||
if((p = strchr(wins_name->name,' ')) != NULL)
|
||||
*p = 0;
|
||||
|
||||
offset+=15;
|
||||
|
||||
wins_name->type=(int)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, offset);
|
||||
offset+=4;
|
||||
|
||||
wins_name->name_flag=RIVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
wins_name->group_flag=RIVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
wins_name->id=((SMB_BIG_UINT)RIVAL(outbuf, offset))<<32;
|
||||
offset+=4;
|
||||
wins_name->id|=RIVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
|
||||
/* special groups have multiple address */
|
||||
if (wins_name->name_flag & 2) {
|
||||
wins_name->num_ip=IVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
}
|
||||
else
|
||||
wins_name->num_ip=1;
|
||||
|
||||
wins_name->owner.s_addr=IVAL(outbuf, offset);
|
||||
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 offset;
|
||||
|
||||
for (i=0; i<wins_name->num_ip; i++) {
|
||||
wins_name->others[i].s_addr=IVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
}
|
||||
}
|
||||
|
||||
wins_name->foo=RIVAL(outbuf, offset);
|
||||
offset+=4;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a update notification request
|
||||
****************************************************************************/
|
||||
static void decode_update_notify_request(char *inbuf, UPDATE_NOTIFY_REQUEST *un_rq)
|
||||
{
|
||||
int i;
|
||||
int offset=4;
|
||||
|
||||
un_rq->partner_count=RIVAL(inbuf, 0);
|
||||
|
||||
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++)
|
||||
offset=decode_wins_owner(inbuf, offset, &un_rq->wins_owner[i]);
|
||||
|
||||
un_rq->initiating_wins_server.s_addr=IVAL(inbuf, offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a send entries request
|
||||
****************************************************************************/
|
||||
static void decode_send_entries_request(char *inbuf, SEND_ENTRIES_REQUEST *se_rq)
|
||||
{
|
||||
int offset;
|
||||
offset=decode_wins_owner(inbuf, 0, &se_rq->wins_owner);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a send entries reply
|
||||
****************************************************************************/
|
||||
static void decode_send_entries_reply(char *inbuf, SEND_ENTRIES_REPLY *se_rp)
|
||||
{
|
||||
int i, offset=4;
|
||||
se_rp->max_names = RIVAL(inbuf, 0);
|
||||
|
||||
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++)
|
||||
offset = decode_wins_name(inbuf, offset, &se_rp->wins_name[i]);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a add version number map table reply
|
||||
****************************************************************************/
|
||||
static void decode_add_version_number_map_table_reply(char *inbuf, AVMT_REP *avmt_rep)
|
||||
{
|
||||
int i;
|
||||
int offset=4;
|
||||
|
||||
avmt_rep->partner_count=RIVAL(inbuf, 0);
|
||||
|
||||
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++)
|
||||
offset=decode_wins_owner(inbuf, offset, &avmt_rep->wins_owner[i]);
|
||||
|
||||
avmt_rep->initiating_wins_server.s_addr=IVAL(inbuf, offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a replicate packet and fill a structure
|
||||
****************************************************************************/
|
||||
static void decode_replicate(char *inbuf, REPLICATE *rep)
|
||||
{
|
||||
rep->msg_type = RIVAL(inbuf, 0);
|
||||
|
||||
switch (rep->msg_type) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* add version number map table reply */
|
||||
decode_add_version_number_map_table_reply(inbuf+4, &rep->avmt_rep);
|
||||
break;
|
||||
case 2:
|
||||
/* send entry request */
|
||||
decode_send_entries_request(inbuf+4, &rep->se_rq);
|
||||
break;
|
||||
case 3:
|
||||
/* send entry request */
|
||||
decode_send_entries_reply(inbuf+4, &rep->se_rp);
|
||||
break;
|
||||
case 4:
|
||||
/* update notification request */
|
||||
decode_update_notify_request(inbuf+4, &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(char *inbuf, generic_header *q)
|
||||
{
|
||||
q->data_size = RIVAL(inbuf,0);
|
||||
q->opcode = RIVAL(inbuf,4);
|
||||
q->assoc_ctx = RIVAL(inbuf,8);
|
||||
q->mess_type = RIVAL(inbuf,12);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
decode a start association request
|
||||
********************************************************************/
|
||||
static void decode_start_assoc_request(char *inbuf, START_ASSOC_REQUEST *q)
|
||||
{
|
||||
q->assoc_ctx = RIVAL(inbuf, 0);
|
||||
q->min_ver = RSVAL(inbuf, 4);
|
||||
q->maj_ver = RSVAL(inbuf, 6);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
decode a start association reply
|
||||
********************************************************************/
|
||||
static void decode_start_assoc_reply(char *inbuf, START_ASSOC_REPLY *r)
|
||||
{
|
||||
r->assoc_ctx=RIVAL(inbuf, 0);
|
||||
r->min_ver = RSVAL(inbuf, 4);
|
||||
r->maj_ver = RSVAL(inbuf, 6);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
decode a start association reply
|
||||
********************************************************************/
|
||||
static void decode_stop_assoc(char *inbuf, STOP_ASSOC *r)
|
||||
{
|
||||
r->reason=RIVAL(inbuf, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode a packet and fill a generic structure
|
||||
****************************************************************************/
|
||||
void decode_generic_packet(char *inbuf, GENERIC_PACKET *q)
|
||||
{
|
||||
read_generic_header(inbuf, &q->header);
|
||||
|
||||
switch (q->header.mess_type) {
|
||||
case 0:
|
||||
decode_start_assoc_request(inbuf+16, &q->sa_rq);
|
||||
break;
|
||||
case 1:
|
||||
decode_start_assoc_reply(inbuf+16, &q->sa_rp);
|
||||
break;
|
||||
case 2:
|
||||
decode_stop_assoc(inbuf+16, &q->so);
|
||||
break;
|
||||
case 3:
|
||||
decode_replicate(inbuf+16, &q->rep);
|
||||
break;
|
||||
default:
|
||||
DEBUG(0,("decode_generic_packet: unknown message type:%d\n", q->header.mess_type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
decode 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,("decode_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;
|
||||
|
||||
}
|
||||
|
||||
|
183
source/wrepld/partners.c
Normal file
183
source/wrepld/partners.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 1.9.
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
935
source/wrepld/process.c
Normal file
935
source/wrepld/process.c
Normal file
@ -0,0 +1,935 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 1.9.
|
||||
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(0,("\n%d ", i));
|
||||
for (j=0; global_wins_table[i][j].address.s_addr!=0; j++)
|
||||
DEBUG(0,("%s:%d \t", inet_ntoa(global_wins_table[i][j].address),
|
||||
(int)global_wins_table[i][j].max_version));
|
||||
}
|
||||
DEBUG(0,("\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(0,("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(0,("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 = lp_list_make(lp_wins_partners());
|
||||
|
||||
DEBUG(0, ("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(0,("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];
|
||||
|
||||
lp_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_int(tdb, INFO_ID_HIGH))<<32 |
|
||||
(SMB_BIG_UINT)tdb_fetch_int(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(0, ("send_entry_reply: 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(0,("send_version_number_map_table: partner_count: %d\n", partner_count));
|
||||
|
||||
for (i=0; i<partner_count; i++) {
|
||||
DEBUG(0,("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(0, ("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(0,("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(0,("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(0,("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 is 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(0, ("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(0,("send_entry_request: we have been asked to send the list of wins records\n"));
|
||||
DEBUGADD(0,("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) {
|
||||
pstring name_type, 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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(0,("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(0, ("send_entry_reply: 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(0,("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(0,("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(0, ("send_entry_reply: request for a partner not in our table\n"));
|
||||
stop_packet(q, r, STOP_REASON_USER_REASON);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(0,("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(0,("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(0,("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 */
|
||||
/*
|
||||
* remove the partner from the list and
|
||||
* reply false to NOT send a packet
|
||||
*/
|
||||
remove_partner(q->header.assoc_ctx);
|
||||
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(0,("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(0,("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(0,("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)
|
||||
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 */
|
||||
|
||||
}
|
||||
|
724
source/wrepld/server.c
Normal file
724
source/wrepld/server.c
Normal file
@ -0,0 +1,724 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 1.9.
|
||||
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 fstring global_myworkgroup;
|
||||
extern pstring global_myname;
|
||||
|
||||
extern pstring user_socket_options;
|
||||
|
||||
extern fstring remote_machine;
|
||||
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(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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
initialise connect, service and file structs
|
||||
****************************************************************************/
|
||||
static void init_structs(void )
|
||||
{
|
||||
/*
|
||||
* Set the machine NETBIOS name if not already
|
||||
* set from the config file.
|
||||
*/
|
||||
|
||||
if (!*global_myname) {
|
||||
char *p;
|
||||
fstrcpy( global_myname, myhostname() );
|
||||
p = strchr_m( global_myname, '.' );
|
||||
if (p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
strupper( global_myname );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
usage on the program
|
||||
****************************************************************************/
|
||||
static void usage(char *pname)
|
||||
{
|
||||
|
||||
d_printf("Usage: %s [-DaioPh?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-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,user_socket_options);
|
||||
|
||||
if (listen(s, 5) == -1) {
|
||||
DEBUG(0,("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,user_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;
|
||||
char buf[4096];
|
||||
|
||||
if (!receive_smb(fd, buf, timeout))
|
||||
return NULL;
|
||||
|
||||
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(buf, 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, &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);
|
||||
|
||||
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, user_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 BOOL append_log;
|
||||
extern char *optarg;
|
||||
/* shall I run as a daemon */
|
||||
BOOL is_daemon = False;
|
||||
BOOL interactive = False;
|
||||
BOOL specified_logfile = 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, "O:l:s:d:Dp:h?Vaiof:")) )
|
||||
switch (opt) {
|
||||
case 'O':
|
||||
pstrcpy(user_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 'a':
|
||||
append_log = True;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
interactive = True;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
append_log = False;
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETLUID
|
||||
/* needed for SecureWare on SCO */
|
||||
setluid(0);
|
||||
#endif
|
||||
|
||||
sec_init();
|
||||
|
||||
load_case_tables();
|
||||
|
||||
append_log = True;
|
||||
|
||||
if(!specified_logfile) {
|
||||
slprintf(logfile, sizeof(logfile)-1, "%s/log.wrepld",
|
||||
dyn_LOGFILEBASE);
|
||||
lp_set_logfile(logfile);
|
||||
}
|
||||
|
||||
pstrcpy(remote_machine, "wrepld");
|
||||
|
||||
setup_logging(argv[0],interactive);
|
||||
|
||||
/* 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);
|
||||
|
||||
init_structs();
|
||||
|
||||
#ifdef WITH_PROFILE
|
||||
if (!profile_setup(False)) {
|
||||
DEBUG(0,("ERROR: failed to setup profiling\n"));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
fstrcpy(global_myworkgroup, lp_workgroup());
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
#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_named("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);
|
||||
}
|
70
source/wrepld/socket.c
Normal file
70
source/wrepld/socket.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 1.9.
|
||||
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));
|
||||
}
|
162
source/wrepld/wins_repl.h
Normal file
162
source/wrepld/wins_repl.h
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Unix SMB/Netbios implementation.
|
||||
* Version 1.9.
|
||||
* 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"
|
||||
|
Loading…
Reference in New Issue
Block a user