r19507: Merge my DSO fixes branch. Building Samba's libraries as shared libraries
[samba.git] / source / auth / gensec / socket.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    GENSEC socket interface
5
6    Copyright (C) Andrew Bartlett 2006
7  
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "lib/socket/socket.h"
26 #include "lib/stream/packet.h"
27 #include "auth/gensec/gensec.h"
28
29 static const struct socket_ops gensec_socket_ops;
30
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 */
37         size_t orig_send_len;
38         BOOL eof;
39         NTSTATUS error;
40         BOOL interrupted;
41         void (*recv_handler)(void *, uint16_t);
42         void *recv_private;
43         int in_extra_read;
44         BOOL wrap; /* Should we be wrapping on this socket at all? */
45 };
46
47 static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
48 {
49         switch (sock->type) {
50         case SOCKET_TYPE_STREAM:
51                 break;
52         default:
53                 return NT_STATUS_INVALID_PARAMETER;
54         }
55
56         sock->backend_name = "gensec";
57
58         return NT_STATUS_OK;
59 }
60
61 /* These functions are for use here only (public because SPNEGO must
62  * use them for recursion) */
63 _PUBLIC_ NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security, 
64                              TALLOC_CTX *mem_ctx, 
65                              const DATA_BLOB *in, 
66                              DATA_BLOB *out,
67                              size_t *len_processed) 
68 {
69         if (!gensec_security->ops->wrap_packets) {
70                 NTSTATUS nt_status;
71                 size_t max_input_size;
72                 DATA_BLOB unwrapped, wrapped;
73                 max_input_size = gensec_max_input_size(gensec_security);
74                 unwrapped = data_blob_const(in->data, MIN(max_input_size, (size_t)in->length));
75                 
76                 nt_status = gensec_wrap(gensec_security, 
77                                         mem_ctx,
78                                         &unwrapped, &wrapped);
79                 if (!NT_STATUS_IS_OK(nt_status)) {
80                         talloc_free(mem_ctx);
81                         return nt_status;
82                 }
83                 
84                 *out = data_blob_talloc(mem_ctx, NULL, 4);
85                 if (!out->data) {
86                         return NT_STATUS_NO_MEMORY;
87                 }
88                 RSIVAL(out->data, 0, wrapped.length);
89                 
90                 nt_status = data_blob_append(mem_ctx, out, wrapped.data, wrapped.length);
91                 
92                 if (!NT_STATUS_IS_OK(nt_status)) {
93                         return nt_status;
94                 }
95                 *len_processed = unwrapped.length;
96                 return nt_status;
97         }
98         return gensec_security->ops->wrap_packets(gensec_security, mem_ctx, in, out,
99                                                   len_processed);
100 }
101
102 /* These functions are for use here only (public because SPNEGO must
103  * use them for recursion) */
104 NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security, 
105                                         TALLOC_CTX *mem_ctx, 
106                                         const DATA_BLOB *in, 
107                                         DATA_BLOB *out,
108                                         size_t *len_processed) 
109 {
110         if (!gensec_security->ops->unwrap_packets) {
111                 DATA_BLOB wrapped;
112                 NTSTATUS nt_status;
113                 size_t packet_size;
114                 if (in->length < 4) {
115                         /* Missing the header we already had! */
116                         DEBUG(0, ("Asked to unwrap packet of bogus length!  How did we get the short packet?!\n"));
117                         return NT_STATUS_INVALID_PARAMETER;
118                 }
119                 
120                 packet_size = RIVAL(in->data, 0);
121                 
122                 wrapped = data_blob_const(in->data + 4, packet_size);
123                 
124                 if (wrapped.length > (in->length - 4)) {
125                         DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d!  How did we get this?!\n",
126                                   (int)wrapped.length, (int)(in->length - 4)));
127                         return NT_STATUS_INTERNAL_ERROR;
128                 }
129                 
130                 nt_status = gensec_unwrap(gensec_security, 
131                                           mem_ctx,
132                                           &wrapped, out);
133                 if (!NT_STATUS_IS_OK(nt_status)) {
134                         return nt_status;
135                 }
136                 
137                 *len_processed = packet_size + 4;
138                 return nt_status;
139         }
140         return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out,
141                                                     len_processed);
142 }
143
144 /* These functions are for use here only (public because SPNEGO must
145  * use them for recursion) */
146 NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security,
147                                     DATA_BLOB blob, size_t *size) 
148 {
149         if (gensec_security->ops->packet_full_request) {
150                 return gensec_security->ops->packet_full_request(gensec_security,
151                                                                  blob, size);
152         }
153         if (gensec_security->ops->unwrap_packets) {
154                 if (blob.length) {
155                         *size = blob.length;
156                         return NT_STATUS_OK;
157                 }
158                 return STATUS_MORE_ENTRIES;
159         }
160         return packet_full_request_u32(NULL, blob, size);
161 }
162
163 static NTSTATUS gensec_socket_full_request(void *private, DATA_BLOB blob, size_t *size) 
164 {
165         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
166         struct gensec_security *gensec_security = gensec_socket->gensec_security;
167         return gensec_packet_full_request(gensec_security, blob, size);
168 }
169
170 /* Try to figure out how much data is waiting to be read */
171 static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending) 
172 {
173         struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
174         if (!gensec_socket->wrap) {
175                 return socket_pending(gensec_socket->socket, npending);
176         }
177
178         if (gensec_socket->read_buffer.length > 0) {
179                 *npending = gensec_socket->read_buffer.length;
180                 return NT_STATUS_OK;
181         }
182
183         /* This is a lie.  We hope the decrypted data will always be
184          * less than this value, so the application just gets a short
185          * read.  Without reading and decrypting it, we can't tell.
186          * If the SASL mech does compression, then we just need to
187          * manually trigger read events */
188         return socket_pending(gensec_socket->socket, npending);
189 }      
190
191 /* Note if an error occours, so we can return it up the stack */
192 static void gensec_socket_error_handler(void *private, NTSTATUS status)
193 {
194         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
195         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
196                 gensec_socket->eof = True;
197         } else {
198                 gensec_socket->error = status;
199         }
200 }
201
202 static void gensec_socket_trigger_read(struct event_context *ev, 
203                                        struct timed_event *te, 
204                                        struct timeval t, void *private)
205 {
206         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
207
208         gensec_socket->in_extra_read++;
209         gensec_socket->recv_handler(gensec_socket->recv_private, EVENT_FD_READ);
210         gensec_socket->in_extra_read--;
211
212         /* It may well be that, having run the recv handler, we still
213          * have even more data waiting for us! 
214          */
215         if (gensec_socket->read_buffer.length && gensec_socket->recv_handler) {
216                 /* Schedule this funcion to run again */
217                 event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(), 
218                                 gensec_socket_trigger_read, gensec_socket);
219         }
220 }
221
222 /* These two routines could be changed to use a circular buffer of
223  * some kind, or linked lists, or ... */
224 static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf,
225                                    size_t wantlen, size_t *nread) 
226 {
227         struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
228
229         if (!gensec_socket->wrap) {
230                 return socket_recv(gensec_socket->socket, buf, wantlen, nread);
231         }
232
233         gensec_socket->error = NT_STATUS_OK;
234
235         if (gensec_socket->read_buffer.length == 0) {
236                 /* Process any data on the socket, into the read buffer. At
237                  * this point, the socket is not available for read any
238                  * longer */
239                 packet_recv(gensec_socket->packet);
240
241                 if (gensec_socket->eof) {
242                         *nread = 0;
243                         return NT_STATUS_OK;
244                 }
245                 
246                 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
247                         return gensec_socket->error;
248                 }
249
250                 if (gensec_socket->read_buffer.length == 0) {
251                         /* Clearly we don't have the entire SASL packet yet,
252                          * so it has not been written into the buffer */
253                         *nread = 0;
254                         return STATUS_MORE_ENTRIES;
255                 }
256         }
257
258
259         *nread = MIN(wantlen, gensec_socket->read_buffer.length);
260         memcpy(buf, gensec_socket->read_buffer.data, *nread);
261
262         if (gensec_socket->read_buffer.length > *nread) {
263                 memmove(gensec_socket->read_buffer.data, 
264                         gensec_socket->read_buffer.data + *nread, 
265                         gensec_socket->read_buffer.length - *nread);
266         }
267
268         gensec_socket->read_buffer.length -= *nread;
269         gensec_socket->read_buffer.data = talloc_realloc(gensec_socket, 
270                                                          gensec_socket->read_buffer.data, 
271                                                          uint8_t, 
272                                                          gensec_socket->read_buffer.length);
273
274         if (gensec_socket->read_buffer.length && 
275             gensec_socket->in_extra_read == 0 && 
276             gensec_socket->recv_handler) {
277                 /* Manually call a read event, to get this moving
278                  * again (as the socket should be dry, so the normal
279                  * event handler won't trigger) */
280                 event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(), 
281                                 gensec_socket_trigger_read, gensec_socket);
282         }
283
284         return NT_STATUS_OK;
285 }
286
287 /* Completed SASL packet callback.  When we have a 'whole' SASL
288  * packet, decrypt it, and add it to the read buffer
289  *
290  * This function (and anything under it) MUST NOT call the event system
291  */
292 static NTSTATUS gensec_socket_unwrap(void *private, DATA_BLOB blob)
293 {
294         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
295         DATA_BLOB unwrapped;
296         NTSTATUS nt_status;
297         TALLOC_CTX *mem_ctx;
298         size_t packet_size;
299
300         mem_ctx = talloc_new(gensec_socket);
301         if (!mem_ctx) {
302                 return NT_STATUS_NO_MEMORY;
303         }
304         nt_status = gensec_unwrap_packets(gensec_socket->gensec_security, 
305                                           mem_ctx,
306                                           &blob, &unwrapped, 
307                                           &packet_size);
308         if (!NT_STATUS_IS_OK(nt_status)) {
309                 talloc_free(mem_ctx);
310                 return nt_status;
311         }
312
313         if (packet_size != blob.length) {
314                 DEBUG(0, ("gensec_socket_unwrap: Did not consume entire packet!\n"));
315                 return NT_STATUS_INTERNAL_ERROR;
316         }
317
318         /* We could change this into a linked list, and have
319          * gensec_socket_recv() and gensec_socket_pending() walk the
320          * linked list */
321
322         nt_status = data_blob_append(gensec_socket, &gensec_socket->read_buffer, 
323                                      unwrapped.data, unwrapped.length); 
324         talloc_free(mem_ctx);
325         return nt_status;
326 }
327
328 /* when the data is sent, we know we have not been interrupted */
329 static void send_callback(void *private) 
330 {
331         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
332         gensec_socket->interrupted = False;
333 }
334
335 /*
336   send data, but only as much as we allow in one packet.  
337
338   If this returns STATUS_MORE_ENTRIES, the caller must retry with
339   exactly the same data, or a NULL blob.
340 */
341 static NTSTATUS gensec_socket_send(struct socket_context *sock, 
342                                    const DATA_BLOB *blob, size_t *sendlen)
343 {
344         NTSTATUS nt_status;
345         struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
346         DATA_BLOB wrapped;
347         TALLOC_CTX *mem_ctx;
348
349         if (!gensec_socket->wrap) {
350                 return socket_send(gensec_socket->socket, blob, sendlen);
351         }
352
353         *sendlen = 0;
354
355         /* We have have been interupted, so the caller should be
356          * giving us the same data again.  */
357         if (gensec_socket->interrupted) {
358                 packet_queue_run(gensec_socket->packet);
359
360                 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
361                         return gensec_socket->error;
362                 } else if (gensec_socket->interrupted) {
363                         return STATUS_MORE_ENTRIES;
364                 } else {
365                         *sendlen = gensec_socket->orig_send_len;
366                         gensec_socket->orig_send_len = 0;
367                         return NT_STATUS_OK;
368                 }
369         }
370
371         mem_ctx = talloc_new(gensec_socket);
372         if (!mem_ctx) {
373                 return NT_STATUS_NO_MEMORY;
374         }
375
376         nt_status = gensec_wrap_packets(gensec_socket->gensec_security, 
377                                         mem_ctx,
378                                         blob, &wrapped, 
379                                         &gensec_socket->orig_send_len);
380         if (!NT_STATUS_IS_OK(nt_status)) {
381                 talloc_free(mem_ctx);
382                 return nt_status;
383         }
384         
385         gensec_socket->interrupted = True;
386         gensec_socket->error = NT_STATUS_OK;
387
388         nt_status = packet_send_callback(gensec_socket->packet, 
389                                          wrapped,
390                                          send_callback, gensec_socket);
391
392         talloc_free(mem_ctx);
393
394         packet_queue_run(gensec_socket->packet);
395
396         if (!NT_STATUS_IS_OK(gensec_socket->error)) {
397                 return gensec_socket->error;
398         } else if (gensec_socket->interrupted) {
399                 return STATUS_MORE_ENTRIES;
400         } else {
401                 *sendlen = gensec_socket->orig_send_len;
402                 gensec_socket->orig_send_len = 0;
403                 return NT_STATUS_OK;
404         }
405 }
406
407 /* Turn a normal socket into a potentially GENSEC wrapped socket */
408
409 NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
410                             struct socket_context *current_socket,
411                             struct event_context *ev,
412                             void (*recv_handler)(void *, uint16_t),
413                             void *recv_private,
414                             struct socket_context **new_socket)
415 {
416         struct gensec_socket *gensec_socket;
417         struct socket_context *new_sock;
418         NTSTATUS nt_status;
419
420         nt_status = socket_create_with_ops(current_socket, &gensec_socket_ops, &new_sock, 
421                                            SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT);
422         if (!NT_STATUS_IS_OK(nt_status)) {
423                 *new_socket = NULL;
424                 return nt_status;
425         }
426
427         new_sock->state = current_socket->state;
428
429         gensec_socket = talloc(new_sock, struct gensec_socket);
430         if (gensec_socket == NULL) {
431                 *new_socket = NULL;
432                 return NT_STATUS_NO_MEMORY;
433         }
434
435         new_sock->private_data       = gensec_socket;
436         gensec_socket->socket        = current_socket;
437
438         if (talloc_reference(gensec_socket, current_socket) == NULL) {
439                 *new_socket = NULL;
440                 return NT_STATUS_NO_MEMORY;
441         }
442
443         /* Nothing to do here, if we are not actually wrapping on this socket */
444         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
445             !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
446                 
447                 gensec_socket->wrap = False;
448                 *new_socket = new_sock;
449                 return NT_STATUS_OK;
450         }
451
452         gensec_socket->gensec_security = gensec_security;
453
454         gensec_socket->wrap          = True;
455         gensec_socket->eof           = False;
456         gensec_socket->error         = NT_STATUS_OK;
457         gensec_socket->interrupted   = False;
458         gensec_socket->in_extra_read = 0;
459
460         gensec_socket->read_buffer   = data_blob(NULL, 0);
461
462         gensec_socket->recv_handler  = recv_handler;
463         gensec_socket->recv_private  = recv_private;
464         gensec_socket->ev            = ev;
465
466         gensec_socket->packet = packet_init(gensec_socket);
467         if (gensec_socket->packet == NULL) {
468                 *new_socket = NULL;
469                 return NT_STATUS_NO_MEMORY;
470         }
471
472         packet_set_private(gensec_socket->packet, gensec_socket);
473         packet_set_socket(gensec_socket->packet, gensec_socket->socket);
474         packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
475         packet_set_full_request(gensec_socket->packet, gensec_socket_full_request);
476         packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
477         packet_set_serialise(gensec_socket->packet);
478
479         /* TODO: full-request that knows about maximum packet size */
480
481         *new_socket = new_sock;
482         return NT_STATUS_OK;
483 }
484
485
486 static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val)
487 {
488         set_socket_options(socket_get_fd(sock), option);
489         return NT_STATUS_OK;
490 }
491
492 static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
493 {
494         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
495         return socket_get_peer_name(gensec->socket, mem_ctx);
496 }
497
498 static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
499 {
500         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
501         return socket_get_peer_addr(gensec->socket, mem_ctx);
502 }
503
504 static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
505 {
506         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
507         return socket_get_my_addr(gensec->socket, mem_ctx);
508 }
509
510 static int gensec_socket_get_fd(struct socket_context *sock)
511 {
512         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
513         return socket_get_fd(gensec->socket);
514 }
515
516 static const struct socket_ops gensec_socket_ops = {
517         .name                   = "gensec",
518         .fn_init                = gensec_socket_init_fn,
519         .fn_recv                = gensec_socket_recv,
520         .fn_send                = gensec_socket_send,
521         .fn_pending             = gensec_socket_pending,
522
523         .fn_set_option          = gensec_socket_set_option,
524
525         .fn_get_peer_name       = gensec_socket_get_peer_name,
526         .fn_get_peer_addr       = gensec_socket_get_peer_addr,
527         .fn_get_my_addr         = gensec_socket_get_my_addr,
528         .fn_get_fd              = gensec_socket_get_fd
529 };
530