Check "auth event notification" param in log_json
[nivanova/samba-autobuild/.git] / auth / ntlmssp / ntlmssp.c
index 916b376b1111e1e47c9c1175a168b32de281902d..37434fbb0c2242073cb44111bf4f9a0ed61081bb 100644 (file)
@@ -24,6 +24,8 @@
 struct auth_session_info;
 
 #include "includes.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
 #include "auth/ntlmssp/ntlmssp.h"
 #include "auth/ntlmssp/ntlmssp_private.h"
 #include "../libcli/auth/libcli_auth.h"
@@ -31,6 +33,9 @@ struct auth_session_info;
 #include "auth/gensec/gensec.h"
 #include "auth/gensec/gensec_internal.h"
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
 /**
  * Callbacks for NTLMSSP - for both client and server operating modes
  *
@@ -42,11 +47,22 @@ static const struct ntlmssp_callbacks {
        NTSTATUS (*sync_fn)(struct gensec_security *gensec_security,
                            TALLOC_CTX *out_mem_ctx,
                            DATA_BLOB in, DATA_BLOB *out);
+       struct tevent_req *(*send_fn)(TALLOC_CTX *mem_ctx,
+                                     struct tevent_context *ev,
+                                     struct gensec_security *gensec_security,
+                                     const DATA_BLOB in);
+       NTSTATUS (*recv_fn)(struct tevent_req *req,
+                           TALLOC_CTX *out_mem_ctx,
+                           DATA_BLOB *out);
 } ntlmssp_callbacks[] = {
        {
                .role           = NTLMSSP_CLIENT,
                .command        = NTLMSSP_INITIAL,
                .sync_fn        = ntlmssp_client_initial,
+       },{
+               .role           = NTLMSSP_CLIENT,
+               .command        = NTLMSSP_NEGOTIATE,
+               .sync_fn        = gensec_ntlmssp_resume_ccache,
        },{
                .role           = NTLMSSP_SERVER,
                .command        = NTLMSSP_NEGOTIATE,
@@ -58,7 +74,8 @@ static const struct ntlmssp_callbacks {
        },{
                .role           = NTLMSSP_SERVER,
                .command        = NTLMSSP_AUTH,
-               .sync_fn        = gensec_ntlmssp_server_auth,
+               .send_fn        = ntlmssp_server_auth_send,
+               .recv_fn        = ntlmssp_server_auth_recv,
        }
 };
 
@@ -82,6 +99,15 @@ static NTSTATUS gensec_ntlmssp_update_find(struct gensec_security *gensec_securi
        if (!input.length) {
                switch (gensec_ntlmssp->ntlmssp_state->role) {
                case NTLMSSP_CLIENT:
+                       if (gensec_ntlmssp->ntlmssp_state->resume_ccache) {
+                               /*
+                                * make sure gensec_ntlmssp_resume_ccache()
+                                * will be called
+                                */
+                               ntlmssp_command = NTLMSSP_NEGOTIATE;
+                               break;
+                       }
+
                        ntlmssp_command = NTLMSSP_INITIAL;
                        break;
                case NTLMSSP_SERVER:
@@ -94,6 +120,10 @@ static NTSTATUS gensec_ntlmssp_update_find(struct gensec_security *gensec_securi
                                return NT_STATUS_INVALID_PARAMETER;
                        }
                        break;
+               default:
+                       DEBUG(1, ("NTLMSSP state has invalid role %d\n",
+                                 gensec_ntlmssp->ntlmssp_state->role));
+                       return NT_STATUS_INVALID_PARAMETER;
                }
        } else {
                if (!msrpc_parse(gensec_ntlmssp->ntlmssp_state,
@@ -126,46 +156,146 @@ static NTSTATUS gensec_ntlmssp_update_find(struct gensec_security *gensec_securi
        return NT_STATUS_INVALID_PARAMETER;
 }
 
-/**
- * Next state function for the wrapped NTLMSSP state machine
- *
- * @param gensec_security GENSEC state, initialised to NTLMSSP
- * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
- * @param in The request, as a DATA_BLOB
- * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
- * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
- *                or NT_STATUS_OK if the user is authenticated.
- */
+struct gensec_ntlmssp_update_state {
+       const struct ntlmssp_callbacks *cb;
+       NTSTATUS status;
+       DATA_BLOB out;
+};
 
-NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security,
-                              TALLOC_CTX *out_mem_ctx,
-                              struct tevent_context *ev,
-                              const DATA_BLOB input, DATA_BLOB *out)
+static void gensec_ntlmssp_update_done(struct tevent_req *subreq);
+
+static struct tevent_req *gensec_ntlmssp_update_send(TALLOC_CTX *mem_ctx,
+                                                    struct tevent_context *ev,
+                                                    struct gensec_security *gensec_security,
+                                                    const DATA_BLOB in)
 {
        struct gensec_ntlmssp_context *gensec_ntlmssp =
                talloc_get_type_abort(gensec_security->private_data,
                                      struct gensec_ntlmssp_context);
-       struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+       struct tevent_req *req = NULL;
+       struct gensec_ntlmssp_update_state *state = NULL;
        NTSTATUS status;
-       uint32_t i;
+       uint32_t i = 0;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct gensec_ntlmssp_update_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       status = gensec_ntlmssp_update_find(gensec_security,
+                                           gensec_ntlmssp,
+                                           in, &i);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
 
-       *out = data_blob(NULL, 0);
+       if (ntlmssp_callbacks[i].send_fn != NULL) {
+               struct tevent_req *subreq = NULL;
 
-       if (!out_mem_ctx) {
-               /* if the caller doesn't want to manage/own the memory,
-                  we can put it on our context */
-               out_mem_ctx = ntlmssp_state;
+               state->cb = &ntlmssp_callbacks[i];
+
+               subreq = state->cb->send_fn(state, ev,
+                                           gensec_security,
+                                           in);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq,
+                                       gensec_ntlmssp_update_done,
+                                       req);
+               return req;
+       }
+
+       status = ntlmssp_callbacks[i].sync_fn(gensec_security,
+                                             state,
+                                             in, &state->out);
+       state->status = status;
+       if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
        }
 
-       status = gensec_ntlmssp_update_find(gensec_security, gensec_ntlmssp, input, &i);
-       NT_STATUS_NOT_OK_RETURN(status);
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static void gensec_ntlmssp_update_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct gensec_ntlmssp_update_state *state =
+               tevent_req_data(req,
+               struct gensec_ntlmssp_update_state);
+       NTSTATUS status;
+
+       status = state->cb->recv_fn(subreq, state, &state->out);
+       TALLOC_FREE(subreq);
+       if (GENSEC_UPDATE_IS_NTERROR(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       state->status = status;
+       tevent_req_done(req);
+}
+
+static NTSTATUS gensec_ntlmssp_update_recv(struct tevent_req *req,
+                                          TALLOC_CTX *out_mem_ctx,
+                                          DATA_BLOB *out)
+{
+       struct gensec_ntlmssp_update_state *state =
+               tevent_req_data(req,
+               struct gensec_ntlmssp_update_state);
+       NTSTATUS status;
+
+       *out = data_blob_null;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       *out = state->out;
+       talloc_steal(out_mem_ctx, state->out.data);
+       status = state->status;
+       tevent_req_received(req);
+       return status;
+}
+
+static NTSTATUS gensec_ntlmssp_may_reset_crypto(struct gensec_security *gensec_security,
+                                               bool full_reset)
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(gensec_security->private_data,
+                                     struct gensec_ntlmssp_context);
+       struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+       NTSTATUS status;
+       bool reset_seqnums = full_reset;
 
-       status = ntlmssp_callbacks[i].sync_fn(gensec_security, out_mem_ctx, input, out);
-       NT_STATUS_NOT_OK_RETURN(status);
+       if (!gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+               return NT_STATUS_OK;
+       }
+
+       status = ntlmssp_sign_reset(ntlmssp_state, reset_seqnums);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n",
+                         nt_errstr(status)));
+               return status;
+       }
 
        return NT_STATUS_OK;
 }
 
+static const char *gensec_ntlmssp_final_auth_type(struct gensec_security *gensec_security)
+{
+       return GENSEC_FINAL_AUTH_TYPE_NTLMSSP;
+}
+
 static const char *gensec_ntlmssp_oids[] = {
        GENSEC_OID_NTLMSSP,
        NULL
@@ -179,7 +309,9 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
        .client_start   = gensec_ntlmssp_client_start,
        .server_start   = gensec_ntlmssp_server_start,
        .magic          = gensec_ntlmssp_magic,
-       .update         = gensec_ntlmssp_update,
+       .update_send    = gensec_ntlmssp_update_send,
+       .update_recv    = gensec_ntlmssp_update_recv,
+       .may_reset_crypto= gensec_ntlmssp_may_reset_crypto,
        .sig_size       = gensec_ntlmssp_sig_size,
        .sign_packet    = gensec_ntlmssp_sign_packet,
        .check_packet   = gensec_ntlmssp_check_packet,
@@ -190,32 +322,85 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
        .session_key    = gensec_ntlmssp_session_key,
        .session_info   = gensec_ntlmssp_session_info,
        .have_feature   = gensec_ntlmssp_have_feature,
+       .final_auth_type = gensec_ntlmssp_final_auth_type,
        .enabled        = true,
        .priority       = GENSEC_NTLMSSP
 };
 
+static const struct gensec_security_ops gensec_ntlmssp_resume_ccache_ops = {
+       .name           = "ntlmssp_resume_ccache",
+       .client_start   = gensec_ntlmssp_resume_ccache_start,
+       .update_send    = gensec_ntlmssp_update_send,
+       .update_recv    = gensec_ntlmssp_update_recv,
+       .session_key    = gensec_ntlmssp_session_key,
+       .have_feature   = gensec_ntlmssp_have_feature,
+       .enabled        = true,
+       .priority       = GENSEC_NTLMSSP
+};
 
-_PUBLIC_ NTSTATUS gensec_ntlmssp_init(void)
+_PUBLIC_ NTSTATUS gensec_ntlmssp_init(TALLOC_CTX *ctx)
 {
        NTSTATUS ret;
 
-       ret = gensec_register(&gensec_ntlmssp_security_ops);
+       ret = gensec_register(ctx, &gensec_ntlmssp_security_ops);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(0,("Failed to register '%s' gensec backend!\n",
                        gensec_ntlmssp_security_ops.name));
                return ret;
        }
 
+       ret = gensec_register(ctx, &gensec_ntlmssp_resume_ccache_ops);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(0,("Failed to register '%s' gensec backend!\n",
+                       gensec_ntlmssp_resume_ccache_ops.name));
+               return ret;
+       }
+
        return ret;
 }
 
+static struct gensec_security *gensec_find_child_by_ops(struct gensec_security *gensec_security,
+                                                       const struct gensec_security_ops *ops)
+{
+       struct gensec_security *current = gensec_security;
+
+       while (current != NULL) {
+               if (current->ops == ops) {
+                       return current;
+               }
+
+               current = current->child_security;
+       }
+
+       return NULL;
+}
+
 uint32_t gensec_ntlmssp_neg_flags(struct gensec_security *gensec_security)
 {
        struct gensec_ntlmssp_context *gensec_ntlmssp;
-       if (gensec_security->ops != &gensec_ntlmssp_security_ops) {
+
+       gensec_security = gensec_find_child_by_ops(gensec_security,
+                                       &gensec_ntlmssp_security_ops);
+       if (gensec_security == NULL) {
                return 0;
        }
+
        gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
                                               struct gensec_ntlmssp_context);
        return gensec_ntlmssp->ntlmssp_state->neg_flags;
 }
+
+const char *gensec_ntlmssp_server_domain(struct gensec_security *gensec_security)
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp;
+
+       gensec_security = gensec_find_child_by_ops(gensec_security,
+                                       &gensec_ntlmssp_security_ops);
+       if (gensec_security == NULL) {
+               return NULL;
+       }
+
+       gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
+                                              struct gensec_ntlmssp_context);
+       return gensec_ntlmssp->ntlmssp_state->server.netbios_domain;
+}