s3-docs: overrided -> overridden
[Samba/gebeck_regimport.git] / source4 / libcli / smb2 / request.c
blob2fcc3813143582c1af638a6166d0f0299cae3c6a
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 client request handling
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005
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.
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.
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/>.
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"
30 /* fill in the bufinfo */
31 void smb2_setup_bufinfo(struct smb2_request *req)
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;
46 initialise a smb2 request
48 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
49 uint16_t body_fixed_size, bool body_dynamic_present,
50 uint32_t body_dynamic_size)
52 struct smb2_request *req;
53 uint32_t hdr_offset;
54 bool compound = false;
56 if (body_dynamic_present) {
57 if (body_dynamic_size == 0) {
58 body_dynamic_size = 1;
60 } else {
61 body_dynamic_size = 0;
64 req = talloc_zero(transport, struct smb2_request);
65 if (req == NULL) return NULL;
67 req->state = SMB2_REQUEST_INIT;
68 req->transport = transport;
70 hdr_offset = NBT_HDR_SIZE;
72 req->out.size = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
73 req->out.allocated = req->out.size + body_dynamic_size;
75 req->out.buffer = talloc_realloc(req, req->out.buffer,
76 uint8_t, req->out.allocated);
77 if (req->out.buffer == NULL) {
78 talloc_free(req);
79 return NULL;
82 req->out.hdr = req->out.buffer + hdr_offset;
83 req->out.body = req->out.hdr + SMB2_HDR_BODY;
84 req->out.body_fixed= body_fixed_size;
85 req->out.body_size = body_fixed_size;
86 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
88 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
89 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
90 SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE, 0);
91 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
92 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
93 SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0);
94 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
95 SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
96 SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, 0);
97 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
98 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
99 SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0);
100 memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
102 /* set the length of the fixed body part and +1 if there's a dynamic part also */
103 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
106 * if we have a dynamic part, make sure the first byte
107 * which is always be part of the packet is initialized
109 if (body_dynamic_size && !compound) {
110 req->out.size += 1;
111 SCVAL(req->out.dynamic, 0, 0);
114 return req;
118 initialise a smb2 request for tree operations
120 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
121 uint16_t body_fixed_size, bool body_dynamic_present,
122 uint32_t body_dynamic_size)
124 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
125 body_fixed_size, body_dynamic_present,
126 body_dynamic_size);
127 if (req == NULL) return NULL;
129 SIVAL(req->out.hdr, SMB2_HDR_PID, tree->session->pid);
130 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
131 req->session = tree->session;
132 req->tree = tree;
134 return req;
137 /* destroy a request structure and return final status */
138 NTSTATUS smb2_request_destroy(struct smb2_request *req)
140 NTSTATUS status;
142 /* this is the error code we give the application for when a
143 _send() call fails completely */
144 if (!req) return NT_STATUS_UNSUCCESSFUL;
146 if (req->state == SMB2_REQUEST_ERROR &&
147 NT_STATUS_IS_OK(req->status)) {
148 status = NT_STATUS_INTERNAL_ERROR;
149 } else {
150 status = req->status;
153 talloc_free(req);
154 return status;
158 receive a response to a packet
160 bool smb2_request_receive(struct smb2_request *req)
162 /* req can be NULL when a send has failed. This eliminates lots of NULL
163 checks in each module */
164 if (!req) return false;
166 /* keep receiving packets until this one is replied to */
167 while (req->state <= SMB2_REQUEST_RECV) {
168 if (tevent_loop_once(req->transport->ev) != 0) {
169 return false;
173 return req->state == SMB2_REQUEST_DONE;
176 /* Return true if the last packet was in error */
177 bool smb2_request_is_error(struct smb2_request *req)
179 return NT_STATUS_IS_ERR(req->status);
182 /* Return true if the last packet was OK */
183 bool smb2_request_is_ok(struct smb2_request *req)
185 return NT_STATUS_IS_OK(req->status);
189 check if a range in the reply body is out of bounds
191 bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
193 if (size == 0) {
194 /* zero bytes is never out of range */
195 return false;
197 /* be careful with wraparound! */
198 if ((uintptr_t)ptr < (uintptr_t)buf->body ||
199 (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
200 size > buf->body_size ||
201 (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
202 return true;
204 return false;
207 size_t smb2_padding_size(uint32_t offset, size_t n)
209 if ((offset & (n-1)) == 0) return 0;
210 return n - (offset & (n-1));
213 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
215 if (buf->dynamic == (buf->body + buf->body_fixed)) {
216 if (buf->dynamic != (buf->buffer + buf->size)) {
217 return 1;
220 return 0;
224 grow a SMB2 buffer by the specified amount
226 NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
228 size_t hdr_ofs;
229 size_t dynamic_ofs;
230 uint8_t *buffer_ptr;
231 uint32_t newsize = buf->size + increase;
233 /* a packet size should be limited a bit */
234 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
236 if (newsize <= buf->allocated) return NT_STATUS_OK;
238 hdr_ofs = buf->hdr - buf->buffer;
239 dynamic_ofs = buf->dynamic - buf->buffer;
241 buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
242 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
244 buf->buffer = buffer_ptr;
245 buf->hdr = buf->buffer + hdr_ofs;
246 buf->body = buf->hdr + SMB2_HDR_BODY;
247 buf->dynamic = buf->buffer + dynamic_ofs;
248 buf->allocated = newsize;
250 return NT_STATUS_OK;
254 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
255 the ptr points to the start of the offset/length pair
257 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
259 uint16_t ofs, size;
260 if (smb2_oob(buf, ptr, 4)) {
261 return NT_STATUS_INVALID_PARAMETER;
263 ofs = SVAL(ptr, 0);
264 size = SVAL(ptr, 2);
265 if (ofs == 0) {
266 *blob = data_blob(NULL, 0);
267 return NT_STATUS_OK;
269 if (smb2_oob(buf, buf->hdr + ofs, size)) {
270 return NT_STATUS_INVALID_PARAMETER;
272 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
273 NT_STATUS_HAVE_NO_MEMORY(blob->data);
274 return NT_STATUS_OK;
278 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
279 the ofs points to the start of the offset/length pair, and is relative
280 to the body start
282 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
283 uint16_t ofs, DATA_BLOB blob)
285 NTSTATUS status;
286 size_t offset;
287 size_t padding_length;
288 size_t padding_fix;
289 uint8_t *ptr = buf->body+ofs;
291 if (buf->dynamic == NULL) {
292 return NT_STATUS_INVALID_PARAMETER;
295 /* we have only 16 bit for the size */
296 if (blob.length > 0xFFFF) {
297 return NT_STATUS_INVALID_PARAMETER;
300 /* check if there're enough room for ofs and size */
301 if (smb2_oob(buf, ptr, 4)) {
302 return NT_STATUS_INVALID_PARAMETER;
305 if (blob.data == NULL) {
306 if (blob.length != 0) {
307 return NT_STATUS_INTERNAL_ERROR;
309 SSVAL(ptr, 0, 0);
310 SSVAL(ptr, 2, 0);
311 return NT_STATUS_OK;
314 offset = buf->dynamic - buf->hdr;
315 padding_length = smb2_padding_size(offset, 2);
316 offset += padding_length;
317 padding_fix = smb2_padding_fix(buf);
319 SSVAL(ptr, 0, offset);
320 SSVAL(ptr, 2, blob.length);
322 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
323 NT_STATUS_NOT_OK_RETURN(status);
325 memset(buf->dynamic, 0, padding_length);
326 buf->dynamic += padding_length;
328 memcpy(buf->dynamic, blob.data, blob.length);
329 buf->dynamic += blob.length;
331 buf->size += blob.length + padding_length - padding_fix;
332 buf->body_size += blob.length + padding_length;
334 return NT_STATUS_OK;
339 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
340 the ofs points to the start of the offset/length pair, and is relative
341 to the body start
343 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
344 uint16_t ofs, DATA_BLOB blob)
346 NTSTATUS status;
347 size_t offset;
348 size_t padding_length;
349 size_t padding_fix;
350 uint8_t *ptr = buf->body+ofs;
352 if (buf->dynamic == NULL) {
353 return NT_STATUS_INVALID_PARAMETER;
356 /* check if there're enough room for ofs and size */
357 if (smb2_oob(buf, ptr, 6)) {
358 return NT_STATUS_INVALID_PARAMETER;
361 if (blob.data == NULL) {
362 if (blob.length != 0) {
363 return NT_STATUS_INTERNAL_ERROR;
365 SSVAL(ptr, 0, 0);
366 SIVAL(ptr, 2, 0);
367 return NT_STATUS_OK;
370 offset = buf->dynamic - buf->hdr;
371 padding_length = smb2_padding_size(offset, 2);
372 offset += padding_length;
373 padding_fix = smb2_padding_fix(buf);
375 SSVAL(ptr, 0, offset);
376 SIVAL(ptr, 2, blob.length);
378 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
379 NT_STATUS_NOT_OK_RETURN(status);
381 memset(buf->dynamic, 0, padding_length);
382 buf->dynamic += padding_length;
384 memcpy(buf->dynamic, blob.data, blob.length);
385 buf->dynamic += blob.length;
387 buf->size += blob.length + padding_length - padding_fix;
388 buf->body_size += blob.length + padding_length;
390 return NT_STATUS_OK;
395 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
396 the ofs points to the start of the offset/length pair, and is relative
397 to the body start
399 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
400 uint32_t ofs, DATA_BLOB blob)
402 NTSTATUS status;
403 size_t offset;
404 size_t padding_length;
405 size_t padding_fix;
406 uint8_t *ptr = buf->body+ofs;
408 if (buf->dynamic == NULL) {
409 return NT_STATUS_INVALID_PARAMETER;
412 /* check if there're enough room for ofs and size */
413 if (smb2_oob(buf, ptr, 8)) {
414 return NT_STATUS_INVALID_PARAMETER;
417 if (blob.data == NULL) {
418 if (blob.length != 0) {
419 return NT_STATUS_INTERNAL_ERROR;
421 SIVAL(ptr, 0, 0);
422 SIVAL(ptr, 4, 0);
423 return NT_STATUS_OK;
426 offset = buf->dynamic - buf->hdr;
427 padding_length = smb2_padding_size(offset, 8);
428 offset += padding_length;
429 padding_fix = smb2_padding_fix(buf);
431 SIVAL(ptr, 0, offset);
432 SIVAL(ptr, 4, blob.length);
434 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
435 NT_STATUS_NOT_OK_RETURN(status);
437 memset(buf->dynamic, 0, padding_length);
438 buf->dynamic += padding_length;
440 memcpy(buf->dynamic, blob.data, blob.length);
441 buf->dynamic += blob.length;
443 buf->size += blob.length + padding_length - padding_fix;
444 buf->body_size += blob.length + padding_length;
446 return NT_STATUS_OK;
451 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
452 the ofs points to the start of the length/offset pair, and is relative
453 to the body start
455 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
456 uint32_t ofs, DATA_BLOB blob)
458 NTSTATUS status;
459 size_t offset;
460 size_t padding_length;
461 size_t padding_fix;
462 uint8_t *ptr = buf->body+ofs;
464 if (buf->dynamic == NULL) {
465 return NT_STATUS_INVALID_PARAMETER;
468 /* check if there're enough room for ofs and size */
469 if (smb2_oob(buf, ptr, 8)) {
470 return NT_STATUS_INVALID_PARAMETER;
473 if (blob.data == NULL) {
474 if (blob.length != 0) {
475 return NT_STATUS_INTERNAL_ERROR;
477 SIVAL(ptr, 0, 0);
478 SIVAL(ptr, 4, 0);
479 return NT_STATUS_OK;
482 offset = buf->dynamic - buf->hdr;
483 padding_length = smb2_padding_size(offset, 8);
484 offset += padding_length;
485 padding_fix = smb2_padding_fix(buf);
487 SIVAL(ptr, 0, blob.length);
488 SIVAL(ptr, 4, offset);
490 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
491 NT_STATUS_NOT_OK_RETURN(status);
493 memset(buf->dynamic, 0, padding_length);
494 buf->dynamic += padding_length;
496 memcpy(buf->dynamic, blob.data, blob.length);
497 buf->dynamic += blob.length;
499 buf->size += blob.length + padding_length - padding_fix;
500 buf->body_size += blob.length + padding_length;
502 return NT_STATUS_OK;
506 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
507 the ptr points to the start of the offset/length pair
509 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
511 uint16_t ofs;
512 uint32_t size;
514 if (smb2_oob(buf, ptr, 6)) {
515 return NT_STATUS_INVALID_PARAMETER;
517 ofs = SVAL(ptr, 0);
518 size = IVAL(ptr, 2);
519 if (ofs == 0) {
520 *blob = data_blob(NULL, 0);
521 return NT_STATUS_OK;
523 if (smb2_oob(buf, buf->hdr + ofs, size)) {
524 return NT_STATUS_INVALID_PARAMETER;
526 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
527 NT_STATUS_HAVE_NO_MEMORY(blob->data);
528 return NT_STATUS_OK;
532 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
533 the ptr points to the start of the offset/length pair
535 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
537 uint32_t ofs, size;
538 if (smb2_oob(buf, ptr, 8)) {
539 return NT_STATUS_INVALID_PARAMETER;
541 ofs = IVAL(ptr, 0);
542 size = IVAL(ptr, 4);
543 if (ofs == 0) {
544 *blob = data_blob(NULL, 0);
545 return NT_STATUS_OK;
547 if (smb2_oob(buf, buf->hdr + ofs, size)) {
548 return NT_STATUS_INVALID_PARAMETER;
550 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
551 NT_STATUS_HAVE_NO_MEMORY(blob->data);
552 return NT_STATUS_OK;
556 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
557 the ptr points to the start of the offset/length pair
559 In this varient the uint16_t is padded by an extra 2 bytes, making
560 the size aligned on 4 byte boundary
562 NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
564 uint32_t ofs, size;
565 if (smb2_oob(buf, ptr, 8)) {
566 return NT_STATUS_INVALID_PARAMETER;
568 ofs = SVAL(ptr, 0);
569 size = IVAL(ptr, 4);
570 if (ofs == 0) {
571 *blob = data_blob(NULL, 0);
572 return NT_STATUS_OK;
574 if (smb2_oob(buf, buf->hdr + ofs, size)) {
575 return NT_STATUS_INVALID_PARAMETER;
577 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
578 NT_STATUS_HAVE_NO_MEMORY(blob->data);
579 return NT_STATUS_OK;
583 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
584 the ptr points to the start of the offset/length pair
586 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
588 uint32_t ofs, size;
589 if (smb2_oob(buf, ptr, 8)) {
590 return NT_STATUS_INVALID_PARAMETER;
592 size = IVAL(ptr, 0);
593 ofs = IVAL(ptr, 4);
594 if (ofs == 0) {
595 *blob = data_blob(NULL, 0);
596 return NT_STATUS_OK;
598 if (smb2_oob(buf, buf->hdr + ofs, size)) {
599 return NT_STATUS_INVALID_PARAMETER;
601 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
602 NT_STATUS_HAVE_NO_MEMORY(blob->data);
603 return NT_STATUS_OK;
607 pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
608 the ptr points to the start of the offset/length pair
610 NTSTATUS smb2_pull_s32o16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
612 uint32_t ofs, size;
613 if (smb2_oob(buf, ptr, 8)) {
614 return NT_STATUS_INVALID_PARAMETER;
616 size = IVAL(ptr, 0);
617 ofs = SVAL(ptr, 4);
618 if (ofs == 0) {
619 *blob = data_blob(NULL, 0);
620 return NT_STATUS_OK;
622 if (smb2_oob(buf, buf->hdr + ofs, size)) {
623 return NT_STATUS_INVALID_PARAMETER;
625 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
626 NT_STATUS_HAVE_NO_MEMORY(blob->data);
627 return NT_STATUS_OK;
631 pull a string in a uint16_t ofs/ uint16_t length/blob format
632 UTF-16 without termination
634 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
635 uint8_t *ptr, const char **str)
637 DATA_BLOB blob;
638 NTSTATUS status;
639 void *vstr;
640 size_t converted_size = 0;
641 bool ret;
643 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
644 NT_STATUS_NOT_OK_RETURN(status);
646 if (blob.data == NULL) {
647 *str = NULL;
648 return NT_STATUS_OK;
651 if (blob.length == 0) {
652 char *s;
653 s = talloc_strdup(mem_ctx, "");
654 NT_STATUS_HAVE_NO_MEMORY(s);
655 *str = s;
656 return NT_STATUS_OK;
659 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
660 blob.data, blob.length, &vstr, &converted_size);
661 data_blob_free(&blob);
662 (*str) = (char *)vstr;
663 if (!ret) {
664 return NT_STATUS_ILLEGAL_CHARACTER;
666 return NT_STATUS_OK;
670 push a string in a uint16_t ofs/ uint16_t length/blob format
671 UTF-16 without termination
673 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
674 uint16_t ofs, const char *str)
676 DATA_BLOB blob;
677 NTSTATUS status;
678 bool ret;
679 void *ptr = NULL;
681 if (str == NULL) {
682 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
685 if (*str == 0) {
686 blob.data = discard_const_p(uint8_t, str);
687 blob.length = 0;
688 return smb2_push_o16s16_blob(buf, ofs, blob);
691 ret = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
692 str, strlen(str), &ptr, &blob.length);
693 if (!ret) {
694 return NT_STATUS_ILLEGAL_CHARACTER;
696 blob.data = (uint8_t *)ptr;
698 status = smb2_push_o16s16_blob(buf, ofs, blob);
699 data_blob_free(&blob);
700 return status;
704 push a file handle into a buffer
706 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
708 SBVAL(data, 0, h->data[0]);
709 SBVAL(data, 8, h->data[1]);
713 pull a file handle from a buffer
715 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
717 h->data[0] = BVAL(ptr, 0);
718 h->data[1] = BVAL(ptr, 8);