1/* 2 Unix SMB/CIFS implementation. 3 4 Copyright (C) Andrew Tridgell 2003 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20/* 21 this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd 22*/ 23 24#include "includes.h" 25#include "smb_server/smb_server.h" 26#include "smbd/service_stream.h" 27#include "lib/stream/packet.h" 28#include "ntvfs/ntvfs.h" 29 30 31/* we over allocate the data buffer to prevent too many realloc calls */ 32#define REQ_OVER_ALLOCATION 0 33 34/* setup the bufinfo used for strings and range checking */ 35void smbsrv_setup_bufinfo(struct smbsrv_request *req) 36{ 37 req->in.bufinfo.mem_ctx = req; 38 req->in.bufinfo.flags = 0; 39 if (req->flags2 & FLAGS2_UNICODE_STRINGS) { 40 req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE; 41 } 42 req->in.bufinfo.align_base = req->in.buffer; 43 req->in.bufinfo.data = req->in.data; 44 req->in.bufinfo.data_size = req->in.data_size; 45} 46 47 48static int smbsrv_request_destructor(struct smbsrv_request *req) 49{ 50 DLIST_REMOVE(req->smb_conn->requests, req); 51 return 0; 52} 53 54/**************************************************************************** 55construct a basic request packet, mostly used to construct async packets 56such as change notify and oplock break requests 57****************************************************************************/ 58struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn) 59{ 60 struct smbsrv_request *req; 61 62 req = talloc_zero(smb_conn, struct smbsrv_request); 63 if (!req) { 64 return NULL; 65 } 66 67 /* setup the request context */ 68 req->smb_conn = smb_conn; 69 70 talloc_set_destructor(req, smbsrv_request_destructor); 71 72 return req; 73} 74 75 76/* 77 setup a chained reply in req->out with the given word count and initial data buffer size. 78*/ 79static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen) 80{ 81 uint32_t chain_base_size = req->out.size; 82 83 /* we need room for the wct value, the words, the buffer length and the buffer */ 84 req->out.size += 1 + VWV(wct) + 2 + buflen; 85 86 /* over allocate by a small amount */ 87 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 88 89 req->out.buffer = talloc_realloc(req, req->out.buffer, 90 uint8_t, req->out.allocated); 91 if (!req->out.buffer) { 92 smbsrv_terminate_connection(req->smb_conn, "allocation failed"); 93 return; 94 } 95 96 req->out.hdr = req->out.buffer + NBT_HDR_SIZE; 97 req->out.vwv = req->out.buffer + chain_base_size + 1; 98 req->out.wct = wct; 99 req->out.data = req->out.vwv + VWV(wct) + 2; 100 req->out.data_size = buflen; 101 req->out.ptr = req->out.data; 102 103 SCVAL(req->out.buffer, chain_base_size, wct); 104 SSVAL(req->out.vwv, VWV(wct), buflen); 105} 106 107 108/* 109 setup a reply in req->out with the given word count and initial data buffer size. 110 the caller will then fill in the command words and data before calling req_send_reply() to 111 send the reply on its way 112*/ 113void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen) 114{ 115 uint16_t flags2; 116 117 if (req->chain_count != 0) { 118 req_setup_chain_reply(req, wct, buflen); 119 return; 120 } 121 122 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen; 123 124 /* over allocate by a small amount */ 125 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 126 127 req->out.buffer = talloc_size(req, req->out.allocated); 128 if (!req->out.buffer) { 129 smbsrv_terminate_connection(req->smb_conn, "allocation failed"); 130 return; 131 } 132 133 flags2 = FLAGS2_LONG_PATH_COMPONENTS | 134 FLAGS2_EXTENDED_ATTRIBUTES | 135 FLAGS2_IS_LONG_NAME; 136#define _SMB_FLAGS2_ECHOED_FLAGS ( \ 137 FLAGS2_UNICODE_STRINGS | \ 138 FLAGS2_EXTENDED_SECURITY | \ 139 FLAGS2_SMB_SECURITY_SIGNATURES \ 140) 141 flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS); 142 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) { 143 flags2 |= FLAGS2_32_BIT_ERROR_CODES; 144 } 145 146 req->out.hdr = req->out.buffer + NBT_HDR_SIZE; 147 req->out.vwv = req->out.hdr + HDR_VWV; 148 req->out.wct = wct; 149 req->out.data = req->out.vwv + VWV(wct) + 2; 150 req->out.data_size = buflen; 151 req->out.ptr = req->out.data; 152 153 SIVAL(req->out.hdr, HDR_RCLS, 0); 154 155 SCVAL(req->out.hdr, HDR_WCT, wct); 156 SSVAL(req->out.vwv, VWV(wct), buflen); 157 158 memcpy(req->out.hdr, "\377SMB", 4); 159 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES); 160 SSVAL(req->out.hdr,HDR_FLG2, flags2); 161 SSVAL(req->out.hdr,HDR_PIDHIGH,0); 162 memset(req->out.hdr + HDR_SS_FIELD, 0, 10); 163 164 if (req->in.hdr) { 165 /* copy the cmd, tid, pid, uid and mid from the request */ 166 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM)); 167 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID)); 168 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID)); 169 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID)); 170 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID)); 171 } else { 172 SCVAL(req->out.hdr,HDR_COM,0); 173 SSVAL(req->out.hdr,HDR_TID,0); 174 SSVAL(req->out.hdr,HDR_PID,0); 175 SSVAL(req->out.hdr,HDR_UID,0); 176 SSVAL(req->out.hdr,HDR_MID,0); 177 } 178} 179 180 181/* 182 setup a copy of a request, used when the server needs to send 183 more than one reply for a single request packet 184*/ 185struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req) 186{ 187 struct smbsrv_request *req; 188 ptrdiff_t diff; 189 190 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request)); 191 if (req == NULL) { 192 return NULL; 193 } 194 195 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated); 196 if (req->out.buffer == NULL) { 197 talloc_free(req); 198 return NULL; 199 } 200 201 diff = req->out.buffer - old_req->out.buffer; 202 203 req->out.hdr += diff; 204 req->out.vwv += diff; 205 req->out.data += diff; 206 req->out.ptr += diff; 207 208 return req; 209} 210 211/* 212 work out the maximum data size we will allow for this reply, given 213 the negotiated max_xmit. The basic reply packet must be setup before 214 this call 215 216 note that this is deliberately a signed integer reply 217*/ 218int req_max_data(struct smbsrv_request *req) 219{ 220 int ret; 221 ret = req->smb_conn->negotiate.max_send; 222 ret -= PTR_DIFF(req->out.data, req->out.hdr); 223 if (ret < 0) ret = 0; 224 return ret; 225} 226 227 228/* 229 grow the allocation of the data buffer portion of a reply 230 packet. Note that as this can reallocate the packet buffer this 231 invalidates any local pointers into the packet. 232 233 To cope with this req->out.ptr is supplied. This will be updated to 234 point at the same offset into the packet as before this call 235*/ 236static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size) 237{ 238 int delta; 239 uint8_t *buf2; 240 241 delta = new_size - req->out.data_size; 242 if (delta + req->out.size <= req->out.allocated) { 243 /* it fits in the preallocation */ 244 return; 245 } 246 247 /* we need to realloc */ 248 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION; 249 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated); 250 if (buf2 == NULL) { 251 smb_panic("out of memory in req_grow_allocation"); 252 } 253 254 if (buf2 == req->out.buffer) { 255 /* the malloc library gave us the same pointer */ 256 return; 257 } 258 259 /* update the pointers into the packet */ 260 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer); 261 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer); 262 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer); 263 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer); 264 265 req->out.buffer = buf2; 266} 267 268 269/* 270 grow the data buffer portion of a reply packet. Note that as this 271 can reallocate the packet buffer this invalidates any local pointers 272 into the packet. 273 274 To cope with this req->out.ptr is supplied. This will be updated to 275 point at the same offset into the packet as before this call 276*/ 277void req_grow_data(struct smbsrv_request *req, size_t new_size) 278{ 279 int delta; 280 281 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) { 282 smb_panic("reply buffer too large!"); 283 } 284 285 req_grow_allocation(req, new_size); 286 287 delta = new_size - req->out.data_size; 288 289 req->out.size += delta; 290 req->out.data_size += delta; 291 292 /* set the BCC to the new data size */ 293 SSVAL(req->out.vwv, VWV(req->out.wct), new_size); 294} 295 296/* 297 send a reply and destroy the request buffer 298 299 note that this only looks at req->out.buffer and req->out.size, allowing manually 300 constructed packets to be sent 301*/ 302void smbsrv_send_reply_nosign(struct smbsrv_request *req) 303{ 304 DATA_BLOB blob; 305 NTSTATUS status; 306 307 if (req->smb_conn->connection->event.fde == NULL) { 308 /* we are in the process of shutting down this connection */ 309 talloc_free(req); 310 return; 311 } 312 313 if (req->out.size > NBT_HDR_SIZE) { 314 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE); 315 } 316 317 blob = data_blob_const(req->out.buffer, req->out.size); 318 status = packet_send(req->smb_conn->packet, blob); 319 if (!NT_STATUS_IS_OK(status)) { 320 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); 321 } 322 talloc_free(req); 323} 324 325/* 326 possibly sign a message then send a reply and destroy the request buffer 327 328 note that this only looks at req->out.buffer and req->out.size, allowing manually 329 constructed packets to be sent 330*/ 331void smbsrv_send_reply(struct smbsrv_request *req) 332{ 333 if (req->smb_conn->connection->event.fde == NULL) { 334 /* we are in the process of shutting down this connection */ 335 talloc_free(req); 336 return; 337 } 338 smbsrv_sign_packet(req); 339 340 smbsrv_send_reply_nosign(req); 341} 342 343/* 344 setup the header of a reply to include an NTSTATUS code 345*/ 346void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status) 347{ 348 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) { 349 /* convert to DOS error codes */ 350 uint8_t eclass; 351 uint32_t ecode; 352 ntstatus_to_dos(status, &eclass, &ecode); 353 SCVAL(req->out.hdr, HDR_RCLS, eclass); 354 SSVAL(req->out.hdr, HDR_ERR, ecode); 355 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES); 356 return; 357 } 358 359 if (NT_STATUS_IS_DOS(status)) { 360 /* its a encoded DOS error, using the reserved range */ 361 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status)); 362 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status)); 363 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES); 364 } else { 365 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status)); 366 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES); 367 } 368} 369 370/* 371 construct and send an error packet, then destroy the request 372 auto-converts to DOS error format when appropriate 373*/ 374void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status) 375{ 376 if (req->smb_conn->connection->event.fde == NULL) { 377 /* the socket has been destroyed - no point trying to send an error! */ 378 talloc_free(req); 379 return; 380 } 381 smbsrv_setup_reply(req, 0, 0); 382 383 /* error returns never have any data */ 384 req_grow_data(req, 0); 385 386 smbsrv_setup_error(req, status); 387 smbsrv_send_reply(req); 388} 389 390 391/* 392 push a string into the data portion of the request packet, growing it if necessary 393 this gets quite tricky - please be very careful to cover all cases when modifying this 394 395 if dest is NULL, then put the string at the end of the data portion of the packet 396 397 if dest_len is -1 then no limit applies 398*/ 399size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags) 400{ 401 size_t len; 402 uint_t grow_size; 403 uint8_t *buf0; 404 const int max_bytes_per_char = 3; 405 406 if (!(flags & (STR_ASCII|STR_UNICODE))) { 407 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII; 408 } 409 410 if (dest == NULL) { 411 dest = req->out.data + req->out.data_size; 412 } 413 414 if (dest_len != -1) { 415 len = dest_len; 416 } else { 417 len = (strlen(str)+2) * max_bytes_per_char; 418 } 419 420 grow_size = len + PTR_DIFF(dest, req->out.data); 421 buf0 = req->out.buffer; 422 423 req_grow_allocation(req, grow_size); 424 425 if (buf0 != req->out.buffer) { 426 dest = req->out.buffer + PTR_DIFF(dest, buf0); 427 } 428 429 len = push_string(dest, str, len, flags); 430 431 grow_size = len + PTR_DIFF(dest, req->out.data); 432 433 if (grow_size > req->out.data_size) { 434 req_grow_data(req, grow_size); 435 } 436 437 return len; 438} 439 440/* 441 append raw bytes into the data portion of the request packet 442 return the number of bytes added 443*/ 444size_t req_append_bytes(struct smbsrv_request *req, 445 const uint8_t *bytes, size_t byte_len) 446{ 447 req_grow_allocation(req, byte_len + req->out.data_size); 448 memcpy(req->out.data + req->out.data_size, bytes, byte_len); 449 req_grow_data(req, byte_len + req->out.data_size); 450 return byte_len; 451} 452/* 453 append variable block (type 5 buffer) into the data portion of the request packet 454 return the number of bytes added 455*/ 456size_t req_append_var_block(struct smbsrv_request *req, 457 const uint8_t *bytes, uint16_t byte_len) 458{ 459 req_grow_allocation(req, byte_len + 3 + req->out.data_size); 460 SCVAL(req->out.data + req->out.data_size, 0, 5); 461 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */ 462 if (byte_len > 0) { 463 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len); 464 } 465 req_grow_data(req, byte_len + 3 + req->out.data_size); 466 return byte_len + 3; 467} 468/** 469 pull a UCS2 string from a request packet, returning a talloced unix string 470 471 the string length is limited by the 3 things: 472 - the data size in the request (end of packet) 473 - the passed 'byte_len' if it is not -1 474 - the end of string (null termination) 475 476 Note that 'byte_len' is the number of bytes in the packet 477 478 on failure zero is returned and *dest is set to NULL, otherwise the number 479 of bytes consumed in the packet is returned 480*/ 481static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags) 482{ 483 int src_len, src_len2, alignment=0; 484 bool ret; 485 char *dest2; 486 487 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) { 488 src++; 489 alignment=1; 490 if (byte_len != -1) { 491 byte_len--; 492 } 493 } 494 495 if (flags & STR_NO_RANGE_CHECK) { 496 src_len = byte_len; 497 } else { 498 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); 499 if (byte_len != -1 && src_len > byte_len) { 500 src_len = byte_len; 501 } 502 } 503 504 if (src_len < 0) { 505 *dest = NULL; 506 return 0; 507 } 508 509 src_len2 = utf16_len_n(src, src_len); 510 if (src_len2 == 0) { 511 *dest = talloc_strdup(bufinfo->mem_ctx, ""); 512 return src_len2 + alignment; 513 } 514 515 ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false); 516 517 if (!ret) { 518 *dest = NULL; 519 return 0; 520 } 521 *dest = dest2; 522 523 return src_len2 + alignment; 524} 525 526/** 527 pull a ascii string from a request packet, returning a talloced string 528 529 the string length is limited by the 3 things: 530 - the data size in the request (end of packet) 531 - the passed 'byte_len' if it is not -1 532 - the end of string (null termination) 533 534 Note that 'byte_len' is the number of bytes in the packet 535 536 on failure zero is returned and *dest is set to NULL, otherwise the number 537 of bytes consumed in the packet is returned 538*/ 539static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags) 540{ 541 int src_len, src_len2; 542 bool ret; 543 char *dest2; 544 545 if (flags & STR_NO_RANGE_CHECK) { 546 src_len = byte_len; 547 } else { 548 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); 549 if (src_len < 0) { 550 *dest = NULL; 551 return 0; 552 } 553 if (byte_len != -1 && src_len > byte_len) { 554 src_len = byte_len; 555 } 556 } 557 558 src_len2 = strnlen((const char *)src, src_len); 559 if (src_len2 <= src_len - 1) { 560 /* include the termination if we didn't reach the end of the packet */ 561 src_len2++; 562 } 563 564 ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false); 565 566 if (!ret) { 567 *dest = NULL; 568 return 0; 569 } 570 *dest = dest2; 571 572 return src_len2; 573} 574 575/** 576 pull a string from a request packet, returning a talloced string 577 578 the string length is limited by the 3 things: 579 - the data size in the request (end of packet) 580 - the passed 'byte_len' if it is not -1 581 - the end of string (null termination) 582 583 Note that 'byte_len' is the number of bytes in the packet 584 585 on failure zero is returned and *dest is set to NULL, otherwise the number 586 of bytes consumed in the packet is returned 587*/ 588size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags) 589{ 590 if (!(flags & STR_ASCII) && 591 (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) { 592 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags); 593 } 594 595 return req_pull_ascii(bufinfo, dest, src, byte_len, flags); 596} 597 598 599/** 600 pull a ASCII4 string buffer from a request packet, returning a talloced string 601 602 an ASCII4 buffer is a null terminated string that has a prefix 603 of the character 0x4. It tends to be used in older parts of the protocol. 604 605 on failure *dest is set to the zero length string. This seems to 606 match win2000 behaviour 607*/ 608size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags) 609{ 610 ssize_t ret; 611 612 if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) { 613 /* win2000 treats this as the empty string! */ 614 (*dest) = talloc_strdup(bufinfo->mem_ctx, ""); 615 return 0; 616 } 617 618 /* this consumes the 0x4 byte. We don't check whether the byte 619 is actually 0x4 or not. This matches win2000 server 620 behaviour */ 621 src++; 622 623 ret = req_pull_string(bufinfo, dest, src, -1, flags); 624 if (ret == -1) { 625 (*dest) = talloc_strdup(bufinfo->mem_ctx, ""); 626 return 1; 627 } 628 629 return ret + 1; 630} 631 632/** 633 pull a DATA_BLOB from a request packet, returning a talloced blob 634 635 return false if any part is outside the data portion of the packet 636*/ 637bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob) 638{ 639 if (len != 0 && req_data_oob(bufinfo, src, len)) { 640 return false; 641 } 642 643 (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len); 644 645 return true; 646} 647 648/* check that a lump of data in a request is within the bounds of the data section of 649 the packet */ 650bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count) 651{ 652 if (count == 0) { 653 return false; 654 } 655 656 /* be careful with wraparound! */ 657 if ((uintptr_t)ptr < (uintptr_t)bufinfo->data || 658 (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size || 659 count > bufinfo->data_size || 660 (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) { 661 return true; 662 } 663 return false; 664} 665 666 667/* 668 pull an open file handle from a packet, taking account of the chained_fnum 669*/ 670static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset) 671{ 672 if (req->chained_fnum != -1) { 673 return req->chained_fnum; 674 } 675 return SVAL(base, offset); 676} 677 678struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset) 679{ 680 struct smbsrv_handle *handle; 681 uint16_t fnum = req_fnum(req, base, offset); 682 683 handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time); 684 if (!handle) { 685 return NULL; 686 } 687 688 /* 689 * For SMB tcons and sessions can be mixed! 690 * But we need to make sure that file handles 691 * are only accessed by the opening session! 692 * 693 * So check if the handle is valid for the given session! 694 */ 695 if (handle->session != req->session) { 696 return NULL; 697 } 698 699 return handle->ntvfs; 700} 701 702void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs) 703{ 704 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data, 705 struct smbsrv_handle); 706 SSVAL(base, offset, handle->hid); 707} 708 709NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h) 710{ 711 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data, 712 struct smbsrv_request); 713 struct smbsrv_handle *handle; 714 struct ntvfs_handle *h; 715 716 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time); 717 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES; 718 719 h = talloc_zero(handle, struct ntvfs_handle); 720 if (!h) goto nomem; 721 722 /* 723 * note: we don't set handle->ntvfs yet, 724 * this will be done by smbsrv_handle_make_valid() 725 * this makes sure the handle is invalid for clients 726 * until the ntvfs subsystem has made it valid 727 */ 728 h->ctx = ntvfs->ctx; 729 h->session_info = ntvfs->session_info; 730 h->smbpid = ntvfs->smbpid; 731 732 h->frontend_data.private_data = handle; 733 734 *_h = h; 735 return NT_STATUS_OK; 736nomem: 737 talloc_free(handle); 738 return NT_STATUS_NO_MEMORY; 739} 740 741NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h) 742{ 743 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon); 744 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data, 745 struct smbsrv_handle); 746 /* this tells the frontend that the handle is valid */ 747 handle->ntvfs = h; 748 /* this moves the smbsrv_request to the smbsrv_tcon memory context */ 749 talloc_steal(tcon, handle); 750 return NT_STATUS_OK; 751} 752 753void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h) 754{ 755 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data, 756 struct smbsrv_handle); 757 talloc_free(handle); 758} 759 760struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key) 761{ 762 struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data, 763 struct smbsrv_request); 764 765 if (key->length != 2) return NULL; 766 767 return smbsrv_pull_fnum(req, key->data, 0); 768} 769 770DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx) 771{ 772 uint8_t key[2]; 773 774 smbsrv_push_fnum(key, 0, handle); 775 776 return data_blob_talloc(mem_ctx, key, sizeof(key)); 777} 778