root/source4/lib/stream/packet.c

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

DEFINITIONS

This source file includes following definitions.
  1. packet_destructor
  2. packet_init
  3. packet_set_callback
  4. packet_set_error_handler
  5. packet_set_private
  6. packet_set_full_request
  7. packet_set_socket
  8. packet_set_event_context
  9. packet_set_fde
  10. packet_set_serialise
  11. packet_set_initial_read
  12. packet_set_nofree
  13. packet_set_unreliable_select
  14. packet_error
  15. packet_eof
  16. packet_next_event
  17. packet_recv
  18. packet_recv_disable
  19. packet_recv_enable
  20. packet_queue_run
  21. packet_send_callback
  22. packet_send
  23. packet_full_request_nbt
  24. packet_full_request_u32

   1 /* 
   2    Unix SMB/CIFS mplementation.
   3 
   4    helper layer for breaking up streams into discrete requests
   5    
   6    Copyright (C) Andrew Tridgell  2005
   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 
  23 #include "includes.h"
  24 #include "../lib/util/dlinklist.h"
  25 #include "lib/events/events.h"
  26 #include "lib/socket/socket.h"
  27 #include "lib/stream/packet.h"
  28 #include "libcli/raw/smb.h"
  29 
  30 struct packet_context {
  31         packet_callback_fn_t callback;
  32         packet_full_request_fn_t full_request;
  33         packet_error_handler_fn_t error_handler;
  34         DATA_BLOB partial;
  35         uint32_t num_read;
  36         uint32_t initial_read;
  37         struct socket_context *sock;
  38         struct tevent_context *ev;
  39         size_t packet_size;
  40         void *private_data;
  41         struct tevent_fd *fde;
  42         bool serialise;
  43         int processing;
  44         bool recv_disable;
  45         bool nofree;
  46 
  47         bool busy;
  48         bool destructor_called;
  49 
  50         bool unreliable_select;
  51 
  52         struct send_element {
  53                 struct send_element *next, *prev;
  54                 DATA_BLOB blob;
  55                 size_t nsent;
  56                 packet_send_callback_fn_t send_callback;
  57                 void *send_callback_private;
  58         } *send_queue;
  59 };
  60 
  61 /*
  62   a destructor used when we are processing packets to prevent freeing of this
  63   context while it is being used
  64 */
  65 static int packet_destructor(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
  66 {
  67         if (pc->busy) {
  68                 pc->destructor_called = true;
  69                 /* now we refuse the talloc_free() request. The free will
  70                    happen again in the packet_recv() code */
  71                 return -1;
  72         }
  73 
  74         return 0;
  75 }
  76 
  77 
  78 /*
  79   initialise a packet receiver
  80 */
  81 _PUBLIC_ struct packet_context *packet_init(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  82 {
  83         struct packet_context *pc = talloc_zero(mem_ctx, struct packet_context);
  84         if (pc != NULL) {
  85                 talloc_set_destructor(pc, packet_destructor);
  86         }
  87         return pc;
  88 }
  89 
  90 
  91 /*
  92   set the request callback, called when a full request is ready
  93 */
  94 _PUBLIC_ void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callback)
     /* [<][>][^][v][top][bottom][index][help] */
  95 {
  96         pc->callback = callback;
  97 }
  98 
  99 /*
 100   set the error handler
 101 */
 102 _PUBLIC_ void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler)
     /* [<][>][^][v][top][bottom][index][help] */
 103 {
 104         pc->error_handler = handler;
 105 }
 106 
 107 /*
 108   set the private pointer passed to the callback functions
 109 */
 110 _PUBLIC_ void packet_set_private(struct packet_context *pc, void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
 111 {
 112         pc->private_data = private_data;
 113 }
 114 
 115 /*
 116   set the full request callback. Should return as follows:
 117      NT_STATUS_OK == blob is a full request.
 118      STATUS_MORE_ENTRIES == blob is not complete yet
 119      any error == blob is not a valid 
 120 */
 121 _PUBLIC_ void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback)
     /* [<][>][^][v][top][bottom][index][help] */
 122 {
 123         pc->full_request = callback;
 124 }
 125 
 126 /*
 127   set a socket context to use. You must set a socket_context
 128 */
 129 _PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock)
     /* [<][>][^][v][top][bottom][index][help] */
 130 {
 131         pc->sock = sock;
 132 }
 133 
 134 /*
 135   set an event context. If this is set then the code will ensure that
 136   packets arrive with separate events, by creating a immediate event
 137   for any secondary packets when more than one packet is read at one
 138   time on a socket. This can matter for code that relies on not
 139   getting more than one packet per event
 140 */
 141 _PUBLIC_ void packet_set_event_context(struct packet_context *pc, struct tevent_context *ev)
     /* [<][>][^][v][top][bottom][index][help] */
 142 {
 143         pc->ev = ev;
 144 }
 145 
 146 /*
 147   tell the packet layer the fde for the socket
 148 */
 149 _PUBLIC_ void packet_set_fde(struct packet_context *pc, struct tevent_fd *fde)
     /* [<][>][^][v][top][bottom][index][help] */
 150 {
 151         pc->fde = fde;
 152 }
 153 
 154 /*
 155   tell the packet layer to serialise requests, so we don't process two
 156   requests at once on one connection. You must have set the
 157   event_context and fde
 158 */
 159 _PUBLIC_ void packet_set_serialise(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 160 {
 161         pc->serialise = true;
 162 }
 163 
 164 /*
 165   tell the packet layer how much to read when starting a new packet
 166   this ensures it doesn't overread
 167 */
 168 _PUBLIC_ void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read)
     /* [<][>][^][v][top][bottom][index][help] */
 169 {
 170         pc->initial_read = initial_read;
 171 }
 172 
 173 /*
 174   tell the packet system not to steal/free blobs given to packet_send()
 175 */
 176 _PUBLIC_ void packet_set_nofree(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 177 {
 178         pc->nofree = true;
 179 }
 180 
 181 /*
 182   tell the packet system that select/poll/epoll on the underlying
 183   socket may not be a reliable way to determine if data is available
 184   for receive. This happens with underlying socket systems such as the
 185   one implemented on top of GNUTLS, where there may be data in
 186   encryption/compression buffers that could be received by
 187   socket_recv(), while there is no data waiting at the real socket
 188   level as seen by select/poll/epoll. The GNUTLS library is supposed
 189   to cope with this by always leaving some data sitting in the socket
 190   buffer, but it does not seem to be reliable.
 191  */
 192 _PUBLIC_ void packet_set_unreliable_select(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 193 {
 194         pc->unreliable_select = true;
 195 }
 196 
 197 /*
 198   tell the caller we have an error
 199 */
 200 static void packet_error(struct packet_context *pc, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 201 {
 202         pc->sock = NULL;
 203         if (pc->error_handler) {
 204                 pc->error_handler(pc->private_data, status);
 205                 return;
 206         }
 207         /* default error handler is to free the callers private pointer */
 208         if (!NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
 209                 DEBUG(0,("packet_error on %s - %s\n", 
 210                          talloc_get_name(pc->private_data), nt_errstr(status)));
 211         }
 212         talloc_free(pc->private_data);
 213         return;
 214 }
 215 
 216 
 217 /*
 218   tell the caller we have EOF
 219 */
 220 static void packet_eof(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 221 {
 222         packet_error(pc, NT_STATUS_END_OF_FILE);
 223 }
 224 
 225 
 226 /*
 227   used to put packets on event boundaries
 228 */
 229 static void packet_next_event(struct tevent_context *ev, struct tevent_timer *te, 
     /* [<][>][^][v][top][bottom][index][help] */
 230                               struct timeval t, void *private_data)
 231 {
 232         struct packet_context *pc = talloc_get_type(private_data, struct packet_context);
 233         if (pc->num_read != 0 && pc->packet_size != 0 &&
 234             pc->packet_size <= pc->num_read) {
 235                 packet_recv(pc);
 236         }
 237 }
 238 
 239 
 240 /*
 241   call this when the socket becomes readable to kick off the whole
 242   stream parsing process
 243 */
 244 _PUBLIC_ void packet_recv(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 245 {
 246         size_t npending;
 247         NTSTATUS status;
 248         size_t nread = 0;
 249         DATA_BLOB blob;
 250         bool recv_retry = false;
 251 
 252         if (pc->processing) {
 253                 EVENT_FD_NOT_READABLE(pc->fde);
 254                 pc->processing++;
 255                 return;
 256         }
 257 
 258         if (pc->recv_disable) {
 259                 EVENT_FD_NOT_READABLE(pc->fde);
 260                 return;
 261         }
 262 
 263         if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) {
 264                 goto next_partial;
 265         }
 266 
 267         if (pc->packet_size != 0) {
 268                 /* we've already worked out how long this next packet is, so skip the
 269                    socket_pending() call */
 270                 npending = pc->packet_size - pc->num_read;
 271         } else if (pc->initial_read != 0) {
 272                 npending = pc->initial_read - pc->num_read;
 273         } else {
 274                 if (pc->sock) {
 275                         status = socket_pending(pc->sock, &npending);
 276                 } else {
 277                         status = NT_STATUS_CONNECTION_DISCONNECTED;
 278                 }
 279                 if (!NT_STATUS_IS_OK(status)) {
 280                         packet_error(pc, status);
 281                         return;
 282                 }
 283         }
 284 
 285         if (npending == 0) {
 286                 packet_eof(pc);
 287                 return;
 288         }
 289 
 290 again:
 291 
 292         if (npending + pc->num_read < npending) {
 293                 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
 294                 return;
 295         }
 296 
 297         if (npending + pc->num_read < pc->num_read) {
 298                 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
 299                 return;
 300         }
 301 
 302         /* possibly expand the partial packet buffer */
 303         if (npending + pc->num_read > pc->partial.length) {
 304                 if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) {
 305                         packet_error(pc, NT_STATUS_NO_MEMORY);
 306                         return;
 307                 }
 308         }
 309 
 310         if (pc->partial.length < pc->num_read + npending) {
 311                 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
 312                 return;
 313         }
 314 
 315         if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) {
 316                 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
 317                 return;
 318         }
 319         if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) {
 320                 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
 321                 return;
 322         }
 323 
 324         status = socket_recv(pc->sock, pc->partial.data + pc->num_read, 
 325                              npending, &nread);
 326 
 327         if (NT_STATUS_IS_ERR(status)) {
 328                 packet_error(pc, status);
 329                 return;
 330         }
 331         if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
 332                 nread = 0;
 333                 status = NT_STATUS_OK;
 334         }
 335         if (!NT_STATUS_IS_OK(status)) {
 336                 return;
 337         }
 338 
 339         if (nread == 0 && !recv_retry) {
 340                 packet_eof(pc);
 341                 return;
 342         }
 343 
 344         pc->num_read += nread;
 345 
 346         if (pc->unreliable_select && nread != 0) {
 347                 recv_retry = true;
 348                 status = socket_pending(pc->sock, &npending);
 349                 if (!NT_STATUS_IS_OK(status)) {
 350                         packet_error(pc, status);
 351                         return;
 352                 }
 353                 if (npending != 0) {
 354                         goto again;
 355                 }
 356         }
 357 
 358 next_partial:
 359         if (pc->partial.length != pc->num_read) {
 360                 if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) {
 361                         packet_error(pc, NT_STATUS_NO_MEMORY);
 362                         return;
 363                 }
 364         }
 365 
 366         /* see if its a full request */
 367         blob = pc->partial;
 368         blob.length = pc->num_read;
 369         status = pc->full_request(pc->private_data, blob, &pc->packet_size);
 370         if (NT_STATUS_IS_ERR(status)) {
 371                 packet_error(pc, status);
 372                 return;
 373         }
 374         if (!NT_STATUS_IS_OK(status)) {
 375                 return;
 376         }
 377 
 378         if (pc->packet_size > pc->num_read) {
 379                 /* the caller made an error */
 380                 DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n",
 381                          (long)pc->packet_size, (long)pc->num_read));
 382                 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
 383                 return;
 384         }
 385 
 386         /* it is a full request - give it to the caller */
 387         blob = pc->partial;
 388         blob.length = pc->num_read;
 389 
 390         if (pc->packet_size < pc->num_read) {
 391                 pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, 
 392                                                pc->num_read - pc->packet_size);
 393                 if (pc->partial.data == NULL) {
 394                         packet_error(pc, NT_STATUS_NO_MEMORY);
 395                         return;
 396                 }
 397                 /* Trunate the blob sent to the caller to only the packet length */
 398                 if (!data_blob_realloc(pc, &blob, pc->packet_size)) {
 399                         packet_error(pc, NT_STATUS_NO_MEMORY);
 400                         return;
 401                 }
 402         } else {
 403                 pc->partial = data_blob(NULL, 0);
 404         }
 405         pc->num_read -= pc->packet_size;
 406         pc->packet_size = 0;
 407         
 408         if (pc->serialise) {
 409                 pc->processing = 1;
 410         }
 411 
 412         pc->busy = true;
 413 
 414         status = pc->callback(pc->private_data, blob);
 415 
 416         pc->busy = false;
 417 
 418         if (pc->destructor_called) {
 419                 talloc_free(pc);
 420                 return;
 421         }
 422 
 423         if (pc->processing) {
 424                 if (pc->processing > 1) {
 425                         EVENT_FD_READABLE(pc->fde);
 426                 }
 427                 pc->processing = 0;
 428         }
 429 
 430         if (!NT_STATUS_IS_OK(status)) {
 431                 packet_error(pc, status);
 432                 return;
 433         }
 434 
 435         /* Have we consumed the whole buffer yet? */
 436         if (pc->partial.length == 0) {
 437                 return;
 438         }
 439 
 440         /* we got multiple packets in one tcp read */
 441         if (pc->ev == NULL) {
 442                 goto next_partial;
 443         }
 444 
 445         blob = pc->partial;
 446         blob.length = pc->num_read;
 447 
 448         status = pc->full_request(pc->private_data, blob, &pc->packet_size);
 449         if (NT_STATUS_IS_ERR(status)) {
 450                 packet_error(pc, status);
 451                 return;
 452         }
 453 
 454         if (!NT_STATUS_IS_OK(status)) {
 455                 return;
 456         }
 457 
 458         event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc);
 459 }
 460 
 461 
 462 /*
 463   temporarily disable receiving 
 464 */
 465 _PUBLIC_ void packet_recv_disable(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 466 {
 467         EVENT_FD_NOT_READABLE(pc->fde);
 468         pc->recv_disable = true;
 469 }
 470 
 471 /*
 472   re-enable receiving 
 473 */
 474 _PUBLIC_ void packet_recv_enable(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 475 {
 476         EVENT_FD_READABLE(pc->fde);
 477         pc->recv_disable = false;
 478         if (pc->num_read != 0 && pc->packet_size >= pc->num_read) {
 479                 event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc);
 480         }
 481 }
 482 
 483 /*
 484   trigger a run of the send queue
 485 */
 486 _PUBLIC_ void packet_queue_run(struct packet_context *pc)
     /* [<][>][^][v][top][bottom][index][help] */
 487 {
 488         while (pc->send_queue) {
 489                 struct send_element *el = pc->send_queue;
 490                 NTSTATUS status;
 491                 size_t nwritten;
 492                 DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent,
 493                                                  el->blob.length - el->nsent);
 494 
 495                 status = socket_send(pc->sock, &blob, &nwritten);
 496 
 497                 if (NT_STATUS_IS_ERR(status)) {
 498                         packet_error(pc, status);
 499                         return;
 500                 }
 501                 if (!NT_STATUS_IS_OK(status)) {
 502                         return;
 503                 }
 504                 el->nsent += nwritten;
 505                 if (el->nsent == el->blob.length) {
 506                         DLIST_REMOVE(pc->send_queue, el);
 507                         if (el->send_callback) {
 508                                 pc->busy = true;
 509                                 el->send_callback(el->send_callback_private);
 510                                 pc->busy = false;
 511                                 if (pc->destructor_called) {
 512                                         talloc_free(pc);
 513                                         return;
 514                                 }
 515                         }
 516                         talloc_free(el);
 517                 }
 518         }
 519 
 520         /* we're out of requests to send, so don't wait for write
 521            events any more */
 522         EVENT_FD_NOT_WRITEABLE(pc->fde);
 523 }
 524 
 525 /*
 526   put a packet in the send queue.  When the packet is actually sent,
 527   call send_callback.  
 528 
 529   Useful for operations that must occour after sending a message, such
 530   as the switch to SASL encryption after as sucessful LDAP bind relpy.
 531 */
 532 _PUBLIC_ NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob,
     /* [<][>][^][v][top][bottom][index][help] */
 533                                        packet_send_callback_fn_t send_callback, 
 534                                        void *private_data)
 535 {
 536         struct send_element *el;
 537         el = talloc(pc, struct send_element);
 538         NT_STATUS_HAVE_NO_MEMORY(el);
 539 
 540         DLIST_ADD_END(pc->send_queue, el, struct send_element *);
 541         el->blob = blob;
 542         el->nsent = 0;
 543         el->send_callback = send_callback;
 544         el->send_callback_private = private_data;
 545 
 546         /* if we aren't going to free the packet then we must reference it
 547            to ensure it doesn't disappear before going out */
 548         if (pc->nofree) {
 549                 if (!talloc_reference(el, blob.data)) {
 550                         return NT_STATUS_NO_MEMORY;
 551                 }
 552         } else {
 553                 talloc_steal(el, blob.data);
 554         }
 555 
 556         if (private_data && !talloc_reference(el, private_data)) {
 557                 return NT_STATUS_NO_MEMORY;
 558         }
 559 
 560         EVENT_FD_WRITEABLE(pc->fde);
 561 
 562         return NT_STATUS_OK;
 563 }
 564 
 565 /*
 566   put a packet in the send queue
 567 */
 568 _PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
     /* [<][>][^][v][top][bottom][index][help] */
 569 {
 570         return packet_send_callback(pc, blob, NULL, NULL);
 571 }
 572 
 573 
 574 /*
 575   a full request checker for NBT formatted packets (first 3 bytes are length)
 576 */
 577 _PUBLIC_ NTSTATUS packet_full_request_nbt(void *private_data, DATA_BLOB blob, size_t *size)
     /* [<][>][^][v][top][bottom][index][help] */
 578 {
 579         if (blob.length < 4) {
 580                 return STATUS_MORE_ENTRIES;
 581         }
 582         *size = 4 + smb_len(blob.data);
 583         if (*size > blob.length) {
 584                 return STATUS_MORE_ENTRIES;
 585         }
 586         return NT_STATUS_OK;
 587 }
 588 
 589 
 590 /*
 591   work out if a packet is complete for protocols that use a 32 bit network byte
 592   order length
 593 */
 594 _PUBLIC_ NTSTATUS packet_full_request_u32(void *private_data, DATA_BLOB blob, size_t *size)
     /* [<][>][^][v][top][bottom][index][help] */
 595 {
 596         if (blob.length < 4) {
 597                 return STATUS_MORE_ENTRIES;
 598         }
 599         *size = 4 + RIVAL(blob.data, 0);
 600         if (*size > blob.length) {
 601                 return STATUS_MORE_ENTRIES;
 602         }
 603         return NT_STATUS_OK;
 604 }

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