r17197: This patch moves the encryption of bulk data on SASL negotiated security
[kai/samba.git] / source4 / 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 };
45
46 static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
47 {
48         switch (sock->type) {
49         case SOCKET_TYPE_STREAM:
50                 break;
51         default:
52                 return NT_STATUS_INVALID_PARAMETER;
53         }
54
55         sock->backend_name = "gensec";
56
57         return NT_STATUS_OK;
58 }
59
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) 
62 {
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;
66                 return NT_STATUS_OK;
67         }
68
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);
75 }      
76
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)
79 {
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;
83         } else {
84                 gensec_socket->error = status;
85         }
86 }
87
88 static void gensec_socket_trigger_read(struct event_context *ev, 
89                                        struct timed_event *te, 
90                                        struct timeval t, void *private)
91 {
92         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
93
94         gensec_socket->in_extra_read++;
95         gensec_socket->recv_handler(gensec_socket->recv_private, EVENT_FD_READ);
96         gensec_socket->in_extra_read--;
97
98         /* It may well be that, having run the recv handler, we still
99          * have even more data waiting for us! 
100          */
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);
105         }
106 }
107
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) 
112 {
113         struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
114
115         gensec_socket->error = NT_STATUS_OK;
116
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
120                  * longer */
121                 packet_recv(gensec_socket->packet);
122
123                 if (gensec_socket->eof) {
124                         *nread = 0;
125                         return NT_STATUS_OK;
126                 }
127                 
128                 if (!NT_STATUS_IS_OK(gensec_socket->error)) {
129                         return gensec_socket->error;
130                 }
131
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 */
135                         *nread = 0;
136                         return STATUS_MORE_ENTRIES;
137                 }
138         }
139
140
141         *nread = MIN(wantlen, gensec_socket->read_buffer.length);
142         memcpy(buf, gensec_socket->read_buffer.data, *nread);
143
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);
148         }
149
150         gensec_socket->read_buffer.length -= *nread;
151         gensec_socket->read_buffer.data = talloc_realloc(gensec_socket, 
152                                                          gensec_socket->read_buffer.data, 
153                                                          uint8_t, 
154                                                          gensec_socket->read_buffer.length);
155
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);
164         }
165
166         return NT_STATUS_OK;
167 }
168
169 /* Completed SASL packet callback.  When we have a 'whole' SASL
170  * packet, decrypt it, and add it to the read buffer
171  *
172  * This function (and anything under it) MUST NOT call the event system
173  */
174 static NTSTATUS gensec_socket_unwrap(void *private, DATA_BLOB blob)
175 {
176         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
177         DATA_BLOB wrapped;
178         DATA_BLOB unwrapped;
179         NTSTATUS nt_status;
180         TALLOC_CTX *mem_ctx;
181         uint32_t packet_size;
182
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;
187         }
188
189         wrapped = data_blob_const(blob.data + 4, blob.length - 4);
190
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;
195         }
196
197         mem_ctx = talloc_new(gensec_socket);
198         if (!mem_ctx) {
199                 return NT_STATUS_NO_MEMORY;
200         }
201         nt_status = gensec_unwrap(gensec_socket->gensec_security, 
202                                   mem_ctx,
203                                   &wrapped, &unwrapped);
204         if (!NT_STATUS_IS_OK(nt_status)) {
205                 talloc_free(mem_ctx);
206                 return nt_status;
207         }
208         /* We could change this into a linked list, and have
209          * gensec_socket_recv() and gensec_socket_pending() walk the
210          * linked list */
211
212         nt_status = data_blob_append(gensec_socket, &gensec_socket->read_buffer, 
213                                      unwrapped.data, unwrapped.length); 
214         talloc_free(mem_ctx);
215         return nt_status;
216 }
217
218 /* when the data is sent, we know we have not been interrupted */
219 static void send_callback(void *private) 
220 {
221         struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
222         gensec_socket->interrupted = False;
223 }
224
225 /*
226   send data, but only as much as we allow in one packet.  
227
228   If this returns STATUS_MORE_ENTRIES, the caller must retry with
229   exactly the same data, or a NULL blob.
230 */
231 static NTSTATUS gensec_socket_send(struct socket_context *sock, 
232                                    const DATA_BLOB *blob, size_t *sendlen)
233 {
234         NTSTATUS nt_status;
235         struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
236         DATA_BLOB unwrapped, wrapped, out;
237         TALLOC_CTX *mem_ctx;
238         size_t max_input_size;
239
240         *sendlen = 0;
241
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);
246
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;
251                 } else {
252                         *sendlen = gensec_socket->orig_send_len;
253                         gensec_socket->orig_send_len = 0;
254                         return NT_STATUS_OK;
255                 }
256         }
257
258         mem_ctx = talloc_new(gensec_socket);
259         if (!mem_ctx) {
260                 return NT_STATUS_NO_MEMORY;
261         }
262
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));
265         
266         nt_status = gensec_wrap(gensec_socket->gensec_security, 
267                                 mem_ctx,
268                                 &unwrapped, &wrapped);
269         if (!NT_STATUS_IS_OK(nt_status)) {
270                 talloc_free(mem_ctx);
271                 return nt_status;
272         }
273         
274         out = data_blob_talloc(mem_ctx, NULL, 4);
275         if (!out.data) {
276                 talloc_free(mem_ctx);
277                 return NT_STATUS_NO_MEMORY;
278         }
279         RSIVAL(out.data, 0, wrapped.length);
280
281         nt_status = data_blob_append(gensec_socket, &out, wrapped.data, wrapped.length);
282
283         if (!NT_STATUS_IS_OK(nt_status)) {
284                 talloc_free(mem_ctx);
285                 return nt_status;
286         }
287         
288         gensec_socket->interrupted = True;
289         gensec_socket->error = NT_STATUS_OK;
290         gensec_socket->orig_send_len
291                 = unwrapped.length;
292
293         nt_status = packet_send_callback(gensec_socket->packet, 
294                                          out,
295                                          send_callback, gensec_socket);
296
297         talloc_free(mem_ctx);
298
299         packet_queue_run(gensec_socket->packet);
300
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;
305         } else {
306                 *sendlen = gensec_socket->orig_send_len;
307                 gensec_socket->orig_send_len = 0;
308                 return NT_STATUS_OK;
309         }
310 }
311
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),
316                                           void *recv_private)
317 {
318         struct gensec_socket *gensec_socket;
319         struct socket_context *new_sock;
320         NTSTATUS nt_status;
321
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)) {
325                 return socket;
326         }
327
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)) {
331                 return NULL;
332         }
333
334         gensec_socket = talloc(new_sock, struct gensec_socket);
335         if (gensec_socket == NULL) {
336                 return NULL;
337         }
338
339         gensec_socket->eof = False;
340         gensec_socket->error = NT_STATUS_OK;
341         gensec_socket->interrupted = False;
342         gensec_socket->in_extra_read = 0;
343
344         gensec_socket->read_buffer = data_blob(NULL, 0);
345
346         gensec_socket->gensec_security = gensec_security;
347         gensec_socket->socket          = socket;
348         if (talloc_reference(gensec_socket, socket) == NULL) {
349                 return NULL;
350         }
351         gensec_socket->recv_handler    = recv_handler;
352         gensec_socket->recv_private    = recv_private;
353         gensec_socket->ev              = ev;
354
355         new_sock->private_data    = gensec_socket;
356
357         gensec_socket->packet = packet_init(gensec_socket);
358         if (gensec_socket->packet == NULL) {
359                 return NULL;
360         }
361
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);
368
369         /* TODO: full-request that knows about maximum packet size */
370
371         new_sock->state = socket->state;
372
373         return new_sock;
374 }
375
376
377 static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val)
378 {
379         set_socket_options(socket_get_fd(sock), option);
380         return NT_STATUS_OK;
381 }
382
383 static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
384 {
385         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
386         return socket_get_peer_name(gensec->socket, mem_ctx);
387 }
388
389 static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
390 {
391         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
392         return socket_get_peer_addr(gensec->socket, mem_ctx);
393 }
394
395 static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
396 {
397         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
398         return socket_get_my_addr(gensec->socket, mem_ctx);
399 }
400
401 static int gensec_socket_get_fd(struct socket_context *sock)
402 {
403         struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
404         return socket_get_fd(gensec->socket);
405 }
406
407 static const struct socket_ops gensec_socket_ops = {
408         .name                   = "gensec",
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,
413
414         .fn_set_option          = gensec_socket_set_option,
415
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
420 };
421