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"
27 #include "auth/gensec/gensec_proto.h"
28 #include "auth/gensec/gensec_socket.h"
30 static const struct socket_ops gensec_socket_ops
;
32 struct gensec_socket
{
33 struct gensec_security
*gensec_security
;
34 struct socket_context
*socket
;
35 struct tevent_context
*ev
;
36 struct packet_context
*packet
;
37 DATA_BLOB read_buffer
; /* SASL packets are turned into liniarlised data here, for reading */
42 void (*recv_handler
)(void *, uint16_t);
45 bool wrap
; /* Should we be wrapping on this socket at all? */
48 static NTSTATUS
gensec_socket_init_fn(struct socket_context
*sock
)
51 case SOCKET_TYPE_STREAM
:
54 return NT_STATUS_INVALID_PARAMETER
;
57 sock
->backend_name
= "gensec";
62 static NTSTATUS
gensec_socket_full_request(void *private_data
, DATA_BLOB blob
, size_t *size
)
64 struct gensec_socket
*gensec_socket
= talloc_get_type(private_data
, struct gensec_socket
);
65 struct gensec_security
*gensec_security
= gensec_socket
->gensec_security
;
66 return gensec_packet_full_request(gensec_security
, blob
, size
);
69 /* Try to figure out how much data is waiting to be read */
70 static NTSTATUS
gensec_socket_pending(struct socket_context
*sock
, size_t *npending
)
72 struct gensec_socket
*gensec_socket
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
73 if (!gensec_socket
->wrap
) {
74 return socket_pending(gensec_socket
->socket
, npending
);
77 if (gensec_socket
->read_buffer
.length
> 0) {
78 *npending
= gensec_socket
->read_buffer
.length
;
82 /* This is a lie. We hope the decrypted data will always be
83 * less than this value, so the application just gets a short
84 * read. Without reading and decrypting it, we can't tell.
85 * If the SASL mech does compression, then we just need to
86 * manually trigger read events */
87 return socket_pending(gensec_socket
->socket
, npending
);
90 /* Note if an error occours, so we can return it up the stack */
91 static void gensec_socket_error_handler(void *private_data
, NTSTATUS status
)
93 struct gensec_socket
*gensec_socket
= talloc_get_type(private_data
, struct gensec_socket
);
94 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
)) {
95 gensec_socket
->eof
= true;
97 gensec_socket
->error
= status
;
101 static void gensec_socket_trigger_read(struct tevent_context
*ev
,
102 struct tevent_timer
*te
,
103 struct timeval t
, void *private_data
)
105 struct gensec_socket
*gensec_socket
= talloc_get_type(private_data
, struct gensec_socket
);
107 gensec_socket
->in_extra_read
++;
108 gensec_socket
->recv_handler(gensec_socket
->recv_private
, TEVENT_FD_READ
);
109 gensec_socket
->in_extra_read
--;
111 /* It may well be that, having run the recv handler, we still
112 * have even more data waiting for us!
114 if (gensec_socket
->read_buffer
.length
> 0) {
115 /* Schedule this funcion to run again */
116 tevent_add_timer(gensec_socket
->ev
, gensec_socket
, timeval_zero(),
117 gensec_socket_trigger_read
, gensec_socket
);
121 /* These two routines could be changed to use a circular buffer of
122 * some kind, or linked lists, or ... */
123 static NTSTATUS
gensec_socket_recv(struct socket_context
*sock
, void *buf
,
124 size_t wantlen
, size_t *nread
)
126 struct gensec_socket
*gensec_socket
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
128 if (!gensec_socket
->wrap
) {
129 return socket_recv(gensec_socket
->socket
, buf
, wantlen
, nread
);
132 gensec_socket
->error
= NT_STATUS_OK
;
134 if (gensec_socket
->read_buffer
.length
== 0) {
135 /* Process any data on the socket, into the read buffer. At
136 * this point, the socket is not available for read any
138 packet_recv(gensec_socket
->packet
);
140 if (gensec_socket
->eof
) {
145 if (!NT_STATUS_IS_OK(gensec_socket
->error
)) {
146 return gensec_socket
->error
;
149 if (gensec_socket
->read_buffer
.length
== 0) {
150 /* Clearly we don't have the entire SASL packet yet,
151 * so it has not been written into the buffer */
153 return STATUS_MORE_ENTRIES
;
158 *nread
= MIN(wantlen
, gensec_socket
->read_buffer
.length
);
159 memcpy(buf
, gensec_socket
->read_buffer
.data
, *nread
);
161 if (gensec_socket
->read_buffer
.length
> *nread
) {
162 memmove(gensec_socket
->read_buffer
.data
,
163 gensec_socket
->read_buffer
.data
+ *nread
,
164 gensec_socket
->read_buffer
.length
- *nread
);
167 gensec_socket
->read_buffer
.length
-= *nread
;
168 gensec_socket
->read_buffer
.data
= talloc_realloc(gensec_socket
,
169 gensec_socket
->read_buffer
.data
,
171 gensec_socket
->read_buffer
.length
);
173 if (gensec_socket
->read_buffer
.length
&&
174 gensec_socket
->in_extra_read
== 0 &&
175 gensec_socket
->recv_handler
) {
176 /* Manually call a read event, to get this moving
177 * again (as the socket should be dry, so the normal
178 * event handler won't trigger) */
179 tevent_add_timer(gensec_socket
->ev
, gensec_socket
, timeval_zero(),
180 gensec_socket_trigger_read
, gensec_socket
);
186 /* Completed SASL packet callback. When we have a 'whole' SASL
187 * packet, decrypt it, and add it to the read buffer
189 * This function (and anything under it) MUST NOT call the event system
191 static NTSTATUS
gensec_socket_unwrap(void *private_data
, DATA_BLOB blob
)
193 struct gensec_socket
*gensec_socket
= talloc_get_type(private_data
, struct gensec_socket
);
199 mem_ctx
= talloc_new(gensec_socket
);
201 return NT_STATUS_NO_MEMORY
;
203 nt_status
= gensec_unwrap_packets(gensec_socket
->gensec_security
,
207 if (!NT_STATUS_IS_OK(nt_status
)) {
208 talloc_free(mem_ctx
);
212 if (packet_size
!= blob
.length
) {
213 DEBUG(0, ("gensec_socket_unwrap: Did not consume entire packet!\n"));
214 talloc_free(mem_ctx
);
215 return NT_STATUS_INTERNAL_ERROR
;
218 /* We could change this into a linked list, and have
219 * gensec_socket_recv() and gensec_socket_pending() walk the
222 if (!data_blob_append(gensec_socket
, &gensec_socket
->read_buffer
,
223 unwrapped
.data
, unwrapped
.length
)) {
224 talloc_free(mem_ctx
);
225 return NT_STATUS_NO_MEMORY
;
228 talloc_free(mem_ctx
);
232 /* when the data is sent, we know we have not been interrupted */
233 static void send_callback(void *private_data
)
235 struct gensec_socket
*gensec_socket
= talloc_get_type(private_data
, struct gensec_socket
);
236 gensec_socket
->interrupted
= false;
240 send data, but only as much as we allow in one packet.
242 If this returns STATUS_MORE_ENTRIES, the caller must retry with
243 exactly the same data, or a NULL blob.
245 static NTSTATUS
gensec_socket_send(struct socket_context
*sock
,
246 const DATA_BLOB
*blob
, size_t *sendlen
)
249 struct gensec_socket
*gensec_socket
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
253 if (!gensec_socket
->wrap
) {
254 return socket_send(gensec_socket
->socket
, blob
, sendlen
);
259 /* We have have been interupted, so the caller should be
260 * giving us the same data again. */
261 if (gensec_socket
->interrupted
) {
262 packet_queue_run(gensec_socket
->packet
);
264 if (!NT_STATUS_IS_OK(gensec_socket
->error
)) {
265 return gensec_socket
->error
;
266 } else if (gensec_socket
->interrupted
) {
267 return STATUS_MORE_ENTRIES
;
269 *sendlen
= gensec_socket
->orig_send_len
;
270 gensec_socket
->orig_send_len
= 0;
275 mem_ctx
= talloc_new(gensec_socket
);
277 return NT_STATUS_NO_MEMORY
;
280 nt_status
= gensec_wrap_packets(gensec_socket
->gensec_security
,
283 &gensec_socket
->orig_send_len
);
284 if (!NT_STATUS_IS_OK(nt_status
)) {
285 talloc_free(mem_ctx
);
289 gensec_socket
->interrupted
= true;
290 gensec_socket
->error
= NT_STATUS_OK
;
292 nt_status
= packet_send_callback(gensec_socket
->packet
,
294 send_callback
, gensec_socket
);
296 talloc_free(mem_ctx
);
298 packet_queue_run(gensec_socket
->packet
);
300 if (!NT_STATUS_IS_OK(gensec_socket
->error
)) {
301 return gensec_socket
->error
;
302 } else if (gensec_socket
->interrupted
) {
303 return STATUS_MORE_ENTRIES
;
305 *sendlen
= gensec_socket
->orig_send_len
;
306 gensec_socket
->orig_send_len
= 0;
311 /* Turn a normal socket into a potentially GENSEC wrapped socket */
312 /* CAREFUL: this function will steal 'current_socket' */
314 NTSTATUS
gensec_socket_init(struct gensec_security
*gensec_security
,
316 struct socket_context
*current_socket
,
317 struct tevent_context
*ev
,
318 void (*recv_handler
)(void *, uint16_t),
320 struct socket_context
**new_socket
)
322 struct gensec_socket
*gensec_socket
;
323 struct socket_context
*new_sock
;
326 nt_status
= socket_create_with_ops(mem_ctx
, &gensec_socket_ops
, &new_sock
,
327 SOCKET_TYPE_STREAM
, current_socket
->flags
| SOCKET_FLAG_ENCRYPT
);
328 if (!NT_STATUS_IS_OK(nt_status
)) {
333 new_sock
->state
= current_socket
->state
;
335 gensec_socket
= talloc(new_sock
, struct gensec_socket
);
336 if (gensec_socket
== NULL
) {
338 talloc_free(new_sock
);
339 return NT_STATUS_NO_MEMORY
;
342 new_sock
->private_data
= gensec_socket
;
343 gensec_socket
->socket
= current_socket
;
345 /* Nothing to do here, if we are not actually wrapping on this socket */
346 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
) &&
347 !gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
349 gensec_socket
->wrap
= false;
350 talloc_steal(gensec_socket
, current_socket
);
351 *new_socket
= new_sock
;
355 gensec_socket
->gensec_security
= gensec_security
;
357 gensec_socket
->wrap
= true;
358 gensec_socket
->eof
= false;
359 gensec_socket
->error
= NT_STATUS_OK
;
360 gensec_socket
->interrupted
= false;
361 gensec_socket
->in_extra_read
= 0;
363 gensec_socket
->read_buffer
= data_blob(NULL
, 0);
365 gensec_socket
->recv_handler
= recv_handler
;
366 gensec_socket
->recv_private
= recv_private
;
367 gensec_socket
->ev
= ev
;
369 gensec_socket
->packet
= packet_init(gensec_socket
);
370 if (gensec_socket
->packet
== NULL
) {
372 talloc_free(new_sock
);
373 return NT_STATUS_NO_MEMORY
;
376 packet_set_private(gensec_socket
->packet
, gensec_socket
);
377 packet_set_socket(gensec_socket
->packet
, gensec_socket
->socket
);
378 packet_set_callback(gensec_socket
->packet
, gensec_socket_unwrap
);
379 packet_set_full_request(gensec_socket
->packet
, gensec_socket_full_request
);
380 packet_set_error_handler(gensec_socket
->packet
, gensec_socket_error_handler
);
381 packet_set_serialise(gensec_socket
->packet
);
383 /* TODO: full-request that knows about maximum packet size */
385 talloc_steal(gensec_socket
, current_socket
);
386 *new_socket
= new_sock
;
391 static NTSTATUS
gensec_socket_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
393 set_socket_options(socket_get_fd(sock
), option
);
397 static char *gensec_socket_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
399 struct gensec_socket
*gensec
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
400 return socket_get_peer_name(gensec
->socket
, mem_ctx
);
403 static struct socket_address
*gensec_socket_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
405 struct gensec_socket
*gensec
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
406 return socket_get_peer_addr(gensec
->socket
, mem_ctx
);
409 static struct socket_address
*gensec_socket_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
411 struct gensec_socket
*gensec
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
412 return socket_get_my_addr(gensec
->socket
, mem_ctx
);
415 static int gensec_socket_get_fd(struct socket_context
*sock
)
417 struct gensec_socket
*gensec
= talloc_get_type(sock
->private_data
, struct gensec_socket
);
418 return socket_get_fd(gensec
->socket
);
421 static const struct socket_ops gensec_socket_ops
= {
423 .fn_init
= gensec_socket_init_fn
,
424 .fn_recv
= gensec_socket_recv
,
425 .fn_send
= gensec_socket_send
,
426 .fn_pending
= gensec_socket_pending
,
428 .fn_set_option
= gensec_socket_set_option
,
430 .fn_get_peer_name
= gensec_socket_get_peer_name
,
431 .fn_get_peer_addr
= gensec_socket_get_peer_addr
,
432 .fn_get_my_addr
= gensec_socket_get_my_addr
,
433 .fn_get_fd
= gensec_socket_get_fd