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