~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libcli/cldap/cldap.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
   cldap client library
 
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
/*
 
23
  see RFC1798 for details of CLDAP
 
24
 
 
25
  basic properties
 
26
    - carried over UDP on port 389
 
27
    - request and response matched by message ID
 
28
    - request consists of only a single searchRequest element
 
29
    - response can be in one of two forms
 
30
       - a single searchResponse, followed by a searchResult
 
31
       - a single searchResult
 
32
*/
 
33
 
 
34
#include "includes.h"
 
35
#include "lib/events/events.h"
 
36
#include "../lib/util/dlinklist.h"
 
37
#include "libcli/ldap/ldap.h"
 
38
#include "libcli/ldap/ldap_ndr.h"
 
39
#include "libcli/cldap/cldap.h"
 
40
#include "lib/socket/socket.h"
 
41
#include "libcli/security/security.h"
 
42
#include "librpc/gen_ndr/ndr_nbt.h"
 
43
 
 
44
/*
 
45
  destroy a pending request
 
46
*/
 
47
static int cldap_request_destructor(struct cldap_request *req)
 
48
{
 
49
        if (req->state == CLDAP_REQUEST_SEND) {
 
50
                DLIST_REMOVE(req->cldap->send_queue, req);
 
51
        }
 
52
        if (!req->is_reply && req->message_id != 0) {
 
53
                idr_remove(req->cldap->idr, req->message_id);
 
54
                req->message_id = 0;
 
55
        }
 
56
        return 0;
 
57
}
 
58
 
 
59
/*
 
60
  handle recv events on a cldap socket
 
61
*/
 
62
static void cldap_socket_recv(struct cldap_socket *cldap)
 
63
{
 
64
        TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 
65
        NTSTATUS status;
 
66
        struct socket_address *src;
 
67
        DATA_BLOB blob;
 
68
        size_t nread, dsize;
 
69
        struct asn1_data *asn1 = asn1_init(tmp_ctx);
 
70
        struct ldap_message *ldap_msg;
 
71
        struct cldap_request *req;
 
72
 
 
73
        if (!asn1) return;
 
74
 
 
75
        status = socket_pending(cldap->sock, &dsize);
 
76
        if (!NT_STATUS_IS_OK(status)) {
 
77
                talloc_free(tmp_ctx);
 
78
                return;
 
79
        }
 
80
 
 
81
        blob = data_blob_talloc(tmp_ctx, NULL, dsize);
 
82
        if (blob.data == NULL) {
 
83
                talloc_free(tmp_ctx);
 
84
                return;
 
85
        }
 
86
 
 
87
        status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread,
 
88
                                 tmp_ctx, &src);
 
89
        if (!NT_STATUS_IS_OK(status)) {
 
90
                talloc_free(tmp_ctx);
 
91
                return;
 
92
        }
 
93
        blob.length = nread;
 
94
 
 
95
        DEBUG(2,("Received cldap packet of length %d from %s:%d\n", 
 
96
                 (int)blob.length, src->addr, src->port));
 
97
 
 
98
        if (!asn1_load(asn1, blob)) {
 
99
                DEBUG(2,("Failed to setup for asn.1 decode\n"));
 
100
                talloc_free(tmp_ctx);
 
101
                return;
 
102
        }
 
103
 
 
104
        ldap_msg = talloc(tmp_ctx, struct ldap_message);
 
105
        if (ldap_msg == NULL) {
 
106
                talloc_free(tmp_ctx);
 
107
                return;
 
108
        }
 
109
 
 
110
        /* this initial decode is used to find the message id */
 
111
        status = ldap_decode(asn1, NULL, ldap_msg);
 
112
        if (!NT_STATUS_IS_OK(status)) {
 
113
                DEBUG(2,("Failed to decode ldap message: %s\n", nt_errstr(status)));
 
114
                talloc_free(tmp_ctx);
 
115
                return;
 
116
        }
 
117
 
 
118
        /* find the pending request */
 
119
        req = idr_find(cldap->idr, ldap_msg->messageid);
 
120
        if (req == NULL) {
 
121
                if (cldap->incoming.handler) {
 
122
                        cldap->incoming.handler(cldap, ldap_msg, src);
 
123
                } else {
 
124
                        DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
 
125
                                 ldap_msg->messageid, src->addr, src->port));
 
126
                }
 
127
                talloc_free(tmp_ctx);
 
128
                return;
 
129
        }
 
130
 
 
131
        req->asn1 = talloc_steal(req, asn1);
 
132
        req->asn1->ofs = 0;
 
133
 
 
134
        req->state = CLDAP_REQUEST_DONE;
 
135
        talloc_free(req->te);
 
136
 
 
137
        talloc_free(tmp_ctx);
 
138
 
 
139
        if (req->async.fn) {
 
140
                req->async.fn(req);
 
141
        }
 
142
}
 
143
 
 
144
/*
 
145
  handle request timeouts
 
146
*/
 
147
static void cldap_request_timeout(struct tevent_context *event_ctx, 
 
148
                                  struct tevent_timer *te, struct timeval t,
 
149
                                  void *private_data)
 
150
{
 
151
        struct cldap_request *req = talloc_get_type(private_data, struct cldap_request);
 
152
 
 
153
        /* possibly try again */
 
154
        if (req->num_retries != 0) {
 
155
                size_t len = req->encoded.length;
 
156
 
 
157
                req->num_retries--;
 
158
 
 
159
                socket_sendto(req->cldap->sock, &req->encoded, &len, 
 
160
                              req->dest);
 
161
 
 
162
                req->te = event_add_timed(req->cldap->event_ctx, req, 
 
163
                                          timeval_current_ofs(req->timeout, 0),
 
164
                                          cldap_request_timeout, req);
 
165
                return;
 
166
        }
 
167
 
 
168
        req->state = CLDAP_REQUEST_ERROR;
 
169
        req->status = NT_STATUS_IO_TIMEOUT;
 
170
        if (req->async.fn) {
 
171
                req->async.fn(req);
 
172
        }
 
173
}
 
174
 
 
175
/*
 
176
  handle send events on a cldap socket
 
177
*/
 
178
static void cldap_socket_send(struct cldap_socket *cldap)
 
179
{
 
180
        struct cldap_request *req;
 
181
        NTSTATUS status;
 
182
 
 
183
        while ((req = cldap->send_queue)) {
 
184
                size_t len;
 
185
                
 
186
                len = req->encoded.length;
 
187
                status = socket_sendto(cldap->sock, &req->encoded, &len,
 
188
                                       req->dest);
 
189
                if (NT_STATUS_IS_ERR(status)) {
 
190
                        DEBUG(0,("Failed to send cldap request of length %u to %s:%d\n",
 
191
                                 (unsigned)req->encoded.length, req->dest->addr, req->dest->port));
 
192
                        DLIST_REMOVE(cldap->send_queue, req);
 
193
                        req->state = CLDAP_REQUEST_ERROR;
 
194
                        req->status = status;
 
195
                        if (req->async.fn) {
 
196
                                req->async.fn(req);
 
197
                        }
 
198
                        continue;
 
199
                }
 
200
 
 
201
                if (!NT_STATUS_IS_OK(status)) return;
 
202
 
 
203
                DLIST_REMOVE(cldap->send_queue, req);
 
204
 
 
205
                if (req->is_reply) {
 
206
                        talloc_free(req);
 
207
                } else {
 
208
                        req->state = CLDAP_REQUEST_WAIT;
 
209
 
 
210
                        req->te = event_add_timed(cldap->event_ctx, req, 
 
211
                                                  timeval_current_ofs(req->timeout, 0),
 
212
                                                  cldap_request_timeout, req);
 
213
 
 
214
                        EVENT_FD_READABLE(cldap->fde);
 
215
                }
 
216
        }
 
217
 
 
218
        EVENT_FD_NOT_WRITEABLE(cldap->fde);
 
219
        return;
 
220
}
 
221
 
 
222
 
 
223
/*
 
224
  handle fd events on a cldap_socket
 
225
*/
 
226
static void cldap_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
 
227
                                 uint16_t flags, void *private_data)
 
228
{
 
229
        struct cldap_socket *cldap = talloc_get_type(private_data, struct cldap_socket);
 
230
        if (flags & EVENT_FD_WRITE) {
 
231
                cldap_socket_send(cldap);
 
232
        } 
 
233
        if (flags & EVENT_FD_READ) {
 
234
                cldap_socket_recv(cldap);
 
235
        }
 
236
}
 
237
 
 
238
/*
 
239
  initialise a cldap_socket. The event_ctx is optional, if provided
 
240
  then operations will use that event context
 
241
*/
 
242
struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx, 
 
243
                                       struct tevent_context *event_ctx,
 
244
                                       struct smb_iconv_convenience *iconv_convenience)
 
245
{
 
246
        struct cldap_socket *cldap;
 
247
        NTSTATUS status;
 
248
 
 
249
        cldap = talloc(mem_ctx, struct cldap_socket);
 
250
        if (cldap == NULL) goto failed;
 
251
 
 
252
        cldap->event_ctx = talloc_reference(cldap, event_ctx);
 
253
        if (cldap->event_ctx == NULL) goto failed;
 
254
 
 
255
        cldap->idr = idr_init(cldap);
 
256
        if (cldap->idr == NULL) goto failed;
 
257
 
 
258
        status = socket_create("ip", SOCKET_TYPE_DGRAM, &cldap->sock, 0);
 
259
        if (!NT_STATUS_IS_OK(status)) goto failed;
 
260
 
 
261
        talloc_steal(cldap, cldap->sock);
 
262
 
 
263
        cldap->fde = event_add_fd(cldap->event_ctx, cldap, 
 
264
                                      socket_get_fd(cldap->sock), 0,
 
265
                                      cldap_socket_handler, cldap);
 
266
 
 
267
        cldap->send_queue = NULL;
 
268
        cldap->incoming.handler = NULL;
 
269
        cldap->iconv_convenience = iconv_convenience;
 
270
        
 
271
        return cldap;
 
272
 
 
273
failed:
 
274
        talloc_free(cldap);
 
275
        return NULL;
 
276
}
 
277
 
 
278
 
 
279
/*
 
280
  setup a handler for incoming requests
 
281
*/
 
282
NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
 
283
                                  void (*handler)(struct cldap_socket *, struct ldap_message *, 
 
284
                                                  struct socket_address *),
 
285
                                  void *private_data)
 
286
{
 
287
        cldap->incoming.handler = handler;
 
288
        cldap->incoming.private_data = private_data;
 
289
        EVENT_FD_READABLE(cldap->fde);
 
290
        return NT_STATUS_OK;
 
291
}
 
292
 
 
293
/*
 
294
  queue a cldap request for send
 
295
*/
 
296
struct cldap_request *cldap_search_send(struct cldap_socket *cldap, 
 
297
                                        struct cldap_search *io)
 
298
{
 
299
        struct ldap_message *msg;
 
300
        struct cldap_request *req;
 
301
        struct ldap_SearchRequest *search;
 
302
 
 
303
        req = talloc_zero(cldap, struct cldap_request);
 
304
        if (req == NULL) goto failed;
 
305
 
 
306
        req->cldap       = cldap;
 
307
        req->state       = CLDAP_REQUEST_SEND;
 
308
        req->timeout     = io->in.timeout;
 
309
        req->num_retries = io->in.retries;
 
310
        req->is_reply    = false;
 
311
        req->asn1        = asn1_init(req);
 
312
        if (!req->asn1) {
 
313
                goto failed;
 
314
        }
 
315
 
 
316
        req->dest = socket_address_from_strings(req, cldap->sock->backend_name,
 
317
                                                io->in.dest_address, 
 
318
                                                io->in.dest_port);
 
319
        if (!req->dest) goto failed;
 
320
 
 
321
        req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
 
322
        if (req->message_id == -1) goto failed;
 
323
 
 
324
        talloc_set_destructor(req, cldap_request_destructor);
 
325
 
 
326
        msg = talloc(req, struct ldap_message);
 
327
        if (msg == NULL) goto failed;
 
328
        msg->messageid       = req->message_id;
 
329
        msg->type            = LDAP_TAG_SearchRequest;
 
330
        msg->controls        = NULL;
 
331
        search = &msg->r.SearchRequest;
 
332
 
 
333
        search->basedn         = "";
 
334
        search->scope          = LDAP_SEARCH_SCOPE_BASE;
 
335
        search->deref          = LDAP_DEREFERENCE_NEVER;
 
336
        search->timelimit      = 0;
 
337
        search->sizelimit      = 0;
 
338
        search->attributesonly = false;
 
339
        search->num_attributes = str_list_length(io->in.attributes);
 
340
        search->attributes     = io->in.attributes;
 
341
        search->tree           = ldb_parse_tree(req, io->in.filter);
 
342
        if (search->tree == NULL) {
 
343
                goto failed;
 
344
        }
 
345
 
 
346
        if (!ldap_encode(msg, NULL, &req->encoded, req)) {
 
347
                DEBUG(0,("Failed to encode cldap message to %s:%d\n",
 
348
                         req->dest->addr, req->dest->port));
 
349
                goto failed;
 
350
        }
 
351
 
 
352
        DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
 
353
 
 
354
        EVENT_FD_WRITEABLE(cldap->fde);
 
355
 
 
356
        return req;
 
357
 
 
358
failed:
 
359
        talloc_free(req);
 
360
        return NULL;
 
361
}
 
362
 
 
363
 
 
364
/*
 
365
  queue a cldap reply for send
 
366
*/
 
367
NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
 
368
{
 
369
        struct ldap_message *msg;
 
370
        struct cldap_request *req;
 
371
        DATA_BLOB blob1, blob2;
 
372
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
373
 
 
374
        req = talloc_zero(cldap, struct cldap_request);
 
375
        if (req == NULL) goto failed;
 
376
 
 
377
        req->cldap       = cldap;
 
378
        req->state       = CLDAP_REQUEST_SEND;
 
379
        req->is_reply    = true;
 
380
        req->asn1        = asn1_init(req);
 
381
        if (!req->asn1) {
 
382
                goto failed;
 
383
        }
 
384
 
 
385
        req->dest        = io->dest;
 
386
        if (talloc_reference(req, io->dest) == NULL) goto failed;
 
387
 
 
388
        talloc_set_destructor(req, cldap_request_destructor);
 
389
 
 
390
        msg = talloc(req, struct ldap_message);
 
391
        if (msg == NULL) goto failed;
 
392
        msg->messageid       = io->messageid;
 
393
        msg->controls        = NULL;
 
394
        
 
395
        if (io->response) {
 
396
                msg->type = LDAP_TAG_SearchResultEntry;
 
397
                msg->r.SearchResultEntry = *io->response;
 
398
 
 
399
                if (!ldap_encode(msg, NULL, &blob1, req)) {
 
400
                        DEBUG(0,("Failed to encode cldap message to %s:%d\n",
 
401
                                 req->dest->addr, req->dest->port));
 
402
                        status = NT_STATUS_INVALID_PARAMETER;
 
403
                        goto failed;
 
404
                }
 
405
        } else {
 
406
                blob1 = data_blob(NULL, 0);
 
407
        }
 
408
 
 
409
        msg->type = LDAP_TAG_SearchResultDone;
 
410
        msg->r.SearchResultDone = *io->result;
 
411
 
 
412
        if (!ldap_encode(msg, NULL, &blob2, req)) {
 
413
                DEBUG(0,("Failed to encode cldap message to %s:%d\n",
 
414
                         req->dest->addr, req->dest->port));
 
415
                status = NT_STATUS_INVALID_PARAMETER;
 
416
                goto failed;
 
417
        }
 
418
 
 
419
        req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
 
420
        if (req->encoded.data == NULL) goto failed;
 
421
 
 
422
        memcpy(req->encoded.data, blob1.data, blob1.length);
 
423
        memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
 
424
 
 
425
        DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
 
426
 
 
427
        EVENT_FD_WRITEABLE(cldap->fde);
 
428
 
 
429
        return NT_STATUS_OK;
 
430
 
 
431
failed:
 
432
        talloc_free(req);
 
433
        return status;
 
434
}
 
435
 
 
436
/*
 
437
  receive a cldap reply
 
438
*/
 
439
NTSTATUS cldap_search_recv(struct cldap_request *req, 
 
440
                           TALLOC_CTX *mem_ctx, 
 
441
                           struct cldap_search *io)
 
442
{
 
443
        struct ldap_message *ldap_msg;
 
444
        NTSTATUS status;
 
445
 
 
446
        if (req == NULL) {
 
447
                return NT_STATUS_NO_MEMORY;
 
448
        }
 
449
 
 
450
        while (req->state < CLDAP_REQUEST_DONE) {
 
451
                if (event_loop_once(req->cldap->event_ctx) != 0) {
 
452
                        talloc_free(req);
 
453
                        return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 
454
                }
 
455
        }
 
456
 
 
457
        if (req->state == CLDAP_REQUEST_ERROR) {
 
458
                status = req->status;
 
459
                talloc_free(req);
 
460
                return status;
 
461
        }
 
462
 
 
463
        ldap_msg = talloc(mem_ctx, struct ldap_message);
 
464
        NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
 
465
 
 
466
        status = ldap_decode(req->asn1, NULL, ldap_msg);
 
467
        if (!NT_STATUS_IS_OK(status)) {
 
468
                DEBUG(2,("Failed to decode cldap search reply: %s\n", nt_errstr(status)));
 
469
                talloc_free(req);
 
470
                return status;
 
471
        }
 
472
 
 
473
        ZERO_STRUCT(io->out);
 
474
 
 
475
        /* the first possible form has a search result in first place */
 
476
        if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
 
477
                io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
 
478
                NT_STATUS_HAVE_NO_MEMORY(io->out.response);
 
479
                *io->out.response = ldap_msg->r.SearchResultEntry;
 
480
 
 
481
                /* decode the 2nd part */
 
482
                status = ldap_decode(req->asn1, NULL, ldap_msg);
 
483
                if (!NT_STATUS_IS_OK(status)) {
 
484
                        DEBUG(2,("Failed to decode cldap search result entry: %s\n", nt_errstr(status)));
 
485
                        talloc_free(req);
 
486
                        return status;
 
487
                }
 
488
        }
 
489
 
 
490
        if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
 
491
                talloc_free(req);
 
492
                return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
 
493
        }
 
494
 
 
495
        io->out.result = talloc(mem_ctx, struct ldap_Result);
 
496
        NT_STATUS_HAVE_NO_MEMORY(io->out.result);
 
497
        *io->out.result = ldap_msg->r.SearchResultDone;
 
498
 
 
499
        talloc_free(req);
 
500
 
 
501
        if (io->out.result->resultcode != LDAP_SUCCESS) {
 
502
                return NT_STATUS_LDAP(io->out.result->resultcode);
 
503
        }
 
504
        return NT_STATUS_OK;
 
505
}
 
506
 
 
507
 
 
508
/*
 
509
  synchronous cldap search
 
510
*/
 
511
NTSTATUS cldap_search(struct cldap_socket *cldap, 
 
512
                      TALLOC_CTX *mem_ctx, 
 
513
                      struct cldap_search *io)
 
514
{
 
515
        struct cldap_request *req = cldap_search_send(cldap, io);
 
516
        return cldap_search_recv(req, mem_ctx, io);
 
517
}
 
518
 
 
519
 
 
520
 
 
521
/*
 
522
  queue a cldap netlogon for send
 
523
*/
 
524
struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap, 
 
525
                                          struct cldap_netlogon *io)
 
526
{
 
527
        struct cldap_search search;
 
528
        char *filter;
 
529
        struct cldap_request *req;
 
530
        const char *attr[] = { "NetLogon", NULL };
 
531
        TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 
532
 
 
533
        filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)", 
 
534
                                 ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
 
535
        if (filter == NULL) goto failed;
 
536
        if (io->in.user) {
 
537
                filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
 
538
                if (filter == NULL) goto failed;
 
539
        }
 
540
        if (io->in.host) {
 
541
                filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
 
542
                if (filter == NULL) goto failed;
 
543
        }
 
544
        if (io->in.realm) {
 
545
                filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
 
546
                if (filter == NULL) goto failed;
 
547
        }
 
548
        if (io->in.acct_control != -1) {
 
549
                filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", 
 
550
                                                ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
 
551
                if (filter == NULL) goto failed;
 
552
        }
 
553
        if (io->in.domain_sid) {
 
554
                struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
 
555
                if (sid == NULL) goto failed;
 
556
                filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
 
557
                                                ldap_encode_ndr_dom_sid(tmp_ctx, sid));
 
558
                if (filter == NULL) goto failed;
 
559
        }
 
560
        if (io->in.domain_guid) {
 
561
                struct GUID guid;
 
562
                NTSTATUS status;
 
563
                status = GUID_from_string(io->in.domain_guid, &guid);
 
564
                if (!NT_STATUS_IS_OK(status)) goto failed;
 
565
                filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
 
566
                                                ldap_encode_ndr_GUID(tmp_ctx, &guid));
 
567
                if (filter == NULL) goto failed;
 
568
        }
 
569
        filter = talloc_asprintf_append_buffer(filter, ")");
 
570
        if (filter == NULL) goto failed;
 
571
 
 
572
        search.in.dest_address = io->in.dest_address;
 
573
        search.in.dest_port    = io->in.dest_port;
 
574
        search.in.filter       = filter;
 
575
        search.in.attributes   = attr;
 
576
        search.in.timeout      = 2;
 
577
        search.in.retries      = 2;
 
578
 
 
579
        req = cldap_search_send(cldap, &search);
 
580
 
 
581
        talloc_free(tmp_ctx);
 
582
        return req;
 
583
failed:
 
584
        talloc_free(tmp_ctx);
 
585
        return NULL;
 
586
}
 
587
 
 
588
 
 
589
/*
 
590
  receive a cldap netlogon reply
 
591
*/
 
592
NTSTATUS cldap_netlogon_recv(struct cldap_request *req, 
 
593
                             TALLOC_CTX *mem_ctx, 
 
594
                             struct cldap_netlogon *io)
 
595
{
 
596
        NTSTATUS status;
 
597
        struct cldap_search search;
 
598
        struct cldap_socket *cldap;
 
599
        DATA_BLOB *data;
 
600
 
 
601
        cldap = req->cldap;
 
602
 
 
603
        status = cldap_search_recv(req, mem_ctx, &search);
 
604
        if (!NT_STATUS_IS_OK(status)) {
 
605
                return status;
 
606
        }
 
607
        if (search.out.response == NULL) {
 
608
                return NT_STATUS_NOT_FOUND;
 
609
        }
 
610
 
 
611
        if (search.out.response->num_attributes != 1 ||
 
612
            strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
 
613
            search.out.response->attributes[0].num_values != 1 ||
 
614
            search.out.response->attributes[0].values->length < 2) {
 
615
                return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 
616
        }
 
617
        data = search.out.response->attributes[0].values;
 
618
 
 
619
        status = pull_netlogon_samlogon_response(data, mem_ctx, req->cldap->iconv_convenience,
 
620
                                                 &io->out.netlogon);
 
621
        if (!NT_STATUS_IS_OK(status)) {
 
622
                return status;
 
623
        }
 
624
        
 
625
        if (io->in.map_response) {
 
626
                map_netlogon_samlogon_response(&io->out.netlogon);
 
627
        }
 
628
        return NT_STATUS_OK;
 
629
}
 
630
 
 
631
/*
 
632
  sync cldap netlogon search
 
633
*/
 
634
NTSTATUS cldap_netlogon(struct cldap_socket *cldap, 
 
635
                        TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
 
636
{
 
637
        struct cldap_request *req = cldap_netlogon_send(cldap, io);
 
638
        return cldap_netlogon_recv(req, mem_ctx, io);
 
639
}
 
640
 
 
641
 
 
642
/*
 
643
  send an empty reply (used on any error, so the client doesn't keep waiting
 
644
  or send the bad request again)
 
645
*/
 
646
NTSTATUS cldap_empty_reply(struct cldap_socket *cldap, 
 
647
                           uint32_t message_id,
 
648
                           struct socket_address *src)
 
649
{
 
650
        NTSTATUS status;
 
651
        struct cldap_reply reply;
 
652
        struct ldap_Result result;
 
653
 
 
654
        reply.messageid    = message_id;
 
655
        reply.dest         = src;
 
656
        reply.response     = NULL;
 
657
        reply.result       = &result;
 
658
 
 
659
        ZERO_STRUCT(result);
 
660
 
 
661
        status = cldap_reply_send(cldap, &reply);
 
662
 
 
663
        return status;
 
664
}
 
665
 
 
666
/*
 
667
  send an error reply (used on any error, so the client doesn't keep waiting
 
668
  or send the bad request again)
 
669
*/
 
670
NTSTATUS cldap_error_reply(struct cldap_socket *cldap, 
 
671
                           uint32_t message_id,
 
672
                           struct socket_address *src,
 
673
                           int resultcode,
 
674
                           const char *errormessage)
 
675
{
 
676
        NTSTATUS status;
 
677
        struct cldap_reply reply;
 
678
        struct ldap_Result result;
 
679
 
 
680
        reply.messageid    = message_id;
 
681
        reply.dest         = src;
 
682
        reply.response     = NULL;
 
683
        reply.result       = &result;
 
684
 
 
685
        ZERO_STRUCT(result);
 
686
        result.resultcode       = resultcode;
 
687
        result.errormessage     = errormessage;
 
688
 
 
689
        status = cldap_reply_send(cldap, &reply);
 
690
 
 
691
        return status;
 
692
}
 
693
 
 
694
 
 
695
/*
 
696
  send a netlogon reply 
 
697
*/
 
698
NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap, 
 
699
                              uint32_t message_id,
 
700
                              struct socket_address *src,
 
701
                              uint32_t version,
 
702
                              struct netlogon_samlogon_response *netlogon)
 
703
{
 
704
        NTSTATUS status;
 
705
        struct cldap_reply reply;
 
706
        struct ldap_SearchResEntry response;
 
707
        struct ldap_Result result;
 
708
        TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 
709
        DATA_BLOB blob;
 
710
 
 
711
        status = push_netlogon_samlogon_response(&blob, tmp_ctx, cldap->iconv_convenience,
 
712
                                                 netlogon);
 
713
        if (!NT_STATUS_IS_OK(status)) {
 
714
                return status;
 
715
        }
 
716
        reply.messageid    = message_id;
 
717
        reply.dest         = src;
 
718
        reply.response     = &response;
 
719
        reply.result       = &result;
 
720
 
 
721
        ZERO_STRUCT(result);
 
722
 
 
723
        response.dn = "";
 
724
        response.num_attributes = 1;
 
725
        response.attributes = talloc(tmp_ctx, struct ldb_message_element);
 
726
        NT_STATUS_HAVE_NO_MEMORY(response.attributes);
 
727
        response.attributes->name = "netlogon";
 
728
        response.attributes->num_values = 1;
 
729
        response.attributes->values = &blob;
 
730
 
 
731
        status = cldap_reply_send(cldap, &reply);
 
732
 
 
733
        talloc_free(tmp_ctx);
 
734
 
 
735
        return status;
 
736
}
 
737
 
 
738