LCOV - code coverage report
Current view: top level - source4/libcli/raw - rawrequest.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 328 405 81.0 %
Date: 2024-06-13 04:01:37 Functions: 32 34 94.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      294671 : void smb_setup_bufinfo(struct smbcli_request *req)
      41             : {
      42      294671 :         req->in.bufinfo.mem_ctx    = req;
      43      294671 :         req->in.bufinfo.flags      = 0;
      44      294671 :         if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
      45      294654 :                 req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE;
      46             :         }
      47      294671 :         req->in.bufinfo.align_base = req->in.buffer;
      48      294671 :         req->in.bufinfo.data       = req->in.data;
      49      294671 :         req->in.bufinfo.data_size  = req->in.data_size;
      50      294671 : }
      51             : 
      52             : 
      53             : /* destroy a request structure and return final status */
      54      332893 : _PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
      55             : {
      56             :         NTSTATUS status;
      57             : 
      58             :         /* this is the error code we give the application for when a
      59             :            _send() call fails completely */
      60      332893 :         if (!req) return NT_STATUS_UNSUCCESSFUL;
      61             : 
      62      362469 :         if (req->state == SMBCLI_REQUEST_ERROR &&
      63       29588 :             NT_STATUS_IS_OK(req->status)) {
      64           0 :                 req->status = NT_STATUS_INTERNAL_ERROR;
      65             :         }
      66             : 
      67      332883 :         status = req->status;
      68             : 
      69      332883 :         if (!req->do_not_free) {
      70      331898 :                 talloc_free(req);
      71             :         }
      72             : 
      73      332883 :         return status;
      74             : }
      75             : 
      76             : 
      77             : /*
      78             :   setup a SMB packet at transport level
      79             : */
      80      332993 : struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
      81             :                                                       uint8_t command, unsigned int wct, unsigned int buflen)
      82             : {
      83             :         struct smbcli_request *req;
      84             :         size_t size;
      85             : 
      86      332993 :         size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
      87             : 
      88      332993 :         req = talloc_zero(transport, struct smbcli_request);
      89      332993 :         if (!req) {
      90           0 :                 return NULL;
      91             :         }
      92             : 
      93             :         /* setup the request context */
      94      332993 :         req->state = SMBCLI_REQUEST_INIT;
      95      332993 :         req->transport = transport;
      96      332993 :         req->out.size = size;
      97             : 
      98             :         /* over allocate by a small amount */
      99      332993 :         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
     100             : 
     101      332993 :         req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
     102      332993 :         if (!req->out.buffer) {
     103           0 :                 return NULL;
     104             :         }
     105             : 
     106      332993 :         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
     107      332993 :         req->out.vwv = req->out.hdr + HDR_VWV;
     108      332993 :         req->out.wct = wct;
     109      332993 :         req->out.data = req->out.vwv + VWV(wct) + 2;
     110      332993 :         req->out.data_size = buflen;
     111      332993 :         req->out.ptr = req->out.data;
     112             : 
     113      332993 :         SCVAL(req->out.hdr, HDR_WCT, wct);
     114      332993 :         SSVAL(req->out.vwv, VWV(wct), buflen);
     115             : 
     116      332993 :         memcpy(req->out.hdr, "\377SMB", 4);
     117      332993 :         SCVAL(req->out.hdr,HDR_COM,command);
     118             : 
     119      332993 :         SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
     120      332993 :         SSVAL(req->out.hdr,HDR_FLG2, 0);
     121             : 
     122             :         /* copy the pid, uid and mid to the request */
     123      332993 :         SSVAL(req->out.hdr, HDR_PID, 0);
     124      332993 :         SSVAL(req->out.hdr, HDR_UID, 0);
     125      332993 :         SSVAL(req->out.hdr, HDR_MID, 0);
     126      332993 :         SSVAL(req->out.hdr, HDR_TID,0);
     127      332993 :         SSVAL(req->out.hdr, HDR_PIDHIGH,0);
     128      332993 :         SIVAL(req->out.hdr, HDR_RCLS, 0);
     129      332993 :         memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
     130             :         
     131      332993 :         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      332992 : struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
     141             :                                                     uint8_t command, unsigned int wct, size_t buflen)
     142             : {
     143             :         struct smbcli_request *req;
     144             : 
     145      332992 :         req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
     146             : 
     147      332992 :         if (!req) return NULL;
     148             : 
     149      332992 :         smb1cli_session_set_id(session->smbXcli, session->vuid);
     150             : 
     151      332992 :         req->session = session;
     152             : 
     153      332992 :         SSVAL(req->out.hdr, HDR_FLG2, session->flags2);
     154      332992 :         SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
     155      332992 :         SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
     156      332992 :         SSVAL(req->out.hdr, HDR_UID, session->vuid);
     157             :         
     158      332992 :         return req;
     159             : }
     160             : 
     161             : /*
     162             :   setup a request for tree based commands
     163             : */
     164      331325 : struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
     165             :                                             uint8_t command, 
     166             :                                             unsigned int wct, unsigned int buflen)
     167             : {
     168             :         struct smbcli_request *req;
     169             : 
     170      331325 :         req = smbcli_request_setup_session(tree->session, command, wct, buflen);
     171      331325 :         if (req) {
     172      331325 :                 smb1cli_tcon_set_id(tree->smbXcli, tree->tid);
     173             : 
     174      331325 :                 req->tree = tree;
     175      331325 :                 SSVAL(req->out.hdr,HDR_TID,tree->tid);
     176             :         }
     177      331325 :         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      424428 : static void smbcli_req_grow_allocation(struct smbcli_request *req, unsigned int new_size)
     190             : {
     191             :         int delta;
     192             :         uint8_t *buf2;
     193             : 
     194      424428 :         delta = new_size - req->out.data_size;
     195      424428 :         if (delta + req->out.size <= req->out.allocated) {
     196             :                 /* it fits in the preallocation */
     197      218362 :                 return;
     198             :         }
     199             : 
     200             :         /* we need to realloc */
     201      206066 :         req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
     202      206066 :         buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
     203      206066 :         if (buf2 == NULL) {
     204           0 :                 smb_panic("out of memory in req_grow_allocation");
     205             :         }
     206             : 
     207      206066 :         if (buf2 == req->out.buffer) {
     208             :                 /* the malloc library gave us the same pointer */
     209       84172 :                 return;
     210             :         }
     211             :         
     212             :         /* update the pointers into the packet */
     213      121894 :         req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
     214      121894 :         req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
     215      121894 :         req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
     216      121894 :         req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
     217             : 
     218      121894 :         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      212214 : static void smbcli_req_grow_data(struct smbcli_request *req, unsigned int new_size)
     231             : {
     232             :         int delta;
     233             : 
     234      212214 :         smbcli_req_grow_allocation(req, new_size);
     235             : 
     236      212214 :         delta = new_size - req->out.data_size;
     237             : 
     238      212214 :         req->out.size += delta;
     239      212214 :         req->out.data_size += delta;
     240             : 
     241             :         /* set the BCC to the new data size */
     242      212214 :         SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
     243      212214 : }
     244             : 
     245             : 
     246             : /*
     247             :   setup a chained reply in req->out with the given word count and
     248             :   initial data buffer size.
     249             : */
     250           3 : NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req,
     251             :                                       uint8_t command, 
     252             :                                       unsigned int wct, size_t buflen)
     253             : {
     254             :         size_t wct_ofs;
     255             :         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           3 :         if (req->subreqs[0] != NULL) {
     263           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     264             :         }
     265           3 :         if (req->subreqs[1] != NULL) {
     266           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     267             :         }
     268             : 
     269           3 :         req->subreqs[0] = smbcli_transport_setup_subreq(req);
     270           3 :         if (req->subreqs[0] == NULL) {
     271           0 :                 return NT_STATUS_NO_MEMORY;
     272             :         }
     273             : 
     274           3 :         wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1);
     275             : 
     276           3 :         size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen;
     277             : 
     278           3 :         req->out.size = size;
     279             : 
     280             :         /* over allocate by a small amount */
     281           3 :         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
     282             : 
     283           3 :         req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
     284           3 :         if (!req->out.buffer) {
     285           0 :                 return NT_STATUS_NO_MEMORY;
     286             :         }
     287             : 
     288           3 :         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
     289           3 :         req->out.vwv = req->out.hdr + wct_ofs;
     290           3 :         req->out.wct = wct;
     291           3 :         req->out.data = req->out.vwv + VWV(wct) + 2;
     292           3 :         req->out.data_size = buflen;
     293           3 :         req->out.ptr = req->out.data;
     294             : 
     295           3 :         SCVAL(req->out.hdr, HDR_WCT, wct);
     296           3 :         SSVAL(req->out.vwv, VWV(wct), buflen);
     297             : 
     298           3 :         memcpy(req->out.hdr, "\377SMB", 4);
     299           3 :         SCVAL(req->out.hdr,HDR_COM,command);
     300             : 
     301           3 :         SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
     302           3 :         SSVAL(req->out.hdr,HDR_FLG2, 0);
     303             : 
     304             :         /* copy the pid, uid and mid to the request */
     305           3 :         SSVAL(req->out.hdr, HDR_PID, 0);
     306           3 :         SSVAL(req->out.hdr, HDR_UID, 0);
     307           3 :         SSVAL(req->out.hdr, HDR_MID, 0);
     308           3 :         SSVAL(req->out.hdr, HDR_TID,0);
     309           3 :         SSVAL(req->out.hdr, HDR_PIDHIGH,0);
     310           3 :         SIVAL(req->out.hdr, HDR_RCLS, 0);
     311           3 :         memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
     312             : 
     313           3 :         if (req->session != NULL) {
     314           3 :                 SSVAL(req->out.hdr, HDR_FLG2, req->session->flags2);
     315           3 :                 SSVAL(req->out.hdr, HDR_PID, req->session->pid & 0xFFFF);
     316           3 :                 SSVAL(req->out.hdr, HDR_PIDHIGH, req->session->pid >> 16);
     317           3 :                 SSVAL(req->out.hdr, HDR_UID, req->session->vuid);
     318             :         }
     319             : 
     320           3 :         if (req->tree != NULL) {
     321           3 :                 SSVAL(req->out.hdr, HDR_TID, req->tree->tid);
     322             :         }
     323             : 
     324           3 :         return NT_STATUS_OK;
     325             : }
     326             : 
     327             : /*
     328             :   advance to the next chained reply in a request
     329             : */
     330           2 : NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
     331             : {
     332           2 :         struct smbcli_transport *transport = req->transport;
     333           2 :         uint8_t *hdr = NULL;
     334           2 :         uint8_t wct = 0;
     335           2 :         uint16_t *vwv = NULL;
     336           2 :         uint32_t num_bytes = 0;
     337           2 :         uint8_t *bytes = NULL;
     338           2 :         struct iovec *recv_iov = NULL;
     339           2 :         uint8_t *inbuf = NULL;
     340             : 
     341           2 :         if (req->subreqs[0] != NULL) {
     342           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     343             :         }
     344           2 :         if (req->subreqs[1] == NULL) {
     345           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     346             :         }
     347             : 
     348           2 :         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           2 :         TALLOC_FREE(req->subreqs[1]);
     360           2 :         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           2 :         req->in.buffer = inbuf;
     369           2 :         req->in.size = NBT_HDR_SIZE + PTR_DIFF(bytes, hdr) + num_bytes;
     370           2 :         req->in.allocated = req->in.size;
     371             : 
     372           2 :         req->in.hdr = hdr;
     373           2 :         req->in.vwv = (uint8_t *)vwv;
     374           2 :         req->in.wct = wct;
     375           2 :         req->in.data = bytes;
     376           2 :         req->in.data_size = num_bytes;
     377           2 :         req->in.ptr = req->in.data;
     378           2 :         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
     379             : 
     380           2 :         smb_setup_bufinfo(req);
     381             : 
     382           2 :         transport->error.e.nt_status = req->status;
     383           2 :         if (NT_STATUS_IS_OK(req->status)) {
     384           2 :                 transport->error.etype = ETYPE_NONE;
     385             :         } else {
     386           0 :                 transport->error.etype = ETYPE_SMB;
     387             :         }
     388             : 
     389           2 :         req->state = SMBCLI_REQUEST_DONE;
     390             : 
     391           2 :         return NT_STATUS_OK;
     392             : }
     393             : 
     394             : 
     395             : /*
     396             :   send a message
     397             : */
     398      294802 : bool smbcli_request_send(struct smbcli_request *req)
     399             : {
     400      294802 :         smbcli_transport_send(req);
     401      294802 :         return true;
     402             : }
     403             : 
     404             : 
     405             : /*
     406             :   receive a response to a packet
     407             : */
     408      332934 : 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      332934 :         if (!req) return false;
     413             : 
     414             :         /* keep receiving packets until this one is replied to */
     415     1509551 :         while (req->state <= SMBCLI_REQUEST_RECV) {
     416      843959 :                 if (tevent_loop_once(req->transport->ev) != 0) {
     417           0 :                         return false;
     418             :                 }
     419             :         }
     420             : 
     421      332924 :         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      137520 : _PUBLIC_ NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
     429             : {
     430      137520 :         (void) smbcli_request_receive(req);
     431      137520 :         return smbcli_request_destroy(req);
     432             : }
     433             : 
     434             : 
     435             : /* Return true if the last packet was in error */
     436      138109 : bool smbcli_request_is_error(struct smbcli_request *req)
     437             : {
     438      138109 :         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      146869 : size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, unsigned int flags)
     447             : {
     448             :         size_t len;
     449             : 
     450             :         /* determine string type to use */
     451      146869 :         if (!(flags & (STR_ASCII|STR_UNICODE))) {
     452       79241 :                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
     453             :         }
     454             : 
     455      146869 :         len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;             
     456             : 
     457      146869 :         smbcli_req_grow_allocation(req, len + req->out.data_size);
     458             : 
     459      146869 :         len = push_string(req->out.data + req->out.data_size, str, len, flags);
     460             : 
     461      146869 :         smbcli_req_grow_data(req, len + req->out.data_size);
     462             : 
     463      146869 :         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       66709 : size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, unsigned int flags, int *len)
     479             : {
     480       66709 :         int diff = 0;
     481             :         size_t ret;
     482             : 
     483             :         /* determine string type to use */
     484       66709 :         if (!(flags & (STR_ASCII|STR_UNICODE))) {
     485       66709 :                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
     486             :         }
     487             : 
     488             :         /* see if an alignment byte will be used */
     489       66709 :         if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
     490       66709 :                 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
     491             :         }
     492             : 
     493             :         /* do the hard work */
     494       66709 :         ret = smbcli_req_append_string(req, str, flags);
     495             : 
     496             :         /* see if we need to subtract the termination */
     497       66709 :         if (flags & STR_TERMINATE) {
     498       66709 :                 diff += (flags & STR_UNICODE) ? 2 : 1;
     499             :         }
     500             : 
     501       66709 :         if (ret >= diff) {
     502       66709 :                 (*len) = ret - diff;
     503             :         } else {
     504           0 :                 (*len) = ret;
     505             :         }
     506             : 
     507       66709 :         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       64194 : size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, unsigned int flags)
     520             : {
     521             :         size_t size;
     522       64194 :         smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
     523       64194 :         size = smbcli_req_append_string(req, str, flags);
     524       64194 :         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        1958 : size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
     535             : {
     536        1958 :         if (blob->length > 0) {
     537        1988 :                 smbcli_req_grow_allocation(req,
     538        1988 :                                            req->out.data_size + blob->length);
     539        1988 :                 memcpy(req->out.data + req->out.data_size,
     540        1037 :                        blob->data,
     541          86 :                        blob->length);
     542        1037 :                 smbcli_req_grow_data(req, req->out.data_size + blob->length);
     543             :         }
     544        1958 :         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       64194 : size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
     552             : {
     553       64194 :         if (byte_len > 0) {
     554       64194 :                 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
     555       64194 :                 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
     556       64194 :                 smbcli_req_grow_data(req, byte_len + req->out.data_size);
     557             :         }
     558       64194 :         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         114 : size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
     566             : {
     567         114 :         smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
     568         114 :         SCVAL(req->out.data + req->out.data_size, 0, 5);
     569         114 :         SSVAL(req->out.data + req->out.data_size, 1, byte_len);           /* add field length */
     570         114 :         if (byte_len > 0) {
     571          78 :                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
     572             :         }
     573         114 :         smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
     574         114 :         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        3987 : 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        3987 :         int src_len, src_len2, alignment=0;
     595             :         bool ret;
     596             :         size_t ret_size;
     597             : 
     598        3987 :         if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
     599         837 :                 src++;
     600         837 :                 alignment=1;
     601         837 :                 if (byte_len != -1) {
     602           0 :                         byte_len--;
     603             :                 }
     604             :         }
     605             : 
     606        3987 :         src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
     607        3987 :         if (src_len < 0) {
     608           0 :                 *dest = NULL;
     609           0 :                 return 0;
     610             :         }
     611        3987 :         if (byte_len != -1 && src_len > byte_len) {
     612           0 :                 src_len = byte_len;
     613             :         }
     614             : 
     615        3987 :         src_len2 = utf16_len_n(src, src_len);
     616             : 
     617             :         /* ucs2 strings must be at least 2 bytes long */
     618        3987 :         if (src_len2 < 2) {
     619           0 :                 *dest = NULL;
     620           0 :                 return 0;
     621             :         }
     622             : 
     623        3987 :         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
     624        3987 :         if (!ret) {
     625           0 :                 *dest = NULL;
     626           0 :                 return 0;
     627             :         }
     628             : 
     629        3987 :         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       13685 : 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             :         int src_len, src_len2;
     649             :         bool ret;
     650             :         size_t ret_size;
     651             : 
     652       13685 :         src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
     653       13685 :         if (src_len < 0) {
     654           0 :                 *dest = NULL;
     655           0 :                 return 0;
     656             :         }
     657       13685 :         if (byte_len != -1 && src_len > byte_len) {
     658       12675 :                 src_len = byte_len;
     659             :         }
     660       13685 :         src_len2 = strnlen((const char *)src, src_len);
     661       13685 :         if (src_len2 < src_len - 1) {
     662             :                 /* include the termination if we didn't reach the end of the packet */
     663       13078 :                 src_len2++;
     664             :         }
     665             : 
     666       13685 :         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
     667             : 
     668       13685 :         if (!ret) {
     669           0 :                 *dest = NULL;
     670           0 :                 return 0;
     671             :         }
     672             : 
     673       13685 :         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        4897 : 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        8592 :         if (!(flags & STR_ASCII) && 
     693        7682 :             (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
     694        3987 :                 return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags);
     695             :         }
     696             : 
     697         910 :         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        1022 : DATA_BLOB smbcli_req_pull_blob(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
     708             : {
     709             :         int src_len;
     710             : 
     711        1022 :         src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
     712             : 
     713        1022 :         if (src_len < 0) {
     714           0 :                 return data_blob(NULL, 0);
     715             :         }
     716             : 
     717        1022 :         if (byte_len != -1 && src_len > byte_len) {
     718        1022 :                 src_len = byte_len;
     719             :         }
     720             : 
     721        1022 :         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       16244 : static bool smbcli_req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
     727             : {
     728             :         /* be careful with wraparound! */
     729       32461 :         if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
     730       32461 :             (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
     731       32461 :             count > bufinfo->data_size ||
     732       16244 :             (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
     733           0 :                 return true;
     734             :         }
     735       16244 :         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       32734 : bool smbcli_raw_pull_data(struct request_bufinfo *bufinfo, const uint8_t *src, int len, uint8_t *dest)
     744             : {
     745       32734 :         if (len == 0) return true;
     746             : 
     747       16244 :         if (smbcli_req_data_oob(bufinfo, src, len)) {
     748           0 :                 return false;
     749             :         }
     750             : 
     751       16244 :         memcpy(dest, src, len);
     752       16244 :         return true;
     753             : }
     754             : 
     755             : 
     756             : /*
     757             :   put a NTTIME into a packet
     758             : */
     759        2208 : void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
     760             : {
     761        2208 :         SBVAL(base, offset, t);
     762        2208 : }
     763             : 
     764             : /*
     765             :   pull a NTTIME from a packet
     766             : */
     767     1517099 : NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
     768             : {
     769     1517099 :         NTTIME ret = BVAL(base, offset);
     770     1517099 :         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      136135 : 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      136135 :         int src_len, src_len2, alignment=0;
     791             :         size_t ret_size;
     792             :         bool ret;
     793             :         char *dest2;
     794             : 
     795      272194 :         if (src < blob->data ||
     796      136135 :             src >= (blob->data + blob->length)) {
     797           1 :                 *dest = NULL;
     798           1 :                 return 0;
     799             :         }
     800             : 
     801      136134 :         src_len = blob->length - PTR_DIFF(src, blob->data);
     802             : 
     803      136134 :         if (byte_len != -1 && src_len > byte_len) {
     804      134760 :                 src_len = byte_len;
     805             :         }
     806             : 
     807      136134 :         if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
     808           0 :                 src++;
     809           0 :                 alignment=1;
     810           0 :                 src_len--;
     811             :         }
     812             : 
     813      136134 :         if (src_len < 2) {
     814           8 :                 *dest = NULL;
     815           8 :                 return 0;
     816             :         }
     817             : 
     818      136126 :         src_len2 = utf16_len_n(src, src_len);
     819             : 
     820      136126 :         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
     821      136126 :         if (!ret) {
     822           0 :                 *dest = NULL;
     823           0 :                 return 0;
     824             :         }
     825      136126 :         *dest = dest2;
     826             : 
     827      136126 :         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             :         int src_len, src_len2;
     848             :         size_t ret_size;
     849             :         bool ret;
     850             :         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      136135 : 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             :         int extra;
     900      136135 :         dest->s = NULL;
     901             : 
     902      136135 :         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      136135 :                 if (session == NULL) {
     907      115325 :                         flags |= STR_UNICODE;
     908       20810 :                 } else if (session->transport->negotiate.capabilities & CAP_UNICODE) {
     909       20810 :                         flags |= STR_UNICODE;
     910             :                 }
     911             :         }
     912             : 
     913      136135 :         if (flags & STR_LEN8BIT) {
     914       41343 :                 if (len_offset > blob->length-1) {
     915           0 :                         return 0;
     916             :                 }
     917       41343 :                 dest->private_length = CVAL(blob->data, len_offset);
     918             :         } else {
     919       94792 :                 if (len_offset > blob->length-4) {
     920           0 :                         return 0;
     921             :                 }
     922       94792 :                 dest->private_length = IVAL(blob->data, len_offset);
     923             :         }
     924      136135 :         extra = 0;
     925      136135 :         dest->s = NULL;
     926      136135 :         if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
     927      136135 :                 int align = 0;
     928      136135 :                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
     929        2102 :                         align = 1;
     930             :                 }
     931      136135 :                 if (flags & STR_LEN_NOTERM) {
     932        2102 :                         extra = 2;
     933             :                 }
     934      408253 :                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s, 
     935      136135 :                                                           blob->data+str_offset+align, 
     936      136135 :                                                           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           0 : 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           0 :         int extra = 0;
     967           0 :         *dest = NULL;
     968             :         
     969           0 :         if (!(flags & STR_ASCII) && 
     970           0 :             ((flags & STR_UNICODE) || 
     971           0 :              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
     972           0 :                 int align = 0;
     973           0 :                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
     974           0 :                         align = 1;
     975             :                 }
     976           0 :                 if (flags & STR_LEN_NOTERM) {
     977           0 :                         extra = 2;
     978             :                 }
     979           0 :                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest, 
     980           0 :                                                           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        9694 : 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             :         size_t max_len;
    1001             :         int len;
    1002             : 
    1003        9694 :         if (!str) return 0;
    1004             : 
    1005             :         /* determine string type to use */
    1006        9694 :         if (!(flags & (STR_ASCII|STR_UNICODE))) {
    1007        9643 :                 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
    1008             :         }
    1009             : 
    1010        9694 :         max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;         
    1011             : 
    1012        9694 :         blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length + max_len);
    1013        9694 :         if (!blob->data) {
    1014           0 :                 return 0;
    1015             :         }
    1016             : 
    1017        9694 :         len = push_string(blob->data + blob->length, str, max_len, flags);
    1018             : 
    1019        9694 :         blob->length += len;
    1020             : 
    1021        9694 :         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        1654 : NTSTATUS smbcli_pull_guid(void *base, uint16_t offset,
    1029             :                           struct GUID *guid)
    1030             : {
    1031             :         DATA_BLOB blob;
    1032             : 
    1033        1654 :         ZERO_STRUCTP(guid);
    1034             : 
    1035        1654 :         blob.data       = offset + (uint8_t *)base;
    1036        1654 :         blob.length     = 16;
    1037             : 
    1038        1654 :         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        1654 : NTSTATUS smbcli_push_guid(void *base, uint16_t offset, const struct GUID *guid)
    1045             : {
    1046             :         NTSTATUS status;
    1047        1654 :         struct GUID_ndr_buf buf = { .buf = {0}, };
    1048             : 
    1049        1654 :         status = GUID_to_ndr_buf(guid, &buf);
    1050        1654 :         if (!NT_STATUS_IS_OK(status)) {
    1051           0 :                 return status;
    1052             :         }
    1053        1654 :         memcpy(offset + (uint8_t *)base, buf.buf, sizeof(buf.buf));
    1054        1654 :         return NT_STATUS_OK;
    1055             : }

Generated by: LCOV version 1.13