2 Unix SMB/CIFS implementation.
4 GENSEC socket interface
6 Copyright (C) Andrew Bartlett 2006
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "lib/events/events.h"
25 #include "lib/socket/socket.h"
26 #include "lib/stream/packet.h"
27 #include "auth/gensec/gensec.h"
29 static const struct socket_ops gensec_socket_ops;
31 struct gensec_socket {
32 struct gensec_security *gensec_security;
33 struct socket_context *socket;
34 struct event_context *ev;
35 struct packet_context *packet;
36 DATA_BLOB read_buffer; /* SASL packets are turned into liniarlised data here, for reading */
41 void (*recv_handler)(void *, uint16_t);
46 static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
49 case SOCKET_TYPE_STREAM:
52 return NT_STATUS_INVALID_PARAMETER;
55 sock->backend_name = "gensec";
60 /* Try to figure out how much data is waiting to be read */
61 static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending)
63 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
64 if (gensec_socket->read_buffer.length > 0) {
65 *npending = gensec_socket->read_buffer.length;
69 /* This is a lie. We hope the decrypted data will always be
70 * less than this value, so the application just gets a short
71 * read. Without reading and decrypting it, we can't tell.
72 * If the SASL mech does compression, then we just need to
73 * manually trigger read events */
74 return socket_pending(gensec_socket->socket, npending);
77 /* Note if an error occours, so we can return it up the stack */
78 static void gensec_socket_error_handler(void *private, NTSTATUS status)
80 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
81 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
82 gensec_socket->eof = True;
84 gensec_socket->error = status;
88 static void gensec_socket_trigger_read(struct event_context *ev,
89 struct timed_event *te,
90 struct timeval t, void *private)
92 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
94 gensec_socket->in_extra_read++;
95 gensec_socket->recv_handler(gensec_socket->recv_private, EVENT_FD_READ);
96 gensec_socket->in_extra_read--;
98 /* It may well be that, having run the recv handler, we still
99 * have even more data waiting for us!
101 if (gensec_socket->read_buffer.length && gensec_socket->recv_handler) {
102 /* Schedule this funcion to run again */
103 event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(),
104 gensec_socket_trigger_read, gensec_socket);
108 /* These two routines could be changed to use a circular buffer of
109 * some kind, or linked lists, or ... */
110 static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf,
111 size_t wantlen, size_t *nread)
113 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
115 gensec_socket->error = NT_STATUS_OK;
117 if (gensec_socket->read_buffer.length == 0) {
118 /* Process any data on the socket, into the read buffer. At
119 * this point, the socket is not available for read any
121 packet_recv(gensec_socket->packet);
123 if (gensec_socket->eof) {
128 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
129 return gensec_socket->error;
132 if (gensec_socket->read_buffer.length == 0) {
133 /* Clearly we don't have the entire SASL packet yet,
134 * so it has not been written into the buffer */
136 return STATUS_MORE_ENTRIES;
141 *nread = MIN(wantlen, gensec_socket->read_buffer.length);
142 memcpy(buf, gensec_socket->read_buffer.data, *nread);
144 if (gensec_socket->read_buffer.length > *nread) {
145 memmove(gensec_socket->read_buffer.data,
146 gensec_socket->read_buffer.data + *nread,
147 gensec_socket->read_buffer.length - *nread);
150 gensec_socket->read_buffer.length -= *nread;
151 gensec_socket->read_buffer.data = talloc_realloc(gensec_socket,
152 gensec_socket->read_buffer.data,
154 gensec_socket->read_buffer.length);
156 if (gensec_socket->read_buffer.length &&
157 gensec_socket->in_extra_read == 0 &&
158 gensec_socket->recv_handler) {
159 /* Manually call a read event, to get this moving
160 * again (as the socket should be dry, so the normal
161 * event handler won't trigger) */
162 event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(),
163 gensec_socket_trigger_read, gensec_socket);
169 /* Completed SASL packet callback. When we have a 'whole' SASL
170 * packet, decrypt it, and add it to the read buffer
172 * This function (and anything under it) MUST NOT call the event system
174 static NTSTATUS gensec_socket_unwrap(void *private, DATA_BLOB blob)
176 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
181 uint32_t packet_size;
183 if (blob.length < 4) {
184 /* Missing the header we already had! */
185 DEBUG(0, ("Asked to unwrap packed of bogus length! How did we get the short packet?!\n"));
186 return NT_STATUS_INVALID_PARAMETER;
189 wrapped = data_blob_const(blob.data + 4, blob.length - 4);
191 packet_size = RIVAL(blob.data, 0);
192 if (packet_size != wrapped.length) {
193 DEBUG(0, ("Asked to unwrap packed of bogus length! How did we get this?!\n"));
194 return NT_STATUS_INTERNAL_ERROR;
197 mem_ctx = talloc_new(gensec_socket);
199 return NT_STATUS_NO_MEMORY;
201 nt_status = gensec_unwrap(gensec_socket->gensec_security,
203 &wrapped, &unwrapped);
204 if (!NT_STATUS_IS_OK(nt_status)) {
205 talloc_free(mem_ctx);
208 /* We could change this into a linked list, and have
209 * gensec_socket_recv() and gensec_socket_pending() walk the
212 nt_status = data_blob_append(gensec_socket, &gensec_socket->read_buffer,
213 unwrapped.data, unwrapped.length);
214 talloc_free(mem_ctx);
218 /* when the data is sent, we know we have not been interrupted */
219 static void send_callback(void *private)
221 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
222 gensec_socket->interrupted = False;
226 send data, but only as much as we allow in one packet.
228 If this returns STATUS_MORE_ENTRIES, the caller must retry with
229 exactly the same data, or a NULL blob.
231 static NTSTATUS gensec_socket_send(struct socket_context *sock,
232 const DATA_BLOB *blob, size_t *sendlen)
235 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
236 DATA_BLOB unwrapped, wrapped, out;
238 size_t max_input_size;
242 /* We have have been interupted, so the caller should be
243 * giving us the same data again. */
244 if (gensec_socket->interrupted) {
245 packet_queue_run(gensec_socket->packet);
247 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
248 return gensec_socket->error;
249 } else if (gensec_socket->interrupted) {
250 return STATUS_MORE_ENTRIES;
252 *sendlen = gensec_socket->orig_send_len;
253 gensec_socket->orig_send_len = 0;
258 mem_ctx = talloc_new(gensec_socket);
260 return NT_STATUS_NO_MEMORY;
263 max_input_size = gensec_max_input_size(gensec_socket->gensec_security);
264 unwrapped = data_blob_const(blob->data, MIN(max_input_size, (size_t)blob->length));
266 nt_status = gensec_wrap(gensec_socket->gensec_security,
268 &unwrapped, &wrapped);
269 if (!NT_STATUS_IS_OK(nt_status)) {
270 talloc_free(mem_ctx);
274 out = data_blob_talloc(mem_ctx, NULL, 4);
276 talloc_free(mem_ctx);
277 return NT_STATUS_NO_MEMORY;
279 RSIVAL(out.data, 0, wrapped.length);
281 nt_status = data_blob_append(gensec_socket, &out, wrapped.data, wrapped.length);
283 if (!NT_STATUS_IS_OK(nt_status)) {
284 talloc_free(mem_ctx);
288 gensec_socket->interrupted = True;
289 gensec_socket->error = NT_STATUS_OK;
290 gensec_socket->orig_send_len
293 nt_status = packet_send_callback(gensec_socket->packet,
295 send_callback, gensec_socket);
297 talloc_free(mem_ctx);
299 packet_queue_run(gensec_socket->packet);
301 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
302 return gensec_socket->error;
303 } else if (gensec_socket->interrupted) {
304 return STATUS_MORE_ENTRIES;
306 *sendlen = gensec_socket->orig_send_len;
307 gensec_socket->orig_send_len = 0;
312 struct socket_context *gensec_socket_init(struct gensec_security *gensec_security,
313 struct socket_context *socket,
314 struct event_context *ev,
315 void (*recv_handler)(void *, uint16_t),
318 struct gensec_socket *gensec_socket;
319 struct socket_context *new_sock;
322 /* Nothing to do here, if we are not actually wrapping on this socket */
323 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
324 !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
328 nt_status = socket_create_with_ops(socket, &gensec_socket_ops, &new_sock,
329 SOCKET_TYPE_STREAM, socket->flags | SOCKET_FLAG_ENCRYPT);
330 if (!NT_STATUS_IS_OK(nt_status)) {
334 gensec_socket = talloc(new_sock, struct gensec_socket);
335 if (gensec_socket == NULL) {
339 gensec_socket->eof = False;
340 gensec_socket->error = NT_STATUS_OK;
341 gensec_socket->interrupted = False;
342 gensec_socket->in_extra_read = 0;
344 gensec_socket->read_buffer = data_blob(NULL, 0);
346 gensec_socket->gensec_security = gensec_security;
347 gensec_socket->socket = socket;
348 if (talloc_reference(gensec_socket, socket) == NULL) {
351 gensec_socket->recv_handler = recv_handler;
352 gensec_socket->recv_private = recv_private;
353 gensec_socket->ev = ev;
355 new_sock->private_data = gensec_socket;
357 gensec_socket->packet = packet_init(gensec_socket);
358 if (gensec_socket->packet == NULL) {
362 packet_set_private(gensec_socket->packet, gensec_socket);
363 packet_set_socket(gensec_socket->packet, socket);
364 packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
365 packet_set_full_request(gensec_socket->packet, packet_full_request_u32);
366 packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
367 packet_set_serialise(gensec_socket->packet);
369 /* TODO: full-request that knows about maximum packet size */
371 new_sock->state = socket->state;
377 static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val)
379 set_socket_options(socket_get_fd(sock), option);
383 static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
385 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
386 return socket_get_peer_name(gensec->socket, mem_ctx);
389 static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
391 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
392 return socket_get_peer_addr(gensec->socket, mem_ctx);
395 static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
397 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
398 return socket_get_my_addr(gensec->socket, mem_ctx);
401 static int gensec_socket_get_fd(struct socket_context *sock)
403 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
404 return socket_get_fd(gensec->socket);
407 static const struct socket_ops gensec_socket_ops = {
409 .fn_init = gensec_socket_init_fn,
410 .fn_recv = gensec_socket_recv,
411 .fn_send = gensec_socket_send,
412 .fn_pending = gensec_socket_pending,
414 .fn_set_option = gensec_socket_set_option,
416 .fn_get_peer_name = gensec_socket_get_peer_name,
417 .fn_get_peer_addr = gensec_socket_get_peer_addr,
418 .fn_get_my_addr = gensec_socket_get_my_addr,
419 .fn_get_fd = gensec_socket_get_fd