root/source4/auth/gensec/socket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gensec_socket_init_fn
  2. gensec_wrap_packets
  3. gensec_unwrap_packets
  4. gensec_packet_full_request
  5. gensec_socket_full_request
  6. gensec_socket_pending
  7. gensec_socket_error_handler
  8. gensec_socket_trigger_read
  9. gensec_socket_recv
  10. gensec_socket_unwrap
  11. send_callback
  12. gensec_socket_send
  13. gensec_socket_init
  14. gensec_socket_set_option
  15. gensec_socket_get_peer_name
  16. gensec_socket_get_peer_addr
  17. gensec_socket_get_my_addr
  18. gensec_socket_get_fd

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

/* [<][>][^][v][top][bottom][index][help] */