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