r4229: - added support for multi-part SMBtrans and SMBtrans2 requests in the
[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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23   this file implements functions for manipulating the 'struct smbcli_request' structure in libsmb
24 */
25
26 #include "includes.h"
27 #include "libcli/raw/libcliraw.h"
28 #include "dlinklist.h"
29
30 /* we over allocate the data buffer to prevent too many realloc calls */
31 #define REQ_OVER_ALLOCATION 0
32
33 /* assume that a character will not consume more than 3 bytes per char */
34 #define MAX_BYTES_PER_CHAR 3
35
36 /* destroy a request structure and return final status */
37 NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
38 {
39         NTSTATUS status;
40
41         /* this is the error code we give the application for when a
42            _send() call fails completely */
43         if (!req) return NT_STATUS_UNSUCCESSFUL;
44
45         if (req->transport) {
46                 /* remove it from the list of pending requests (a null op if
47                    its not in the list) */
48                 DLIST_REMOVE(req->transport->pending_recv, req);
49         }
50
51         if (req->state == SMBCLI_REQUEST_ERROR &&
52             NT_STATUS_IS_OK(req->status)) {
53                 req->status = NT_STATUS_INTERNAL_ERROR;
54         }
55
56         status = req->status;
57         talloc_free(req);
58         return status;
59 }
60
61
62 /*
63   low-level function to setup a request buffer for a non-SMB packet 
64   at the transport level
65 */
66 struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, uint_t size)
67 {
68         struct smbcli_request *req;
69
70         req = talloc_p(transport, struct smbcli_request);
71         if (!req) {
72                 return NULL;
73         }
74         ZERO_STRUCTP(req);
75
76         /* setup the request context */
77         req->state = SMBCLI_REQUEST_INIT;
78         req->transport = transport;
79         req->session = NULL;
80         req->tree = NULL;
81         req->out.size = size;
82
83         /* over allocate by a small amount */
84         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
85
86         req->out.buffer = talloc(req, req->out.allocated);
87         if (!req->out.buffer) {
88                 return NULL;
89         }
90
91         SIVAL(req->out.buffer, 0, 0);
92
93         return req;
94 }
95
96
97 /*
98   setup a SMB packet at transport level
99 */
100 struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
101                                                       uint8_t command, uint_t wct, uint_t buflen)
102 {
103         struct smbcli_request *req;
104
105         req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
106
107         if (!req) return NULL;
108         
109         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
110         req->out.vwv = req->out.hdr + HDR_VWV;
111         req->out.wct = wct;
112         req->out.data = req->out.vwv + VWV(wct) + 2;
113         req->out.data_size = buflen;
114         req->out.ptr = req->out.data;
115
116         SCVAL(req->out.hdr, HDR_WCT, wct);
117         SSVAL(req->out.vwv, VWV(wct), buflen);
118
119         memcpy(req->out.hdr, "\377SMB", 4);
120         SCVAL(req->out.hdr,HDR_COM,command);
121
122         SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
123         SSVAL(req->out.hdr,HDR_FLG2, 0);
124
125         if (command != SMBtranss && command != SMBtranss2) {
126                 /* assign a mid */
127                 req->mid = smbcli_transport_next_mid(transport);
128         }
129
130         /* copy the pid, uid and mid to the request */
131         SSVAL(req->out.hdr, HDR_PID, 0);
132         SSVAL(req->out.hdr, HDR_UID, 0);
133         SSVAL(req->out.hdr, HDR_MID, req->mid);
134         SSVAL(req->out.hdr, HDR_TID,0);
135         SSVAL(req->out.hdr, HDR_PIDHIGH,0);
136         SIVAL(req->out.hdr, HDR_RCLS, 0);
137         memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
138         
139         return req;
140 }
141
142 /*
143   setup a reply in req->out with the given word count and initial data
144   buffer size.  the caller will then fill in the command words and
145   data before calling smbcli_request_send() to send the reply on its
146   way. This interface is used before a session is setup.
147 */
148 struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
149                                                     uint8_t command, uint_t wct, uint_t buflen)
150 {
151         struct smbcli_request *req;
152
153         req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
154
155         if (!req) return NULL;
156
157         req->session = session;
158
159         SSVAL(req->out.hdr, HDR_FLG2, session->flags2);
160         SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
161         SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
162         SSVAL(req->out.hdr, HDR_UID, session->vuid);
163         
164         return req;
165 }
166
167 /*
168   setup a request for tree based commands
169 */
170 struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
171                                       uint8_t command, 
172                                       uint_t wct, uint_t buflen)
173 {
174         struct smbcli_request *req;
175
176         req = smbcli_request_setup_session(tree->session, command, wct, buflen);
177         if (req) {
178                 req->tree = tree;
179                 SSVAL(req->out.hdr,HDR_TID,tree->tid);
180         }
181         return req;
182 }
183
184 /*
185   grow the allocation of the data buffer portion of a reply
186   packet. Note that as this can reallocate the packet buffer this
187   invalidates any local pointers into the packet.
188
189   To cope with this req->out.ptr is supplied. This will be updated to
190   point at the same offset into the packet as before this call
191 */
192 static void smbcli_req_grow_allocation(struct smbcli_request *req, uint_t new_size)
193 {
194         int delta;
195         uint8_t *buf2;
196
197         delta = new_size - req->out.data_size;
198         if (delta + req->out.size <= req->out.allocated) {
199                 /* it fits in the preallocation */
200                 return;
201         }
202
203         /* we need to realloc */
204         req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
205         buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
206         if (buf2 == NULL) {
207                 smb_panic("out of memory in req_grow_allocation");
208         }
209
210         if (buf2 == req->out.buffer) {
211                 /* the malloc library gave us the same pointer */
212                 return;
213         }
214         
215         /* update the pointers into the packet */
216         req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
217         req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
218         req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
219         req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
220
221         req->out.buffer = buf2;
222 }
223
224
225 /*
226   grow the data buffer portion of a reply packet. Note that as this
227   can reallocate the packet buffer this invalidates any local pointers
228   into the packet. 
229
230   To cope with this req->out.ptr is supplied. This will be updated to
231   point at the same offset into the packet as before this call
232 */
233 static void smbcli_req_grow_data(struct smbcli_request *req, uint_t new_size)
234 {
235         int delta;
236
237         smbcli_req_grow_allocation(req, new_size);
238
239         delta = new_size - req->out.data_size;
240
241         req->out.size += delta;
242         req->out.data_size += delta;
243
244         /* set the BCC to the new data size */
245         SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
246 }
247
248
249 /*
250   send a message
251 */
252 BOOL smbcli_request_send(struct smbcli_request *req)
253 {
254         if (IVAL(req->out.buffer, 0) == 0) {
255                 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
256         }
257
258         smbcli_request_calculate_sign_mac(req);
259
260         smbcli_transport_send(req);
261
262         return True;
263 }
264
265
266 /*
267   receive a response to a packet
268 */
269 BOOL smbcli_request_receive(struct smbcli_request *req)
270 {
271         /* req can be NULL when a send has failed. This eliminates lots of NULL
272            checks in each module */
273         if (!req) return False;
274
275         /* keep receiving packets until this one is replied to */
276         while (req->state <= SMBCLI_REQUEST_RECV) {
277                 if (event_loop_once(req->transport->event.ctx) != 0) {
278                         return False;
279                 }
280         }
281
282         return req->state == SMBCLI_REQUEST_DONE;
283 }
284
285
286 /*
287   receive another reply to a request - this is used for requests that
288   have multi-part replies (such as SMBtrans2)
289 */
290 BOOL smbcli_request_receive_more(struct smbcli_request *req)
291 {
292         req->state = SMBCLI_REQUEST_RECV;
293         DLIST_ADD(req->transport->pending_recv, req);
294
295         return smbcli_request_receive(req);
296 }
297
298
299 /*
300   handle oplock break requests from the server - return True if the request was
301   an oplock break
302 */
303 BOOL handle_oplock_break(struct smbcli_transport *transport, uint_t len, const uint8_t *hdr, const uint8_t *vwv)
304 {
305         /* we must be very fussy about what we consider an oplock break to avoid
306            matching readbraw replies */
307         if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
308             (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
309             CVAL(hdr,HDR_COM) != SMBlockingX ||
310             SVAL(hdr, HDR_MID) != 0xFFFF ||
311             SVAL(vwv,VWV(6)) != 0 ||
312             SVAL(vwv,VWV(7)) != 0) {
313                 return False;
314         }
315
316         if (transport->oplock.handler) {
317                 uint16_t tid = SVAL(hdr, HDR_TID);
318                 uint16_t fnum = SVAL(vwv,VWV(2));
319                 uint8_t level = CVAL(vwv,VWV(3)+1);
320                 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
321         }
322
323         return True;
324 }
325
326 /*
327   wait for a reply to be received for a packet that just returns an error
328   code and nothing more
329 */
330 NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
331 {
332         smbcli_request_receive(req);
333         return smbcli_request_destroy(req);
334 }
335
336
337 /* Return true if the last packet was in error */
338 BOOL smbcli_request_is_error(struct smbcli_request *req)
339 {
340         return NT_STATUS_IS_ERR(req->status);
341 }
342
343 /*
344   append a string into the data portion of the request packet
345
346   return the number of bytes added to the packet
347 */
348 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, uint_t flags)
349 {
350         size_t len;
351
352         /* determine string type to use */
353         if (!(flags & (STR_ASCII|STR_UNICODE))) {
354                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
355         }
356
357         len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;             
358
359         smbcli_req_grow_allocation(req, len + req->out.data_size);
360
361         len = push_string(req->out.data + req->out.data_size, str, len, flags);
362
363         smbcli_req_grow_data(req, len + req->out.data_size);
364
365         return len;
366 }
367
368
369 /*
370   this is like smbcli_req_append_string but it also return the
371   non-terminated string byte length, which can be less than the number
372   of bytes consumed in the packet for 2 reasons:
373
374    1) the string in the packet may be null terminated
375    2) the string in the packet may need a 1 byte UCS2 alignment
376
377  this is used in places where the non-terminated string byte length is
378  placed in the packet as a separate field  
379 */
380 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, uint_t flags, int *len)
381 {
382         int diff = 0;
383         size_t ret;
384
385         /* determine string type to use */
386         if (!(flags & (STR_ASCII|STR_UNICODE))) {
387                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
388         }
389
390         /* see if an alignment byte will be used */
391         if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
392                 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
393         }
394
395         /* do the hard work */
396         ret = smbcli_req_append_string(req, str, flags);
397
398         /* see if we need to subtract the termination */
399         if (flags & STR_TERMINATE) {
400                 diff += (flags & STR_UNICODE) ? 2 : 1;
401         }
402
403         if (ret >= diff) {
404                 (*len) = ret - diff;
405         } else {
406                 (*len) = ret;
407         }
408
409         return ret;
410 }
411
412
413 /*
414   push a string into the data portion of the request packet, growing it if necessary
415   this gets quite tricky - please be very careful to cover all cases when modifying this
416
417   if dest is NULL, then put the string at the end of the data portion of the packet
418
419   if dest_len is -1 then no limit applies
420 */
421 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, uint_t flags)
422 {
423         size_t size;
424         smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
425         size = smbcli_req_append_string(req, str, flags);
426         return size + 1;
427 }
428
429
430 /*
431   push a blob into the data portion of the request packet, growing it if necessary
432   this gets quite tricky - please be very careful to cover all cases when modifying this
433
434   if dest is NULL, then put the blob at the end of the data portion of the packet
435 */
436 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
437 {
438         smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
439         memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
440         smbcli_req_grow_data(req, req->out.data_size + blob->length);
441         return blob->length;
442 }
443
444 /*
445   append raw bytes into the data portion of the request packet
446   return the number of bytes added
447 */
448 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
449 {
450         smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
451         memcpy(req->out.data + req->out.data_size, bytes, byte_len);
452         smbcli_req_grow_data(req, byte_len + req->out.data_size);
453         return byte_len;
454 }
455
456 /*
457   append variable block (type 5 buffer) into the data portion of the request packet
458   return the number of bytes added
459 */
460 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
461 {
462         smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
463         SCVAL(req->out.data + req->out.data_size, 0, 5);
464         SSVAL(req->out.data + req->out.data_size, 1, byte_len);         /* add field length */
465         if (byte_len > 0) {
466                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
467         }
468         smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
469         return byte_len + 3;
470 }
471
472
473 /*
474   pull a UCS2 string from a request packet, returning a talloced unix string
475
476   the string length is limited by the 3 things:
477    - the data size in the request (end of packet)
478    - the passed 'byte_len' if it is not -1
479    - the end of string (null termination)
480
481   Note that 'byte_len' is the number of bytes in the packet
482
483   on failure zero is returned and *dest is set to NULL, otherwise the number
484   of bytes consumed in the packet is returned
485 */
486 static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
487                                 char **dest, const uint8_t *src, int byte_len, uint_t flags)
488 {
489         int src_len, src_len2, alignment=0;
490         ssize_t ret;
491
492         if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
493                 src++;
494                 alignment=1;
495                 if (byte_len != -1) {
496                         byte_len--;
497                 }
498         }
499
500         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
501         if (src_len < 0) {
502                 *dest = NULL;
503                 return 0;
504         }
505         if (byte_len != -1 && src_len > byte_len) {
506                 src_len = byte_len;
507         }
508
509         src_len2 = utf16_len_n(src, src_len);
510
511         /* ucs2 strings must be at least 2 bytes long */
512         if (src_len2 < 2) {
513                 *dest = NULL;
514                 return 0;
515         }
516
517         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest);
518         if (ret == -1) {
519                 *dest = NULL;
520                 return 0;
521         }
522
523         return src_len2 + alignment;
524 }
525
526 /*
527   pull a ascii string from a request packet, returning a talloced string
528
529   the string length is limited by the 3 things:
530    - the data size in the request (end of packet)
531    - the passed 'byte_len' if it is not -1
532    - the end of string (null termination)
533
534   Note that 'byte_len' is the number of bytes in the packet
535
536   on failure zero is returned and *dest is set to NULL, otherwise the number
537   of bytes consumed in the packet is returned
538 */
539 size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
540                              char **dest, const uint8_t *src, int byte_len, uint_t flags)
541 {
542         int src_len, src_len2;
543         ssize_t ret;
544
545         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
546         if (src_len < 0) {
547                 *dest = NULL;
548                 return 0;
549         }
550         if (byte_len != -1 && src_len > byte_len) {
551                 src_len = byte_len;
552         }
553         src_len2 = strnlen((const char *)src, src_len);
554         if (src_len2 < src_len - 1) {
555                 /* include the termination if we didn't reach the end of the packet */
556                 src_len2++;
557         }
558
559         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest);
560
561         if (ret == -1) {
562                 *dest = NULL;
563                 return 0;
564         }
565
566         return ret;
567 }
568
569 /*
570   pull a string from a request packet, returning a talloced 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 size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx, 
583                            char **dest, const uint8_t *src, int byte_len, uint_t flags)
584 {
585         if (!(flags & STR_ASCII) && 
586             (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
587                 return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
588         }
589
590         return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
591 }
592
593
594 /*
595   pull a DATA_BLOB from a reply packet, returning a talloced blob
596   make sure we don't go past end of packet
597
598   if byte_len is -1 then limit the blob only by packet size
599 */
600 DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
601 {
602         int src_len;
603
604         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
605
606         if (src_len < 0) {
607                 return data_blob(NULL, 0);
608         }
609
610         if (byte_len != -1 && src_len > byte_len) {
611                 src_len = byte_len;
612         }
613
614         return data_blob_talloc(mem_ctx, src, src_len);
615 }
616
617 /* check that a lump of data in a request is within the bounds of the data section of
618    the packet */
619 static BOOL smbcli_req_data_oob(struct smbcli_request *req, const uint8_t *ptr, uint32_t count)
620 {
621         /* be careful with wraparound! */
622         if (ptr < req->in.data ||
623             ptr >= req->in.data + req->in.data_size ||
624             count > req->in.data_size ||
625             ptr + count > req->in.data + req->in.data_size) {
626                 return True;
627         }
628         return False;
629 }
630
631 /*
632   pull a lump of data from a request packet
633
634   return False if any part is outside the data portion of the packet
635 */
636 BOOL smbcli_raw_pull_data(struct smbcli_request *req, const uint8_t *src, int len, uint8_t *dest)
637 {
638         if (len == 0) return True;
639
640         if (smbcli_req_data_oob(req, src, len)) {
641                 return False;
642         }
643
644         memcpy(dest, src, len);
645         return True;
646 }
647
648
649 /*
650   put a NTTIME into a packet
651 */
652 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
653 {
654         SBVAL(base, offset, t);
655 }
656
657 /*
658   pull a NTTIME from a packet
659 */
660 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
661 {
662         NTTIME ret = BVAL(base, offset);
663         return ret;
664 }
665
666 /*
667   pull a UCS2 string from a blob, returning a talloced unix string
668
669   the string length is limited by the 3 things:
670    - the data size in the blob
671    - the passed 'byte_len' if it is not -1
672    - the end of string (null termination)
673
674   Note that 'byte_len' is the number of bytes in the packet
675
676   on failure zero is returned and *dest is set to NULL, otherwise the number
677   of bytes consumed in the blob is returned
678 */
679 static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
680                                  DATA_BLOB *blob, const char **dest, 
681                                  const uint8_t *src, int byte_len, uint_t flags)
682 {
683         int src_len, src_len2, alignment=0;
684         ssize_t ret;
685         char *dest2;
686
687         if (src < blob->data ||
688             src >= (blob->data + blob->length)) {
689                 *dest = NULL;
690                 return 0;
691         }
692
693         src_len = blob->length - PTR_DIFF(src, blob->data);
694
695         if (byte_len != -1 && src_len > byte_len) {
696                 src_len = byte_len;
697         }
698
699         if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
700                 src++;
701                 alignment=1;
702                 src_len--;
703         }
704
705         if (src_len < 2) {
706                 *dest = NULL;
707                 return 0;
708         }
709
710         src_len2 = utf16_len_n(src, src_len);
711
712         ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
713         if (ret == -1) {
714                 *dest = NULL;
715                 return 0;
716         }
717         *dest = dest2;
718
719         return src_len2 + alignment;
720 }
721
722 /*
723   pull a ascii string from a blob, returning a talloced string
724
725   the string length is limited by the 3 things:
726    - the data size in the blob
727    - the passed 'byte_len' if it is not -1
728    - the end of string (null termination)
729
730   Note that 'byte_len' is the number of bytes in the blob
731
732   on failure zero is returned and *dest is set to NULL, otherwise the number
733   of bytes consumed in the blob is returned
734 */
735 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
736                                   DATA_BLOB *blob, const char **dest, 
737                                   const uint8_t *src, int byte_len, uint_t flags)
738 {
739         int src_len, src_len2;
740         ssize_t ret;
741         char *dest2;
742
743         src_len = blob->length - PTR_DIFF(src, blob->data);
744         if (src_len < 0) {
745                 *dest = NULL;
746                 return 0;
747         }
748         if (byte_len != -1 && src_len > byte_len) {
749                 src_len = byte_len;
750         }
751         src_len2 = strnlen((const char *)src, src_len);
752
753         if (src_len2 < src_len - 1) {
754                 /* include the termination if we didn't reach the end of the packet */
755                 src_len2++;
756         }
757
758         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
759
760         if (ret == -1) {
761                 *dest = NULL;
762                 return 0;
763         }
764         *dest = dest2;
765
766         return ret;
767 }
768
769 /*
770   pull a string from a blob, returning a talloced WIRE_STRING
771
772   the string length is limited by the 3 things:
773    - the data size in the blob
774    - length field on the wire
775    - the end of string (null termination)
776
777    if STR_LEN8BIT is set in the flags then assume the length field is
778    8 bits, instead of 32
779
780   on failure zero is returned and dest->s is set to NULL, otherwise the number
781   of bytes consumed in the blob is returned
782 */
783 size_t smbcli_blob_pull_string(struct smbcli_session *session,
784                             TALLOC_CTX *mem_ctx,
785                             DATA_BLOB *blob, 
786                             WIRE_STRING *dest, 
787                             uint16_t len_offset, uint16_t str_offset, 
788                             uint_t flags)
789 {
790         int extra;
791         dest->s = NULL;
792         
793         if (flags & STR_LEN8BIT) {
794                 if (len_offset > blob->length-1) {
795                         return 0;
796                 }
797                 dest->private_length = CVAL(blob->data, len_offset);
798         } else {
799                 if (len_offset > blob->length-4) {
800                         return 0;
801                 }
802                 dest->private_length = IVAL(blob->data, len_offset);
803         }
804         extra = 0;
805         dest->s = NULL;
806         if (!(flags & STR_ASCII) && 
807             ((flags & STR_UNICODE) || 
808              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
809                 int align = 0;
810                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
811                         align = 1;
812                 }
813                 if (flags & STR_LEN_NOTERM) {
814                         extra = 2;
815                 }
816                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s, 
817                                                           blob->data+str_offset+align, 
818                                                           dest->private_length, flags);
819         }
820
821         if (flags & STR_LEN_NOTERM) {
822                 extra = 1;
823         }
824
825         return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s, 
826                                            blob->data+str_offset, dest->private_length, flags);
827 }
828
829 /*
830   pull a string from a blob, returning a talloced char *
831
832   Currently only used by the UNIX search info level.
833
834   the string length is limited by 2 things:
835    - the data size in the blob
836    - the end of string (null termination)
837
838   on failure zero is returned and dest->s is set to NULL, otherwise the number
839   of bytes consumed in the blob is returned
840 */
841 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
842                             TALLOC_CTX *mem_ctx,
843                             DATA_BLOB *blob, 
844                             const char **dest, 
845                             uint16_t str_offset, 
846                             uint_t flags)
847 {
848         int extra = 0;
849         *dest = NULL;
850         
851         if (!(flags & STR_ASCII) && 
852             ((flags & STR_UNICODE) || 
853              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
854                 int align = 0;
855                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
856                         align = 1;
857                 }
858                 if (flags & STR_LEN_NOTERM) {
859                         extra = 2;
860                 }
861                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest, 
862                                                           blob->data+str_offset+align, 
863                                                           -1, flags);
864         }
865
866         if (flags & STR_LEN_NOTERM) {
867                 extra = 1;
868         }
869
870         return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
871                                            blob->data+str_offset, -1, flags);
872 }
873
874
875 /*
876   append a string into a blob
877 */
878 size_t smbcli_blob_append_string(struct smbcli_session *session,
879                               TALLOC_CTX *mem_ctx, DATA_BLOB *blob, 
880                               const char *str, uint_t flags)
881 {
882         size_t max_len;
883         int len;
884
885         if (!str) return 0;
886
887         /* determine string type to use */
888         if (!(flags & (STR_ASCII|STR_UNICODE))) {
889                 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
890         }
891
892         max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;         
893
894         blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
895         if (!blob->data) {
896                 return 0;
897         }
898
899         len = push_string(blob->data + blob->length, str, max_len, flags);
900
901         blob->length += len;
902
903         return len;
904 }