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