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