r1654: rename cli_ -> smbcli_
[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_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 smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, uint_t size)
62 {
63         struct smbcli_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("smbcli_request");
71         if (!mem_ctx) {
72                 return NULL;
73         }
74
75         req = talloc(mem_ctx, sizeof(struct smbcli_request));
76         if (!req) {
77                 return NULL;
78         }
79         ZERO_STRUCTP(req);
80
81         /* setup the request context */
82         req->state = SMBCLI_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 smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
107                                                 uint8_t command, uint_t wct, uint_t buflen)
108 {
109         struct smbcli_request *req;
110
111         req = smbcli_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 = smbcli_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 smbcli_request_send() to send the reply on its
150   way. This interface is used before a session is setup.
151 */
152 struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
153                                               uint8_t command, uint_t wct, uint_t buflen)
154 {
155         struct smbcli_request *req;
156         uint16_t flags2;
157         uint32_t capabilities;
158
159         req = smbcli_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 smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
193                                       uint8_t command, 
194                                       uint_t wct, uint_t buflen)
195 {
196         struct smbcli_request *req;
197
198         req = smbcli_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 smbcli_req_grow_allocation(struct smbcli_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 smbcli_req_grow_data(struct smbcli_request *req, uint_t new_size)
256 {
257         int delta;
258
259         smbcli_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 smbcli_request_send(struct smbcli_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         smbcli_request_calculate_sign_mac(req);
281
282         smbcli_transport_send(req);
283
284         return True;
285 }
286
287
288 /*
289   receive a response to a packet
290 */
291 BOOL smbcli_request_receive(struct smbcli_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 <= SMBCLI_REQUEST_RECV) {
299                 event_loop_once(req->transport->event.ctx);
300         }
301
302         return True;
303 }
304
305
306 /*
307   receive another reply to a request - this is used for requests that
308   have multi-part replies (such as SMBtrans2)
309 */
310 BOOL smbcli_request_receive_more(struct smbcli_request *req)
311 {
312         req->state = SMBCLI_REQUEST_RECV;
313         DLIST_ADD(req->transport->pending_recv, req);
314
315         return smbcli_request_receive(req);
316 }
317
318
319 /*
320   handle oplock break requests from the server - return True if the request was
321   an oplock break
322 */
323 BOOL handle_oplock_break(struct smbcli_transport *transport, uint_t len, const char *hdr, const char *vwv)
324 {
325         /* we must be very fussy about what we consider an oplock break to avoid
326            matching readbraw replies */
327         if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
328             (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
329             CVAL(hdr,HDR_COM) != SMBlockingX ||
330             SVAL(hdr, HDR_MID) != 0xFFFF ||
331             SVAL(vwv,VWV(6)) != 0 ||
332             SVAL(vwv,VWV(7)) != 0) {
333                 return False;
334         }
335
336         if (transport->oplock.handler) {
337                 uint16_t tid = SVAL(hdr, HDR_TID);
338                 uint16_t fnum = SVAL(vwv,VWV(2));
339                 uint8_t level = CVAL(vwv,VWV(3)+1);
340                 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
341         }
342
343         return True;
344 }
345
346 /*
347   wait for a reply to be received for a packet that just returns an error
348   code and nothing more
349 */
350 NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
351 {
352         smbcli_request_receive(req);
353         return smbcli_request_destroy(req);
354 }
355
356
357 /* Return true if the last packet was in error */
358 BOOL smbcli_request_is_error(struct smbcli_request *req)
359 {
360         return NT_STATUS_IS_ERR(req->status);
361 }
362
363 /*
364   append a string into the data portion of the request packet
365
366   return the number of bytes added to the packet
367 */
368 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, uint_t flags)
369 {
370         size_t len;
371
372         /* determine string type to use */
373         if (!(flags & (STR_ASCII|STR_UNICODE))) {
374                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
375         }
376
377         len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;             
378
379         smbcli_req_grow_allocation(req, len + req->out.data_size);
380
381         len = push_string(NULL, req->out.data + req->out.data_size, str, len, flags);
382
383         smbcli_req_grow_data(req, len + req->out.data_size);
384
385         return len;
386 }
387
388 /*
389   this is like smbcli_req_append_string but it also return the
390   non-terminated string byte length, which can be less than the number
391   of bytes consumed in the packet for 2 reasons:
392
393    1) the string in the packet may be null terminated
394    2) the string in the packet may need a 1 byte UCS2 alignment
395
396  this is used in places where the non-terminated string byte length is
397  placed in the packet as a separate field  
398 */
399 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, uint_t flags, int *len)
400 {
401         int diff = 0;
402         size_t ret;
403
404         /* determine string type to use */
405         if (!(flags & (STR_ASCII|STR_UNICODE))) {
406                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
407         }
408
409         /* see if an alignment byte will be used */
410         if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
411                 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
412         }
413
414         /* do the hard work */
415         ret = smbcli_req_append_string(req, str, flags);
416
417         /* see if we need to subtract the termination */
418         if (flags & STR_TERMINATE) {
419                 diff += (flags & STR_UNICODE) ? 2 : 1;
420         }
421
422         if (ret >= diff) {
423                 (*len) = ret - diff;
424         } else {
425                 (*len) = ret;
426         }
427
428         return ret;
429 }
430
431
432 /*
433   push a string into the data portion of the request packet, growing it if necessary
434   this gets quite tricky - please be very careful to cover all cases when modifying this
435
436   if dest is NULL, then put the string at the end of the data portion of the packet
437
438   if dest_len is -1 then no limit applies
439 */
440 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, uint_t flags)
441 {
442         size_t size;
443         smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
444         size = smbcli_req_append_string(req, str, flags);
445         return size + 1;
446 }
447
448
449 /*
450   push a blob into the data portion of the request packet, growing it if necessary
451   this gets quite tricky - please be very careful to cover all cases when modifying this
452
453   if dest is NULL, then put the blob at the end of the data portion of the packet
454 */
455 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
456 {
457         smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
458         memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
459         smbcli_req_grow_data(req, req->out.data_size + blob->length);
460         return blob->length;
461 }
462
463 /*
464   append raw bytes into the data portion of the request packet
465   return the number of bytes added
466 */
467 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
468 {
469         smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
470         memcpy(req->out.data + req->out.data_size, bytes, byte_len);
471         smbcli_req_grow_data(req, byte_len + req->out.data_size);
472         return byte_len;
473 }
474
475 /*
476   append variable block (type 5 buffer) into the data portion of the request packet
477   return the number of bytes added
478 */
479 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
480 {
481         smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
482         SCVAL(req->out.data + req->out.data_size, 0, 5);
483         SSVAL(req->out.data + req->out.data_size, 1, byte_len);         /* add field length */
484         if (byte_len > 0) {
485                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
486         }
487         smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
488         return byte_len + 3;
489 }
490
491
492 /*
493   pull a UCS2 string from a request packet, returning a talloced unix string
494
495   the string length is limited by the 3 things:
496    - the data size in the request (end of packet)
497    - the passed 'byte_len' if it is not -1
498    - the end of string (null termination)
499
500   Note that 'byte_len' is the number of bytes in the packet
501
502   on failure zero is returned and *dest is set to NULL, otherwise the number
503   of bytes consumed in the packet is returned
504 */
505 static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
506                                 char **dest, const char *src, int byte_len, uint_t flags)
507 {
508         int src_len, src_len2, alignment=0;
509         ssize_t ret;
510
511         if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
512                 src++;
513                 alignment=1;
514                 if (byte_len != -1) {
515                         byte_len--;
516                 }
517         }
518
519         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
520         if (src_len < 0) {
521                 *dest = NULL;
522                 return 0;
523         }
524         if (byte_len != -1 && src_len > byte_len) {
525                 src_len = byte_len;
526         }
527
528         src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
529         if (src_len2 < src_len - 2) {
530                 /* include the termination if we didn't reach the end of the packet */
531                 src_len2 += 2;
532         }
533
534         /* ucs2 strings must be at least 2 bytes long */
535         if (src_len2 < 2) {
536                 *dest = NULL;
537                 return 0;
538         }
539
540         ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
541         if (ret == -1) {
542                 *dest = NULL;
543                 return 0;
544         }
545
546         return src_len2 + alignment;
547 }
548
549 /*
550   pull a ascii string from a request packet, returning a talloced string
551
552   the string length is limited by the 3 things:
553    - the data size in the request (end of packet)
554    - the passed 'byte_len' if it is not -1
555    - the end of string (null termination)
556
557   Note that 'byte_len' is the number of bytes in the packet
558
559   on failure zero is returned and *dest is set to NULL, otherwise the number
560   of bytes consumed in the packet is returned
561 */
562 size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
563                           char **dest, const char *src, int byte_len, uint_t flags)
564 {
565         int src_len, src_len2;
566         ssize_t ret;
567
568         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
569         if (src_len < 0) {
570                 *dest = NULL;
571                 return 0;
572         }
573         if (byte_len != -1 && src_len > byte_len) {
574                 src_len = byte_len;
575         }
576         src_len2 = strnlen(src, src_len);
577         if (src_len2 < src_len - 1) {
578                 /* include the termination if we didn't reach the end of the packet */
579                 src_len2++;
580         }
581
582         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
583
584         if (ret == -1) {
585                 *dest = NULL;
586                 return 0;
587         }
588
589         return ret;
590 }
591
592 /*
593   pull a string from a request packet, returning a talloced string
594
595   the string length is limited by the 3 things:
596    - the data size in the request (end of packet)
597    - the passed 'byte_len' if it is not -1
598    - the end of string (null termination)
599
600   Note that 'byte_len' is the number of bytes in the packet
601
602   on failure zero is returned and *dest is set to NULL, otherwise the number
603   of bytes consumed in the packet is returned
604 */
605 size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx, 
606                            char **dest, const char *src, int byte_len, uint_t flags)
607 {
608         if (!(flags & STR_ASCII) && 
609             (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
610                 return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
611         }
612
613         return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
614 }
615
616
617 /*
618   pull a DATA_BLOB from a reply packet, returning a talloced blob
619   make sure we don't go past end of packet
620
621   if byte_len is -1 then limit the blob only by packet size
622 */
623 DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
624 {
625         int src_len;
626
627         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
628
629         if (src_len < 0) {
630                 return data_blob(NULL, 0);
631         }
632
633         if (byte_len != -1 && src_len > byte_len) {
634                 src_len = byte_len;
635         }
636
637         return data_blob_talloc(mem_ctx, src, src_len);
638 }
639
640 /* check that a lump of data in a request is within the bounds of the data section of
641    the packet */
642 static BOOL smbcli_req_data_oob(struct smbcli_request *req, const char *ptr, uint32_t count)
643 {
644         /* be careful with wraparound! */
645         if (ptr < req->in.data ||
646             ptr >= req->in.data + req->in.data_size ||
647             count > req->in.data_size ||
648             ptr + count > req->in.data + req->in.data_size) {
649                 return True;
650         }
651         return False;
652 }
653
654 /*
655   pull a lump of data from a request packet
656
657   return False if any part is outside the data portion of the packet
658 */
659 BOOL smbcli_raw_pull_data(struct smbcli_request *req, const char *src, int len, char *dest)
660 {
661         if (len == 0) return True;
662
663         if (smbcli_req_data_oob(req, src, len)) {
664                 return False;
665         }
666
667         memcpy(dest, src, len);
668         return True;
669 }
670
671
672 /*
673   put a NTTIME into a packet
674 */
675 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
676 {
677         SBVAL(base, offset, t);
678 }
679
680 /*
681   pull a NTTIME from a packet
682 */
683 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
684 {
685         NTTIME ret = BVAL(base, offset);
686         return ret;
687 }
688
689 /*
690   pull a UCS2 string from a blob, returning a talloced unix string
691
692   the string length is limited by the 3 things:
693    - the data size in the blob
694    - the passed 'byte_len' if it is not -1
695    - the end of string (null termination)
696
697   Note that 'byte_len' is the number of bytes in the packet
698
699   on failure zero is returned and *dest is set to NULL, otherwise the number
700   of bytes consumed in the blob is returned
701 */
702 static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
703                                  DATA_BLOB *blob, const char **dest, 
704                                  const char *src, int byte_len, uint_t flags)
705 {
706         int src_len, src_len2, alignment=0;
707         ssize_t ret;
708
709         if (src < (const char *)blob->data ||
710             src >= (const char *)(blob->data + blob->length)) {
711                 *dest = NULL;
712                 return 0;
713         }
714
715         src_len = blob->length - PTR_DIFF(src, blob->data);
716
717         if (byte_len != -1 && src_len > byte_len) {
718                 src_len = byte_len;
719         }
720
721         if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
722                 src++;
723                 alignment=1;
724                 src_len--;
725         }
726
727         if (src_len < 2) {
728                 *dest = NULL;
729                 return 0;
730         }
731
732         src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
733
734         if (src_len2 < src_len - 2) {
735                 /* include the termination if we didn't reach the end of the packet */
736                 src_len2 += 2;
737         }
738
739         ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
740         if (ret == -1) {
741                 *dest = NULL;
742                 return 0;
743         }
744
745         return src_len2 + alignment;
746 }
747
748 /*
749   pull a ascii string from a blob, returning a talloced string
750
751   the string length is limited by the 3 things:
752    - the data size in the blob
753    - the passed 'byte_len' if it is not -1
754    - the end of string (null termination)
755
756   Note that 'byte_len' is the number of bytes in the blob
757
758   on failure zero is returned and *dest is set to NULL, otherwise the number
759   of bytes consumed in the blob is returned
760 */
761 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
762                                   DATA_BLOB *blob, const char **dest, 
763                                   const char *src, int byte_len, uint_t flags)
764 {
765         int src_len, src_len2;
766         ssize_t ret;
767
768         src_len = blob->length - PTR_DIFF(src, blob->data);
769         if (src_len < 0) {
770                 *dest = NULL;
771                 return 0;
772         }
773         if (byte_len != -1 && src_len > byte_len) {
774                 src_len = byte_len;
775         }
776         src_len2 = strnlen(src, src_len);
777
778         if (src_len2 < src_len - 1) {
779                 /* include the termination if we didn't reach the end of the packet */
780                 src_len2++;
781         }
782
783         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
784
785         if (ret == -1) {
786                 *dest = NULL;
787                 return 0;
788         }
789
790         return ret;
791 }
792
793 /*
794   pull a string from a blob, returning a talloced WIRE_STRING
795
796   the string length is limited by the 3 things:
797    - the data size in the blob
798    - length field on the wire
799    - the end of string (null termination)
800
801    if STR_LEN8BIT is set in the flags then assume the length field is
802    8 bits, instead of 32
803
804   on failure zero is returned and dest->s is set to NULL, otherwise the number
805   of bytes consumed in the blob is returned
806 */
807 size_t smbcli_blob_pull_string(struct smbcli_session *session,
808                             TALLOC_CTX *mem_ctx,
809                             DATA_BLOB *blob, 
810                             WIRE_STRING *dest, 
811                             uint16_t len_offset, uint16_t str_offset, 
812                             uint_t flags)
813 {
814         int extra;
815         dest->s = NULL;
816         
817         if (len_offset > blob->length-4) {
818                 return 0;
819         }
820         if (flags & STR_LEN8BIT) {
821                 dest->private_length = CVAL(blob->data, len_offset);
822         } else {
823                 dest->private_length = IVAL(blob->data, len_offset);
824         }
825         extra = 0;
826         dest->s = NULL;
827         if (!(flags & STR_ASCII) && 
828             ((flags & STR_UNICODE) || 
829              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
830                 int align = 0;
831                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
832                         align = 1;
833                 }
834                 if (flags & STR_LEN_NOTERM) {
835                         extra = 2;
836                 }
837                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s, 
838                                                           blob->data+str_offset+align, 
839                                                           dest->private_length, flags);
840         }
841
842         if (flags & STR_LEN_NOTERM) {
843                 extra = 1;
844         }
845
846         return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s, 
847                                            blob->data+str_offset, dest->private_length, flags);
848 }
849
850 /*
851   pull a string from a blob, returning a talloced char *
852
853   Currently only used by the UNIX search info level.
854
855   the string length is limited by 2 things:
856    - the data size in the blob
857    - the end of string (null termination)
858
859   on failure zero is returned and dest->s is set to NULL, otherwise the number
860   of bytes consumed in the blob is returned
861 */
862 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
863                             TALLOC_CTX *mem_ctx,
864                             DATA_BLOB *blob, 
865                             const char **dest, 
866                             uint16_t str_offset, 
867                             uint_t flags)
868 {
869         int extra = 0;
870         *dest = NULL;
871         
872         if (!(flags & STR_ASCII) && 
873             ((flags & STR_UNICODE) || 
874              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
875                 int align = 0;
876                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
877                         align = 1;
878                 }
879                 if (flags & STR_LEN_NOTERM) {
880                         extra = 2;
881                 }
882                 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest, 
883                                                           blob->data+str_offset+align, 
884                                                           -1, flags);
885         }
886
887         if (flags & STR_LEN_NOTERM) {
888                 extra = 1;
889         }
890
891         return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
892                                            blob->data+str_offset, -1, flags);
893 }
894
895
896 /*
897   append a string into a blob
898 */
899 size_t smbcli_blob_append_string(struct smbcli_session *session,
900                               TALLOC_CTX *mem_ctx, DATA_BLOB *blob, 
901                               const char *str, uint_t flags)
902 {
903         size_t max_len;
904         int len;
905
906         if (!str) return 0;
907
908         /* determine string type to use */
909         if (!(flags & (STR_ASCII|STR_UNICODE))) {
910                 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
911         }
912
913         max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;         
914
915         blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
916         if (!blob->data) {
917                 return 0;
918         }
919
920         len = push_string(NULL, blob->data + blob->length, str, max_len, flags);
921
922         blob->length += len;
923
924         return len;
925 }