root/source4/libcli/smb2/request.c

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

DEFINITIONS

This source file includes following definitions.
  1. smb2_setup_bufinfo
  2. smb2_request_destructor
  3. smb2_request_init
  4. smb2_request_init_tree
  5. smb2_request_destroy
  6. smb2_request_receive
  7. smb2_request_is_error
  8. smb2_request_is_ok
  9. smb2_oob
  10. smb2_padding_size
  11. smb2_padding_fix
  12. smb2_grow_buffer
  13. smb2_pull_o16s16_blob
  14. smb2_push_o16s16_blob
  15. smb2_push_o16s32_blob
  16. smb2_push_o32s32_blob
  17. smb2_push_s32o32_blob
  18. smb2_pull_o16s32_blob
  19. smb2_pull_o32s32_blob
  20. smb2_pull_o16As32_blob
  21. smb2_pull_s32o32_blob
  22. smb2_pull_s32o16_blob
  23. smb2_pull_o16s16_string
  24. smb2_push_o16s16_string
  25. smb2_push_handle
  26. smb2_pull_handle

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    SMB2 client request handling
   5 
   6    Copyright (C) Andrew Tridgell        2005
   7    Copyright (C) Stefan Metzmacher      2005
   8    
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "libcli/raw/libcliraw.h"
  25 #include "libcli/smb2/smb2.h"
  26 #include "../lib/util/dlinklist.h"
  27 #include "lib/events/events.h"
  28 #include "libcli/smb2/smb2_calls.h"
  29 
  30 /* fill in the bufinfo */
  31 void smb2_setup_bufinfo(struct smb2_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         req->in.bufinfo.mem_ctx    = req;
  34         req->in.bufinfo.flags      = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
  35         req->in.bufinfo.align_base = req->in.buffer;
  36         if (req->in.dynamic) {
  37                 req->in.bufinfo.data       = req->in.dynamic;
  38                 req->in.bufinfo.data_size  = req->in.body_size - req->in.body_fixed;
  39         } else {
  40                 req->in.bufinfo.data       = NULL;
  41                 req->in.bufinfo.data_size  = 0;
  42         }
  43 }
  44 
  45 
  46 /* destroy a request structure */
  47 static int smb2_request_destructor(struct smb2_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  48 {
  49         if (req->transport) {
  50                 /* remove it from the list of pending requests (a null op if
  51                    its not in the list) */
  52                 DLIST_REMOVE(req->transport->pending_recv, req);
  53         }
  54         return 0;
  55 }
  56 
  57 /*
  58   initialise a smb2 request
  59 */
  60 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
     /* [<][>][^][v][top][bottom][index][help] */
  61                                        uint16_t body_fixed_size, bool body_dynamic_present,
  62                                        uint32_t body_dynamic_size)
  63 {
  64         struct smb2_request *req;
  65         uint64_t seqnum;
  66 
  67         if (body_dynamic_present) {
  68                 if (body_dynamic_size == 0) {
  69                         body_dynamic_size = 1;
  70                 }
  71         } else {
  72                 body_dynamic_size = 0;
  73         }
  74 
  75         req = talloc(transport, struct smb2_request);
  76         if (req == NULL) return NULL;
  77 
  78         seqnum = transport->seqnum++;
  79         if (seqnum == UINT64_MAX) {
  80                 seqnum = transport->seqnum++;
  81         }
  82 
  83         req->state     = SMB2_REQUEST_INIT;
  84         req->transport = transport;
  85         req->session   = NULL;
  86         req->tree      = NULL;
  87         req->seqnum    = seqnum;
  88         req->status    = NT_STATUS_OK;
  89         req->async.fn  = NULL;
  90         req->next = req->prev = NULL;
  91 
  92         ZERO_STRUCT(req->cancel);
  93         ZERO_STRUCT(req->in);
  94 
  95         req->out.size      = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
  96 
  97         req->out.allocated = req->out.size + body_dynamic_size;
  98         req->out.buffer    = talloc_array(req, uint8_t, req->out.allocated);
  99         if (req->out.buffer == NULL) {
 100                 talloc_free(req);
 101                 return NULL;
 102         }
 103 
 104         req->out.hdr       = req->out.buffer + NBT_HDR_SIZE;
 105         req->out.body      = req->out.hdr + SMB2_HDR_BODY;
 106         req->out.body_fixed= body_fixed_size;
 107         req->out.body_size = body_fixed_size;
 108         req->out.dynamic   = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
 109 
 110         SIVAL(req->out.hdr, 0,                          SMB2_MAGIC);
 111         SSVAL(req->out.hdr, SMB2_HDR_LENGTH,            SMB2_HDR_BODY);
 112         SSVAL(req->out.hdr, SMB2_HDR_EPOCH,             0);
 113         SIVAL(req->out.hdr, SMB2_HDR_STATUS,            0);
 114         SSVAL(req->out.hdr, SMB2_HDR_OPCODE,            opcode);
 115         SSVAL(req->out.hdr, SMB2_HDR_CREDIT,            0);
 116         SIVAL(req->out.hdr, SMB2_HDR_FLAGS,             0);
 117         SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND,      0);
 118         SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID,                req->seqnum);
 119         SIVAL(req->out.hdr, SMB2_HDR_PID,               0);
 120         SIVAL(req->out.hdr, SMB2_HDR_TID,               0);
 121         SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID,                0);
 122         memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
 123 
 124         /* set the length of the fixed body part and +1 if there's a dynamic part also */
 125         SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
 126 
 127         /* 
 128          * if we have a dynamic part, make sure the first byte
 129          * which is always be part of the packet is initialized
 130          */
 131         if (body_dynamic_size) {
 132                 req->out.size += 1;
 133                 SCVAL(req->out.dynamic, 0, 0);
 134         }
 135 
 136         talloc_set_destructor(req, smb2_request_destructor);
 137 
 138         return req;
 139 }
 140 
 141 /*
 142     initialise a smb2 request for tree operations
 143 */
 144 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
     /* [<][>][^][v][top][bottom][index][help] */
 145                                             uint16_t body_fixed_size, bool body_dynamic_present,
 146                                             uint32_t body_dynamic_size)
 147 {
 148         struct smb2_request *req = smb2_request_init(tree->session->transport, opcode, 
 149                                                      body_fixed_size, body_dynamic_present,
 150                                                      body_dynamic_size);
 151         if (req == NULL) return NULL;
 152 
 153         SBVAL(req->out.hdr,  SMB2_HDR_SESSION_ID, tree->session->uid);
 154         SIVAL(req->out.hdr,  SMB2_HDR_TID, tree->tid);
 155         req->session = tree->session;
 156         req->tree = tree;
 157 
 158         return req;     
 159 }
 160 
 161 /* destroy a request structure and return final status */
 162 NTSTATUS smb2_request_destroy(struct smb2_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 163 {
 164         NTSTATUS status;
 165 
 166         /* this is the error code we give the application for when a
 167            _send() call fails completely */
 168         if (!req) return NT_STATUS_UNSUCCESSFUL;
 169 
 170         if (req->state == SMB2_REQUEST_ERROR &&
 171             NT_STATUS_IS_OK(req->status)) {
 172                 status = NT_STATUS_INTERNAL_ERROR;
 173         } else {
 174                 status = req->status;
 175         }
 176 
 177         talloc_free(req);
 178         return status;
 179 }
 180 
 181 /*
 182   receive a response to a packet
 183 */
 184 bool smb2_request_receive(struct smb2_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 185 {
 186         /* req can be NULL when a send has failed. This eliminates lots of NULL
 187            checks in each module */
 188         if (!req) return false;
 189 
 190         /* keep receiving packets until this one is replied to */
 191         while (req->state <= SMB2_REQUEST_RECV) {
 192                 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
 193                         return false;
 194                 }
 195         }
 196 
 197         return req->state == SMB2_REQUEST_DONE;
 198 }
 199 
 200 /* Return true if the last packet was in error */
 201 bool smb2_request_is_error(struct smb2_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 202 {
 203         return NT_STATUS_IS_ERR(req->status);
 204 }
 205 
 206 /* Return true if the last packet was OK */
 207 bool smb2_request_is_ok(struct smb2_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 208 {
 209         return NT_STATUS_IS_OK(req->status);
 210 }
 211 
 212 /*
 213   check if a range in the reply body is out of bounds
 214 */
 215 bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
     /* [<][>][^][v][top][bottom][index][help] */
 216 {
 217         if (size == 0) {
 218                 /* zero bytes is never out of range */
 219                 return false;
 220         }
 221         /* be careful with wraparound! */
 222         if ((uintptr_t)ptr < (uintptr_t)buf->body ||
 223             (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
 224             size > buf->body_size ||
 225             (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
 226                 return true;
 227         }
 228         return false;
 229 }
 230 
 231 size_t smb2_padding_size(uint32_t offset, size_t n)
     /* [<][>][^][v][top][bottom][index][help] */
 232 {
 233         if ((offset & (n-1)) == 0) return 0;
 234         return n - (offset & (n-1));
 235 }
 236 
 237 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
     /* [<][>][^][v][top][bottom][index][help] */
 238 {
 239         if (buf->dynamic == (buf->body + buf->body_fixed)) {
 240                 return 1;
 241         }
 242         return 0;
 243 }
 244 
 245 /*
 246   grow a SMB2 buffer by the specified amount
 247 */
 248 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
     /* [<][>][^][v][top][bottom][index][help] */
 249 {
 250         size_t dynamic_ofs;
 251         uint8_t *buffer_ptr;
 252         uint32_t newsize = buf->size + increase;
 253 
 254         /* a packet size should be limited a bit */
 255         if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
 256 
 257         if (newsize <= buf->allocated) return NT_STATUS_OK;
 258 
 259         dynamic_ofs = buf->dynamic - buf->buffer;
 260 
 261         buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
 262         NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
 263 
 264         buf->buffer     = buffer_ptr;
 265         buf->hdr        = buf->buffer + NBT_HDR_SIZE;
 266         buf->body       = buf->hdr    + SMB2_HDR_BODY;
 267         buf->dynamic    = buf->buffer + dynamic_ofs;
 268         buf->allocated  = newsize;
 269 
 270         return NT_STATUS_OK;
 271 }
 272 
 273 /*
 274   pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
 275   the ptr points to the start of the offset/length pair
 276 */
 277 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 278 {
 279         uint16_t ofs, size;
 280         if (smb2_oob(buf, ptr, 4)) {
 281                 return NT_STATUS_INVALID_PARAMETER;
 282         }
 283         ofs  = SVAL(ptr, 0);
 284         size = SVAL(ptr, 2);
 285         if (ofs == 0) {
 286                 *blob = data_blob(NULL, 0);
 287                 return NT_STATUS_OK;
 288         }
 289         if (smb2_oob(buf, buf->hdr + ofs, size)) {
 290                 return NT_STATUS_INVALID_PARAMETER;
 291         }
 292         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
 293         NT_STATUS_HAVE_NO_MEMORY(blob->data);
 294         return NT_STATUS_OK;
 295 }
 296 
 297 /*
 298   push a uint16_t ofs/ uint16_t length/blob triple into a data blob
 299   the ofs points to the start of the offset/length pair, and is relative
 300   to the body start
 301 */
 302 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, 
     /* [<][>][^][v][top][bottom][index][help] */
 303                                uint16_t ofs, DATA_BLOB blob)
 304 {
 305         NTSTATUS status;
 306         size_t offset;
 307         size_t padding_length;
 308         size_t padding_fix;
 309         uint8_t *ptr = buf->body+ofs;
 310 
 311         if (buf->dynamic == NULL) {
 312                 return NT_STATUS_INVALID_PARAMETER;
 313         }
 314 
 315         /* we have only 16 bit for the size */
 316         if (blob.length > 0xFFFF) {
 317                 return NT_STATUS_INVALID_PARAMETER;
 318         }
 319 
 320         /* check if there're enough room for ofs and size */
 321         if (smb2_oob(buf, ptr, 4)) {
 322                 return NT_STATUS_INVALID_PARAMETER;
 323         }
 324 
 325         if (blob.data == NULL) {
 326                 if (blob.length != 0) {
 327                         return NT_STATUS_INTERNAL_ERROR;
 328                 }
 329                 SSVAL(ptr, 0, 0);
 330                 SSVAL(ptr, 2, 0);
 331                 return NT_STATUS_OK;
 332         }
 333 
 334         offset = buf->dynamic - buf->hdr;
 335         padding_length = smb2_padding_size(offset, 2);
 336         offset += padding_length;
 337         padding_fix = smb2_padding_fix(buf);
 338 
 339         SSVAL(ptr, 0, offset);
 340         SSVAL(ptr, 2, blob.length);
 341 
 342         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
 343         NT_STATUS_NOT_OK_RETURN(status);
 344 
 345         memset(buf->dynamic, 0, padding_length);
 346         buf->dynamic += padding_length;
 347 
 348         memcpy(buf->dynamic, blob.data, blob.length);
 349         buf->dynamic += blob.length;
 350 
 351         buf->size += blob.length + padding_length - padding_fix;
 352         buf->body_size += blob.length + padding_length;
 353 
 354         return NT_STATUS_OK;
 355 }
 356 
 357 
 358 /*
 359   push a uint16_t ofs/ uint32_t length/blob triple into a data blob
 360   the ofs points to the start of the offset/length pair, and is relative
 361   to the body start
 362 */
 363 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, 
     /* [<][>][^][v][top][bottom][index][help] */
 364                                uint16_t ofs, DATA_BLOB blob)
 365 {
 366         NTSTATUS status;
 367         size_t offset;
 368         size_t padding_length;
 369         size_t padding_fix;
 370         uint8_t *ptr = buf->body+ofs;
 371 
 372         if (buf->dynamic == NULL) {
 373                 return NT_STATUS_INVALID_PARAMETER;
 374         }
 375 
 376         /* check if there're enough room for ofs and size */
 377         if (smb2_oob(buf, ptr, 6)) {
 378                 return NT_STATUS_INVALID_PARAMETER;
 379         }
 380 
 381         if (blob.data == NULL) {
 382                 if (blob.length != 0) {
 383                         return NT_STATUS_INTERNAL_ERROR;
 384                 }
 385                 SSVAL(ptr, 0, 0);
 386                 SIVAL(ptr, 2, 0);
 387                 return NT_STATUS_OK;
 388         }
 389 
 390         offset = buf->dynamic - buf->hdr;
 391         padding_length = smb2_padding_size(offset, 2);
 392         offset += padding_length;
 393         padding_fix = smb2_padding_fix(buf);
 394 
 395         SSVAL(ptr, 0, offset);
 396         SIVAL(ptr, 2, blob.length);
 397 
 398         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
 399         NT_STATUS_NOT_OK_RETURN(status);
 400 
 401         memset(buf->dynamic, 0, padding_length);
 402         buf->dynamic += padding_length;
 403 
 404         memcpy(buf->dynamic, blob.data, blob.length);
 405         buf->dynamic += blob.length;
 406 
 407         buf->size += blob.length + padding_length - padding_fix;
 408         buf->body_size += blob.length + padding_length;
 409 
 410         return NT_STATUS_OK;
 411 }
 412 
 413 
 414 /*
 415   push a uint32_t ofs/ uint32_t length/blob triple into a data blob
 416   the ofs points to the start of the offset/length pair, and is relative
 417   to the body start
 418 */
 419 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, 
     /* [<][>][^][v][top][bottom][index][help] */
 420                                uint32_t ofs, DATA_BLOB blob)
 421 {
 422         NTSTATUS status;
 423         size_t offset;
 424         size_t padding_length;
 425         size_t padding_fix;
 426         uint8_t *ptr = buf->body+ofs;
 427 
 428         if (buf->dynamic == NULL) {
 429                 return NT_STATUS_INVALID_PARAMETER;
 430         }
 431 
 432         /* check if there're enough room for ofs and size */
 433         if (smb2_oob(buf, ptr, 8)) {
 434                 return NT_STATUS_INVALID_PARAMETER;
 435         }
 436 
 437         if (blob.data == NULL) {
 438                 if (blob.length != 0) {
 439                         return NT_STATUS_INTERNAL_ERROR;
 440                 }
 441                 SIVAL(ptr, 0, 0);
 442                 SIVAL(ptr, 4, 0);
 443                 return NT_STATUS_OK;
 444         }
 445 
 446         offset = buf->dynamic - buf->hdr;
 447         padding_length = smb2_padding_size(offset, 8);
 448         offset += padding_length;
 449         padding_fix = smb2_padding_fix(buf);
 450 
 451         SIVAL(ptr, 0, offset);
 452         SIVAL(ptr, 4, blob.length);
 453 
 454         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
 455         NT_STATUS_NOT_OK_RETURN(status);
 456 
 457         memset(buf->dynamic, 0, padding_length);
 458         buf->dynamic += padding_length;
 459 
 460         memcpy(buf->dynamic, blob.data, blob.length);
 461         buf->dynamic += blob.length;
 462 
 463         buf->size += blob.length + padding_length - padding_fix;
 464         buf->body_size += blob.length + padding_length;
 465 
 466         return NT_STATUS_OK;
 467 }
 468 
 469 
 470 /*
 471   push a uint32_t length/ uint32_t ofs/blob triple into a data blob
 472   the ofs points to the start of the length/offset pair, and is relative
 473   to the body start
 474 */
 475 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, 
     /* [<][>][^][v][top][bottom][index][help] */
 476                                uint32_t ofs, DATA_BLOB blob)
 477 {
 478         NTSTATUS status;
 479         size_t offset;
 480         size_t padding_length;
 481         size_t padding_fix;
 482         uint8_t *ptr = buf->body+ofs;
 483 
 484         if (buf->dynamic == NULL) {
 485                 return NT_STATUS_INVALID_PARAMETER;
 486         }
 487 
 488         /* check if there're enough room for ofs and size */
 489         if (smb2_oob(buf, ptr, 8)) {
 490                 return NT_STATUS_INVALID_PARAMETER;
 491         }
 492 
 493         if (blob.data == NULL) {
 494                 if (blob.length != 0) {
 495                         return NT_STATUS_INTERNAL_ERROR;
 496                 }
 497                 SIVAL(ptr, 0, 0);
 498                 SIVAL(ptr, 4, 0);
 499                 return NT_STATUS_OK;
 500         }
 501 
 502         offset = buf->dynamic - buf->hdr;
 503         padding_length = smb2_padding_size(offset, 8);
 504         offset += padding_length;
 505         padding_fix = smb2_padding_fix(buf);
 506 
 507         SIVAL(ptr, 0, blob.length);
 508         SIVAL(ptr, 4, offset);
 509 
 510         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
 511         NT_STATUS_NOT_OK_RETURN(status);
 512 
 513         memset(buf->dynamic, 0, padding_length);
 514         buf->dynamic += padding_length;
 515 
 516         memcpy(buf->dynamic, blob.data, blob.length);
 517         buf->dynamic += blob.length;
 518 
 519         buf->size += blob.length + padding_length - padding_fix;
 520         buf->body_size += blob.length + padding_length;
 521 
 522         return NT_STATUS_OK;
 523 }
 524 
 525 /*
 526   pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
 527   the ptr points to the start of the offset/length pair
 528 */
 529 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 530 {
 531         uint16_t ofs;
 532         uint32_t size;
 533 
 534         if (smb2_oob(buf, ptr, 6)) {
 535                 return NT_STATUS_INVALID_PARAMETER;
 536         }
 537         ofs  = SVAL(ptr, 0);
 538         size = IVAL(ptr, 2);
 539         if (ofs == 0) {
 540                 *blob = data_blob(NULL, 0);
 541                 return NT_STATUS_OK;
 542         }
 543         if (smb2_oob(buf, buf->hdr + ofs, size)) {
 544                 return NT_STATUS_INVALID_PARAMETER;
 545         }
 546         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
 547         NT_STATUS_HAVE_NO_MEMORY(blob->data);
 548         return NT_STATUS_OK;
 549 }
 550 
 551 /*
 552   pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
 553   the ptr points to the start of the offset/length pair
 554 */
 555 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 556 {
 557         uint32_t ofs, size;
 558         if (smb2_oob(buf, ptr, 8)) {
 559                 return NT_STATUS_INVALID_PARAMETER;
 560         }
 561         ofs  = IVAL(ptr, 0);
 562         size = IVAL(ptr, 4);
 563         if (ofs == 0) {
 564                 *blob = data_blob(NULL, 0);
 565                 return NT_STATUS_OK;
 566         }
 567         if (smb2_oob(buf, buf->hdr + ofs, size)) {
 568                 return NT_STATUS_INVALID_PARAMETER;
 569         }
 570         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
 571         NT_STATUS_HAVE_NO_MEMORY(blob->data);
 572         return NT_STATUS_OK;
 573 }
 574 
 575 /*
 576   pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
 577   the ptr points to the start of the offset/length pair
 578   
 579   In this varient the uint16_t is padded by an extra 2 bytes, making
 580   the size aligned on 4 byte boundary
 581 */
 582 NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 583 {
 584         uint32_t ofs, size;
 585         if (smb2_oob(buf, ptr, 8)) {
 586                 return NT_STATUS_INVALID_PARAMETER;
 587         }
 588         ofs  = SVAL(ptr, 0);
 589         size = IVAL(ptr, 4);
 590         if (ofs == 0) {
 591                 *blob = data_blob(NULL, 0);
 592                 return NT_STATUS_OK;
 593         }
 594         if (smb2_oob(buf, buf->hdr + ofs, size)) {
 595                 return NT_STATUS_INVALID_PARAMETER;
 596         }
 597         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
 598         NT_STATUS_HAVE_NO_MEMORY(blob->data);
 599         return NT_STATUS_OK;
 600 }
 601 
 602 /*
 603   pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
 604   the ptr points to the start of the offset/length pair
 605 */
 606 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 607 {
 608         uint32_t ofs, size;
 609         if (smb2_oob(buf, ptr, 8)) {
 610                 return NT_STATUS_INVALID_PARAMETER;
 611         }
 612         size = IVAL(ptr, 0);
 613         ofs  = IVAL(ptr, 4);
 614         if (ofs == 0) {
 615                 *blob = data_blob(NULL, 0);
 616                 return NT_STATUS_OK;
 617         }
 618         if (smb2_oob(buf, buf->hdr + ofs, size)) {
 619                 return NT_STATUS_INVALID_PARAMETER;
 620         }
 621         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
 622         NT_STATUS_HAVE_NO_MEMORY(blob->data);
 623         return NT_STATUS_OK;
 624 }
 625 
 626 /*
 627   pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
 628   the ptr points to the start of the offset/length pair
 629 */
 630 NTSTATUS smb2_pull_s32o16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 631 {
 632         uint32_t ofs, size;
 633         if (smb2_oob(buf, ptr, 8)) {
 634                 return NT_STATUS_INVALID_PARAMETER;
 635         }
 636         size = IVAL(ptr, 0);
 637         ofs  = SVAL(ptr, 4);
 638         if (ofs == 0) {
 639                 *blob = data_blob(NULL, 0);
 640                 return NT_STATUS_OK;
 641         }
 642         if (smb2_oob(buf, buf->hdr + ofs, size)) {
 643                 return NT_STATUS_INVALID_PARAMETER;
 644         }
 645         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
 646         NT_STATUS_HAVE_NO_MEMORY(blob->data);
 647         return NT_STATUS_OK;
 648 }
 649 
 650 /*
 651   pull a string in a uint16_t ofs/ uint16_t length/blob format
 652   UTF-16 without termination
 653 */
 654 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 655                                  uint8_t *ptr, const char **str)
 656 {
 657         DATA_BLOB blob;
 658         NTSTATUS status;
 659         void *vstr;
 660         bool ret;
 661 
 662         status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
 663         NT_STATUS_NOT_OK_RETURN(status);
 664 
 665         if (blob.data == NULL) {
 666                 *str = NULL;
 667                 return NT_STATUS_OK;
 668         }
 669 
 670         if (blob.length == 0) {
 671                 char *s;
 672                 s = talloc_strdup(mem_ctx, "");
 673                 NT_STATUS_HAVE_NO_MEMORY(s);
 674                 *str = s;
 675                 return NT_STATUS_OK;
 676         }
 677 
 678         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
 679                                      blob.data, blob.length, &vstr, NULL, false);
 680         data_blob_free(&blob);
 681         (*str) = (char *)vstr;
 682         if (!ret) {
 683                 return NT_STATUS_ILLEGAL_CHARACTER;
 684         }
 685         return NT_STATUS_OK;
 686 }
 687 
 688 /*
 689   push a string in a uint16_t ofs/ uint16_t length/blob format
 690   UTF-16 without termination
 691 */
 692 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
     /* [<][>][^][v][top][bottom][index][help] */
 693                                  uint16_t ofs, const char *str)
 694 {
 695         DATA_BLOB blob;
 696         NTSTATUS status;
 697         bool ret;
 698 
 699         if (str == NULL) {
 700                 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
 701         }
 702 
 703         if (*str == 0) {
 704                 blob.data = discard_const_p(uint8_t, str);
 705                 blob.length = 0;
 706                 return smb2_push_o16s16_blob(buf, ofs, blob);
 707         }
 708 
 709         ret = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16, 
 710                                      str, strlen(str), (void **)&blob.data, &blob.length, 
 711                                          false);
 712         if (!ret) {
 713                 return NT_STATUS_ILLEGAL_CHARACTER;
 714         }
 715 
 716         status = smb2_push_o16s16_blob(buf, ofs, blob);
 717         data_blob_free(&blob);
 718         return status;
 719 }
 720 
 721 /*
 722   push a file handle into a buffer
 723 */
 724 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
     /* [<][>][^][v][top][bottom][index][help] */
 725 {
 726         SBVAL(data, 0, h->data[0]);
 727         SBVAL(data, 8, h->data[1]);
 728 }
 729 
 730 /*
 731   pull a file handle from a buffer
 732 */
 733 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
     /* [<][>][^][v][top][bottom][index][help] */
 734 {
 735         h->data[0] = BVAL(ptr, 0);
 736         h->data[1] = BVAL(ptr, 8);
 737 }

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