s4:rpc_server: only pass dcesrv_auth to auth_state.session_key_fn()
[samba.git] / source4 / rpc_server / dcerpc_server.c
index 6a985c5c63c0dbc9ec32b6b3a228a538e6974e00..7ceaf03c673eaa3ad1e3c14e9eba1f771afa4f20 100644 (file)
@@ -239,7 +239,7 @@ const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoi
 /*
   find the earlier parts of a fragmented call awaiting reassembily
 */
-static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
+static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint32_t call_id)
 {
        struct dcesrv_call_state *c;
        for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
@@ -359,7 +359,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
                 * Because one endpoint can only have one process
                 * model, we add a new IP_TCP endpoint for each model.
                 *
-                * This woks in conjunction with the forced overwrite
+                * This works in conjunction with the forced overwrite
                 * of ep->use_single_process below.
                 */
                if (ep->use_single_process != use_single_process
@@ -459,14 +459,57 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS dcesrv_session_info_session_key(struct dcesrv_auth *auth,
+                                               DATA_BLOB *session_key)
+{
+       if (auth->session_info == NULL) {
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
+       if (auth->session_info->session_key.length == 0) {
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
+       *session_key = auth->session_info->session_key;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS dcesrv_remote_session_key(struct dcesrv_auth *auth,
+                                         DATA_BLOB *session_key)
+{
+       if (auth->auth_type != DCERPC_AUTH_TYPE_NONE) {
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
+       return dcesrv_session_info_session_key(auth, session_key);
+}
+
+static NTSTATUS dcesrv_local_fixed_session_key(struct dcesrv_auth *auth,
+                                              DATA_BLOB *session_key)
+{
+       return dcerpc_generic_session_key(NULL, session_key);
+}
+
 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
                                      DATA_BLOB *session_key)
 {
-       if (p->auth_state.session_info->session_key.length) {
-               *session_key = p->auth_state.session_info->session_key;
-               return NT_STATUS_OK;
-       }
-       return NT_STATUS_NO_USER_SESSION_KEY;
+       struct dcesrv_auth *auth = &p->auth_state;
+
+       return dcesrv_remote_session_key(auth, session_key);
+}
+
+/*
+ * Fetch the authentication session key if available.
+ *
+ * This is the key generated by a gensec authentication.
+ *
+ */
+_PUBLIC_ NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call,
+                                         DATA_BLOB *session_key)
+{
+       struct dcesrv_auth *auth = &call->conn->auth_state;
+
+       return dcesrv_session_info_session_key(auth, session_key);
 }
 
 /*
@@ -477,7 +520,14 @@ NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
                                  DATA_BLOB *session_key)
 {
-       NTSTATUS status = p->auth_state.session_key(p, session_key);
+       struct dcesrv_auth *auth = &p->auth_state;
+       NTSTATUS status;
+
+       if (auth->session_key_fn == NULL) {
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
+       status = auth->session_key_fn(auth, session_key);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -487,10 +537,23 @@ _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
        return NT_STATUS_OK;
 }
 
+/*
+ * Fetch the transport session key if available.
+ * Typically this is the SMB session key
+ * or a fixed key for local transports.
+ *
+ * The key is always truncated to 16 bytes.
+*/
+_PUBLIC_ NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call,
+                                              DATA_BLOB *session_key)
+{
+       return dcesrv_fetch_session_key(call->conn, session_key);
+}
+
 /*
   connect to a dcerpc endpoint
 */
-_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
+static NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
                                 TALLOC_CTX *mem_ctx,
                                 const struct dcesrv_endpoint *ep,
                                 struct auth_session_info *session_info,
@@ -500,6 +563,8 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
                                 uint32_t state_flags,
                                 struct dcesrv_connection **_p)
 {
+       enum dcerpc_transport_t transport =
+               dcerpc_binding_get_transport(ep->ep_description);
        struct dcesrv_connection *p;
 
        if (!session_info) {
@@ -517,8 +582,6 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
        p->dce_ctx = dce_ctx;
        p->endpoint = ep;
        p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx);
-       p->auth_state.session_info = session_info;
-       p->auth_state.session_key = dcesrv_generic_session_key;
        p->event_ctx = event_ctx;
        p->msg_ctx = msg_ctx;
        p->server_id = server_id;
@@ -528,6 +591,23 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
        p->max_xmit_frag = 5840;
        p->max_total_request_size = DCERPC_NCACN_REQUEST_DEFAULT_MAX_SIZE;
 
+       p->auth_state.session_info = session_info;
+       switch (transport) {
+       case NCACN_NP:
+               p->auth_state.session_key_fn = dcesrv_remote_session_key;
+               break;
+       case NCALRPC:
+       case NCACN_UNIX_STREAM:
+               p->auth_state.session_key_fn = dcesrv_local_fixed_session_key;
+               break;
+       default:
+               /*
+                * All other's get a NULL pointer, which
+                * results in NT_STATUS_NO_USER_SESSION_KEY
+                */
+               break;
+       }
+
        /*
         * For now we only support NDR32.
         */
@@ -2661,7 +2741,6 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn)
        }
 
        if (transport == NCACN_NP) {
-               dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
                dcesrv_conn->stream = talloc_move(dcesrv_conn,
                                                  &srv_conn->tstream);
        } else {
@@ -2723,8 +2802,6 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn)
 
        srv_conn->private_data = dcesrv_conn;
 
-       irpc_add_name(srv_conn->msg_ctx, "rpc_server");
-
        subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
                                               dcesrv_conn->event_ctx,
                                               dcesrv_conn->stream);
@@ -2870,7 +2947,9 @@ static const struct stream_server_ops dcesrv_stream_ops = {
 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, 
                                   struct loadparm_context *lp_ctx,
                                   struct dcesrv_endpoint *e,
-                           struct tevent_context *event_ctx, const struct model_ops *model_ops)
+                                  struct tevent_context *event_ctx,
+                                  const struct model_ops *model_ops,
+                                  void *process_context)
 {
        struct dcesrv_socket_context *dcesrv_sock;
        uint16_t port = 1;
@@ -2890,7 +2969,7 @@ static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
                                     model_ops, &dcesrv_stream_ops, 
                                     "unix", endpoint, &port,
                                     lpcfg_socket_options(lp_ctx),
-                                    dcesrv_sock);
+                                    dcesrv_sock, process_context);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
                         endpoint, nt_errstr(status)));
@@ -2902,7 +2981,9 @@ static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, 
                                      struct loadparm_context *lp_ctx,
                                      struct dcesrv_endpoint *e,
-                                     struct tevent_context *event_ctx, const struct model_ops *model_ops)
+                                     struct tevent_context *event_ctx,
+                                     const struct model_ops *model_ops,
+                                     void *process_context)
 {
        struct dcesrv_socket_context *dcesrv_sock;
        uint16_t port = 1;
@@ -2944,7 +3025,7 @@ static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
                                     model_ops, &dcesrv_stream_ops, 
                                     "unix", full_path, &port, 
                                     lpcfg_socket_options(lp_ctx),
-                                    dcesrv_sock);
+                                    dcesrv_sock, process_context);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
                         endpoint, full_path, nt_errstr(status)));
@@ -2955,7 +3036,9 @@ static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
                                 struct loadparm_context *lp_ctx,
                                 struct dcesrv_endpoint *e,
-                                struct tevent_context *event_ctx, const struct model_ops *model_ops)
+                                struct tevent_context *event_ctx,
+                                const struct model_ops *model_ops,
+                                void *process_context)
 {
        struct dcesrv_socket_context *dcesrv_sock;
        NTSTATUS status;
@@ -2977,7 +3060,7 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
        status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
                                          model_ops, &dcesrv_stream_ops,
                                          endpoint,
-                                         dcesrv_sock);
+                                         dcesrv_sock, process_context);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
                         endpoint, nt_errstr(status)));
@@ -2990,9 +3073,12 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
 /*
   add a socket address to the list of events, one event per dcerpc endpoint
 */
-static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
-                                        struct tevent_context *event_ctx, const struct model_ops *model_ops,
-                                        const char *address)
+static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx,
+                                        struct dcesrv_endpoint *e,
+                                        struct tevent_context *event_ctx,
+                                        const struct model_ops *model_ops,
+                                        const char *address,
+                                        void *process_context)
 {
        struct dcesrv_socket_context *dcesrv_sock;
        uint16_t port = 0;
@@ -3016,7 +3102,7 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct
                                     model_ops, &dcesrv_stream_ops, 
                                     "ip", address, &port,
                                     lpcfg_socket_options(dce_ctx->lp_ctx),
-                                    dcesrv_sock);
+                                    dcesrv_sock, process_context);
        if (!NT_STATUS_IS_OK(status)) {
                struct dcesrv_if_list *iface;
                DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) for ",
@@ -3055,7 +3141,9 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct
 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, 
                                  struct loadparm_context *lp_ctx,
                                  struct dcesrv_endpoint *e,
-                                 struct tevent_context *event_ctx, const struct model_ops *model_ops)
+                                 struct tevent_context *event_ctx,
+                                 const struct model_ops *model_ops,
+                                 void *process_context)
 {
        NTSTATUS status;
 
@@ -3070,17 +3158,21 @@ static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
                num_interfaces = iface_list_count(ifaces);
                for(i = 0; i < num_interfaces; i++) {
                        const char *address = iface_list_n_ip(ifaces, i);
-                       status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
+                       status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx,
+                                                         model_ops, address,
+                                                         process_context);
                        NT_STATUS_NOT_OK_RETURN(status);
                }
        } else {
                char **wcard;
-               int i;
-               int num_binds = 0;
+               size_t i;
+               size_t num_binds = 0;
                wcard = iface_list_wildcard(dce_ctx);
                NT_STATUS_HAVE_NO_MEMORY(wcard);
                for (i=0; wcard[i]; i++) {
-                       status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
+                       status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx,
+                                                         model_ops, wcard[i],
+                                                         process_context);
                        if (NT_STATUS_IS_OK(status)) {
                                num_binds++;
                        }
@@ -3098,23 +3190,28 @@ NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
                       struct loadparm_context *lp_ctx,
                       struct dcesrv_endpoint *e,
                       struct tevent_context *event_ctx,
-                      const struct model_ops *model_ops)
+                      const struct model_ops *model_ops,
+                      void *process_context)
 {
        enum dcerpc_transport_t transport =
                dcerpc_binding_get_transport(e->ep_description);
 
        switch (transport) {
        case NCACN_UNIX_STREAM:
-               return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
+               return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx,
+                                         model_ops, process_context);
 
        case NCALRPC:
-               return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
+               return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx,
+                                            model_ops, process_context);
 
        case NCACN_IP_TCP:
-               return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
+               return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx,
+                                        model_ops, process_context);
 
        case NCACN_NP:
-               return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
+               return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx,
+                                       model_ops, process_context);
 
        default:
                return NT_STATUS_NOT_SUPPORTED;
@@ -3147,3 +3244,11 @@ _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call
 {
        return dce_call->context->conn->auth_state.session_info->info->account_name;
 }
+
+/**
+ * retrieve session_info from a dce_call
+ */
+_PUBLIC_ struct auth_session_info *dcesrv_call_session_info(struct dcesrv_call_state *dce_call)
+{
+       return dce_call->context->conn->auth_state.session_info;
+}