auth/gensec: make it possible to implement async backends
authorStefan Metzmacher <metze@samba.org>
Mon, 5 Aug 2013 14:12:13 +0000 (16:12 +0200)
committerStefan Metzmacher <metze@samba.org>
Sat, 10 Aug 2013 07:19:03 +0000 (09:19 +0200)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
auth/gensec/gensec.c
auth/gensec/gensec_internal.h

index d364a344a999bb99848fb01e7dcddaaf94ff2444..abcbcb95067b5f1dbf7872eb304a1e5d9ec1a94b 100644 (file)
@@ -218,61 +218,92 @@ _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_
                                const DATA_BLOB in, DATA_BLOB *out)
 {
        NTSTATUS status;
+       const struct gensec_security_ops *ops = gensec_security->ops;
+       TALLOC_CTX *frame = NULL;
+       struct tevent_req *subreq = NULL;
+       bool ok;
 
-       status = gensec_security->ops->update(gensec_security, out_mem_ctx,
-                                             ev, in, out);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       if (ops->update_send == NULL) {
 
-       /*
-        * Because callers using the
-        * gensec_start_mech_by_auth_type() never call
-        * gensec_want_feature(), it isn't sensible for them
-        * to have to call gensec_have_feature() manually, and
-        * these are not points of negotiation, but are
-        * asserted by the client
-        */
-       switch (gensec_security->dcerpc_auth_level) {
-       case DCERPC_AUTH_LEVEL_INTEGRITY:
-               if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-                       DEBUG(0,("Did not manage to negotiate mandetory feature "
-                                "SIGN for dcerpc auth_level %u\n",
-                                gensec_security->dcerpc_auth_level));
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-               break;
-       case DCERPC_AUTH_LEVEL_PRIVACY:
-               if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-                       DEBUG(0,("Did not manage to negotiate mandetory feature "
-                                "SIGN for dcerpc auth_level %u\n",
-                                gensec_security->dcerpc_auth_level));
-                       return NT_STATUS_ACCESS_DENIED;
+               status = ops->update(gensec_security, out_mem_ctx,
+                                    ev, in, out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
-               if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
-                       DEBUG(0,("Did not manage to negotiate mandetory feature "
-                                "SEAL for dcerpc auth_level %u\n",
-                                gensec_security->dcerpc_auth_level));
-                       return NT_STATUS_ACCESS_DENIED;
+
+               /*
+                * Because callers using the
+                * gensec_start_mech_by_auth_type() never call
+                * gensec_want_feature(), it isn't sensible for them
+                * to have to call gensec_have_feature() manually, and
+                * these are not points of negotiation, but are
+                * asserted by the client
+                */
+               switch (gensec_security->dcerpc_auth_level) {
+               case DCERPC_AUTH_LEVEL_INTEGRITY:
+                       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+                               DEBUG(0,("Did not manage to negotiate mandetory feature "
+                                        "SIGN for dcerpc auth_level %u\n",
+                                        gensec_security->dcerpc_auth_level));
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+                       break;
+               case DCERPC_AUTH_LEVEL_PRIVACY:
+                       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+                               DEBUG(0,("Did not manage to negotiate mandetory feature "
+                                        "SIGN for dcerpc auth_level %u\n",
+                                        gensec_security->dcerpc_auth_level));
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+                       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+                               DEBUG(0,("Did not manage to negotiate mandetory feature "
+                                        "SEAL for dcerpc auth_level %u\n",
+                                        gensec_security->dcerpc_auth_level));
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+                       break;
+               default:
+                       break;
                }
-               break;
-       default:
-               break;
+
+               return NT_STATUS_OK;
        }
 
-       return NT_STATUS_OK;
+       frame = talloc_stackframe();
+
+       subreq = ops->update_send(frame, ev, gensec_security, in);
+       if (subreq == NULL) {
+               goto fail;
+       }
+       ok = tevent_req_poll_ntstatus(subreq, ev, &status);
+       if (!ok) {
+               goto fail;
+       }
+       status = ops->update_recv(subreq, out_mem_ctx, out);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
 }
 
 struct gensec_update_state {
-       struct tevent_immediate *im;
+       const struct gensec_security_ops *ops;
+       struct tevent_req *subreq;
        struct gensec_security *gensec_security;
-       DATA_BLOB in;
        DATA_BLOB out;
+
+       /*
+        * only for sync backends, we should remove this
+        * once all backends are async.
+        */
+       struct tevent_immediate *im;
+       DATA_BLOB in;
 };
 
 static void gensec_update_async_trigger(struct tevent_context *ctx,
                                        struct tevent_immediate *im,
                                        void *private_data);
+static void gensec_update_subreq_done(struct tevent_req *subreq);
+
 /**
  * Next state function for the GENSEC state machine async version
  *
@@ -298,17 +329,31 @@ _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       state->gensec_security          = gensec_security;
-       state->in                       = in;
-       state->out                      = data_blob(NULL, 0);
-       state->im                       = tevent_create_immediate(state);
-       if (tevent_req_nomem(state->im, req)) {
+       state->ops = gensec_security->ops;
+       state->gensec_security = gensec_security;
+
+       if (state->ops->update_send == NULL) {
+               state->in = in;
+               state->im = tevent_create_immediate(state);
+               if (tevent_req_nomem(state->im, req)) {
+                       return tevent_req_post(req, ev);
+               }
+
+               tevent_schedule_immediate(state->im, ev,
+                                         gensec_update_async_trigger,
+                                         req);
+
+               return req;
+       }
+
+       state->subreq = state->ops->update_send(state, ev, gensec_security, in);
+       if (tevent_req_nomem(state->subreq, req)) {
                return tevent_req_post(req, ev);
        }
 
-       tevent_schedule_immediate(state->im, ev,
-                                 gensec_update_async_trigger,
-                                 req);
+       tevent_req_set_callback(state->subreq,
+                               gensec_update_subreq_done,
+                               req);
 
        return req;
 }
@@ -323,12 +368,71 @@ static void gensec_update_async_trigger(struct tevent_context *ctx,
                tevent_req_data(req, struct gensec_update_state);
        NTSTATUS status;
 
-       status = gensec_update(state->gensec_security, state, ctx,
-                              state->in, &state->out);
+       status = state->ops->update(state->gensec_security, state, ctx,
+                                   state->in, &state->out);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static void gensec_update_subreq_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct gensec_update_state *state =
+               tevent_req_data(req,
+               struct gensec_update_state);
+       NTSTATUS status;
+
+       state->subreq = NULL;
+
+       status = state->ops->update_recv(subreq, state, &state->out);
+       TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
        }
 
+       /*
+        * Because callers using the
+        * gensec_start_mech_by_authtype() never call
+        * gensec_want_feature(), it isn't sensible for them
+        * to have to call gensec_have_feature() manually, and
+        * these are not points of negotiation, but are
+        * asserted by the client
+        */
+       switch (state->gensec_security->dcerpc_auth_level) {
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) {
+                       DEBUG(0,("Did not manage to negotiate mandetory feature "
+                                "SIGN for dcerpc auth_level %u\n",
+                                state->gensec_security->dcerpc_auth_level));
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
+               break;
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) {
+                       DEBUG(0,("Did not manage to negotiate mandetory feature "
+                                "SIGN for dcerpc auth_level %u\n",
+                                state->gensec_security->dcerpc_auth_level));
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
+               if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SEAL)) {
+                       DEBUG(0,("Did not manage to negotiate mandetory feature "
+                                "SEAL for dcerpc auth_level %u\n",
+                                state->gensec_security->dcerpc_auth_level));
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
+               break;
+       default:
+               break;
+       }
+
        tevent_req_done(req);
 }
 
index 41b6f0d6efdff5a29f38c865709bbbbe5a044524..c04164a3dbd0c40c49895a66eb6622eae0032c94 100644 (file)
@@ -40,6 +40,13 @@ struct gensec_security_ops {
        NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
                           struct tevent_context *ev,
                           const DATA_BLOB in, DATA_BLOB *out);
+       struct tevent_req *(*update_send)(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct gensec_security *gensec_security,
+                                         const DATA_BLOB in);
+       NTSTATUS (*update_recv)(struct tevent_req *req,
+                               TALLOC_CTX *out_mem_ctx,
+                               DATA_BLOB *out);
        NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
                                uint8_t *data, size_t length,
                                const uint8_t *whole_pdu, size_t pdu_length,