1/*
2   Unix SMB/CIFS implementation.
3   process incoming packets - main loop
4   Copyright (C) Jean Fran�ois Micouleau      1998-2002.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22#include "wins_repl.h"
23
24extern fd_set *listen_set;
25extern int listen_number;
26extern int *sock_array;
27
28WINS_OWNER global_wins_table[64][64];
29int partner_count;
30
31TALLOC_CTX *mem_ctx;
32
33#define WINS_LIST "wins.tdb"
34#define INFO_VERSION	"INFO/version"
35#define INFO_COUNT	"INFO/num_entries"
36#define INFO_ID_HIGH	"INFO/id_high"
37#define INFO_ID_LOW	"INFO/id_low"
38#define ENTRY_PREFIX 	"ENTRY/"
39
40
41/*******************************************************************
42fill the header of a reply.
43********************************************************************/
44static void fill_header(GENERIC_PACKET *g, int opcode, int ctx, int mess)
45{
46	if (g==NULL)
47		return;
48
49	g->header.opcode=opcode;
50	g->header.assoc_ctx=ctx;
51	g->header.mess_type=mess;
52}
53
54/*******************************************************************
55dump the global table, that's a debug code.
56********************************************************************/
57static void dump_global_table(void)
58{
59	int i,j;
60
61	for (i=0;i<partner_count;i++) {
62		DEBUG(10,("\n%d ", i));
63		for (j=0; global_wins_table[i][j].address.s_addr!=0; j++)
64			DEBUG(10,("%s:%d \t", inet_ntoa(global_wins_table[i][j].address),
65				(int)global_wins_table[i][j].max_version));
66	}
67	DEBUG(10,("\n"));
68}
69
70/*******************************************************************
71start association
72********************************************************************/
73static void start_assoc_process(GENERIC_PACKET *q, GENERIC_PACKET *r)
74{
75	/*
76	 * add this request to our current wins partners list
77	 * this list is used to know with who we are in contact
78	 *
79	 */
80	r->sa_rp.assoc_ctx=time(NULL);
81	fill_header(r, OPCODE_NON_NBT, q->sa_rq.assoc_ctx, MESSAGE_TYPE_START_ASSOC_REPLY);
82
83	/* reply we are a NT4 server */
84
85	/* w2K is min=2, maj=5 */
86
87	r->sa_rp.min_ver=1;
88	r->sa_rp.maj_ver=1;
89
90	add_partner(r->sa_rp.assoc_ctx, q->sa_rq.assoc_ctx, False, False);
91}
92
93/*******************************************************************
94start association reply
95********************************************************************/
96static void start_assoc_reply(GENERIC_PACKET *q, GENERIC_PACKET *r)
97{
98	int i;
99
100	/* check if we have already registered this client */
101	if (!check_partner(q->header.assoc_ctx)) {
102		DEBUG(0,("start_assoc_reply: unknown client\n"));
103		stop_packet(q, r, STOP_REASON_USER_REASON);
104		return;
105	}
106
107	if (!update_server_partner(q->header.assoc_ctx, q->sa_rp.assoc_ctx)) {
108		DEBUG(0,("start_assoc_reply: can't update server ctx\n"));
109		stop_packet(q, r, STOP_REASON_USER_REASON);
110		return;
111	}
112
113	/* if pull, request map table */
114	if (check_pull_partner(q->header.assoc_ctx)) {
115		fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);
116
117		r->rep.msg_type=MESSAGE_REP_ADD_VERSION_REQUEST;
118		DEBUG(5,("start_assoc_reply: requesting map table\n"));
119
120		return;
121	}
122
123	/* if push, send our table */
124	if (check_push_partner(q->header.assoc_ctx)) {
125		fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);
126		r->rep.msg_type=MESSAGE_REP_UPDATE_NOTIFY_REQUEST;
127		r->rep.un_rq.partner_count=partner_count;
128
129		r->rep.un_rq.wins_owner=(WINS_OWNER *)talloc(mem_ctx, partner_count*sizeof(WINS_OWNER));
130		if (r->rep.un_rq.wins_owner==NULL) {
131			DEBUG(0,("start_assoc_reply: can't alloc memory\n"));
132			stop_packet(q, r, STOP_REASON_USER_REASON);
133			return;
134		}
135
136		for (i=0; i<partner_count; i++)
137			r->rep.un_rq.wins_owner[i]=global_wins_table[0][i];
138
139		DEBUG(5,("start_assoc_reply: sending update table\n"));
140		return;
141	}
142
143	/* neither push/pull, stop */
144	/* we should not come here */
145	DEBUG(0,("we have a partner which is neither push nor pull !\n"));
146	stop_packet(q, r, STOP_REASON_USER_REASON);
147}
148
149/****************************************************************************
150initialise and fill the in-memory partner table.
151****************************************************************************/
152int init_wins_partner_table(void)
153{
154	int i=1,j=0,k;
155	char **partner = str_list_make(lp_wins_partners(), NULL);
156
157	if (partner==NULL) {
158		DEBUG(0,("wrepld: no partner list in smb.conf, exiting\n"));
159		exit_server("normal exit");
160		return(0);
161	}
162
163	DEBUG(4, ("init_wins_partner_table: partners: %s\n", lp_wins_partners()));
164
165	global_wins_table[0][0].address=*iface_n_ip(0);
166	global_wins_table[0][0].max_version=0;
167	global_wins_table[0][0].min_version=0;
168	global_wins_table[0][0].type=0;
169
170	while (partner[j]!=NULL) {
171		DEBUG(3,("init_wins_partner_table, adding partner: %s\n", partner[j]));
172
173		global_wins_table[0][i].address=*interpret_addr2(partner[j]);
174		global_wins_table[0][i].max_version=0;
175		global_wins_table[0][i].min_version=0;
176		global_wins_table[0][i].type=0;
177		global_wins_table[0][i].last_pull=0;
178		global_wins_table[0][i].last_push=0;
179
180		i++;
181		j++;
182	}
183
184	for (k=1; k<i;k++)
185		for (j=0; j<i; j++)
186			global_wins_table[k][j]=global_wins_table[0][j];
187
188	str_list_free (&partner);
189
190	return i;
191}
192
193/****************************************************************************
194read the last ID from the wins tdb file.
195****************************************************************************/
196static void get_our_last_id(WINS_OWNER *wins_owner)
197{
198	TDB_CONTEXT *tdb;
199
200	tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);
201	if (!tdb) {
202		DEBUG(2,("get_our_last_id: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));
203		return;
204	}
205
206	wins_owner->max_version=((SMB_BIG_UINT)tdb_fetch_int32(tdb, INFO_ID_HIGH))<<32 |
207				 (SMB_BIG_UINT)tdb_fetch_int32(tdb, INFO_ID_LOW);
208
209	tdb_close(tdb);
210}
211
212/****************************************************************************
213send the list of wins server we know.
214****************************************************************************/
215static void send_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r)
216{
217	int i;
218	int s_ctx=get_server_assoc(q->header.assoc_ctx);
219
220	if (s_ctx==0) {
221		DEBUG(5, ("send_version_number_map_table: request for a partner not in our table\n"));
222		stop_packet(q, r, STOP_REASON_USER_REASON);
223		return;
224	}
225
226	/*
227	 * return an array of wins servers, we are partner with.
228	 * each entry contains the IP address and the version info
229	 * version: ID of the last entry we've got
230	 */
231
232	/* the first wins server must be self */
233
234	/*
235	 * get our last ID from the wins database
236	 * it can have been updated since last read
237	 * as nmbd got registration/release.
238	 */
239	get_our_last_id(&global_wins_table[0][0]);
240
241	r->rep.avmt_rep.wins_owner=(WINS_OWNER *)talloc(mem_ctx, partner_count*sizeof(WINS_OWNER));
242	if (r->rep.avmt_rep.wins_owner==NULL) {
243		stop_packet(q, r, STOP_REASON_USER_REASON);
244		return;
245	}
246
247	DEBUG(5,("send_version_number_map_table: partner_count: %d\n", partner_count));
248
249	for (i=0; i<partner_count; i++) {
250		DEBUG(5,("send_version_number_map_table, partner: %d -> %s, \n", i, inet_ntoa(global_wins_table[0][i].address)));
251		r->rep.avmt_rep.wins_owner[i]=global_wins_table[0][i];
252	}
253
254	r->rep.msg_type=1;
255	r->rep.avmt_rep.partner_count=partner_count;
256	r->rep.avmt_rep.initiating_wins_server.s_addr=0; /* blatant lie, NT4/w2K do the same ! */
257	fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);
258}
259
260/****************************************************************************
261for a given partner, ask it to send entries we don't have.
262****************************************************************************/
263static BOOL check_partners_and_send_entries(GENERIC_PACKET *q, GENERIC_PACKET *r, int partner)
264{
265	int server;
266	int other;
267	SMB_BIG_UINT temp;
268	SMB_BIG_UINT current;
269
270
271	/*
272	 * we check if our partner has more records than us.
273	 * we need to check more than our direct partners as
274	 * we can have this case:
275	 * us: A, partners: B,C, indirect partner: D
276	 * A<->B, A<->C, B<->D, C<->D
277	 *
278	 * So if we're talking to B, we need to check if between
279	 * B and C, which one have more records about D.
280	 * and also check if we don't already have the records.
281	 */
282
283
284	 /* check all servers even indirect */
285	 for (server=1; global_wins_table[0][server].address.s_addr!=0; server++) {
286		current = global_wins_table[partner][server].max_version;
287
288		temp=0;
289
290		for (other=1; other<partner_count; other++) {
291			/* skip the partner itself */
292			if (other==partner)
293				continue;
294
295			if (global_wins_table[other][server].max_version > temp)
296				temp=global_wins_table[other][server].max_version;
297		}
298
299		if (current >= temp && current > global_wins_table[0][server].max_version) {
300			/*
301			 * it has more records than every body else and more than us,
302			 * ask it the difference between what we have and what it has
303			 */
304			fill_header(r, OPCODE_NON_NBT, get_server_assoc(q->header.assoc_ctx), MESSAGE_TYPE_REPLICATE);
305
306			r->rep.msg_type=MESSAGE_REP_SEND_ENTRIES_REQUEST;
307			r->rep.se_rq.wins_owner.address=global_wins_table[partner][server].address;
308
309			r->rep.se_rq.wins_owner.max_version=global_wins_table[partner][server].max_version;
310			r->rep.se_rq.wins_owner.min_version=global_wins_table[0][server].max_version;
311			r->rep.se_rq.wins_owner.type=0;
312
313			write_server_assoc_table(q->header.assoc_ctx, global_wins_table[0][partner].address, global_wins_table[partner][server].address);
314
315			/*
316			 * and we update our version for this server
317			 * as we can't use the IDs returned in the send_entries function
318			 * the max ID can be larger than the largest ID returned
319			 */
320
321			global_wins_table[0][server].max_version=global_wins_table[partner][server].max_version;
322
323			return True;
324		}
325	}
326	return False;
327}
328
329/****************************************************************************
330receive the list of wins server we know.
331****************************************************************************/
332static void receive_version_number_map_table(GENERIC_PACKET *q, GENERIC_PACKET *r)
333{
334	fstring peer;
335	struct in_addr addr;
336	int i,j,k,l;
337	int s_ctx=get_server_assoc(q->header.assoc_ctx);
338
339	if (s_ctx==0) {
340		DEBUG(5, ("receive_version_number_map_table: request for a partner not in our table\n"));
341		stop_packet(q, r, STOP_REASON_USER_REASON);
342		return;
343	}
344
345	fstrcpy(peer,get_peer_addr(q->fd));
346	addr=*interpret_addr2(peer);
347
348	get_our_last_id(&global_wins_table[0][0]);
349
350	DEBUG(5,("receive_version_number_map_table: received a map of %d server from: %s\n",
351	          q->rep.avmt_rep.partner_count ,inet_ntoa(q->rep.avmt_rep.initiating_wins_server)));
352	DEBUG(5,("real peer is: %s\n", peer));
353
354	for (i=0; global_wins_table[0][i].address.s_addr!=addr.s_addr && i<partner_count;i++)
355		;
356
357	if (i==partner_count) {
358		DEBUG(5,("receive_version_number_map_table: unknown partner: %s\n", peer));
359		stop_packet(q, r, STOP_REASON_USER_REASON);
360		return;
361	}
362
363	for (j=0; j<q->rep.avmt_rep.partner_count;j++) {
364		/*
365		 * search if we already have this entry or if it's a new one
366		 * it can be a new one in case of propagation
367		 */
368		for (k=0; global_wins_table[0][k].address.s_addr!=0 &&
369			  global_wins_table[0][k].address.s_addr!=q->rep.avmt_rep.wins_owner[j].address.s_addr; k++);
370
371		global_wins_table[i][k].address.s_addr=q->rep.avmt_rep.wins_owner[j].address.s_addr;
372		global_wins_table[i][k].max_version=q->rep.avmt_rep.wins_owner[j].max_version;
373		global_wins_table[i][k].min_version=q->rep.avmt_rep.wins_owner[j].min_version;
374		global_wins_table[i][k].type=q->rep.avmt_rep.wins_owner[j].type;
375
376		/*
377		 * in case it's a new one, rewrite the address for all the partner
378		 * to reserve the slot.
379		 */
380
381		for(l=0; l<partner_count; l++)
382			global_wins_table[l][k].address.s_addr=q->rep.avmt_rep.wins_owner[j].address.s_addr;
383	}
384
385	dump_global_table();
386
387	/*
388	 * if this server have newer records than what we have
389	 * for several wins servers, we need to ask it.
390	 * Alas a send entry request is only on one server.
391	 * So in the send entry reply, we'll ask for the next server if required.
392	 */
393
394	if (check_partners_and_send_entries(q, r, i))
395		return;
396
397	/* it doesn't have more entries than us */
398	stop_packet(q, r, STOP_REASON_USER_REASON);
399}
400
401/****************************************************************************
402add an entry to the wins list we'll send.
403****************************************************************************/
404static 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)
405{
406	WINS_NAME *temp_list;
407	int i;
408	int current=*max_names;
409
410	temp_list=talloc_realloc(mem_ctx, *wins_name, (current+1)*sizeof(WINS_NAME));
411	if (temp_list==NULL)
412		return False;
413
414	temp_list[current].name_len=0x11;
415
416	safe_strcpy(temp_list[current].name, name, 15);
417
418	temp_list[current].type=type;
419	temp_list[current].empty=0;
420
421	temp_list[current].name_flag=wins_flags;
422
423	if ( (wins_flags&0x03) == 1 || (wins_flags&0x03)==2)
424		temp_list[current].group_flag=0x01000000;
425	else
426		temp_list[current].group_flag=0x00000000;
427
428	temp_list[current].id=id;
429
430	temp_list[current].owner.s_addr=ip_list[0].s_addr;
431
432	if (temp_list[current].name_flag & 2) {
433		temp_list[current].num_ip=num_ips;
434		temp_list[current].others=(struct in_addr *)talloc(mem_ctx, sizeof(struct in_addr)*num_ips);
435		if (temp_list[current].others==NULL)
436			return False;
437
438		for (i=0; i<num_ips; i++)
439			temp_list[current].others[i].s_addr=ip_list[i].s_addr;
440
441	} else
442		temp_list[current].num_ip=1;
443
444	temp_list[current].foo=0xffffffff;
445
446	*wins_name=temp_list;
447
448	return True;
449}
450
451/****************************************************************************
452send the list of name we have.
453****************************************************************************/
454static void send_entry_request(GENERIC_PACKET *q, GENERIC_PACKET *r)
455{
456	int max_names=0;
457	int i;
458	time_t time_now = time(NULL);
459	WINS_OWNER *wins_owner;
460	TDB_CONTEXT *tdb;
461	TDB_DATA kbuf, dbuf, newkey;
462	int s_ctx=get_server_assoc(q->header.assoc_ctx);
463	int num_interfaces = iface_count();
464
465	if (s_ctx==0) {
466		DEBUG(1, ("send_entry_request: request for a partner not in our table\n"));
467		stop_packet(q, r, STOP_REASON_USER_REASON);
468		return;
469	}
470
471
472	wins_owner=&q->rep.se_rq.wins_owner;
473	r->rep.se_rp.wins_name=NULL;
474
475	DEBUG(3,("send_entry_request: we have been asked to send the list of wins records\n"));
476	DEBUGADD(3,("owned by: %s and between min: %d and max: %d\n", inet_ntoa(wins_owner->address),
477		    (int)wins_owner->min_version, (int)wins_owner->max_version));
478
479	/*
480	 * if we are asked to send records owned by us
481	 * we overwrite the wins ip with 0.0.0.0
482	 * to make it easy in case of multihomed
483	 */
484
485	for (i=0; i<num_interfaces; i++)
486		if (ip_equal(wins_owner->address, *iface_n_ip(i))) {
487			wins_owner->address=*interpret_addr2("0.0.0.0");
488			break;
489		}
490
491
492	tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);
493	if (!tdb) {
494		DEBUG(2,("send_entry_request: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));
495		return;
496	}
497
498	for (kbuf = tdb_firstkey(tdb);
499	     kbuf.dptr;
500	     newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
501		fstring name_type;
502		pstring name, ip_str;
503		char *p;
504		int type = 0;
505		int nb_flags;
506		int ttl;
507		unsigned int num_ips;
508		int low, high;
509		SMB_BIG_UINT version;
510		struct in_addr wins_ip;
511		struct in_addr *ip_list;
512		int wins_flags;
513		int len;
514
515		if (strncmp(kbuf.dptr, ENTRY_PREFIX, strlen(ENTRY_PREFIX)) != 0)
516			continue;
517
518
519		dbuf = tdb_fetch(tdb, kbuf);
520		if (!dbuf.dptr)
521			continue;
522
523		fstrcpy(name_type, kbuf.dptr+strlen(ENTRY_PREFIX));
524		pstrcpy(name, name_type);
525
526		if((p = strchr(name,'#')) != NULL) {
527			*p = 0;
528			sscanf(p+1,"%x",&type);
529		}
530
531		len = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddfddd",
532				&nb_flags,
533				&high,
534				&low,
535				ip_str,
536				&ttl,
537				&num_ips,
538				&wins_flags);
539
540		wins_ip=*interpret_addr2(ip_str);
541
542 		/* Allocate the space for the ip_list. */
543		if((ip_list = (struct in_addr *)talloc(mem_ctx,  num_ips * sizeof(struct in_addr))) == NULL) {
544			SAFE_FREE(dbuf.dptr);
545			DEBUG(0,("initialise_wins: talloc fail !\n"));
546			return;
547		}
548
549		for (i = 0; i < num_ips; i++) {
550			len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", ip_str);
551			ip_list[i] = *interpret_addr2(ip_str);
552		}
553
554		SAFE_FREE(dbuf.dptr);
555
556		/* add all entries that have 60 seconds or more to live */
557		if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
558			if(ttl != PERMANENT_TTL)
559				ttl -= time_now;
560
561			DEBUG( 4, ("send_entry_request: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
562			    name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
563
564			/* add the record to the list to send */
565			version=((SMB_BIG_UINT)high)<<32 | low;
566
567			if (wins_owner->min_version<=version && wins_owner->max_version>=version &&
568			    wins_owner->address.s_addr==wins_ip.s_addr) {
569				if(!add_record_to_winsname(&r->rep.se_rp.wins_name, &max_names, name, type, wins_flags, version, ip_list, num_ips))
570					return;
571				max_names++;
572			}
573
574		} else {
575			DEBUG(4, ("send_entry_request: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n",
576				  name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
577		}
578	}
579
580	tdb_close(tdb);
581
582	DEBUG(4,("send_entry_request, sending %d records\n", max_names));
583	fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);
584	r->rep.msg_type=MESSAGE_REP_SEND_ENTRIES_REPLY; /* reply */
585	r->rep.se_rp.max_names=max_names;
586}
587
588
589/****************************************************************************
590.
591****************************************************************************/
592static void update_notify_request(GENERIC_PACKET *q, GENERIC_PACKET *r)
593{
594	int i,j,k,l;
595	UPDATE_NOTIFY_REQUEST *u;
596	int s_ctx=get_server_assoc(q->header.assoc_ctx);
597
598	if (s_ctx==0) {
599		DEBUG(4, ("update_notify_request: request for a partner not in our table\n"));
600		stop_packet(q, r, STOP_REASON_USER_REASON);
601		return;
602	}
603
604	u=&q->rep.un_rq;
605
606	/* check if we already have the range of records */
607
608	DEBUG(5,("update_notify_request: wins server: %s offered this list of %d records:\n",
609		inet_ntoa(u->initiating_wins_server), u->partner_count));
610
611	get_our_last_id(&global_wins_table[0][0]);
612
613	for (i=0; i<partner_count; i++) {
614		if (global_wins_table[0][i].address.s_addr==u->initiating_wins_server.s_addr) {
615			DEBUG(5,("update_notify_request: found initiator at index %d\n", i));
616			break;
617		}
618	}
619
620	/*
621	 * some explanation is required, before someone say it's crap.
622	 *
623	 * let's take an example, we have 2 wins partners, we already now
624	 * that our max id is 10, partner 1 ID is 20 and partner 2 ID is 30
625	 * the array looks like:
626	 *
627	 * 	0	1	2
628	 * 0	10	20	30
629	 * 1
630	 * 2
631	 *
632	 * we receive an update from partner 2 saying he has: 1:15, 2:40, 3:50
633	 * we must enlarge the array to add partner 3, it will look like:
634	 *
635	 * 	0	1	2	3
636	 * 0	10	20	30
637	 * 1
638	 * 2		15	40	50
639	 *
640	 * now we know, we should pull from partner 2, the records 30->40 of 2 and 0->50 of 3.
641	 * once the pull will be over, our table will look like:
642	 *
643	 * 	0	1	2	3
644	 * 0	10	20	40	50
645	 * 1
646	 * 2		15	40	50
647	 *
648	 *
649	 */
650
651	for (j=0; j<u->partner_count;j++) {
652		/*
653		 * search if we already have this entry or if it's a new one
654		 * it can be a new one in case of propagation
655		 */
656
657		for (k=0; global_wins_table[0][k].address.s_addr!=0 &&
658			  global_wins_table[0][k].address.s_addr!=u->wins_owner[j].address.s_addr; k++);
659
660		global_wins_table[i][k].address.s_addr=u->wins_owner[j].address.s_addr;
661		global_wins_table[i][k].max_version=u->wins_owner[j].max_version;
662		global_wins_table[i][k].min_version=u->wins_owner[j].min_version;
663		global_wins_table[i][k].type=u->wins_owner[j].type;
664
665		/*
666		 * in case it's a new one, rewrite the address for all the partner
667		 * to reserve the slot.
668		 */
669
670		for(l=0; l<partner_count; l++)
671			global_wins_table[l][k].address.s_addr=u->wins_owner[j].address.s_addr;
672	}
673
674	dump_global_table();
675
676	stop_packet(q, r, STOP_REASON_USER_REASON);
677}
678
679/****************************************************************************
680.
681****************************************************************************/
682static void send_entry_reply(GENERIC_PACKET *q, GENERIC_PACKET *r)
683{
684	int i,j,k;
685	struct in_addr partner, server;
686	pid_t pid;
687	int s_ctx=get_server_assoc(q->header.assoc_ctx);
688	WINS_RECORD record;
689
690	if (s_ctx==0) {
691		DEBUG(1, ("send_entry_reply: request for a partner not in our table\n"));
692		stop_packet(q, r, STOP_REASON_USER_REASON);
693		return;
694	}
695
696	DEBUG(5,("send_entry_reply:got %d new records\n", q->rep.se_rp.max_names));
697
698	/* we got records from a wins partner but that can be from another wins server */
699	/* hopefully we track that */
700
701	/* and the only doc available from MS is wrong ! */
702
703	get_server_assoc_table(q->header.assoc_ctx, &partner, &server);
704
705	for (j=0; global_wins_table[0][j].address.s_addr!=0; j++) {
706		if (global_wins_table[0][j].address.s_addr==server.s_addr) {
707			DEBUG(5,("send_entry_reply: found server at index %d\n", j));
708			break;
709		}
710	}
711
712	pid = pidfile_pid("nmbd");
713	if (pid == 0) {
714		DEBUG(0,("send_entry_reply: Can't find pid for nmbd\n"));
715		return;
716	}
717
718	for (k=0; k<q->rep.se_rp.max_names; k++) {
719		DEBUG(5,("send_entry_reply: %s<%02x> %d\n", q->rep.se_rp.wins_name[k].name, q->rep.se_rp.wins_name[k].type,
720		         (int)q->rep.se_rp.wins_name[k].id));
721
722		safe_strcpy(record.name, q->rep.se_rp.wins_name[k].name, 16);
723		record.type=q->rep.se_rp.wins_name[k].type;
724		record.id=q->rep.se_rp.wins_name[k].id;
725		record.wins_flags=q->rep.se_rp.wins_name[k].name_flag&0x00ff;
726		record.num_ips=q->rep.se_rp.wins_name[k].num_ip;
727
728		record.wins_ip.s_addr=server.s_addr;
729
730		if (record.num_ips==1)
731			record.ip[0]=q->rep.se_rp.wins_name[k].owner;
732		else
733			for (i=0; i<record.num_ips; i++)
734				record.ip[i]=q->rep.se_rp.wins_name[k].others[i];
735
736		record.nb_flags=0;
737
738		if (record.wins_flags&WINS_NGROUP || record.wins_flags&WINS_SGROUP)
739			record.nb_flags|=NB_GROUP;
740
741		if (record.wins_flags&WINS_ACTIVE)
742			record.nb_flags|=NB_ACTIVE;
743
744		record.nb_flags|=record.wins_flags&WINS_HNODE;
745
746		message_send_pid(pid, MSG_WINS_NEW_ENTRY, &record, sizeof(record), False);
747
748	}
749
750	dump_global_table();
751
752	/*
753	 * we got some entries,
754	 * ask the partner to send us the map table again
755	 * to get the other servers entries.
756	 *
757	 * we're getting the map table 1 time more than really
758	 * required. We could remove that call, but that
759	 * would complexify the code. I prefer this trade-of.
760	 */
761	fill_header(r, OPCODE_NON_NBT, s_ctx, MESSAGE_TYPE_REPLICATE);
762
763	r->rep.msg_type=MESSAGE_REP_ADD_VERSION_REQUEST;
764}
765
766/****************************************************************************
767decode the replication message and reply.
768****************************************************************************/
769static void replicate(GENERIC_PACKET *q, GENERIC_PACKET *r)
770{
771	switch (q->rep.msg_type) {
772		case 0:
773			/* add version number map table request */
774			send_version_number_map_table(q, r);
775			break;
776		case 1:
777			receive_version_number_map_table(q, r);
778			break;
779		case 2:
780			/* send entry request */
781			send_entry_request(q, r);
782			break;
783		case 3:
784			/* send entry reply */
785			send_entry_reply(q, r);
786			break;
787		case 4:
788			/* update notification request */
789			update_notify_request(q, r);
790			break;
791	}
792}
793
794/****************************************************************************
795do a switch on the message type, and return the response size
796****************************************************************************/
797static BOOL switch_message(GENERIC_PACKET *q, GENERIC_PACKET *r)
798{
799	switch (q->header.mess_type) {
800		case 0:
801			/* Start association type */
802			start_assoc_process(q, r);
803			return True;
804			break;
805		case 1:
806			/* start association reply */
807			start_assoc_reply(q, r);
808			return True;
809			break;
810		case 2:
811			/* stop association message */
812			return False;
813			break;
814		case 3:
815			/* replication message */
816			replicate(q, r);
817			return True;
818			break;
819	}
820
821	return False;
822}
823
824
825/****************************************************************************
826  construct a reply to the incoming packet
827****************************************************************************/
828void construct_reply(struct wins_packet_struct *p)
829{
830	GENERIC_PACKET r;
831	struct BUFFER buffer;
832
833	buffer.buffer=NULL;
834	buffer.offset=0;
835	buffer.length=0;
836
837	DEBUG(5,("dump: received packet\n"));
838	dump_generic_packet(p->packet);
839
840	/* Verify if the request we got is from a listed partner */
841	if (!check_partner(p->packet->header.assoc_ctx)) {
842		fstring peer;
843		struct in_addr addr;
844		int i;
845		fstrcpy(peer,get_peer_addr(p->fd));
846		addr=*interpret_addr2(peer);
847
848		for (i=1; i<partner_count; i++)
849			if (ip_equal(addr, global_wins_table[0][i].address))
850				break;
851
852		if (i==partner_count) {
853			DEBUG(1,("construct_reply: got a request from a non peer machine: %s\n", peer));
854			stop_packet(p->packet, &r, STOP_REASON_AUTH_FAILED);
855			p->stop_packet=True;
856			encode_generic_packet(&buffer, &r);
857			if (!send_smb(p->fd, buffer.buffer))
858				exit_server("process_smb: send_smb failed.");
859			return;
860		}
861	}
862
863	if (switch_message(p->packet, &r)) {
864		encode_generic_packet(&buffer, &r);
865		DEBUG(5,("dump: sending packet\n"));
866		dump_generic_packet(&r);
867
868		if(buffer.offset > 0) {
869			if (!send_smb(p->fd, buffer.buffer))
870				exit_server("process_smb: send_smb failed.");
871		}
872	}
873
874	/* if we got a stop assoc or if we send a stop assoc, close the fd after */
875	if (p->packet->header.mess_type==MESSAGE_TYPE_STOP_ASSOC ||
876	    r.header.mess_type==MESSAGE_TYPE_STOP_ASSOC) {
877	    	remove_partner(p->packet->header.assoc_ctx);
878		p->stop_packet=True;
879	}
880}
881
882/****************************************************************************
883  contact periodically our wins partner to do a pull replication
884****************************************************************************/
885void run_pull_replication(time_t t)
886{
887	/* we pull every 30 minutes to query about new records*/
888	int i, s;
889	struct BUFFER buffer;
890	GENERIC_PACKET p;
891
892	buffer.buffer=NULL;
893	buffer.offset=0;
894	buffer.length=0;
895
896	for (i=1; i<partner_count; i++) {
897		if (global_wins_table[0][i].last_pull < t) {
898			global_wins_table[0][i].last_pull=t+30*60; /* next in 30 minutes */
899
900			/* contact the wins server */
901			p.header.mess_type=MESSAGE_TYPE_START_ASSOC_REQUEST;
902			p.header.opcode=OPCODE_NON_NBT;
903			p.header.assoc_ctx=0;
904			p.sa_rq.assoc_ctx=(int)t;
905			p.sa_rq.min_ver=1;
906			p.sa_rq.maj_ver=1;
907
908			DEBUG(3,("run_pull_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
909			encode_generic_packet(&buffer, &p);
910			dump_generic_packet(&p);
911
912			/* send the packet to the server and add the descriptor to receive answers */
913			s=open_socket_out(SOCK_STREAM, &global_wins_table[0][i].address, 42, LONG_CONNECT_TIMEOUT);
914			if (s==-1) {
915				DEBUG(0,("run_pull_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
916				return;
917			}
918
919			if(buffer.offset > 0) {
920				if (!send_smb(s, buffer.buffer))
921					exit_server("run_pull_replication: send_smb failed.");
922			}
923
924			add_fd_to_sock_array(s);
925			FD_SET(s, listen_set);
926
927			/* add ourself as a client */
928			add_partner((int)t, 0, True, False);
929		}
930	}
931}
932
933/****************************************************************************
934  contact periodically our wins partner to do a push replication
935****************************************************************************/
936void run_push_replication(time_t t)
937{
938	/* we push every 30 minutes or 25 new entries */
939	int i, s;
940	struct BUFFER buffer;
941	GENERIC_PACKET p;
942
943	buffer.buffer=NULL;
944	buffer.offset=0;
945	buffer.length=0;
946
947	for (i=1; i<partner_count; i++) {
948		if (global_wins_table[0][i].last_pull < t) {
949			global_wins_table[0][i].last_pull=t+30*60; /* next in 30 minutes */
950
951			/* contact the wins server */
952			p.header.mess_type=MESSAGE_TYPE_START_ASSOC_REQUEST;
953			p.header.opcode=OPCODE_NON_NBT;
954			p.header.assoc_ctx=0;
955			p.sa_rq.assoc_ctx=(int)t;
956			p.sa_rq.min_ver=1;
957			p.sa_rq.maj_ver=1;
958
959			DEBUG(3,("run_push_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
960			encode_generic_packet(&buffer, &p);
961			dump_generic_packet(&p);
962
963			/* send the packet to the server and add the descriptor to receive answers */
964			s=open_socket_out(SOCK_STREAM, &global_wins_table[0][i].address, 42, LONG_CONNECT_TIMEOUT);
965			if (s==-1) {
966				DEBUG(0,("run_push_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
967				return;
968			}
969
970			if(buffer.offset > 0) {
971				if (!send_smb(s, buffer.buffer))
972					exit_server("run_push_replication: send_smb failed.");
973			}
974
975			add_fd_to_sock_array(s);
976			FD_SET(s, listen_set);
977
978			/* add ourself as a client */
979			add_partner((int)t, 0, False, True);
980		}
981	}
982}
983
984