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"
34 /****************************************************************************
36 ****************************************************************************/
37 static BOOL timeout_until(struct timeval *timeout,
38 const struct timeval *endtime)
44 if ((now.tv_sec > endtime->tv_sec) ||
45 ((now.tv_sec == endtime->tv_sec) &&
46 (now.tv_usec > endtime->tv_usec)))
49 timeout->tv_sec = endtime->tv_sec - now.tv_sec;
50 timeout->tv_usec = endtime->tv_usec - now.tv_usec;
55 /****************************************************************************
56 Read data from the client, reading exactly N bytes, with timeout.
57 ****************************************************************************/
58 static ssize_t read_data_until(int fd,char *buffer,size_t N,
59 const struct timeval *endtime)
66 if (endtime != NULL) {
68 struct timeval timeout;
74 if (!timeout_until(&timeout, endtime))
77 res = sys_select(fd+1, &r_fds, NULL, NULL, &timeout);
82 ret = sys_read(fd,buffer + total,N - total);
85 DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
90 DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
95 return (ssize_t)total;
99 /****************************************************************************
100 Write data to a fd with timeout.
101 ****************************************************************************/
102 static ssize_t write_data_until(int fd,char *buffer,size_t N,
103 const struct timeval *endtime)
110 if (endtime != NULL) {
112 struct timeval timeout;
118 if (!timeout_until(&timeout, endtime))
121 res = sys_select(fd+1, NULL, &w_fds, NULL, &timeout);
126 ret = sys_write(fd,buffer + total,N - total);
129 DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
137 return (ssize_t)total;
142 static BOOL read_one_uint8(int sock, uint8_t *result, struct asn1_data *data,
143 const struct timeval *endtime)
145 if (read_data_until(sock, result, 1, endtime) != 1)
148 return asn1_write(data, result, 1);
151 /* Read a complete ASN sequence (ie LDAP result) from a socket */
152 static BOOL asn1_read_sequence_until(int sock, struct asn1_data *data,
153 const struct timeval *endtime)
161 if (!read_one_uint8(sock, &b, data, endtime))
165 data->has_error = True;
169 if (!read_one_uint8(sock, &b, data, endtime))
174 if (!read_one_uint8(sock, &b, data, endtime))
178 if (!read_one_uint8(sock, &b, data, endtime))
187 buf = talloc_size(NULL, len);
191 if (read_data_until(sock, buf, len, endtime) != len)
194 if (!asn1_write(data, buf, len))
206 /****************************************************************************
207 create an outgoing socket. timeout is in milliseconds.
208 **************************************************************************/
209 static int open_socket_out(int type, struct ipv4_addr *addr, int port, int timeout)
211 struct sockaddr_in sock_out;
213 int connect_loop = 250; /* 250 milliseconds */
214 int loops = (timeout) / connect_loop;
216 /* create a socket to write to */
217 res = socket(PF_INET, type, 0);
219 { DEBUG(0,("socket error\n")); return -1; }
221 if (type != SOCK_STREAM) return(res);
223 memset((char *)&sock_out,'\0',sizeof(sock_out));
224 putip((char *)&sock_out.sin_addr,(char *)addr);
226 sock_out.sin_port = htons( port );
227 sock_out.sin_family = PF_INET;
229 /* set it non-blocking */
230 set_blocking(res,False);
232 DEBUG(3,("Connecting to %s at port %d\n", sys_inet_ntoa(*addr),port));
234 /* and connect it to the destination */
236 ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
238 /* Some systems return EAGAIN when they mean EINPROGRESS */
239 if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
240 errno == EAGAIN) && loops--) {
241 msleep(connect_loop);
245 if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
247 DEBUG(1,("timeout connecting to %s:%d\n", sys_inet_ntoa(*addr),port));
253 if (ret < 0 && errno == EISCONN) {
260 DEBUG(2,("error connecting to %s:%d (%s)\n",
261 sys_inet_ntoa(*addr),port,strerror(errno)));
266 /* set it blocking again */
267 set_blocking(res,True);
273 static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn,
275 enum ldap_scope scope,
278 const char **attributes)
280 struct ldap_message *res;
282 res = new_ldap_message(conn);
287 res->type = LDAP_TAG_SearchRequest;
288 res->r.SearchRequest.basedn = base;
289 res->r.SearchRequest.scope = scope;
290 res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
291 res->r.SearchRequest.timelimit = 0;
292 res->r.SearchRequest.sizelimit = 0;
293 res->r.SearchRequest.attributesonly = False;
294 res->r.SearchRequest.filter = filter;
295 res->r.SearchRequest.num_attributes = num_attributes;
296 res->r.SearchRequest.attributes = attributes;
302 static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw)
304 struct ldap_message *res;
306 res = new_ldap_message(conn);
311 res->type = LDAP_TAG_BindRequest;
312 res->r.BindRequest.version = 3;
313 res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
314 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
315 res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
320 static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, const char *sasl_mechanism, DATA_BLOB *secblob)
322 struct ldap_message *res;
324 res = new_ldap_message(conn);
329 res->type = LDAP_TAG_BindRequest;
330 res->r.BindRequest.version = 3;
331 res->r.BindRequest.dn = "";
332 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
333 res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
334 res->r.BindRequest.creds.SASL.secblob = *secblob;
339 static struct ldap_connection *new_ldap_connection(TALLOC_CTX *mem_ctx)
341 struct ldap_connection *result;
343 result = talloc(mem_ctx, struct ldap_connection);
349 result->mem_ctx = result;
350 result->next_msgid = 1;
351 result->outstanding = NULL;
352 result->searchid = 0;
353 result->search_entries = NULL;
354 result->auth_dn = NULL;
355 result->simple_pw = NULL;
356 result->gensec = NULL;
361 struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
365 struct ldap_connection *conn;
368 conn = new_ldap_connection(mem_ctx);
373 ret = ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
374 &conn->port, &conn->ldaps);
380 hp = sys_gethostbyname(conn->host);
381 if (!hp || !hp->h_addr) {
386 putip((char *)&ip, (char *)hp->h_addr);
388 conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
389 if (conn->sock < 0) {
397 struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
399 struct ldap_message *result;
401 result = talloc(mem_ctx, struct ldap_message);
407 result->mem_ctx = result;
412 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
413 const struct timeval *endtime)
417 struct ldap_queue_entry *entry;
419 msg->messageid = conn->next_msgid++;
421 if (!ldap_encode(msg, &request))
424 result = (write_data_until(conn->sock, request.data, request.length,
425 endtime) == request.length);
427 data_blob_free(&request);
432 /* abandon and unbind don't expect results */
434 if ((msg->type == LDAP_TAG_AbandonRequest) ||
435 (msg->type == LDAP_TAG_UnbindRequest))
438 entry = malloc_p(struct ldap_queue_entry);
443 entry->msgid = msg->messageid;
445 DLIST_ADD(conn->outstanding, entry);
450 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
451 const struct timeval *endtime)
453 struct asn1_data data;
456 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
459 result = ldap_decode(&data, msg);
465 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
468 struct ldap_queue_entry *e;
470 for (e = conn->outstanding; e != NULL; e = e->next) {
472 if (e->msgid == msgid) {
473 struct ldap_message *result = e->msg;
474 DLIST_REMOVE(conn->outstanding, e);
483 static void add_search_entry(struct ldap_connection *conn,
484 struct ldap_message *msg)
486 struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry);
492 DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
496 static void fill_outstanding_request(struct ldap_connection *conn,
497 struct ldap_message *msg)
499 struct ldap_queue_entry *e;
501 for (e = conn->outstanding; e != NULL; e = e->next) {
502 if (e->msgid == msg->messageid) {
508 /* This reply has not been expected, destroy the incoming msg */
513 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
514 const struct timeval *endtime)
516 struct ldap_message *result = recv_from_queue(conn, msgid);
522 struct asn1_data data;
525 result = new_ldap_message(conn);
527 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
530 res = ldap_decode(&data, result);
536 if (result->messageid == msgid)
539 if (result->type == LDAP_TAG_SearchResultEntry) {
540 add_search_entry(conn, result);
542 fill_outstanding_request(conn, result);
549 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
550 struct ldap_message *request)
552 if (!ldap_send_msg(conn, request, NULL))
555 return ldap_receive(conn, request->messageid, NULL);
558 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
560 struct ldap_message *response;
561 struct ldap_message *msg;
563 int result = LDAP_OTHER;
581 if (conn->simple_pw) {
582 pw = conn->simple_pw;
588 msg = new_ldap_simple_bind_msg(conn, dn, pw);
592 response = ldap_transaction(conn, msg);
598 result = response->r.BindResponse.response.resultcode;
601 talloc_free(response);
606 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
609 TALLOC_CTX *mem_ctx = NULL;
610 struct ldap_message *response;
611 struct ldap_message *msg;
612 DATA_BLOB input = data_blob(NULL, 0);
613 DATA_BLOB output = data_blob(NULL, 0);
614 int result = LDAP_OTHER;
619 status = gensec_client_start(conn, &conn->gensec);
620 if (!NT_STATUS_IS_OK(status)) {
621 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
625 gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
627 status = gensec_set_domain(conn->gensec, domain);
628 if (!NT_STATUS_IS_OK(status)) {
629 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
630 domain, nt_errstr(status)));
634 status = gensec_set_username(conn->gensec, username);
635 if (!NT_STATUS_IS_OK(status)) {
636 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
637 username, nt_errstr(status)));
641 status = gensec_set_password(conn->gensec, password);
642 if (!NT_STATUS_IS_OK(status)) {
643 DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
648 status = gensec_set_target_hostname(conn->gensec, conn->host);
649 if (!NT_STATUS_IS_OK(status)) {
650 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
655 status = gensec_set_target_service(conn->gensec, "ldap");
656 if (!NT_STATUS_IS_OK(status)) {
657 DEBUG(1, ("Failed to start set GENSEC target service: %s\n",
662 status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
663 if (!NT_STATUS_IS_OK(status)) {
664 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
669 mem_ctx = talloc_init("ldap_bind_sasl");
673 status = gensec_update(conn->gensec, mem_ctx,
678 if (NT_STATUS_IS_OK(status) && output.length == 0) {
681 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
685 msg = new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
689 response = ldap_transaction(conn, msg);
696 result = response->r.BindResponse.response.resultcode;
698 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
702 if (!NT_STATUS_IS_OK(status)) {
703 status = gensec_update(conn->gensec, mem_ctx,
704 response->r.BindResponse.SASL.secblob,
710 talloc_free(response);
715 talloc_free(mem_ctx);
720 struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url,
721 const char *userdn, const char *password)
723 struct ldap_connection *conn;
726 conn =ldap_connect(mem_ctx, url);
731 result = ldap_bind_simple(conn, userdn, password);
732 if (result != LDAP_SUCCESS) {
740 struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url,
741 const char *username, const char *domain, const char *password)
743 struct ldap_connection *conn;
746 conn =ldap_connect(mem_ctx, url);
751 result = ldap_bind_sasl(conn, username, domain, password);
752 if (result != LDAP_SUCCESS) {
760 BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
761 const struct timeval *endtime)
763 struct ldap_message *msg = new_ldap_message(conn);
769 msg->type = LDAP_TAG_AbandonRequest;
770 msg->r.AbandonRequest.messageid = msgid;
772 result = ldap_send_msg(conn, msg, endtime);
777 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
778 const struct timeval *endtime)
780 if ((conn->searchid != 0) &&
781 (!ldap_abandon_message(conn, conn->searchid, endtime)))
784 conn->searchid = conn->next_msgid;
785 return ldap_send_msg(conn, msg, endtime);
788 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
789 const struct timeval *endtime)
791 struct ldap_message *result;
793 if (conn->search_entries != NULL) {
794 struct ldap_queue_entry *e = conn->search_entries;
797 DLIST_REMOVE(conn->search_entries, e);
802 result = ldap_receive(conn, conn->searchid, endtime);
807 if (result->type == LDAP_TAG_SearchResultEntry)
810 if (result->type == LDAP_TAG_SearchResultDone) {
811 /* TODO: Handle Paged Results */
816 /* TODO: Handle Search References here */
820 void ldap_endsearchent(struct ldap_connection *conn,
821 const struct timeval *endtime)
823 struct ldap_queue_entry *e;
825 e = conn->search_entries;
828 struct ldap_queue_entry *next = e->next;
829 DLIST_REMOVE(conn->search_entries, e);
835 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
836 struct ldap_message *msg,
837 const struct timeval *endtime)
839 struct ldap_message *res1, *res2 = NULL;
840 if (!ldap_setsearchent(conn, msg, endtime))
843 res1 = ldap_getsearchent(conn, endtime);
846 res2 = ldap_getsearchent(conn, endtime);
848 ldap_endsearchent(conn, endtime);
854 /* More than one entry */
863 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
867 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
869 if (msg->type != LDAP_TAG_SearchResultEntry)
872 for (i=0; i<r->num_attributes; i++) {
873 if (strequal(attr, r->attributes[i].name)) {
874 if (r->attributes[i].num_values != 1)
877 *value = r->attributes[i].values[0];
884 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
885 TALLOC_CTX *mem_ctx, char **value)
889 if (!ldap_find_single_value(msg, attr, &blob))
892 *value = talloc_size(mem_ctx, blob.length+1);
897 memcpy(*value, blob.data, blob.length);
898 (*value)[blob.length] = '\0';
902 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
910 if (!ldap_find_single_value(msg, attr, &blob))
913 val = malloc(blob.length+1);
917 memcpy(val, blob.data, blob.length);
918 val[blob.length] = '\0';
923 *value = strtol(val, NULL, 10);
933 int ldap_error(struct ldap_connection *conn)
938 NTSTATUS ldap2nterror(int ldaperror)