s3:winbindd fix use of uninitialized variables
[Samba.git] / source4 / auth / gensec / socket.c
blobc89e080232331ac247696fe2bb68e8fbc777e21c
1 /*
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/>.
22 #include "includes.h"
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 */
38 size_t orig_send_len;
39 bool eof;
40 NTSTATUS error;
41 bool interrupted;
42 void (*recv_handler)(void *, uint16_t);
43 void *recv_private;
44 int in_extra_read;
45 bool wrap; /* Should we be wrapping on this socket at all? */
48 static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
50 switch (sock->type) {
51 case SOCKET_TYPE_STREAM:
52 break;
53 default:
54 return NT_STATUS_INVALID_PARAMETER;
57 sock->backend_name = "gensec";
59 return NT_STATUS_OK;
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;
79 return NT_STATUS_OK;
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;
96 } else {
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
137 * longer */
138 packet_recv(gensec_socket->packet);
140 if (gensec_socket->eof) {
141 *nread = 0;
142 return NT_STATUS_OK;
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 */
152 *nread = 0;
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,
170 uint8_t,
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);
183 return NT_STATUS_OK;
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);
194 DATA_BLOB unwrapped;
195 NTSTATUS nt_status;
196 TALLOC_CTX *mem_ctx;
197 size_t packet_size;
199 mem_ctx = talloc_new(gensec_socket);
200 if (!mem_ctx) {
201 return NT_STATUS_NO_MEMORY;
203 nt_status = gensec_unwrap_packets(gensec_socket->gensec_security,
204 mem_ctx,
205 &blob, &unwrapped,
206 &packet_size);
207 if (!NT_STATUS_IS_OK(nt_status)) {
208 talloc_free(mem_ctx);
209 return nt_status;
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
220 * linked list */
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);
229 return NT_STATUS_OK;
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)
248 NTSTATUS nt_status;
249 struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
250 DATA_BLOB wrapped;
251 TALLOC_CTX *mem_ctx;
253 if (!gensec_socket->wrap) {
254 return socket_send(gensec_socket->socket, blob, sendlen);
257 *sendlen = 0;
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;
268 } else {
269 *sendlen = gensec_socket->orig_send_len;
270 gensec_socket->orig_send_len = 0;
271 return NT_STATUS_OK;
275 mem_ctx = talloc_new(gensec_socket);
276 if (!mem_ctx) {
277 return NT_STATUS_NO_MEMORY;
280 nt_status = gensec_wrap_packets(gensec_socket->gensec_security,
281 mem_ctx,
282 blob, &wrapped,
283 &gensec_socket->orig_send_len);
284 if (!NT_STATUS_IS_OK(nt_status)) {
285 talloc_free(mem_ctx);
286 return nt_status;
289 gensec_socket->interrupted = true;
290 gensec_socket->error = NT_STATUS_OK;
292 nt_status = packet_send_callback(gensec_socket->packet,
293 wrapped,
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;
304 } else {
305 *sendlen = gensec_socket->orig_send_len;
306 gensec_socket->orig_send_len = 0;
307 return NT_STATUS_OK;
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,
315 TALLOC_CTX *mem_ctx,
316 struct socket_context *current_socket,
317 struct tevent_context *ev,
318 void (*recv_handler)(void *, uint16_t),
319 void *recv_private,
320 struct socket_context **new_socket)
322 struct gensec_socket *gensec_socket;
323 struct socket_context *new_sock;
324 NTSTATUS nt_status;
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)) {
329 *new_socket = NULL;
330 return nt_status;
333 new_sock->state = current_socket->state;
335 gensec_socket = talloc(new_sock, struct gensec_socket);
336 if (gensec_socket == NULL) {
337 *new_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;
352 return NT_STATUS_OK;
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) {
371 *new_socket = 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;
387 return NT_STATUS_OK;
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);
394 return NT_STATUS_OK;
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 = {
422 .name = "gensec",
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