r17251: - split out the starttls into its own function
authorStefan Metzmacher <metze@samba.org>
Wed, 26 Jul 2006 06:18:13 +0000 (06:18 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:10:23 +0000 (14:10 -0500)
- give an operations error when tls is already on the socket

metze

source/ldap_server/ldap_extended.c

index bc757fc9734d2e03a563973a45ce3b2b47353edc..06e5feb828ae4ac2f9efe8e95acbc0fe104d1df2 100644 (file)
@@ -41,56 +41,110 @@ static void ldapsrv_start_tls(void *private)
        packet_set_socket(ctx->conn->packet, ctx->conn->connection->socket);
 }
 
-NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
+static NTSTATUS ldapsrv_StartTLS(struct ldapsrv_call *call,
+                                struct ldapsrv_reply *reply,
+                                const char **errstr)
 {
-       struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
-       struct ldapsrv_reply *reply;
+       struct ldapsrv_starttls_context *ctx;
 
-       DEBUG(10, ("Extended\n"));
+       (*errstr) = NULL;
 
-       reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
-       if (!reply) {
-               return NT_STATUS_NO_MEMORY;
+       /*
+        * TODO: give LDAP_OPERATIONS_ERROR also when
+        *       there're pending requests or there's
+        *       a SASL bind in progress
+        *       (see rfc4513 section 3.1.1)
+        */
+       if (call->conn->sockets.tls) {
+               (*errstr) = talloc_asprintf(reply, "START-TLS: TLS is already enabled on this LDAP session");
+               return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
        }
 
-       ZERO_STRUCT(reply->msg->r);
-
-       /* check if we have a START_TLS call */
-       if (strcmp(req->oid, LDB_EXTENDED_START_TLS_OID) == 0) {
-               struct ldapsrv_starttls_context *ctx;
-               int result = 0;
-               const char *errstr;
-               ctx = talloc(call, struct ldapsrv_starttls_context); 
-
-               if (ctx) {
-                       ctx->conn = call->conn;
-                       ctx->tls_socket = tls_init_server(call->conn->service->tls_params,
-                                                call->conn->connection->socket,
-                                                call->conn->connection->event.fde, 
-                                                NULL);
-               } 
-
-               if (!ctx || !ctx->tls_socket) {
-                       result = LDAP_OPERATIONS_ERROR;
-                       errstr = talloc_asprintf(reply, 
-                                                "START-TLS: Failed to setup TLS socket");
-               } else {
-                       result = LDAP_SUCCESS;
-                       errstr = NULL;
-                       call->send_callback = ldapsrv_start_tls;
-                       call->send_private  = ctx;
-               }
-
-               reply->msg->r.ExtendedResponse.response.resultcode = result;
-               reply->msg->r.ExtendedResponse.response.errormessage = errstr;
-               reply->msg->r.ExtendedResponse.oid = talloc_strdup(reply, req->oid);
-               if (!reply->msg->r.ExtendedResponse.oid) {
-                       return NT_STATUS_NO_MEMORY;
-               }
+       ctx = talloc(call, struct ldapsrv_starttls_context);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->conn = call->conn;
+       ctx->tls_socket = tls_init_server(call->conn->service->tls_params,
+                                         call->conn->connection->socket,
+                                         call->conn->connection->event.fde, 
+                                         NULL);
+       if (!ctx->tls_socket) {
+               (*errstr) = talloc_asprintf(reply, "START-TLS: Failed to setup TLS socket");
+               return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
        }
 
-       /* TODO: OID not recognized, return a protocol error */
+       call->send_callback = ldapsrv_start_tls;
+       call->send_private  = ctx;
+
+       reply->msg->r.ExtendedResponse.response.resultcode = LDAP_SUCCESS;
+       reply->msg->r.ExtendedResponse.response.errormessage = NULL;
 
        ldapsrv_queue_reply(call, reply);
        return NT_STATUS_OK;
 }
+
+struct ldapsrv_extended_operation {
+       const char *oid;
+       NTSTATUS (*fn)(struct ldapsrv_call *call, struct ldapsrv_reply *reply, const char **errorstr);
+};
+
+static struct ldapsrv_extended_operation extended_ops[] = {
+       {
+               .oid    = LDB_EXTENDED_START_TLS_OID,
+               .fn     = ldapsrv_StartTLS,
+       },{
+               .oid    = NULL,
+               .fn     = NULL,
+       }
+};
+
+NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
+{
+       struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
+       struct ldapsrv_reply *reply;
+       int result = LDAP_PROTOCOL_ERROR;
+       const char *error_str = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+       uint32_t i;
+
+       DEBUG(10, ("Extended\n"));
+
+       reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
+       NT_STATUS_HAVE_NO_MEMORY(reply);
+       ZERO_STRUCT(reply->msg->r);
+       reply->msg->r.ExtendedResponse.oid = talloc_steal(reply, req->oid);
+       reply->msg->r.ExtendedResponse.response.resultcode = LDAP_PROTOCOL_ERROR;
+       reply->msg->r.ExtendedResponse.response.errormessage = NULL;
+       for (i=0; extended_ops[i].oid; i++) {
+               if (strcmp(extended_ops[i].oid,req->oid) != 0) continue;
+               /* 
+                * if the backend function returns an error we
+                * need to send the reply otherwise the reply is already
+                * send and we need to return directly
+                */
+               status = extended_ops[i].fn(call, reply, &error_str);
+               NT_STATUS_IS_OK_RETURN(status);
+               if (NT_STATUS_IS_LDAP(status)) {
+                       result = NT_STATUS_LDAP_CODE(status);
+               } else {
+                       result = LDAP_OPERATIONS_ERROR;
+                       error_str = talloc_asprintf(reply, "Extended Operation(%s) failed: %s",
+                                                   req->oid, nt_errstr(status));
+               }
+       }
+       /* if we haven't found the oid, then status is still NT_STATUS_OK */
+       if (NT_STATUS_IS_OK(status)) {
+               error_str = talloc_asprintf(reply, "Extended Operation(%s) not supported",
+                                           req->oid);
+       }
+       reply->msg->r.ExtendedResponse.response.resultcode = result;
+       reply->msg->r.ExtendedResponse.response.errormessage = error_str;
+       ldapsrv_queue_reply(call, reply);
+       return NT_STATUS_OK;
+}