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/gensec/gensec_socket.h"
31 #include "auth/credentials/credentials.h"
32 #include "lib/stream/packet.h"
33 #include "param/param.h"
35 struct ldap_simple_creds
{
40 _PUBLIC_ NTSTATUS
ldap_rebind(struct ldap_connection
*conn
)
43 struct ldap_simple_creds
*creds
;
45 switch (conn
->bind
.type
) {
47 status
= ldap_bind_sasl(conn
, (struct cli_credentials
*)conn
->bind
.creds
,
51 case LDAP_BIND_SIMPLE
:
52 creds
= (struct ldap_simple_creds
*)conn
->bind
.creds
;
55 return NT_STATUS_UNSUCCESSFUL
;
58 status
= ldap_bind_simple(conn
, creds
->dn
, creds
->pw
);
62 return NT_STATUS_UNSUCCESSFUL
;
69 static struct ldap_message
*new_ldap_simple_bind_msg(struct ldap_connection
*conn
,
70 const char *dn
, const char *pw
)
72 struct ldap_message
*res
;
74 res
= new_ldap_message(conn
);
79 res
->type
= LDAP_TAG_BindRequest
;
80 res
->r
.BindRequest
.version
= 3;
81 res
->r
.BindRequest
.dn
= talloc_strdup(res
, dn
);
82 res
->r
.BindRequest
.mechanism
= LDAP_AUTH_MECH_SIMPLE
;
83 res
->r
.BindRequest
.creds
.password
= talloc_strdup(res
, pw
);
91 perform a simple username/password bind
93 _PUBLIC_ NTSTATUS
ldap_bind_simple(struct ldap_connection
*conn
,
94 const char *userdn
, const char *password
)
96 struct ldap_request
*req
;
97 struct ldap_message
*msg
;
102 return NT_STATUS_INVALID_CONNECTION
;
118 if (conn
->simple_pw
) {
119 pw
= conn
->simple_pw
;
125 msg
= new_ldap_simple_bind_msg(conn
, dn
, pw
);
126 NT_STATUS_HAVE_NO_MEMORY(msg
);
128 /* send the request */
129 req
= ldap_request_send(conn
, msg
);
131 NT_STATUS_HAVE_NO_MEMORY(req
);
133 /* wait for replies */
134 status
= ldap_request_wait(req
);
135 if (!NT_STATUS_IS_OK(status
)) {
140 /* check its a valid reply */
141 msg
= req
->replies
[0];
142 if (msg
->type
!= LDAP_TAG_BindResponse
) {
144 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
147 status
= ldap_check_response(conn
, &msg
->r
.BindResponse
.response
);
151 if (NT_STATUS_IS_OK(status
)) {
152 struct ldap_simple_creds
*creds
= talloc(conn
, struct ldap_simple_creds
);
154 return NT_STATUS_NO_MEMORY
;
156 creds
->dn
= talloc_strdup(creds
, dn
);
157 creds
->pw
= talloc_strdup(creds
, pw
);
158 if (creds
->dn
== NULL
|| creds
->pw
== NULL
) {
159 return NT_STATUS_NO_MEMORY
;
161 conn
->bind
.type
= LDAP_BIND_SIMPLE
;
162 conn
->bind
.creds
= creds
;
169 static struct ldap_message
*new_ldap_sasl_bind_msg(struct ldap_connection
*conn
,
170 const char *sasl_mechanism
,
173 struct ldap_message
*res
;
175 res
= new_ldap_message(conn
);
180 res
->type
= LDAP_TAG_BindRequest
;
181 res
->r
.BindRequest
.version
= 3;
182 res
->r
.BindRequest
.dn
= "";
183 res
->r
.BindRequest
.mechanism
= LDAP_AUTH_MECH_SASL
;
184 res
->r
.BindRequest
.creds
.SASL
.mechanism
= talloc_strdup(res
, sasl_mechanism
);
186 res
->r
.BindRequest
.creds
.SASL
.secblob
= talloc(res
, DATA_BLOB
);
187 if (!res
->r
.BindRequest
.creds
.SASL
.secblob
) {
191 *res
->r
.BindRequest
.creds
.SASL
.secblob
= *secblob
;
193 res
->r
.BindRequest
.creds
.SASL
.secblob
= NULL
;
195 res
->controls
= NULL
;
202 perform a sasl bind using the given credentials
204 _PUBLIC_ NTSTATUS
ldap_bind_sasl(struct ldap_connection
*conn
,
205 struct cli_credentials
*creds
,
206 struct loadparm_context
*lp_ctx
)
209 TALLOC_CTX
*tmp_ctx
= NULL
;
211 DATA_BLOB input
= data_blob(NULL
, 0);
212 DATA_BLOB output
= data_blob(NULL
, 0);
214 struct ldap_message
**sasl_mechs_msgs
;
215 struct ldap_SearchResEntry
*search
;
218 const char **sasl_names
;
219 uint32_t old_gensec_features
;
220 static const char *supported_sasl_mech_attrs
[] = {
221 "supportedSASLMechanisms",
227 status
= gensec_client_start(conn
, &conn
->gensec
,
228 lpcfg_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
,
321 conn
->event
.event_ctx
,
324 /* The status value here, from GENSEC is vital to the security
325 * of the system. Even if the other end accepts, if GENSEC
326 * claims 'MORE_PROCESSING_REQUIRED' then you must keep
327 * feeding it blobs, or else the remote host/attacker might
328 * avoid mutal authentication requirements.
330 * Likewise, you must not feed GENSEC too much (after the OK),
331 * it doesn't like that either
334 gensec_status
= status
;
336 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
337 !NT_STATUS_IS_OK(status
)) {
340 if (NT_STATUS_IS_OK(status
) && output
.length
== 0) {
344 /* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
345 msg
= new_ldap_sasl_bind_msg(tmp_ctx
, conn
->gensec
->ops
->sasl_name
, (output
.data
?&output
:NULL
));
347 status
= NT_STATUS_NO_MEMORY
;
351 req
= ldap_request_send(conn
, msg
);
353 status
= NT_STATUS_NO_MEMORY
;
356 talloc_reparent(conn
, tmp_ctx
, req
);
358 status
= ldap_result_n(req
, 0, &response
);
359 if (!NT_STATUS_IS_OK(status
)) {
363 if (response
->type
!= LDAP_TAG_BindResponse
) {
364 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
368 result
= response
->r
.BindResponse
.response
.resultcode
;
370 if (result
!= LDAP_SUCCESS
&& result
!= LDAP_SASL_BIND_IN_PROGRESS
) {
371 status
= ldap_check_response(conn
,
372 &response
->r
.BindResponse
.response
);
376 /* This is where we check if GENSEC wanted to be fed more data */
377 if (!NT_STATUS_EQUAL(gensec_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
380 if (response
->r
.BindResponse
.SASL
.secblob
) {
381 input
= *response
->r
.BindResponse
.SASL
.secblob
;
383 input
= data_blob(NULL
, 0);
387 talloc_free(tmp_ctx
);
389 if (NT_STATUS_IS_OK(status
)) {
390 struct socket_context
*sasl_socket
;
391 status
= gensec_socket_init(conn
->gensec
,
394 conn
->event
.event_ctx
,
395 ldap_read_io_handler
,
398 if (!NT_STATUS_IS_OK(status
)) goto failed
;
400 conn
->sock
= sasl_socket
;
401 packet_set_socket(conn
->packet
, conn
->sock
);
403 conn
->bind
.type
= LDAP_BIND_SASL
;
404 conn
->bind
.creds
= creds
;
410 talloc_free(tmp_ctx
);
411 talloc_free(conn
->gensec
);