~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/nbt_server/wins/winswack.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
 
 
4
   "secure" wins server WACK processing
 
5
 
 
6
   Copyright (C) Andrew Tridgell        2005
 
7
   Copyright (C) Stefan Metzmacher      2005
 
8
   
 
9
   This program is free software; you can redistribute it and/or modify
 
10
   it under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 3 of the License, or
 
12
   (at your option) any later version.
 
13
   
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
   
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
#include "includes.h"
 
24
#include "nbt_server/nbt_server.h"
 
25
#include "nbt_server/wins/winsdb.h"
 
26
#include "nbt_server/wins/winsserver.h"
 
27
#include "system/time.h"
 
28
#include "libcli/composite/composite.h"
 
29
#include "param/param.h"
 
30
#include "smbd/service_task.h"
 
31
 
 
32
struct wins_challenge_state {
 
33
        struct wins_challenge_io *io;
 
34
        uint32_t current_address;
 
35
        struct nbt_name_query query;
 
36
};
 
37
 
 
38
static void wins_challenge_handler(struct nbt_name_request *req)
 
39
{
 
40
        struct composite_context *ctx = talloc_get_type(req->async.private_data, struct composite_context);
 
41
        struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
 
42
 
 
43
        ctx->status = nbt_name_query_recv(req, state, &state->query);
 
44
 
 
45
        /* if we timed out then try the next owner address, if any */
 
46
        if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_IO_TIMEOUT)) {
 
47
                state->current_address++;
 
48
                if (state->current_address < state->io->in.num_addresses) {
 
49
                        struct nbtd_interface *iface;
 
50
 
 
51
                        state->query.in.dest_port = state->io->in.nbt_port;
 
52
                        state->query.in.dest_addr = state->io->in.addresses[state->current_address];
 
53
                        
 
54
                        iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->query.in.dest_addr, true);
 
55
                        if (!iface) {
 
56
                                composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
 
57
                                return;
 
58
                        }
 
59
 
 
60
                        ZERO_STRUCT(state->query.out);
 
61
                        req = nbt_name_query_send(iface->nbtsock, &state->query);
 
62
                        composite_continue_nbt(ctx, req, wins_challenge_handler, ctx);
 
63
                        return;
 
64
                }
 
65
        }
 
66
 
 
67
        composite_done(ctx);
 
68
}
 
69
 
 
70
NTSTATUS wins_challenge_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
 
71
{
 
72
        NTSTATUS status = ctx->status;
 
73
        struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
 
74
 
 
75
        if (NT_STATUS_IS_OK(status)) {
 
76
                io->out.num_addresses   = state->query.out.num_addrs;
 
77
                io->out.addresses       = state->query.out.reply_addrs;
 
78
                talloc_steal(mem_ctx, io->out.addresses);
 
79
        } else {
 
80
                ZERO_STRUCT(io->out);
 
81
        }
 
82
 
 
83
        talloc_free(ctx);
 
84
        return status;
 
85
}
 
86
 
 
87
struct composite_context *wins_challenge_send(TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
 
88
{
 
89
        struct composite_context *result;
 
90
        struct wins_challenge_state *state;
 
91
        struct nbt_name_request *req;
 
92
        struct nbtd_interface *iface;
 
93
 
 
94
        result = talloc_zero(mem_ctx, struct composite_context);
 
95
        if (result == NULL) return NULL;
 
96
        result->state = COMPOSITE_STATE_IN_PROGRESS;
 
97
        result->event_ctx = talloc_reference(result, io->in.event_ctx);
 
98
 
 
99
        state = talloc_zero(result, struct wins_challenge_state);
 
100
        if (state == NULL) goto failed;
 
101
        result->private_data = state;
 
102
 
 
103
        /* package up the state variables for this wack request */
 
104
        state->io               = io;
 
105
        state->current_address  = 0;
 
106
 
 
107
        /* setup a name query to the first address */
 
108
        state->query.in.name        = *state->io->in.name;
 
109
        state->query.in.dest_port   = state->io->in.nbt_port;
 
110
        state->query.in.dest_addr   = state->io->in.addresses[state->current_address];
 
111
        state->query.in.broadcast   = false;
 
112
        state->query.in.wins_lookup = true;
 
113
        state->query.in.timeout     = 1;
 
114
        state->query.in.retries     = 2;
 
115
        ZERO_STRUCT(state->query.out);
 
116
 
 
117
        iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->query.in.dest_addr, true);
 
118
        if (!iface) {
 
119
                goto failed;
 
120
        }
 
121
 
 
122
        req = nbt_name_query_send(iface->nbtsock, &state->query);
 
123
        if (req == NULL) goto failed;
 
124
 
 
125
        req->async.fn = wins_challenge_handler;
 
126
        req->async.private_data = result;
 
127
 
 
128
        return result;
 
129
failed:
 
130
        talloc_free(result);
 
131
        return NULL;
 
132
}
 
133
 
 
134
struct wins_release_demand_io {
 
135
        struct {
 
136
                struct nbtd_server *nbtd_server;
 
137
                struct tevent_context *event_ctx;
 
138
                struct nbt_name *name;
 
139
                uint16_t nb_flags;
 
140
                uint32_t num_addresses;
 
141
                const char **addresses;
 
142
        } in;
 
143
};
 
144
 
 
145
struct wins_release_demand_state {
 
146
        struct wins_release_demand_io *io;
 
147
        uint32_t current_address;
 
148
        uint32_t addresses_left;
 
149
        struct nbt_name_release release;
 
150
};
 
151
 
 
152
static void wins_release_demand_handler(struct nbt_name_request *req)
 
153
{
 
154
        struct composite_context *ctx = talloc_get_type(req->async.private_data, struct composite_context);
 
155
        struct wins_release_demand_state *state = talloc_get_type(ctx->private_data, struct wins_release_demand_state);
 
156
 
 
157
        ctx->status = nbt_name_release_recv(req, state, &state->release);
 
158
 
 
159
        /* if we timed out then try the next owner address, if any */
 
160
        if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_IO_TIMEOUT)) {
 
161
                state->current_address++;
 
162
                state->addresses_left--;
 
163
                if (state->current_address < state->io->in.num_addresses) {
 
164
                        struct nbtd_interface *iface;
 
165
 
 
166
                        state->release.in.dest_port = lp_nbt_port(state->io->in.nbtd_server->task->lp_ctx);
 
167
                        state->release.in.dest_addr = state->io->in.addresses[state->current_address];
 
168
                        state->release.in.address   = state->release.in.dest_addr;
 
169
                        state->release.in.timeout   = (state->addresses_left > 1 ? 2 : 1);
 
170
                        state->release.in.retries   = (state->addresses_left > 1 ? 0 : 2);
 
171
 
 
172
                        iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->release.in.dest_addr, true);
 
173
                        if (!iface) {
 
174
                                composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
 
175
                                return;
 
176
                        }
 
177
 
 
178
                        ZERO_STRUCT(state->release.out);
 
179
                        req = nbt_name_release_send(iface->nbtsock, &state->release);
 
180
                        composite_continue_nbt(ctx, req, wins_release_demand_handler, ctx);
 
181
                        return;
 
182
                }
 
183
        }
 
184
 
 
185
        composite_done(ctx);
 
186
}
 
187
 
 
188
static NTSTATUS wins_release_demand_recv(struct composite_context *ctx,
 
189
                                         TALLOC_CTX *mem_ctx,
 
190
                                         struct wins_release_demand_io *io)
 
191
{
 
192
        NTSTATUS status = ctx->status;
 
193
        talloc_free(ctx);
 
194
        return status;
 
195
}
 
196
 
 
197
static struct composite_context *wins_release_demand_send(TALLOC_CTX *mem_ctx, struct wins_release_demand_io *io)
 
198
{
 
199
        struct composite_context *result;
 
200
        struct wins_release_demand_state *state;
 
201
        struct nbt_name_request *req;
 
202
        struct nbtd_interface *iface;
 
203
 
 
204
        result = talloc_zero(mem_ctx, struct composite_context);
 
205
        if (result == NULL) return NULL;
 
206
        result->state = COMPOSITE_STATE_IN_PROGRESS;
 
207
        result->event_ctx = talloc_reference(result, io->in.event_ctx);
 
208
 
 
209
        state = talloc_zero(result, struct wins_release_demand_state);
 
210
        if (state == NULL) goto failed;
 
211
        result->private_data = state;
 
212
 
 
213
        /* package up the state variables for this wack request */
 
214
        state->io               = io;
 
215
        state->current_address  = 0;
 
216
        state->addresses_left   = state->io->in.num_addresses;
 
217
 
 
218
        /* 
 
219
         * setup a name query to the first address
 
220
         * - if we have more than one address try the first
 
221
         *   with 2 secs timeout and no retry
 
222
         * - otherwise use 1 sec timeout (w2k3 uses 0.5 sec here)
 
223
         *   with 2 retries
 
224
         */
 
225
        state->release.in.name        = *state->io->in.name;
 
226
        state->release.in.dest_port   = lp_nbt_port(state->io->in.nbtd_server->task->lp_ctx);
 
227
        state->release.in.dest_addr   = state->io->in.addresses[state->current_address];
 
228
        state->release.in.address     = state->release.in.dest_addr;
 
229
        state->release.in.broadcast   = false;
 
230
        state->release.in.timeout     = (state->addresses_left > 1 ? 2 : 1);
 
231
        state->release.in.retries     = (state->addresses_left > 1 ? 0 : 2);
 
232
        ZERO_STRUCT(state->release.out);
 
233
 
 
234
        iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->release.in.dest_addr, true);
 
235
        if (!iface) {
 
236
                goto failed;
 
237
        }
 
238
 
 
239
        req = nbt_name_release_send(iface->nbtsock, &state->release);
 
240
        if (req == NULL) goto failed;
 
241
 
 
242
        req->async.fn = wins_release_demand_handler;
 
243
        req->async.private_data = result;
 
244
 
 
245
        return result;
 
246
failed:
 
247
        talloc_free(result);
 
248
        return NULL;
 
249
}
 
250
 
 
251
/*
 
252
  wrepl_server needs to be able to do a name query request, but some windows
 
253
  servers always send the reply to port 137, regardless of the request
 
254
  port. To cope with this we use a irpc request to the NBT server
 
255
  which has port 137 open, and thus can receive the replies
 
256
*/
 
257
struct proxy_wins_challenge_state {
 
258
        struct irpc_message *msg;
 
259
        struct nbtd_proxy_wins_challenge *req;
 
260
        struct wins_challenge_io io;
 
261
        struct composite_context *c_req;
 
262
};
 
263
 
 
264
static void proxy_wins_challenge_handler(struct composite_context *c_req)
 
265
{
 
266
        NTSTATUS status;
 
267
        uint32_t i;
 
268
        struct proxy_wins_challenge_state *s = talloc_get_type(c_req->async.private_data,
 
269
                                                               struct proxy_wins_challenge_state);
 
270
 
 
271
        status = wins_challenge_recv(s->c_req, s, &s->io);
 
272
        if (!NT_STATUS_IS_OK(status)) {
 
273
                ZERO_STRUCT(s->req->out);
 
274
                irpc_send_reply(s->msg, status);
 
275
                return;
 
276
        }
 
277
 
 
278
        s->req->out.num_addrs   = s->io.out.num_addresses;              
 
279
        /* TODO: fix pidl to handle inline ipv4address arrays */
 
280
        s->req->out.addrs       = talloc_array(s->msg, struct nbtd_proxy_wins_addr,
 
281
                                               s->io.out.num_addresses);
 
282
        if (!s->req->out.addrs) {
 
283
                ZERO_STRUCT(s->req->out);
 
284
                irpc_send_reply(s->msg, NT_STATUS_NO_MEMORY);
 
285
                return;
 
286
        }
 
287
        for (i=0; i < s->io.out.num_addresses; i++) {
 
288
                s->req->out.addrs[i].addr = talloc_steal(s->req->out.addrs, s->io.out.addresses[i]);
 
289
        }
 
290
 
 
291
        irpc_send_reply(s->msg, status);
 
292
}
 
293
 
 
294
NTSTATUS nbtd_proxy_wins_challenge(struct irpc_message *msg, 
 
295
                                   struct nbtd_proxy_wins_challenge *req)
 
296
{
 
297
        struct nbtd_server *nbtd_server =
 
298
                talloc_get_type(msg->private_data, struct nbtd_server);
 
299
        struct proxy_wins_challenge_state *s;
 
300
        uint32_t i;
 
301
 
 
302
        s = talloc(msg, struct proxy_wins_challenge_state);
 
303
        NT_STATUS_HAVE_NO_MEMORY(s);
 
304
 
 
305
        s->msg = msg;
 
306
        s->req = req;
 
307
 
 
308
        s->io.in.nbtd_server    = nbtd_server;
 
309
        s->io.in.nbt_port       = lp_nbt_port(nbtd_server->task->lp_ctx);
 
310
        s->io.in.event_ctx      = msg->ev;
 
311
        s->io.in.name           = &req->in.name;
 
312
        s->io.in.num_addresses  = req->in.num_addrs;
 
313
        s->io.in.addresses      = talloc_array(s, const char *, req->in.num_addrs);
 
314
        NT_STATUS_HAVE_NO_MEMORY(s->io.in.addresses);
 
315
        /* TODO: fix pidl to handle inline ipv4address arrays */
 
316
        for (i=0; i < req->in.num_addrs; i++) {
 
317
                s->io.in.addresses[i]   = talloc_steal(s->io.in.addresses, req->in.addrs[i].addr);
 
318
        }
 
319
 
 
320
        s->c_req = wins_challenge_send(s, &s->io);
 
321
        NT_STATUS_HAVE_NO_MEMORY(s->c_req);
 
322
 
 
323
        s->c_req->async.fn              = proxy_wins_challenge_handler;
 
324
        s->c_req->async.private_data    = s;
 
325
 
 
326
        msg->defer_reply = true;
 
327
        return NT_STATUS_OK;
 
328
}
 
329
 
 
330
/*
 
331
  wrepl_server needs to be able to do a name release demands, but some windows
 
332
  servers always send the reply to port 137, regardless of the request
 
333
  port. To cope with this we use a irpc request to the NBT server
 
334
  which has port 137 open, and thus can receive the replies
 
335
*/
 
336
struct proxy_wins_release_demand_state {
 
337
        struct irpc_message *msg;
 
338
        struct nbtd_proxy_wins_release_demand *req;
 
339
        struct wins_release_demand_io io;
 
340
        struct composite_context *c_req;
 
341
};
 
342
 
 
343
static void proxy_wins_release_demand_handler(struct composite_context *c_req)
 
344
{
 
345
        NTSTATUS status;
 
346
        struct proxy_wins_release_demand_state *s = talloc_get_type(c_req->async.private_data,
 
347
                                                               struct proxy_wins_release_demand_state);
 
348
 
 
349
        status = wins_release_demand_recv(s->c_req, s, &s->io);
 
350
 
 
351
        irpc_send_reply(s->msg, status);
 
352
}
 
353
 
 
354
NTSTATUS nbtd_proxy_wins_release_demand(struct irpc_message *msg, 
 
355
                                   struct nbtd_proxy_wins_release_demand *req)
 
356
{
 
357
        struct nbtd_server *nbtd_server =
 
358
                talloc_get_type(msg->private_data, struct nbtd_server);
 
359
        struct proxy_wins_release_demand_state *s;
 
360
        uint32_t i;
 
361
 
 
362
        s = talloc(msg, struct proxy_wins_release_demand_state);
 
363
        NT_STATUS_HAVE_NO_MEMORY(s);
 
364
 
 
365
        s->msg = msg;
 
366
        s->req = req;
 
367
 
 
368
        s->io.in.nbtd_server    = nbtd_server;
 
369
        s->io.in.event_ctx      = msg->ev;
 
370
        s->io.in.name           = &req->in.name;
 
371
        s->io.in.num_addresses  = req->in.num_addrs;
 
372
        s->io.in.addresses      = talloc_array(s, const char *, req->in.num_addrs);
 
373
        NT_STATUS_HAVE_NO_MEMORY(s->io.in.addresses);
 
374
        /* TODO: fix pidl to handle inline ipv4address arrays */
 
375
        for (i=0; i < req->in.num_addrs; i++) {
 
376
                s->io.in.addresses[i]   = talloc_steal(s->io.in.addresses, req->in.addrs[i].addr);
 
377
        }
 
378
 
 
379
        s->c_req = wins_release_demand_send(s, &s->io);
 
380
        NT_STATUS_HAVE_NO_MEMORY(s->c_req);
 
381
 
 
382
        s->c_req->async.fn              = proxy_wins_release_demand_handler;
 
383
        s->c_req->async.private_data    = s;
 
384
 
 
385
        msg->defer_reply = true;
 
386
        return NT_STATUS_OK;
 
387
}