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 "system/filesys.h"
29 #include "auth/auth.h"
31 #include "dlinklist.h"
32 #include "libcli/ldap/ldap.h"
36 /****************************************************************************
38 ****************************************************************************/
39 static BOOL timeout_until(struct timeval *timeout,
40 const struct timeval *endtime)
46 if ((now.tv_sec > endtime->tv_sec) ||
47 ((now.tv_sec == endtime->tv_sec) &&
48 (now.tv_usec > endtime->tv_usec)))
51 timeout->tv_sec = endtime->tv_sec - now.tv_sec;
52 timeout->tv_usec = endtime->tv_usec - now.tv_usec;
57 /****************************************************************************
58 Read data from the client, reading exactly N bytes, with timeout.
59 ****************************************************************************/
60 static ssize_t read_data_until(int fd,char *buffer,size_t N,
61 const struct timeval *endtime)
68 if (endtime != NULL) {
70 struct timeval timeout;
76 if (!timeout_until(&timeout, endtime))
79 res = sys_select(fd+1, &r_fds, NULL, NULL, &timeout);
84 ret = sys_read(fd,buffer + total,N - total);
87 DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
92 DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
97 return (ssize_t)total;
101 /****************************************************************************
102 Write data to a fd with timeout.
103 ****************************************************************************/
104 static ssize_t write_data_until(int fd,char *buffer,size_t N,
105 const struct timeval *endtime)
112 if (endtime != NULL) {
114 struct timeval timeout;
120 if (!timeout_until(&timeout, endtime))
123 res = sys_select(fd+1, NULL, &w_fds, NULL, &timeout);
128 ret = sys_write(fd,buffer + total,N - total);
131 DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
139 return (ssize_t)total;
144 static BOOL read_one_uint8(int sock, uint8_t *result, struct asn1_data *data,
145 const struct timeval *endtime)
147 if (read_data_until(sock, result, 1, endtime) != 1)
150 return asn1_write(data, result, 1);
153 /* Read a complete ASN sequence (ie LDAP result) from a socket */
154 static BOOL asn1_read_sequence_until(int sock, struct asn1_data *data,
155 const struct timeval *endtime)
163 if (!read_one_uint8(sock, &b, data, endtime))
167 data->has_error = True;
171 if (!read_one_uint8(sock, &b, data, endtime))
176 if (!read_one_uint8(sock, &b, data, endtime))
180 if (!read_one_uint8(sock, &b, data, endtime))
189 buf = talloc_size(NULL, len);
193 if (read_data_until(sock, buf, len, endtime) != len)
196 if (!asn1_write(data, buf, len))
208 /****************************************************************************
209 create an outgoing socket. timeout is in milliseconds.
210 **************************************************************************/
211 static int open_socket_out(int type, struct ipv4_addr *addr, int port, int timeout)
213 struct sockaddr_in sock_out;
215 int connect_loop = 250; /* 250 milliseconds */
216 int loops = (timeout) / connect_loop;
218 /* create a socket to write to */
219 res = socket(PF_INET, type, 0);
221 { DEBUG(0,("socket error\n")); return -1; }
223 if (type != SOCK_STREAM) return(res);
225 memset((char *)&sock_out,'\0',sizeof(sock_out));
226 sock_out.sin_addr.s_addr = addr->addr;
228 sock_out.sin_port = htons( port );
229 sock_out.sin_family = PF_INET;
231 /* set it non-blocking */
232 set_blocking(res,False);
234 DEBUG(3,("Connecting to %s at port %d\n", sys_inet_ntoa(*addr),port));
236 /* and connect it to the destination */
238 ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
240 /* Some systems return EAGAIN when they mean EINPROGRESS */
241 if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
242 errno == EAGAIN) && loops--) {
243 msleep(connect_loop);
247 if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
249 DEBUG(1,("timeout connecting to %s:%d\n", sys_inet_ntoa(*addr),port));
255 if (ret < 0 && errno == EISCONN) {
262 DEBUG(2,("error connecting to %s:%d (%s)\n",
263 sys_inet_ntoa(*addr),port,strerror(errno)));
268 /* set it blocking again */
269 set_blocking(res,True);
275 static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn,
277 enum ldap_scope scope,
280 const char **attributes)
282 struct ldap_message *res;
284 res = new_ldap_message(conn);
289 res->type = LDAP_TAG_SearchRequest;
290 res->r.SearchRequest.basedn = base;
291 res->r.SearchRequest.scope = scope;
292 res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
293 res->r.SearchRequest.timelimit = 0;
294 res->r.SearchRequest.sizelimit = 0;
295 res->r.SearchRequest.attributesonly = False;
296 res->r.SearchRequest.filter = filter;
297 res->r.SearchRequest.num_attributes = num_attributes;
298 res->r.SearchRequest.attributes = attributes;
304 static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw)
306 struct ldap_message *res;
308 res = new_ldap_message(conn);
313 res->type = LDAP_TAG_BindRequest;
314 res->r.BindRequest.version = 3;
315 res->r.BindRequest.dn = talloc_strdup(res, dn);
316 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
317 res->r.BindRequest.creds.password = talloc_strdup(res, pw);
322 static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, const char *sasl_mechanism, DATA_BLOB *secblob)
324 struct ldap_message *res;
326 res = new_ldap_message(conn);
331 res->type = LDAP_TAG_BindRequest;
332 res->r.BindRequest.version = 3;
333 res->r.BindRequest.dn = "";
334 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
335 res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
336 res->r.BindRequest.creds.SASL.secblob = *secblob;
341 static struct ldap_connection *new_ldap_connection(TALLOC_CTX *mem_ctx)
343 struct ldap_connection *result;
345 result = talloc(mem_ctx, struct ldap_connection);
351 result->next_msgid = 1;
352 result->outstanding = NULL;
353 result->searchid = 0;
354 result->search_entries = NULL;
355 result->auth_dn = NULL;
356 result->simple_pw = NULL;
357 result->gensec = NULL;
362 struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
366 struct ldap_connection *conn;
369 conn = new_ldap_connection(mem_ctx);
374 ret = ldap_parse_basic_url(conn, url, &conn->host,
375 &conn->port, &conn->ldaps);
381 hp = sys_gethostbyname(conn->host);
382 if (!hp || !hp->h_addr) {
387 memcpy((char *)&ip, (char *)hp->h_addr, 4);
389 conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
390 if (conn->sock < 0) {
398 struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
400 return talloc(mem_ctx, struct ldap_message);
403 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
404 const struct timeval *endtime)
408 struct ldap_queue_entry *entry;
410 msg->messageid = conn->next_msgid++;
412 if (!ldap_encode(msg, &request))
415 result = (write_data_until(conn->sock, request.data, request.length,
416 endtime) == request.length);
418 data_blob_free(&request);
423 /* abandon and unbind don't expect results */
425 if ((msg->type == LDAP_TAG_AbandonRequest) ||
426 (msg->type == LDAP_TAG_UnbindRequest))
429 entry = malloc_p(struct ldap_queue_entry);
434 entry->msgid = msg->messageid;
436 DLIST_ADD(conn->outstanding, entry);
441 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
442 const struct timeval *endtime)
444 struct asn1_data data;
447 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
450 result = ldap_decode(&data, msg);
456 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
459 struct ldap_queue_entry *e;
461 for (e = conn->outstanding; e != NULL; e = e->next) {
463 if (e->msgid == msgid) {
464 struct ldap_message *result = e->msg;
465 DLIST_REMOVE(conn->outstanding, e);
474 static void add_search_entry(struct ldap_connection *conn,
475 struct ldap_message *msg)
477 struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry);
483 DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
487 static void fill_outstanding_request(struct ldap_connection *conn,
488 struct ldap_message *msg)
490 struct ldap_queue_entry *e;
492 for (e = conn->outstanding; e != NULL; e = e->next) {
493 if (e->msgid == msg->messageid) {
499 /* This reply has not been expected, destroy the incoming msg */
504 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
505 const struct timeval *endtime)
507 struct ldap_message *result = recv_from_queue(conn, msgid);
513 struct asn1_data data;
516 result = new_ldap_message(conn);
518 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
521 res = ldap_decode(&data, result);
527 if (result->messageid == msgid)
530 if (result->type == LDAP_TAG_SearchResultEntry) {
531 add_search_entry(conn, result);
533 fill_outstanding_request(conn, result);
543 static ssize_t write_data(int fd, char *buffer, size_t N)
549 ret = sys_write(fd,buffer + total,N - total);
552 DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
561 return (ssize_t)total;
566 Read data from the client, reading exactly N bytes
568 static ssize_t read_data(int fd, char *buffer, size_t N)
575 ret = sys_read(fd,buffer + total,N - total);
578 DEBUG(10,("read_data: read of %d returned 0. Error = %s\n",
579 (int)(N - total), strerror(errno) ));
584 DEBUG(0,("read_data: read failure for %d. Error = %s\n",
585 (int)(N - total), strerror(errno) ));
591 return (ssize_t)total;
594 static struct ldap_message *ldap_transaction_sasl(struct ldap_connection *conn, struct ldap_message *req)
602 struct asn1_data asn1;
603 struct ldap_message *rep;
605 req->messageid = conn->next_msgid++;
607 if (!ldap_encode(req, &request))
610 status = gensec_wrap(conn->gensec,
614 if (!NT_STATUS_IS_OK(status)) {
615 DEBUG(0,("gensec_wrap: %s\n",nt_errstr(status)));
619 RSIVAL(length, 0, wrapped.length);
621 result = (write_data(conn->sock, length, 4) == 4);
625 result = (write_data(conn->sock, wrapped.data, wrapped.length) == wrapped.length);
629 wrapped = data_blob(NULL, 0x4000);
630 data_blob_clear(&wrapped);
632 result = (read_data(conn->sock, length, 4) == 4);
636 len = RIVAL(length,0);
638 result = (read_data(conn->sock, wrapped.data, MIN(wrapped.length,len)) == len);
642 wrapped.length = len;
644 status = gensec_unwrap(conn->gensec,
648 if (!NT_STATUS_IS_OK(status)) {
649 DEBUG(0,("gensec_unwrap: %s\n",nt_errstr(status)));
653 rep = new_ldap_message(req);
655 asn1_load(&asn1, request);
656 if (!ldap_decode(&asn1, rep)) {
663 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
664 struct ldap_message *request)
666 if ((request->type != LDAP_TAG_BindRequest) && conn->gensec &&
667 (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) ||
668 gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN))) {
669 return ldap_transaction_sasl(conn, request);
672 if (!ldap_send_msg(conn, request, NULL))
675 return ldap_receive(conn, request->messageid, NULL);
678 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
680 struct ldap_message *response;
681 struct ldap_message *msg;
683 int result = LDAP_OTHER;
701 if (conn->simple_pw) {
702 pw = conn->simple_pw;
708 msg = new_ldap_simple_bind_msg(conn, dn, pw);
712 response = ldap_transaction(conn, msg);
718 result = response->r.BindResponse.response.resultcode;
721 talloc_free(response);
726 int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds)
729 TALLOC_CTX *mem_ctx = NULL;
730 struct ldap_message *response;
731 struct ldap_message *msg;
732 DATA_BLOB input = data_blob(NULL, 0);
733 DATA_BLOB output = data_blob(NULL, 0);
734 int result = LDAP_OTHER;
739 status = gensec_client_start(conn, &conn->gensec);
740 if (!NT_STATUS_IS_OK(status)) {
741 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
745 gensec_want_feature(conn->gensec, 0 | GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
747 status = gensec_set_credentials(conn->gensec, creds);
748 if (!NT_STATUS_IS_OK(status)) {
749 DEBUG(1, ("Failed to start set GENSEC creds: %s\n",
754 status = gensec_set_target_hostname(conn->gensec, conn->host);
755 if (!NT_STATUS_IS_OK(status)) {
756 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
761 status = gensec_set_target_service(conn->gensec, "ldap");
762 if (!NT_STATUS_IS_OK(status)) {
763 DEBUG(1, ("Failed to start set GENSEC target service: %s\n",
768 status = gensec_start_mech_by_sasl_name(conn->gensec, "NTLM");
769 if (!NT_STATUS_IS_OK(status)) {
770 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
775 mem_ctx = talloc_init("ldap_bind_sasl");
779 status = gensec_update(conn->gensec, mem_ctx,
784 if (NT_STATUS_IS_OK(status) && output.length == 0) {
787 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
791 msg = new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
795 response = ldap_transaction(conn, msg);
802 result = response->r.BindResponse.response.resultcode;
804 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
808 if (!NT_STATUS_IS_OK(status)) {
809 status = gensec_update(conn->gensec, mem_ctx,
810 response->r.BindResponse.SASL.secblob,
816 talloc_free(response);
820 talloc_free(mem_ctx);
825 struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url,
826 const char *userdn, const char *password)
828 struct ldap_connection *conn;
831 conn =ldap_connect(mem_ctx, url);
836 result = ldap_bind_simple(conn, userdn, password);
837 if (result != LDAP_SUCCESS) {
845 struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx,
847 struct cli_credentials *creds)
849 struct ldap_connection *conn;
852 conn =ldap_connect(mem_ctx, url);
857 result = ldap_bind_sasl(conn, creds);
858 if (result != LDAP_SUCCESS) {
866 BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
867 const struct timeval *endtime)
869 struct ldap_message *msg = new_ldap_message(conn);
875 msg->type = LDAP_TAG_AbandonRequest;
876 msg->r.AbandonRequest.messageid = msgid;
878 result = ldap_send_msg(conn, msg, endtime);
883 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
884 const struct timeval *endtime)
886 if ((conn->searchid != 0) &&
887 (!ldap_abandon_message(conn, conn->searchid, endtime)))
890 conn->searchid = conn->next_msgid;
891 return ldap_send_msg(conn, msg, endtime);
894 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
895 const struct timeval *endtime)
897 struct ldap_message *result;
899 if (conn->search_entries != NULL) {
900 struct ldap_queue_entry *e = conn->search_entries;
903 DLIST_REMOVE(conn->search_entries, e);
908 result = ldap_receive(conn, conn->searchid, endtime);
913 if (result->type == LDAP_TAG_SearchResultEntry)
916 if (result->type == LDAP_TAG_SearchResultDone) {
917 /* TODO: Handle Paged Results */
922 /* TODO: Handle Search References here */
926 void ldap_endsearchent(struct ldap_connection *conn,
927 const struct timeval *endtime)
929 struct ldap_queue_entry *e;
931 e = conn->search_entries;
934 struct ldap_queue_entry *next = e->next;
935 DLIST_REMOVE(conn->search_entries, e);
941 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
942 struct ldap_message *msg,
943 const struct timeval *endtime)
945 struct ldap_message *res1, *res2 = NULL;
946 if (!ldap_setsearchent(conn, msg, endtime))
949 res1 = ldap_getsearchent(conn, endtime);
952 res2 = ldap_getsearchent(conn, endtime);
954 ldap_endsearchent(conn, endtime);
960 /* More than one entry */
969 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
973 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
975 if (msg->type != LDAP_TAG_SearchResultEntry)
978 for (i=0; i<r->num_attributes; i++) {
979 if (strequal(attr, r->attributes[i].name)) {
980 if (r->attributes[i].num_values != 1)
983 *value = r->attributes[i].values[0];
990 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
991 TALLOC_CTX *mem_ctx, char **value)
995 if (!ldap_find_single_value(msg, attr, &blob))
998 *value = talloc_size(mem_ctx, blob.length+1);
1003 memcpy(*value, blob.data, blob.length);
1004 (*value)[blob.length] = '\0';
1008 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
1016 if (!ldap_find_single_value(msg, attr, &blob))
1019 val = malloc(blob.length+1);
1023 memcpy(val, blob.data, blob.length);
1024 val[blob.length] = '\0';
1029 *value = strtol(val, NULL, 10);
1039 int ldap_error(struct ldap_connection *conn)
1044 NTSTATUS ldap2nterror(int ldaperror)
1046 return NT_STATUS_OK;