Fix the last reported debian problem with nmbd not waiting
[ira/wip.git] / source / nmbd / nmbd_subnetdb.c
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-1998
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    Revision History:
22
23 */
24
25 #include "includes.h"
26
27 extern int global_nmb_port;
28
29 /* This is the broadcast subnets database. */
30 struct subnet_record *subnetlist = NULL;
31
32 /* Extra subnets - keep these separate so enumeration code doesn't
33    run onto it by mistake. */
34
35 struct subnet_record *unicast_subnet = NULL;
36 struct subnet_record *remote_broadcast_subnet = NULL;
37 struct subnet_record *wins_server_subnet = NULL;
38
39 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
40
41 /****************************************************************************
42   Add a subnet into the list.
43   **************************************************************************/
44
45 static void add_subnet(struct subnet_record *subrec)
46 {
47         DLIST_ADD(subnetlist, subrec);
48 }
49
50 /****************************************************************************
51 stop listening on a subnet
52 we don't free the record as we don't have proper reference counting for it
53 yet and it may be in use by a response record
54   ****************************************************************************/
55
56 void close_subnet(struct subnet_record *subrec)
57 {
58         if (subrec->dgram_sock != -1) {
59                 close(subrec->dgram_sock);
60                 subrec->dgram_sock = -1;
61         }
62         if (subrec->nmb_sock != -1) {
63                 close(subrec->nmb_sock);
64                 subrec->nmb_sock = -1;
65         }
66
67         DLIST_REMOVE(subnetlist, subrec);
68 }
69
70 /****************************************************************************
71   Create a subnet entry.
72   ****************************************************************************/
73
74 static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
75                                          struct in_addr myip, struct in_addr bcast_ip, 
76                                          struct in_addr mask_ip)
77 {
78         struct subnet_record *subrec = NULL;
79         int nmb_sock, dgram_sock;
80
81         /* Check if we are creating a non broadcast subnet - if so don't create
82                 sockets.  */
83
84         if(type != NORMAL_SUBNET) {
85                 nmb_sock = -1;
86                 dgram_sock = -1;
87         } else {
88                 struct sockaddr_storage ss;
89
90                 in_addr_to_sockaddr_storage(&ss, myip);
91
92                 /*
93                  * Attempt to open the sockets on port 137/138 for this interface
94                  * and bind them.
95                  * Fail the subnet creation if this fails.
96                  */
97
98                 if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, &ss,true)) == -1) {
99                         if( DEBUGLVL( 0 ) ) {
100                                 Debug1( "nmbd_subnetdb:make_subnet()\n" );
101                                 Debug1( "  Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
102                                 Debug1( "for port %d.  ", global_nmb_port );
103                                 Debug1( "Error was %s\n", strerror(errno) );
104                         }
105                         return NULL;
106                 }
107
108                 if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, &ss, true)) == -1) {
109                         if( DEBUGLVL( 0 ) ) {
110                                 Debug1( "nmbd_subnetdb:make_subnet()\n" );
111                                 Debug1( "  Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
112                                 Debug1( "for port %d.  ", DGRAM_PORT );
113                                 Debug1( "Error was %s\n", strerror(errno) );
114                         }
115                         return NULL;
116                 }
117
118                 /* Make sure we can broadcast from these sockets. */
119                 set_socket_options(nmb_sock,"SO_BROADCAST");
120                 set_socket_options(dgram_sock,"SO_BROADCAST");
121
122                 /* Set them non-blocking. */
123                 set_blocking(nmb_sock, False);
124                 set_blocking(dgram_sock, False);
125         }
126
127         subrec = SMB_MALLOC_P(struct subnet_record);
128         if (!subrec) {
129                 DEBUG(0,("make_subnet: malloc fail !\n"));
130                 if (nmb_sock != -1) {
131                         close(nmb_sock);
132                 }
133                 if (dgram_sock != -1) {
134                         close(dgram_sock);
135                 }
136                 return(NULL);
137         }
138   
139         ZERO_STRUCTP(subrec);
140
141         if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
142                 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
143                 if (nmb_sock != -1) {
144                         close(nmb_sock);
145                 }
146                 if (dgram_sock != -1) {
147                         close(dgram_sock);
148                 }
149                 ZERO_STRUCTP(subrec);
150                 SAFE_FREE(subrec);
151                 return(NULL);
152         }
153
154         DEBUG(2, ("making subnet name:%s ", name ));
155         DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
156         DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
157  
158         subrec->namelist_changed = False;
159         subrec->work_changed = False;
160  
161         subrec->bcast_ip = bcast_ip;
162         subrec->mask_ip  = mask_ip;
163         subrec->myip = myip;
164         subrec->type = type;
165         subrec->nmb_sock = nmb_sock;
166         subrec->dgram_sock = dgram_sock;
167   
168         return subrec;
169 }
170
171 /****************************************************************************
172   Create a normal subnet
173 **************************************************************************/
174
175 struct subnet_record *make_normal_subnet(const struct interface *iface)
176 {
177
178         struct subnet_record *subrec;
179         const struct in_addr *pip = &((const struct sockaddr_in *)&iface->ip)->sin_addr;
180         const struct in_addr *pbcast = &((const struct sockaddr_in *)&iface->bcast)->sin_addr;
181         const struct in_addr *pnmask = &((const struct sockaddr_in *)&iface->netmask)->sin_addr;
182
183         subrec = make_subnet(inet_ntoa(*pip), NORMAL_SUBNET,
184                              *pip, *pbcast, *pnmask);
185         if (subrec) {
186                 add_subnet(subrec);
187         }
188         return subrec;
189 }
190
191 /****************************************************************************
192   Create subnet entries.
193 **************************************************************************/
194
195 bool create_subnets(void)
196 {
197         /* We only count IPv4 interfaces whilst we're waiting. */
198         int num_interfaces = iface_count_v4();
199         int i;
200         struct in_addr unicast_ip, ipzero;
201
202   try_interfaces_again:
203
204         if (iface_count_v4() == 0) {
205                 DEBUG(0,("create_subnets: No local interfaces !\n"));
206                 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
207         }
208
209         /* We only count IPv4 interfaces here. */
210         while (iface_count_v4() == 0) {
211                 void (*saved_handler)(int);
212
213                 /*
214                  * Whilst we're waiting for an interface, allow SIGTERM to
215                  * cause us to exit.
216                  */
217
218                 saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
219
220                 sleep(5);
221                 load_interfaces();
222
223                 /*
224                  * We got an interface, restore our normal term handler.
225                  */
226
227                 CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
228         }
229
230         /*
231          * Here we count v4 and v6 - we know there's at least one
232          * IPv4 interface and we filter on it below.
233          */
234         num_interfaces = iface_count();
235
236         /*
237          * Create subnets from all the local interfaces and thread them onto
238          * the linked list.
239          */
240
241         for (i = 0 ; i < num_interfaces; i++) {
242                 const struct interface *iface = get_interface(i);
243
244                 if (!iface) {
245                         DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
246                         continue;
247                 }
248
249                 /* Ensure we're only dealing with IPv4 here. */
250                 if (iface->ip.ss_family != AF_INET) {
251                         DEBUG(2,("create_subnets: "
252                                 "ignoring non IPv4 interface.\n"));
253                         continue;
254                 }
255
256                 /*
257                  * We don't want to add a loopback interface, in case
258                  * someone has added 127.0.0.1 for smbd, nmbd needs to
259                  * ignore it here. JRA.
260                  */
261
262                 if (is_loopback_addr(&iface->ip)) {
263                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
264                         continue;
265                 }
266
267                 if (!make_normal_subnet(iface))
268                         return False;
269         }
270
271         /* We must have at least one subnet. */
272         if (subnetlist == NULL) {
273                 void (*saved_handler)(int);
274
275                 DEBUG(0,("create_subnets: Unable to create any subnet from "
276                                 "given interfaces. Is your interface line in "
277                                 "smb.conf correct ?\n"));
278
279                 saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
280
281                 sleep(5);
282                 load_interfaces();
283
284                 CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
285                 goto try_interfaces_again;
286         }
287
288         if (lp_we_are_a_wins_server()) {
289                 /* Pick the first interface IPv4 address as the WINS server ip. */
290                 const struct in_addr *nip = first_ipv4_iface();
291
292                 if (!nip) {
293                         return False;
294                 }
295
296                 unicast_ip = *nip;
297         } else {
298                 /* note that we do not set the wins server IP here. We just
299                         set it at zero and let the wins registration code cope
300                         with getting the IPs right for each packet */
301                 zero_ip_v4(&unicast_ip);
302         }
303
304         /*
305          * Create the unicast and remote broadcast subnets.
306          * Don't put these onto the linked list.
307          * The ip address of the unicast subnet is set to be
308          * the WINS server address, if it exists, or ipzero if not.
309          */
310
311         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
312                                 unicast_ip, unicast_ip, unicast_ip);
313
314         zero_ip_v4(&ipzero);
315
316         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
317                                 REMOTE_BROADCAST_SUBNET,
318                                 ipzero, ipzero, ipzero);
319
320         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
321                 return False;
322
323         /* 
324          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
325          * the linked list.
326          */
327
328         if (lp_we_are_a_wins_server()) {
329                 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
330                                                 WINS_SERVER_SUBNET, 
331                                                 ipzero, ipzero, ipzero )) == NULL )
332                         return False;
333         }
334
335         return True;
336 }
337
338 /*******************************************************************
339 Function to tell us if we can use the unicast subnet.
340 ******************************************************************/
341
342 bool we_are_a_wins_client(void)
343 {
344         if (wins_srv_count() > 0) {
345                 return True;
346         }
347
348         return False;
349 }
350
351 /*******************************************************************
352 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
353 ******************************************************************/
354
355 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
356 {
357         if(subrec == unicast_subnet)
358                 return NULL;
359         else if((subrec->next == NULL) && we_are_a_wins_client())
360                 return unicast_subnet;
361         else
362                 return subrec->next;
363 }
364
365 /*******************************************************************
366  Access function used by retransmit_or_expire_response_records() in
367  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
368  Needed when we need to enumerate all the broadcast, unicast and
369  WINS subnets.
370 ******************************************************************/
371
372 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
373 {
374         if(subrec == unicast_subnet) {
375                 if(wins_server_subnet)
376                         return wins_server_subnet;
377                 else
378                         return NULL;
379         }
380
381         if(wins_server_subnet && subrec == wins_server_subnet)
382                 return NULL;
383
384         if((subrec->next == NULL) && we_are_a_wins_client())
385                 return unicast_subnet;
386         else
387                 return subrec->next;
388 }