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