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