Fix include paths to new location of libutil.
[kai/samba-autobuild/.git] / source4 / libcli / ldap / ldap_client.c
index fcb2d922148b106d8c608dd74ca21f0f007d128d..a59356761b440658d1506b34388b0f69c48c351f 100644 (file)
 */
 
 #include "includes.h"
-#include "libcli/util/asn_1.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/asn1.h"
+#include "../lib/util/dlinklist.h"
 #include "lib/events/events.h"
 #include "lib/socket/socket.h"
 #include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_proto.h"
 #include "libcli/ldap/ldap_client.h"
 #include "libcli/composite/composite.h"
 #include "lib/stream/packet.h"
 #include "lib/tls/tls.h"
 #include "auth/gensec/gensec.h"
 #include "system/time.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
 
-
-/*
+/**
   create a new ldap_connection stucture. The event context is optional
 */
-struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, 
-                                           struct event_context *ev)
+_PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, 
+                                            struct loadparm_context *lp_ctx,
+                                            struct event_context *ev)
 {
        struct ldap_connection *conn;
 
-       conn = talloc_zero(mem_ctx, struct ldap_connection);
-       if (conn == NULL) {
+       if (ev == NULL) {
                return NULL;
        }
 
-       if (ev == NULL) {
-               ev = event_context_init(conn);
-               if (ev == NULL) {
-                       talloc_free(conn);
-                       return NULL;
-               }
+       conn = talloc_zero(mem_ctx, struct ldap_connection);
+       if (conn == NULL) {
+               return NULL;
        }
 
        conn->next_messageid  = 1;
        conn->event.event_ctx = ev;
 
+       conn->lp_ctx = lp_ctx;
+
        /* set a reasonable request timeout */
        conn->timeout = 60;
 
@@ -76,6 +77,12 @@ static void ldap_connection_dead(struct ldap_connection *conn)
 {
        struct ldap_request *req;
 
+       talloc_free(conn->sock);  /* this will also free event.fde */
+       talloc_free(conn->packet);
+       conn->sock = NULL;
+       conn->event.fde = NULL;
+       conn->packet = NULL;
+
        /* return an error for any pending request ... */
        while (conn->pending) {
                req = conn->pending;
@@ -86,12 +93,6 @@ static void ldap_connection_dead(struct ldap_connection *conn)
                        req->async.fn(req);
                }
        }
-
-       talloc_free(conn->sock);  /* this will also free event.fde */
-       talloc_free(conn->packet);
-       conn->sock = NULL;
-       conn->event.fde = NULL;
-       conn->packet = NULL;
 }
 
 static void ldap_reconnect(struct ldap_connection *conn);
@@ -116,6 +117,7 @@ static void ldap_error_handler(void *private_data, NTSTATUS status)
 static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
 {
        struct ldap_request *req;
+       int i;
 
        for (req=conn->pending; req; req=req->next) {
                if (req->messageid == msg->messageid) break;
@@ -132,6 +134,20 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
                return;
        }
 
+       /* Check for undecoded critical extensions */
+       for (i=0; msg->controls && msg->controls[i]; i++) {
+               if (!msg->controls_decoded[i] && 
+                   msg->controls[i]->critical) {
+                       req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
+                       req->state = LDAP_REQUEST_DONE;
+                       DLIST_REMOVE(conn->pending, req);
+                       if (req->async.fn) {
+                               req->async.fn(req);
+                       }
+                       return;
+               }
+       }
+
        /* add to the list of replies received */
        talloc_steal(req, msg);
        req->replies = talloc_realloc(req, req->replies, 
@@ -273,7 +289,7 @@ struct ldap_connect_state {
 static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
 static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
 
-struct composite_context *ldap_connect_send(struct ldap_connection *conn,
+_PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
                                            const char *url)
 {
        struct composite_context *result, *ctx;
@@ -281,7 +297,7 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
        char protocol[11];
        int ret;
 
-       result = talloc_zero(NULL, struct composite_context);
+       result = talloc_zero(conn, struct composite_context);
        if (result == NULL) goto failed;
        result->state = COMPOSITE_STATE_IN_PROGRESS;
        result->async.fn = NULL;
@@ -319,6 +335,12 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
                SMB_ASSERT(sizeof(protocol)>10);
                SMB_ASSERT(sizeof(path)>1024);
        
+               /* LDAPI connections are to localhost, so give the local host name as the target for gensec */
+               conn->host = talloc_asprintf(conn, "%s.%s", lp_netbios_name(conn->lp_ctx),  lp_realm(conn->lp_ctx));
+               if (composite_nomem(conn->host, state->ctx)) {
+                       return result;
+               }
+
                /* The %c specifier doesn't null terminate :-( */
                ZERO_STRUCT(path);
                ret = sscanf(url, "%10[^:]://%1025c", protocol, path);
@@ -336,7 +358,7 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
                }
 
                ctx = socket_connect_send(conn->sock, NULL, unix_addr, 
-                                         0, conn->event.event_ctx);
+                                         0, lp_resolve_context(conn->lp_ctx), conn->event.event_ctx);
                ctx->async.fn = ldap_connect_recv_unix_conn;
                ctx->async.private_data = state;
                return result;
@@ -349,7 +371,7 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
                }
                
                ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
-                                               conn->event.event_ctx);
+                                               lp_resolve_context(conn->lp_ctx), conn->event.event_ctx);
                if (ctx == NULL) goto failed;
 
                ctx->async.fn = ldap_connect_recv_tcp_conn;
@@ -361,7 +383,8 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
        return NULL;
 }
 
-static void ldap_connect_got_sock(struct composite_context *ctx, struct ldap_connection *conn) 
+static void ldap_connect_got_sock(struct composite_context *ctx, 
+                                 struct ldap_connection *conn) 
 {
        /* setup a handler for events on this socket */
        conn->event.fde = event_add_fd(conn->event.event_ctx, conn->sock, 
@@ -376,14 +399,27 @@ static void ldap_connect_got_sock(struct composite_context *ctx, struct ldap_con
 
        talloc_steal(conn, conn->sock);
        if (conn->ldaps) {
-               struct socket_context *tls_socket = tls_init_client(conn->sock, conn->event.fde);
+               struct socket_context *tls_socket;
+               struct socket_context *tmp_socket;
+               char *cafile = private_path(conn->sock, conn->lp_ctx, lp_tls_cafile(conn->lp_ctx));
+
+               if (!cafile || !*cafile) {
+                       talloc_free(conn->sock);
+                       return;
+               }
+
+               tls_socket = tls_init_client(conn->sock, conn->event.fde, cafile);
+               talloc_free(cafile);
+
                if (tls_socket == NULL) {
                        talloc_free(conn->sock);
                        return;
                }
-               talloc_unlink(conn, conn->sock);
-               conn->sock = tls_socket;
-               talloc_steal(conn, conn->sock);
+
+               /* the original socket, must become a child of the tls socket */
+               tmp_socket = conn->sock;
+               conn->sock = talloc_steal(conn, tls_socket);
+               talloc_steal(conn->sock, tmp_socket);
        }
 
        conn->packet = packet_init(conn);
@@ -399,7 +435,7 @@ static void ldap_connect_got_sock(struct composite_context *ctx, struct ldap_con
        packet_set_error_handler(conn->packet, ldap_error_handler);
        packet_set_event_context(conn->packet, conn->event.event_ctx);
        packet_set_fde(conn->packet, conn->event.fde);
-       packet_set_serialise(conn->packet);
+/*     packet_set_serialise(conn->packet); */
 
        composite_done(ctx);
 }
@@ -445,7 +481,7 @@ _PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx)
        return status;
 }
 
-NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
+_PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
 {
        struct composite_context *ctx = ldap_connect_send(conn, url);
        return ldap_connect_recv(ctx);
@@ -453,7 +489,7 @@ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
 
 /* set reconnect parameters */
 
-void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
+_PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
 {
        if (conn) {
                conn->reconnect.max_retries = max_retries;
@@ -538,7 +574,7 @@ static void ldap_request_complete(struct event_context *ev, struct timed_event *
 /*
   send a ldap message - async interface
 */
-struct ldap_request *ldap_request_send(struct ldap_connection *conn,
+_PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
                                       struct ldap_message *msg)
 {
        struct ldap_request *req;
@@ -614,7 +650,7 @@ failed:
   wait for a request to complete
   note that this does not destroy the request
 */
-NTSTATUS ldap_request_wait(struct ldap_request *req)
+_PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
 {
        while (req->state < LDAP_REQUEST_DONE) {
                if (event_loop_once(req->conn->event.event_ctx) != 0) {
@@ -678,7 +714,7 @@ static const struct {
 /*
   used to setup the status code from a ldap response
 */
-NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
+_PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
 {
        int i;
        const char *codename = "unknown";
@@ -711,7 +747,7 @@ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r
 /*
   return error string representing the last error
 */
-const char *ldap_errstr(struct ldap_connection *conn, 
+_PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn, 
                        TALLOC_CTX *mem_ctx, 
                        NTSTATUS status)
 {
@@ -725,7 +761,7 @@ const char *ldap_errstr(struct ldap_connection *conn,
 /*
   return the Nth result message, waiting if necessary
 */
-NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
+_PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
 {
        *msg = NULL;
 
@@ -753,7 +789,7 @@ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **ms
 /*
   return a single result message, checking if it is of the expected LDAP type
 */
-NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
+_PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
 {
        NTSTATUS status;
        status = ldap_result_n(req, 0, msg);
@@ -771,7 +807,7 @@ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, in
   a simple ldap transaction, for single result requests that only need a status code
   this relies on single valued requests having the response type == request type + 1
 */
-NTSTATUS ldap_transaction(struct ldap_connection *conn, struct ldap_message *msg)
+_PUBLIC_ NTSTATUS ldap_transaction(struct ldap_connection *conn, struct ldap_message *msg)
 {
        struct ldap_request *req = ldap_request_send(conn, msg);
        struct ldap_message *res;