LCOV - code coverage report
Current view: top level - source4/libcli/raw - rawrequest.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 363 433 83.8 %
Date: 2024-04-21 15:09:00 Functions: 33 34 97.1 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Andrew Tridgell  2003
       5             :    Copyright (C) James Myers 2003 <myersjj@samba.org>
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : /*
      22             :   this file implements functions for manipulating the 'struct smbcli_request' structure in libsmb
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "libcli/raw/libcliraw.h"
      27             : #include "libcli/raw/raw_proto.h"
      28             : #include "lib/events/events.h"
      29             : #include "librpc/ndr/libndr.h"
      30             : #include "librpc/gen_ndr/ndr_misc.h"
      31             : #include "../libcli/smb/smbXcli_base.h"
      32             : 
      33             : /* we over allocate the data buffer to prevent too many realloc calls */
      34             : #define REQ_OVER_ALLOCATION 0
      35             : 
      36             : /* assume that a character will not consume more than 3 bytes per char */
      37             : #define MAX_BYTES_PER_CHAR 3
      38             : 
      39             : /* setup the bufinfo used for strings and range checking */
      40      441298 : void smb_setup_bufinfo(struct smbcli_request *req)
      41             : {
      42      441298 :         req->in.bufinfo.mem_ctx    = req;
      43      441298 :         req->in.bufinfo.flags      = 0;
      44      441298 :         if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
      45      440749 :                 req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE;
      46             :         }
      47      441298 :         req->in.bufinfo.align_base = req->in.buffer;
      48      441298 :         req->in.bufinfo.data       = req->in.data;
      49      441298 :         req->in.bufinfo.data_size  = req->in.data_size;
      50      441298 : }
      51             : 
      52             : 
      53             : /* destroy a request structure and return final status */
      54      513914 : _PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
      55             : {
      56        7718 :         NTSTATUS status;
      57             : 
      58             :         /* this is the error code we give the application for when a
      59             :            _send() call fails completely */
      60      513914 :         if (!req) return NT_STATUS_UNSUCCESSFUL;
      61             : 
      62      513908 :         if (req->state == SMBCLI_REQUEST_ERROR &&
      63       32203 :             NT_STATUS_IS_OK(req->status)) {
      64           0 :                 req->status = NT_STATUS_INTERNAL_ERROR;
      65             :         }
      66             : 
      67      513908 :         status = req->status;
      68             : 
      69      513908 :         if (!req->do_not_free) {
      70      508138 :                 talloc_free(req);
      71             :         }
      72             : 
      73      513908 :         return status;
      74             : }
      75             : 
      76             : 
      77             : /*
      78             :   setup a SMB packet at transport level
      79             : */
      80      514238 : struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
      81             :                                                       uint8_t command, unsigned int wct, unsigned int buflen)
      82             : {
      83        7718 :         struct smbcli_request *req;
      84        7718 :         size_t size;
      85             : 
      86      514238 :         size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
      87             : 
      88      514238 :         req = talloc_zero(transport, struct smbcli_request);
      89      514238 :         if (!req) {
      90           0 :                 return NULL;
      91             :         }
      92             : 
      93             :         /* setup the request context */
      94      514238 :         req->state = SMBCLI_REQUEST_INIT;
      95      514238 :         req->transport = transport;
      96      514238 :         req->out.size = size;
      97             : 
      98             :         /* over allocate by a small amount */
      99      514238 :         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
     100             : 
     101      514238 :         req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
     102      514238 :         if (!req->out.buffer) {
     103           0 :                 return NULL;
     104             :         }
     105             : 
     106      514238 :         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
     107      514238 :         req->out.vwv = req->out.hdr + HDR_VWV;
     108      514238 :         req->out.wct = wct;
     109      514238 :         req->out.data = req->out.vwv + VWV(wct) + 2;
     110      514238 :         req->out.data_size = buflen;
     111      514238 :         req->out.ptr = req->out.data;
     112             : 
     113      514238 :         SCVAL(req->out.hdr, HDR_WCT, wct);
     114      514238 :         SSVAL(req->out.vwv, VWV(wct), buflen);
     115             : 
     116      514238 :         memcpy(req->out.hdr, "\377SMB", 4);
     117      514238 :         SCVAL(req->out.hdr,HDR_COM,command);
     118             : 
     119      514238 :         SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
     120      514238 :         SSVAL(req->out.hdr,HDR_FLG2, 0);
     121             : 
     122             :         /* copy the pid, uid and mid to the request */
     123      514238 :         SSVAL(req->out.hdr, HDR_PID, 0);
     124      514238 :         SSVAL(req->out.hdr, HDR_UID, 0);
     125      514238 :         SSVAL(req->out.hdr, HDR_MID, 0);
     126      514238 :         SSVAL(req->out.hdr, HDR_TID,0);
     127      514238 :         SSVAL(req->out.hdr, HDR_PIDHIGH,0);
     128      514238 :         SIVAL(req->out.hdr, HDR_RCLS, 0);
     129      514238 :         memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
     130             : 
     131      514238 :         return req;
     132             : }
     133             : 
     134             : /*
     135             :   setup a reply in req->out with the given word count and initial data
     136             :   buffer size.  the caller will then fill in the command words and
     137             :   data before calling smbcli_request_send() to send the reply on its
     138             :   way. This interface is used before a session is setup.
     139             : */
     140      514231 : struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
     141             :                                                     uint8_t command, unsigned int wct, size_t buflen)
     142             : {
     143        7718 :         struct smbcli_request *req;
     144             : 
     145      514231 :         req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
     146             : 
     147      514231 :         if (!req) return NULL;
     148             : 
     149      514231 :         smb1cli_session_set_id(session->smbXcli, session->vuid);
     150             : 
     151      514231 :         req->session = session;
     152             : 
     153      514231 :         SSVAL(req->out.hdr, HDR_FLG2, session->flags2);
     154      514231 :         SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
     155      514231 :         SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
     156      514231 :         SSVAL(req->out.hdr, HDR_UID, session->vuid);
     157             : 
     158      514231 :         return req;
     159             : }
     160             : 
     161             : /*
     162             :   setup a request for tree based commands
     163             : */
     164      505124 : struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
     165             :                                             uint8_t command,
     166             :                                             unsigned int wct, unsigned int buflen)
     167             : {
     168        7456 :         struct smbcli_request *req;
     169             : 
     170      505124 :         req = smbcli_request_setup_session(tree->session, command, wct, buflen);
     171      505124 :         if (req) {
     172      505124 :                 smb1cli_tcon_set_id(tree->smbXcli, tree->tid);
     173             : 
     174      505124 :                 req->tree = tree;
     175      505124 :                 SSVAL(req->out.hdr,HDR_TID,tree->tid);
     176             :         }
     177      505124 :         return req;
     178             : }
     179             : 
     180             : 
     181             : /*
     182             :   grow the allocation of the data buffer portion of a reply
     183             :   packet. Note that as this can reallocate the packet buffer this
     184             :   invalidates any local pointers into the packet.
     185             : 
     186             :   To cope with this req->out.ptr is supplied. This will be updated to
     187             :   point at the same offset into the packet as before this call
     188             : */
     189      893400 : static void smbcli_req_grow_allocation(struct smbcli_request *req, unsigned int new_size)
     190             : {
     191       39392 :         int delta;
     192       39392 :         uint8_t *buf2;
     193             : 
     194      893400 :         delta = new_size - req->out.data_size;
     195      893400 :         if (delta + req->out.size <= req->out.allocated) {
     196             :                 /* it fits in the preallocation */
     197      457376 :                 return;
     198             :         }
     199             : 
     200             :         /* we need to realloc */
     201      411792 :         req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
     202      411792 :         buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
     203      411792 :         if (buf2 == NULL) {
     204           0 :                 smb_panic("out of memory in req_grow_allocation");
     205             :         }
     206             : 
     207      411792 :         if (buf2 == req->out.buffer) {
     208             :                 /* the malloc library gave us the same pointer */
     209      183100 :                 return;
     210             :         }
     211             : 
     212             :         /* update the pointers into the packet */
     213      219090 :         req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
     214      219090 :         req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
     215      219090 :         req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
     216      219090 :         req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
     217             : 
     218      219090 :         req->out.buffer = buf2;
     219             : }
     220             : 
     221             : 
     222             : /*
     223             :   grow the data buffer portion of a reply packet. Note that as this
     224             :   can reallocate the packet buffer this invalidates any local pointers
     225             :   into the packet.
     226             : 
     227             :   To cope with this req->out.ptr is supplied. This will be updated to
     228             :   point at the same offset into the packet as before this call
     229             : */
     230      446700 : static void smbcli_req_grow_data(struct smbcli_request *req, unsigned int new_size)
     231             : {
     232       19696 :         int delta;
     233             : 
     234      446700 :         smbcli_req_grow_allocation(req, new_size);
     235             : 
     236      446700 :         delta = new_size - req->out.data_size;
     237             : 
     238      446700 :         req->out.size += delta;
     239      446700 :         req->out.data_size += delta;
     240             : 
     241             :         /* set the BCC to the new data size */
     242      446700 :         SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
     243      446700 : }
     244             : 
     245             : 
     246             : /*
     247             :   setup a chained reply in req->out with the given word count and
     248             :   initial data buffer size.
     249             : */
     250          18 : NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req,
     251             :                                       uint8_t command,
     252             :                                       unsigned int wct, size_t buflen)
     253             : {
     254           3 :         size_t wct_ofs;
     255           3 :         size_t size;
     256             : 
     257             :         /*
     258             :          * here we only support one chained command
     259             :          * If someone needs longer chains, the low
     260             :          * level code should be used directly.
     261             :          */
     262          18 :         if (req->subreqs[0] != NULL) {
     263           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     264             :         }
     265          18 :         if (req->subreqs[1] != NULL) {
     266           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     267             :         }
     268             : 
     269          18 :         req->subreqs[0] = smbcli_transport_setup_subreq(req);
     270          18 :         if (req->subreqs[0] == NULL) {
     271           0 :                 return NT_STATUS_NO_MEMORY;
     272             :         }
     273             : 
     274          18 :         wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1);
     275             : 
     276          18 :         size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen;
     277             : 
     278          18 :         req->out.size = size;
     279             : 
     280             :         /* over allocate by a small amount */
     281          18 :         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
     282             : 
     283          18 :         req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
     284          18 :         if (!req->out.buffer) {
     285           0 :                 return NT_STATUS_NO_MEMORY;
     286             :         }
     287             : 
     288          18 :         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
     289          18 :         req->out.vwv = req->out.hdr + wct_ofs;
     290          18 :         req->out.wct = wct;
     291          18 :         req->out.data = req->out.vwv + VWV(wct) + 2;
     292          18 :         req->out.data_size = buflen;
     293          18 :         req->out.ptr = req->out.data;
     294             : 
     295          18 :         SCVAL(req->out.hdr, HDR_WCT, wct);
     296          18 :         SSVAL(req->out.vwv, VWV(wct), buflen);
     297             : 
     298          18 :         memcpy(req->out.hdr, "\377SMB", 4);
     299          18 :         SCVAL(req->out.hdr,HDR_COM,command);
     300             : 
     301          18 :         SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
     302          18 :         SSVAL(req->out.hdr,HDR_FLG2, 0);
     303             : 
     304             :         /* copy the pid, uid and mid to the request */
     305          18 :         SSVAL(req->out.hdr, HDR_PID, 0);
     306          18 :         SSVAL(req->out.hdr, HDR_UID, 0);
     307          18 :         SSVAL(req->out.hdr, HDR_MID, 0);
     308          18 :         SSVAL(req->out.hdr, HDR_TID,0);
     309          18 :         SSVAL(req->out.hdr, HDR_PIDHIGH,0);
     310          18 :         SIVAL(req->out.hdr, HDR_RCLS, 0);
     311          18 :         memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
     312             : 
     313          18 :         if (req->session != NULL) {
     314          18 :                 SSVAL(req->out.hdr, HDR_FLG2, req->session->flags2);
     315          18 :                 SSVAL(req->out.hdr, HDR_PID, req->session->pid & 0xFFFF);
     316          18 :                 SSVAL(req->out.hdr, HDR_PIDHIGH, req->session->pid >> 16);
     317          18 :                 SSVAL(req->out.hdr, HDR_UID, req->session->vuid);
     318             :         }
     319             : 
     320          18 :         if (req->tree != NULL) {
     321          18 :                 SSVAL(req->out.hdr, HDR_TID, req->tree->tid);
     322             :         }
     323             : 
     324          18 :         return NT_STATUS_OK;
     325             : }
     326             : 
     327             : /*
     328             :   advance to the next chained reply in a request
     329             : */
     330          12 : NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
     331             : {
     332          12 :         struct smbcli_transport *transport = req->transport;
     333          12 :         uint8_t *hdr = NULL;
     334          12 :         uint8_t wct = 0;
     335          12 :         uint16_t *vwv = NULL;
     336          12 :         uint32_t num_bytes = 0;
     337          12 :         uint8_t *bytes = NULL;
     338          12 :         struct iovec *recv_iov = NULL;
     339          12 :         uint8_t *inbuf = NULL;
     340             : 
     341          12 :         if (req->subreqs[0] != NULL) {
     342           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     343             :         }
     344          12 :         if (req->subreqs[1] == NULL) {
     345           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     346             :         }
     347             : 
     348          12 :         req->status = smb1cli_req_recv(req->subreqs[1], req,
     349             :                                        &recv_iov,
     350             :                                        &hdr,
     351             :                                        &wct,
     352             :                                        &vwv,
     353             :                                        NULL, /* pvwv_offset */
     354             :                                        &num_bytes,
     355             :                                        &bytes,
     356             :                                        NULL, /* pbytes_offset */
     357             :                                        &inbuf,
     358             :                                        NULL, 0); /* expected */
     359          12 :         TALLOC_FREE(req->subreqs[1]);
     360          12 :         if (!NT_STATUS_IS_OK(req->status)) {
     361           0 :                 if (recv_iov == NULL) {
     362           0 :                         req->state = SMBCLI_REQUEST_ERROR;
     363           0 :                         return req->status;
     364             :                 }
     365             :         }
     366             : 
     367             :         /* fill in the 'in' portion of the matching request */
     368          12 :         req->in.buffer = inbuf;
     369          12 :         req->in.size = NBT_HDR_SIZE + PTR_DIFF(bytes, hdr) + num_bytes;
     370          12 :         req->in.allocated = req->in.size;
     371             : 
     372          12 :         req->in.hdr = hdr;
     373          12 :         req->in.vwv = (uint8_t *)vwv;
     374          12 :         req->in.wct = wct;
     375          12 :         req->in.data = bytes;
     376          12 :         req->in.data_size = num_bytes;
     377          12 :         req->in.ptr = req->in.data;
     378          12 :         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
     379             : 
     380          12 :         smb_setup_bufinfo(req);
     381             : 
     382          12 :         transport->error.e.nt_status = req->status;
     383          12 :         if (NT_STATUS_IS_OK(req->status)) {
     384          12 :                 transport->error.etype = ETYPE_NONE;
     385             :         } else {
     386           0 :                 transport->error.etype = ETYPE_SMB;
     387             :         }
     388             : 
     389          12 :         req->state = SMBCLI_REQUEST_DONE;
     390             : 
     391          12 :         return NT_STATUS_OK;
     392             : }
     393             : 
     394             : 
     395             : /*
     396             :   send a message
     397             : */
     398      441610 : bool smbcli_request_send(struct smbcli_request *req)
     399             : {
     400      441610 :         smbcli_transport_send(req);
     401      441610 :         return true;
     402             : }
     403             : 
     404             : 
     405             : /*
     406             :   receive a response to a packet
     407             : */
     408      514447 : bool smbcli_request_receive(struct smbcli_request *req)
     409             : {
     410             :         /* req can be NULL when a send has failed. This eliminates lots of NULL
     411             :            checks in each module */
     412      514447 :         if (!req) return false;
     413             : 
     414             :         /* keep receiving packets until this one is replied to */
     415     1932992 :         while (req->state <= SMBCLI_REQUEST_RECV) {
     416     1418549 :                 if (tevent_loop_once(req->transport->ev) != 0) {
     417           0 :                         return false;
     418             :                 }
     419             :         }
     420             : 
     421      514443 :         return req->state == SMBCLI_REQUEST_DONE;
     422             : }
     423             : 
     424             : /*
     425             :   wait for a reply to be received for a packet that just returns an error
     426             :   code and nothing more
     427             : */
     428      246881 : _PUBLIC_ NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
     429             : {
     430      246881 :         (void) smbcli_request_receive(req);
     431      246881 :         return smbcli_request_destroy(req);
     432             : }
     433             : 
     434             : 
     435             : /* Return true if the last packet was in error */
     436      198761 : bool smbcli_request_is_error(struct smbcli_request *req)
     437             : {
     438      198761 :         return NT_STATUS_IS_ERR(req->status);
     439             : }
     440             : 
     441             : /*
     442             :   append a string into the data portion of the request packet
     443             : 
     444             :   return the number of bytes added to the packet
     445             : */
     446      288500 : size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, unsigned int flags)
     447             : {
     448       10427 :         size_t len;
     449             : 
     450             :         /* determine string type to use */
     451      288500 :         if (!(flags & (STR_ASCII|STR_UNICODE))) {
     452      204851 :                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
     453             :         }
     454             : 
     455      288500 :         len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
     456             : 
     457      288500 :         smbcli_req_grow_allocation(req, len + req->out.data_size);
     458             : 
     459      288500 :         len = push_string(req->out.data + req->out.data_size, str, len, flags);
     460             : 
     461      288500 :         smbcli_req_grow_data(req, len + req->out.data_size);
     462             : 
     463      288500 :         return len;
     464             : }
     465             : 
     466             : 
     467             : /*
     468             :   this is like smbcli_req_append_string but it also return the
     469             :   non-terminated string byte length, which can be less than the number
     470             :   of bytes consumed in the packet for 2 reasons:
     471             : 
     472             :    1) the string in the packet may be null terminated
     473             :    2) the string in the packet may need a 1 byte UCS2 alignment
     474             : 
     475             :  this is used in places where the non-terminated string byte length is
     476             :  placed in the packet as a separate field
     477             : */
     478       80714 : size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, unsigned int flags, int *len)
     479             : {
     480       80714 :         int diff = 0;
     481         511 :         size_t ret;
     482             : 
     483             :         /* determine string type to use */
     484       80714 :         if (!(flags & (STR_ASCII|STR_UNICODE))) {
     485       80714 :                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
     486             :         }
     487             : 
     488             :         /* see if an alignment byte will be used */
     489       80714 :         if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
     490       80714 :                 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
     491             :         }
     492             : 
     493             :         /* do the hard work */
     494       80714 :         ret = smbcli_req_append_string(req, str, flags);
     495             : 
     496             :         /* see if we need to subtract the termination */
     497       80714 :         if (flags & STR_TERMINATE) {
     498       80714 :                 diff += (flags & STR_UNICODE) ? 2 : 1;
     499             :         }
     500             : 
     501       80714 :         if (ret >= diff) {
     502       80714 :                 (*len) = ret - diff;
     503             :         } else {
     504           0 :                 (*len) = ret;
     505             :         }
     506             : 
     507       80714 :         return ret;
     508             : }
     509             : 
     510             : 
     511             : /*
     512             :   push a string into the data portion of the request packet, growing it if necessary
     513             :   this gets quite tricky - please be very careful to cover all cases when modifying this
     514             : 
     515             :   if dest is NULL, then put the string at the end of the data portion of the packet
     516             : 
     517             :   if dest_len is -1 then no limit applies
     518             : */
     519      150896 : size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, unsigned int flags)
     520             : {
     521        9136 :         size_t size;
     522      150896 :         smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
     523      150896 :         size = smbcli_req_append_string(req, str, flags);
     524      150896 :         return size + 1;
     525             : }
     526             : 
     527             : 
     528             : /*
     529             :   push a blob into the data portion of the request packet, growing it if necessary
     530             :   this gets quite tricky - please be very careful to cover all cases when modifying this
     531             : 
     532             :   if dest is NULL, then put the blob at the end of the data portion of the packet
     533             : */
     534        9625 : size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
     535             : {
     536        9625 :         if (blob->length > 0) {
     537        6688 :                 smbcli_req_grow_allocation(req,
     538        6688 :                                            req->out.data_size + blob->length);
     539        6688 :                 memcpy(req->out.data + req->out.data_size,
     540        6688 :                        blob->data,
     541        6688 :                        blob->length);
     542        6688 :                 smbcli_req_grow_data(req, req->out.data_size + blob->length);
     543             :         }
     544        9625 :         return blob->length;
     545             : }
     546             : 
     547             : /*
     548             :   append raw bytes into the data portion of the request packet
     549             :   return the number of bytes added
     550             : */
     551      150896 : size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
     552             : {
     553      150896 :         if (byte_len > 0) {
     554      150896 :                 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
     555      150896 :                 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
     556      150896 :                 smbcli_req_grow_data(req, byte_len + req->out.data_size);
     557             :         }
     558      150896 :         return byte_len;
     559             : }
     560             : 
     561             : /*
     562             :   append variable block (type 5 buffer) into the data portion of the request packet
     563             :   return the number of bytes added
     564             : */
     565         616 : size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
     566             : {
     567         616 :         smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
     568         616 :         SCVAL(req->out.data + req->out.data_size, 0, 5);
     569         616 :         SSVAL(req->out.data + req->out.data_size, 1, byte_len);           /* add field length */
     570         616 :         if (byte_len > 0) {
     571         406 :                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
     572             :         }
     573         616 :         smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
     574         616 :         return byte_len + 3;
     575             : }
     576             : 
     577             : 
     578             : /*
     579             :   pull a UCS2 string from a request packet, returning a talloced unix string
     580             : 
     581             :   the string length is limited by the 3 things:
     582             :    - the data size in the request (end of packet)
     583             :    - the passed 'byte_len' if it is not -1
     584             :    - the end of string (null termination)
     585             : 
     586             :   Note that 'byte_len' is the number of bytes in the packet
     587             : 
     588             :   on failure zero is returned and *dest is set to NULL, otherwise the number
     589             :   of bytes consumed in the packet is returned
     590             : */
     591       19098 : static size_t smbcli_req_pull_ucs2(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
     592             :                                 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
     593             : {
     594       19098 :         int src_len, src_len2, alignment=0;
     595         537 :         bool ret;
     596         537 :         size_t ret_size;
     597             : 
     598       19098 :         if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
     599        1616 :                 src++;
     600        1616 :                 alignment=1;
     601        1616 :                 if (byte_len != -1) {
     602           0 :                         byte_len--;
     603             :                 }
     604             :         }
     605             : 
     606       19098 :         src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
     607       19098 :         if (src_len < 0) {
     608           0 :                 *dest = NULL;
     609           0 :                 return 0;
     610             :         }
     611       19098 :         if (byte_len != -1 && src_len > byte_len) {
     612           0 :                 src_len = byte_len;
     613             :         }
     614             : 
     615       19098 :         src_len2 = utf16_null_terminated_len_n(src, src_len);
     616             : 
     617             :         /* ucs2 strings must be at least 2 bytes long */
     618       19098 :         if (src_len2 < 2) {
     619           0 :                 *dest = NULL;
     620           0 :                 return 0;
     621             :         }
     622             : 
     623       19098 :         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
     624       19098 :         if (!ret) {
     625           0 :                 *dest = NULL;
     626           0 :                 return 0;
     627             :         }
     628             : 
     629       19098 :         return src_len2 + alignment;
     630             : }
     631             : 
     632             : /*
     633             :   pull a ascii string from a request packet, returning a talloced string
     634             : 
     635             :   the string length is limited by the 3 things:
     636             :    - the data size in the request (end of packet)
     637             :    - the passed 'byte_len' if it is not -1
     638             :    - the end of string (null termination)
     639             : 
     640             :   Note that 'byte_len' is the number of bytes in the packet
     641             : 
     642             :   on failure zero is returned and *dest is set to NULL, otherwise the number
     643             :   of bytes consumed in the packet is returned
     644             : */
     645       36269 : size_t smbcli_req_pull_ascii(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
     646             :                              char **dest, const uint8_t *src, int byte_len, unsigned int flags)
     647             : {
     648         140 :         int src_len, src_len2;
     649         140 :         bool ret;
     650         140 :         size_t ret_size;
     651             : 
     652       36269 :         src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
     653       36269 :         if (src_len < 0) {
     654           0 :                 *dest = NULL;
     655           0 :                 return 0;
     656             :         }
     657       36269 :         if (byte_len != -1 && src_len > byte_len) {
     658       32809 :                 src_len = byte_len;
     659             :         }
     660       36269 :         src_len2 = strnlen((const char *)src, src_len);
     661       36269 :         if (src_len2 < src_len - 1) {
     662             :                 /* include the termination if we didn't reach the end of the packet */
     663       32034 :                 src_len2++;
     664             :         }
     665             : 
     666       36269 :         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
     667             : 
     668       36269 :         if (!ret) {
     669           0 :                 *dest = NULL;
     670           0 :                 return 0;
     671             :         }
     672             : 
     673       36269 :         return ret_size;
     674             : }
     675             : 
     676             : /**
     677             :   pull a string from a request packet, returning a talloced string
     678             : 
     679             :   the string length is limited by the 3 things:
     680             :    - the data size in the request (end of packet)
     681             :    - the passed 'byte_len' if it is not -1
     682             :    - the end of string (null termination)
     683             : 
     684             :   Note that 'byte_len' is the number of bytes in the packet
     685             : 
     686             :   on failure zero is returned and *dest is set to NULL, otherwise the number
     687             :   of bytes consumed in the packet is returned
     688             : */
     689       21998 : size_t smbcli_req_pull_string(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
     690             :                            char **dest, const uint8_t *src, int byte_len, unsigned int flags)
     691             : {
     692       21998 :         if (!(flags & STR_ASCII) &&
     693       19098 :             (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
     694       19098 :                 return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags);
     695             :         }
     696             : 
     697        2900 :         return smbcli_req_pull_ascii(bufinfo, mem_ctx, dest, src, byte_len, flags);
     698             : }
     699             : 
     700             : 
     701             : /**
     702             :   pull a DATA_BLOB from a reply packet, returning a talloced blob
     703             :   make sure we don't go past end of packet
     704             : 
     705             :   if byte_len is -1 then limit the blob only by packet size
     706             : */
     707        5389 : DATA_BLOB smbcli_req_pull_blob(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
     708             : {
     709         133 :         int src_len;
     710             : 
     711        5389 :         src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
     712             : 
     713        5389 :         if (src_len < 0) {
     714           0 :                 return data_blob(NULL, 0);
     715             :         }
     716             : 
     717        5389 :         if (byte_len != -1 && src_len > byte_len) {
     718        5389 :                 src_len = byte_len;
     719             :         }
     720             : 
     721        5389 :         return data_blob_talloc(mem_ctx, src, src_len);
     722             : }
     723             : 
     724             : /* check that a lump of data in a request is within the bounds of the data section of
     725             :    the packet */
     726       18148 : static bool smbcli_req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
     727             : {
     728             :         /* be careful with wraparound! */
     729       18193 :         if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
     730       18148 :             (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
     731       18148 :             count > bufinfo->data_size ||
     732       18148 :             (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
     733           0 :                 return true;
     734             :         }
     735       18103 :         return false;
     736             : }
     737             : 
     738             : /*
     739             :   pull a lump of data from a request packet
     740             : 
     741             :   return false if any part is outside the data portion of the packet
     742             : */
     743       34947 : bool smbcli_raw_pull_data(struct request_bufinfo *bufinfo, const uint8_t *src, int len, uint8_t *dest)
     744             : {
     745       34947 :         if (len == 0) return true;
     746             : 
     747       18148 :         if (smbcli_req_data_oob(bufinfo, src, len)) {
     748           0 :                 return false;
     749             :         }
     750             : 
     751       18148 :         memcpy(dest, src, len);
     752       18148 :         return true;
     753             : }
     754             : 
     755             : 
     756             : /*
     757             :   put a NTTIME into a packet
     758             : */
     759        9542 : void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
     760             : {
     761        9542 :         SBVAL(base, offset, t);
     762        9542 : }
     763             : 
     764             : /*
     765             :   pull a NTTIME from a packet
     766             : */
     767     6213306 : NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
     768             : {
     769     6213306 :         NTTIME ret = BVAL(base, offset);
     770     6213306 :         return ret;
     771             : }
     772             : 
     773             : /**
     774             :   pull a UCS2 string from a blob, returning a talloced unix string
     775             : 
     776             :   the string length is limited by the 3 things:
     777             :    - the data size in the blob
     778             :    - the passed 'byte_len' if it is not -1
     779             :    - the end of string (null termination)
     780             : 
     781             :   Note that 'byte_len' is the number of bytes in the packet
     782             : 
     783             :   on failure zero is returned and *dest is set to NULL, otherwise the number
     784             :   of bytes consumed in the blob is returned
     785             : */
     786     1013496 : size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
     787             :                              const DATA_BLOB *blob, const char **dest,
     788             :                              const uint8_t *src, int byte_len, unsigned int flags)
     789             : {
     790     1013496 :         int src_len, src_len2, alignment=0;
     791         614 :         size_t ret_size;
     792         614 :         bool ret;
     793         614 :         char *dest2;
     794             : 
     795     1013496 :         if (src < blob->data ||
     796     1013496 :             src >= (blob->data + blob->length)) {
     797           5 :                 *dest = NULL;
     798           5 :                 return 0;
     799             :         }
     800             : 
     801     1013491 :         src_len = blob->length - PTR_DIFF(src, blob->data);
     802             : 
     803     1013491 :         if (byte_len != -1 && src_len > byte_len) {
     804     1004659 :                 src_len = byte_len;
     805             :         }
     806             : 
     807     1013491 :         if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
     808           0 :                 src++;
     809           0 :                 alignment=1;
     810           0 :                 src_len--;
     811             :         }
     812             : 
     813     1013491 :         if (src_len < 2) {
     814       67051 :                 *dest = NULL;
     815       67051 :                 return 0;
     816             :         }
     817             : 
     818      946440 :         src_len2 = utf16_null_terminated_len_n(src, src_len);
     819             : 
     820      946440 :         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
     821      946440 :         if (!ret) {
     822           0 :                 *dest = NULL;
     823           0 :                 return 0;
     824             :         }
     825      946440 :         *dest = dest2;
     826             : 
     827      946440 :         return src_len2 + alignment;
     828             : }
     829             : 
     830             : /**
     831             :   pull a ascii string from a blob, returning a talloced string
     832             : 
     833             :   the string length is limited by the 3 things:
     834             :    - the data size in the blob
     835             :    - the passed 'byte_len' if it is not -1
     836             :    - the end of string (null termination)
     837             : 
     838             :   Note that 'byte_len' is the number of bytes in the blob
     839             : 
     840             :   on failure zero is returned and *dest is set to NULL, otherwise the number
     841             :   of bytes consumed in the blob is returned
     842             : */
     843           0 : static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
     844             :                                      const DATA_BLOB *blob, const char **dest,
     845             :                                      const uint8_t *src, int byte_len, unsigned int flags)
     846             : {
     847           0 :         int src_len, src_len2;
     848           0 :         size_t ret_size;
     849           0 :         bool ret;
     850           0 :         char *dest2;
     851             : 
     852           0 :         src_len = blob->length - PTR_DIFF(src, blob->data);
     853           0 :         if (src_len < 0) {
     854           0 :                 *dest = NULL;
     855           0 :                 return 0;
     856             :         }
     857           0 :         if (byte_len != -1 && src_len > byte_len) {
     858           0 :                 src_len = byte_len;
     859             :         }
     860           0 :         src_len2 = strnlen((const char *)src, src_len);
     861             : 
     862           0 :         if (src_len2 < src_len - 1) {
     863             :                 /* include the termination if we didn't reach the end of the packet */
     864           0 :                 src_len2++;
     865             :         }
     866             : 
     867           0 :         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
     868             : 
     869           0 :         if (!ret) {
     870           0 :                 *dest = NULL;
     871           0 :                 return 0;
     872             :         }
     873           0 :         *dest = dest2;
     874             : 
     875           0 :         return ret_size;
     876             : }
     877             : 
     878             : /**
     879             :   pull a string from a blob, returning a talloced struct smb_wire_string
     880             : 
     881             :   the string length is limited by the 3 things:
     882             :    - the data size in the blob
     883             :    - length field on the wire
     884             :    - the end of string (null termination)
     885             : 
     886             :    if STR_LEN8BIT is set in the flags then assume the length field is
     887             :    8 bits, instead of 32
     888             : 
     889             :   on failure zero is returned and dest->s is set to NULL, otherwise the number
     890             :   of bytes consumed in the blob is returned
     891             : */
     892     1013490 : size_t smbcli_blob_pull_string(struct smbcli_session *session,
     893             :                                TALLOC_CTX *mem_ctx,
     894             :                                const DATA_BLOB *blob,
     895             :                                struct smb_wire_string *dest,
     896             :                                uint16_t len_offset, uint16_t str_offset,
     897             :                                unsigned int flags)
     898             : {
     899         614 :         int extra;
     900     1013490 :         dest->s = NULL;
     901             : 
     902     1013490 :         if (!(flags & STR_ASCII)) {
     903             :                 /* this is here to cope with SMB2 calls using the SMB
     904             :                    parsers. SMB2 will pass smbcli_session==NULL, which forces
     905             :                    unicode on (as used by SMB2) */
     906     1013490 :                 if (session == NULL) {
     907      877450 :                         flags |= STR_UNICODE;
     908      136040 :                 } else if (session->transport->negotiate.capabilities & CAP_UNICODE) {
     909      136040 :                         flags |= STR_UNICODE;
     910             :                 }
     911             :         }
     912             : 
     913     1013490 :         if (flags & STR_LEN8BIT) {
     914      238954 :                 if (len_offset > blob->length-1) {
     915           0 :                         return 0;
     916             :                 }
     917      238954 :                 dest->private_length = CVAL(blob->data, len_offset);
     918             :         } else {
     919      774536 :                 if (len_offset > blob->length-4) {
     920           0 :                         return 0;
     921             :                 }
     922      774536 :                 dest->private_length = IVAL(blob->data, len_offset);
     923             :         }
     924     1013490 :         extra = 0;
     925     1013490 :         dest->s = NULL;
     926     1013490 :         if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
     927     1013490 :                 int align = 0;
     928     1013490 :                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
     929       10508 :                         align = 1;
     930             :                 }
     931     1013490 :                 if (flags & STR_LEN_NOTERM) {
     932       10508 :                         extra = 2;
     933             :                 }
     934     1013490 :                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
     935     1013490 :                                                           blob->data+str_offset+align,
     936     1013490 :                                                           dest->private_length, flags);
     937             :         }
     938             : 
     939           0 :         if (flags & STR_LEN_NOTERM) {
     940           0 :                 extra = 1;
     941             :         }
     942             : 
     943           0 :         return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
     944           0 :                                            blob->data+str_offset, dest->private_length, flags);
     945             : }
     946             : 
     947             : /**
     948             :   pull a string from a blob, returning a talloced char *
     949             : 
     950             :   Currently only used by the UNIX search info level.
     951             : 
     952             :   the string length is limited by 2 things:
     953             :    - the data size in the blob
     954             :    - the end of string (null termination)
     955             : 
     956             :   on failure zero is returned and dest->s is set to NULL, otherwise the number
     957             :   of bytes consumed in the blob is returned
     958             : */
     959           6 : size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
     960             :                             TALLOC_CTX *mem_ctx,
     961             :                             DATA_BLOB *blob,
     962             :                             const char **dest,
     963             :                             uint16_t str_offset,
     964             :                             unsigned int flags)
     965             : {
     966           6 :         int extra = 0;
     967           6 :         *dest = NULL;
     968             : 
     969           6 :         if (!(flags & STR_ASCII) &&
     970           6 :             ((flags & STR_UNICODE) ||
     971           6 :              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
     972           6 :                 int align = 0;
     973           6 :                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
     974           0 :                         align = 1;
     975             :                 }
     976           6 :                 if (flags & STR_LEN_NOTERM) {
     977           0 :                         extra = 2;
     978             :                 }
     979           6 :                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
     980           6 :                                                           blob->data+str_offset+align,
     981             :                                                           -1, flags);
     982             :         }
     983             : 
     984           0 :         if (flags & STR_LEN_NOTERM) {
     985           0 :                 extra = 1;
     986             :         }
     987             : 
     988           0 :         return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
     989           0 :                                            blob->data+str_offset, -1, flags);
     990             : }
     991             : 
     992             : 
     993             : /*
     994             :   append a string into a blob
     995             : */
     996       23275 : size_t smbcli_blob_append_string(struct smbcli_session *session,
     997             :                               TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
     998             :                               const char *str, unsigned int flags)
     999             : {
    1000         619 :         size_t max_len;
    1001         619 :         int len;
    1002             : 
    1003       23275 :         if (!str) return 0;
    1004             : 
    1005             :         /* determine string type to use */
    1006       23275 :         if (!(flags & (STR_ASCII|STR_UNICODE))) {
    1007       22409 :                 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
    1008             :         }
    1009             : 
    1010       23275 :         max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
    1011             : 
    1012       23275 :         blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length + max_len);
    1013       23275 :         if (!blob->data) {
    1014           0 :                 return 0;
    1015             :         }
    1016             : 
    1017       23275 :         len = push_string(blob->data + blob->length, str, max_len, flags);
    1018             : 
    1019       23275 :         blob->length += len;
    1020             : 
    1021       23275 :         return len;
    1022             : }
    1023             : 
    1024             : /*
    1025             :   pull a GUID structure from the wire. The buffer must be at least 16
    1026             :   bytes long
    1027             :  */
    1028        1611 : NTSTATUS smbcli_pull_guid(void *base, uint16_t offset,
    1029             :                           struct GUID *guid)
    1030             : {
    1031           0 :         DATA_BLOB blob;
    1032             : 
    1033        1611 :         ZERO_STRUCTP(guid);
    1034             : 
    1035        1611 :         blob.data       = offset + (uint8_t *)base;
    1036        1611 :         blob.length     = 16;
    1037             : 
    1038        1611 :         return GUID_from_ndr_blob(&blob, guid);
    1039             : }
    1040             : 
    1041             : /*
    1042             :   push a guid onto the wire. The buffer must hold 16 bytes
    1043             :  */
    1044        1611 : NTSTATUS smbcli_push_guid(void *base, uint16_t offset, const struct GUID *guid)
    1045             : {
    1046        1611 :         struct GUID_ndr_buf buf = { .buf = {0}, };
    1047             : 
    1048        1611 :         GUID_to_ndr_buf(guid, &buf);
    1049        1611 :         memcpy(offset + (uint8_t *)base, buf.buf, sizeof(buf.buf));
    1050        1611 :         return NT_STATUS_OK;
    1051             : }

Generated by: LCOV version 1.14