Line data Source code
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 3 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, see <http://www.gnu.org/licenses/>.
20 :
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include "nmbd/nmbd.h"
26 :
27 : uint16_t samba_nb_type = 0; /* samba's NetBIOS name type */
28 :
29 :
30 : /**************************************************************************
31 : Set Samba's NetBIOS name type.
32 : ***************************************************************************/
33 :
34 43 : void set_samba_nb_type(void)
35 : {
36 43 : if( lp_we_are_a_wins_server() || wins_srv_count() ) {
37 0 : samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */
38 : } else {
39 43 : samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */
40 : }
41 43 : }
42 :
43 : /***************************************************************************
44 : Convert a NetBIOS name to upper case.
45 : ***************************************************************************/
46 :
47 12385 : static bool upcase_name( struct nmb_name *target, const struct nmb_name *source )
48 : {
49 : int i;
50 : unstring targ;
51 : fstring scope;
52 :
53 12385 : if( NULL != source ) {
54 11245 : memcpy( target, source, sizeof( struct nmb_name ) );
55 : }
56 :
57 12385 : pull_ascii_nstring(targ, sizeof(targ), target->name);
58 12385 : if (!strupper_m( targ )) {
59 0 : return false;
60 : }
61 12385 : push_ascii_nstring( target->name, targ);
62 :
63 12385 : pull_ascii(scope, target->scope, 64, -1, STR_TERMINATE);
64 12385 : if (!strupper_m( scope )) {
65 0 : return false;
66 : }
67 12385 : push_ascii(target->scope, scope, 64, STR_TERMINATE);
68 :
69 : /* fudge... We're using a byte-by-byte compare, so we must be sure that
70 : * unused space doesn't have garbage in it.
71 : */
72 :
73 87557 : for( i = strlen( target->name ); i < sizeof( target->name ); i++ ) {
74 75172 : target->name[i] = '\0';
75 : }
76 805025 : for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ ) {
77 792640 : target->scope[i] = '\0';
78 : }
79 12385 : return true;
80 : }
81 :
82 : /**************************************************************************
83 : Remove a name from the namelist.
84 : ***************************************************************************/
85 :
86 8 : void remove_name_from_namelist(struct subnet_record *subrec,
87 : struct name_record *namerec )
88 : {
89 8 : if (subrec == wins_server_subnet)
90 0 : remove_name_from_wins_namelist(namerec);
91 : else {
92 8 : subrec->namelist_changed = True;
93 8 : DLIST_REMOVE(subrec->namelist, namerec);
94 : }
95 :
96 8 : SAFE_FREE(namerec->data.ip);
97 8 : ZERO_STRUCTP(namerec);
98 8 : SAFE_FREE(namerec);
99 8 : }
100 :
101 : /**************************************************************************
102 : Find a name in a subnet.
103 : **************************************************************************/
104 :
105 11245 : struct name_record *find_name_on_subnet(struct subnet_record *subrec,
106 : const struct nmb_name *nmbname,
107 : bool self_only)
108 : {
109 : struct nmb_name uc_name;
110 : struct name_record *name_ret;
111 :
112 11245 : if (!upcase_name( &uc_name, nmbname )) {
113 0 : return NULL;
114 : }
115 :
116 11245 : if (subrec == wins_server_subnet) {
117 0 : return find_name_on_wins_subnet(&uc_name, self_only);
118 : }
119 :
120 108921 : for( name_ret = subrec->namelist; name_ret; name_ret = name_ret->next) {
121 99689 : if (memcmp(&uc_name, &name_ret->name, sizeof(struct nmb_name)) == 0) {
122 2013 : break;
123 : }
124 : }
125 :
126 11245 : if( name_ret ) {
127 : /* Self names only - these include permanent names. */
128 2013 : if( self_only && (name_ret->data.source != SELF_NAME) && (name_ret->data.source != PERMANENT_NAME) ) {
129 0 : DEBUG( 9, ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
130 : subrec->subnet_name, nmb_namestr(nmbname) ) );
131 0 : return NULL;
132 : }
133 :
134 2013 : DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
135 : subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) );
136 :
137 2013 : return name_ret;
138 : }
139 :
140 9232 : DEBUG( 9, ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
141 : subrec->subnet_name, nmb_namestr(nmbname) ) );
142 :
143 9232 : return NULL;
144 : }
145 :
146 : /**************************************************************************
147 : Find a name over all known broadcast subnets.
148 : ************************************************************************/
149 :
150 0 : struct name_record *find_name_for_remote_broadcast_subnet(struct nmb_name *nmbname,
151 : bool self_only)
152 : {
153 : struct subnet_record *subrec;
154 : struct name_record *namerec;
155 :
156 0 : for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) {
157 0 : namerec = find_name_on_subnet(subrec, nmbname, self_only);
158 0 : if (namerec) {
159 0 : return namerec;
160 : }
161 : }
162 :
163 0 : return NULL;
164 : }
165 :
166 : /**************************************************************************
167 : Update the ttl of an entry in a subnet name list.
168 : ***************************************************************************/
169 :
170 0 : void update_name_ttl( struct name_record *namerec, int ttl )
171 : {
172 0 : time_t time_now = time(NULL);
173 :
174 0 : if( namerec->data.death_time != PERMANENT_TTL) {
175 0 : namerec->data.death_time = time_now + ttl;
176 : }
177 :
178 0 : namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
179 :
180 0 : if (namerec->subnet == wins_server_subnet) {
181 0 : wins_store_changed_namerec(namerec);
182 : } else {
183 0 : namerec->subnet->namelist_changed = True;
184 : }
185 0 : }
186 :
187 : /**************************************************************************
188 : Add an entry to a subnet name list.
189 : ***********************************************************************/
190 :
191 1140 : bool add_name_to_subnet( struct subnet_record *subrec,
192 : const char *name,
193 : int type,
194 : uint16_t nb_flags,
195 : int ttl,
196 : enum name_source source,
197 : int num_ips,
198 : struct in_addr *iplist)
199 : {
200 1140 : bool ret = False;
201 : struct name_record *namerec;
202 1140 : time_t time_now = time(NULL);
203 :
204 1140 : if (num_ips == 0) {
205 0 : return false;
206 : }
207 :
208 1140 : namerec = SMB_MALLOC_P(struct name_record);
209 1140 : if( NULL == namerec ) {
210 0 : DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
211 0 : return False;
212 : }
213 :
214 1140 : memset( (char *)namerec, '\0', sizeof(*namerec) );
215 1140 : namerec->data.ip = SMB_MALLOC_ARRAY( struct in_addr, num_ips );
216 1140 : if( NULL == namerec->data.ip ) {
217 0 : DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
218 0 : ZERO_STRUCTP(namerec);
219 0 : SAFE_FREE(namerec);
220 0 : return False;
221 : }
222 :
223 1140 : namerec->subnet = subrec;
224 :
225 1140 : make_nmb_name(&namerec->name, name, type);
226 1140 : if (!upcase_name(&namerec->name, NULL )) {
227 0 : SAFE_FREE(namerec->data.ip);
228 0 : SAFE_FREE(namerec);
229 0 : return False;
230 : }
231 :
232 : /* Enter the name as active. */
233 1140 : namerec->data.nb_flags = nb_flags | NB_ACTIVE;
234 1140 : namerec->data.wins_flags = WINS_ACTIVE;
235 :
236 : /* If it's our primary name, flag it as so. */
237 1140 : if (strequal( my_netbios_names(0), name )) {
238 258 : namerec->data.nb_flags |= NB_PERM;
239 : }
240 :
241 : /* Copy the IPs. */
242 1140 : namerec->data.num_ips = num_ips;
243 1140 : memcpy( (namerec->data.ip), iplist, num_ips * sizeof(struct in_addr) );
244 :
245 : /* Data source. */
246 1140 : namerec->data.source = source;
247 :
248 : /* Setup the death_time and refresh_time. */
249 1140 : if (ttl == PERMANENT_TTL) {
250 1140 : namerec->data.death_time = PERMANENT_TTL;
251 : } else {
252 0 : namerec->data.death_time = time_now + ttl;
253 : }
254 :
255 1140 : namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
256 :
257 1140 : DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
258 : ttl=%d nb_flags=%2x to subnet %s\n",
259 : nmb_namestr( &namerec->name ),
260 : inet_ntoa( *iplist ),
261 : ttl,
262 : (unsigned int)nb_flags,
263 : subrec->subnet_name ) );
264 :
265 : /* Now add the record to the name list. */
266 :
267 1140 : if (subrec == wins_server_subnet) {
268 0 : ret = add_name_to_wins_subnet(namerec);
269 : /* Free namerec - it's stored in the tdb. */
270 0 : SAFE_FREE(namerec->data.ip);
271 0 : SAFE_FREE(namerec);
272 : } else {
273 1140 : DLIST_ADD(subrec->namelist, namerec);
274 1140 : subrec->namelist_changed = True;
275 1140 : ret = True;
276 : }
277 :
278 1140 : return ret;
279 : }
280 :
281 : /*******************************************************************
282 : Utility function automatically called when a name refresh or register
283 : succeeds. By definition this is a SELF_NAME (or we wouldn't be registering
284 : it).
285 : ******************************************************************/
286 :
287 312 : void standard_success_register(struct subnet_record *subrec,
288 : struct userdata_struct *userdata,
289 : struct nmb_name *nmbname, uint16_t nb_flags, int ttl,
290 : struct in_addr registered_ip)
291 : {
292 : struct name_record *namerec;
293 :
294 312 : namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME);
295 312 : if (namerec == NULL) {
296 : unstring name;
297 312 : pull_ascii_nstring(name, sizeof(name), nmbname->name);
298 312 : add_name_to_subnet( subrec, name, nmbname->name_type,
299 : nb_flags, ttl, SELF_NAME, 1, ®istered_ip );
300 : } else {
301 0 : update_name_ttl( namerec, ttl );
302 : }
303 312 : }
304 :
305 : /*******************************************************************
306 : Utility function automatically called when a name refresh or register
307 : fails. Note that this is only ever called on a broadcast subnet with
308 : one IP address per name. This is why it can just delete the name
309 : without enumerating the IP addresses. JRA.
310 : ******************************************************************/
311 :
312 0 : void standard_fail_register( struct subnet_record *subrec,
313 : struct nmb_name *nmbname )
314 : {
315 : struct name_record *namerec;
316 :
317 0 : namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME);
318 :
319 0 : DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
320 : on subnet %s\n", nmb_namestr(nmbname), subrec->subnet_name) );
321 :
322 : /* Remove the name from the subnet. */
323 0 : if( namerec ) {
324 0 : remove_name_from_namelist(subrec, namerec);
325 : }
326 0 : }
327 :
328 : /*******************************************************************
329 : Utility function to remove an IP address from a name record.
330 : ******************************************************************/
331 :
332 8 : static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
333 : {
334 8 : if( ind != namerec->data.num_ips ) {
335 8 : memmove( (char *)(&namerec->data.ip[ind]),
336 8 : (char *)(&namerec->data.ip[ind+1]),
337 8 : ( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
338 : }
339 :
340 8 : namerec->data.num_ips--;
341 8 : if (namerec->subnet == wins_server_subnet) {
342 0 : wins_store_changed_namerec(namerec);
343 : } else {
344 8 : namerec->subnet->namelist_changed = True;
345 : }
346 8 : }
347 :
348 : /*******************************************************************
349 : Utility function to check if an IP address exists in a name record.
350 : ******************************************************************/
351 :
352 0 : bool find_ip_in_name_record( struct name_record *namerec, struct in_addr ip )
353 : {
354 : int i;
355 :
356 0 : for(i = 0; i < namerec->data.num_ips; i++) {
357 0 : if(ip_equal_v4( namerec->data.ip[i], ip)) {
358 0 : return True;
359 : }
360 : }
361 :
362 0 : return False;
363 : }
364 :
365 : /*******************************************************************
366 : Utility function to add an IP address to a name record.
367 : ******************************************************************/
368 :
369 0 : void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip )
370 : {
371 : struct in_addr *new_list;
372 :
373 : /* Don't add one we already have. */
374 0 : if( find_ip_in_name_record( namerec, new_ip )) {
375 0 : return;
376 : }
377 :
378 0 : new_list = SMB_MALLOC_ARRAY( struct in_addr, namerec->data.num_ips + 1);
379 0 : if( NULL == new_list ) {
380 0 : DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
381 0 : return;
382 : }
383 :
384 0 : memcpy( (char *)new_list, (char *)namerec->data.ip, namerec->data.num_ips * sizeof(struct in_addr) );
385 0 : new_list[namerec->data.num_ips] = new_ip;
386 :
387 0 : SAFE_FREE(namerec->data.ip);
388 0 : namerec->data.ip = new_list;
389 0 : namerec->data.num_ips += 1;
390 :
391 0 : if (namerec->subnet == wins_server_subnet) {
392 0 : wins_store_changed_namerec(namerec);
393 : } else {
394 0 : namerec->subnet->namelist_changed = True;
395 : }
396 : }
397 :
398 : /*******************************************************************
399 : Utility function to remove an IP address from a name record.
400 : ******************************************************************/
401 :
402 8 : void remove_ip_from_name_record( struct name_record *namerec,
403 : struct in_addr remove_ip )
404 : {
405 : /* Try and find the requested ip address - remove it. */
406 : int i;
407 8 : int orig_num = namerec->data.num_ips;
408 :
409 8 : for(i = 0; i < orig_num; i++) {
410 8 : if( ip_equal_v4( remove_ip, namerec->data.ip[i]) ) {
411 8 : remove_nth_ip_in_record( namerec, i);
412 8 : break;
413 : }
414 : }
415 8 : }
416 :
417 : /*******************************************************************
418 : Utility function that release_name callers can plug into as the
419 : success function when a name release is successful. Used to save
420 : duplication of success_function code.
421 : ******************************************************************/
422 :
423 4 : void standard_success_release( struct subnet_record *subrec,
424 : struct userdata_struct *userdata,
425 : struct nmb_name *nmbname,
426 : struct in_addr released_ip )
427 : {
428 : struct name_record *namerec;
429 :
430 4 : namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
431 4 : if( namerec == NULL ) {
432 0 : DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
433 : on subnet %s. Name was not found on subnet.\n", nmb_namestr(nmbname), inet_ntoa(released_ip),
434 : subrec->subnet_name) );
435 0 : return;
436 : } else {
437 4 : int orig_num = namerec->data.num_ips;
438 :
439 4 : remove_ip_from_name_record( namerec, released_ip );
440 :
441 4 : if( namerec->data.num_ips == orig_num ) {
442 0 : DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
443 : on subnet %s. This ip is not known for this name.\n", nmb_namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name ) );
444 : }
445 : }
446 :
447 4 : if( namerec->data.num_ips == 0 ) {
448 4 : remove_name_from_namelist( subrec, namerec );
449 : }
450 : }
451 :
452 : /*******************************************************************
453 : Expires old names in a subnet namelist.
454 : NB. Does not touch the wins_subnet - no wins specific processing here.
455 : ******************************************************************/
456 :
457 3499 : static void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
458 : {
459 : struct name_record *namerec;
460 : struct name_record *next_namerec;
461 :
462 44007 : for( namerec = subrec->namelist; namerec; namerec = next_namerec ) {
463 40508 : next_namerec = namerec->next;
464 40508 : if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
465 0 : if( namerec->data.source == SELF_NAME ) {
466 0 : DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
467 : name %s\n", subrec->subnet_name, nmb_namestr(&namerec->name) ) );
468 0 : namerec->data.death_time += 300;
469 0 : namerec->subnet->namelist_changed = True;
470 0 : continue;
471 : }
472 :
473 0 : DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
474 : subrec->subnet_name, nmb_namestr(&namerec->name)));
475 :
476 0 : remove_name_from_namelist(subrec, namerec );
477 : }
478 : }
479 3499 : }
480 :
481 : /*******************************************************************
482 : Expires old names in all subnet namelists.
483 : NB. Does not touch the wins_subnet.
484 : ******************************************************************/
485 :
486 3499 : void expire_names(time_t t)
487 : {
488 : struct subnet_record *subrec;
489 :
490 6998 : for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) ) {
491 3499 : expire_names_on_subnet( subrec, t );
492 : }
493 3499 : }
494 :
495 : /****************************************************************************
496 : Add the magic samba names, useful for finding samba servers.
497 : These go directly into the name list for a particular subnet,
498 : without going through the normal registration process.
499 : When adding them to the unicast subnet, add them as a list of
500 : all broadcast subnet IP addresses.
501 : **************************************************************************/
502 :
503 129 : void add_samba_names_to_subnet( struct subnet_record *subrec )
504 : {
505 129 : struct in_addr *iplist = &subrec->myip;
506 129 : int num_ips = 1;
507 :
508 : /* These names are added permanently (ttl of zero) and will NOT be refreshed. */
509 :
510 129 : if( (subrec == unicast_subnet) || (subrec == wins_server_subnet) || (subrec == remote_broadcast_subnet) ) {
511 : struct subnet_record *bcast_subrecs;
512 : int i;
513 :
514 : /* Create an IP list containing all our known subnets. */
515 :
516 86 : num_ips = iface_count();
517 86 : iplist = SMB_MALLOC_ARRAY( struct in_addr, num_ips);
518 86 : if( NULL == iplist ) {
519 0 : DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
520 0 : return;
521 : }
522 :
523 172 : for( bcast_subrecs = FIRST_SUBNET, i = 0; bcast_subrecs &&
524 : i < num_ips;
525 86 : bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ ) {
526 86 : iplist[i] = bcast_subrecs->myip;
527 : }
528 86 : num_ips = i;
529 : }
530 :
531 129 : add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
532 : PERMANENT_NAME, num_ips, iplist);
533 129 : add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
534 : PERMANENT_NAME, num_ips, iplist);
535 129 : add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
536 : PERMANENT_NAME, num_ips, iplist);
537 129 : add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
538 : PERMANENT_NAME, num_ips, iplist);
539 :
540 129 : if(iplist != &subrec->myip) {
541 86 : SAFE_FREE(iplist);
542 : }
543 : }
544 :
545 : /****************************************************************************
546 : Dump a name_record struct.
547 : **************************************************************************/
548 :
549 2418 : void dump_name_record( struct name_record *namerec, FILE *fp)
550 : {
551 : const char *src_type;
552 : struct tm *tm;
553 : int i;
554 :
555 2418 : fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name));
556 2418 : switch(namerec->data.source) {
557 0 : case LMHOSTS_NAME:
558 0 : src_type = "LMHOSTS_NAME";
559 0 : break;
560 0 : case WINS_PROXY_NAME:
561 0 : src_type = "WINS_PROXY_NAME";
562 0 : break;
563 0 : case REGISTER_NAME:
564 0 : src_type = "REGISTER_NAME";
565 0 : break;
566 711 : case SELF_NAME:
567 711 : src_type = "SELF_NAME";
568 711 : break;
569 0 : case DNS_NAME:
570 0 : src_type = "DNS_NAME";
571 0 : break;
572 0 : case DNSFAIL_NAME:
573 0 : src_type = "DNSFAIL_NAME";
574 0 : break;
575 1707 : case PERMANENT_NAME:
576 1707 : src_type = "PERMANENT_NAME";
577 1707 : break;
578 0 : default:
579 0 : src_type = "unknown!";
580 0 : break;
581 : }
582 :
583 2418 : fprintf(fp, "Source = %s\nb_flags = %x\t", src_type,
584 2418 : namerec->data.nb_flags);
585 :
586 2418 : if(namerec->data.death_time != PERMANENT_TTL) {
587 : const char *asct;
588 0 : tm = localtime(&namerec->data.death_time);
589 0 : if (!tm) {
590 0 : return;
591 : }
592 0 : asct = asctime(tm);
593 0 : if (!asct) {
594 0 : return;
595 : }
596 0 : fprintf(fp, "death_time = %s\t", asct);
597 : } else {
598 2418 : fprintf(fp, "death_time = PERMANENT\t");
599 : }
600 :
601 2418 : if(namerec->data.refresh_time != PERMANENT_TTL) {
602 : const char *asct;
603 2418 : tm = localtime(&namerec->data.refresh_time);
604 2418 : if (!tm) {
605 0 : return;
606 : }
607 2418 : asct = asctime(tm);
608 2418 : if (!asct) {
609 0 : return;
610 : }
611 2418 : fprintf(fp, "refresh_time = %s\n", asct);
612 : } else {
613 0 : fprintf(fp, "refresh_time = PERMANENT\n");
614 : }
615 :
616 2418 : fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
617 4836 : for(i = 0; i < namerec->data.num_ips; i++) {
618 2418 : fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
619 : }
620 :
621 2418 : fprintf(fp, "\n\n");
622 : }
623 :
624 : /****************************************************************************
625 : Dump the contents of the namelists on all the subnets (including unicast)
626 : into a file. Initiated by SIGHUP - used to debug the state of the namelists.
627 : **************************************************************************/
628 :
629 249 : static void dump_subnet_namelist(struct subnet_record *subrec, FILE *fp)
630 : {
631 : struct name_record *namerec;
632 249 : fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
633 2667 : for( namerec = subrec->namelist; namerec; namerec = namerec->next) {
634 2418 : dump_name_record(namerec, fp);
635 : }
636 249 : }
637 :
638 : /****************************************************************************
639 : Dump the contents of the namelists on all the subnets (including unicast)
640 : into a file. Initiated by SIGHUP - used to debug the state of the namelists.
641 : **************************************************************************/
642 :
643 83 : void dump_all_namelists(void)
644 : {
645 : int fd;
646 : FILE *fp;
647 : struct subnet_record *subrec;
648 : char *dump_path;
649 :
650 83 : dump_path = lock_path(talloc_tos(), "namelist.debug");
651 83 : if (dump_path == NULL) {
652 0 : DEBUG(0, ("out of memory!\n"));
653 0 : return;
654 : }
655 :
656 83 : fd = open(dump_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
657 83 : if (fd == -1) {
658 0 : DBG_ERR("Can't open file %s: %s\n", dump_path,
659 : strerror(errno));
660 0 : return;
661 : }
662 83 : TALLOC_FREE(dump_path);
663 :
664 83 : fp = fdopen(fd, "w");
665 83 : if (!fp) {
666 0 : DBG_ERR("fdopen failed: %s\n", strerror(errno));
667 0 : close(fd);
668 0 : return;
669 : }
670 83 : fd = -1;
671 :
672 166 : for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
673 83 : dump_subnet_namelist( subrec, fp );
674 : }
675 :
676 83 : if (!we_are_a_wins_client()) {
677 83 : dump_subnet_namelist( unicast_subnet, fp );
678 : }
679 :
680 83 : if (remote_broadcast_subnet->namelist != NULL) {
681 83 : dump_subnet_namelist( remote_broadcast_subnet, fp );
682 : }
683 :
684 83 : if (wins_server_subnet != NULL) {
685 0 : dump_wins_subnet_namelist(fp );
686 : }
687 :
688 83 : fclose( fp );
689 : }
|