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