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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "lib/socket/socket.h"
25 #include "lib/stream/packet.h"
26 #include "auth/gensec/gensec.h"
28 static const struct socket_ops gensec_socket_ops;
30 struct gensec_socket {
31 struct gensec_security *gensec_security;
32 struct socket_context *socket;
33 struct event_context *ev;
34 struct packet_context *packet;
35 DATA_BLOB read_buffer; /* SASL packets are turned into liniarlised data here, for reading */
40 void (*recv_handler)(void *, uint16_t);
43 BOOL wrap; /* Should we be wrapping on this socket at all? */
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 /* These functions are for use here only (public because SPNEGO must
61 * use them for recursion) */
62 _PUBLIC_ NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security,
66 size_t *len_processed)
68 if (!gensec_security->ops->wrap_packets) {
70 size_t max_input_size;
71 DATA_BLOB unwrapped, wrapped;
72 max_input_size = gensec_max_input_size(gensec_security);
73 unwrapped = data_blob_const(in->data, MIN(max_input_size, (size_t)in->length));
75 nt_status = gensec_wrap(gensec_security,
77 &unwrapped, &wrapped);
78 if (!NT_STATUS_IS_OK(nt_status)) {
83 *out = data_blob_talloc(mem_ctx, NULL, 4);
85 return NT_STATUS_NO_MEMORY;
87 RSIVAL(out->data, 0, wrapped.length);
89 nt_status = data_blob_append(mem_ctx, out, wrapped.data, wrapped.length);
91 if (!NT_STATUS_IS_OK(nt_status)) {
94 *len_processed = unwrapped.length;
97 return gensec_security->ops->wrap_packets(gensec_security, mem_ctx, in, out,
101 /* These functions are for use here only (public because SPNEGO must
102 * use them for recursion) */
103 NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security,
107 size_t *len_processed)
109 if (!gensec_security->ops->unwrap_packets) {
113 if (in->length < 4) {
114 /* Missing the header we already had! */
115 DEBUG(0, ("Asked to unwrap packet of bogus length! How did we get the short packet?!\n"));
116 return NT_STATUS_INVALID_PARAMETER;
119 packet_size = RIVAL(in->data, 0);
121 wrapped = data_blob_const(in->data + 4, packet_size);
123 if (wrapped.length > (in->length - 4)) {
124 DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d! How did we get this?!\n",
125 (int)wrapped.length, (int)(in->length - 4)));
126 return NT_STATUS_INTERNAL_ERROR;
129 nt_status = gensec_unwrap(gensec_security,
132 if (!NT_STATUS_IS_OK(nt_status)) {
136 *len_processed = packet_size + 4;
139 return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out,
143 /* These functions are for use here only (public because SPNEGO must
144 * use them for recursion) */
145 NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security,
146 DATA_BLOB blob, size_t *size)
148 if (gensec_security->ops->packet_full_request) {
149 return gensec_security->ops->packet_full_request(gensec_security,
152 if (gensec_security->ops->unwrap_packets) {
157 return STATUS_MORE_ENTRIES;
159 return packet_full_request_u32(NULL, blob, size);
162 static NTSTATUS gensec_socket_full_request(void *private, DATA_BLOB blob, size_t *size)
164 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
165 struct gensec_security *gensec_security = gensec_socket->gensec_security;
166 return gensec_packet_full_request(gensec_security, blob, size);
169 /* Try to figure out how much data is waiting to be read */
170 static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending)
172 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
173 if (!gensec_socket->wrap) {
174 return socket_pending(gensec_socket->socket, npending);
177 if (gensec_socket->read_buffer.length > 0) {
178 *npending = gensec_socket->read_buffer.length;
182 /* This is a lie. We hope the decrypted data will always be
183 * less than this value, so the application just gets a short
184 * read. Without reading and decrypting it, we can't tell.
185 * If the SASL mech does compression, then we just need to
186 * manually trigger read events */
187 return socket_pending(gensec_socket->socket, npending);
190 /* Note if an error occours, so we can return it up the stack */
191 static void gensec_socket_error_handler(void *private, NTSTATUS status)
193 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
194 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
195 gensec_socket->eof = True;
197 gensec_socket->error = status;
201 static void gensec_socket_trigger_read(struct event_context *ev,
202 struct timed_event *te,
203 struct timeval t, void *private)
205 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
207 gensec_socket->in_extra_read++;
208 gensec_socket->recv_handler(gensec_socket->recv_private, EVENT_FD_READ);
209 gensec_socket->in_extra_read--;
211 /* It may well be that, having run the recv handler, we still
212 * have even more data waiting for us!
214 if (gensec_socket->read_buffer.length && gensec_socket->recv_handler) {
215 /* Schedule this funcion to run again */
216 event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(),
217 gensec_socket_trigger_read, gensec_socket);
221 /* These two routines could be changed to use a circular buffer of
222 * some kind, or linked lists, or ... */
223 static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf,
224 size_t wantlen, size_t *nread)
226 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
228 if (!gensec_socket->wrap) {
229 return socket_recv(gensec_socket->socket, buf, wantlen, nread);
232 gensec_socket->error = NT_STATUS_OK;
234 if (gensec_socket->read_buffer.length == 0) {
235 /* Process any data on the socket, into the read buffer. At
236 * this point, the socket is not available for read any
238 packet_recv(gensec_socket->packet);
240 if (gensec_socket->eof) {
245 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
246 return gensec_socket->error;
249 if (gensec_socket->read_buffer.length == 0) {
250 /* Clearly we don't have the entire SASL packet yet,
251 * so it has not been written into the buffer */
253 return STATUS_MORE_ENTRIES;
258 *nread = MIN(wantlen, gensec_socket->read_buffer.length);
259 memcpy(buf, gensec_socket->read_buffer.data, *nread);
261 if (gensec_socket->read_buffer.length > *nread) {
262 memmove(gensec_socket->read_buffer.data,
263 gensec_socket->read_buffer.data + *nread,
264 gensec_socket->read_buffer.length - *nread);
267 gensec_socket->read_buffer.length -= *nread;
268 gensec_socket->read_buffer.data = talloc_realloc(gensec_socket,
269 gensec_socket->read_buffer.data,
271 gensec_socket->read_buffer.length);
273 if (gensec_socket->read_buffer.length &&
274 gensec_socket->in_extra_read == 0 &&
275 gensec_socket->recv_handler) {
276 /* Manually call a read event, to get this moving
277 * again (as the socket should be dry, so the normal
278 * event handler won't trigger) */
279 event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(),
280 gensec_socket_trigger_read, gensec_socket);
286 /* Completed SASL packet callback. When we have a 'whole' SASL
287 * packet, decrypt it, and add it to the read buffer
289 * This function (and anything under it) MUST NOT call the event system
291 static NTSTATUS gensec_socket_unwrap(void *private, DATA_BLOB blob)
293 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
299 mem_ctx = talloc_new(gensec_socket);
301 return NT_STATUS_NO_MEMORY;
303 nt_status = gensec_unwrap_packets(gensec_socket->gensec_security,
307 if (!NT_STATUS_IS_OK(nt_status)) {
308 talloc_free(mem_ctx);
312 if (packet_size != blob.length) {
313 DEBUG(0, ("gensec_socket_unwrap: Did not consume entire packet!\n"));
314 return NT_STATUS_INTERNAL_ERROR;
317 /* We could change this into a linked list, and have
318 * gensec_socket_recv() and gensec_socket_pending() walk the
321 nt_status = data_blob_append(gensec_socket, &gensec_socket->read_buffer,
322 unwrapped.data, unwrapped.length);
323 talloc_free(mem_ctx);
327 /* when the data is sent, we know we have not been interrupted */
328 static void send_callback(void *private)
330 struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
331 gensec_socket->interrupted = False;
335 send data, but only as much as we allow in one packet.
337 If this returns STATUS_MORE_ENTRIES, the caller must retry with
338 exactly the same data, or a NULL blob.
340 static NTSTATUS gensec_socket_send(struct socket_context *sock,
341 const DATA_BLOB *blob, size_t *sendlen)
344 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
348 if (!gensec_socket->wrap) {
349 return socket_send(gensec_socket->socket, blob, sendlen);
354 /* We have have been interupted, so the caller should be
355 * giving us the same data again. */
356 if (gensec_socket->interrupted) {
357 packet_queue_run(gensec_socket->packet);
359 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
360 return gensec_socket->error;
361 } else if (gensec_socket->interrupted) {
362 return STATUS_MORE_ENTRIES;
364 *sendlen = gensec_socket->orig_send_len;
365 gensec_socket->orig_send_len = 0;
370 mem_ctx = talloc_new(gensec_socket);
372 return NT_STATUS_NO_MEMORY;
375 nt_status = gensec_wrap_packets(gensec_socket->gensec_security,
378 &gensec_socket->orig_send_len);
379 if (!NT_STATUS_IS_OK(nt_status)) {
380 talloc_free(mem_ctx);
384 gensec_socket->interrupted = True;
385 gensec_socket->error = NT_STATUS_OK;
387 nt_status = packet_send_callback(gensec_socket->packet,
389 send_callback, gensec_socket);
391 talloc_free(mem_ctx);
393 packet_queue_run(gensec_socket->packet);
395 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
396 return gensec_socket->error;
397 } else if (gensec_socket->interrupted) {
398 return STATUS_MORE_ENTRIES;
400 *sendlen = gensec_socket->orig_send_len;
401 gensec_socket->orig_send_len = 0;
406 /* Turn a normal socket into a potentially GENSEC wrapped socket */
408 NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
409 struct socket_context *current_socket,
410 struct event_context *ev,
411 void (*recv_handler)(void *, uint16_t),
413 struct socket_context **new_socket)
415 struct gensec_socket *gensec_socket;
416 struct socket_context *new_sock;
419 nt_status = socket_create_with_ops(current_socket, &gensec_socket_ops, &new_sock,
420 SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT);
421 if (!NT_STATUS_IS_OK(nt_status)) {
426 new_sock->state = current_socket->state;
428 gensec_socket = talloc(new_sock, struct gensec_socket);
429 if (gensec_socket == NULL) {
431 return NT_STATUS_NO_MEMORY;
434 new_sock->private_data = gensec_socket;
435 gensec_socket->socket = current_socket;
437 if (talloc_reference(gensec_socket, current_socket) == NULL) {
439 return NT_STATUS_NO_MEMORY;
442 /* Nothing to do here, if we are not actually wrapping on this socket */
443 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
444 !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
446 gensec_socket->wrap = False;
447 *new_socket = new_sock;
451 gensec_socket->gensec_security = gensec_security;
453 gensec_socket->wrap = True;
454 gensec_socket->eof = False;
455 gensec_socket->error = NT_STATUS_OK;
456 gensec_socket->interrupted = False;
457 gensec_socket->in_extra_read = 0;
459 gensec_socket->read_buffer = data_blob(NULL, 0);
461 gensec_socket->recv_handler = recv_handler;
462 gensec_socket->recv_private = recv_private;
463 gensec_socket->ev = ev;
465 gensec_socket->packet = packet_init(gensec_socket);
466 if (gensec_socket->packet == NULL) {
468 return NT_STATUS_NO_MEMORY;
471 packet_set_private(gensec_socket->packet, gensec_socket);
472 packet_set_socket(gensec_socket->packet, gensec_socket->socket);
473 packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
474 packet_set_full_request(gensec_socket->packet, gensec_socket_full_request);
475 packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
476 packet_set_serialise(gensec_socket->packet);
478 /* TODO: full-request that knows about maximum packet size */
480 *new_socket = new_sock;
485 static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val)
487 set_socket_options(socket_get_fd(sock), option);
491 static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
493 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
494 return socket_get_peer_name(gensec->socket, mem_ctx);
497 static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
499 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
500 return socket_get_peer_addr(gensec->socket, mem_ctx);
503 static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
505 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
506 return socket_get_my_addr(gensec->socket, mem_ctx);
509 static int gensec_socket_get_fd(struct socket_context *sock)
511 struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
512 return socket_get_fd(gensec->socket);
515 static const struct socket_ops gensec_socket_ops = {
517 .fn_init = gensec_socket_init_fn,
518 .fn_recv = gensec_socket_recv,
519 .fn_send = gensec_socket_send,
520 .fn_pending = gensec_socket_pending,
522 .fn_set_option = gensec_socket_set_option,
524 .fn_get_peer_name = gensec_socket_get_peer_name,
525 .fn_get_peer_addr = gensec_socket_get_peer_addr,
526 .fn_get_my_addr = gensec_socket_get_my_addr,
527 .fn_get_fd = gensec_socket_get_fd