2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7 Copyright (C) Jeremy Allison 1994-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 extern int DEBUGLEVEL
;
29 extern char **my_netbios_names
;
31 uint16 samba_nb_type
= 0; /* samba's NetBIOS name type */
34 /* ************************************************************************** **
35 * Set Samba's NetBIOS name type.
36 * ************************************************************************** **
38 void set_samba_nb_type(void)
40 if( lp_wins_support() || (*lp_wins_server()) )
41 samba_nb_type
= NB_MFLAG
; /* samba is a 'hybrid' node type. */
43 samba_nb_type
= NB_BFLAG
; /* samba is broadcast-only node type. */
44 } /* set_samba_nb_type */
46 /* ************************************************************************** **
47 * Convert a NetBIOS name to upper case.
48 * ************************************************************************** **
50 static void upcase_name( struct nmb_name
*target
, struct nmb_name
*source
)
55 (void)memcpy( target
, source
, sizeof( struct nmb_name
) );
57 strupper( target
->name
);
58 strupper( target
->scope
);
60 /* fudge... We're using a byte-by-byte compare, so we must be sure that
61 * unused space doesn't have garbage in it.
63 for( i
= strlen( target
->name
); i
< sizeof( target
->name
); i
++ )
64 target
->name
[i
] = '\0';
65 for( i
= strlen( target
->scope
); i
< sizeof( target
->scope
); i
++ )
66 target
->scope
[i
] = '\0';
69 /* ************************************************************************** **
70 * Add a new or overwrite an existing namelist entry.
71 * ************************************************************************** **
73 static void update_name_in_namelist( struct subnet_record
*subrec
,
74 struct name_record
*namerec
)
76 struct name_record
*oldrec
= NULL
;
78 (void)ubi_trInsert( subrec
->namelist
, namerec
, &(namerec
->name
), &oldrec
);
82 free( oldrec
->data
.ip
);
85 } /* update_name_in_namelist */
87 /* ************************************************************************** **
88 * Remove a name from the namelist.
89 * ************************************************************************** **
91 void remove_name_from_namelist( struct subnet_record
*subrec
,
92 struct name_record
*namerec
)
94 (void)ubi_trRemove( subrec
->namelist
, namerec
);
96 if(namerec
->data
.ip
!= NULL
)
97 free((char *)namerec
->data
.ip
);
99 ZERO_STRUCTP(namerec
);
100 free((char *)namerec
);
102 subrec
->namelist_changed
= True
;
103 } /* remove_name_from_namelist */
105 /* ************************************************************************** **
106 * Find a name in a subnet.
107 * ************************************************************************** **
109 struct name_record
*find_name_on_subnet( struct subnet_record
*subrec
,
110 struct nmb_name
*nmbname
,
113 struct nmb_name uc_name
[1];
114 struct name_record
*name_ret
;
116 upcase_name( uc_name
, nmbname
);
117 name_ret
= (struct name_record
*)ubi_trFind( subrec
->namelist
, uc_name
);
120 /* Self names only - these include permanent names. */
122 && (name_ret
->data
.source
!= SELF_NAME
)
123 && (name_ret
->data
.source
!= PERMANENT_NAME
) )
126 ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
127 subrec
->subnet_name
, nmb_namestr(nmbname
) ) );
130 DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
131 subrec
->subnet_name
, nmb_namestr(nmbname
), name_ret
->data
.source
) );
135 ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
136 subrec
->subnet_name
, nmb_namestr(nmbname
) ) );
138 } /* find_name_on_subnet */
140 /* ************************************************************************** **
141 * Find a name over all known broadcast subnets.
142 * ************************************************************************** **
144 struct name_record
*find_name_for_remote_broadcast_subnet(
145 struct nmb_name
*nmbname
,
148 struct subnet_record
*subrec
;
149 struct name_record
*namerec
= NULL
;
151 for( subrec
= FIRST_SUBNET
;
153 subrec
= NEXT_SUBNET_EXCLUDING_UNICAST(subrec
) )
155 if( NULL
!= (namerec
= find_name_on_subnet(subrec
, nmbname
, self_only
)) )
160 } /* find_name_for_remote_broadcast_subnet */
162 /* ************************************************************************** **
163 * Update the ttl of an entry in a subnet name list.
164 * ************************************************************************** **
166 void update_name_ttl( struct name_record
*namerec
, int ttl
)
168 time_t time_now
= time(NULL
);
170 if( namerec
->data
.death_time
!= PERMANENT_TTL
)
171 namerec
->data
.death_time
= time_now
+ ttl
;
173 namerec
->data
.refresh_time
= time_now
+ MIN((ttl
/2), MAX_REFRESH_TIME
);
175 namerec
->subnet
->namelist_changed
= True
;
176 } /* update_name_ttl */
178 /* ************************************************************************** **
179 * Add an entry to a subnet name list.
180 * ************************************************************************** **
182 struct name_record
*add_name_to_subnet( struct subnet_record
*subrec
,
187 enum name_source source
,
189 struct in_addr
*iplist
)
191 struct name_record
*namerec
;
192 time_t time_now
= time(NULL
);
194 namerec
= (struct name_record
*)malloc( sizeof(*namerec
) );
195 if( NULL
== namerec
)
197 DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
201 memset( (char *)namerec
, '\0', sizeof(*namerec
) );
202 namerec
->data
.ip
= (struct in_addr
*)malloc( sizeof(struct in_addr
)
204 if( NULL
== namerec
->data
.ip
)
206 DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
208 ZERO_STRUCTP(namerec
);
209 free( (char *)namerec
);
213 namerec
->subnet
= subrec
;
215 make_nmb_name( &namerec
->name
, name
, type
);
216 upcase_name( &namerec
->name
, NULL
);
218 /* Enter the name as active. */
219 namerec
->data
.nb_flags
= nb_flags
| NB_ACTIVE
;
221 /* If it's our primary name, flag it as so. */
222 if( strequal( my_netbios_names
[0], name
) )
223 namerec
->data
.nb_flags
|= NB_PERM
;
226 namerec
->data
.num_ips
= num_ips
;
227 memcpy( (namerec
->data
.ip
), iplist
, num_ips
* sizeof(struct in_addr
) );
230 namerec
->data
.source
= source
;
232 /* Setup the death_time and refresh_time. */
233 if( ttl
== PERMANENT_TTL
)
234 namerec
->data
.death_time
= PERMANENT_TTL
;
236 namerec
->data
.death_time
= time_now
+ ttl
;
238 namerec
->data
.refresh_time
= time_now
+ MIN((ttl
/2), MAX_REFRESH_TIME
);
240 /* Now add the record to the name list. */
241 update_name_in_namelist( subrec
, namerec
);
243 DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
244 ttl=%d nb_flags=%2x to subnet %s\n",
245 nmb_namestr( &namerec
->name
),
246 inet_ntoa( *iplist
),
248 (unsigned int)nb_flags
,
249 subrec
->subnet_name
) );
251 subrec
->namelist_changed
= True
;
256 /*******************************************************************
257 Utility function automatically called when a name refresh or register
258 succeeds. By definition this is a SELF_NAME (or we wouldn't be registering
260 ******************************************************************/
262 void standard_success_register(struct subnet_record
*subrec
,
263 struct userdata_struct
*userdata
,
264 struct nmb_name
*nmbname
, uint16 nb_flags
, int ttl
,
265 struct in_addr registered_ip
)
267 struct name_record
*namerec
;
269 namerec
= find_name_on_subnet( subrec
, nmbname
, FIND_SELF_NAME
);
270 if( NULL
== namerec
)
271 (void)add_name_to_subnet( subrec
, nmbname
->name
, nmbname
->name_type
,
272 nb_flags
, ttl
, SELF_NAME
, 1, ®istered_ip
);
274 update_name_ttl( namerec
, ttl
);
277 /*******************************************************************
278 Utility function automatically called when a name refresh or register
279 fails. Note that this is only ever called on a broadcast subnet with
280 one IP address per name. This is why it can just delete the name
281 without enumerating the IP adresses. JRA.
282 ******************************************************************/
284 void standard_fail_register( struct subnet_record
*subrec
,
285 struct response_record
*rrec
,
286 struct nmb_name
*nmbname
)
288 struct name_record
*namerec
;
290 namerec
= find_name_on_subnet( subrec
, nmbname
, FIND_SELF_NAME
);
292 DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
294 nmb_namestr(nmbname
), subrec
->subnet_name
) );
296 /* Remove the name from the subnet. */
298 remove_name_from_namelist(subrec
, namerec
);
301 /*******************************************************************
302 Utility function to remove an IP address from a name record.
303 ******************************************************************/
305 static void remove_nth_ip_in_record( struct name_record
*namerec
, int ind
)
307 if( ind
!= namerec
->data
.num_ips
)
308 memmove( (char *)(&namerec
->data
.ip
[ind
]),
309 (char *)(&namerec
->data
.ip
[ind
+1]),
310 ( namerec
->data
.num_ips
- ind
- 1) * sizeof(struct in_addr
) );
312 namerec
->data
.num_ips
--;
313 namerec
->subnet
->namelist_changed
= True
;
316 /*******************************************************************
317 Utility function to check if an IP address exists in a name record.
318 ******************************************************************/
320 BOOL
find_ip_in_name_record( struct name_record
*namerec
, struct in_addr ip
)
324 for(i
= 0; i
< namerec
->data
.num_ips
; i
++)
325 if(ip_equal( namerec
->data
.ip
[i
], ip
))
331 /*******************************************************************
332 Utility function to add an IP address to a name record.
333 ******************************************************************/
335 void add_ip_to_name_record( struct name_record
*namerec
, struct in_addr new_ip
)
337 struct in_addr
*new_list
;
339 /* Don't add one we already have. */
340 if( find_ip_in_name_record( namerec
, new_ip
) )
343 new_list
= (struct in_addr
*)malloc( (namerec
->data
.num_ips
+ 1)
344 * sizeof(struct in_addr
) );
345 if( NULL
== new_list
)
347 DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
351 memcpy( (char *)new_list
,
352 (char *)namerec
->data
.ip
,
353 namerec
->data
.num_ips
* sizeof(struct in_addr
) );
354 new_list
[namerec
->data
.num_ips
] = new_ip
;
356 free((char *)namerec
->data
.ip
);
357 namerec
->data
.ip
= new_list
;
358 namerec
->data
.num_ips
+= 1;
360 namerec
->subnet
->namelist_changed
= True
;
363 /*******************************************************************
364 Utility function to remove an IP address from a name record.
365 ******************************************************************/
367 void remove_ip_from_name_record( struct name_record
*namerec
,
368 struct in_addr remove_ip
)
370 /* Try and find the requested ip address - remove it. */
372 int orig_num
= namerec
->data
.num_ips
;
374 for(i
= 0; i
< orig_num
; i
++)
375 if( ip_equal( remove_ip
, namerec
->data
.ip
[i
]) )
377 remove_nth_ip_in_record( namerec
, i
);
382 /*******************************************************************
383 Utility function that release_name callers can plug into as the
384 success function when a name release is successful. Used to save
385 duplication of success_function code.
386 ******************************************************************/
388 void standard_success_release( struct subnet_record
*subrec
,
389 struct userdata_struct
*userdata
,
390 struct nmb_name
*nmbname
,
391 struct in_addr released_ip
)
393 struct name_record
*namerec
;
395 namerec
= find_name_on_subnet( subrec
, nmbname
, FIND_ANY_NAME
);
397 if( namerec
== NULL
)
399 DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
400 on subnet %s. Name was not found on subnet.\n",
401 nmb_namestr(nmbname
),
402 inet_ntoa(released_ip
),
403 subrec
->subnet_name
) );
408 int orig_num
= namerec
->data
.num_ips
;
410 remove_ip_from_name_record( namerec
, released_ip
);
412 if( namerec
->data
.num_ips
== orig_num
)
413 DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
414 on subnet %s. This ip is not known for this name.\n",
415 nmb_namestr(nmbname
),
416 inet_ntoa(released_ip
),
417 subrec
->subnet_name
) );
420 if( namerec
->data
.num_ips
== 0 )
421 remove_name_from_namelist( subrec
, namerec
);
424 /*******************************************************************
425 Expires old names in a subnet namelist.
426 ******************************************************************/
428 void expire_names_on_subnet(struct subnet_record
*subrec
, time_t t
)
430 struct name_record
*namerec
;
431 struct name_record
*next_namerec
;
433 for( namerec
= (struct name_record
*)ubi_trFirst( subrec
->namelist
);
435 namerec
= next_namerec
)
437 next_namerec
= (struct name_record
*)ubi_trNext( namerec
);
438 if( (namerec
->data
.death_time
!= PERMANENT_TTL
)
439 && (namerec
->data
.death_time
< t
) )
441 if( namerec
->data
.source
== SELF_NAME
)
443 DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
445 subrec
->subnet_name
, nmb_namestr(&namerec
->name
) ) );
446 namerec
->data
.death_time
+= 300;
447 namerec
->subnet
->namelist_changed
= True
;
450 DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
451 subrec
->subnet_name
, nmb_namestr(&namerec
->name
)));
453 remove_name_from_namelist( subrec
, namerec
);
458 /*******************************************************************
459 Expires old names in all subnet namelists.
460 ******************************************************************/
462 void expire_names(time_t t
)
464 struct subnet_record
*subrec
;
466 for( subrec
= FIRST_SUBNET
;
468 subrec
= NEXT_SUBNET_INCLUDING_UNICAST(subrec
) )
470 expire_names_on_subnet( subrec
, t
);
474 /****************************************************************************
475 Add the magic samba names, useful for finding samba servers.
476 These go directly into the name list for a particular subnet,
477 without going through the normal registration process.
478 When adding them to the unicast subnet, add them as a list of
479 all broadcast subnet IP addresses.
480 **************************************************************************/
482 void add_samba_names_to_subnet( struct subnet_record
*subrec
)
484 struct in_addr
*iplist
= &subrec
->myip
;
487 /* These names are added permanently (ttl of zero) and will NOT be
490 if( (subrec
== unicast_subnet
)
491 || (subrec
== wins_server_subnet
)
492 || (subrec
== remote_broadcast_subnet
) )
494 struct subnet_record
*bcast_subrecs
;
496 /* Create an IP list containing all our known subnets. */
498 num_ips
= iface_count();
499 iplist
= (struct in_addr
*)malloc( num_ips
* sizeof(struct in_addr
) );
502 DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
506 for( bcast_subrecs
= FIRST_SUBNET
, i
= 0;
508 bcast_subrecs
= NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs
), i
++ )
509 iplist
[i
] = bcast_subrecs
->myip
;
513 (void)add_name_to_subnet(subrec
,"*",0x0,samba_nb_type
, PERMANENT_TTL
,
514 PERMANENT_NAME
, num_ips
, iplist
);
515 (void)add_name_to_subnet(subrec
,"*",0x20,samba_nb_type
,PERMANENT_TTL
,
516 PERMANENT_NAME
, num_ips
, iplist
);
517 (void)add_name_to_subnet(subrec
,"__SAMBA__",0x20,samba_nb_type
,PERMANENT_TTL
,
518 PERMANENT_NAME
, num_ips
, iplist
);
519 (void)add_name_to_subnet(subrec
,"__SAMBA__",0x00,samba_nb_type
,PERMANENT_TTL
,
520 PERMANENT_NAME
, num_ips
, iplist
);
522 if(iplist
!= &subrec
->myip
)
523 free((char *)iplist
);
526 /****************************************************************************
527 Dump the contents of the namelists on all the subnets (including unicast)
528 into a file. Initiated by SIGHUP - used to debug the state of the namelists.
529 **************************************************************************/
531 static void dump_subnet_namelist( struct subnet_record
*subrec
, FILE *fp
)
533 struct name_record
*namerec
;
538 fprintf(fp
, "Subnet %s\n----------------------\n", subrec
->subnet_name
);
539 for( namerec
= (struct name_record
*)ubi_trFirst( subrec
->namelist
);
541 namerec
= (struct name_record
*)ubi_trNext( namerec
) )
543 fprintf(fp
,"\tName = %s\t", nmb_namestr(&namerec
->name
));
544 switch(namerec
->data
.source
)
547 src_type
= "LMHOSTS_NAME";
549 case WINS_PROXY_NAME
:
550 src_type
= "WINS_PROXY_NAME";
553 src_type
= "REGISTER_NAME";
556 src_type
= "SELF_NAME";
559 src_type
= "DNS_NAME";
562 src_type
= "DNSFAIL_NAME";
565 src_type
= "PERMANENT_NAME";
568 src_type
= "unknown!";
571 fprintf(fp
,"Source = %s\nb_flags = %x\t", src_type
, namerec
->data
.nb_flags
);
573 if(namerec
->data
.death_time
!= PERMANENT_TTL
)
575 tm
= LocalTime(&namerec
->data
.death_time
);
576 fprintf(fp
, "death_time = %s\t", asctime(tm
));
579 fprintf(fp
, "death_time = PERMANENT\t");
581 if(namerec
->data
.refresh_time
!= PERMANENT_TTL
)
583 tm
= LocalTime(&namerec
->data
.refresh_time
);
584 fprintf(fp
, "refresh_time = %s\n", asctime(tm
));
587 fprintf(fp
, "refresh_time = PERMANENT\n");
589 fprintf(fp
, "\t\tnumber of IPS = %d", namerec
->data
.num_ips
);
590 for(i
= 0; i
< namerec
->data
.num_ips
; i
++)
591 fprintf(fp
, "\t%s", inet_ntoa(namerec
->data
.ip
[i
]));
597 /****************************************************************************
598 Dump the contents of the namelists on all the subnets (including unicast)
599 into a file. Initiated by SIGHUP - used to debug the state of the namelists.
600 **************************************************************************/
602 void dump_all_namelists(void)
606 struct subnet_record
*subrec
;
608 pstrcpy(fname
,lp_lockdir());
609 trim_string(fname
,NULL
,"/");
611 pstrcat(fname
,"namelist.debug");
613 fp
= sys_fopen(fname
,"w");
617 DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
618 fname
,strerror(errno
)));
622 for( subrec
= FIRST_SUBNET
;
624 subrec
= NEXT_SUBNET_INCLUDING_UNICAST(subrec
) )
625 dump_subnet_namelist( subrec
, fp
);
627 if( !we_are_a_wins_client() )
628 dump_subnet_namelist( unicast_subnet
, fp
);
630 if( remote_broadcast_subnet
->namelist
!= NULL
)
631 dump_subnet_namelist( remote_broadcast_subnet
, fp
);
633 if( wins_server_subnet
!= NULL
)
634 dump_subnet_namelist( wins_server_subnet
, fp
);