named_pipe_auth: tsocket ...
authorStefan Metzmacher <metze@samba.org>
Thu, 12 Mar 2009 17:10:19 +0000 (18:10 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 2 Apr 2009 15:29:47 +0000 (17:29 +0200)
source4/libcli/config.mk
source4/libcli/named_pipe_auth/config.mk [new file with mode: 0644]
source4/libcli/named_pipe_auth/npa_tsocket.c [new file with mode: 0644]
source4/libcli/named_pipe_auth/npa_tsocket.h [new file with mode: 0644]
source4/smbd/config.mk

index 5b50bdfcbec2a8b793a5b652305bf6f714de25eb..1593d2b612e99e16f4bc65872442bd142d24e6cd 100644 (file)
@@ -2,6 +2,7 @@ mkinclude auth/config.mk
 mkinclude ldap/config.mk
 mkinclude security/config.mk
 mkinclude wbclient/config.mk
+mkinclude named_pipe_auth/config.mk
 
 [SUBSYSTEM::LIBSAMBA-ERRORS]
 
diff --git a/source4/libcli/named_pipe_auth/config.mk b/source4/libcli/named_pipe_auth/config.mk
new file mode 100644 (file)
index 0000000..7146355
--- /dev/null
@@ -0,0 +1,4 @@
+[SUBSYSTEM::TSOCKET_NAMED_PIPE_AUTH]
+PUBLIC_DEPENDENCIES = NDR_NAMED_PIPE_AUTH TEVENT TSOCKET
+
+TSOCKET_NAMED_PIPE_AUTH_OBJ_FILES = $(libclisrcdir)/named_pipe_auth/npa_tsocket.o
diff --git a/source4/libcli/named_pipe_auth/npa_tsocket.c b/source4/libcli/named_pipe_auth/npa_tsocket.c
new file mode 100644 (file)
index 0000000..02fe493
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "../util/tevent_unix.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../lib/tsocket/tsocket_internal.h"
+#include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
+#include "libcli/named_pipe_auth/npa_tsocket.h"
+
+static const struct tsocket_context_ops tsocket_context_npa_ops;
+static const struct tsocket_address_ops tsocket_address_npa_ops;
+
+struct tsocket_context_npa {
+       enum {
+               TSOCKET_CONTEXT_NPA_CLIENT = 1
+       } type;
+       struct tsocket_address *laddr;
+       struct tsocket_address *raddr;
+
+       int status;
+       struct tsocket_context *usock;
+
+       struct tevent_immediate *trigger;
+
+       bool writeable;
+       struct {
+               uint8_t buf[4096];
+               off_t ofs;
+               size_t remain;
+               struct iovec iov;
+       } write;
+
+       bool readable;
+       struct {
+               bool eof;
+               uint8_t buf[4096];
+               off_t ofs;
+               size_t remain;
+       } read;
+};
+
+struct tsocket_address_npa {
+       enum {
+               TSOCKET_ADDRESS_NPA_CLI_LOCAL = 1,
+               TSOCKET_ADDRESS_NPA_CLI_REMOTE
+       } type;
+       union {
+               struct {
+                       const char *directory;
+                       const char *npipe;
+               } cli_remote;
+       } u;
+};
+
+int _tsocket_address_npa_client_local(TALLOC_CTX *mem_ctx,
+                               struct tsocket_address **_addr,
+                               const char *location)
+{
+       struct tsocket_address *addr;
+       struct tsocket_address_npa *npaa;
+
+       addr = tsocket_address_create(mem_ctx,
+                                     &tsocket_address_npa_ops,
+                                     &npaa,
+                                     struct tsocket_address_npa,
+                                     location);
+       if (!addr) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ZERO_STRUCTP(npaa);
+       npaa->type = TSOCKET_ADDRESS_NPA_CLI_LOCAL;
+
+       *_addr = addr;
+       return 0;
+}
+
+int _tsocket_address_npa_client_remote(TALLOC_CTX *mem_ctx,
+                                      const char *directory,
+                                      const char *npipe,
+                                      struct tsocket_address **_addr,
+                                      const char *location)
+{
+       struct tsocket_address *addr;
+       struct tsocket_address_npa *npaa;
+
+       if (!directory || directory[0] == '\0') {
+               errno = ENOTDIR;
+               return -1;
+       }
+
+       if (!npipe || npipe[0] == '\0') {
+               errno = EINVAL;
+               return -1;
+       }
+
+       addr = tsocket_address_create(mem_ctx,
+                                     &tsocket_address_npa_ops,
+                                     &npaa,
+                                     struct tsocket_address_npa,
+                                     location);
+       if (!addr) {
+               goto nomem;
+       }
+
+       ZERO_STRUCTP(npaa);
+
+       npaa->type = TSOCKET_ADDRESS_NPA_CLI_REMOTE;
+       npaa->u.cli_remote.directory = talloc_strdup(npaa, directory);
+       if (!npaa->u.cli_remote.directory) {
+               goto nomem;
+       }
+       npaa->u.cli_remote.npipe = talloc_strdup(npaa, npipe);
+       if (!npaa->u.cli_remote.npipe) {
+               goto nomem;
+       }
+
+       *_addr = addr;
+       return 0;
+nomem:
+       errno = ENOMEM;
+       return -1;
+}
+
+static char *tsocket_address_npa_string(const struct tsocket_address *addr,
+                                       TALLOC_CTX *mem_ctx)
+{
+       struct tsocket_address_npa *npaa = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_npa);
+
+       switch (npaa->type) {
+       case TSOCKET_ADDRESS_NPA_CLI_LOCAL:
+               return talloc_strdup(mem_ctx, "npa:client:local");
+       case TSOCKET_ADDRESS_NPA_CLI_REMOTE:
+               return talloc_asprintf(mem_ctx,
+                                      "npa:client:remote[%s]",
+                                      npaa->u.cli_remote.npipe);
+       }
+
+       return NULL;
+}
+
+static struct tsocket_address *tsocket_address_npa_copy(
+                                       const struct tsocket_address *addr,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *location)
+{
+       struct tsocket_address_npa *npaa = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_npa);
+       struct tsocket_address *copy;
+       int ret = -1;
+
+       switch (npaa->type) {
+       case TSOCKET_ADDRESS_NPA_CLI_LOCAL:
+               ret = _tsocket_address_npa_client_local(mem_ctx,
+                                                       &copy,
+                                                       location);
+               break;
+       case TSOCKET_ADDRESS_NPA_CLI_REMOTE:
+               ret = _tsocket_address_npa_client_remote(mem_ctx,
+                                       npaa->u.cli_remote.directory,
+                                       npaa->u.cli_remote.npipe,
+                                       &copy,
+                                       location);
+               break;
+       default:
+               errno = EINVAL;
+               ret = -1;
+       }
+       if (ret != 0) {
+               return NULL;
+       }
+
+       return copy;
+}
+
+static int tsocket_address_npa_create_socket(const struct tsocket_address *addr,
+                                            enum tsocket_type type,
+                                            TALLOC_CTX *mem_ctx,
+                                            struct tsocket_context **_sock,
+                                            const char *location)
+{
+       struct tsocket_address_npa *npaa = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_npa);
+       struct tsocket_context *sock = NULL;
+       struct tsocket_context_npa *npas;
+       struct tsocket_address *unix_addr;
+       int ret;
+       int tmp_errno;
+
+       if (npaa->type != TSOCKET_ADDRESS_NPA_CLI_LOCAL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /*
+        * the client can only ask for STREAM,
+        * while the server can also choose MESSAGE.
+        */
+       switch (type) {
+       case TSOCKET_TYPE_STREAM:
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return -1;
+       }
+
+       sock = tsocket_context_create(mem_ctx,
+                                     &tsocket_context_npa_ops,
+                                     &npas,
+                                     struct tsocket_context_npa,
+                                     location);
+       if (!sock) {
+               goto nomem;
+       }
+
+       npas->writeable = false;
+       ZERO_STRUCT(npas->write);
+       npas->readable = false;
+       ZERO_STRUCT(npas->read);
+
+       npas->trigger = tevent_create_immediate(npas);
+       if (!npas->trigger) {
+               goto nomem;
+       }
+
+       npas->laddr = tsocket_address_copy(addr, npas);
+       if (!npas->laddr) {
+               goto nomem;
+       }
+       npas->raddr = NULL;
+       npas->status = ENOTCONN;
+
+       ret = tsocket_address_unix_from_path(npas, "", &unix_addr);
+       if (ret != 0) {
+               goto failed;
+       }
+
+       ret = tsocket_address_create_socket(unix_addr,
+                                           TSOCKET_TYPE_STREAM,
+                                           npas, &npas->usock);
+       if (ret != 0) {
+               goto failed;
+       }
+       talloc_free(unix_addr);
+
+       *_sock = sock;
+       return 0;
+nomem:
+       errno = ENOMEM;
+failed:
+       tmp_errno = errno;
+       talloc_free(sock);
+       errno = tmp_errno;
+       return -1;
+}
+
+static const struct tsocket_address_ops tsocket_address_npa_ops = {
+       .name           = "npa",
+       .string         = tsocket_address_npa_string,
+       .copy           = tsocket_address_npa_copy,
+       .create_socket  = tsocket_address_npa_create_socket
+};
+
+static int tsocket_context_npa_set_event_context(struct tsocket_context *sock,
+                                                struct tevent_context *ev)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+
+       tevent_schedule_immediate(npas->trigger, NULL, NULL, NULL);
+       ZERO_STRUCT(sock->event);
+
+       if (!ev) {
+               return 0;
+       }
+
+       sock->event.ctx = ev;
+
+       return 0;
+}
+
+static void tsocket_context_npa_schedule_event(struct tsocket_context *sock);
+
+static void tsocket_context_npa_trigger_event(struct tevent_context *ev,
+                                             struct tevent_immediate *im,
+                                             void *private_data)
+{
+       struct tsocket_context *sock = talloc_get_type(private_data,
+                                      struct tsocket_context);
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+
+       if (npas->writeable && sock->event.write_handler) {
+               sock->event.write_handler(sock, sock->event.write_private);
+               goto done;
+       }
+
+       if (npas->readable && sock->event.read_handler) {
+               sock->event.read_handler(sock, sock->event.read_private);
+               goto done;
+       }
+
+done:
+       /* maybe reschedule */
+       tsocket_context_npa_schedule_event(sock);
+}
+
+static void tsocket_context_npa_schedule_event(struct tsocket_context *sock)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       bool trigger = false;
+
+       if (npas->readable && sock->event.read_handler) {
+               trigger = true;
+       }
+
+       if (npas->writeable && sock->event.write_handler) {
+               trigger = true;
+       }
+
+       if (trigger) {
+               tevent_schedule_immediate(npas->trigger, sock->event.ctx,
+                                         tsocket_context_npa_trigger_event,
+                                         sock);
+       }
+}
+
+static int tsocket_context_npa_set_read_handler(struct tsocket_context *sock,
+                                               tsocket_event_handler_t handler,
+                                               void *private_data)
+{
+       sock->event.read_handler = handler;
+       sock->event.read_private = private_data;
+
+       tsocket_context_npa_schedule_event(sock);
+       return 0;
+}
+
+static int tsocket_context_npa_set_write_handler(struct tsocket_context *sock,
+                                                tsocket_event_handler_t handler,
+                                                void *private_data)
+{
+       sock->event.write_handler = handler;
+       sock->event.write_private = private_data;
+
+       tsocket_context_npa_schedule_event(sock);
+       return 0;
+}
+
+static struct tevent_req *tsocket_npa_connect_send(struct tsocket_context *sock,
+                                       const struct tsocket_address *remote);
+static void tsocket_connect_npa_done(struct tevent_req *subreq);
+
+static int tsocket_context_npa_connect_to(struct tsocket_context *sock,
+                                         const struct tsocket_address *remote)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct tsocket_address_npa *npaa = talloc_get_type(remote->private_data,
+                                          struct tsocket_address_npa);
+       struct tevent_req *req;
+
+       if (!npaa) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (npaa->type != TSOCKET_ADDRESS_NPA_CLI_REMOTE) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (npas->type != TSOCKET_CONTEXT_NPA_CLIENT) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (npas->status == EINPROGRESS) {
+               errno = EALREADY;
+               return -1;
+       }
+
+       if (npas->status != ENOTCONN) {
+               errno = npas->status;
+               return -1;
+       }
+
+       req = tsocket_npa_connect_send(sock, remote);
+       if (!req) {
+               return -1;
+       }
+       tevent_req_set_callback(req, tsocket_connect_npa_done, sock);
+
+       /* the connect is on its way */
+       npas->status = EINPROGRESS;
+       errno = EINPROGRESS;
+       return -1;
+}
+
+struct tsocket_npa_connect_state {
+       struct tsocket_context *sock;
+       const char *unix_path;
+       struct tsocket_address *unix_addr;
+       struct tsocket_address *raddr;
+
+       struct named_pipe_auth_req auth_req;
+       DATA_BLOB auth_req_blob;
+       struct iovec auth_req_iov;
+
+       struct named_pipe_auth_rep auth_rep;
+       uint8_t auth_rep_buf[20];
+       uint32_t auth_rep_remain;
+       DATA_BLOB auth_rep_blob;
+};
+
+static void tsocket_npa_connect_unix_done(struct tevent_req *subreq);
+
+static struct tevent_req *tsocket_npa_connect_send(struct tsocket_context *sock,
+                                       const struct tsocket_address *remote)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct tsocket_address_npa *npaa = talloc_get_type(remote->private_data,
+                                          struct tsocket_address_npa);
+       struct tevent_req *req, *subreq;
+       struct tsocket_npa_connect_state *state;
+       int ret;
+       enum ndr_err_code ndr_err;
+
+       req = tevent_req_create(npas, &state, struct tsocket_npa_connect_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->unix_path = talloc_asprintf(state, "%s/%s",
+                                          npaa->u.cli_remote.directory,
+                                          npaa->u.cli_remote.npipe);
+       if (tevent_req_nomem(state->unix_path, req)) {
+               goto post;
+       }
+
+       ret = tsocket_address_unix_from_path(state,
+                                            state->unix_path,
+                                            &state->unix_addr);
+       if (ret != 0) {
+               tevent_req_error(req, errno);
+               goto post;
+       }
+
+       state->raddr = tsocket_address_copy(remote, state);
+       if (tevent_req_nomem(state->raddr, req)) {
+               goto post;
+       }
+
+       /* we send no Info3 yet */
+       state->auth_req.level = 0;
+
+       ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
+                       state, NULL, &state->auth_req,
+                       (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               tevent_req_error(req, EINVAL);
+               goto post;
+       }
+
+       state->auth_req_iov.iov_base = state->auth_req_blob.data;
+       state->auth_req_iov.iov_len = state->auth_req_blob.length;
+
+       subreq = tsocket_connect_send(npas->usock, state, state->unix_addr);
+       if (tevent_req_nomem(subreq, req)) {
+               goto post;
+       }
+       tevent_req_set_callback(subreq, tsocket_npa_connect_unix_done, state);
+
+       return req;
+post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_npa_connect_writev_done(struct tevent_req *subreq);
+
+static void tsocket_npa_connect_unix_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct tsocket_npa_connect_state *state =
+               tevent_req_data(req,
+               struct tsocket_npa_connect_state);
+       struct tsocket_context_npa *npas =
+               talloc_get_type(state->sock->private_data,
+               struct tsocket_context_npa);
+       int ret;
+       int sys_errno;
+
+       ret = tsocket_connect_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret != 0) {
+               tevent_req_error(req, sys_errno);
+               return;
+       }
+
+       subreq = tsocket_writev_send(npas->usock, state,
+                                    &state->auth_req_iov, 1);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, tsocket_npa_connect_writev_done, state);
+}
+
+static int tsocket_npa_connect_readv_callback(struct tsocket_context *sock,
+                                             void *private_data,
+                                             TALLOC_CTX *mem_ctx,
+                                             struct iovec **_vector,
+                                             size_t *_count)
+{
+       struct tevent_req *req =
+               talloc_get_type(private_data,
+               struct tevent_req);
+       struct tsocket_npa_connect_state *state =
+               tevent_req_data(req,
+               struct tsocket_npa_connect_state);
+       struct iovec *vector;
+       size_t count = 1;
+
+       if (state->auth_rep_remain == 0) {
+               *_vector = NULL;
+               *_count = 0;
+               return 0;
+       }
+
+       vector = talloc_array(mem_ctx, struct iovec, count);
+       if (!vector) {
+               return -1;
+       }
+
+       vector[0].iov_base = state->auth_rep_buf;
+       vector[0].iov_len = sizeof(state->auth_rep_buf);
+
+       state->auth_rep_remain = 0;
+
+       *_vector = vector;
+       *_count = count;
+       return 0;
+}
+
+static void tsocket_npa_connect_readv_done(struct tevent_req *subreq);
+
+static void tsocket_npa_connect_writev_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct tsocket_npa_connect_state *state =
+               tevent_req_data(req,
+               struct tsocket_npa_connect_state);
+       struct tsocket_context_npa *npas =
+               talloc_get_type(state->sock->private_data,
+               struct tsocket_context_npa);
+       int ret;
+       int sys_errno;
+
+       ret = tsocket_writev_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               tevent_req_error(req, sys_errno);
+               return;
+       }
+
+       state->auth_rep_remain = sizeof(state->auth_rep_buf);
+       subreq = tsocket_readv_send(npas->usock, state,
+                                   tsocket_npa_connect_readv_callback,
+                                   state);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, tsocket_npa_connect_readv_done, state);
+}
+
+static void tsocket_npa_connect_readv_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct tsocket_npa_connect_state *state =
+               tevent_req_data(req,
+               struct tsocket_npa_connect_state);
+       int ret;
+       int sys_errno;
+       enum ndr_err_code ndr_err;
+
+       ret = tsocket_readv_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               tevent_req_error(req, sys_errno);
+               return;
+       }
+
+       state->auth_rep_blob = data_blob_const(state->auth_rep_buf,
+                                              sizeof(state->auth_rep_buf));
+
+       DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
+                (uint32_t)state->auth_rep_blob.length));
+       dump_data(10, state->auth_rep_blob.data, state->auth_rep_blob.length);
+
+       ndr_err = ndr_pull_struct_blob(
+               &state->auth_rep_blob, state, NULL, &state->auth_rep,
+               (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
+
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
+                         "ndr_error"));//ndr_errstr(ndr_err)));
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       if (state->auth_rep.length != 16) {
+               DEBUG(0, ("req invalid length: %u != 16\n",
+                         state->auth_req.length));
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
+               DEBUG(0, ("req invalid magic: %s != %s\n",
+                         state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
+               DEBUG(0, ("req failed: %s\n",
+                         nt_errstr(state->auth_rep.status)));
+               tevent_req_error(req, EACCES);
+               return;
+       }
+
+       if (state->auth_rep.level != 1) {
+               DEBUG(0, ("req invalid level: %u != 1\n",
+                         state->auth_rep.level));
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static int tsocket_npa_connect_recv(struct tevent_req *req,
+                                   int *perrno,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct tsocket_address **raddr)
+{
+       struct tsocket_npa_connect_state *state =
+               tevent_req_data(req,
+               struct tsocket_npa_connect_state);
+
+       if (tevent_req_is_unix_error(req, perrno)) {
+               tevent_req_received(req);
+               return -1;
+       }
+
+       *raddr = talloc_move(mem_ctx, &state->raddr);
+       tevent_req_received(req);
+       return 0;
+}
+
+static void tsocket_connect_npa_done(struct tevent_req *subreq)
+{
+       struct tsocket_context *sock =
+               tevent_req_callback_data(subreq,
+               struct tsocket_context);
+       struct tsocket_context_npa *npas =
+               talloc_get_type(sock->private_data,
+               struct tsocket_context_npa);
+       int ret;
+       int sys_errno;
+
+       ret = tsocket_npa_connect_recv(subreq, &sys_errno,
+                                      npas, &npas->raddr);
+       talloc_free(subreq);
+       if (ret != 0) {
+               npas->status = sys_errno;
+               npas->readable = true;
+               tsocket_context_npa_schedule_event(sock);
+               return;
+       }
+
+       npas->status = 0;
+       npas->writeable = true;
+       npas->readable = true;
+       tsocket_context_npa_schedule_event(sock);
+}
+
+static int tsocket_context_npa_listen_on(struct tsocket_context *sock,
+                                        int queue_size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+static int tsocket_context_npa_accept_new(struct tsocket_context *sock,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct tsocket_context **_new_sock,
+                                         const char *location)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+static ssize_t tsocket_context_npa_pending_data(struct tsocket_context *sock)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+
+       if (npas->status != 0) {
+               errno = npas->status;
+               return -1;
+       }
+
+       return npas->read.remain;
+}
+
+static int tsocket_npa_readv_callback(struct tsocket_context *usock,
+                                     void *private_data,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct iovec **_vector,
+                                     size_t *_count)
+{
+       struct tsocket_context *sock =
+               talloc_get_type(private_data,
+               struct tsocket_context);
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct iovec *vector;
+       size_t count = 1;
+       ssize_t pending;
+
+       errno = ENOSYS;
+       return -1;
+
+       if (npas->read.ofs == sizeof(npas->read.buf)) {
+               *_vector = NULL;
+               *_count = 0;
+               return 0;
+       }
+
+       vector = talloc_array(mem_ctx, struct iovec, count);
+       if (!vector) {
+               return -1;
+       }
+
+       pending = tsocket_pending(npas->usock);
+       if (pending < 0) {
+               return pending;
+       }
+//TODO: fix the logic...
+       npas->read.ofs = MAX(pending, 1);
+
+       vector[0].iov_base = npas->read.buf;
+       vector[0].iov_len = npas->read.ofs;
+
+       *_vector = vector;
+       *_count = count;
+       return 0;
+}
+
+static void tsocket_context_npa_readv_done(struct tevent_req *subreq);
+
+static int tsocket_context_npa_readv_data(struct tsocket_context *sock,
+                                         const struct iovec *vector,
+                                         size_t count)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct tevent_req *subreq;
+       size_t i;
+       int ret = 0;
+
+       /* return 0 as eof only once and then an error */
+       if (npas->read.eof) {
+               npas->read.eof = false;
+               return 0;
+       }
+
+       if (npas->status != 0) {
+               errno = npas->status;
+               return -1;
+       }
+
+       if (npas->read.remain == 0) {
+               errno = EAGAIN;
+               return -1;
+       }
+
+       for (i=0; i < count; i++) {
+               size_t len;
+
+               if (vector[i].iov_len == 0) {
+                       continue;
+               }
+
+               len = MIN(vector[i].iov_len, npas->read.remain);
+
+               if (len == 0) {
+                       break;
+               }
+
+               memcpy(vector[i].iov_base,
+                      npas->read.buf + npas->read.ofs,
+                      len);
+
+               ret += len;
+               npas->read.ofs += len;
+               npas->read.remain -= len;
+       }
+
+       /* memmove ...*/
+       if (npas->read.remain > 0) {
+               return ret;
+       }
+
+       npas->readable = false;
+
+       subreq = tsocket_readv_send(npas->usock, npas,
+                                   tsocket_npa_readv_callback,
+                                   sock);
+       if (!subreq) {
+               /* we report the error async */
+               tsocket_disconnect(npas->usock);
+               npas->status = ENOMEM;
+               npas->readable = true;
+               tsocket_context_npa_schedule_event(sock);
+
+               /* don't return an error here */
+               return ret;
+       }
+       tevent_req_set_callback(subreq, tsocket_context_npa_readv_done, sock);
+
+       return ret;
+}
+
+static void tsocket_context_npa_readv_done(struct tevent_req *subreq)
+{
+       struct tsocket_context *sock =
+               tevent_req_callback_data(subreq,
+               struct tsocket_context);
+       struct tsocket_context_npa *npas =
+               talloc_get_type(sock->private_data,
+               struct tsocket_context_npa);
+       int ret;
+       int sys_errno;
+
+       ret = tsocket_readv_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               npas->status = sys_errno;
+               npas->readable = true;
+               tsocket_context_npa_schedule_event(sock);
+               return;
+       }
+
+       npas->readable = true;
+       tsocket_context_npa_schedule_event(sock);
+
+}
+
+static void tsocket_context_npa_writev_done(struct tevent_req *subreq);
+
+static int tsocket_context_npa_writev_data(struct tsocket_context *sock,
+                                          const struct iovec *vector,
+                                          size_t count)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct tevent_req *subreq;
+       size_t i;
+       int ret = 0;
+
+       if (npas->status != 0) {
+               errno = npas->status;
+               return -1;
+       }
+
+       if (npas->write.ofs > 0) {
+               errno = EAGAIN;
+               return -1;
+       }
+
+       for (i=0; i < count; i++) {
+               size_t len;
+
+               if (vector[i].iov_len == 0) {
+                       continue;
+               }
+
+               len = MIN(vector[i].iov_len, npas->write.remain);
+
+               if (len == 0) {
+                       break;
+               }
+
+               memcpy(npas->write.buf + npas->write.ofs,
+                      vector[i].iov_base,
+                      len);
+
+               ret += len;
+               npas->write.ofs += len;
+       }
+
+       /* memmove ...*/
+       if (npas->read.ofs == 0) {
+               return 0;
+       }
+
+       npas->write.iov.iov_base = npas->write.buf;
+       npas->write.iov.iov_len = npas->write.ofs;
+
+       subreq = tsocket_writev_send(npas->usock, npas,
+                                    &npas->write.iov, 1);
+       if (!subreq) {
+               npas->write.ofs = 0;
+               errno = ENOMEM;
+               return -1;
+       }
+       tevent_req_set_callback(subreq, tsocket_context_npa_writev_done, sock);
+
+       npas->writeable = false;
+       return ret;
+}
+
+static void tsocket_context_npa_writev_done(struct tevent_req *subreq)
+{
+       struct tsocket_context *sock =
+               tevent_req_callback_data(subreq,
+               struct tsocket_context);
+       struct tsocket_context_npa *npas =
+               talloc_get_type(sock->private_data,
+               struct tsocket_context_npa);
+       int ret;
+       int sys_errno;
+
+       ret = tsocket_writev_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               npas->status = sys_errno;
+               npas->readable = true;
+               tsocket_context_npa_schedule_event(sock);
+               return;
+       }
+
+       npas->write.ofs = 0;
+       npas->writeable = true;
+       tsocket_context_npa_schedule_event(sock);
+}
+
+static ssize_t tsocket_context_npa_recvfrom_data(struct tsocket_context *sock,
+                                                uint8_t *data, size_t len,
+                                                TALLOC_CTX *addr_ctx,
+                                                struct tsocket_address **remote)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+static ssize_t tsocket_context_npa_sendto_data(struct tsocket_context *sock,
+                                              const uint8_t *data, size_t len,
+                                              const struct tsocket_address *remote)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+static int tsocket_context_npa_get_status(const struct tsocket_context *sock)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       return npas->status;
+}
+
+static int tsocket_context_npa_get_local_address(const struct tsocket_context *sock,
+                                                TALLOC_CTX *mem_ctx,
+                                                struct tsocket_address **_addr,
+                                                const char *location)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct tsocket_address *addr;
+
+       addr = _tsocket_address_copy(npas->laddr, mem_ctx, location);
+       if (!addr) {
+               return -1;
+       }
+
+       *_addr = addr;
+       return 0;
+}
+
+static int tsocket_context_npa_get_remote_address(const struct tsocket_context *sock,
+                                                 TALLOC_CTX *mem_ctx,
+                                                 struct tsocket_address **_addr,
+                                                 const char *location)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+       struct tsocket_address *addr;
+
+       if (!npas->raddr) {
+               errno = ENOTCONN;
+               return -1;
+       }
+
+       addr = _tsocket_address_copy(npas->raddr, mem_ctx, location);
+       if (!addr) {
+               return -1;
+       }
+
+       *_addr = addr;
+       return 0;
+}
+
+static int tsocket_context_npa_get_option(const struct tsocket_context *sock,
+                                         const char *option,
+                                         TALLOC_CTX *mem_ctx,
+                                         char **_value)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+static int tsocket_context_npa_set_option(const struct tsocket_context *sock,
+                                         const char *option,
+                                         bool force,
+                                         const char *value)
+{
+       if (!force) {
+               return 0;
+       }
+
+       errno = ENOSYS;
+       return -1;
+}
+
+static void tsocket_context_npa_disconnect(struct tsocket_context *sock)
+{
+       struct tsocket_context_npa *npas = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_npa);
+
+       tsocket_context_npa_set_event_context(sock, NULL);
+
+       if (npas->usock) {
+               tsocket_disconnect(npas->usock);
+       }
+}
+
+static const struct tsocket_context_ops tsocket_context_npa_ops = {
+       .name                   = "nap",
+
+       .set_event_context      = tsocket_context_npa_set_event_context,
+       .set_read_handler       = tsocket_context_npa_set_read_handler,
+       .set_write_handler      = tsocket_context_npa_set_write_handler,
+
+       .connect_to             = tsocket_context_npa_connect_to,
+       .listen_on              = tsocket_context_npa_listen_on,
+       .accept_new             = tsocket_context_npa_accept_new,
+
+       .pending_data           = tsocket_context_npa_pending_data,
+       .readv_data             = tsocket_context_npa_readv_data,
+       .writev_data            = tsocket_context_npa_writev_data,
+       .recvfrom_data          = tsocket_context_npa_recvfrom_data,
+       .sendto_data            = tsocket_context_npa_sendto_data,
+
+       .get_status             = tsocket_context_npa_get_status,
+       .get_local_address      = tsocket_context_npa_get_local_address,
+       .get_remote_address     = tsocket_context_npa_get_remote_address,
+
+       .get_option             = tsocket_context_npa_get_option,
+       .set_option             = tsocket_context_npa_set_option,
+
+       .disconnect             = tsocket_context_npa_disconnect
+};
+
diff --git a/source4/libcli/named_pipe_auth/npa_tsocket.h b/source4/libcli/named_pipe_auth/npa_tsocket.h
new file mode 100644 (file)
index 0000000..baaabf7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NPA_TSOCKET_H
+#define NPA_TSOCKET_H
+
+struct tsocket_address;
+
+int _tsocket_address_npa_client_local(TALLOC_CTX *mem_ctx,
+                               struct tsocket_address **_addr,
+                               const char *location);
+#define tsocket_address_npa_client_local(mem_ctx, _addr) \
+       _tsocket_address_npa_client_local(mem_ctx, _addr, \
+                                         __location__)
+
+int _tsocket_address_npa_client_remote(TALLOC_CTX *mem_ctx,
+                                      const char *directory,
+                                      const char *npipe,
+                                      struct tsocket_address **_addr,
+                                      const char *location);
+#define tsocket_address_npa_client_remote(mem_ctx, directory, npipe, _addr) \
+       _tsocket_address_npa_client_remote(mem_ctx, directory, npipe, _addr, \
+                                          __location__)
+
+#endif /* NPA_TSOCKET_H */
index a76d10cbe721e9c274667ae03a6cfa538ab72c46..77f9f24bf112293cd47380b5f57d80cf96b710d6 100644 (file)
@@ -2,7 +2,7 @@
 
 [SUBSYSTEM::service]
 PRIVATE_DEPENDENCIES = \
-               LIBTEVENT MESSAGING samba_socket NDR_NAMED_PIPE_AUTH
+               LIBTEVENT MESSAGING samba_socket NDR_NAMED_PIPE_AUTH TSOCKET_NAMED_PIPE_AUTH
 
 service_OBJ_FILES = $(addprefix $(smbdsrcdir)/, \
                service.o \