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