📄 socket.c
字号:
/* Unix SMB/CIFS implementation. GENSEC socket interface Copyright (C) Andrew Bartlett 2006 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 "lib/events/events.h"#include "lib/socket/socket.h"#include "lib/stream/packet.h"#include "auth/gensec/gensec.h"#include "auth/gensec/gensec_proto.h"static const struct socket_ops gensec_socket_ops;struct gensec_socket { struct gensec_security *gensec_security; struct socket_context *socket; struct event_context *ev; struct packet_context *packet; DATA_BLOB read_buffer; /* SASL packets are turned into liniarlised data here, for reading */ size_t orig_send_len; bool eof; NTSTATUS error; bool interrupted; void (*recv_handler)(void *, uint16_t); void *recv_private; int in_extra_read; bool wrap; /* Should we be wrapping on this socket at all? */};static NTSTATUS gensec_socket_init_fn(struct socket_context *sock){ switch (sock->type) { case SOCKET_TYPE_STREAM: break; default: return NT_STATUS_INVALID_PARAMETER; } sock->backend_name = "gensec"; return NT_STATUS_OK;}/* These functions are for use here only (public because SPNEGO must * use them for recursion) */_PUBLIC_ NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out, size_t *len_processed) { if (!gensec_security->ops->wrap_packets) { NTSTATUS nt_status; size_t max_input_size; DATA_BLOB unwrapped, wrapped; max_input_size = gensec_max_input_size(gensec_security); unwrapped = data_blob_const(in->data, MIN(max_input_size, (size_t)in->length)); nt_status = gensec_wrap(gensec_security, mem_ctx, &unwrapped, &wrapped); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } *out = data_blob_talloc(mem_ctx, NULL, 4); if (!out->data) { return NT_STATUS_NO_MEMORY; } RSIVAL(out->data, 0, wrapped.length); if (!data_blob_append(mem_ctx, out, wrapped.data, wrapped.length)) { return NT_STATUS_NO_MEMORY; } *len_processed = unwrapped.length; return NT_STATUS_OK; } return gensec_security->ops->wrap_packets(gensec_security, mem_ctx, in, out, len_processed);}/* These functions are for use here only (public because SPNEGO must * use them for recursion) */NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out, size_t *len_processed) { if (!gensec_security->ops->unwrap_packets) { DATA_BLOB wrapped; NTSTATUS nt_status; size_t packet_size; if (in->length < 4) { /* Missing the header we already had! */ DEBUG(0, ("Asked to unwrap packet of bogus length! How did we get the short packet?!\n")); return NT_STATUS_INVALID_PARAMETER; } packet_size = RIVAL(in->data, 0); wrapped = data_blob_const(in->data + 4, packet_size); if (wrapped.length > (in->length - 4)) { DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d! How did we get this?!\n", (int)wrapped.length, (int)(in->length - 4))); return NT_STATUS_INTERNAL_ERROR; } nt_status = gensec_unwrap(gensec_security, mem_ctx, &wrapped, out); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } *len_processed = packet_size + 4; return nt_status; } return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out, len_processed);}/* These functions are for use here only (public because SPNEGO must * use them for recursion) */NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security, DATA_BLOB blob, size_t *size) { if (gensec_security->ops->packet_full_request) { return gensec_security->ops->packet_full_request(gensec_security, blob, size); } if (gensec_security->ops->unwrap_packets) { if (blob.length) { *size = blob.length; return NT_STATUS_OK; } return STATUS_MORE_ENTRIES; } return packet_full_request_u32(NULL, blob, size);}static NTSTATUS gensec_socket_full_request(void *private, DATA_BLOB blob, size_t *size) { struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket); struct gensec_security *gensec_security = gensec_socket->gensec_security; return gensec_packet_full_request(gensec_security, blob, size);}/* Try to figure out how much data is waiting to be read */static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending) { struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); if (!gensec_socket->wrap) { return socket_pending(gensec_socket->socket, npending); } if (gensec_socket->read_buffer.length > 0) { *npending = gensec_socket->read_buffer.length; return NT_STATUS_OK; } /* This is a lie. We hope the decrypted data will always be * less than this value, so the application just gets a short * read. Without reading and decrypting it, we can't tell. * If the SASL mech does compression, then we just need to * manually trigger read events */ return socket_pending(gensec_socket->socket, npending);} /* Note if an error occours, so we can return it up the stack */static void gensec_socket_error_handler(void *private, NTSTATUS status){ struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket); if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { gensec_socket->eof = true; } else { gensec_socket->error = status; }}static void gensec_socket_trigger_read(struct event_context *ev, struct timed_event *te, struct timeval t, void *private){ struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket); gensec_socket->in_extra_read++; gensec_socket->recv_handler(gensec_socket->recv_private, EVENT_FD_READ); gensec_socket->in_extra_read--; /* It may well be that, having run the recv handler, we still * have even more data waiting for us! */ if (gensec_socket->read_buffer.length && gensec_socket->recv_handler) { /* Schedule this funcion to run again */ event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(), gensec_socket_trigger_read, gensec_socket); }}/* These two routines could be changed to use a circular buffer of * some kind, or linked lists, or ... */static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf, size_t wantlen, size_t *nread) { struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); if (!gensec_socket->wrap) { return socket_recv(gensec_socket->socket, buf, wantlen, nread); } gensec_socket->error = NT_STATUS_OK; if (gensec_socket->read_buffer.length == 0) { /* Process any data on the socket, into the read buffer. At * this point, the socket is not available for read any * longer */ packet_recv(gensec_socket->packet); if (gensec_socket->eof) { *nread = 0; return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(gensec_socket->error)) { return gensec_socket->error; } if (gensec_socket->read_buffer.length == 0) { /* Clearly we don't have the entire SASL packet yet, * so it has not been written into the buffer */ *nread = 0; return STATUS_MORE_ENTRIES; } } *nread = MIN(wantlen, gensec_socket->read_buffer.length); memcpy(buf, gensec_socket->read_buffer.data, *nread); if (gensec_socket->read_buffer.length > *nread) { memmove(gensec_socket->read_buffer.data, gensec_socket->read_buffer.data + *nread, gensec_socket->read_buffer.length - *nread); } gensec_socket->read_buffer.length -= *nread; gensec_socket->read_buffer.data = talloc_realloc(gensec_socket,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -