off by one bug in string length; CR 1159
[Samba.git] / source / nmbd / nmbd_subnetdb.c
blob62968264259d9a70b7512a51dc0d168dac95a4e5
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
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.
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.
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.
22 Revision History:
26 #include "includes.h"
28 extern int ClientNMB;
29 extern int ClientDGRAM;
30 extern int global_nmb_port;
32 /* This is the broadcast subnets database. */
33 struct subnet_record *subnetlist = NULL;
35 /* Extra subnets - keep these separate so enumeration code doesn't
36 run onto it by mistake. */
38 struct subnet_record *unicast_subnet = NULL;
39 struct subnet_record *remote_broadcast_subnet = NULL;
40 struct subnet_record *wins_server_subnet = NULL;
42 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
44 /****************************************************************************
45 Add a subnet into the list.
46 **************************************************************************/
48 static void add_subnet(struct subnet_record *subrec)
50 DLIST_ADD(subnetlist, subrec);
53 /* ************************************************************************** **
54 * Comparison routine for ordering the splay-tree based namelists assoicated
55 * with each subnet record.
57 * Input: Item - Pointer to the comparison key.
58 * Node - Pointer to a node the splay tree.
60 * Output: The return value will be <0 , ==0, or >0 depending upon the
61 * ordinal relationship of the two keys.
63 * ************************************************************************** **
65 static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
67 struct name_record *NR = (struct name_record *)Node;
69 if( DEBUGLVL( 10 ) )
71 struct nmb_name *Iname = (struct nmb_name *)Item;
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) );
79 return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
80 } /* namelist_entry_compare */
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)
90 DLIST_REMOVE(subnetlist, subrec);
92 if (subrec->dgram_sock != -1) {
93 close(subrec->dgram_sock);
94 subrec->dgram_sock = -1;
96 if (subrec->nmb_sock != -1) {
97 close(subrec->nmb_sock);
98 subrec->nmb_sock = -1;
104 /****************************************************************************
105 Create a subnet entry.
106 ****************************************************************************/
108 static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
109 struct in_addr myip, struct in_addr bcast_ip,
110 struct in_addr mask_ip)
112 struct subnet_record *subrec = NULL;
113 int nmb_sock, dgram_sock;
115 /* Check if we are creating a non broadcast subnet - if so don't create
116 sockets.
119 if(type != NORMAL_SUBNET)
121 nmb_sock = -1;
122 dgram_sock = -1;
124 else
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.
132 if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1)
134 if( DEBUGLVL( 0 ) )
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) );
141 return NULL;
144 if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1)
146 if( DEBUGLVL( 0 ) )
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) );
153 return NULL;
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");
162 subrec = (struct subnet_record *)malloc(sizeof(*subrec));
164 if (!subrec)
166 DEBUG(0,("make_subnet: malloc fail !\n"));
167 close(nmb_sock);
168 close(dgram_sock);
169 return(NULL);
172 memset( (char *)subrec, '\0', sizeof(*subrec) );
173 (void)ubi_trInitTree( subrec->namelist,
174 namelist_entry_compare,
175 ubi_trOVERWRITE );
177 if((subrec->subnet_name = strdup(name)) == NULL)
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);
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)));
191 subrec->namelist_changed = False;
192 subrec->work_changed = False;
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;
201 return subrec;
205 /****************************************************************************
206 Create a normal subnet
207 **************************************************************************/
208 struct subnet_record *make_normal_subnet(struct interface *iface)
210 struct subnet_record *subrec;
212 subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
213 iface->ip, iface->bcast, iface->nmask);
214 if (subrec) {
215 add_subnet(subrec);
217 return subrec;
221 /****************************************************************************
222 Create subnet entries.
223 **************************************************************************/
225 BOOL create_subnets(void)
227 int num_interfaces = iface_count();
228 int i;
229 struct in_addr unicast_ip, ipzero;
230 extern struct in_addr loopback_ip;
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();
241 num_interfaces = iface_count();
244 * Create subnets from all the local interfaces and thread them onto
245 * the linked list.
248 for (i = 0 ; i < num_interfaces; i++)
250 struct interface *iface = get_interface(i);
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.
258 if (ip_equal(iface->ip, loopback_ip)) {
259 DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
260 continue;
263 if (!make_normal_subnet(iface)) return False;
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);
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.
283 unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
284 unicast_ip, unicast_ip, unicast_ip);
286 zero_ip(&ipzero);
288 remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
289 REMOTE_BROADCAST_SUBNET,
290 ipzero, ipzero, ipzero);
292 if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
293 return False;
296 * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
297 * the linked list.
300 if (lp_we_are_a_wins_server())
302 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
303 WINS_SERVER_SUBNET,
304 ipzero, ipzero, ipzero )) == NULL )
305 return False;
308 return True;
311 /*******************************************************************
312 Function to tell us if we can use the unicast subnet.
313 ******************************************************************/
314 BOOL we_are_a_wins_client(void)
316 if (wins_srv_count() > 0) {
317 return True;
320 return False;
323 /*******************************************************************
324 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
325 ******************************************************************/
327 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
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;
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 ******************************************************************/
344 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
346 if(subrec == unicast_subnet)
348 if(wins_server_subnet)
349 return wins_server_subnet;
350 else
351 return NULL;
354 if(wins_server_subnet && subrec == wins_server_subnet)
355 return NULL;
357 if((subrec->next == NULL) && we_are_a_wins_client())
358 return unicast_subnet;
359 else
360 return subrec->next;