s3-nmbd: Remove obsolete signal type cast.
[ira/wip.git] / source3 / 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 = -1;
80         int dgram_sock = -1;
81         int nmb_bcast = -1;
82         int dgram_bcast = -1;
83         bool bind_bcast = lp_nmbd_bind_explicit_broadcast();
84
85         /* Check if we are creating a non broadcast subnet - if so don't create
86                 sockets.  */
87
88         if (type == NORMAL_SUBNET) {
89                 struct sockaddr_storage ss;
90                 struct sockaddr_storage ss_bcast;
91
92                 in_addr_to_sockaddr_storage(&ss, myip);
93                 in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip);
94
95                 /*
96                  * Attempt to open the sockets on port 137/138 for this interface
97                  * and bind them.
98                  * Fail the subnet creation if this fails.
99                  */
100
101                 nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,
102                                           0, &ss, true);
103                 if (nmb_sock == -1) {
104                         DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
105                         DEBUGADD(0,("  Failed to open nmb socket on interface %s ",
106                                     inet_ntoa(myip)));
107                         DEBUGADD(0,("for port %d.  ", global_nmb_port));
108                         DEBUGADD(0,("Error was %s\n", strerror(errno)));
109                         goto failed;
110                 }
111                 set_socket_options(nmb_sock,"SO_BROADCAST");
112                 set_blocking(nmb_sock, false);
113
114                 if (bind_bcast) {
115                         nmb_bcast = open_socket_in(SOCK_DGRAM, global_nmb_port,
116                                                    0, &ss_bcast, true);
117                         if (nmb_bcast == -1) {
118                                 DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
119                                 DEBUGADD(0,("  Failed to open nmb bcast socket on interface %s ",
120                                             inet_ntoa(bcast_ip)));
121                                 DEBUGADD(0,("for port %d.  ", global_nmb_port));
122                                 DEBUGADD(0,("Error was %s\n", strerror(errno)));
123                                 goto failed;
124                         }
125                         set_socket_options(nmb_bcast, "SO_BROADCAST");
126                         set_blocking(nmb_bcast, false);
127                 }
128
129                 dgram_sock = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
130                                             3, &ss, true);
131                 if (dgram_sock == -1) {
132                         DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
133                         DEBUGADD(0,("  Failed to open dgram socket on interface %s ",
134                                     inet_ntoa(myip)));
135                         DEBUGADD(0,("for port %d.  ", DGRAM_PORT));
136                         DEBUGADD(0,("Error was %s\n", strerror(errno)));
137                         goto failed;
138                 }
139                 set_socket_options(dgram_sock, "SO_BROADCAST");
140                 set_blocking(dgram_sock, false);
141
142                 if (bind_bcast) {
143                         dgram_bcast = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
144                                                      3, &ss_bcast, true);
145                         if (dgram_bcast == -1) {
146                                 DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
147                                 DEBUGADD(0,("  Failed to open dgram bcast socket on interface %s ",
148                                             inet_ntoa(bcast_ip)));
149                                 DEBUGADD(0,("for port %d.  ", DGRAM_PORT));
150                                 DEBUGADD(0,("Error was %s\n", strerror(errno)));
151                                 goto failed;
152                         }
153                         set_socket_options(dgram_bcast, "SO_BROADCAST");
154                         set_blocking(dgram_bcast, false);
155                 }
156         }
157
158         subrec = SMB_MALLOC_P(struct subnet_record);
159         if (!subrec) {
160                 DEBUG(0,("make_subnet: malloc fail !\n"));
161                 goto failed;
162         }
163   
164         ZERO_STRUCTP(subrec);
165
166         if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
167                 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
168                 goto failed;
169         }
170
171         DEBUG(2, ("making subnet name:%s ", name ));
172         DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
173         DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
174  
175         subrec->namelist_changed = False;
176         subrec->work_changed = False;
177  
178         subrec->bcast_ip = bcast_ip;
179         subrec->mask_ip  = mask_ip;
180         subrec->myip = myip;
181         subrec->type = type;
182         subrec->nmb_sock = nmb_sock;
183         subrec->nmb_bcast = nmb_bcast;
184         subrec->dgram_sock = dgram_sock;
185         subrec->dgram_bcast = dgram_bcast;
186
187         return subrec;
188
189 failed:
190         SAFE_FREE(subrec);
191         if (nmb_sock != -1) {
192                 close(nmb_sock);
193         }
194         if (nmb_bcast != -1) {
195                 close(nmb_bcast);
196         }
197         if (dgram_sock != -1) {
198                 close(dgram_sock);
199         }
200         if (dgram_bcast != -1) {
201                 close(dgram_bcast);
202         }
203         return NULL;
204 }
205
206 /****************************************************************************
207   Create a normal subnet
208 **************************************************************************/
209
210 struct subnet_record *make_normal_subnet(const struct interface *iface)
211 {
212
213         struct subnet_record *subrec;
214         const struct in_addr *pip = &((const struct sockaddr_in *)&iface->ip)->sin_addr;
215         const struct in_addr *pbcast = &((const struct sockaddr_in *)&iface->bcast)->sin_addr;
216         const struct in_addr *pnmask = &((const struct sockaddr_in *)&iface->netmask)->sin_addr;
217
218         subrec = make_subnet(inet_ntoa(*pip), NORMAL_SUBNET,
219                              *pip, *pbcast, *pnmask);
220         if (subrec) {
221                 add_subnet(subrec);
222         }
223         return subrec;
224 }
225
226 /****************************************************************************
227   Create subnet entries.
228 **************************************************************************/
229
230 bool create_subnets(void)
231 {
232         /* We only count IPv4 interfaces whilst we're waiting. */
233         int num_interfaces;
234         int i;
235         struct in_addr unicast_ip, ipzero;
236
237   try_interfaces_again:
238
239         /* Only count IPv4, non-loopback interfaces. */
240         if (iface_count_v4_nl() == 0) {
241                 DEBUG(0,("create_subnets: No local IPv4 non-loopback interfaces !\n"));
242                 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
243         }
244
245         /* We only count IPv4, non-loopback interfaces here. */
246         while (iface_count_v4_nl() == 0) {
247                 void (*saved_handler)(int);
248
249                 /*
250                  * Whilst we're waiting for an interface, allow SIGTERM to
251                  * cause us to exit.
252                  */
253
254                 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
255
256                 sleep(5);
257                 load_interfaces();
258
259                 /*
260                  * We got an interface, restore our normal term handler.
261                  */
262
263                 CatchSignal(SIGTERM, saved_handler);
264         }
265
266         /*
267          * Here we count v4 and v6 - we know there's at least one
268          * IPv4 interface and we filter on it below.
269          */
270         num_interfaces = iface_count();
271
272         /*
273          * Create subnets from all the local interfaces and thread them onto
274          * the linked list.
275          */
276
277         for (i = 0 ; i < num_interfaces; i++) {
278                 const struct interface *iface = get_interface(i);
279
280                 if (!iface) {
281                         DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
282                         continue;
283                 }
284
285                 /* Ensure we're only dealing with IPv4 here. */
286                 if (iface->ip.ss_family != AF_INET) {
287                         DEBUG(2,("create_subnets: "
288                                 "ignoring non IPv4 interface.\n"));
289                         continue;
290                 }
291
292                 /*
293                  * We don't want to add a loopback interface, in case
294                  * someone has added 127.0.0.1 for smbd, nmbd needs to
295                  * ignore it here. JRA.
296                  */
297
298                 if (is_loopback_addr((struct sockaddr *)&iface->ip)) {
299                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
300                         continue;
301                 }
302
303                 if (!make_normal_subnet(iface))
304                         return False;
305         }
306
307         /* We must have at least one subnet. */
308         if (subnetlist == NULL) {
309                 void (*saved_handler)(int);
310
311                 DEBUG(0,("create_subnets: Unable to create any subnet from "
312                                 "given interfaces. Is your interface line in "
313                                 "smb.conf correct ?\n"));
314
315                 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
316
317                 sleep(5);
318                 load_interfaces();
319
320                 CatchSignal(SIGTERM, saved_handler);
321                 goto try_interfaces_again;
322         }
323
324         if (lp_we_are_a_wins_server()) {
325                 /* Pick the first interface IPv4 address as the WINS server
326                  * ip. */
327                 const struct in_addr *nip = first_ipv4_iface();
328
329                 if (!nip) {
330                         return False;
331                 }
332
333                 unicast_ip = *nip;
334         } else {
335                 /* note that we do not set the wins server IP here. We just
336                         set it at zero and let the wins registration code cope
337                         with getting the IPs right for each packet */
338                 zero_ip_v4(&unicast_ip);
339         }
340
341         /*
342          * Create the unicast and remote broadcast subnets.
343          * Don't put these onto the linked list.
344          * The ip address of the unicast subnet is set to be
345          * the WINS server address, if it exists, or ipzero if not.
346          */
347
348         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
349                                 unicast_ip, unicast_ip, unicast_ip);
350
351         zero_ip_v4(&ipzero);
352
353         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
354                                 REMOTE_BROADCAST_SUBNET,
355                                 ipzero, ipzero, ipzero);
356
357         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
358                 return False;
359
360         /* 
361          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
362          * the linked list.
363          */
364
365         if (lp_we_are_a_wins_server()) {
366                 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
367                                                 WINS_SERVER_SUBNET, 
368                                                 ipzero, ipzero, ipzero )) == NULL )
369                         return False;
370         }
371
372         return True;
373 }
374
375 /*******************************************************************
376 Function to tell us if we can use the unicast subnet.
377 ******************************************************************/
378
379 bool we_are_a_wins_client(void)
380 {
381         if (wins_srv_count() > 0) {
382                 return True;
383         }
384
385         return False;
386 }
387
388 /*******************************************************************
389 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
390 ******************************************************************/
391
392 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
393 {
394         if(subrec == unicast_subnet)
395                 return NULL;
396         else if((subrec->next == NULL) && we_are_a_wins_client())
397                 return unicast_subnet;
398         else
399                 return subrec->next;
400 }
401
402 /*******************************************************************
403  Access function used by retransmit_or_expire_response_records() in
404  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
405  Needed when we need to enumerate all the broadcast, unicast and
406  WINS subnets.
407 ******************************************************************/
408
409 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
410 {
411         if(subrec == unicast_subnet) {
412                 if(wins_server_subnet)
413                         return wins_server_subnet;
414                 else
415                         return NULL;
416         }
417
418         if(wins_server_subnet && subrec == wins_server_subnet)
419                 return NULL;
420
421         if((subrec->next == NULL) && we_are_a_wins_client())
422                 return unicast_subnet;
423         else
424                 return subrec->next;
425 }