r6247: added the server side code for receiving mailslot requests, and
[samba.git] / source / nbt_server / interfaces.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NBT interface handling
5
6    Copyright (C) Andrew Tridgell        2005
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
23 #include "includes.h"
24 #include "dlinklist.h"
25 #include "nbt_server/nbt_server.h"
26 #include "smbd/service_task.h"
27 #include "lib/socket/socket.h"
28
29
30 /*
31   receive an incoming request and dispatch it to the right place
32 */
33 static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
34                                  struct nbt_name_packet *packet, 
35                                  const char *src_address, int src_port)
36 {
37         /* see if its from one of our own interfaces - if so, then ignore it */
38         if (nbtd_self_packet(nbtsock, packet, src_address, src_port)) {
39                 DEBUG(10,("Ignoring self packet from %s:%d\n", src_address, src_port));
40                 return;
41         }
42
43         switch (packet->operation & NBT_OPCODE) {
44         case NBT_OPCODE_QUERY:
45                 nbtd_request_query(nbtsock, packet, src_address, src_port);
46                 break;
47
48         case NBT_OPCODE_REGISTER:
49         case NBT_OPCODE_REFRESH:
50         case NBT_OPCODE_REFRESH2:
51                 nbtd_request_defense(nbtsock, packet, src_address, src_port);
52                 break;
53
54         case NBT_OPCODE_RELEASE:
55         case NBT_OPCODE_MULTI_HOME_REG:
56                 nbtd_winsserver_request(nbtsock, packet, src_address, src_port);
57                 break;
58
59         default:
60                 nbtd_bad_packet(packet, src_address, "Unexpected opcode");
61                 break;
62         }
63 }
64
65
66 /*
67   find a registered name on an interface
68 */
69 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
70                                         struct nbt_name *name, 
71                                         uint16_t nb_flags)
72 {
73         struct nbtd_iface_name *iname;
74         for (iname=iface->names;iname;iname=iname->next) {
75                 if (iname->name.type == name->type &&
76                     strcmp(name->name, iname->name.name) == 0 &&
77                     ((iname->nb_flags & nb_flags) == nb_flags)) {
78                         return iname;
79                 }
80         }
81         return NULL;
82 }
83
84 /*
85   start listening on the given address
86 */
87 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
88                                 const char *bind_address, 
89                                 const char *address, 
90                                 const char *bcast, 
91                                 const char *netmask)
92 {
93         struct nbtd_interface *iface;
94         NTSTATUS status;
95
96         /*
97           we actually create two sockets. One listens on the broadcast address
98           for the interface, and the other listens on our specific address. This
99           allows us to run with "bind interfaces only" while still receiving 
100           broadcast addresses, and also simplifies matching incoming requests 
101           to interfaces
102         */
103
104         iface = talloc(nbtsrv, struct nbtd_interface);
105         NT_STATUS_HAVE_NO_MEMORY(iface);
106
107         iface->nbtsrv        = nbtsrv;
108         iface->bcast_address = talloc_steal(iface, bcast);
109         iface->ip_address    = talloc_steal(iface, address);
110         iface->netmask       = talloc_steal(iface, netmask);
111         iface->names         = NULL;
112
113         if (strcmp(netmask, "0.0.0.0") != 0) {
114                 struct nbt_name_socket *bcast_nbtsock;
115
116                 /* listen for broadcasts on port 137 */
117                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
118                 NT_STATUS_HAVE_NO_MEMORY(bcast_nbtsock);
119
120                 status = socket_listen(bcast_nbtsock->sock, bcast, lp_nbt_port(), 0, 0);
121                 if (!NT_STATUS_IS_OK(status)) {
122                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
123                                  bcast, lp_nbt_port(), nt_errstr(status)));
124                         talloc_free(iface);
125                         return status;
126                 }
127
128                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
129         }
130
131         /* listen for unicasts on port 137 */
132         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
133         NT_STATUS_HAVE_NO_MEMORY(iface->nbtsock);
134
135         status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0);
136         if (!NT_STATUS_IS_OK(status)) {
137                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
138                          bind_address, lp_nbt_port(), nt_errstr(status)));
139                 talloc_free(iface);
140                 return status;
141         }
142         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
143
144         /* also setup the datagram listeners */
145         status = nbtd_dgram_setup(iface, bind_address);
146         if (!NT_STATUS_IS_OK(status)) {
147                 DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
148                          bind_address, nt_errstr(status)));
149                 talloc_free(iface);
150                 return status;
151         }
152         
153         if (strcmp(netmask, "0.0.0.0") == 0) {
154                 DLIST_ADD(nbtsrv->bcast_interface, iface);
155         } else {
156                 DLIST_ADD(nbtsrv->interfaces, iface);
157         }
158
159         return NT_STATUS_OK;
160 }
161
162
163 /*
164   setup a socket for talking to our WINS servers
165 */
166 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
167 {
168         struct nbtd_interface *iface;
169
170         iface = talloc_zero(nbtsrv, struct nbtd_interface);
171         NT_STATUS_HAVE_NO_MEMORY(iface);
172
173         iface->nbtsrv        = nbtsrv;
174
175         DLIST_ADD(nbtsrv->wins_interface, iface);
176
177         return NT_STATUS_OK;
178 }
179
180
181 /*
182   setup our listening sockets on the configured network interfaces
183 */
184 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
185 {
186         int num_interfaces = iface_count();
187         int i;
188         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
189         NTSTATUS status;
190
191         /* if we are allowing incoming packets from any address, then
192            we also need to bind to the wildcard address */
193         if (!lp_bind_interfaces_only()) {
194                 const char *primary_address;
195
196                 /* the primary address is the address we will return
197                    for non-WINS queries not made on a specific
198                    interface */
199                 if (num_interfaces > 0) {
200                         primary_address = iface_n_ip(0);
201                 } else {
202                         primary_address = sys_inet_ntoa(interpret_addr2(
203                                                                 lp_netbios_name()));
204                 }
205                 primary_address = talloc_strdup(tmp_ctx, primary_address);
206                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
207
208                 status = nbtd_add_socket(nbtsrv, 
209                                          "0.0.0.0",
210                                          primary_address,
211                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
212                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
213                 NT_STATUS_NOT_OK_RETURN(status);
214         }
215
216         for (i=0; i<num_interfaces; i++) {
217                 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
218                 const char *bcast   = talloc_strdup(tmp_ctx, iface_n_bcast(i));
219                 const char *netmask = talloc_strdup(tmp_ctx, iface_n_netmask(i));
220
221                 status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
222                 NT_STATUS_NOT_OK_RETURN(status);
223         }
224
225         if (lp_wins_server_list()) {
226                 status = nbtd_add_wins_socket(nbtsrv);
227                 NT_STATUS_NOT_OK_RETURN(status);
228         }
229
230         talloc_free(tmp_ctx);
231
232         return NT_STATUS_OK;
233 }
234
235
236 /*
237   form a list of addresses that we should use in name query replies
238   we always place the IP in the given interface first
239 */
240 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
241 {
242         struct nbtd_server *nbtsrv = iface->nbtsrv;
243         const char **ret = NULL;
244         struct nbtd_interface *iface2;
245         int count = 0;
246
247         if (iface->ip_address) {
248                 ret = talloc_array(mem_ctx, const char *, 2);
249                 if (ret == NULL) goto failed;
250
251                 ret[0] = talloc_strdup(ret, iface->ip_address);
252                 if (ret[0] == NULL) goto failed;
253                 ret[1] = NULL;
254
255                 count = 1;
256         }
257
258         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
259                 const char **ret2;
260
261                 if (iface->ip_address &&
262                     strcmp(iface2->ip_address, iface->ip_address) == 0) {
263                         continue;
264                 }
265
266                 ret2 = talloc_realloc(mem_ctx, ret, const char *, count+2);
267                 if (ret2 == NULL) goto failed;
268                 ret = ret2;
269                 ret[count] = talloc_strdup(ret, iface2->ip_address);
270                 if (ret[count] == NULL) goto failed;
271                 count++;
272         }
273         ret[count] = NULL;
274         return ret;
275
276 failed:
277         talloc_free(ret);
278         return NULL;
279 }