/*
  handle recv events on a smb_krb5 socket
*/
static void smb_krb5_socket_recv(struct smb_krb5_socket *smb_krb5)
{
	TALLOC_CTX *tmp_ctx = talloc_new(smb_krb5);
	DATA_BLOB blob;
	size_t nread, dsize;

	smb_krb5->status = socket_pending(smb_krb5->sock, &dsize);
	if (!NT_STATUS_IS_OK(smb_krb5->status)) {
		talloc_free(tmp_ctx);
		return;
	}

	blob = data_blob_talloc(tmp_ctx, NULL, dsize);
	if (blob.data == NULL && dsize != 0) {
		smb_krb5->status = NT_STATUS_NO_MEMORY;
		talloc_free(tmp_ctx);
		return;
	}

	smb_krb5->status = socket_recv(smb_krb5->sock, blob.data, blob.length, &nread);
	if (!NT_STATUS_IS_OK(smb_krb5->status)) {
		talloc_free(tmp_ctx);
		return;
	}
	blob.length = nread;

	if (nread == 0) {
		smb_krb5->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
		talloc_free(tmp_ctx);
		return;
	}

	DEBUG(4,("Received smb_krb5 packet of length %d\n",
		 (int)blob.length));

	talloc_steal(smb_krb5, blob.data);
	smb_krb5->reply = blob;
	talloc_free(tmp_ctx);
}
Ejemplo n.º 2
0
/*
  handle recv events on a nbt dgram socket
*/
static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
{
	TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
	NTSTATUS status;
	struct socket_address *src;
	DATA_BLOB blob;
	size_t nread, dsize;
	struct nbt_dgram_packet *packet;
	const char *mailslot_name;
	enum ndr_err_code ndr_err;

	status = socket_pending(dgmsock->sock, &dsize);
	if (!NT_STATUS_IS_OK(status)) {
		talloc_free(tmp_ctx);
		return;
	}

	blob = data_blob_talloc(tmp_ctx, NULL, dsize);
	if ((dsize != 0) && (blob.data == NULL)) {
		talloc_free(tmp_ctx);
		return;
	}

	status = socket_recvfrom(dgmsock->sock, blob.data, blob.length, &nread,
				 tmp_ctx, &src);
	if (!NT_STATUS_IS_OK(status)) {
		talloc_free(tmp_ctx);
		return;
	}
	blob.length = nread;

	DEBUG(5,("Received dgram packet of length %d from %s:%d\n", 
		 (int)blob.length, src->addr, src->port));

	packet = talloc(tmp_ctx, struct nbt_dgram_packet);
	if (packet == NULL) {
		talloc_free(tmp_ctx);
		return;
	}

	/* parse the request */
	ndr_err = ndr_pull_struct_blob(&blob, packet, packet,
				      (ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(2,("Failed to parse incoming NBT DGRAM packet - %s\n",
			 nt_errstr(status)));
		talloc_free(tmp_ctx);
		return;
	}

	/* if this is a mailslot message, then see if we can dispatch it to a handler */
	mailslot_name = dgram_mailslot_name(packet);
	if (mailslot_name) {
		struct dgram_mailslot_handler *dgmslot;
		dgmslot = dgram_mailslot_find(dgmsock, mailslot_name);
		if (dgmslot) {
			dgmslot->handler(dgmslot, packet, src);
		} else {
			DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
		}
	} else {
		/* dispatch if there is a general handler */
		if (dgmsock->incoming.handler) {
			dgmsock->incoming.handler(dgmsock, packet, src);
		}
	}

	talloc_free(tmp_ctx);
}
Ejemplo n.º 3
0
/*
  call this when the socket becomes readable to kick off the whole
  stream parsing process
*/
_PUBLIC_ void packet_recv(struct packet_context *pc)
{
	size_t npending;
	NTSTATUS status;
	size_t nread = 0;
	DATA_BLOB blob;
	bool recv_retry = false;

	if (pc->processing) {
		TEVENT_FD_NOT_READABLE(pc->fde);
		pc->processing++;
		return;
	}

	if (pc->recv_disable) {
		pc->recv_need_enable = true;
		TEVENT_FD_NOT_READABLE(pc->fde);
		return;
	}

	if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) {
		goto next_partial;
	}

	if (pc->packet_size != 0) {
		/* we've already worked out how long this next packet is, so skip the
		   socket_pending() call */
		npending = pc->packet_size - pc->num_read;
	} else if (pc->initial_read != 0) {
		npending = pc->initial_read - pc->num_read;
	} else {
		if (pc->sock) {
			status = socket_pending(pc->sock, &npending);
		} else {
			status = NT_STATUS_CONNECTION_DISCONNECTED;
		}
		if (!NT_STATUS_IS_OK(status)) {
			packet_error(pc, status);
			return;
		}
	}

	if (npending == 0) {
		packet_eof(pc);
		return;
	}

again:

	if (npending + pc->num_read < npending) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	if (npending + pc->num_read < pc->num_read) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	/* possibly expand the partial packet buffer */
	if (npending + pc->num_read > pc->partial.length) {
		if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
	}

	if (pc->partial.length < pc->num_read + npending) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}
	if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) {
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	status = socket_recv(pc->sock, pc->partial.data + pc->num_read, 
			     npending, &nread);

	if (NT_STATUS_IS_ERR(status)) {
		packet_error(pc, status);
		return;
	}
	if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
		nread = 0;
		status = NT_STATUS_OK;
	}
	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	if (nread == 0 && !recv_retry) {
		packet_eof(pc);
		return;
	}

	pc->num_read += nread;

	if (pc->unreliable_select && nread != 0) {
		recv_retry = true;
		status = socket_pending(pc->sock, &npending);
		if (!NT_STATUS_IS_OK(status)) {
			packet_error(pc, status);
			return;
		}
		if (npending != 0) {
			goto again;
		}
	}

next_partial:
	if (pc->partial.length != pc->num_read) {
		if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
	}

	/* see if its a full request */
	blob = pc->partial;
	blob.length = pc->num_read;
	status = pc->full_request(pc->private_data, blob, &pc->packet_size);
	if (NT_STATUS_IS_ERR(status)) {
		packet_error(pc, status);
		return;
	}
	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	if (pc->packet_size > pc->num_read) {
		/* the caller made an error */
		DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n",
			 (long)pc->packet_size, (long)pc->num_read));
		packet_error(pc, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	/* it is a full request - give it to the caller */
	blob = pc->partial;
	blob.length = pc->num_read;

	if (pc->packet_size < pc->num_read) {
		pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, 
					       pc->num_read - pc->packet_size);
		if (pc->partial.data == NULL) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
		/* Trunate the blob sent to the caller to only the packet length */
		if (!data_blob_realloc(pc, &blob, pc->packet_size)) {
			packet_error(pc, NT_STATUS_NO_MEMORY);
			return;
		}
	} else {
		pc->partial = data_blob(NULL, 0);
	}
	pc->num_read -= pc->packet_size;
	pc->packet_size = 0;
	
	if (pc->serialise) {
		pc->processing = 1;
	}

	pc->busy = true;

	status = pc->callback(pc->private_data, blob);

	pc->busy = false;

	if (pc->destructor_called) {
		talloc_free(pc);
		return;
	}

	if (pc->processing) {
		if (pc->processing > 1) {
			TEVENT_FD_READABLE(pc->fde);
		}
		pc->processing = 0;
	}

	if (!NT_STATUS_IS_OK(status)) {
		packet_error(pc, status);
		return;
	}

	/* Have we consumed the whole buffer yet? */
	if (pc->partial.length == 0) {
		return;
	}

	/* we got multiple packets in one tcp read */
	if (pc->ev == NULL) {
		goto next_partial;
	}

	blob = pc->partial;
	blob.length = pc->num_read;

	status = pc->full_request(pc->private_data, blob, &pc->packet_size);
	if (NT_STATUS_IS_ERR(status)) {
		packet_error(pc, status);
		return;
	}

	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	tevent_add_timer(pc->ev, pc, timeval_zero(), packet_next_event, pc);
}
Ejemplo n.º 4
0
/*
  handle fd recv events on a KDC socket
*/
static void kdc_recv_handler(struct kdc_socket *kdc_socket)
{
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx = talloc_new(kdc_socket);
	DATA_BLOB blob;
	struct kdc_reply *rep;
	DATA_BLOB reply;
	size_t nread, dsize;
	struct socket_address *src;
	struct socket_address *my_addr;
	int ret;

	status = socket_pending(kdc_socket->sock, &dsize);
	if (!NT_STATUS_IS_OK(status)) {
		talloc_free(tmp_ctx);
		return;
	}

	blob = data_blob_talloc(tmp_ctx, NULL, dsize);
	if (blob.data == NULL) {
		/* hope this is a temporary low memory condition */
		talloc_free(tmp_ctx);
		return;
	}

	status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,
				 tmp_ctx, &src);
	if (!NT_STATUS_IS_OK(status)) {
		talloc_free(tmp_ctx);
		return;
	}
	blob.length = nread;
	
	DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n", 
		 (long)blob.length, src->addr, (uint16_t)src->port));
	
	my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx);
	if (!my_addr) {
		talloc_free(tmp_ctx);
		return;
	}


	/* Call krb5 */
	ret = kdc_socket->process(kdc_socket->kdc, 
				  tmp_ctx, 
				  &blob,  
				  &reply,
				  src, my_addr,
				  1 /* Datagram */);
	if (!ret) {
		talloc_free(tmp_ctx);
		return;
	}

	/* queue a pending reply */
	rep = talloc(kdc_socket, struct kdc_reply);
	if (rep == NULL) {
		talloc_free(tmp_ctx);
		return;
	}
	rep->dest         = talloc_steal(rep, src);
	rep->packet       = reply;
	talloc_steal(rep, reply.data);

	if (rep->packet.data == NULL) {
		talloc_free(rep);
		talloc_free(tmp_ctx);
		return;
	}

	DLIST_ADD_END(kdc_socket->send_queue, rep, struct kdc_reply *);
	EVENT_FD_WRITEABLE(kdc_socket->fde);
	talloc_free(tmp_ctx);
}