1/* 2 Unix SMB/CIFS implementation. 3 NBT netbios routines and daemon - version 2 4 Copyright (C) Andrew Tridgell 1994-1998 5 Copyright (C) Luke Kenneth Casson Leighton 1994-1998 6 Copyright (C) Jeremy Allison 1994-2003 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22*/ 23 24#include "includes.h" 25 26uint16 samba_nb_type = 0; /* samba's NetBIOS name type */ 27 28 29/************************************************************************** 30 Set Samba's NetBIOS name type. 31***************************************************************************/ 32 33void set_samba_nb_type(void) 34{ 35 if( lp_wins_support() || wins_srv_count() ) 36 samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */ 37 else 38 samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */ 39} 40 41/*************************************************************************** 42 Convert a NetBIOS name to upper case. 43***************************************************************************/ 44 45static void upcase_name( struct nmb_name *target, struct nmb_name *source ) 46{ 47 int i; 48 unstring targ; 49 fstring scope; 50 51 if( NULL != source ) 52 memcpy( target, source, sizeof( struct nmb_name ) ); 53 54 pull_ascii_nstring(targ, sizeof(targ), target->name); 55 strupper_m( targ ); 56 push_ascii_nstring( target->name, targ); 57 58 pull_ascii(scope, target->scope, 64, -1, STR_TERMINATE); 59 strupper_m( scope ); 60 push_ascii(target->scope, scope, 64, STR_TERMINATE); 61 62 /* fudge... We're using a byte-by-byte compare, so we must be sure that 63 * unused space doesn't have garbage in it. 64 */ 65 66 for( i = strlen( target->name ); i < sizeof( target->name ); i++ ) 67 target->name[i] = '\0'; 68 for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ ) 69 target->scope[i] = '\0'; 70} 71 72/************************************************************************** 73 Add a new or overwrite an existing namelist entry. 74***************************************************************************/ 75 76static void update_name_in_namelist( struct subnet_record *subrec, 77 struct name_record *namerec ) 78{ 79 struct name_record *oldrec = NULL; 80 81 ubi_trInsert( subrec->namelist, namerec, &(namerec->name), &oldrec ); 82 if( oldrec ) { 83 SAFE_FREE( oldrec->data.ip ); 84 SAFE_FREE( oldrec ); 85 } 86} 87 88/************************************************************************** 89 Remove a name from the namelist. 90***************************************************************************/ 91 92void remove_name_from_namelist( struct subnet_record *subrec, 93 struct name_record *namerec ) 94{ 95 ubi_trRemove( subrec->namelist, namerec ); 96 SAFE_FREE(namerec->data.ip); 97 ZERO_STRUCTP(namerec); 98 SAFE_FREE(namerec); 99 subrec->namelist_changed = True; 100} 101 102/************************************************************************** 103 Find a name in a subnet. 104**************************************************************************/ 105 106struct name_record *find_name_on_subnet( struct subnet_record *subrec, 107 struct nmb_name *nmbname, 108 BOOL self_only ) 109{ 110 struct nmb_name uc_name[1]; 111 struct name_record *name_ret; 112 113 upcase_name( uc_name, nmbname ); 114 name_ret = (struct name_record *)ubi_trFind( subrec->namelist, uc_name ); 115 if( name_ret ) { 116 /* Self names only - these include permanent names. */ 117 if( self_only && (name_ret->data.source != SELF_NAME) && (name_ret->data.source != PERMANENT_NAME) ) { 118 DEBUG( 9, ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n", 119 subrec->subnet_name, nmb_namestr(nmbname) ) ); 120 return( NULL ); 121 } 122 123 DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n", 124 subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) ); 125 return( name_ret ); 126 } 127 128 DEBUG( 9, ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n", 129 subrec->subnet_name, nmb_namestr(nmbname) ) ); 130 return( NULL ); 131} 132 133/************************************************************************** 134 Find a name over all known broadcast subnets. 135************************************************************************/ 136 137struct name_record *find_name_for_remote_broadcast_subnet( 138 struct nmb_name *nmbname, 139 BOOL self_only ) 140{ 141 struct subnet_record *subrec; 142 struct name_record *namerec = NULL; 143 144 for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) { 145 if( NULL != (namerec = find_name_on_subnet(subrec, nmbname, self_only)) ) 146 break; 147 } 148 149 return( namerec ); 150} 151 152/************************************************************************** 153 Update the ttl of an entry in a subnet name list. 154***************************************************************************/ 155 156void update_name_ttl( struct name_record *namerec, int ttl ) 157{ 158 time_t time_now = time(NULL); 159 160 if( namerec->data.death_time != PERMANENT_TTL ) 161 namerec->data.death_time = time_now + ttl; 162 163 namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME); 164 165 namerec->subnet->namelist_changed = True; 166} 167 168/************************************************************************** 169 Add an entry to a subnet name list. 170***********************************************************************/ 171 172struct name_record *add_name_to_subnet( struct subnet_record *subrec, 173 const char *name, 174 int type, 175 uint16 nb_flags, 176 int ttl, 177 enum name_source source, 178 int num_ips, 179 struct in_addr *iplist) 180{ 181 struct name_record *namerec; 182 time_t time_now = time(NULL); 183 184 namerec = SMB_MALLOC_P(struct name_record); 185 if( NULL == namerec ) { 186 DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) ); 187 return( NULL ); 188 } 189 190 memset( (char *)namerec, '\0', sizeof(*namerec) ); 191 namerec->data.ip = SMB_MALLOC_ARRAY( struct in_addr, num_ips ); 192 if( NULL == namerec->data.ip ) { 193 DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) ); 194 ZERO_STRUCTP(namerec); 195 SAFE_FREE(namerec); 196 return NULL; 197 } 198 199 namerec->subnet = subrec; 200 201 make_nmb_name(&namerec->name, name, type); 202 upcase_name(&namerec->name, NULL ); 203 204 /* Enter the name as active. */ 205 namerec->data.nb_flags = nb_flags | NB_ACTIVE; 206 namerec->data.wins_flags = WINS_ACTIVE; 207 208 /* If it's our primary name, flag it as so. */ 209 if( strequal( my_netbios_names(0), name ) ) 210 namerec->data.nb_flags |= NB_PERM; 211 212 /* Copy the IPs. */ 213 namerec->data.num_ips = num_ips; 214 memcpy( (namerec->data.ip), iplist, num_ips * sizeof(struct in_addr) ); 215 216 /* Data source. */ 217 namerec->data.source = source; 218 219 /* Setup the death_time and refresh_time. */ 220 if( ttl == PERMANENT_TTL ) 221 namerec->data.death_time = PERMANENT_TTL; 222 else 223 namerec->data.death_time = time_now + ttl; 224 225 namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME); 226 227 /* Now add the record to the name list. */ 228 update_name_in_namelist( subrec, namerec ); 229 230 DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \ 231ttl=%d nb_flags=%2x to subnet %s\n", 232 nmb_namestr( &namerec->name ), 233 inet_ntoa( *iplist ), 234 ttl, 235 (unsigned int)nb_flags, 236 subrec->subnet_name ) ); 237 238 subrec->namelist_changed = True; 239 240 return(namerec); 241} 242 243/******************************************************************* 244 Utility function automatically called when a name refresh or register 245 succeeds. By definition this is a SELF_NAME (or we wouldn't be registering 246 it). 247 ******************************************************************/ 248 249void standard_success_register(struct subnet_record *subrec, 250 struct userdata_struct *userdata, 251 struct nmb_name *nmbname, uint16 nb_flags, int ttl, 252 struct in_addr registered_ip) 253{ 254 struct name_record *namerec; 255 256 namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME ); 257 if( NULL == namerec ) { 258 unstring name; 259 pull_ascii_nstring(name, sizeof(name), nmbname->name); 260 add_name_to_subnet( subrec, name, nmbname->name_type, 261 nb_flags, ttl, SELF_NAME, 1, ®istered_ip ); 262 } else { 263 update_name_ttl( namerec, ttl ); 264 } 265} 266 267/******************************************************************* 268 Utility function automatically called when a name refresh or register 269 fails. Note that this is only ever called on a broadcast subnet with 270 one IP address per name. This is why it can just delete the name 271 without enumerating the IP adresses. JRA. 272 ******************************************************************/ 273 274void standard_fail_register( struct subnet_record *subrec, 275 struct response_record *rrec, 276 struct nmb_name *nmbname ) 277{ 278 struct name_record *namerec; 279 280 namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME ); 281 282 DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \ 283on subnet %s\n", nmb_namestr(nmbname), subrec->subnet_name) ); 284 285 /* Remove the name from the subnet. */ 286 if( namerec ) 287 remove_name_from_namelist(subrec, namerec); 288} 289 290/******************************************************************* 291 Utility function to remove an IP address from a name record. 292 ******************************************************************/ 293 294static void remove_nth_ip_in_record( struct name_record *namerec, int ind) 295{ 296 if( ind != namerec->data.num_ips ) 297 memmove( (char *)(&namerec->data.ip[ind]), 298 (char *)(&namerec->data.ip[ind+1]), 299 ( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) ); 300 301 namerec->data.num_ips--; 302 namerec->subnet->namelist_changed = True; 303} 304 305/******************************************************************* 306 Utility function to check if an IP address exists in a name record. 307 ******************************************************************/ 308 309BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip ) 310{ 311 int i; 312 313 for(i = 0; i < namerec->data.num_ips; i++) 314 if(ip_equal( namerec->data.ip[i], ip)) 315 return True; 316 317 return False; 318} 319 320/******************************************************************* 321 Utility function to add an IP address to a name record. 322 ******************************************************************/ 323 324void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip ) 325{ 326 struct in_addr *new_list; 327 328 /* Don't add one we already have. */ 329 if( find_ip_in_name_record( namerec, new_ip ) ) 330 return; 331 332 new_list = SMB_MALLOC_ARRAY( struct in_addr, namerec->data.num_ips + 1); 333 if( NULL == new_list ) { 334 DEBUG(0,("add_ip_to_name_record: Malloc fail !\n")); 335 return; 336 } 337 338 memcpy( (char *)new_list, (char *)namerec->data.ip, namerec->data.num_ips * sizeof(struct in_addr) ); 339 new_list[namerec->data.num_ips] = new_ip; 340 341 SAFE_FREE(namerec->data.ip); 342 namerec->data.ip = new_list; 343 namerec->data.num_ips += 1; 344 345 namerec->subnet->namelist_changed = True; 346} 347 348/******************************************************************* 349 Utility function to remove an IP address from a name record. 350 ******************************************************************/ 351 352void remove_ip_from_name_record( struct name_record *namerec, 353 struct in_addr remove_ip ) 354{ 355 /* Try and find the requested ip address - remove it. */ 356 int i; 357 int orig_num = namerec->data.num_ips; 358 359 for(i = 0; i < orig_num; i++) { 360 if( ip_equal( remove_ip, namerec->data.ip[i]) ) { 361 remove_nth_ip_in_record( namerec, i); 362 break; 363 } 364 } 365} 366 367/******************************************************************* 368 Utility function that release_name callers can plug into as the 369 success function when a name release is successful. Used to save 370 duplication of success_function code. 371 ******************************************************************/ 372 373void standard_success_release( struct subnet_record *subrec, 374 struct userdata_struct *userdata, 375 struct nmb_name *nmbname, 376 struct in_addr released_ip ) 377{ 378 struct name_record *namerec; 379 380 namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME ); 381 if( namerec == NULL ) { 382 DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \ 383on subnet %s. Name was not found on subnet.\n", nmb_namestr(nmbname), inet_ntoa(released_ip), 384 subrec->subnet_name) ); 385 return; 386 } else { 387 int orig_num = namerec->data.num_ips; 388 389 remove_ip_from_name_record( namerec, released_ip ); 390 391 if( namerec->data.num_ips == orig_num ) 392 DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \ 393on subnet %s. This ip is not known for this name.\n", nmb_namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name ) ); 394 } 395 396 if( namerec->data.num_ips == 0 ) 397 remove_name_from_namelist( subrec, namerec ); 398} 399 400/******************************************************************* 401 Expires old names in a subnet namelist. 402******************************************************************/ 403 404void expire_names_on_subnet(struct subnet_record *subrec, time_t t) 405{ 406 struct name_record *namerec; 407 struct name_record *next_namerec; 408 409 for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); namerec; namerec = next_namerec ) { 410 next_namerec = (struct name_record *)ubi_trNext( namerec ); 411 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) { 412 if( namerec->data.source == SELF_NAME ) { 413 DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \ 414name %s\n", subrec->subnet_name, nmb_namestr(&namerec->name) ) ); 415 namerec->data.death_time += 300; 416 namerec->subnet->namelist_changed = True; 417 continue; 418 } 419 420 DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n", 421 subrec->subnet_name, nmb_namestr(&namerec->name))); 422 423 remove_name_from_namelist( subrec, namerec ); 424 } 425 } 426} 427 428/******************************************************************* 429 Expires old names in all subnet namelists. 430******************************************************************/ 431 432void expire_names(time_t t) 433{ 434 struct subnet_record *subrec; 435 436 for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) ) { 437 expire_names_on_subnet( subrec, t ); 438 } 439} 440 441/**************************************************************************** 442 Add the magic samba names, useful for finding samba servers. 443 These go directly into the name list for a particular subnet, 444 without going through the normal registration process. 445 When adding them to the unicast subnet, add them as a list of 446 all broadcast subnet IP addresses. 447**************************************************************************/ 448 449void add_samba_names_to_subnet( struct subnet_record *subrec ) 450{ 451 struct in_addr *iplist = &subrec->myip; 452 int num_ips = 1; 453 454 /* These names are added permanently (ttl of zero) and will NOT be refreshed. */ 455 456 if( (subrec == unicast_subnet) || (subrec == wins_server_subnet) || (subrec == remote_broadcast_subnet) ) { 457 struct subnet_record *bcast_subrecs; 458 int i; 459 460 /* Create an IP list containing all our known subnets. */ 461 462 num_ips = iface_count(); 463 iplist = SMB_MALLOC_ARRAY( struct in_addr, num_ips); 464 if( NULL == iplist ) { 465 DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n")); 466 return; 467 } 468 469 for( bcast_subrecs = FIRST_SUBNET, i = 0; bcast_subrecs; bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ ) 470 iplist[i] = bcast_subrecs->myip; 471 } 472 473 add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL, 474 PERMANENT_NAME, num_ips, iplist); 475 add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL, 476 PERMANENT_NAME, num_ips, iplist); 477 add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL, 478 PERMANENT_NAME, num_ips, iplist); 479 add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL, 480 PERMANENT_NAME, num_ips, iplist); 481 482 if(iplist != &subrec->myip) 483 SAFE_FREE(iplist); 484} 485 486/**************************************************************************** 487 Dump the contents of the namelists on all the subnets (including unicast) 488 into a file. Initiated by SIGHUP - used to debug the state of the namelists. 489**************************************************************************/ 490 491static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp) 492{ 493 struct name_record *namerec; 494 const char *src_type; 495 struct tm *tm; 496 int i; 497 498 x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name); 499 for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); namerec; 500 namerec = (struct name_record *)ubi_trNext( namerec ) ) { 501 502 x_fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name)); 503 switch(namerec->data.source) { 504 case LMHOSTS_NAME: 505 src_type = "LMHOSTS_NAME"; 506 break; 507 case WINS_PROXY_NAME: 508 src_type = "WINS_PROXY_NAME"; 509 break; 510 case REGISTER_NAME: 511 src_type = "REGISTER_NAME"; 512 break; 513 case SELF_NAME: 514 src_type = "SELF_NAME"; 515 break; 516 case DNS_NAME: 517 src_type = "DNS_NAME"; 518 break; 519 case DNSFAIL_NAME: 520 src_type = "DNSFAIL_NAME"; 521 break; 522 case PERMANENT_NAME: 523 src_type = "PERMANENT_NAME"; 524 break; 525 default: 526 src_type = "unknown!"; 527 break; 528 } 529 530 x_fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags); 531 532 if(namerec->data.death_time != PERMANENT_TTL) { 533 tm = LocalTime(&namerec->data.death_time); 534 x_fprintf(fp, "death_time = %s\t", asctime(tm)); 535 } else { 536 x_fprintf(fp, "death_time = PERMANENT\t"); 537 } 538 539 if(namerec->data.refresh_time != PERMANENT_TTL) { 540 tm = LocalTime(&namerec->data.refresh_time); 541 x_fprintf(fp, "refresh_time = %s\n", asctime(tm)); 542 } else { 543 x_fprintf(fp, "refresh_time = PERMANENT\n"); 544 } 545 546 x_fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips); 547 for(i = 0; i < namerec->data.num_ips; i++) 548 x_fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i])); 549 550 x_fprintf(fp, "\n\n"); 551 } 552} 553 554/**************************************************************************** 555 Dump the contents of the namelists on all the subnets (including unicast) 556 into a file. Initiated by SIGHUP - used to debug the state of the namelists. 557**************************************************************************/ 558 559void dump_all_namelists(void) 560{ 561 XFILE *fp; 562 struct subnet_record *subrec; 563 564 fp = x_fopen(lock_path("namelist.debug"),O_WRONLY|O_CREAT|O_TRUNC, 0644); 565 566 if (!fp) { 567 DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n", 568 "namelist.debug",strerror(errno))); 569 return; 570 } 571 572 for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) ) 573 dump_subnet_namelist( subrec, fp ); 574 575 if( !we_are_a_wins_client() ) 576 dump_subnet_namelist( unicast_subnet, fp ); 577 578 if( remote_broadcast_subnet->namelist != NULL ) 579 dump_subnet_namelist( remote_broadcast_subnet, fp ); 580 581 if( wins_server_subnet != NULL ) 582 dump_subnet_namelist( wins_server_subnet, fp ); 583 x_fclose( fp ); 584} 585