From 56de6fa4705d8e43049e8c862c024301e3ef78d3 Mon Sep 17 00:00:00 2001 From: Jean-François Micouleau Date: Sat, 27 Apr 2002 16:58:05 +0000 Subject: this code has been sitting on one of my box for 3 months. add wins push replication, better handling of partners, rewrote half of parser. I know some parser code need to be changed to better cope with multihomed machine and groups. J.F. (This used to be commit a2d07bc6eb269c8048165947928b8b5643dc9a64) --- source3/wrepld/parser.c | 245 +++++++++++++++++++++++++++++----------------- source3/wrepld/partners.c | 20 +++- source3/wrepld/process.c | 57 +++++++++-- source3/wrepld/server.c | 43 +++++++- 4 files changed, 262 insertions(+), 103 deletions(-) (limited to 'source3/wrepld') diff --git a/source3/wrepld/parser.c b/source3/wrepld/parser.c index 61d8a604ce..1c3fd70095 100644 --- a/source3/wrepld/parser.c +++ b/source3/wrepld/parser.c @@ -26,64 +26,85 @@ extern TALLOC_CTX *mem_ctx; /**************************************************************************** grow the send buffer if necessary ****************************************************************************/ -static BOOL grow_buffer(struct BUFFER *buffer, int more) +BOOL grow_buffer(struct BUFFER *buffer, int more) { char *temp; DEBUG(10,("grow_buffer: size is: %d offet is:%d growing by %d\n", buffer->length, buffer->offset, more)); + /* grow by at least 256 bytes */ + if (more<256) + more=256; + if (buffer->offset+more >= buffer->length) { - temp=(char *)talloc_realloc(mem_ctx, buffer->buffer, sizeof(char)* (buffer->length+256) ); + temp=(char *)talloc_realloc(mem_ctx, buffer->buffer, sizeof(char)* (buffer->length+more) ); if (temp==NULL) { DEBUG(0,("grow_buffer: can't grow buffer\n")); return False; } - buffer->length+=256; + buffer->length+=more; buffer->buffer=temp; } return True; } +/**************************************************************************** +check if the buffer has that much data +****************************************************************************/ +static BOOL check_buffer(struct BUFFER *buffer, int more) +{ + char *temp; + + DEBUG(10,("check_buffer: size is: %d offet is:%d growing by %d\n", buffer->length, buffer->offset, more)); + + if (buffer->offset+more > buffer->length) { + DEBUG(10,("check_buffer: buffer smaller than requested, size is: %d needed: %d\n", buffer->length, buffer->offset+more)); + return False; + } + + return True; +} + /**************************************************************************** decode a WINS_OWNER struct ****************************************************************************/ -static int decode_wins_owner(char *inbuf, int offset, WINS_OWNER *wins_owner) +static void decode_wins_owner(struct BUFFER *inbuf, 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; + if(!check_buffer(inbuf, 24)) + return; + + wins_owner->address.s_addr=IVAL(inbuf->buffer, inbuf->offset); + wins_owner->max_version=((SMB_BIG_UINT)RIVAL(inbuf->buffer, inbuf->offset+4))<<32; + wins_owner->max_version|=RIVAL(inbuf->buffer, inbuf->offset+8); + wins_owner->min_version=((SMB_BIG_UINT)RIVAL(inbuf->buffer, inbuf->offset+12))<<32; + wins_owner->min_version|=RIVAL(inbuf->buffer, inbuf->offset+16); + wins_owner->type=RIVAL(inbuf->buffer, inbuf->offset+20); + inbuf->offset+=24; + } /**************************************************************************** decode a WINS_NAME struct ****************************************************************************/ -static int decode_wins_name(char *outbuf, int offset, WINS_NAME *wins_name) +static void decode_wins_name(struct BUFFER *outbuf, WINS_NAME *wins_name) { char *p; int i; - wins_name->name_len=RIVAL(outbuf, offset); - offset+=4; - memcpy(wins_name->name,outbuf+offset, 15); + if(!check_buffer(outbuf, 40)) + return; + + wins_name->name_len=RIVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; + memcpy(wins_name->name,outbuf->buffer+outbuf->offset, 15); wins_name->name[16]='\0'; if((p = strchr(wins_name->name,' ')) != NULL) *p = 0; - offset+=15; + outbuf->offset+=15; - wins_name->type=(int)outbuf[offset++]; + wins_name->type=(int)outbuf->buffer[outbuf->offset++]; /* * fix to bug in WINS replication, @@ -94,136 +115,162 @@ static int decode_wins_name(char *outbuf, int offset, WINS_NAME *wins_name) wins_name->type=0x1B; } - wins_name->empty=RIVAL(outbuf, offset); - offset+=4; + wins_name->empty=RIVAL(outbuf->buffer, outbuf->offset); + outbuf->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; + wins_name->name_flag=RIVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; + wins_name->group_flag=RIVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; + wins_name->id=((SMB_BIG_UINT)RIVAL(outbuf->buffer, outbuf->offset))<<32; + outbuf->offset+=4; + wins_name->id|=RIVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; /* special groups have multiple address */ if (wins_name->name_flag & 2) { - wins_name->num_ip=IVAL(outbuf, offset); - offset+=4; + if(!check_buffer(outbuf, 4)) + return; + wins_name->num_ip=IVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; } else wins_name->num_ip=1; - wins_name->owner.s_addr=IVAL(outbuf, offset); - offset+=4; + if(!check_buffer(outbuf, 4)) + return; + wins_name->owner.s_addr=IVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; if (wins_name->name_flag & 2) { wins_name->others=(struct in_addr *)talloc(mem_ctx, sizeof(struct in_addr)*wins_name->num_ip); if (wins_name->others==NULL) - return offset; + return; + if(!check_buffer(outbuf, 4*wins_name->num_ip)) + return; for (i=0; inum_ip; i++) { - wins_name->others[i].s_addr=IVAL(outbuf, offset); - offset+=4; + wins_name->others[i].s_addr=IVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; } } - wins_name->foo=RIVAL(outbuf, offset); - offset+=4; + if(!check_buffer(outbuf, 4)) + return; + wins_name->foo=RIVAL(outbuf->buffer, outbuf->offset); + outbuf->offset+=4; - return offset; } /**************************************************************************** decode a update notification request ****************************************************************************/ -static void decode_update_notify_request(char *inbuf, UPDATE_NOTIFY_REQUEST *un_rq) +static void decode_update_notify_request(struct BUFFER *inbuf, UPDATE_NOTIFY_REQUEST *un_rq) { int i; - int offset=4; - un_rq->partner_count=RIVAL(inbuf, 0); + if(!check_buffer(inbuf, 4)) + return; + un_rq->partner_count=RIVAL(inbuf->buffer, inbuf->offset); + inbuf->offset+=4; un_rq->wins_owner=(WINS_OWNER *)talloc(mem_ctx, un_rq->partner_count*sizeof(WINS_OWNER)); if (un_rq->wins_owner==NULL) return; for (i=0; ipartner_count; i++) - offset=decode_wins_owner(inbuf, offset, &un_rq->wins_owner[i]); + decode_wins_owner(inbuf, &un_rq->wins_owner[i]); - un_rq->initiating_wins_server.s_addr=IVAL(inbuf, offset); + if(!check_buffer(inbuf, 4)) + return; + un_rq->initiating_wins_server.s_addr=IVAL(inbuf->buffer, inbuf->offset); + inbuf->offset+=4; } /**************************************************************************** decode a send entries request ****************************************************************************/ -static void decode_send_entries_request(char *inbuf, SEND_ENTRIES_REQUEST *se_rq) +static void decode_send_entries_request(struct BUFFER *inbuf, SEND_ENTRIES_REQUEST *se_rq) { - int offset; - offset=decode_wins_owner(inbuf, 0, &se_rq->wins_owner); + decode_wins_owner(inbuf, &se_rq->wins_owner); } /**************************************************************************** decode a send entries reply ****************************************************************************/ -static void decode_send_entries_reply(char *inbuf, SEND_ENTRIES_REPLY *se_rp) +static void decode_send_entries_reply(struct BUFFER *inbuf, SEND_ENTRIES_REPLY *se_rp) { - int i, offset=4; - se_rp->max_names = RIVAL(inbuf, 0); + int i; + + if(!check_buffer(inbuf, 4)) + return; + se_rp->max_names = RIVAL(inbuf->buffer, inbuf->offset); + inbuf->offset+=4; se_rp->wins_name=(WINS_NAME *)talloc(mem_ctx, se_rp->max_names*sizeof(WINS_NAME)); if (se_rp->wins_name==NULL) return; for (i=0; imax_names; i++) - offset = decode_wins_name(inbuf, offset, &se_rp->wins_name[i]); + decode_wins_name(inbuf, &se_rp->wins_name[i]); } /**************************************************************************** decode a add version number map table reply ****************************************************************************/ -static void decode_add_version_number_map_table_reply(char *inbuf, AVMT_REP *avmt_rep) +static void decode_add_version_number_map_table_reply(struct BUFFER *inbuf, AVMT_REP *avmt_rep) { int i; - int offset=4; - avmt_rep->partner_count=RIVAL(inbuf, 0); + if(!check_buffer(inbuf, 4)) + return; + + avmt_rep->partner_count=RIVAL(inbuf->buffer, inbuf->offset); + inbuf->offset+=4; avmt_rep->wins_owner=(WINS_OWNER *)talloc(mem_ctx, avmt_rep->partner_count*sizeof(WINS_OWNER)); if (avmt_rep->wins_owner==NULL) return; for (i=0; ipartner_count; i++) - offset=decode_wins_owner(inbuf, offset, &avmt_rep->wins_owner[i]); + decode_wins_owner(inbuf, &avmt_rep->wins_owner[i]); - avmt_rep->initiating_wins_server.s_addr=IVAL(inbuf, offset); + if(!check_buffer(inbuf, 4)) + return; + avmt_rep->initiating_wins_server.s_addr=IVAL(inbuf->buffer, inbuf->offset); + inbuf->offset+=4; } /**************************************************************************** decode a replicate packet and fill a structure ****************************************************************************/ -static void decode_replicate(char *inbuf, REPLICATE *rep) +static void decode_replicate(struct BUFFER *inbuf, REPLICATE *rep) { - rep->msg_type = RIVAL(inbuf, 0); + if(!check_buffer(inbuf, 4)) + return; + + rep->msg_type = RIVAL(inbuf->buffer, inbuf->offset); + + inbuf->offset+=4; switch (rep->msg_type) { case 0: break; case 1: /* add version number map table reply */ - decode_add_version_number_map_table_reply(inbuf+4, &rep->avmt_rep); + decode_add_version_number_map_table_reply(inbuf, &rep->avmt_rep); break; case 2: /* send entry request */ - decode_send_entries_request(inbuf+4, &rep->se_rq); + decode_send_entries_request(inbuf, &rep->se_rq); break; case 3: /* send entry request */ - decode_send_entries_reply(inbuf+4, &rep->se_rp); + decode_send_entries_reply(inbuf, &rep->se_rp); break; case 4: /* update notification request */ - decode_update_notify_request(inbuf+4, &rep->un_rq); + decode_update_notify_request(inbuf, &rep->un_rq); break; default: DEBUG(0,("decode_replicate: unknown message type:%d\n", rep->msg_type)); @@ -234,61 +281,75 @@ static void decode_replicate(char *inbuf, REPLICATE *rep) /**************************************************************************** read the generic header and fill the struct. ****************************************************************************/ -static void read_generic_header(char *inbuf, generic_header *q) +static void read_generic_header(struct BUFFER *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); + if(!check_buffer(inbuf, 16)) + return; + + q->data_size = RIVAL(inbuf->buffer, inbuf->offset+0); + q->opcode = RIVAL(inbuf->buffer, inbuf->offset+4); + q->assoc_ctx = RIVAL(inbuf->buffer, inbuf->offset+8); + q->mess_type = RIVAL(inbuf->buffer, inbuf->offset+12); } /******************************************************************* decode a start association request ********************************************************************/ -static void decode_start_assoc_request(char *inbuf, START_ASSOC_REQUEST *q) +static void decode_start_assoc_request(struct BUFFER *inbuf, START_ASSOC_REQUEST *q) { - q->assoc_ctx = RIVAL(inbuf, 0); - q->min_ver = RSVAL(inbuf, 4); - q->maj_ver = RSVAL(inbuf, 6); + if(!check_buffer(inbuf, 8)) + return; + + q->assoc_ctx = RIVAL(inbuf->buffer, inbuf->offset+0); + q->min_ver = RSVAL(inbuf->buffer, inbuf->offset+4); + q->maj_ver = RSVAL(inbuf->buffer, inbuf->offset+6); } /******************************************************************* decode a start association reply ********************************************************************/ -static void decode_start_assoc_reply(char *inbuf, START_ASSOC_REPLY *r) +static void decode_start_assoc_reply(struct BUFFER *inbuf, START_ASSOC_REPLY *r) { - r->assoc_ctx=RIVAL(inbuf, 0); - r->min_ver = RSVAL(inbuf, 4); - r->maj_ver = RSVAL(inbuf, 6); + if(!check_buffer(inbuf, 8)) + return; + + r->assoc_ctx=RIVAL(inbuf->buffer, inbuf->offset+0); + r->min_ver = RSVAL(inbuf->buffer, inbuf->offset+4); + r->maj_ver = RSVAL(inbuf->buffer, inbuf->offset+6); } /******************************************************************* decode a start association reply ********************************************************************/ -static void decode_stop_assoc(char *inbuf, STOP_ASSOC *r) +static void decode_stop_assoc(struct BUFFER *inbuf, STOP_ASSOC *r) { - r->reason=RIVAL(inbuf, 0); + if(!check_buffer(inbuf, 4)) + return; + + r->reason=RIVAL(inbuf->buffer, inbuf->offset); } /**************************************************************************** decode a packet and fill a generic structure ****************************************************************************/ -void decode_generic_packet(char *inbuf, GENERIC_PACKET *q) +void decode_generic_packet(struct BUFFER *inbuf, GENERIC_PACKET *q) { read_generic_header(inbuf, &q->header); + inbuf->offset+=16; + switch (q->header.mess_type) { case 0: - decode_start_assoc_request(inbuf+16, &q->sa_rq); + decode_start_assoc_request(inbuf, &q->sa_rq); break; case 1: - decode_start_assoc_reply(inbuf+16, &q->sa_rp); + decode_start_assoc_reply(inbuf, &q->sa_rp); break; case 2: - decode_stop_assoc(inbuf+16, &q->so); + decode_stop_assoc(inbuf, &q->so); break; case 3: - decode_replicate(inbuf+16, &q->rep); + decode_replicate(inbuf, &q->rep); break; default: DEBUG(0,("decode_generic_packet: unknown message type:%d\n", q->header.mess_type)); @@ -296,6 +357,9 @@ void decode_generic_packet(char *inbuf, GENERIC_PACKET *q) } } +/**************************************************************************** +encode a WINS_OWNER struct +****************************************************************************/ static void encode_wins_owner(struct BUFFER *outbuf, WINS_OWNER *wins_owner) { if (!grow_buffer(outbuf, 24)) @@ -316,6 +380,9 @@ static void encode_wins_owner(struct BUFFER *outbuf, WINS_OWNER *wins_owner) } +/**************************************************************************** +encode a WINS_NAME struct +****************************************************************************/ static void encode_wins_name(struct BUFFER *outbuf, WINS_NAME *wins_name) { int i; @@ -366,7 +433,7 @@ static void encode_wins_name(struct BUFFER *outbuf, WINS_NAME *wins_name) } /**************************************************************************** -decode a update notification request +encode a update notification request ****************************************************************************/ static void encode_update_notify_request(struct BUFFER *outbuf, UPDATE_NOTIFY_REQUEST *un_rq) { @@ -464,7 +531,7 @@ static void encode_replicate(struct BUFFER *outbuf, REPLICATE *rep) encode_update_notify_request(outbuf, &rep->un_rq); break; default: - DEBUG(0,("decode_replicate: unknown message type:%d\n", rep->msg_type)); + DEBUG(0,("encode_replicate: unknown message type:%d\n", rep->msg_type)); break; } } diff --git a/source3/wrepld/partners.c b/source3/wrepld/partners.c index abdaeaf2ee..11f8e3ffee 100644 --- a/source3/wrepld/partners.c +++ b/source3/wrepld/partners.c @@ -31,7 +31,9 @@ verify if we know this partner BOOL check_partner(int assoc) { int i; - + + DEBUG(0,("check_partner: total_current_partners: %d\n", total_current_partners)); + for (i=0; is_addr=current_partners[i].partner_server.s_addr; diff --git a/source3/wrepld/process.c b/source3/wrepld/process.c index e63b8a993c..031e974895 100644 --- a/source3/wrepld/process.c +++ b/source3/wrepld/process.c @@ -212,7 +212,7 @@ static void send_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r) 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")); + DEBUG(0, ("send_version_number_map_table: request for a partner not in our table\n")); stop_packet(q, r, STOP_REASON_USER_REASON); return; } @@ -382,7 +382,7 @@ static void receive_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET * * 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. + * So in the send entry reply, we'll ask for the next server if required. */ if (check_partners_and_send_entries(q, r, i)) @@ -586,7 +586,7 @@ static void update_notify_request(GENERIC_PACKET *q, GENERIC_PACKET *r) 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")); + DEBUG(0, ("update_notify_request: request for a partner not in our table\n")); stop_packet(q, r, STOP_REASON_USER_REASON); return; } @@ -799,11 +799,6 @@ static BOOL switch_message(GENERIC_PACKET *q, GENERIC_PACKET *r) 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: @@ -868,8 +863,10 @@ void construct_reply(struct wins_packet_struct *p) /* 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) + r.header.mess_type==MESSAGE_TYPE_STOP_ASSOC) { + remove_partner(p->packet->header.assoc_ctx); p->stop_packet=True; + } } /**************************************************************************** @@ -929,6 +926,48 @@ void run_pull_replication(time_t t) void run_push_replication(time_t t) { /* we push every 30 minutes or 25 new entries */ + int i, s; + struct BUFFER buffer; + GENERIC_PACKET p; + + buffer.buffer=NULL; + buffer.offset=0; + buffer.length=0; + for (i=1; i 0) { + if (!send_smb(s, buffer.buffer)) + exit_server("run_push_replication: send_smb failed."); + } + + add_fd_to_sock_array(s); + FD_SET(s, listen_set); + + /* add ourself as a client */ + add_partner((int)t, 0, False, True); + } + } } diff --git a/source3/wrepld/server.c b/source3/wrepld/server.c index d078a833ae..f06fdf1190 100644 --- a/source3/wrepld/server.c +++ b/source3/wrepld/server.c @@ -304,17 +304,49 @@ static struct wins_packet_struct *read_wins_packet(int fd, int timeout) { struct wins_packet_struct *p; GENERIC_PACKET *q; - char buf[4096]; + struct BUFFER inbuf; + ssize_t len=0; + size_t total=0; + ssize_t ret; + BOOL ok = False; - if (!receive_smb(fd, buf, timeout)) + inbuf.buffer=NULL; + inbuf.length=0; + inbuf.offset=0; + + if(!grow_buffer(&inbuf, 4)) + return NULL; + + ok = (read(fd, inbuf.buffer,4) == 4); + if (!ok) return NULL; + len = smb_len(inbuf.buffer); + + if (len<=0) + return NULL; + + if(!grow_buffer(&inbuf, len)) + return NULL; + + while (total < len) { + ret = read(fd, inbuf.buffer + total + 4, len - total); + if (ret == 0) { + DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(len - total), strerror(errno) )); + return NULL; + } + if (ret == -1) { + DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(len - total), strerror(errno) )); + return NULL; + } + total += ret; + } q = (GENERIC_PACKET *)talloc(mem_ctx, sizeof(GENERIC_PACKET)); p = (struct wins_packet_struct *)talloc(mem_ctx, sizeof(*p)); if (q==NULL || p==NULL) return NULL; - decode_generic_packet(buf, q); + decode_generic_packet(&inbuf, q); q->fd=fd; @@ -403,7 +435,10 @@ static BOOL listen_for_wins_packets(void) /* accept and add the new socket to the listen set */ new_s=accept(s, &addr, &in_addrlen); - + + if (new_s < 0) + continue; + DEBUG(5,("listen_for_wins_packets: new connection, old: %d, new : %d\n", s, new_s)); set_socket_options(new_s, "SO_KEEPALIVE"); -- cgit