s3-net: use new rpccli_spoolss_enumforms wrapper.
[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, 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;
199         int i;
200         struct in_addr unicast_ip, ipzero;
201
202   try_interfaces_again:
203
204         /* Only count IPv4, non-loopback interfaces. */
205         if (iface_count_v4_nl() == 0) {
206                 DEBUG(0,("create_subnets: No local IPv4 non-loopback interfaces !\n"));
207                 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
208         }
209
210         /* We only count IPv4, non-loopback interfaces here. */
211         while (iface_count_v4_nl() == 0) {
212                 void (*saved_handler)(int);
213
214                 /*
215                  * Whilst we're waiting for an interface, allow SIGTERM to
216                  * cause us to exit.
217                  */
218
219                 saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
220
221                 sleep(5);
222                 load_interfaces();
223
224                 /*
225                  * We got an interface, restore our normal term handler.
226                  */
227
228                 CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
229         }
230
231         /*
232          * Here we count v4 and v6 - we know there's at least one
233          * IPv4 interface and we filter on it below.
234          */
235         num_interfaces = iface_count();
236
237         /*
238          * Create subnets from all the local interfaces and thread them onto
239          * the linked list.
240          */
241
242         for (i = 0 ; i < num_interfaces; i++) {
243                 const struct interface *iface = get_interface(i);
244
245                 if (!iface) {
246                         DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
247                         continue;
248                 }
249
250                 /* Ensure we're only dealing with IPv4 here. */
251                 if (iface->ip.ss_family != AF_INET) {
252                         DEBUG(2,("create_subnets: "
253                                 "ignoring non IPv4 interface.\n"));
254                         continue;
255                 }
256
257                 /*
258                  * We don't want to add a loopback interface, in case
259                  * someone has added 127.0.0.1 for smbd, nmbd needs to
260                  * ignore it here. JRA.
261                  */
262
263                 if (is_loopback_addr((struct sockaddr *)&iface->ip)) {
264                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
265                         continue;
266                 }
267
268                 if (!make_normal_subnet(iface))
269                         return False;
270         }
271
272         /* We must have at least one subnet. */
273         if (subnetlist == NULL) {
274                 void (*saved_handler)(int);
275
276                 DEBUG(0,("create_subnets: Unable to create any subnet from "
277                                 "given interfaces. Is your interface line in "
278                                 "smb.conf correct ?\n"));
279
280                 saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
281
282                 sleep(5);
283                 load_interfaces();
284
285                 CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
286                 goto try_interfaces_again;
287         }
288
289         if (lp_we_are_a_wins_server()) {
290                 /* Pick the first interface IPv4 address as the WINS server
291                  * ip. */
292                 const struct in_addr *nip = first_ipv4_iface();
293
294                 if (!nip) {
295                         return False;
296                 }
297
298                 unicast_ip = *nip;
299         } else {
300                 /* note that we do not set the wins server IP here. We just
301                         set it at zero and let the wins registration code cope
302                         with getting the IPs right for each packet */
303                 zero_ip_v4(&unicast_ip);
304         }
305
306         /*
307          * Create the unicast and remote broadcast subnets.
308          * Don't put these onto the linked list.
309          * The ip address of the unicast subnet is set to be
310          * the WINS server address, if it exists, or ipzero if not.
311          */
312
313         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
314                                 unicast_ip, unicast_ip, unicast_ip);
315
316         zero_ip_v4(&ipzero);
317
318         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
319                                 REMOTE_BROADCAST_SUBNET,
320                                 ipzero, ipzero, ipzero);
321
322         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
323                 return False;
324
325         /* 
326          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
327          * the linked list.
328          */
329
330         if (lp_we_are_a_wins_server()) {
331                 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
332                                                 WINS_SERVER_SUBNET, 
333                                                 ipzero, ipzero, ipzero )) == NULL )
334                         return False;
335         }
336
337         return True;
338 }
339
340 /*******************************************************************
341 Function to tell us if we can use the unicast subnet.
342 ******************************************************************/
343
344 bool we_are_a_wins_client(void)
345 {
346         if (wins_srv_count() > 0) {
347                 return True;
348         }
349
350         return False;
351 }
352
353 /*******************************************************************
354 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
355 ******************************************************************/
356
357 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
358 {
359         if(subrec == unicast_subnet)
360                 return NULL;
361         else if((subrec->next == NULL) && we_are_a_wins_client())
362                 return unicast_subnet;
363         else
364                 return subrec->next;
365 }
366
367 /*******************************************************************
368  Access function used by retransmit_or_expire_response_records() in
369  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
370  Needed when we need to enumerate all the broadcast, unicast and
371  WINS subnets.
372 ******************************************************************/
373
374 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
375 {
376         if(subrec == unicast_subnet) {
377                 if(wins_server_subnet)
378                         return wins_server_subnet;
379                 else
380                         return NULL;
381         }
382
383         if(wins_server_subnet && subrec == wins_server_subnet)
384                 return NULL;
385
386         if((subrec->next == NULL) && we_are_a_wins_client())
387                 return unicast_subnet;
388         else
389                 return subrec->next;
390 }