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