Merge branch 'master' of git://git.samba.org/samba
[kai/samba.git] / source4 / smbd / service_named_pipe.c
index ad7ba76b0debc6c354c92e91cfe1b72b656208b3..93ae60d69adf5fe64cb4b7280ee30183308c1387 100644 (file)
 */
 
 #include "includes.h"
-#include "lib/events/events.h"
-#include "lib/socket/socket.h"
+#include <tevent.h>
 #include "smbd/service.h"
 #include "param/param.h"
 #include "auth/session.h"
+#include "auth/auth_sam_reply.h"
 #include "lib/stream/packet.h"
 #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
 #include "system/passwd.h"
+#include "libcli/raw/smb.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
 
 struct named_pipe_socket {
        const char *pipe_name;
@@ -49,7 +52,12 @@ static void named_pipe_handover_connection(void *private_data)
                private_data, struct named_pipe_connection);
        struct stream_connection *conn = pipe_conn->connection;
 
-       EVENT_FD_NOT_WRITEABLE(conn->event.fde);
+       TEVENT_FD_NOT_WRITEABLE(conn->event.fde);
+
+       packet_set_socket(pipe_conn->packet, NULL);
+       packet_set_event_context(pipe_conn->packet, NULL);
+       packet_set_fde(pipe_conn->packet, NULL);
+       TALLOC_FREE(pipe_conn->packet);
 
        if (!NT_STATUS_IS_OK(pipe_conn->status)) {
                stream_terminate_connection(conn, nt_errstr(pipe_conn->status));
@@ -59,12 +67,12 @@ static void named_pipe_handover_connection(void *private_data)
        /*
         * remove the named_pipe layer together with its packet layer
         */
-       conn->ops       = pipe_conn->pipe_sock->ops;
-       conn->private   = pipe_conn->pipe_sock->private_data;
-       talloc_free(pipe_conn);
+       conn->ops               = pipe_conn->pipe_sock->ops;
+       conn->private_data      = pipe_conn->pipe_sock->private_data;
+       talloc_unlink(conn, pipe_conn);
 
        /* we're now ready to start receiving events on this stream */
-       EVENT_FD_READABLE(conn->event.fde);
+       TEVENT_FD_READABLE(conn->event.fde);
 
        /*
         * hand over to the real pipe implementation,
@@ -106,7 +114,7 @@ static NTSTATUS named_pipe_recv_auth_request(void *private_data,
 
        DEBUG(10,("named_pipe_auth: req_blob.length[%u]\n",
                  (unsigned int)req_blob.length));
-       dump_data(10, req_blob.data, req_blob.length);
+       dump_data(11, req_blob.data, req_blob.length);
 
        /* parse the passed credentials */
        ndr_err = ndr_pull_struct_blob_all(
@@ -122,6 +130,10 @@ static NTSTATUS named_pipe_recv_auth_request(void *private_data,
                goto reply;
        }
 
+       if (DEBUGLVL(10)) {
+               NDR_PRINT_DEBUG(named_pipe_auth_req, &req);
+       }
+
        if (strcmp(NAMED_PIPE_AUTH_MAGIC, req.magic) != 0) {
                DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n",
                          req.magic, NAMED_PIPE_AUTH_MAGIC));
@@ -164,6 +176,137 @@ static NTSTATUS named_pipe_recv_auth_request(void *private_data,
                        goto reply;
                }
 
+               break;
+       case 2:
+               rep.level = 2;
+               rep.info.info2.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
+               rep.info.info2.device_state = 0xff | 0x0400 | 0x0100;
+               rep.info.info2.allocation_size = 4096;
+
+               if (!req.info.info2.sam_info3) {
+                       /*
+                        * anon connection, we don't create a session info
+                        * and leave it NULL
+                        */
+                       rep.status = NT_STATUS_OK;
+                       break;
+               }
+
+               val.sam3 = req.info.info2.sam_info3;
+
+               rep.status = make_server_info_netlogon_validation(pipe_conn,
+                                               val.sam3->base.account_name.string,
+                                               3, &val, &server_info);
+               if (!NT_STATUS_IS_OK(rep.status)) {
+                       DEBUG(2, ("make_server_info_netlogon_validation returned "
+                                 "%s\n", nt_errstr(rep.status)));
+                       goto reply;
+               }
+
+               /* setup the session_info on the connection */
+               rep.status = auth_generate_session_info(conn,
+                                                       conn->event.ctx,
+                                                       conn->lp_ctx,
+                                                       server_info,
+                                                       &conn->session_info);
+               if (!NT_STATUS_IS_OK(rep.status)) {
+                       DEBUG(2, ("auth_generate_session_info failed: %s\n",
+                                 nt_errstr(rep.status)));
+                       goto reply;
+               }
+
+               conn->session_info->session_key = data_blob_const(req.info.info2.session_key,
+                                                       req.info.info2.session_key_length);
+               talloc_steal(conn->session_info, req.info.info2.session_key);
+
+               break;
+       case 3:
+               rep.level = 3;
+               rep.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
+               rep.info.info3.device_state = 0xff | 0x0400 | 0x0100;
+               rep.info.info3.allocation_size = 4096;
+
+               if (!req.info.info3.sam_info3) {
+                       /*
+                        * anon connection, we don't create a session info
+                        * and leave it NULL
+                        */
+                       rep.status = NT_STATUS_OK;
+                       break;
+               }
+
+               val.sam3 = req.info.info3.sam_info3;
+
+               rep.status = make_server_info_netlogon_validation(pipe_conn,
+                                               val.sam3->base.account_name.string,
+                                               3, &val, &server_info);
+               if (!NT_STATUS_IS_OK(rep.status)) {
+                       DEBUG(2, ("make_server_info_netlogon_validation returned "
+                                 "%s\n", nt_errstr(rep.status)));
+                       goto reply;
+               }
+
+               /* setup the session_info on the connection */
+               rep.status = auth_generate_session_info(conn,
+                                                       conn->event.ctx,
+                                                       conn->lp_ctx,
+                                                       server_info,
+                                                       &conn->session_info);
+               if (!NT_STATUS_IS_OK(rep.status)) {
+                       DEBUG(2, ("auth_generate_session_info failed: %s\n",
+                                 nt_errstr(rep.status)));
+                       goto reply;
+               }
+
+               if (req.info.info3.gssapi_delegated_creds_length) {
+                       OM_uint32 minor_status;
+                       gss_buffer_desc cred_token;
+                       gss_cred_id_t cred_handle;
+                       int ret;
+
+                       DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n"));
+
+                       cred_token.value = req.info.info3.gssapi_delegated_creds;
+                       cred_token.length = req.info.info3.gssapi_delegated_creds_length;
+
+                       ret = gss_import_cred(&minor_status,
+                                              &cred_token,
+                                              &cred_handle);
+                       if (ret != GSS_S_COMPLETE) {
+                               rep.status = NT_STATUS_INTERNAL_ERROR;
+                               goto reply;
+                       }
+
+                       conn->session_info->credentials = cli_credentials_init(conn->session_info);
+                       if (!conn->session_info->credentials) {
+                               rep.status = NT_STATUS_NO_MEMORY;
+                               goto reply;
+                       }
+
+                       cli_credentials_set_conf(conn->session_info->credentials,
+                                                conn->lp_ctx);
+                       /* Just so we don't segfault trying to get at a username */
+                       cli_credentials_set_anonymous(conn->session_info->credentials);
+
+                       ret = cli_credentials_set_client_gss_creds(conn->session_info->credentials,
+                                                                  conn->event.ctx,
+                                                                  conn->lp_ctx,
+                                                                  cred_handle,
+                                                                  CRED_SPECIFIED);
+                       if (ret) {
+                               rep.status = NT_STATUS_INTERNAL_ERROR;
+                               goto reply;
+                       }
+
+                       /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
+                       cli_credentials_set_kerberos_state(conn->session_info->credentials,
+                                                          CRED_MUST_USE_KERBEROS);
+               }
+
+               conn->session_info->session_key = data_blob_const(req.info.info3.session_key,
+                                                       req.info.info3.session_key_length);
+               talloc_steal(conn->session_info, req.info.info3.session_key);
+
                break;
        default:
                DEBUG(2, ("named_pipe_auth_req: unknown level %u\n",
@@ -186,10 +329,13 @@ reply:
                return status;
        }
 
-       pipe_conn->status = rep.status;
+       DEBUG(10,("named_pipe_auth reply[%u]\n", (unsigned)rep_blob.length));
+       dump_data(11, rep_blob.data, rep_blob.length);
+       if (DEBUGLVL(10)) {
+               NDR_PRINT_DEBUG(named_pipe_auth_rep, &rep);
+       }
 
-       DEBUG(10,("named_pipe_auth reply[%u]\n", rep_blob.length));
-       dump_data(10, rep_blob.data, rep_blob.length);
+       pipe_conn->status = rep.status;
        status = packet_send_callback(pipe_conn->packet, rep_blob,
                                      named_pipe_handover_connection,
                                      pipe_conn);
@@ -208,7 +354,7 @@ reply:
 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
 {
        struct named_pipe_connection *pipe_conn = talloc_get_type(
-               conn->private, struct named_pipe_connection);
+               conn->private_data, struct named_pipe_connection);
 
        DEBUG(10,("named_pipe_recv\n"));
 
@@ -221,7 +367,7 @@ static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
 {
        struct named_pipe_connection *pipe_conn = talloc_get_type(
-               conn->private, struct named_pipe_connection);
+               conn->private_data, struct named_pipe_connection);
 
        packet_queue_run(pipe_conn->packet);
 }
@@ -237,7 +383,7 @@ static void named_pipe_recv_error(void *private_data, NTSTATUS status)
        stream_terminate_connection(pipe_conn->connection, nt_errstr(status));
 }
 
-static NTSTATUS named_pipe_full_request(void *private, DATA_BLOB blob, size_t *size)
+static NTSTATUS named_pipe_full_request(void *private_data, DATA_BLOB blob, size_t *size)
 {
        if (blob.length < 8) {
                return STATUS_MORE_ENTRIES;
@@ -261,7 +407,7 @@ static NTSTATUS named_pipe_full_request(void *private, DATA_BLOB blob, size_t *s
 static void named_pipe_accept(struct stream_connection *conn)
 {
        struct named_pipe_socket *pipe_sock = talloc_get_type(
-               conn->private, struct named_pipe_socket);
+               conn->private_data, struct named_pipe_socket);
        struct named_pipe_connection *pipe_conn;
 
        DEBUG(5,("named_pipe_accept\n"));
@@ -290,7 +436,7 @@ static void named_pipe_accept(struct stream_connection *conn)
        pipe_conn->pipe_sock = pipe_sock;
 
        pipe_conn->connection = conn;
-       conn->private = pipe_conn;
+       conn->private_data = pipe_conn;
 }
 
 static const struct stream_server_ops named_pipe_stream_ops = {
@@ -300,7 +446,7 @@ static const struct stream_server_ops named_pipe_stream_ops = {
        .send_handler           = named_pipe_send,
 };
 
-NTSTATUS stream_setup_named_pipe(struct event_context *event_context,
+NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context,
                                 struct loadparm_context *lp_ctx,
                                 const struct model_ops *model_ops,
                                 const struct stream_server_ops *stream_ops,
@@ -329,6 +475,8 @@ NTSTATUS stream_setup_named_pipe(struct event_context *event_context,
 
        if (!directory_create_or_exist(dirname, geteuid(), 0700)) {
                status = map_nt_error_from_unix(errno);
+               DEBUG(0,(__location__ ": Failed to create stream pipe directory %s - %s\n",
+                        dirname, nt_errstr(status)));
                goto fail;
        }