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