Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/libads/netlogon_ping.c
Line
Count
Source
1
/*
2
 * Samba Unix/Linux SMB client library
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
#include "replace.h"
19
#include <tevent.h>
20
#include "netlogon_ping.h"
21
#include "libcli/netlogon/netlogon_proto.h"
22
#include "libcli/ldap/ldap_ndr.h"
23
#include "libcli/ldap/ldap_message.h"
24
#include "libcli/cldap/cldap.h"
25
#include "source3/include/tldap.h"
26
#include "source3/include/tldap_util.h"
27
#include "source3/lib/tldap_tls_connect.h"
28
#include "lib/util/tevent_unix.h"
29
#include "lib/util/tevent_ntstatus.h"
30
#include "source4/lib/tls/tls.h"
31
#include "source3/libads/cldap.h"
32
#include "librpc/gen_ndr/netlogon.h"
33
34
#define RETURN_ON_FALSE(x) \
35
0
  if (!(x))          \
36
0
    return false;
37
38
bool check_cldap_reply_required_flags(uint32_t ret_flags, uint32_t req_flags)
39
0
{
40
0
  if (req_flags == 0) {
41
0
    return true;
42
0
  }
43
44
0
  if (req_flags & DS_PDC_REQUIRED)
45
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
46
47
0
  if (req_flags & DS_GC_SERVER_REQUIRED)
48
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
49
50
0
  if (req_flags & DS_ONLY_LDAP_NEEDED)
51
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
52
53
0
  if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
54
0
      (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
55
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
56
57
0
  if (req_flags & DS_KDC_REQUIRED)
58
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
59
60
0
  if (req_flags & DS_TIMESERV_REQUIRED)
61
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
62
63
0
  if (req_flags & DS_WEB_SERVICE_REQUIRED)
64
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_ADS_WEB_SERVICE);
65
66
0
  if (req_flags & DS_WRITABLE_REQUIRED)
67
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
68
69
0
  if (req_flags & DS_DIRECTORY_SERVICE_6_REQUIRED)
70
0
    RETURN_ON_FALSE(ret_flags &
71
0
        (NBT_SERVER_SELECT_SECRET_DOMAIN_6 |
72
0
         NBT_SERVER_FULL_SECRET_DOMAIN_6));
73
74
0
  if (req_flags & DS_DIRECTORY_SERVICE_8_REQUIRED)
75
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_8);
76
77
0
  if (req_flags & DS_DIRECTORY_SERVICE_9_REQUIRED)
78
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_9);
79
80
0
  if (req_flags & DS_DIRECTORY_SERVICE_10_REQUIRED)
81
0
    RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_10);
82
83
0
  return true;
84
0
}
85
86
struct ldap_netlogon_state {
87
  struct tevent_context *ev;
88
  struct tsocket_address *local;
89
  struct tsocket_address *remote;
90
  enum client_netlogon_ping_protocol proto;
91
  const char *filter;
92
93
  struct tstream_context *plain;
94
  struct tldap_context *tldap;
95
  struct tstream_tls_params *tls_params;
96
97
  struct netlogon_samlogon_response *response;
98
};
99
100
static void ldap_netlogon_connected(struct tevent_req *subreq);
101
static void ldap_netlogon_starttls_done(struct tevent_req *subreq);
102
static void ldap_netlogon_tls_set_up(struct tevent_req *subreq);
103
static void ldap_netlogon_search(struct tevent_req *req);
104
static void ldap_netlogon_searched(struct tevent_req *subreq);
105
106
static struct tevent_req *ldap_netlogon_send(
107
  TALLOC_CTX *mem_ctx,
108
  struct tevent_context *ev,
109
  const struct tsocket_address *server,
110
  enum client_netlogon_ping_protocol proto,
111
  const char *filter)
112
0
{
113
0
  struct tevent_req *req = NULL, *subreq = NULL;
114
0
  struct ldap_netlogon_state *state = NULL;
115
0
  uint16_t port;
116
0
  int ret;
117
118
0
  req = tevent_req_create(mem_ctx, &state, struct ldap_netlogon_state);
119
0
  if (req == NULL) {
120
0
    return NULL;
121
0
  }
122
0
  state->ev = ev;
123
0
  state->filter = filter;
124
0
  state->proto = proto;
125
126
0
  state->remote = tsocket_address_copy(server, state);
127
0
  if (tevent_req_nomem(state->remote, req)) {
128
0
    return tevent_req_post(req, ev);
129
0
  }
130
131
0
  port = (proto == CLIENT_NETLOGON_PING_LDAPS) ? 636 : 389;
132
133
0
  ret = tsocket_address_inet_set_port(state->remote, port);
134
0
  if (ret != 0) {
135
0
    tevent_req_nterror(req, map_nt_error_from_unix_common(errno));
136
0
    return tevent_req_post(req, ev);
137
0
  }
138
139
0
  ret = tsocket_address_inet_from_strings(
140
0
    state, "ip", NULL, 0, &state->local);
141
0
  if (ret != 0) {
142
0
    tevent_req_nterror(req, map_nt_error_from_unix_common(errno));
143
0
    return tevent_req_post(req, ev);
144
0
  }
145
146
0
  subreq = tstream_inet_tcp_connect_send(state,
147
0
                 state->ev,
148
0
                 state->local,
149
0
                 state->remote);
150
0
  if (tevent_req_nomem(subreq, req)) {
151
0
    return tevent_req_post(req, ev);
152
0
  }
153
0
  tevent_req_set_callback(subreq, ldap_netlogon_connected, req);
154
155
0
  return req;
156
0
}
157
158
static void ldap_netlogon_connected(struct tevent_req *subreq)
159
0
{
160
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
161
0
                struct tevent_req);
162
0
  struct ldap_netlogon_state *state = tevent_req_data(
163
0
    req, struct ldap_netlogon_state);
164
0
  int ret, err;
165
0
  NTSTATUS status;
166
167
0
  ret = tstream_inet_tcp_connect_recv(
168
0
    subreq, &err, state, &state->plain, NULL);
169
0
  TALLOC_FREE(subreq);
170
0
  if (ret == -1) {
171
0
    tevent_req_nterror(req, map_nt_error_from_unix_common(err));
172
0
    return;
173
0
  }
174
175
0
  state->tldap = tldap_context_create_from_plain_stream(
176
0
    state, &state->plain);
177
0
  if (tevent_req_nomem(state->tldap, req)) {
178
0
    return;
179
0
  }
180
181
0
  if (state->proto == CLIENT_NETLOGON_PING_LDAP) {
182
0
    ldap_netlogon_search(req);
183
0
    return;
184
0
  }
185
186
0
  status = tstream_tls_params_client(state,
187
0
             false,
188
0
             NULL,
189
0
             NULL,
190
0
             NULL,
191
0
             "NORMAL",
192
0
             TLS_VERIFY_PEER_NO_CHECK,
193
0
             NULL,
194
0
             &state->tls_params);
195
0
  if (tevent_req_nterror(req, status)) {
196
0
    DBG_ERR("tstream_tls_params_client(NO_CHECK): %s\n",
197
0
      nt_errstr(status));
198
0
    return;
199
0
  }
200
201
0
  if (state->proto == CLIENT_NETLOGON_PING_STARTTLS) {
202
0
    subreq = tldap_extended_send(state,
203
0
               state->ev,
204
0
               state->tldap,
205
0
               LDB_EXTENDED_START_TLS_OID,
206
0
               NULL,
207
0
               NULL,
208
0
               0,
209
0
               NULL,
210
0
               0);
211
0
    if (tevent_req_nomem(subreq, req)) {
212
0
      return;
213
0
    }
214
0
    tevent_req_set_callback(subreq,
215
0
          ldap_netlogon_starttls_done,
216
0
          req);
217
0
    return;
218
0
  }
219
220
0
  subreq = tldap_tls_connect_send(state,
221
0
          state->ev,
222
0
          state->tldap,
223
0
          state->tls_params);
224
0
  if (tevent_req_nomem(subreq, req)) {
225
0
    return;
226
0
  }
227
0
  tevent_req_set_callback(subreq, ldap_netlogon_tls_set_up, req);
228
0
}
229
230
static void ldap_netlogon_starttls_done(struct tevent_req *subreq)
231
0
{
232
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
233
0
                struct tevent_req);
234
0
  struct ldap_netlogon_state *state = tevent_req_data(
235
0
    req, struct ldap_netlogon_state);
236
0
  TLDAPRC rc;
237
238
0
  rc = tldap_extended_recv(subreq, NULL, NULL, NULL);
239
0
  TALLOC_FREE(subreq);
240
0
  if (!TLDAP_RC_IS_SUCCESS(rc)) {
241
0
    tevent_req_nterror(req, NT_STATUS_LDAP(TLDAP_RC_V(rc)));
242
0
    return;
243
0
  }
244
245
0
  subreq = tldap_tls_connect_send(state,
246
0
          state->ev,
247
0
          state->tldap,
248
0
          state->tls_params);
249
0
  if (tevent_req_nomem(subreq, req)) {
250
0
    return;
251
0
  }
252
0
  tevent_req_set_callback(subreq, ldap_netlogon_tls_set_up, req);
253
0
}
254
255
static void ldap_netlogon_tls_set_up(struct tevent_req *subreq)
256
0
{
257
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
258
0
                struct tevent_req);
259
0
  TLDAPRC rc;
260
261
0
  rc = tldap_tls_connect_recv(subreq);
262
0
  TALLOC_FREE(subreq);
263
0
  if (!TLDAP_RC_IS_SUCCESS(rc)) {
264
0
    tevent_req_nterror(req, NT_STATUS_LDAP(TLDAP_RC_V(rc)));
265
0
    return;
266
0
  }
267
268
0
  ldap_netlogon_search(req);
269
0
}
270
271
static void ldap_netlogon_search(struct tevent_req *req)
272
0
{
273
0
  struct ldap_netlogon_state *state = tevent_req_data(
274
0
    req, struct ldap_netlogon_state);
275
0
  static const char *attrs[] = {"netlogon"};
276
0
  struct tevent_req *subreq = NULL;
277
278
0
  subreq = tldap_search_all_send(state,
279
0
               state->ev,
280
0
               state->tldap,
281
0
               "",
282
0
               TLDAP_SCOPE_BASE,
283
0
               state->filter,
284
0
               attrs,
285
0
               ARRAY_SIZE(attrs),
286
0
               0,
287
0
               NULL,
288
0
               0,
289
0
               NULL,
290
0
               0,
291
0
               0,
292
0
               0,
293
0
               0);
294
0
  if (tevent_req_nomem(subreq, req)) {
295
0
    return;
296
0
  }
297
0
  tevent_req_set_callback(subreq, ldap_netlogon_searched, req);
298
0
}
299
300
static void ldap_netlogon_searched(struct tevent_req *subreq)
301
0
{
302
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
303
0
                struct tevent_req);
304
0
  struct ldap_netlogon_state *state = tevent_req_data(
305
0
    req, struct ldap_netlogon_state);
306
0
  struct tldap_message **msgs = NULL;
307
0
  DATA_BLOB blob = {.data = NULL};
308
0
  NTSTATUS status;
309
0
  TLDAPRC rc;
310
0
  bool ok;
311
312
0
  rc = tldap_search_all_recv(subreq, state, &msgs, NULL);
313
0
  TALLOC_FREE(subreq);
314
0
  if (!TLDAP_RC_IS_SUCCESS(rc)) {
315
0
    tevent_req_nterror(req, NT_STATUS_LDAP(TLDAP_RC_V(rc)));
316
0
    return;
317
0
  }
318
319
0
  if (talloc_array_length(msgs) != 1) {
320
0
    tevent_req_nterror(req,
321
0
           NT_STATUS_LDAP(TLDAP_RC_V(
322
0
             TLDAP_NO_RESULTS_RETURNED)));
323
0
    return;
324
0
  }
325
326
0
  ok = tldap_get_single_valueblob(msgs[0], "netlogon", &blob);
327
0
  if (!ok) {
328
0
    tevent_req_nterror(req,
329
0
           NT_STATUS_LDAP(TLDAP_RC_V(
330
0
             TLDAP_NO_RESULTS_RETURNED)));
331
0
    return;
332
0
  }
333
334
0
  state->response = talloc(state, struct netlogon_samlogon_response);
335
0
  if (tevent_req_nomem(state->response, req)) {
336
0
    return;
337
0
  }
338
339
0
  status = pull_netlogon_samlogon_response(&blob,
340
0
             state->response,
341
0
             state->response);
342
0
  if (!NT_STATUS_IS_OK(status)) {
343
0
    tevent_req_nterror(req, status);
344
0
    return;
345
0
  }
346
347
0
  tevent_req_done(req);
348
0
}
349
350
static NTSTATUS ldap_netlogon_recv(
351
  struct tevent_req *req,
352
  TALLOC_CTX *mem_ctx,
353
  struct netlogon_samlogon_response **response)
354
0
{
355
0
  struct ldap_netlogon_state *state = tevent_req_data(
356
0
    req, struct ldap_netlogon_state);
357
0
  NTSTATUS status;
358
359
0
  if (tevent_req_is_nterror(req, &status)) {
360
0
    return status;
361
0
  }
362
0
  *response = talloc_move(mem_ctx, &state->response);
363
0
  tevent_req_received(req);
364
0
  return NT_STATUS_OK;
365
0
}
366
367
struct cldap_netlogon_ping_state {
368
  struct cldap_socket *sock;
369
  struct cldap_search search;
370
  struct netlogon_samlogon_response *response;
371
};
372
373
static void cldap_netlogon_ping_done(struct tevent_req *subreq);
374
375
static struct tevent_req *cldap_netlogon_ping_send(
376
  TALLOC_CTX *mem_ctx,
377
  struct tevent_context *ev,
378
  const struct tsocket_address *server,
379
  const char *filter)
380
0
{
381
0
  struct tevent_req *req = NULL, *subreq = NULL;
382
0
  struct cldap_netlogon_ping_state *state = NULL;
383
0
  struct tsocket_address *server_389 = NULL;
384
0
  static const char *const attr[] = {"NetLogon", NULL};
385
0
  int ret;
386
0
  NTSTATUS status;
387
388
0
  req = tevent_req_create(mem_ctx,
389
0
        &state,
390
0
        struct cldap_netlogon_ping_state);
391
0
  if (req == NULL) {
392
0
    return NULL;
393
0
  }
394
395
0
  server_389 = tsocket_address_copy(server, state);
396
0
  if (tevent_req_nomem(server_389, req)) {
397
0
    return tevent_req_post(req, ev);
398
0
  }
399
400
0
  ret = tsocket_address_inet_set_port(server_389, 389);
401
0
  if (ret != 0) {
402
0
    tevent_req_nterror(req, map_nt_error_from_unix_common(errno));
403
0
    return tevent_req_post(req, ev);
404
0
  }
405
406
0
  status = cldap_socket_init(state, NULL, server_389, &state->sock);
407
0
  if (tevent_req_nterror(req, status)) {
408
0
    return tevent_req_post(req, ev);
409
0
  }
410
411
0
  state->search = (struct cldap_search){
412
0
    .in.filter = filter,
413
0
    .in.attributes = attr,
414
0
    .in.timeout = 2,
415
0
    .in.retries = 2,
416
0
  };
417
418
0
  subreq = cldap_search_send(state, ev, state->sock, &state->search);
419
0
  if (tevent_req_nomem(subreq, req)) {
420
0
    return tevent_req_post(req, ev);
421
0
  }
422
0
  tevent_req_set_callback(subreq, cldap_netlogon_ping_done, req);
423
0
  return req;
424
0
}
425
426
static void cldap_netlogon_ping_done(struct tevent_req *subreq)
427
0
{
428
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
429
0
                struct tevent_req);
430
0
  struct cldap_netlogon_ping_state *state = tevent_req_data(
431
0
    req, struct cldap_netlogon_ping_state);
432
0
  struct ldap_SearchResEntry *resp = NULL;
433
0
  NTSTATUS status;
434
435
0
  status = cldap_search_recv(subreq, state, &state->search);
436
0
  TALLOC_FREE(subreq);
437
0
  if (tevent_req_nterror(req, status)) {
438
0
    return;
439
0
  }
440
441
0
  TALLOC_FREE(state->sock);
442
443
0
  resp = state->search.out.response;
444
445
0
  if (resp == NULL) {
446
0
    tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
447
0
    return;
448
0
  }
449
450
0
  if (resp->num_attributes != 1 ||
451
0
      !strequal(resp->attributes[0].name, "netlogon") ||
452
0
      resp->attributes[0].num_values != 1 ||
453
0
      resp->attributes[0].values->length < 2)
454
0
  {
455
0
    tevent_req_nterror(req, NT_STATUS_UNEXPECTED_NETWORK_ERROR);
456
0
    return;
457
0
  }
458
459
0
  state->response = talloc(state, struct netlogon_samlogon_response);
460
0
  if (tevent_req_nomem(state->response, req)) {
461
0
    return;
462
0
  }
463
464
0
  status = pull_netlogon_samlogon_response(resp->attributes[0].values,
465
0
             state->response,
466
0
             state->response);
467
0
  if (tevent_req_nterror(req, status)) {
468
0
    return;
469
0
  }
470
0
  tevent_req_done(req);
471
0
}
472
473
static NTSTATUS cldap_netlogon_ping_recv(
474
  struct tevent_req *req,
475
  TALLOC_CTX *mem_ctx,
476
  struct netlogon_samlogon_response **response)
477
0
{
478
0
  struct cldap_netlogon_ping_state *state = tevent_req_data(
479
0
    req, struct cldap_netlogon_ping_state);
480
0
  NTSTATUS status;
481
482
0
  if (tevent_req_is_nterror(req, &status)) {
483
0
    return status;
484
0
  }
485
0
  *response = talloc_move(mem_ctx, &state->response);
486
0
  tevent_req_received(req);
487
0
  return NT_STATUS_OK;
488
0
}
489
490
struct netlogon_ping_state {
491
  struct netlogon_samlogon_response *response;
492
};
493
494
static void netlogon_ping_done_cldap(struct tevent_req *subreq);
495
static void netlogon_ping_done_ldaps(struct tevent_req *subreq);
496
497
static struct tevent_req *netlogon_ping_send(
498
  TALLOC_CTX *mem_ctx,
499
  struct tevent_context *ev,
500
  struct tsocket_address *server,
501
  enum client_netlogon_ping_protocol proto,
502
  const char *filter,
503
  struct timeval timeout)
504
0
{
505
0
  struct tevent_req *req = NULL, *subreq = NULL;
506
0
  struct netlogon_ping_state *state = NULL;
507
508
0
  req = tevent_req_create(mem_ctx, &state, struct netlogon_ping_state);
509
0
  if (req == NULL) {
510
0
    return NULL;
511
0
  }
512
513
0
  switch (proto) {
514
0
  case CLIENT_NETLOGON_PING_CLDAP:
515
0
    subreq = cldap_netlogon_ping_send(state, ev, server, filter);
516
0
    if (tevent_req_nomem(subreq, req)) {
517
0
      return tevent_req_post(req, ev);
518
0
    }
519
0
    tevent_req_set_callback(subreq, netlogon_ping_done_cldap, req);
520
0
    break;
521
0
  case CLIENT_NETLOGON_PING_LDAP:
522
0
  case CLIENT_NETLOGON_PING_LDAPS:
523
0
  case CLIENT_NETLOGON_PING_STARTTLS:
524
0
    subreq = ldap_netlogon_send(state, ev, server, proto, filter);
525
0
    if (tevent_req_nomem(subreq, req)) {
526
0
      return tevent_req_post(req, ev);
527
0
    }
528
0
    tevent_req_set_callback(subreq, netlogon_ping_done_ldaps, req);
529
0
    break;
530
0
  default:
531
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
532
0
    return tevent_req_post(req, ev);
533
0
    break;
534
0
  }
535
536
0
  return req;
537
0
}
538
539
static void netlogon_ping_done_cldap(struct tevent_req *subreq)
540
0
{
541
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
542
0
                struct tevent_req);
543
0
  struct netlogon_ping_state *state = tevent_req_data(
544
0
    req, struct netlogon_ping_state);
545
0
  NTSTATUS status;
546
547
0
  status = cldap_netlogon_ping_recv(subreq, state, &state->response);
548
0
  if (tevent_req_nterror(req, status)) {
549
0
    return;
550
0
  }
551
0
  tevent_req_done(req);
552
0
}
553
554
static void netlogon_ping_done_ldaps(struct tevent_req *subreq)
555
0
{
556
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
557
0
                struct tevent_req);
558
0
  struct netlogon_ping_state *state = tevent_req_data(
559
0
    req, struct netlogon_ping_state);
560
0
  NTSTATUS status;
561
562
0
  status = ldap_netlogon_recv(subreq, state, &state->response);
563
0
  TALLOC_FREE(subreq);
564
0
  if (tevent_req_nterror(req, status)) {
565
0
    return;
566
0
  }
567
0
  tevent_req_done(req);
568
0
}
569
570
static NTSTATUS netlogon_ping_recv(
571
  struct tevent_req *req,
572
  TALLOC_CTX *mem_ctx,
573
  struct netlogon_samlogon_response **response)
574
0
{
575
0
  struct netlogon_ping_state *state = tevent_req_data(
576
0
    req, struct netlogon_ping_state);
577
0
  NTSTATUS status;
578
579
0
  if (tevent_req_is_nterror(req, &status)) {
580
0
    return status;
581
0
  }
582
0
  *response = talloc_move(mem_ctx, &state->response);
583
0
  return NT_STATUS_OK;
584
0
}
585
586
struct netlogon_pings_state {
587
  struct tevent_context *ev;
588
589
  struct tsocket_address **servers;
590
  size_t num_servers;
591
  size_t wanted_servers;
592
  struct timeval timeout;
593
  enum client_netlogon_ping_protocol proto;
594
  uint32_t required_flags;
595
596
  char *filter;
597
  size_t num_sent;
598
  size_t num_received;
599
  size_t num_good_received;
600
  struct tevent_req **reqs;
601
  struct netlogon_samlogon_response **responses;
602
};
603
604
static void netlogon_pings_next(struct tevent_req *subreq);
605
static void netlogon_pings_done(struct tevent_req *subreq);
606
607
struct tevent_req *netlogon_pings_send(TALLOC_CTX *mem_ctx,
608
               struct tevent_context *ev,
609
               enum client_netlogon_ping_protocol proto,
610
               struct tsocket_address **servers,
611
               size_t num_servers,
612
               struct netlogon_ping_filter filter,
613
               size_t wanted_servers,
614
               struct timeval timeout)
615
0
{
616
0
  struct tevent_req *req = NULL;
617
0
  struct netlogon_pings_state *state = NULL;
618
0
  char *filter_str = NULL;
619
0
  size_t i;
620
621
0
  req = tevent_req_create(mem_ctx, &state, struct netlogon_pings_state);
622
0
  if (req == NULL) {
623
0
    return NULL;
624
0
  }
625
0
  state->ev = ev;
626
0
  state->proto = proto;
627
0
  state->servers = servers;
628
0
  state->num_servers = num_servers;
629
0
  state->wanted_servers = wanted_servers;
630
0
  state->timeout = timeout;
631
0
  state->required_flags = filter.required_flags;
632
633
0
  state->reqs = talloc_zero_array(state,
634
0
          struct tevent_req *,
635
0
          num_servers);
636
0
  if (tevent_req_nomem(state->reqs, req)) {
637
0
    return tevent_req_post(req, ev);
638
0
  }
639
640
0
  state->responses = talloc_zero_array(
641
0
    state, struct netlogon_samlogon_response *, num_servers);
642
0
  if (tevent_req_nomem(state->responses, req)) {
643
0
    return tevent_req_post(req, ev);
644
0
  }
645
646
0
  filter_str = talloc_asprintf(state,
647
0
             "(&(NtVer=%s)",
648
0
             ldap_encode_ndr_uint32(state,
649
0
                  filter.ntversion));
650
0
  if (filter.domain != NULL) {
651
0
    talloc_asprintf_addbuf(&filter_str,
652
0
               "(DnsDomain=%s)",
653
0
               filter.domain);
654
0
  }
655
0
  if (filter.acct_ctrl != -1) {
656
0
    talloc_asprintf_addbuf(
657
0
      &filter_str,
658
0
      "(AAC=%s)",
659
0
      ldap_encode_ndr_uint32(mem_ctx, filter.acct_ctrl));
660
0
  }
661
0
  if (filter.domain_sid != NULL) {
662
0
    talloc_asprintf_addbuf(
663
0
      &filter_str,
664
0
      "(domainSid=%s)",
665
0
      ldap_encode_ndr_dom_sid(mem_ctx, filter.domain_sid));
666
0
  }
667
0
  if (filter.domain_guid != NULL) {
668
0
    talloc_asprintf_addbuf(
669
0
      &filter_str,
670
0
      "(DomainGuid=%s)",
671
0
      ldap_encode_ndr_GUID(mem_ctx, filter.domain_guid));
672
0
  }
673
0
  if (filter.hostname != NULL) {
674
0
    talloc_asprintf_addbuf(&filter_str,
675
0
               "(Host=%s)",
676
0
               filter.hostname);
677
0
  }
678
0
  if (filter.user != NULL) {
679
0
    talloc_asprintf_addbuf(&filter_str, "(User=%s)", filter.user);
680
0
  }
681
0
  talloc_asprintf_addbuf(&filter_str, ")");
682
683
0
  if (tevent_req_nomem(filter_str, req)) {
684
0
    return tevent_req_post(req, ev);
685
0
  }
686
0
  state->filter = filter_str;
687
688
0
  for (i = 0; i < wanted_servers; i++) {
689
0
    state->reqs[i] = netlogon_ping_send(state->reqs,
690
0
                state->ev,
691
0
                state->servers[i],
692
0
                state->proto,
693
0
                state->filter,
694
0
                state->timeout);
695
0
    if (tevent_req_nomem(state->reqs[i], req)) {
696
0
      return tevent_req_post(req, ev);
697
0
    }
698
0
    tevent_req_set_callback(state->reqs[i],
699
0
          netlogon_pings_done,
700
0
          req);
701
0
  }
702
0
  state->num_sent = wanted_servers;
703
0
  if (state->num_sent < state->num_servers) {
704
    /*
705
     * After 100 milliseconds fire the next one
706
     */
707
0
    struct tevent_req *subreq = tevent_wakeup_send(
708
0
      state, state->ev, timeval_current_ofs(0, 100000));
709
0
    if (tevent_req_nomem(subreq, req)) {
710
0
      return tevent_req_post(req, ev);
711
0
    }
712
0
    tevent_req_set_callback(subreq, netlogon_pings_next, req);
713
0
  }
714
715
0
  return req;
716
0
}
717
718
static void netlogon_pings_next(struct tevent_req *subreq)
719
0
{
720
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
721
0
                struct tevent_req);
722
0
  struct netlogon_pings_state *state = tevent_req_data(
723
0
    req, struct netlogon_pings_state);
724
0
  bool ret;
725
726
0
  ret = tevent_wakeup_recv(subreq);
727
0
  TALLOC_FREE(subreq);
728
0
  if (!ret) {
729
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
730
0
    return;
731
0
  }
732
733
0
  subreq = netlogon_ping_send(state->reqs,
734
0
            state->ev,
735
0
            state->servers[state->num_sent],
736
0
            state->proto,
737
0
            state->filter,
738
0
            state->timeout);
739
0
  if (tevent_req_nomem(subreq, req)) {
740
0
    return;
741
0
  }
742
0
  tevent_req_set_callback(subreq, netlogon_pings_done, req);
743
0
  state->reqs[state->num_sent] = subreq;
744
0
  state->num_sent += 1;
745
746
0
  if (state->num_sent < state->num_servers) {
747
    /*
748
     * After 100 milliseconds fire the next one
749
     */
750
0
    subreq = tevent_wakeup_send(state,
751
0
              state->ev,
752
0
              timeval_current_ofs(0, 100000));
753
0
    if (tevent_req_nomem(subreq, req)) {
754
0
      return;
755
0
    }
756
0
    tevent_req_set_callback(subreq, netlogon_pings_next, req);
757
0
  }
758
0
}
759
760
static void netlogon_pings_done(struct tevent_req *subreq)
761
0
{
762
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
763
0
                struct tevent_req);
764
0
  struct netlogon_pings_state *state = tevent_req_data(
765
0
    req, struct netlogon_pings_state);
766
0
  struct netlogon_samlogon_response *response = NULL;
767
0
  NTSTATUS status;
768
0
  size_t i;
769
770
0
  for (i = 0; i < state->num_sent; i++) {
771
0
    if (state->reqs[i] == subreq) {
772
0
      break;
773
0
    }
774
0
  }
775
776
0
  if (i == state->num_sent) {
777
    /*
778
     * Got a response we did not fire...
779
     */
780
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
781
0
    return;
782
0
  }
783
0
  state->reqs[i] = NULL;
784
785
0
  status = netlogon_ping_recv(subreq, state, &response);
786
0
  TALLOC_FREE(subreq);
787
0
  state->num_received += 1;
788
789
0
  if (NT_STATUS_IS_OK(status)) {
790
0
    enum netlogon_command cmd;
791
0
    uint32_t ret_flags;
792
0
    bool ok = true;
793
794
0
    switch (response->ntver) {
795
0
    case NETLOGON_NT_VERSION_5EX:
796
0
      ret_flags = response->data.nt5_ex.server_type;
797
0
      cmd = response->data.nt5_ex.command;
798
0
      ok &= !(cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE ||
799
0
        cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE_EX);
800
0
      break;
801
0
    case NETLOGON_NT_VERSION_5:
802
0
      ret_flags = response->data.nt5.server_type;
803
0
      cmd = response->data.nt5.command;
804
0
      ok &= !(cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE ||
805
0
        cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE_EX);
806
0
      break;
807
0
    default:
808
0
      ret_flags = 0;
809
0
      break;
810
0
    }
811
812
0
    ok &= check_cldap_reply_required_flags(ret_flags,
813
0
                   state->required_flags);
814
0
    if (ok) {
815
0
      state->responses[i] = talloc_move(state->responses,
816
0
                &response);
817
0
      state->num_good_received += 1;
818
0
    }
819
0
  }
820
821
0
  if (state->num_good_received >= state->wanted_servers) {
822
0
    tevent_req_done(req);
823
0
    return;
824
0
  }
825
0
  if (state->num_received < state->num_servers) {
826
    /*
827
     * Wait for more answers
828
     */
829
0
    return;
830
0
  }
831
0
  if (state->num_good_received == 1) {
832
    /* We require at least one DC */
833
0
    tevent_req_done(req);
834
0
    return;
835
0
  }
836
  /*
837
   * Everybody replied, but we did not get a single good
838
   * answers (see above)
839
   */
840
0
  tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
841
0
  return;
842
0
}
843
844
NTSTATUS netlogon_pings_recv(struct tevent_req *req,
845
           TALLOC_CTX *mem_ctx,
846
           struct netlogon_samlogon_response ***responses)
847
0
{
848
0
  struct netlogon_pings_state *state = tevent_req_data(
849
0
    req, struct netlogon_pings_state);
850
0
  NTSTATUS status;
851
852
0
  if (tevent_req_is_nterror(req, &status)) {
853
0
    return status;
854
0
  }
855
0
  *responses = talloc_move(mem_ctx, &state->responses);
856
0
  tevent_req_received(req);
857
0
  return NT_STATUS_OK;
858
0
}
859
860
NTSTATUS netlogon_pings(TALLOC_CTX *mem_ctx,
861
      enum client_netlogon_ping_protocol proto,
862
      struct tsocket_address **servers,
863
      int num_servers,
864
      struct netlogon_ping_filter filter,
865
      int wanted_servers,
866
      struct timeval timeout,
867
      struct netlogon_samlogon_response ***responses)
868
0
{
869
0
  TALLOC_CTX *frame = talloc_stackframe();
870
0
  struct tevent_context *ev = NULL;
871
0
  struct tevent_req *req = NULL;
872
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
873
874
0
  ev = samba_tevent_context_init(frame);
875
0
  if (ev == NULL) {
876
0
    goto fail;
877
0
  }
878
0
  req = netlogon_pings_send(frame,
879
0
          ev,
880
0
          proto,
881
0
          servers,
882
0
          num_servers,
883
0
          filter,
884
0
          wanted_servers,
885
0
          timeout);
886
0
  if (req == NULL) {
887
0
    goto fail;
888
0
  }
889
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
890
0
    goto fail;
891
0
  }
892
0
  status = netlogon_pings_recv(req, mem_ctx, responses);
893
0
 fail:
894
  TALLOC_FREE(frame);
895
0
  return status;
896
0
}