Line data Source code
1 : /*
2 : Samba Unix/Linux SMB client library
3 : net ads cldap functions
4 : Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 : Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
6 : Copyright (C) 2008 Guenther Deschner (gd@samba.org)
7 : Copyright (C) 2009 Stefan Metzmacher (metze@samba.org)
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 "../libcli/cldap/cldap.h"
25 : #include "../librpc/gen_ndr/ndr_netlogon.h"
26 : #include "../lib/tsocket/tsocket.h"
27 : #include "../lib/util/tevent_ntstatus.h"
28 : #include "libads/cldap.h"
29 :
30 : struct cldap_multi_netlogon_state {
31 : struct tevent_context *ev;
32 : const struct tsocket_address * const *servers;
33 : int num_servers;
34 : const char *domain;
35 : const char *hostname;
36 : unsigned ntversion;
37 : int min_servers;
38 :
39 : struct cldap_socket **cldap;
40 : struct tevent_req **subreqs;
41 : int num_sent;
42 : int num_received;
43 : int num_good_received;
44 : struct cldap_netlogon *ios;
45 : struct netlogon_samlogon_response **responses;
46 : };
47 :
48 : static void cldap_multi_netlogon_done(struct tevent_req *subreq);
49 : static void cldap_multi_netlogon_next(struct tevent_req *subreq);
50 :
51 : /****************************************************************
52 : ****************************************************************/
53 :
54 : #define RETURN_ON_FALSE(x) if (!(x)) return false;
55 :
56 670 : bool check_cldap_reply_required_flags(uint32_t ret_flags,
57 : uint32_t req_flags)
58 : {
59 670 : if (req_flags == 0) {
60 573 : return true;
61 : }
62 :
63 97 : if (req_flags & DS_PDC_REQUIRED)
64 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
65 :
66 97 : if (req_flags & DS_GC_SERVER_REQUIRED)
67 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
68 :
69 97 : if (req_flags & DS_ONLY_LDAP_NEEDED)
70 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
71 :
72 97 : if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
73 9 : (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
74 88 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
75 :
76 97 : if (req_flags & DS_KDC_REQUIRED)
77 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
78 :
79 97 : if (req_flags & DS_TIMESERV_REQUIRED)
80 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
81 :
82 97 : if (req_flags & DS_WEB_SERVICE_REQUIRED)
83 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_ADS_WEB_SERVICE);
84 :
85 97 : if (req_flags & DS_WRITABLE_REQUIRED)
86 88 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
87 :
88 97 : if (req_flags & DS_DIRECTORY_SERVICE_6_REQUIRED)
89 0 : RETURN_ON_FALSE(ret_flags & (NBT_SERVER_SELECT_SECRET_DOMAIN_6
90 0 : |NBT_SERVER_FULL_SECRET_DOMAIN_6));
91 :
92 97 : if (req_flags & DS_DIRECTORY_SERVICE_8_REQUIRED)
93 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_8);
94 :
95 97 : if (req_flags & DS_DIRECTORY_SERVICE_9_REQUIRED)
96 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_9);
97 :
98 97 : if (req_flags & DS_DIRECTORY_SERVICE_10_REQUIRED)
99 0 : RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_10);
100 :
101 97 : return true;
102 : }
103 :
104 : /*
105 : * Do a parallel cldap ping to the servers. The first "min_servers"
106 : * are fired directly, the remaining ones in 100msec intervals. If
107 : * "min_servers" responses came in successfully, we immediately reply,
108 : * not waiting for the remaining ones.
109 : */
110 :
111 858 : struct tevent_req *cldap_multi_netlogon_send(
112 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
113 : const struct tsocket_address * const *servers, int num_servers,
114 : const char *domain, const char *hostname, unsigned ntversion,
115 : int min_servers)
116 : {
117 0 : struct tevent_req *req, *subreq;
118 0 : struct cldap_multi_netlogon_state *state;
119 0 : int i;
120 :
121 858 : req = tevent_req_create(mem_ctx, &state,
122 : struct cldap_multi_netlogon_state);
123 858 : if (req == NULL) {
124 0 : return NULL;
125 : }
126 858 : state->ev = ev;
127 858 : state->servers = servers;
128 858 : state->num_servers = num_servers;
129 858 : state->domain = domain;
130 858 : state->hostname = hostname;
131 858 : state->ntversion = ntversion;
132 858 : state->min_servers = min_servers;
133 :
134 858 : if (min_servers > num_servers) {
135 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
136 0 : return tevent_req_post(req, ev);
137 : }
138 :
139 858 : state->subreqs = talloc_zero_array(state,
140 : struct tevent_req *,
141 : num_servers);
142 858 : if (tevent_req_nomem(state->subreqs, req)) {
143 0 : return tevent_req_post(req, ev);
144 : }
145 :
146 858 : state->cldap = talloc_zero_array(state,
147 : struct cldap_socket *,
148 : num_servers);
149 858 : if (tevent_req_nomem(state->cldap, req)) {
150 0 : return tevent_req_post(req, ev);
151 : }
152 :
153 858 : state->responses = talloc_zero_array(state,
154 : struct netlogon_samlogon_response *,
155 : num_servers);
156 858 : if (tevent_req_nomem(state->responses, req)) {
157 0 : return tevent_req_post(req, ev);
158 : }
159 :
160 858 : state->ios = talloc_zero_array(state->responses,
161 : struct cldap_netlogon,
162 : num_servers);
163 858 : if (tevent_req_nomem(state->ios, req)) {
164 0 : return tevent_req_post(req, ev);
165 : }
166 :
167 1906 : for (i=0; i<num_servers; i++) {
168 0 : NTSTATUS status;
169 :
170 1048 : status = cldap_socket_init(state->cldap,
171 : NULL, /* local_addr */
172 1048 : state->servers[i],
173 1048 : &state->cldap[i]);
174 1048 : if (!NT_STATUS_IS_OK(status)) {
175 : /*
176 : * Don't error out all sends just
177 : * because one cldap_socket_init() failed.
178 : * Log it here, and the cldap_netlogon_send()
179 : * will catch it (with in.dest_address == NULL)
180 : * and correctly error out in
181 : * cldap_multi_netlogon_done(). This still allows
182 : * the other requests to be concurrently sent.
183 : */
184 0 : DBG_NOTICE("cldap_socket_init failed for %s "
185 : " error %s\n",
186 : tsocket_address_string(state->servers[i],
187 : req),
188 : nt_errstr(status));
189 : }
190 :
191 1048 : state->ios[i].in.dest_address = NULL;
192 1048 : state->ios[i].in.dest_port = 0;
193 1048 : state->ios[i].in.realm = domain;
194 1048 : state->ios[i].in.host = NULL;
195 1048 : state->ios[i].in.user = NULL;
196 1048 : state->ios[i].in.domain_guid = NULL;
197 1048 : state->ios[i].in.domain_sid = NULL;
198 1048 : state->ios[i].in.acct_control = 0;
199 1048 : state->ios[i].in.version = ntversion;
200 1048 : state->ios[i].in.map_response = false;
201 : }
202 :
203 1716 : for (i=0; i<min_servers; i++) {
204 1716 : state->subreqs[i] = cldap_netlogon_send(state->subreqs,
205 858 : state->ev,
206 858 : state->cldap[i],
207 858 : &state->ios[i]);
208 858 : if (tevent_req_nomem(state->subreqs[i], req)) {
209 0 : return tevent_req_post(req, ev);
210 : }
211 858 : tevent_req_set_callback(
212 : state->subreqs[i], cldap_multi_netlogon_done, req);
213 : }
214 858 : state->num_sent = min_servers;
215 :
216 858 : if (state->num_sent < state->num_servers) {
217 : /*
218 : * After 100 milliseconds fire the next one
219 : */
220 190 : subreq = tevent_wakeup_send(state, state->ev,
221 : timeval_current_ofs(0, 100000));
222 190 : if (tevent_req_nomem(subreq, req)) {
223 0 : return tevent_req_post(req, ev);
224 : }
225 190 : tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
226 : req);
227 : }
228 :
229 858 : return req;
230 : }
231 :
232 858 : static void cldap_multi_netlogon_done(struct tevent_req *subreq)
233 : {
234 858 : struct tevent_req *req = tevent_req_callback_data(
235 : subreq, struct tevent_req);
236 858 : struct cldap_multi_netlogon_state *state = tevent_req_data(
237 : req, struct cldap_multi_netlogon_state);
238 0 : NTSTATUS status;
239 0 : struct netlogon_samlogon_response *response;
240 0 : int i;
241 :
242 858 : for (i=0; i<state->num_sent; i++) {
243 858 : if (state->subreqs[i] == subreq) {
244 858 : break;
245 : }
246 : }
247 858 : if (i == state->num_sent) {
248 : /*
249 : * Got a response we did not fire...
250 : */
251 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
252 0 : return;
253 : }
254 858 : state->subreqs[i] = NULL;
255 :
256 858 : response = talloc_zero(state, struct netlogon_samlogon_response);
257 858 : if (tevent_req_nomem(response, req)) {
258 0 : return;
259 : }
260 :
261 858 : status = cldap_netlogon_recv(subreq, response,
262 858 : &state->ios[i]);
263 858 : TALLOC_FREE(subreq);
264 858 : state->num_received += 1;
265 :
266 858 : if (NT_STATUS_IS_OK(status)) {
267 848 : *response = state->ios[i].out.netlogon;
268 848 : state->responses[i] = talloc_move(state->responses,
269 : &response);
270 848 : state->num_good_received += 1;
271 : }
272 :
273 858 : if ((state->num_received == state->num_servers) ||
274 190 : (state->num_good_received >= state->min_servers)) {
275 858 : tevent_req_done(req);
276 858 : return;
277 : }
278 : }
279 :
280 0 : static void cldap_multi_netlogon_next(struct tevent_req *subreq)
281 : {
282 0 : struct tevent_req *req = tevent_req_callback_data(
283 : subreq, struct tevent_req);
284 0 : struct cldap_multi_netlogon_state *state = tevent_req_data(
285 : req, struct cldap_multi_netlogon_state);
286 0 : bool ret;
287 :
288 0 : ret = tevent_wakeup_recv(subreq);
289 0 : TALLOC_FREE(subreq);
290 0 : if (!ret) {
291 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
292 0 : return;
293 : }
294 :
295 0 : subreq = cldap_netlogon_send(state->subreqs,
296 : state->ev,
297 0 : state->cldap[state->num_sent],
298 0 : &state->ios[state->num_sent]);
299 0 : if (tevent_req_nomem(subreq, req)) {
300 0 : return;
301 : }
302 0 : tevent_req_set_callback(subreq, cldap_multi_netlogon_done, req);
303 0 : state->subreqs[state->num_sent] = subreq;
304 0 : state->num_sent += 1;
305 :
306 0 : if (state->num_sent < state->num_servers) {
307 : /*
308 : * After 100 milliseconds fire the next one
309 : */
310 0 : subreq = tevent_wakeup_send(state, state->ev,
311 : timeval_current_ofs(0, 100000));
312 0 : if (tevent_req_nomem(subreq, req)) {
313 0 : return;
314 : }
315 0 : tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
316 : req);
317 : }
318 : }
319 :
320 858 : NTSTATUS cldap_multi_netlogon_recv(
321 : struct tevent_req *req, TALLOC_CTX *mem_ctx,
322 : struct netlogon_samlogon_response ***responses)
323 : {
324 858 : struct cldap_multi_netlogon_state *state = tevent_req_data(
325 : req, struct cldap_multi_netlogon_state);
326 0 : NTSTATUS status;
327 :
328 858 : if (tevent_req_is_nterror(req, &status) &&
329 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
330 0 : return status;
331 : }
332 : /*
333 : * If we timeout, give back what we have so far
334 : */
335 858 : *responses = talloc_move(mem_ctx, &state->responses);
336 858 : return NT_STATUS_OK;
337 : }
338 :
339 858 : NTSTATUS cldap_multi_netlogon(
340 : TALLOC_CTX *mem_ctx,
341 : const struct tsocket_address * const *servers,
342 : int num_servers,
343 : const char *domain, const char *hostname, unsigned ntversion,
344 : int min_servers, struct timeval timeout,
345 : struct netlogon_samlogon_response ***responses)
346 : {
347 0 : struct tevent_context *ev;
348 0 : struct tevent_req *req;
349 858 : NTSTATUS status = NT_STATUS_NO_MEMORY;
350 :
351 858 : ev = samba_tevent_context_init(talloc_tos());
352 858 : if (ev == NULL) {
353 0 : goto fail;
354 : }
355 858 : req = cldap_multi_netlogon_send(
356 : ev, ev, servers, num_servers, domain, hostname, ntversion,
357 : min_servers);
358 858 : if (req == NULL) {
359 0 : goto fail;
360 : }
361 858 : if (!tevent_req_set_endtime(req, ev, timeout)) {
362 0 : goto fail;
363 : }
364 858 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
365 0 : goto fail;
366 : }
367 858 : status = cldap_multi_netlogon_recv(req, mem_ctx, responses);
368 858 : fail:
369 858 : TALLOC_FREE(ev);
370 858 : return status;
371 : }
372 :
373 : /*******************************************************************
374 : do a cldap netlogon query. Always 389/udp
375 : *******************************************************************/
376 :
377 416 : bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
378 : struct sockaddr_storage *ss,
379 : const char *realm,
380 : uint32_t nt_version,
381 : struct netlogon_samlogon_response **_reply)
382 : {
383 0 : NTSTATUS status;
384 0 : char addrstr[INET6_ADDRSTRLEN];
385 0 : const char *dest_str;
386 0 : struct tsocket_address *dest_addr;
387 0 : const struct tsocket_address * const *dest_addrs;
388 416 : struct netlogon_samlogon_response **responses = NULL;
389 0 : int ret;
390 :
391 416 : dest_str = print_sockaddr(addrstr, sizeof(addrstr), ss);
392 :
393 416 : ret = tsocket_address_inet_from_strings(mem_ctx, "ip",
394 : dest_str, LDAP_PORT,
395 : &dest_addr);
396 416 : if (ret != 0) {
397 0 : status = map_nt_error_from_unix(errno);
398 0 : DEBUG(2,("Failed to create cldap tsocket_address for %s - %s\n",
399 : dest_str, nt_errstr(status)));
400 0 : return false;
401 : }
402 :
403 416 : dest_addrs = (const struct tsocket_address * const *)&dest_addr;
404 :
405 832 : status = cldap_multi_netlogon(talloc_tos(),
406 : dest_addrs, 1,
407 : realm, NULL,
408 : nt_version, 1,
409 832 : timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0),
410 : &responses);
411 416 : if (!NT_STATUS_IS_OK(status)) {
412 0 : DEBUG(2, ("ads_cldap_netlogon: cldap_multi_netlogon "
413 : "failed: %s\n", nt_errstr(status)));
414 0 : return false;
415 : }
416 416 : if (responses == NULL || responses[0] == NULL) {
417 10 : DEBUG(2, ("ads_cldap_netlogon: did not get a reply\n"));
418 10 : TALLOC_FREE(responses);
419 10 : return false;
420 : }
421 406 : *_reply = talloc_move(mem_ctx, &responses[0]);
422 :
423 406 : return true;
424 : }
425 :
426 : /*******************************************************************
427 : do a cldap netlogon query. Always 389/udp
428 : *******************************************************************/
429 :
430 348 : bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
431 : struct sockaddr_storage *ss,
432 : const char *realm,
433 : struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
434 : {
435 348 : uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
436 348 : struct netlogon_samlogon_response *reply = NULL;
437 0 : bool ret;
438 :
439 348 : ret = ads_cldap_netlogon(mem_ctx, ss, realm, nt_version, &reply);
440 348 : if (!ret) {
441 0 : return false;
442 : }
443 :
444 348 : if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
445 0 : DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
446 : reply->ntver));
447 0 : return false;
448 : }
449 :
450 348 : *reply5 = reply->data.nt5_ex;
451 :
452 348 : return true;
453 : }
|