2 Unix SMB/CIFS mplementation.
3 LDAP protocol helper functions for SAMBA
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Simo Sorce 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "system/network.h"
28 #include "auth/auth.h"
30 #include "dlinklist.h"
33 static struct ldap_message
*new_ldap_search_message(struct ldap_connection
*conn
,
35 enum ldap_scope scope
,
38 const char **attributes
)
40 struct ldap_message
*res
;
42 res
= new_ldap_message(conn
);
47 res
->type
= LDAP_TAG_SearchRequest
;
48 res
->r
.SearchRequest
.basedn
= base
;
49 res
->r
.SearchRequest
.scope
= scope
;
50 res
->r
.SearchRequest
.deref
= LDAP_DEREFERENCE_NEVER
;
51 res
->r
.SearchRequest
.timelimit
= 0;
52 res
->r
.SearchRequest
.sizelimit
= 0;
53 res
->r
.SearchRequest
.attributesonly
= False
;
54 res
->r
.SearchRequest
.filter
= filter
;
55 res
->r
.SearchRequest
.num_attributes
= num_attributes
;
56 res
->r
.SearchRequest
.attributes
= attributes
;
62 static struct ldap_message
*new_ldap_simple_bind_msg(struct ldap_connection
*conn
, const char *dn
, const char *pw
)
64 struct ldap_message
*res
;
66 res
= new_ldap_message(conn
);
71 res
->type
= LDAP_TAG_BindRequest
;
72 res
->r
.BindRequest
.version
= 3;
73 res
->r
.BindRequest
.dn
= talloc_strdup(res
->mem_ctx
, dn
);
74 res
->r
.BindRequest
.mechanism
= LDAP_AUTH_MECH_SIMPLE
;
75 res
->r
.BindRequest
.creds
.password
= talloc_strdup(res
->mem_ctx
, pw
);
80 static struct ldap_message
*new_ldap_sasl_bind_msg(struct ldap_connection
*conn
, const char *sasl_mechanism
, DATA_BLOB
*secblob
)
82 struct ldap_message
*res
;
84 res
= new_ldap_message(conn
);
89 res
->type
= LDAP_TAG_BindRequest
;
90 res
->r
.BindRequest
.version
= 3;
91 res
->r
.BindRequest
.dn
= "";
92 res
->r
.BindRequest
.mechanism
= LDAP_AUTH_MECH_SASL
;
93 res
->r
.BindRequest
.creds
.SASL
.mechanism
= talloc_strdup(res
->mem_ctx
, sasl_mechanism
);
94 res
->r
.BindRequest
.creds
.SASL
.secblob
= *secblob
;
99 static struct ldap_connection
*new_ldap_connection(TALLOC_CTX
*mem_ctx
)
101 struct ldap_connection
*result
;
103 result
= talloc_p(mem_ctx
, struct ldap_connection
);
109 result
->mem_ctx
= result
;
110 result
->next_msgid
= 1;
111 result
->outstanding
= NULL
;
112 result
->searchid
= 0;
113 result
->search_entries
= NULL
;
114 result
->auth_dn
= NULL
;
115 result
->simple_pw
= NULL
;
116 result
->gensec
= NULL
;
121 struct ldap_connection
*ldap_connect(TALLOC_CTX
*mem_ctx
, const char *url
)
125 struct ldap_connection
*conn
;
128 conn
= new_ldap_connection(mem_ctx
);
133 ret
= ldap_parse_basic_url(conn
->mem_ctx
, url
, &conn
->host
,
134 &conn
->port
, &conn
->ldaps
);
140 hp
= sys_gethostbyname(conn
->host
);
141 if (!hp
|| !hp
->h_addr
) {
146 putip((char *)&ip
, (char *)hp
->h_addr
);
148 conn
->sock
= open_socket_out(SOCK_STREAM
, &ip
, conn
->port
, LDAP_CONNECTION_TIMEOUT
);
149 if (conn
->sock
< 0) {
157 struct ldap_message
*new_ldap_message(TALLOC_CTX
*mem_ctx
)
159 struct ldap_message
*result
;
161 result
= talloc_p(mem_ctx
, struct ldap_message
);
167 result
->mem_ctx
= result
;
172 BOOL
ldap_send_msg(struct ldap_connection
*conn
, struct ldap_message
*msg
,
173 const struct timeval
*endtime
)
177 struct ldap_queue_entry
*entry
;
179 msg
->messageid
= conn
->next_msgid
++;
181 if (!ldap_encode(msg
, &request
))
184 result
= (write_data_until(conn
->sock
, request
.data
, request
.length
,
185 endtime
) == request
.length
);
187 data_blob_free(&request
);
192 /* abandon and unbind don't expect results */
194 if ((msg
->type
== LDAP_TAG_AbandonRequest
) ||
195 (msg
->type
== LDAP_TAG_UnbindRequest
))
198 entry
= malloc_p(struct ldap_queue_entry
);
203 entry
->msgid
= msg
->messageid
;
205 DLIST_ADD(conn
->outstanding
, entry
);
210 BOOL
ldap_receive_msg(struct ldap_connection
*conn
, struct ldap_message
*msg
,
211 const struct timeval
*endtime
)
213 struct asn1_data data
;
216 if (!asn1_read_sequence_until(conn
->sock
, &data
, endtime
))
219 result
= ldap_decode(&data
, msg
);
225 static struct ldap_message
*recv_from_queue(struct ldap_connection
*conn
,
228 struct ldap_queue_entry
*e
;
230 for (e
= conn
->outstanding
; e
!= NULL
; e
= e
->next
) {
232 if (e
->msgid
== msgid
) {
233 struct ldap_message
*result
= e
->msg
;
234 DLIST_REMOVE(conn
->outstanding
, e
);
243 static void add_search_entry(struct ldap_connection
*conn
,
244 struct ldap_message
*msg
)
246 struct ldap_queue_entry
*e
= malloc_p(struct ldap_queue_entry
);
252 DLIST_ADD_END(conn
->search_entries
, e
, struct ldap_queue_entry
*);
256 static void fill_outstanding_request(struct ldap_connection
*conn
,
257 struct ldap_message
*msg
)
259 struct ldap_queue_entry
*e
;
261 for (e
= conn
->outstanding
; e
!= NULL
; e
= e
->next
) {
262 if (e
->msgid
== msg
->messageid
) {
268 /* This reply has not been expected, destroy the incoming msg */
273 struct ldap_message
*ldap_receive(struct ldap_connection
*conn
, int msgid
,
274 const struct timeval
*endtime
)
276 struct ldap_message
*result
= recv_from_queue(conn
, msgid
);
282 struct asn1_data data
;
285 result
= new_ldap_message(conn
);
287 if (!asn1_read_sequence_until(conn
->sock
, &data
, endtime
))
290 res
= ldap_decode(&data
, result
);
296 if (result
->messageid
== msgid
)
299 if (result
->type
== LDAP_TAG_SearchResultEntry
) {
300 add_search_entry(conn
, result
);
302 fill_outstanding_request(conn
, result
);
309 struct ldap_message
*ldap_transaction(struct ldap_connection
*conn
,
310 struct ldap_message
*request
)
312 if (!ldap_send_msg(conn
, request
, NULL
))
315 return ldap_receive(conn
, request
->messageid
, NULL
);
318 int ldap_bind_simple(struct ldap_connection
*conn
, const char *userdn
, const char *password
)
320 struct ldap_message
*response
;
321 struct ldap_message
*msg
;
323 int result
= LDAP_OTHER
;
341 if (conn
->simple_pw
) {
342 pw
= conn
->simple_pw
;
348 msg
= new_ldap_simple_bind_msg(conn
, dn
, pw
);
352 response
= ldap_transaction(conn
, msg
);
358 result
= response
->r
.BindResponse
.response
.resultcode
;
361 talloc_free(response
);
366 int ldap_bind_sasl(struct ldap_connection
*conn
, const char *username
, const char *domain
, const char *password
)
369 TALLOC_CTX
*mem_ctx
= NULL
;
370 struct ldap_message
*response
;
371 struct ldap_message
*msg
;
372 DATA_BLOB input
= data_blob(NULL
, 0);
373 DATA_BLOB output
= data_blob(NULL
, 0);
374 int result
= LDAP_OTHER
;
379 status
= gensec_client_start(conn
, &conn
->gensec
);
380 if (!NT_STATUS_IS_OK(status
)) {
381 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status
)));
385 gensec_want_feature(conn
->gensec
, GENSEC_FEATURE_SIGN
| GENSEC_FEATURE_SEAL
);
387 status
= gensec_set_domain(conn
->gensec
, domain
);
388 if (!NT_STATUS_IS_OK(status
)) {
389 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
390 domain
, nt_errstr(status
)));
394 status
= gensec_set_username(conn
->gensec
, username
);
395 if (!NT_STATUS_IS_OK(status
)) {
396 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
397 username
, nt_errstr(status
)));
401 status
= gensec_set_password(conn
->gensec
, password
);
402 if (!NT_STATUS_IS_OK(status
)) {
403 DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
408 status
= gensec_set_target_hostname(conn
->gensec
, conn
->host
);
409 if (!NT_STATUS_IS_OK(status
)) {
410 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
415 status
= gensec_set_target_service(conn
->gensec
, "ldap");
416 if (!NT_STATUS_IS_OK(status
)) {
417 DEBUG(1, ("Failed to start set GENSEC target service: %s\n",
422 status
= gensec_start_mech_by_sasl_name(conn
->gensec
, "GSS-SPNEGO");
423 if (!NT_STATUS_IS_OK(status
)) {
424 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
429 mem_ctx
= talloc_init("ldap_bind_sasl");
433 status
= gensec_update(conn
->gensec
, mem_ctx
,
438 if (NT_STATUS_IS_OK(status
) && output
.length
== 0) {
441 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
445 msg
= new_ldap_sasl_bind_msg(conn
, "GSS-SPNEGO", &output
);
449 response
= ldap_transaction(conn
, msg
);
456 result
= response
->r
.BindResponse
.response
.resultcode
;
458 if (result
!= LDAP_SUCCESS
&& result
!= LDAP_SASL_BIND_IN_PROGRESS
) {
462 if (!NT_STATUS_IS_OK(status
)) {
463 status
= gensec_update(conn
->gensec
, mem_ctx
,
464 response
->r
.BindResponse
.SASL
.secblob
,
470 talloc_free(response
);
475 talloc_destroy(mem_ctx
);
480 struct ldap_connection
*ldap_setup_connection(TALLOC_CTX
*mem_ctx
, const char *url
,
481 const char *userdn
, const char *password
)
483 struct ldap_connection
*conn
;
486 conn
=ldap_connect(mem_ctx
, url
);
491 result
= ldap_bind_simple(conn
, userdn
, password
);
492 if (result
!= LDAP_SUCCESS
) {
500 struct ldap_connection
*ldap_setup_connection_with_sasl(TALLOC_CTX
*mem_ctx
, const char *url
,
501 const char *username
, const char *domain
, const char *password
)
503 struct ldap_connection
*conn
;
506 conn
=ldap_connect(mem_ctx
, url
);
511 result
= ldap_bind_sasl(conn
, username
, domain
, password
);
512 if (result
!= LDAP_SUCCESS
) {
520 BOOL
ldap_abandon_message(struct ldap_connection
*conn
, int msgid
,
521 const struct timeval
*endtime
)
523 struct ldap_message
*msg
= new_ldap_message(conn
);
529 msg
->type
= LDAP_TAG_AbandonRequest
;
530 msg
->r
.AbandonRequest
.messageid
= msgid
;
532 result
= ldap_send_msg(conn
, msg
, endtime
);
537 BOOL
ldap_setsearchent(struct ldap_connection
*conn
, struct ldap_message
*msg
,
538 const struct timeval
*endtime
)
540 if ((conn
->searchid
!= 0) &&
541 (!ldap_abandon_message(conn
, conn
->searchid
, endtime
)))
544 conn
->searchid
= conn
->next_msgid
;
545 return ldap_send_msg(conn
, msg
, endtime
);
548 struct ldap_message
*ldap_getsearchent(struct ldap_connection
*conn
,
549 const struct timeval
*endtime
)
551 struct ldap_message
*result
;
553 if (conn
->search_entries
!= NULL
) {
554 struct ldap_queue_entry
*e
= conn
->search_entries
;
557 DLIST_REMOVE(conn
->search_entries
, e
);
562 result
= ldap_receive(conn
, conn
->searchid
, endtime
);
567 if (result
->type
== LDAP_TAG_SearchResultEntry
)
570 if (result
->type
== LDAP_TAG_SearchResultDone
) {
571 /* TODO: Handle Paged Results */
576 /* TODO: Handle Search References here */
580 void ldap_endsearchent(struct ldap_connection
*conn
,
581 const struct timeval
*endtime
)
583 struct ldap_queue_entry
*e
;
585 e
= conn
->search_entries
;
588 struct ldap_queue_entry
*next
= e
->next
;
589 DLIST_REMOVE(conn
->search_entries
, e
);
595 struct ldap_message
*ldap_searchone(struct ldap_connection
*conn
,
596 struct ldap_message
*msg
,
597 const struct timeval
*endtime
)
599 struct ldap_message
*res1
, *res2
= NULL
;
600 if (!ldap_setsearchent(conn
, msg
, endtime
))
603 res1
= ldap_getsearchent(conn
, endtime
);
606 res2
= ldap_getsearchent(conn
, endtime
);
608 ldap_endsearchent(conn
, endtime
);
614 /* More than one entry */
623 BOOL
ldap_find_single_value(struct ldap_message
*msg
, const char *attr
,
627 struct ldap_SearchResEntry
*r
= &msg
->r
.SearchResultEntry
;
629 if (msg
->type
!= LDAP_TAG_SearchResultEntry
)
632 for (i
=0; i
<r
->num_attributes
; i
++) {
633 if (strequal(attr
, r
->attributes
[i
].name
)) {
634 if (r
->attributes
[i
].num_values
!= 1)
637 *value
= r
->attributes
[i
].values
[0];
644 BOOL
ldap_find_single_string(struct ldap_message
*msg
, const char *attr
,
645 TALLOC_CTX
*mem_ctx
, char **value
)
649 if (!ldap_find_single_value(msg
, attr
, &blob
))
652 *value
= talloc_size(mem_ctx
, blob
.length
+1);
657 memcpy(*value
, blob
.data
, blob
.length
);
658 (*value
)[blob
.length
] = '\0';
662 BOOL
ldap_find_single_int(struct ldap_message
*msg
, const char *attr
,
670 if (!ldap_find_single_value(msg
, attr
, &blob
))
673 val
= malloc(blob
.length
+1);
677 memcpy(val
, blob
.data
, blob
.length
);
678 val
[blob
.length
] = '\0';
683 *value
= strtol(val
, NULL
, 10);
693 int ldap_error(struct ldap_connection
*conn
)
698 NTSTATUS
ldap2nterror(int ldaperror
)