Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : LDAP bind calls
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 : Copyright (C) Volker Lendecke 2004
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 :
24 : #include "includes.h"
25 : #include "libcli/ldap/libcli_ldap.h"
26 : #include "libcli/ldap/ldap_proto.h"
27 : #include "libcli/ldap/ldap_client.h"
28 : #include "lib/tls/tls.h"
29 : #include "auth/gensec/gensec.h"
30 : #include "auth/gensec/gensec_internal.h" /* TODO: remove this */
31 : #include "source4/auth/gensec/gensec_tstream.h"
32 : #include "auth/credentials/credentials.h"
33 : #include "lib/stream/packet.h"
34 : #include "param/param.h"
35 : #include "param/loadparm.h"
36 : #include "librpc/gen_ndr/ads.h"
37 :
38 : struct ldap_simple_creds {
39 : const char *dn;
40 : const char *pw;
41 : };
42 :
43 0 : _PUBLIC_ NTSTATUS ldap_rebind(struct ldap_connection *conn)
44 : {
45 0 : NTSTATUS status;
46 0 : struct ldap_simple_creds *creds;
47 :
48 0 : switch (conn->bind.type) {
49 0 : case LDAP_BIND_SASL:
50 0 : status = ldap_bind_sasl(conn, (struct cli_credentials *)conn->bind.creds,
51 : conn->lp_ctx);
52 0 : break;
53 :
54 0 : case LDAP_BIND_SIMPLE:
55 0 : creds = (struct ldap_simple_creds *)conn->bind.creds;
56 :
57 0 : if (creds == NULL) {
58 0 : return NT_STATUS_UNSUCCESSFUL;
59 : }
60 :
61 0 : status = ldap_bind_simple(conn, creds->dn, creds->pw);
62 0 : break;
63 :
64 0 : default:
65 0 : return NT_STATUS_UNSUCCESSFUL;
66 : }
67 :
68 0 : return status;
69 : }
70 :
71 :
72 444 : static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn,
73 : const char *dn, const char *pw)
74 : {
75 0 : struct ldap_message *res;
76 :
77 444 : res = new_ldap_message(conn);
78 444 : if (!res) {
79 0 : return NULL;
80 : }
81 :
82 444 : res->type = LDAP_TAG_BindRequest;
83 444 : res->r.BindRequest.version = 3;
84 444 : res->r.BindRequest.dn = talloc_strdup(res, dn);
85 444 : res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
86 444 : res->r.BindRequest.creds.password = talloc_strdup(res, pw);
87 444 : res->controls = NULL;
88 :
89 444 : return res;
90 : }
91 :
92 :
93 : /*
94 : perform a simple username/password bind
95 : */
96 444 : _PUBLIC_ NTSTATUS ldap_bind_simple(struct ldap_connection *conn,
97 : const char *userdn, const char *password)
98 : {
99 0 : struct ldap_request *req;
100 0 : struct ldap_message *msg;
101 0 : const char *dn, *pw;
102 0 : NTSTATUS status;
103 :
104 444 : if (conn == NULL) {
105 0 : return NT_STATUS_INVALID_CONNECTION;
106 : }
107 :
108 444 : if (userdn) {
109 443 : dn = userdn;
110 : } else {
111 1 : if (conn->auth_dn) {
112 0 : dn = conn->auth_dn;
113 : } else {
114 1 : dn = "";
115 : }
116 : }
117 :
118 444 : if (password) {
119 443 : pw = password;
120 : } else {
121 1 : if (conn->simple_pw) {
122 0 : pw = conn->simple_pw;
123 : } else {
124 1 : pw = "";
125 : }
126 : }
127 :
128 444 : msg = new_ldap_simple_bind_msg(conn, dn, pw);
129 444 : NT_STATUS_HAVE_NO_MEMORY(msg);
130 :
131 : /* send the request */
132 444 : req = ldap_request_send(conn, msg);
133 444 : talloc_free(msg);
134 444 : NT_STATUS_HAVE_NO_MEMORY(req);
135 :
136 : /* wait for replies */
137 444 : status = ldap_request_wait(req);
138 444 : if (!NT_STATUS_IS_OK(status)) {
139 0 : talloc_free(req);
140 0 : return status;
141 : }
142 :
143 : /* check its a valid reply */
144 444 : msg = req->replies[0];
145 444 : if (msg->type != LDAP_TAG_BindResponse) {
146 0 : talloc_free(req);
147 0 : return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
148 : }
149 :
150 444 : status = ldap_check_response(conn, &msg->r.BindResponse.response);
151 :
152 444 : talloc_free(req);
153 :
154 444 : if (NT_STATUS_IS_OK(status)) {
155 319 : struct ldap_simple_creds *creds = talloc(conn, struct ldap_simple_creds);
156 319 : if (creds == NULL) {
157 0 : return NT_STATUS_NO_MEMORY;
158 : }
159 319 : creds->dn = talloc_strdup(creds, dn);
160 319 : creds->pw = talloc_strdup(creds, pw);
161 319 : if (creds->dn == NULL || creds->pw == NULL) {
162 0 : return NT_STATUS_NO_MEMORY;
163 : }
164 319 : conn->bind.type = LDAP_BIND_SIMPLE;
165 319 : conn->bind.creds = creds;
166 : }
167 :
168 444 : return status;
169 : }
170 :
171 :
172 35034 : static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn,
173 : const char *sasl_mechanism,
174 : DATA_BLOB *secblob)
175 : {
176 122 : struct ldap_message *res;
177 :
178 35034 : res = new_ldap_message(conn);
179 35034 : if (!res) {
180 0 : return NULL;
181 : }
182 :
183 35034 : res->type = LDAP_TAG_BindRequest;
184 35034 : res->r.BindRequest.version = 3;
185 35034 : res->r.BindRequest.dn = "";
186 35034 : res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
187 35034 : res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
188 35034 : if (secblob) {
189 35034 : res->r.BindRequest.creds.SASL.secblob = talloc(res, DATA_BLOB);
190 35034 : if (!res->r.BindRequest.creds.SASL.secblob) {
191 0 : talloc_free(res);
192 0 : return NULL;
193 : }
194 35034 : *res->r.BindRequest.creds.SASL.secblob = *secblob;
195 : } else {
196 0 : res->r.BindRequest.creds.SASL.secblob = NULL;
197 : }
198 35034 : res->controls = NULL;
199 :
200 35034 : return res;
201 : }
202 :
203 :
204 : /*
205 : perform a sasl bind using the given credentials
206 : */
207 26102 : _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
208 : struct cli_credentials *creds,
209 : struct loadparm_context *lp_ctx)
210 : {
211 122 : NTSTATUS status;
212 26102 : TALLOC_CTX *tmp_ctx = NULL;
213 :
214 26102 : DATA_BLOB input = data_blob(NULL, 0);
215 26102 : DATA_BLOB output = data_blob(NULL, 0);
216 :
217 122 : struct ldap_message **sasl_mechs_msgs;
218 122 : struct ldap_SearchResEntry *search;
219 122 : int count, i;
220 26102 : bool first = true;
221 26102 : int wrap_flags = 0;
222 122 : const char **sasl_names;
223 122 : uint32_t old_gensec_features;
224 122 : static const char *supported_sasl_mech_attrs[] = {
225 : "supportedSASLMechanisms",
226 : NULL
227 : };
228 26102 : unsigned int logon_retries = 0;
229 122 : size_t queue_length;
230 :
231 26102 : if (conn->sockets.active == NULL) {
232 0 : status = NT_STATUS_CONNECTION_DISCONNECTED;
233 0 : goto failed;
234 : }
235 :
236 26102 : queue_length = tevent_queue_length(conn->sockets.send_queue);
237 26102 : if (queue_length != 0) {
238 0 : status = NT_STATUS_INVALID_PARAMETER_MIX;
239 0 : DEBUG(1, ("SASL bind triggered with non empty send_queue[%zu]: %s\n",
240 : queue_length, nt_errstr(status)));
241 0 : goto failed;
242 : }
243 :
244 26102 : if (conn->pending != NULL) {
245 0 : status = NT_STATUS_INVALID_PARAMETER_MIX;
246 0 : DEBUG(1, ("SASL bind triggered with pending requests: %s\n",
247 : nt_errstr(status)));
248 0 : goto failed;
249 : }
250 :
251 26102 : status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
252 : false, NULL, NULL, &sasl_mechs_msgs);
253 26102 : if (!NT_STATUS_IS_OK(status)) {
254 0 : DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
255 : nt_errstr(status)));
256 0 : goto failed;
257 : }
258 :
259 26102 : count = ildap_count_entries(conn, sasl_mechs_msgs);
260 26102 : if (count != 1) {
261 0 : DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
262 : count));
263 0 : goto failed;
264 : }
265 :
266 26102 : tmp_ctx = talloc_new(conn);
267 26102 : if (tmp_ctx == NULL) goto failed;
268 :
269 26102 : search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
270 26102 : if (search->num_attributes != 1) {
271 0 : DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n",
272 : search->num_attributes));
273 0 : goto failed;
274 : }
275 :
276 26102 : sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
277 26102 : if (!sasl_names) {
278 0 : DEBUG(1, ("talloc_arry(char *, %d) failed\n",
279 : count));
280 0 : goto failed;
281 : }
282 :
283 104408 : for (i=0; i<search->attributes[0].num_values; i++) {
284 78306 : sasl_names[i] = (const char *)search->attributes[0].values[i].data;
285 : }
286 26102 : sasl_names[i] = NULL;
287 :
288 26102 : gensec_init();
289 :
290 26102 : if (conn->sockets.active == conn->sockets.tls) {
291 : /*
292 : * require Kerberos SIGN/SEAL only if we don't use SSL
293 : * Windows seem not to like double encryption
294 : */
295 48 : wrap_flags = 0;
296 26054 : } else if (cli_credentials_is_anonymous(creds)) {
297 : /*
298 : * anonymous isn't protected
299 : */
300 0 : wrap_flags = 0;
301 : } else {
302 26054 : wrap_flags = lpcfg_client_ldap_sasl_wrapping(lp_ctx);
303 : }
304 :
305 25980 : try_logon_again:
306 : /*
307 : we loop back here on a logon failure, and re-create the
308 : gensec session. The logon_retries counter ensures we don't
309 : loop forever.
310 : */
311 26228 : data_blob_free(&input);
312 26228 : TALLOC_FREE(conn->gensec);
313 :
314 26228 : status = gensec_client_start(conn, &conn->gensec,
315 : lpcfg_gensec_settings(conn, lp_ctx));
316 26228 : if (!NT_STATUS_IS_OK(status)) {
317 0 : DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
318 0 : goto failed;
319 : }
320 :
321 26228 : old_gensec_features = cli_credentials_get_gensec_features(creds);
322 26228 : if (wrap_flags == 0) {
323 177 : cli_credentials_set_gensec_features(creds,
324 : old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL),
325 : CRED_SPECIFIED);
326 : }
327 :
328 : /* this call also sets the gensec_want_features */
329 26228 : status = gensec_set_credentials(conn->gensec, creds);
330 26228 : if (!NT_STATUS_IS_OK(status)) {
331 0 : DEBUG(1, ("Failed to set GENSEC creds: %s\n",
332 : nt_errstr(status)));
333 0 : goto failed;
334 : }
335 :
336 : /* reset the original gensec_features (on the credentials
337 : * context, so we don't tattoo it ) */
338 26228 : cli_credentials_set_gensec_features(creds,
339 : old_gensec_features,
340 : CRED_SPECIFIED);
341 :
342 26228 : if (wrap_flags & ADS_AUTH_SASL_SEAL) {
343 25924 : gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
344 25924 : gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL);
345 : }
346 26228 : if (wrap_flags & ADS_AUTH_SASL_SIGN) {
347 127 : gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
348 : }
349 :
350 : /*
351 : * This is an indication for the NTLMSSP backend to
352 : * also encrypt when only GENSEC_FEATURE_SIGN is requested
353 : * in gensec_[un]wrap().
354 : */
355 26228 : gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE);
356 :
357 26228 : if (conn->host) {
358 26228 : status = gensec_set_target_hostname(conn->gensec, conn->host);
359 26228 : if (!NT_STATUS_IS_OK(status)) {
360 0 : DEBUG(1, ("Failed to set GENSEC target hostname: %s\n",
361 : nt_errstr(status)));
362 0 : goto failed;
363 : }
364 : }
365 :
366 26228 : status = gensec_set_target_service(conn->gensec, "ldap");
367 26228 : if (!NT_STATUS_IS_OK(status)) {
368 0 : DEBUG(1, ("Failed to set GENSEC target service: %s\n",
369 : nt_errstr(status)));
370 0 : goto failed;
371 : }
372 :
373 26228 : status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
374 26228 : if (!NT_STATUS_IS_OK(status)) {
375 0 : DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
376 : count, nt_errstr(status)));
377 0 : goto failed;
378 : }
379 :
380 34709 : while (1) {
381 244 : NTSTATUS gensec_status;
382 244 : struct ldap_message *response;
383 244 : struct ldap_message *msg;
384 244 : struct ldap_request *req;
385 60937 : int result = LDAP_OTHER;
386 :
387 60937 : status = gensec_update(conn->gensec, tmp_ctx,
388 : input,
389 : &output);
390 : /* The status value here, from GENSEC is vital to the security
391 : * of the system. Even if the other end accepts, if GENSEC
392 : * claims 'MORE_PROCESSING_REQUIRED' then you must keep
393 : * feeding it blobs, or else the remote host/attacker might
394 : * avoid mutual authentication requirements.
395 : *
396 : * Likewise, you must not feed GENSEC too much (after the OK),
397 : * it doesn't like that either.
398 : *
399 : * For SASL/EXTERNAL, there is no data to send, but we still
400 : * must send the actual Bind request the first time around.
401 : * Otherwise, a result of NT_STATUS_OK with 0 output means the
402 : * end of a multi-step authentication, and no message must be
403 : * sent.
404 : */
405 :
406 60937 : gensec_status = status;
407 :
408 60937 : if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
409 25903 : !NT_STATUS_IS_OK(status)) {
410 272 : break;
411 : }
412 60665 : if (NT_STATUS_IS_OK(status) && output.length == 0) {
413 25631 : if (!first)
414 25509 : break;
415 : }
416 35034 : first = false;
417 :
418 : /* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
419 35034 : msg = new_ldap_sasl_bind_msg(tmp_ctx, conn->gensec->ops->sasl_name, (output.data?&output:NULL));
420 35034 : if (msg == NULL) {
421 0 : status = NT_STATUS_NO_MEMORY;
422 0 : goto failed;
423 : }
424 :
425 35034 : req = ldap_request_send(conn, msg);
426 35034 : if (req == NULL) {
427 0 : status = NT_STATUS_NO_MEMORY;
428 0 : goto failed;
429 : }
430 35034 : talloc_reparent(conn, tmp_ctx, req);
431 :
432 35034 : status = ldap_result_n(req, 0, &response);
433 35034 : if (!NT_STATUS_IS_OK(status)) {
434 0 : goto failed;
435 : }
436 :
437 35034 : if (response->type != LDAP_TAG_BindResponse) {
438 0 : status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
439 0 : goto failed;
440 : }
441 :
442 35034 : result = response->r.BindResponse.response.resultcode;
443 :
444 35034 : if (result == LDAP_STRONG_AUTH_REQUIRED) {
445 125 : if (wrap_flags == 0) {
446 125 : wrap_flags = ADS_AUTH_SASL_SIGN;
447 126 : goto try_logon_again;
448 : }
449 : }
450 :
451 34909 : if (result == LDAP_INVALID_CREDENTIALS) {
452 : /*
453 : try a second time on invalid credentials, to
454 : give the user a chance to re-enter the
455 : password and to handle the case where our
456 : kerberos ticket is invalid as the server
457 : password has changed
458 : */
459 0 : const char *principal;
460 :
461 197 : principal = gensec_get_target_principal(conn->gensec);
462 197 : if (principal == NULL) {
463 197 : const char *hostname = gensec_get_target_hostname(conn->gensec);
464 197 : const char *service = gensec_get_target_service(conn->gensec);
465 197 : if (hostname != NULL && service != NULL) {
466 197 : principal = talloc_asprintf(tmp_ctx, "%s/%s", service, hostname);
467 : }
468 : }
469 :
470 393 : if (cli_credentials_failed_kerberos_login(creds, principal, &logon_retries) ||
471 196 : cli_credentials_wrong_password(creds)) {
472 : /*
473 : destroy our gensec session and loop
474 : back up to the top to retry,
475 : offering the user a chance to enter
476 : new credentials, or get a new ticket
477 : if using kerberos
478 : */
479 1 : goto try_logon_again;
480 : }
481 : }
482 :
483 34908 : if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
484 199 : status = ldap_check_response(conn,
485 199 : &response->r.BindResponse.response);
486 199 : break;
487 : }
488 :
489 : /* This is where we check if GENSEC wanted to be fed more data */
490 34709 : if (!NT_STATUS_EQUAL(gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
491 0 : break;
492 : }
493 34709 : if (response->r.BindResponse.SASL.secblob) {
494 34709 : input = *response->r.BindResponse.SASL.secblob;
495 : } else {
496 0 : input = data_blob(NULL, 0);
497 : }
498 : }
499 :
500 26102 : TALLOC_FREE(tmp_ctx);
501 :
502 26102 : if (!NT_STATUS_IS_OK(status)) {
503 471 : goto failed;
504 : }
505 :
506 25631 : conn->bind.type = LDAP_BIND_SASL;
507 25631 : conn->bind.creds = creds;
508 :
509 25631 : if (wrap_flags & ADS_AUTH_SASL_SEAL) {
510 25454 : if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
511 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
512 : }
513 :
514 25454 : if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
515 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
516 : }
517 177 : } else if (wrap_flags & ADS_AUTH_SASL_SIGN) {
518 125 : if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
519 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
520 : }
521 : }
522 :
523 25631 : if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) &&
524 52 : !gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
525 52 : return NT_STATUS_OK;
526 : }
527 :
528 25579 : status = gensec_create_tstream(conn->sockets.raw,
529 : conn->gensec,
530 : conn->sockets.raw,
531 : &conn->sockets.sasl);
532 25579 : if (!NT_STATUS_IS_OK(status)) {
533 0 : goto failed;
534 : }
535 :
536 25579 : conn->sockets.active = conn->sockets.sasl;
537 :
538 25579 : return NT_STATUS_OK;
539 :
540 471 : failed:
541 471 : talloc_free(tmp_ctx);
542 471 : talloc_free(conn->gensec);
543 471 : conn->gensec = NULL;
544 471 : return status;
545 : }
|