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