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