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