2 Unix SMB/CIFS mplementation.
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Volker Lendecke 2004
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.
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.
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/>.
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/credentials/credentials.h"
31 #include "lib/stream/packet.h"
32 #include "param/param.h"
34 struct ldap_simple_creds
{
39 _PUBLIC_ NTSTATUS
ldap_rebind(struct ldap_connection
*conn
)
42 struct ldap_simple_creds
*creds
;
44 switch (conn
->bind
.type
) {
46 status
= ldap_bind_sasl(conn
, (struct cli_credentials
*)conn
->bind
.creds
,
50 case LDAP_BIND_SIMPLE
:
51 creds
= (struct ldap_simple_creds
*)conn
->bind
.creds
;
54 return NT_STATUS_UNSUCCESSFUL
;
57 status
= ldap_bind_simple(conn
, creds
->dn
, creds
->pw
);
61 return NT_STATUS_UNSUCCESSFUL
;
68 static struct ldap_message
*new_ldap_simple_bind_msg(struct ldap_connection
*conn
,
69 const char *dn
, const char *pw
)
71 struct ldap_message
*res
;
73 res
= new_ldap_message(conn
);
78 res
->type
= LDAP_TAG_BindRequest
;
79 res
->r
.BindRequest
.version
= 3;
80 res
->r
.BindRequest
.dn
= talloc_strdup(res
, dn
);
81 res
->r
.BindRequest
.mechanism
= LDAP_AUTH_MECH_SIMPLE
;
82 res
->r
.BindRequest
.creds
.password
= talloc_strdup(res
, pw
);
90 perform a simple username/password bind
92 _PUBLIC_ NTSTATUS
ldap_bind_simple(struct ldap_connection
*conn
,
93 const char *userdn
, const char *password
)
95 struct ldap_request
*req
;
96 struct ldap_message
*msg
;
101 return NT_STATUS_INVALID_CONNECTION
;
117 if (conn
->simple_pw
) {
118 pw
= conn
->simple_pw
;
124 msg
= new_ldap_simple_bind_msg(conn
, dn
, pw
);
125 NT_STATUS_HAVE_NO_MEMORY(msg
);
127 /* send the request */
128 req
= ldap_request_send(conn
, msg
);
130 NT_STATUS_HAVE_NO_MEMORY(req
);
132 /* wait for replies */
133 status
= ldap_request_wait(req
);
134 if (!NT_STATUS_IS_OK(status
)) {
139 /* check its a valid reply */
140 msg
= req
->replies
[0];
141 if (msg
->type
!= LDAP_TAG_BindResponse
) {
143 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
146 status
= ldap_check_response(conn
, &msg
->r
.BindResponse
.response
);
150 if (NT_STATUS_IS_OK(status
)) {
151 struct ldap_simple_creds
*creds
= talloc(conn
, struct ldap_simple_creds
);
153 return NT_STATUS_NO_MEMORY
;
155 creds
->dn
= talloc_strdup(creds
, dn
);
156 creds
->pw
= talloc_strdup(creds
, pw
);
157 if (creds
->dn
== NULL
|| creds
->pw
== NULL
) {
158 return NT_STATUS_NO_MEMORY
;
160 conn
->bind
.type
= LDAP_BIND_SIMPLE
;
161 conn
->bind
.creds
= creds
;
168 static struct ldap_message
*new_ldap_sasl_bind_msg(struct ldap_connection
*conn
,
169 const char *sasl_mechanism
,
172 struct ldap_message
*res
;
174 res
= new_ldap_message(conn
);
179 res
->type
= LDAP_TAG_BindRequest
;
180 res
->r
.BindRequest
.version
= 3;
181 res
->r
.BindRequest
.dn
= "";
182 res
->r
.BindRequest
.mechanism
= LDAP_AUTH_MECH_SASL
;
183 res
->r
.BindRequest
.creds
.SASL
.mechanism
= talloc_strdup(res
, sasl_mechanism
);
185 res
->r
.BindRequest
.creds
.SASL
.secblob
= talloc(res
, DATA_BLOB
);
186 if (!res
->r
.BindRequest
.creds
.SASL
.secblob
) {
190 *res
->r
.BindRequest
.creds
.SASL
.secblob
= *secblob
;
192 res
->r
.BindRequest
.creds
.SASL
.secblob
= NULL
;
194 res
->controls
= NULL
;
201 perform a sasl bind using the given credentials
203 _PUBLIC_ NTSTATUS
ldap_bind_sasl(struct ldap_connection
*conn
,
204 struct cli_credentials
*creds
,
205 struct loadparm_context
*lp_ctx
)
208 TALLOC_CTX
*tmp_ctx
= NULL
;
210 DATA_BLOB input
= data_blob(NULL
, 0);
211 DATA_BLOB output
= data_blob(NULL
, 0);
213 struct ldap_message
**sasl_mechs_msgs
;
214 struct ldap_SearchResEntry
*search
;
217 const char **sasl_names
;
218 uint32_t old_gensec_features
;
219 static const char *supported_sasl_mech_attrs
[] = {
220 "supportedSASLMechanisms",
226 status
= gensec_client_start(conn
, &conn
->gensec
,
227 conn
->event
.event_ctx
,
228 lp_gensec_settings(conn
, lp_ctx
));
229 if (!NT_STATUS_IS_OK(status
)) {
230 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status
)));
234 /* require Kerberos SIGN/SEAL only if we don't use SSL
235 * Windows seem not to like double encryption */
236 old_gensec_features
= cli_credentials_get_gensec_features(creds
);
237 if (tls_enabled(conn
->sock
)) {
238 cli_credentials_set_gensec_features(creds
, old_gensec_features
& ~(GENSEC_FEATURE_SIGN
|GENSEC_FEATURE_SEAL
));
241 /* this call also sets the gensec_want_features */
242 status
= gensec_set_credentials(conn
->gensec
, creds
);
243 if (!NT_STATUS_IS_OK(status
)) {
244 DEBUG(1, ("Failed to set GENSEC creds: %s\n",
249 /* reset the original gensec_features (on the credentials
250 * context, so we don't tatoo it ) */
251 cli_credentials_set_gensec_features(creds
, old_gensec_features
);
254 status
= gensec_set_target_hostname(conn
->gensec
, conn
->host
);
255 if (!NT_STATUS_IS_OK(status
)) {
256 DEBUG(1, ("Failed to set GENSEC target hostname: %s\n",
262 status
= gensec_set_target_service(conn
->gensec
, "ldap");
263 if (!NT_STATUS_IS_OK(status
)) {
264 DEBUG(1, ("Failed to set GENSEC target service: %s\n",
269 status
= ildap_search(conn
, "", LDAP_SEARCH_SCOPE_BASE
, "", supported_sasl_mech_attrs
,
270 false, NULL
, NULL
, &sasl_mechs_msgs
);
271 if (!NT_STATUS_IS_OK(status
)) {
272 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
277 count
= ildap_count_entries(conn
, sasl_mechs_msgs
);
279 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
284 tmp_ctx
= talloc_new(conn
);
285 if (tmp_ctx
== NULL
) goto failed
;
287 search
= &sasl_mechs_msgs
[0]->r
.SearchResultEntry
;
288 if (search
->num_attributes
!= 1) {
289 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n",
290 search
->num_attributes
));
294 sasl_names
= talloc_array(tmp_ctx
, const char *, search
->attributes
[0].num_values
+ 1);
296 DEBUG(1, ("talloc_arry(char *, %d) failed\n",
301 for (i
=0; i
<search
->attributes
[0].num_values
; i
++) {
302 sasl_names
[i
] = (const char *)search
->attributes
[0].values
[i
].data
;
304 sasl_names
[i
] = NULL
;
306 status
= gensec_start_mech_by_sasl_list(conn
->gensec
, sasl_names
);
307 if (!NT_STATUS_IS_OK(status
)) {
308 DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
309 count
, nt_errstr(status
)));
314 NTSTATUS gensec_status
;
315 struct ldap_message
*response
;
316 struct ldap_message
*msg
;
317 struct ldap_request
*req
;
318 int result
= LDAP_OTHER
;
320 status
= gensec_update(conn
->gensec
, tmp_ctx
,
323 /* The status value here, from GENSEC is vital to the security
324 * of the system. Even if the other end accepts, if GENSEC
325 * claims 'MORE_PROCESSING_REQUIRED' then you must keep
326 * feeding it blobs, or else the remote host/attacker might
327 * avoid mutal authentication requirements.
329 * Likewise, you must not feed GENSEC too much (after the OK),
330 * it doesn't like that either
333 gensec_status
= status
;
335 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
336 !NT_STATUS_IS_OK(status
)) {
339 if (NT_STATUS_IS_OK(status
) && output
.length
== 0) {
343 /* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
344 msg
= new_ldap_sasl_bind_msg(tmp_ctx
, conn
->gensec
->ops
->sasl_name
, (output
.data
?&output
:NULL
));
346 status
= NT_STATUS_NO_MEMORY
;
350 req
= ldap_request_send(conn
, msg
);
352 status
= NT_STATUS_NO_MEMORY
;
355 talloc_steal(tmp_ctx
, req
);
357 status
= ldap_result_n(req
, 0, &response
);
358 if (!NT_STATUS_IS_OK(status
)) {
362 if (response
->type
!= LDAP_TAG_BindResponse
) {
363 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
367 result
= response
->r
.BindResponse
.response
.resultcode
;
369 if (result
!= LDAP_SUCCESS
&& result
!= LDAP_SASL_BIND_IN_PROGRESS
) {
370 status
= ldap_check_response(conn
,
371 &response
->r
.BindResponse
.response
);
375 /* This is where we check if GENSEC wanted to be fed more data */
376 if (!NT_STATUS_EQUAL(gensec_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
379 if (response
->r
.BindResponse
.SASL
.secblob
) {
380 input
= *response
->r
.BindResponse
.SASL
.secblob
;
382 input
= data_blob(NULL
, 0);
386 talloc_free(tmp_ctx
);
388 if (NT_STATUS_IS_OK(status
)) {
389 struct socket_context
*sasl_socket
;
390 status
= gensec_socket_init(conn
->gensec
,
393 conn
->event
.event_ctx
,
394 ldap_read_io_handler
,
397 if (!NT_STATUS_IS_OK(status
)) goto failed
;
399 conn
->sock
= sasl_socket
;
400 packet_set_socket(conn
->packet
, conn
->sock
);
402 conn
->bind
.type
= LDAP_BIND_SASL
;
403 conn
->bind
.creds
= creds
;
409 talloc_free(tmp_ctx
);
410 talloc_free(conn
->gensec
);