From 3c8dc5cd214c58747bfbbd72a8d05fc50454585a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 21 May 2010 12:29:22 -0400 Subject: s4:smbd: Use tstream_npa_accept_existing to accept named pipe connections Pair-programmed-with: Stefan Metzmacher --- source4/rpc_server/service_rpc.c | 28 +- source4/smbd/service_named_pipe.c | 693 +++++++++----------------------------- 2 files changed, 175 insertions(+), 546 deletions(-) diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c index 05e45d8529..87c38fd2ed 100644 --- a/source4/rpc_server/service_rpc.c +++ b/source4/rpc_server/service_rpc.c @@ -361,21 +361,20 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn) if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) { dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key; - ret = tstream_npa_existing_socket(dcesrv_conn, - socket_get_fd(srv_conn->socket), - FILE_TYPE_MESSAGE_MODE_PIPE, - &dcesrv_conn->stream); + dcesrv_conn->stream = talloc_move(dcesrv_conn, + &srv_conn->tstream); } else { ret = tstream_bsd_existing_socket(dcesrv_conn, socket_get_fd(srv_conn->socket), &dcesrv_conn->stream); - } - if (ret == -1) { - status = map_nt_error_from_unix(errno); - DEBUG(0,("dcesrv_sock_accept: failed to setup tstream: %s\n", - nt_errstr(status))); - stream_terminate_connection(srv_conn, nt_errstr(status)); - return; + if (ret == -1) { + status = map_nt_error_from_unix(errno); + DEBUG(0, ("dcesrv_sock_accept: " + "failed to setup tstream: %s\n", + nt_errstr(status))); + stream_terminate_connection(srv_conn, nt_errstr(status)); + return; + } } dcesrv_conn->local_address = srv_conn->local_address; @@ -545,9 +544,10 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, dcesrv_sock->endpoint = e; dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - status = stream_setup_named_pipe(event_ctx, lp_ctx, - model_ops, &dcesrv_stream_ops, - e->ep_description->endpoint, dcesrv_sock); + status = tstream_setup_named_pipe(event_ctx, lp_ctx, + model_ops, &dcesrv_stream_ops, + e->ep_description->endpoint, + dcesrv_sock); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n", e->ep_description->endpoint, nt_errstr(status))); diff --git a/source4/smbd/service_named_pipe.c b/source4/smbd/service_named_pipe.c index 235d4c2a3a..81f9878d55 100644 --- a/source4/smbd/service_named_pipe.c +++ b/source4/smbd/service_named_pipe.c @@ -36,6 +36,7 @@ #include "auth/credentials/credentials.h" #include "auth/credentials/credentials_krb5.h" #include "libcli/security/dom_sid.h" +#include "libcli/named_pipe_auth/npa_tstream.h" struct named_pipe_socket { const char *pipe_name; @@ -44,234 +45,127 @@ struct named_pipe_socket { void *private_data; }; -struct named_pipe_connection { - struct stream_connection *connection; - const struct named_pipe_socket *pipe_sock; - struct tstream_context *tstream; -}; - -static void named_pipe_terminate_connection(struct named_pipe_connection *pipe_conn, const char *reason) -{ - stream_terminate_connection(pipe_conn->connection, reason); -} - -static NTSTATUS named_pipe_full_request(void *private_data, DATA_BLOB blob, size_t *size) -{ - if (blob.length < 8) { - return STATUS_MORE_ENTRIES; - } - - if (memcmp(NAMED_PIPE_AUTH_MAGIC, &blob.data[4], 4) != 0) { - DEBUG(0,("named_pipe_full_request: wrong protocol\n")); - *size = blob.length; - /* the error will be handled in named_pipe_recv_auth_request */ - return NT_STATUS_OK; - } - - *size = 4 + RIVAL(blob.data, 0); - if (*size > blob.length) { - return STATUS_MORE_ENTRIES; - } - - return NT_STATUS_OK; -} - -static void named_pipe_auth_request(struct tevent_req *subreq); +static void named_pipe_accept_done(struct tevent_req *subreq); static void named_pipe_accept(struct stream_connection *conn) { - struct named_pipe_socket *pipe_sock = talloc_get_type(conn->private_data, - struct named_pipe_socket); - struct named_pipe_connection *pipe_conn; + struct tstream_context *plain_tstream; + int fd; struct tevent_req *subreq; - int rc, fd; + int ret; - pipe_conn = talloc_zero(conn, struct named_pipe_connection); - if (pipe_conn == NULL) { - stream_terminate_connection(conn, - "named_pipe_accept: out of memory"); - return; - } + /* Let tstream take over fd operations */ + fd = socket_get_fd(conn->socket); + socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE); TALLOC_FREE(conn->event.fde); + TALLOC_FREE(conn->socket); - /* - * We have to duplicate the fd, cause it gets closed when the tstream - * is freed and you shouldn't work a fd the tstream is based on. - */ - fd = dup(socket_get_fd(conn->socket)); - if (fd == -1) { - char *reason; - - reason = talloc_asprintf(conn, - "named_pipe_accept: failed to duplicate the file descriptor - %s", - strerror(errno)); - if (reason == NULL) { - reason = strerror(errno); - } - stream_terminate_connection(conn, reason); - } - rc = tstream_bsd_existing_socket(pipe_conn, - fd, - &pipe_conn->tstream); - if (rc < 0) { + ret = tstream_bsd_existing_socket(conn, fd, &plain_tstream); + if (ret != 0) { stream_terminate_connection(conn, "named_pipe_accept: out of memory"); return; } - pipe_conn->connection = conn; - pipe_conn->pipe_sock = pipe_sock; - conn->private_data = pipe_conn; - - /* - * The named pipe pdu's have the length as 8 byte (initial_read_size), - * named_pipe_full_request provides the pdu length then. - */ - subreq = tstream_read_pdu_blob_send(pipe_conn, - pipe_conn->connection->event.ctx, - pipe_conn->tstream, - 8, /* initial_read_size */ - named_pipe_full_request, - pipe_conn); + subreq = tstream_npa_accept_existing_send(conn, conn->event.ctx, + plain_tstream, + FILE_TYPE_MESSAGE_MODE_PIPE, + 0xff | 0x0400 | 0x0100, + 4096); if (subreq == NULL) { - named_pipe_terminate_connection(pipe_conn, - "named_pipe_accept: " - "no memory for tstream_read_pdu_blob_send"); + stream_terminate_connection(conn, + "named_pipe_accept: " + "no memory for tstream_npa_accept_existing_send"); return; } - tevent_req_set_callback(subreq, named_pipe_auth_request, pipe_conn); + tevent_req_set_callback(subreq, named_pipe_accept_done, conn); } -struct named_pipe_call { - struct named_pipe_connection *pipe_conn; - DATA_BLOB in; - DATA_BLOB out; - struct iovec out_iov[1]; - NTSTATUS status; -}; - -static void named_pipe_handover_connection(struct tevent_req *subreq); - -static void named_pipe_auth_request(struct tevent_req *subreq) +static void named_pipe_accept_done(struct tevent_req *subreq) { - struct named_pipe_connection *pipe_conn = tevent_req_callback_data(subreq, - struct named_pipe_connection); - struct stream_connection *conn = pipe_conn->connection; - struct named_pipe_call *call; - enum ndr_err_code ndr_err; + struct stream_connection *conn = tevent_req_callback_data(subreq, + struct stream_connection); + struct named_pipe_socket *pipe_sock = + talloc_get_type(conn->private_data, + struct named_pipe_socket); + struct tsocket_address *client; + char *client_name; + struct tsocket_address *server; + char *server_name; + struct netr_SamInfo3 *info3; + DATA_BLOB session_key; + DATA_BLOB delegated_creds; + union netr_Validation val; struct auth_serversupplied_info *server_info; - struct named_pipe_auth_req pipe_request; - struct named_pipe_auth_rep pipe_reply; struct auth_context *auth_context; uint32_t session_flags = 0; struct dom_sid *anonymous_sid; + const char *reason = NULL; + TALLOC_CTX *tmp_ctx; NTSTATUS status; + int error; int ret; - call = talloc(pipe_conn, struct named_pipe_call); - if (call == NULL) { - named_pipe_terminate_connection(pipe_conn, - "named_pipe_auth_request: " - "no memory for named_pipe_call"); - return; + tmp_ctx = talloc_new(conn); + if (!tmp_ctx) { + reason = "Out of memory!\n"; + goto out; } - call->pipe_conn = pipe_conn; - status = tstream_read_pdu_blob_recv(subreq, - call, - &call->in); + ret = tstream_npa_accept_existing_recv(subreq, &error, tmp_ctx, + &conn->tstream, + &client, + &client_name, + &server, + &server_name, + &info3, + &session_key, + &delegated_creds); TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - const char *reason; - - reason = talloc_asprintf(call, "named_pipe_call_loop: " - "tstream_read_pdu_blob_recv() - %s", - nt_errstr(status)); - if (reason == NULL) { - reason = nt_errstr(status); - } - - named_pipe_terminate_connection(pipe_conn, reason); - return; - } - - DEBUG(10,("Received named_pipe packet of length %lu from %s\n", - (long) call->in.length, - tsocket_address_string(pipe_conn->connection->remote_address, call))); - dump_data(11, call->in.data, call->in.length); - - /* - * TODO: check it's a root (uid == 0) pipe - */ - - ZERO_STRUCT(pipe_reply); - pipe_reply.level = 0; - pipe_reply.status = NT_STATUS_INTERNAL_ERROR; - - /* parse the passed credentials */ - ndr_err = ndr_pull_struct_blob_all( - &call->in, - pipe_conn, - &pipe_request, - (ndr_pull_flags_fn_t) ndr_pull_named_pipe_auth_req); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - pipe_reply.status = ndr_map_error2ntstatus(ndr_err); - DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n", - nt_errstr(pipe_reply.status))); - goto reply; - } - - if (DEBUGLVL(10)) { - NDR_PRINT_DEBUG(named_pipe_auth_req, &pipe_request); - } - - if (strcmp(NAMED_PIPE_AUTH_MAGIC, pipe_request.magic) != 0) { - DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n", - pipe_request.magic, NAMED_PIPE_AUTH_MAGIC)); - pipe_reply.status = NT_STATUS_INVALID_PARAMETER; - goto reply; + if (ret != 0) { + reason = talloc_asprintf(conn, + "tstream_npa_accept_existing_recv()" + " failed: %s", strerror(error)); + goto out; } - switch (pipe_request.level) { - case 0: - /* - * anon connection, we don't create a session info - * and leave it NULL - */ - pipe_reply.level = 0; - pipe_reply.status = NT_STATUS_OK; - break; - case 1: - val.sam3 = &pipe_request.info.info1; - - pipe_reply.level = 1; - pipe_reply.status = make_server_info_netlogon_validation(pipe_conn, - "TODO", - 3, &val, - &server_info); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("make_server_info_netlogon_validation returned " - "%s\n", nt_errstr(pipe_reply.status))); - goto reply; + DEBUG(10, ("Accepted npa connection from %s. " + "Client: %s (%s). Server: %s (%s)\n", + tsocket_address_string(conn->remote_address, tmp_ctx), + client_name, tsocket_address_string(client, tmp_ctx), + server_name, tsocket_address_string(server, tmp_ctx))); + + if (info3) { + val.sam3 = info3; + + status = make_server_info_netlogon_validation(conn, + val.sam3->base.account_name.string, + 3, &val, &server_info); + if (!NT_STATUS_IS_OK(status)) { + reason = talloc_asprintf(conn, + "make_server_info_netlogon_validation " + "returned: %s", nt_errstr(status)); + goto out; } - pipe_reply.status = auth_context_create(conn, - conn->event.ctx, conn->msg_ctx, - conn->lp_ctx, - &auth_context); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("auth_context_create returned " - "%s\n", nt_errstr(pipe_reply.status))); - goto reply; + status = auth_context_create(conn, conn->event.ctx, + conn->msg_ctx, conn->lp_ctx, + &auth_context); + if (!NT_STATUS_IS_OK(status)) { + reason = talloc_asprintf(conn, + "auth_context_create returned: %s", + nt_errstr(status)); + goto out; } - anonymous_sid = dom_sid_parse_talloc(auth_context, SID_NT_ANONYMOUS); + anonymous_sid = dom_sid_parse_talloc(auth_context, + SID_NT_ANONYMOUS); if (anonymous_sid == NULL) { - named_pipe_terminate_connection(pipe_conn, "Failed to parse Anonymous SID "); talloc_free(auth_context); - return; + reason = "Failed to parse Anonymous SID "; + goto out; } session_flags = AUTH_SESSION_INFO_DEFAULT_GROUPS; @@ -279,355 +173,98 @@ static void named_pipe_auth_request(struct tevent_req *subreq) session_flags |= AUTH_SESSION_INFO_AUTHENTICATED; } - /* setup the session_info on the connection */ - pipe_reply.status = auth_context->generate_session_info(conn, - auth_context, - server_info, - session_flags, - &conn->session_info); - talloc_free(auth_context); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("auth_generate_session_info failed: %s\n", - nt_errstr(pipe_reply.status))); - goto reply; - } - - break; - case 2: - pipe_reply.level = 2; - pipe_reply.info.info2.file_type = FILE_TYPE_MESSAGE_MODE_PIPE; - pipe_reply.info.info2.device_state = 0xff | 0x0400 | 0x0100; - pipe_reply.info.info2.allocation_size = 4096; - - if (pipe_request.info.info2.sam_info3 == NULL) { - /* - * anon connection, we don't create a session info - * and leave it NULL - */ - pipe_reply.status = NT_STATUS_OK; - break; - } - - val.sam3 = pipe_request.info.info2.sam_info3; - - pipe_reply.status = make_server_info_netlogon_validation(pipe_conn, - val.sam3->base.account_name.string, - 3, &val, &server_info); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("make_server_info_netlogon_validation returned " - "%s\n", nt_errstr(pipe_reply.status))); - goto reply; - } /* setup the session_info on the connection */ - pipe_reply.status = auth_context_create(conn, - conn->event.ctx, conn->msg_ctx, - conn->lp_ctx, - &auth_context); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("auth_context_create returned " - "%s\n", nt_errstr(pipe_reply.status))); - goto reply; - } - - anonymous_sid = dom_sid_parse_talloc(auth_context, SID_NT_ANONYMOUS); - if (anonymous_sid == NULL) { - named_pipe_terminate_connection(pipe_conn, "Failed to parse Anonymous SID "); - talloc_free(auth_context); - return; - } - - session_flags = AUTH_SESSION_INFO_DEFAULT_GROUPS; - if (!dom_sid_equal(anonymous_sid, server_info->account_sid)) { - session_flags |= AUTH_SESSION_INFO_AUTHENTICATED; - } - - pipe_reply.status = auth_context->generate_session_info(conn, - auth_context, - server_info, - session_flags, - &conn->session_info); - talloc_free(auth_context); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("auth_generate_session_info failed: %s\n", - nt_errstr(pipe_reply.status))); - goto reply; - } - - conn->session_info->session_key = data_blob_const(pipe_request.info.info2.session_key, - pipe_request.info.info2.session_key_length); - talloc_steal(conn->session_info, pipe_request.info.info2.session_key); - - break; - case 3: - pipe_reply.level = 3; - pipe_reply.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE; - pipe_reply.info.info3.device_state = 0xff | 0x0400 | 0x0100; - pipe_reply.info.info3.allocation_size = 4096; - - if (pipe_request.info.info3.server_addr == NULL) { - pipe_reply.status = NT_STATUS_INVALID_ADDRESS; - DEBUG(2, ("Missing server address\n")); - goto reply; - } - if (pipe_request.info.info3.client_addr == NULL) { - pipe_reply.status = NT_STATUS_INVALID_ADDRESS; - DEBUG(2, ("Missing client address\n")); - goto reply; - } - - ret = tsocket_address_inet_from_strings(conn, "ip", - pipe_request.info.info3.server_addr, - pipe_request.info.info3.server_port, - &conn->local_address); - if (ret != 0) { - DEBUG(2, ("Invalid server address[%s] port[%u] - %s\n", - pipe_request.info.info3.server_addr, - pipe_request.info.info3.server_port, - strerror(errno))); - pipe_reply.status = NT_STATUS_INVALID_ADDRESS; - goto reply; - } - - ret = tsocket_address_inet_from_strings(conn, "ip", - pipe_request.info.info3.client_addr, - pipe_request.info.info3.client_port, - &conn->remote_address); - if (ret != 0) { - DEBUG(2, ("Invalid client address[%s] port[%u] - %s\n", - pipe_request.info.info3.client_addr, - pipe_request.info.info3.client_port, - strerror(errno))); - pipe_reply.status = NT_STATUS_INVALID_ADDRESS; - goto reply; - } - - if (pipe_request.info.info3.sam_info3 == NULL) { - /* - * anon connection, we don't create a session info - * and leave it NULL - */ - pipe_reply.status = NT_STATUS_OK; - break; - } - - val.sam3 = pipe_request.info.info3.sam_info3; - - pipe_reply.status = make_server_info_netlogon_validation(pipe_conn, - val.sam3->base.account_name.string, - 3, &val, &server_info); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("make_server_info_netlogon_validation returned " - "%s\n", nt_errstr(pipe_reply.status))); - goto reply; - } - - /* setup the session_info on the connection */ - pipe_reply.status = auth_context_create(conn, - conn->event.ctx, conn->msg_ctx, - conn->lp_ctx, - &auth_context); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("auth_context_create returned " - "%s\n", nt_errstr(pipe_reply.status))); - goto reply; - } - - anonymous_sid = dom_sid_parse_talloc(auth_context, SID_NT_ANONYMOUS); - if (anonymous_sid == NULL) { - named_pipe_terminate_connection(pipe_conn, "Failed to parse Anonymous SID "); - talloc_free(auth_context); - return; - } - - session_flags = AUTH_SESSION_INFO_DEFAULT_GROUPS; - if (!dom_sid_equal(anonymous_sid, server_info->account_sid)) { - session_flags |= AUTH_SESSION_INFO_AUTHENTICATED; - } - - /* setup the session_info on the connection */ - pipe_reply.status = auth_context->generate_session_info(conn, - auth_context, - server_info, - session_flags, - &conn->session_info); + status = auth_context->generate_session_info(conn, + auth_context, + server_info, + session_flags, + &conn->session_info); talloc_free(auth_context); - if (!NT_STATUS_IS_OK(pipe_reply.status)) { - DEBUG(2, ("auth_generate_session_info failed: %s\n", - nt_errstr(pipe_reply.status))); - goto reply; - } - - if (pipe_request.info.info3.gssapi_delegated_creds_length) { - OM_uint32 minor_status; - gss_buffer_desc cred_token; - gss_cred_id_t cred_handle; - const char *error_string; - - DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n")); - - cred_token.value = pipe_request.info.info3.gssapi_delegated_creds; - cred_token.length = pipe_request.info.info3.gssapi_delegated_creds_length; - - ret = gss_import_cred(&minor_status, - &cred_token, - &cred_handle); - if (ret != GSS_S_COMPLETE) { - pipe_reply.status = NT_STATUS_INTERNAL_ERROR; - goto reply; - } - - conn->session_info->credentials = cli_credentials_init(conn->session_info); - if (conn->session_info->credentials == NULL) { - pipe_reply.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, &error_string); - if (ret) { - pipe_reply.status = NT_STATUS_INTERNAL_ERROR; - DEBUG(2, ("Failed to set pipe forwarded creds: %s\n", error_string)); - 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(pipe_request.info.info3.session_key, - pipe_request.info.info3.session_key_length); - talloc_steal(conn->session_info, pipe_request.info.info3.session_key); - - break; - default: - DEBUG(0, ("named_pipe_auth_req: unknown level %u\n", - pipe_request.level)); - pipe_reply.level = 0; - pipe_reply.status = NT_STATUS_INVALID_LEVEL; - goto reply; - } - -reply: - /* create the output */ - ndr_err = ndr_push_struct_blob(&call->out, pipe_conn, - &pipe_reply, - (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - const char *reason; - status = ndr_map_error2ntstatus(ndr_err); - - reason = talloc_asprintf(pipe_conn, "named_pipe_auth_request: could not marshall named_pipe_auth_rep: %s\n", - nt_errstr(status)); - if (reason == NULL) { - reason = "named_pipe_auth_request: could not marshall named_pipe_auth_rep"; + if (!NT_STATUS_IS_OK(status)) { + reason = talloc_asprintf(conn, + "auth_generate_session_info " + "returned: %s", nt_errstr(status)); + goto out; } - named_pipe_terminate_connection(pipe_conn, reason); - return; } - DEBUG(10,("named_pipe_auth_request: named_pipe_auth reply[%u]\n", - (unsigned) call->out.length)); - dump_data(11, call->out.data, call->out.length); - if (DEBUGLVL(10)) { - NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply); + if (session_key.length) { + conn->session_info->session_key = session_key; + talloc_steal(conn->session_info, session_key.data); } - call->status = pipe_reply.status; - - call->out_iov[0].iov_base = call->out.data; - call->out_iov[0].iov_len = call->out.length; + if (delegated_creds.length) { + struct cli_credentials *creds; + OM_uint32 minor_status; + gss_buffer_desc cred_token; + gss_cred_id_t cred_handle; + const char *error_string; - subreq = tstream_writev_send(call, - pipe_conn->connection->event.ctx, - pipe_conn->tstream, - call->out_iov, 1); - if (subreq == NULL) { - named_pipe_terminate_connection(pipe_conn, "named_pipe_auth_request: " - "no memory for tstream_writev_send"); - return; - } + DEBUG(10, ("Delegated credentials supplied by client\n")); - tevent_req_set_callback(subreq, named_pipe_handover_connection, call); -} + cred_token.value = delegated_creds.data; + cred_token.length = delegated_creds.length; -static void named_pipe_handover_connection(struct tevent_req *subreq) -{ - struct named_pipe_call *call = tevent_req_callback_data(subreq, - struct named_pipe_call); - struct named_pipe_connection *pipe_conn = call->pipe_conn; - struct stream_connection *conn = pipe_conn->connection; - int sys_errno; - int rc; - - rc = tstream_writev_recv(subreq, &sys_errno); - TALLOC_FREE(subreq); - if (rc == -1) { - const char *reason; - - reason = talloc_asprintf(call, "named_pipe_handover_connection: " - "tstream_writev_recv() - %d:%s", - sys_errno, strerror(sys_errno)); - if (reason == NULL) { - reason = "named_pipe_handover_connection: " - "tstream_writev_recv() failed"; + ret = gss_import_cred(&minor_status, + &cred_token, + &cred_handle); + if (ret != GSS_S_COMPLETE) { + reason = "Internal error in gss_import_cred()"; + goto out; } - named_pipe_terminate_connection(pipe_conn, reason); - return; - } - - if (!NT_STATUS_IS_OK(call->status)) { - const char *reason; - - reason = talloc_asprintf(call, "named_pipe_handover_connection: " - "reply status - %s", nt_errstr(call->status)); - if (reason == NULL) { - reason = nt_errstr(call->status); + creds = cli_credentials_init(conn->session_info); + if (!creds) { + reason = "Out of memory in cli_credentials_init()"; + goto out; + } + conn->session_info->credentials = creds; + + cli_credentials_set_conf(creds, conn->lp_ctx); + /* Just so we don't segfault trying to get at a username */ + cli_credentials_set_anonymous(creds); + + ret = cli_credentials_set_client_gss_creds(creds, + conn->event.ctx, + conn->lp_ctx, + cred_handle, + CRED_SPECIFIED, + &error_string); + if (ret) { + reason = talloc_asprintf(conn, + "Failed to set pipe forwarded" + "creds: %s\n", error_string); + goto out; } - named_pipe_terminate_connection(pipe_conn, reason); - return; - } + /* This credential handle isn't useful for password + * authentication, so ensure nobody tries to do that */ + cli_credentials_set_kerberos_state(creds, + CRED_MUST_USE_KERBEROS); - /* - * remove the named_pipe layer together with its packet layer - */ - conn->ops = pipe_conn->pipe_sock->ops; - conn->private_data = pipe_conn->pipe_sock->private_data; - talloc_unlink(conn, pipe_conn); - - conn->event.fde = tevent_add_fd(conn->event.ctx, - conn, - socket_get_fd(conn->socket), - TEVENT_FD_READ, - stream_io_handler_fde, - conn); - if (conn->event.fde == NULL) { - named_pipe_terminate_connection(pipe_conn, "named_pipe_handover_connection: " - "setting up the stream_io_handler_fde failed"); - return; } /* * hand over to the real pipe implementation, * now that we have setup the transport session_info */ + conn->ops = pipe_sock->ops; + conn->private_data = pipe_sock->private_data; conn->ops->accept_connection(conn); - DEBUG(10,("named_pipe_handover_connection[%s]: succeeded\n", - conn->ops->name)); + DEBUG(10, ("named pipe connection [%s] established\n", + conn->ops->name)); - /* we don't have to free call here as the connection got closed */ + talloc_free(tmp_ctx); + return; + +out: + talloc_free(tmp_ctx); + if (!reason) { + reason = "Internal error"; + } + stream_terminate_connection(conn, reason); } /* @@ -635,11 +272,7 @@ static void named_pipe_handover_connection(struct tevent_req *subreq) */ static void named_pipe_recv(struct stream_connection *conn, uint16_t flags) { - struct named_pipe_connection *pipe_conn = talloc_get_type( - conn->private_data, struct named_pipe_connection); - - named_pipe_terminate_connection(pipe_conn, - "named_pipe_recv: called"); + stream_terminate_connection(conn, "named_pipe_recv: called"); } /* @@ -647,11 +280,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_data, struct named_pipe_connection); - - named_pipe_terminate_connection(pipe_conn, - "named_pipe_send: called"); + stream_terminate_connection(conn, "named_pipe_send: called"); } static const struct stream_server_ops named_pipe_stream_ops = { @@ -661,12 +290,12 @@ static const struct stream_server_ops named_pipe_stream_ops = { .send_handler = named_pipe_send, }; -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, - const char *pipe_name, - void *private_data) +NTSTATUS tstream_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, + const char *pipe_name, + void *private_data) { char *dirname; struct named_pipe_socket *pipe_sock; @@ -707,8 +336,8 @@ NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context, talloc_free(dirname); - pipe_sock->ops = stream_ops; - pipe_sock->private_data = talloc_reference(pipe_sock, private_data); + pipe_sock->ops = stream_ops; + pipe_sock->private_data = private_data; status = stream_setup_socket(event_context, lp_ctx, -- cgit