[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed May 26 02:16:47 MDT 2010


The branch, master has been updated
       via  3c8dc5c... s4:smbd: Use tstream_npa_accept_existing to accept named pipe connections
       via  2e17123... s4:smbd: Add tstream to the stream_connection structure
       via  b7159e6... named_pipe_auth: implement tstream_npa_accept_existing_send/recv
      from  9e194cd... s3-waf: Check for additional options on *xattr

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 3c8dc5cd214c58747bfbbd72a8d05fc50454585a
Author: Simo Sorce <ssorce at redhat.com>
Date:   Fri May 21 12:29:22 2010 -0400

    s4:smbd: Use tstream_npa_accept_existing to accept named pipe connections
    
    Pair-programmed-with: Stefan Metzmacher <metze at samba.org>

commit 2e171239f9abbadae0363818ce730df8f0eaada2
Author: Simo Sorce <ssorce at redhat.com>
Date:   Fri May 21 10:34:58 2010 -0400

    s4:smbd: Add tstream to the stream_connection structure

commit b7159e6ffd9f2c907301ce4d3e6ba3ff01c8a1f6
Author: Simo Sorce <ssorce at redhat.com>
Date:   Wed May 19 17:02:52 2010 -0400

    named_pipe_auth: implement tstream_npa_accept_existing_send/recv
    
    Pair-programmed-with: Stefan Metzmacher <metze at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 libcli/named_pipe_auth/npa_tstream.c |  455 ++++++++++++++++++++++
 libcli/named_pipe_auth/npa_tstream.h |   66 ++++
 source4/rpc_server/service_rpc.c     |   28 +-
 source4/smbd/service_named_pipe.c    |  693 ++++++++--------------------------
 source4/smbd/service_stream.h        |    1 +
 5 files changed, 697 insertions(+), 546 deletions(-)


Changeset truncated at 500 lines:

diff --git a/libcli/named_pipe_auth/npa_tstream.c b/libcli/named_pipe_auth/npa_tstream.c
index 20228a2..0834c7d 100644
--- a/libcli/named_pipe_auth/npa_tstream.c
+++ b/libcli/named_pipe_auth/npa_tstream.c
@@ -1077,3 +1077,458 @@ int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
 	return 0;
 }
 
+
+struct tstream_npa_accept_state {
+	struct tevent_context *ev;
+	struct tstream_context *plain;
+	uint16_t file_type;
+	uint16_t device_state;
+	uint64_t alloc_size;
+
+	DATA_BLOB npa_blob;
+	struct iovec out_iov;
+
+	/* results */
+	NTSTATUS accept_status;
+	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;
+};
+
+static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
+					  void *private_data,
+					  TALLOC_CTX *mem_ctx,
+					  struct iovec **_vector,
+					  size_t *_count);
+static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
+static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct tstream_context *plain,
+					uint16_t file_type,
+					uint16_t device_state,
+					uint64_t allocation_size)
+{
+	struct tstream_npa_accept_state *state;
+	struct tevent_req *req, *subreq;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct tstream_npa_accept_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	switch (file_type) {
+	case FILE_TYPE_BYTE_MODE_PIPE:
+		break;
+	case FILE_TYPE_MESSAGE_MODE_PIPE:
+		break;
+	default:
+		tevent_req_error(req, EINVAL);
+		goto post;
+	}
+
+	ZERO_STRUCTP(state);
+
+	state->ev = ev;
+	state->plain = plain;
+	state->file_type = file_type;
+	state->device_state = device_state;
+	state->alloc_size = allocation_size;
+
+	/*
+	 * 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_readv_pdu_send(state, ev, plain,
+					tstream_npa_accept_next_vector,
+					state);
+	if (tevent_req_nomem(subreq, req)) {
+		goto post;
+	}
+
+	tevent_req_set_callback(subreq,
+				tstream_npa_accept_existing_reply, req);
+
+	return req;
+
+post:
+	tevent_req_post(req, ev);
+	return req;
+}
+
+static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
+					  void *private_data,
+					  TALLOC_CTX *mem_ctx,
+					  struct iovec **_vector,
+					  size_t *_count)
+{
+	struct tstream_npa_accept_state *state =
+		talloc_get_type_abort(private_data,
+					struct tstream_npa_accept_state);
+	struct iovec *vector;
+	size_t count;
+	off_t ofs = 0;
+
+	if (state->npa_blob.length == 0) {
+		state->npa_blob = data_blob_talloc(state, NULL, 4);
+		if (!state->npa_blob.data) {
+			return -1;
+		}
+	} else if (state->npa_blob.length == 4) {
+		uint32_t msg_len;
+
+		ofs = 4;
+
+		msg_len = RIVAL(state->npa_blob.data, 0);
+
+		if (msg_len > 0x00FFFFFF) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		if (msg_len == 0) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		msg_len += ofs;
+
+		state->npa_blob.data = talloc_realloc(state,
+						      state->npa_blob.data,
+						      uint8_t, msg_len);
+		if (!state->npa_blob.data) {
+			return -1;
+		}
+		state->npa_blob.length = msg_len;
+	} else {
+		if (memcmp(&state->npa_blob.data[4],
+			   NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
+			DEBUG(0, ("Wrong protocol\n"));
+#if defined(EPROTONOSUPPORT)
+			errno = EPROTONOSUPPORT;
+#elif defined(EPROTO)
+			errno = EPROTO;
+#else
+			errno = EINVAL;
+#endif
+			return -1;
+		}
+		*_vector = NULL;
+		*_count = 0;
+		return 0;
+	}
+
+	/* we need to get a message header */
+	vector = talloc_array(mem_ctx, struct iovec, 1);
+	if (!vector) {
+		return -1;
+	}
+	vector[0].iov_base = state->npa_blob.data + ofs;
+	vector[0].iov_len = state->npa_blob.length - ofs;
+	count = 1;
+
+	*_vector = vector;
+	*_count = count;
+	return 0;
+}
+
+static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+			tevent_req_callback_data(subreq, struct tevent_req);
+	struct tstream_npa_accept_state *state =
+			tevent_req_data(req, struct tstream_npa_accept_state);
+	struct named_pipe_auth_req *pipe_request;
+	struct named_pipe_auth_rep pipe_reply;
+	struct named_pipe_auth_req_info3 i3;
+	enum ndr_err_code ndr_err;
+	DATA_BLOB out;
+	int sys_errno;
+	int ret;
+
+	ret = tstream_readv_pdu_recv(subreq, &sys_errno);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, sys_errno);
+		return;
+	}
+
+	DEBUG(10, ("Received packet of length %lu\n",
+		   (long)state->npa_blob.length));
+	dump_data(11, state->npa_blob.data, state->npa_blob.length);
+
+	ZERO_STRUCT(pipe_reply);
+	pipe_reply.level = 0;
+	pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
+	/*
+	 * TODO: check it's a root (uid == 0) pipe
+	 */
+
+	pipe_request = talloc(state, struct named_pipe_auth_req);
+	if (!pipe_request) {
+		DEBUG(0, ("Out of memory!\n"));
+		goto reply;
+	}
+
+	/* parse the passed credentials */
+	ndr_err = ndr_pull_struct_blob_all(
+			&state->npa_blob, pipe_request, 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);
+	}
+
+	ZERO_STRUCT(i3);
+
+	switch (pipe_request->level) {
+	case 0:
+		pipe_reply.level = 0;
+		pipe_reply.status = NT_STATUS_OK;
+
+		/* we need to force byte mode in this level */
+		state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
+		break;
+
+	case 1:
+		pipe_reply.level = 1;
+		pipe_reply.status = NT_STATUS_OK;
+
+		/* We must copy net3_SamInfo3, so that
+		 * info3 is an actual talloc pointer, then we steal
+		 * pipe_request on info3 so that all the allocated memory
+		 * pointed by the structrue members is preserved */
+		state->info3 = (struct netr_SamInfo3 *)talloc_memdup(state,
+						&pipe_request->info.info1,
+						sizeof(struct netr_SamInfo3));
+		if (!state->info3) {
+			pipe_reply.status = NT_STATUS_NO_MEMORY;
+			DEBUG(0, ("Out of memory!\n"));
+			goto reply;
+		}
+		talloc_move(state->info3, &pipe_request);
+
+		/* we need to force byte mode in this level */
+		state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
+		break;
+
+	case 2:
+		pipe_reply.level = 2;
+		pipe_reply.status = NT_STATUS_OK;
+		pipe_reply.info.info2.file_type = state->file_type;
+		pipe_reply.info.info2.device_state = state->device_state;
+		pipe_reply.info.info2.allocation_size = state->alloc_size;
+
+		i3.client_name = pipe_request->info.info2.client_name;
+		i3.client_addr = pipe_request->info.info2.client_addr;
+		i3.client_port = pipe_request->info.info2.client_port;
+		i3.server_name = pipe_request->info.info2.server_name;
+		i3.server_addr = pipe_request->info.info2.server_addr;
+		i3.server_port = pipe_request->info.info2.server_port;
+		i3.sam_info3 = pipe_request->info.info2.sam_info3;
+		i3.session_key_length =
+				pipe_request->info.info2.session_key_length;
+		i3.session_key = pipe_request->info.info2.session_key;
+		break;
+
+	case 3:
+		pipe_reply.level = 3;
+		pipe_reply.status = NT_STATUS_OK;
+		pipe_reply.info.info3.file_type = state->file_type;
+		pipe_reply.info.info3.device_state = state->device_state;
+		pipe_reply.info.info3.allocation_size = state->alloc_size;
+
+		i3 = pipe_request->info.info3;
+		break;
+
+	default:
+		DEBUG(0, ("Unknown level %u\n", pipe_request->level));
+		pipe_reply.level = 0;
+		pipe_reply.status = NT_STATUS_INVALID_LEVEL;
+		goto reply;
+	}
+
+	if (pipe_reply.level >=2) {
+
+		if (i3.server_addr == NULL) {
+			pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+			DEBUG(2, ("Missing server address\n"));
+			goto reply;
+		}
+		if (i3.client_addr == NULL) {
+			pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+			DEBUG(2, ("Missing client address\n"));
+			goto reply;
+		}
+
+		state->server_name = discard_const_p(char,
+					talloc_move(state, &i3.server_name));
+		ret = tsocket_address_inet_from_strings(state, "ip",
+							i3.server_addr,
+							i3.server_port,
+							&state->server);
+		if (ret != 0) {
+			DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
+				  i3.server_addr, i3.server_port,
+				  strerror(errno)));
+			pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+			goto reply;
+		}
+
+		state->client_name = discard_const_p(char,
+					talloc_move(state, &i3.client_name));
+		ret = tsocket_address_inet_from_strings(state, "ip",
+							i3.client_addr,
+							i3.client_port,
+							&state->client);
+		if (ret != 0) {
+			DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
+				  i3.client_addr, i3.client_port,
+				  strerror(errno)));
+			pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+			goto reply;
+		}
+
+		state->info3 = talloc_move(state, &i3.sam_info3);
+		state->session_key.data = talloc_move(state, &i3.session_key);
+		state->session_key.length = i3.session_key_length;
+	}
+
+	if (pipe_reply.level >= 3) {
+		state->delegated_creds.data =
+			talloc_move(state, &i3.gssapi_delegated_creds);
+		state->delegated_creds.length =
+			i3.gssapi_delegated_creds_length;
+	}
+
+reply:
+	/* create the output */
+	ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
+			(ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DEBUG(2, ("Error encoding structure: %s",
+			  ndr_map_error2string(ndr_err)));
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
+	dump_data(11, out.data, out.length);
+
+	if (DEBUGLVL(10)) {
+		NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
+	}
+
+	state->accept_status = pipe_reply.status;
+
+	state->out_iov.iov_base = out.data;
+	state->out_iov.iov_len = out.length;
+
+	subreq = tstream_writev_send(state, state->ev,
+				     state->plain,
+				     &state->out_iov, 1);
+	if (tevent_req_nomem(subreq, req)) {
+		DEBUG(0, ("no memory for tstream_writev_send"));
+		return;
+	}
+
+	tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
+}
+
+static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+			tevent_req_callback_data(subreq, struct tevent_req);
+	int sys_errno;
+	int ret;
+
+	ret = tstream_writev_recv(subreq, &sys_errno);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_error(req, sys_errno);
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+int _tstream_npa_accept_existing_recv(struct tevent_req *req,
+				      int *perrno,
+				      TALLOC_CTX *mem_ctx,
+				      struct tstream_context **stream,
+				      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,
+				      const char *location)
+{
+	struct tstream_npa_accept_state *state =
+			tevent_req_data(req, struct tstream_npa_accept_state);
+	struct tstream_npa *npas;
+	int ret;
+
+	ret = tsocket_simple_int_recv(req, perrno);
+	if (ret != 0) {
+		DEBUG(2, ("Failed to accept named pipe conection: %s\n",
+			  strerror(*perrno)));
+		tevent_req_received(req);
+		return -1;
+	}
+
+	if (!NT_STATUS_IS_OK(state->accept_status)) {
+#if defined(EPROTONOSUPPORT)
+		*perrno = EPROTONOSUPPORT;
+#elif defined(EPROTO)
+		*perrno = EPROTO;
+#else
+		*perrno = EINVAL;
+#endif
+		DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
+			  nt_errstr(state->accept_status),
+			  strerror(*perrno)));
+		tevent_req_received(req);
+		return -1;
+	}
+
+	*stream = tstream_context_create(mem_ctx,
+					 &tstream_npa_ops,
+					 &npas,
+					 struct tstream_npa,
+					 location);
+	if (!*stream) {
+		*perrno = ENOMEM;
+		tevent_req_received(req);
+		return -1;
+	}
+	ZERO_STRUCTP(npas);
+	npas->unix_stream = state->plain;
+	npas->file_type = state->file_type;
+
+	*client = talloc_move(mem_ctx, &state->client);
+	*_client_name = talloc_move(mem_ctx, &state->client_name);
+	*server = talloc_move(mem_ctx, &state->server);
+	*server_name = talloc_move(mem_ctx, &state->server_name);
+	*info3 = talloc_move(mem_ctx, &state->info3);
+	*session_key = state->session_key;
+	talloc_move(mem_ctx, &state->session_key.data);
+	*delegated_creds = state->delegated_creds;
+	talloc_move(mem_ctx, &state->delegated_creds.data);
+
+	tevent_req_received(req);
+	return 0;
+}
diff --git a/libcli/named_pipe_auth/npa_tstream.h b/libcli/named_pipe_auth/npa_tstream.h
index 7a19e10..63845be 100644
--- a/libcli/named_pipe_auth/npa_tstream.h
+++ b/libcli/named_pipe_auth/npa_tstream.h
@@ -56,4 +56,70 @@ int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
 	_tstream_npa_existing_socket(mem_ctx, fd, ft, stream, \
 				     __location__)
 
+
+/**
+ * @brief Accepts a connection for authenticated named pipes
+ *
+ * @param[in]  mem_ctx          The memory context for the operation
+ * @param[in]  ev               The tevent_context for the operation
+ * @param[in]  plain            The plain tstream_context of the bsd unix
+ *                              domain socket.
+ *                              This must be valid for the whole life of the
+ *                              resulting npa tstream_context!
+ * @param[in]  file_type        The file_type, message mode or byte mode
+ * @param[in]  device_state     The reported device state
+ * @param[in]  allocation_size  The reported allocation size
+ *
+ * @return the tevent_req handle
+ */
+struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct tstream_context *plain,
+					uint16_t file_type,
+					uint16_t device_state,
+					uint64_t allocation_size);
+
+/**
+ * @brief The receive end of the previous async function
+ *
+ * @param[in]  req		The tevent_req handle
+ * @param[out] perrno		Pointer to store the errno in case of error
+ * @param[in]  mem_ctx		The memory context for the results


-- 
Samba Shared Repository


More information about the samba-cvs mailing list