Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : wins client name registration and refresh
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 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 :
22 : #include "includes.h"
23 : #include "nbt_server/nbt_server.h"
24 : #include "nbt_server/wins/winsserver.h"
25 : #include "libcli/composite/composite.h"
26 : #include "lib/events/events.h"
27 : #include "librpc/gen_ndr/ndr_nbt.h"
28 : #include "samba/service_task.h"
29 : #include "param/param.h"
30 :
31 : /* we send WINS client requests using our primary network interface
32 : */
33 389 : static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface)
34 : {
35 389 : struct nbtd_server *nbtsrv = iface->nbtsrv;
36 389 : return nbtsrv->interfaces->nbtsock;
37 : }
38 :
39 :
40 : static void nbtd_wins_refresh(struct tevent_context *ev, struct tevent_timer *te,
41 : struct timeval t, void *private_data);
42 :
43 : /*
44 : retry a WINS name registration
45 : */
46 0 : static void nbtd_wins_register_retry(struct tevent_context *ev, struct tevent_timer *te,
47 : struct timeval t, void *private_data)
48 : {
49 0 : struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
50 0 : nbtd_winsclient_register(iname);
51 0 : }
52 :
53 : /*
54 : start a timer to refresh this name
55 : */
56 0 : static void nbtd_wins_start_refresh_timer(struct nbtd_iface_name *iname)
57 : {
58 0 : uint32_t refresh_time;
59 0 : uint32_t max_refresh_time = lpcfg_parm_int(iname->iface->nbtsrv->task->lp_ctx, NULL, "nbtd", "max_refresh_time", 7200);
60 :
61 0 : refresh_time = MIN(max_refresh_time, iname->ttl/2);
62 :
63 0 : tevent_add_timer(iname->iface->nbtsrv->task->event_ctx,
64 : iname,
65 : timeval_add(&iname->registration_time, refresh_time, 0),
66 : nbtd_wins_refresh, iname);
67 0 : }
68 :
69 : struct nbtd_wins_refresh_state {
70 : struct nbtd_iface_name *iname;
71 : struct nbt_name_refresh_wins io;
72 : };
73 :
74 : /*
75 : called when a wins name refresh has completed
76 : */
77 0 : static void nbtd_wins_refresh_handler(struct tevent_req *subreq)
78 : {
79 0 : NTSTATUS status;
80 0 : struct nbtd_wins_refresh_state *state =
81 0 : tevent_req_callback_data(subreq,
82 : struct nbtd_wins_refresh_state);
83 0 : struct nbtd_iface_name *iname = state->iname;
84 :
85 0 : status = nbt_name_refresh_wins_recv(subreq, state, &state->io);
86 0 : TALLOC_FREE(subreq);
87 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
88 : /* our WINS server is dead - start registration over
89 : from scratch */
90 0 : DEBUG(2,("Failed to refresh %s with WINS server %s\n",
91 : nbt_name_string(state, &iname->name), iname->wins_server));
92 0 : talloc_free(state);
93 0 : nbtd_winsclient_register(iname);
94 0 : return;
95 : }
96 :
97 0 : if (!NT_STATUS_IS_OK(status)) {
98 0 : DEBUG(1,("Name refresh failure with WINS for %s - %s\n",
99 : nbt_name_string(state, &iname->name), nt_errstr(status)));
100 0 : talloc_free(state);
101 0 : return;
102 : }
103 :
104 0 : if (state->io.out.rcode != 0) {
105 0 : DEBUG(1,("WINS server %s rejected name refresh of %s - %s\n",
106 : state->io.out.wins_server,
107 : nbt_name_string(state, &iname->name),
108 : nt_errstr(nbt_rcode_to_ntstatus(state->io.out.rcode))));
109 0 : iname->nb_flags |= NBT_NM_CONFLICT;
110 0 : talloc_free(state);
111 0 : return;
112 : }
113 :
114 0 : DEBUG(4,("Refreshed name %s with WINS server %s\n",
115 : nbt_name_string(state, &iname->name), iname->wins_server));
116 : /* success - start a periodic name refresh */
117 0 : iname->nb_flags |= NBT_NM_ACTIVE;
118 0 : if (iname->wins_server) {
119 : /*
120 : * talloc_free() would generate a warning,
121 : * so steal it into the tmp context
122 : */
123 0 : talloc_steal(state, iname->wins_server);
124 : }
125 0 : iname->wins_server = talloc_move(iname, &state->io.out.wins_server);
126 0 : iname->registration_time = timeval_current();
127 :
128 0 : talloc_free(state);
129 :
130 0 : nbtd_wins_start_refresh_timer(iname);
131 : }
132 :
133 :
134 : /*
135 : refresh a WINS name registration
136 : */
137 0 : static void nbtd_wins_refresh(struct tevent_context *ev, struct tevent_timer *te,
138 : struct timeval t, void *private_data)
139 : {
140 0 : struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
141 0 : struct nbtd_interface *iface = iname->iface;
142 0 : struct nbt_name_socket *nbtsock = wins_socket(iface);
143 0 : struct tevent_req *subreq;
144 0 : struct nbtd_wins_refresh_state *state;
145 0 : char **l;
146 :
147 0 : state = talloc_zero(iname, struct nbtd_wins_refresh_state);
148 0 : if (state == NULL) {
149 0 : return;
150 : }
151 :
152 0 : state->iname = iname;
153 :
154 : /* setup a wins name refresh request */
155 0 : state->io.in.name = iname->name;
156 0 : l = str_list_make_single(state, iname->wins_server);
157 0 : state->io.in.wins_servers = discard_const_p(const char *, l);
158 0 : state->io.in.wins_port = lpcfg_nbt_port(iface->nbtsrv->task->lp_ctx);
159 0 : state->io.in.addresses = nbtd_address_list(iface, state);
160 0 : state->io.in.nb_flags = iname->nb_flags;
161 0 : state->io.in.ttl = iname->ttl;
162 :
163 0 : if (!state->io.in.addresses) {
164 0 : talloc_free(state);
165 0 : return;
166 : }
167 :
168 0 : subreq = nbt_name_refresh_wins_send(state, ev, nbtsock, &state->io);
169 0 : if (subreq == NULL) {
170 0 : talloc_free(state);
171 0 : return;
172 : }
173 :
174 0 : tevent_req_set_callback(subreq, nbtd_wins_refresh_handler, state);
175 : }
176 :
177 : struct nbtd_wins_register_state {
178 : struct nbtd_iface_name *iname;
179 : struct nbt_name_register_wins io;
180 : };
181 :
182 : /*
183 : called when a wins name register has completed
184 : */
185 389 : static void nbtd_wins_register_handler(struct tevent_req *subreq)
186 : {
187 12 : NTSTATUS status;
188 12 : struct nbtd_wins_register_state *state =
189 389 : tevent_req_callback_data(subreq,
190 : struct nbtd_wins_register_state);
191 389 : struct nbtd_iface_name *iname = state->iname;
192 :
193 389 : status = nbt_name_register_wins_recv(subreq, state, &state->io);
194 389 : TALLOC_FREE(subreq);
195 389 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
196 : /* none of the WINS servers responded - try again
197 : periodically */
198 0 : int wins_retry_time = lpcfg_parm_int(iname->iface->nbtsrv->task->lp_ctx, NULL, "nbtd", "wins_retry", 300);
199 0 : tevent_add_timer(iname->iface->nbtsrv->task->event_ctx,
200 : iname,
201 : timeval_current_ofs(wins_retry_time, 0),
202 : nbtd_wins_register_retry,
203 : iname);
204 0 : talloc_free(state);
205 0 : return;
206 : }
207 :
208 389 : if (!NT_STATUS_IS_OK(status)) {
209 389 : DEBUG(1,("Name register failure with WINS for %s - %s\n",
210 : nbt_name_string(state, &iname->name), nt_errstr(status)));
211 389 : talloc_free(state);
212 389 : return;
213 : }
214 :
215 0 : if (state->io.out.rcode != 0) {
216 0 : DEBUG(1,("WINS server %s rejected name register of %s - %s\n",
217 : state->io.out.wins_server,
218 : nbt_name_string(state, &iname->name),
219 : nt_errstr(nbt_rcode_to_ntstatus(state->io.out.rcode))));
220 0 : iname->nb_flags |= NBT_NM_CONFLICT;
221 0 : talloc_free(state);
222 0 : return;
223 : }
224 :
225 : /* success - start a periodic name refresh */
226 0 : iname->nb_flags |= NBT_NM_ACTIVE;
227 0 : if (iname->wins_server) {
228 : /*
229 : * talloc_free() would generate a warning,
230 : * so steal it into the tmp context
231 : */
232 0 : talloc_steal(state, iname->wins_server);
233 : }
234 0 : iname->wins_server = talloc_move(iname, &state->io.out.wins_server);
235 :
236 0 : iname->registration_time = timeval_current();
237 :
238 0 : DEBUG(3,("Registered %s with WINS server %s\n",
239 : nbt_name_string(state, &iname->name), iname->wins_server));
240 :
241 0 : talloc_free(state);
242 :
243 0 : nbtd_wins_start_refresh_timer(iname);
244 : }
245 :
246 : /*
247 : register a name with our WINS servers
248 : */
249 389 : void nbtd_winsclient_register(struct nbtd_iface_name *iname)
250 : {
251 389 : struct nbtd_interface *iface = iname->iface;
252 389 : struct nbt_name_socket *nbtsock = wins_socket(iface);
253 12 : struct nbtd_wins_register_state *state;
254 12 : struct tevent_req *subreq;
255 :
256 389 : state = talloc_zero(iname, struct nbtd_wins_register_state);
257 389 : if (state == NULL) {
258 0 : return;
259 : }
260 :
261 389 : state->iname = iname;
262 :
263 : /* setup a wins name register request */
264 389 : state->io.in.name = iname->name;
265 389 : state->io.in.wins_port = lpcfg_nbt_port(iface->nbtsrv->task->lp_ctx);
266 389 : state->io.in.wins_servers = lpcfg_wins_server_list(iface->nbtsrv->task->lp_ctx);
267 389 : state->io.in.addresses = nbtd_address_list(iface, state);
268 389 : state->io.in.nb_flags = iname->nb_flags;
269 389 : state->io.in.ttl = iname->ttl;
270 :
271 389 : if (state->io.in.addresses == NULL) {
272 0 : talloc_free(state);
273 0 : return;
274 : }
275 :
276 389 : subreq = nbt_name_register_wins_send(state, iface->nbtsrv->task->event_ctx,
277 : nbtsock, &state->io);
278 389 : if (subreq == NULL) {
279 0 : talloc_free(state);
280 0 : return;
281 : }
282 :
283 389 : tevent_req_set_callback(subreq, nbtd_wins_register_handler, state);
284 : }
|