diff options
Diffstat (limited to 'source3/wrepld/parser.c')
-rw-r--r-- | source3/wrepld/parser.c | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/source3/wrepld/parser.c b/source3/wrepld/parser.c new file mode 100644 index 0000000000..1eb2233810 --- /dev/null +++ b/source3/wrepld/parser.c @@ -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; + +} + + |