2b84345abb1d6ded1c37e5df435bc1382b0290ee
[samba.git] / source / libcli / raw / rawrequest.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Andrew Tridgell  2003
5    Copyright (C) James Myers 2003 <myersjj@samba.org>
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23   this file implements functions for manipulating the 'struct cli_request' structure in libsmb
24 */
25
26 #include "includes.h"
27
28 /* we over allocate the data buffer to prevent too many realloc calls */
29 #define REQ_OVER_ALLOCATION 256
30
31 /* assume that a character will not consume more than 3 bytes per char */
32 #define MAX_BYTES_PER_CHAR 3
33
34 /* destroy a request structure and return final status */
35 NTSTATUS cli_request_destroy(struct cli_request *req)
36 {
37         NTSTATUS status;
38
39         /* this is the error code we give the application for when a
40            _send() call fails completely */
41         if (!req) return NT_STATUS_UNSUCCESSFUL;
42
43         /* remove it from the list of pending requests (a null op if
44            its not in the list) */
45         DLIST_REMOVE(req->transport->pending_requests, req);
46
47         /* ahh, its so nice to destroy a complex structure in such a
48            simple way! */
49         status = req->status;
50         talloc_destroy(req->mem_ctx);
51         return status;
52 }
53
54
55 /*
56   low-level function to setup a request buffer for a non-SMB packet 
57   at the transport level
58 */
59 struct cli_request *cli_request_setup_nonsmb(struct cli_transport *transport, uint_t size)
60 {
61         struct cli_request *req;
62         TALLOC_CTX *mem_ctx;
63         
64         /* each request gets its own talloc context. The request
65            structure itself is also allocated inside this context,
66            so we need to allocate it before we construct the request
67         */
68         mem_ctx = talloc_init("cli_request");
69         if (!mem_ctx) {
70                 return NULL;
71         }
72
73         req = talloc(mem_ctx, sizeof(struct cli_request));
74         if (!req) {
75                 return NULL;
76         }
77         ZERO_STRUCTP(req);
78
79         /* setup the request context */
80         req->mem_ctx = mem_ctx;
81         req->transport = transport;
82         req->session = NULL;
83         req->tree = NULL;
84         req->out.size = size;
85
86         /* over allocate by a small amount */
87         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
88
89         req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
90         if (!req->out.buffer) {
91                 return NULL;
92         }
93
94         SIVAL(req->out.buffer, 0, 0);
95
96         return req;
97 }
98
99
100 /*
101   setup a SMB packet at transport level
102 */
103 struct cli_request *cli_request_setup_transport(struct cli_transport *transport,
104                                                 uint8 command, unsigned wct, unsigned buflen)
105 {
106         struct cli_request *req;
107
108         req = cli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
109
110         if (!req) return NULL;
111         
112         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
113         req->out.vwv = req->out.hdr + HDR_VWV;
114         req->out.wct = wct;
115         req->out.data = req->out.vwv + VWV(wct) + 2;
116         req->out.data_size = buflen;
117         req->out.ptr = req->out.data;
118
119         SCVAL(req->out.hdr, HDR_WCT, wct);
120         SSVAL(req->out.vwv, VWV(wct), buflen);
121
122         memcpy(req->out.hdr, "\377SMB", 4);
123         SCVAL(req->out.hdr,HDR_COM,command);
124
125         SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
126         SSVAL(req->out.hdr,HDR_FLG2, 0);
127
128         /* assign a mid */
129         req->mid = cli_transport_next_mid(transport);
130
131         /* copy the pid, uid and mid to the request */
132         SSVAL(req->out.hdr, HDR_PID, 0);
133         SSVAL(req->out.hdr, HDR_UID, 0);
134         SSVAL(req->out.hdr, HDR_MID, req->mid);
135         SSVAL(req->out.hdr, HDR_TID,0);
136         SSVAL(req->out.hdr, HDR_PIDHIGH,0);
137         SIVAL(req->out.hdr, HDR_RCLS, 0);
138         memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
139         
140         return req;
141 }
142
143 /*
144   setup a reply in req->out with the given word count and initial data
145   buffer size.  the caller will then fill in the command words and
146   data before calling cli_request_send() to send the reply on its
147   way. This interface is used before a session is setup.
148 */
149 struct cli_request *cli_request_setup_session(struct cli_session *session,
150                                               uint8 command, unsigned wct, unsigned buflen)
151 {
152         struct cli_request *req;
153         uint16 flags2;
154         uint32 capabilities;
155
156         req = cli_request_setup_transport(session->transport, command, wct, buflen);
157
158         if (!req) return NULL;
159
160         req->session = session;
161         
162         flags2 = FLAGS2_LONG_PATH_COMPONENTS;
163         capabilities = session->transport->negotiate.capabilities;
164
165         if (capabilities & CAP_UNICODE) {
166                 flags2 |= FLAGS2_UNICODE_STRINGS;
167         }
168         if (capabilities & CAP_STATUS32) {
169                 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
170         }
171         if (capabilities & CAP_EXTENDED_SECURITY) {
172                 flags2 |= FLAGS2_EXTENDED_SECURITY;
173         }
174         if (session->transport->negotiate.sign_info.doing_signing) {
175                 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
176         }
177
178         SSVAL(req->out.hdr, HDR_FLG2, flags2);
179         SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
180         SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
181         SSVAL(req->out.hdr, HDR_UID, session->vuid);
182         
183         return req;
184 }
185
186 /*
187   setup a request for tree based commands
188 */
189 struct cli_request *cli_request_setup(struct cli_tree *tree,
190                                       uint8 command, 
191                                       unsigned wct, unsigned buflen)
192 {
193         struct cli_request *req;
194
195         req = cli_request_setup_session(tree->session, command, wct, buflen);
196         if (req) {
197                 req->tree = tree;
198                 SSVAL(req->out.hdr,HDR_TID,tree->tid);
199         }
200         return req;
201 }
202
203 /*
204   grow the allocation of the data buffer portion of a reply
205   packet. Note that as this can reallocate the packet buffer this
206   invalidates any local pointers into the packet.
207
208   To cope with this req->out.ptr is supplied. This will be updated to
209   point at the same offset into the packet as before this call
210 */
211 static void cli_req_grow_allocation(struct cli_request *req, unsigned new_size)
212 {
213         int delta;
214         char *buf2;
215
216         delta = new_size - req->out.data_size;
217         if (delta + req->out.size <= req->out.allocated) {
218                 /* it fits in the preallocation */
219                 return;
220         }
221
222         /* we need to realloc */
223         req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
224         buf2 = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
225         if (buf2 == NULL) {
226                 smb_panic("out of memory in req_grow_allocation");
227         }
228
229         if (buf2 == req->out.buffer) {
230                 /* the malloc library gave us the same pointer */
231                 return;
232         }
233         
234         /* update the pointers into the packet */
235         req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
236         req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
237         req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
238         req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
239
240         req->out.buffer = buf2;
241 }
242
243
244 /*
245   grow the data buffer portion of a reply packet. Note that as this
246   can reallocate the packet buffer this invalidates any local pointers
247   into the packet. 
248
249   To cope with this req->out.ptr is supplied. This will be updated to
250   point at the same offset into the packet as before this call
251 */
252 static void cli_req_grow_data(struct cli_request *req, unsigned new_size)
253 {
254         int delta;
255
256         cli_req_grow_allocation(req, new_size);
257
258         delta = new_size - req->out.data_size;
259
260         req->out.size += delta;
261         req->out.data_size += delta;
262
263         /* set the BCC to the new data size */
264         SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
265 }
266
267 /*
268   send a message
269 */
270 BOOL cli_request_send(struct cli_request *req)
271 {
272         uint_t ret;
273
274         if (IVAL(req->out.buffer, 0) == 0) {
275                 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
276         }
277
278         cli_request_calculate_sign_mac(req);
279
280         ret = cli_sock_write(req->transport->socket, req->out.buffer, req->out.size);
281
282         if (req->out.size != ret) {
283                 req->transport->error.etype = ETYPE_SOCKET;
284                 req->transport->error.e.socket_error = SOCKET_WRITE_ERROR;
285                 DEBUG(0,("Error writing %d bytes to server - %s\n",
286                          (int)req->out.size, strerror(errno)));
287                 return False;
288         }
289
290         /* add it to the list of pending requests */
291         DLIST_ADD(req->transport->pending_requests, req);
292         
293         return True;
294 }
295
296
297 /*
298   receive a response to a packet
299 */
300 BOOL cli_request_receive(struct cli_request *req)
301 {
302         /* req can be NULL when a send has failed. This eliminates lots of NULL
303            checks in each module */
304         if (!req) return False;
305
306         /* keep receiving packets until this one is replied to */
307         while (!req->in.buffer) {
308                 if (!cli_transport_select(req->transport)) {
309                         return False;
310                 }
311
312                 if (!cli_request_receive_next(req->transport)) {
313                         cli_transport_close(req->transport);
314                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
315                         return False;
316                 }
317         }
318
319         return True;
320 }
321
322
323 /*
324   handle oplock break requests from the server - return True if the request was
325   an oplock break
326 */
327 static BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, const char *hdr, const char *vwv)
328 {
329         /* we must be very fussy about what we consider an oplock break to avoid
330            matching readbraw replies */
331         if (len != MIN_SMB_SIZE + VWV(8) ||
332             (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
333             CVAL(hdr,HDR_COM) != SMBlockingX ||
334             SVAL(hdr, HDR_MID) != 0xFFFF ||
335             SVAL(vwv,VWV(6)) != 0 ||
336             SVAL(vwv,VWV(7)) != 0) {
337                 return False;
338         }
339
340         if (transport->oplock.handler) {
341                 uint16 tid = SVAL(hdr, HDR_TID);
342                 uint16 fnum = SVAL(vwv,VWV(2));
343                 uint8 level = CVAL(vwv,VWV(3));
344                 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
345         }
346
347         return True;
348 }
349
350
351 /*
352   receive an async message from the server
353   this function assumes that the caller already knows that the socket is readable
354   and that there is a packet waiting
355
356   The packet is not actually returned by this function, instead any
357   registered async message handlers are called
358
359   return True if a packet was successfully received and processed
360   return False if the socket appears to be dead
361 */
362 BOOL cli_request_receive_next(struct cli_transport *transport)
363 {
364         BOOL ret;
365         int len;
366         char header[NBT_HDR_SIZE];
367         char *buffer, *hdr, *vwv;
368         TALLOC_CTX *mem_ctx;
369         struct cli_request *req;
370         uint16 wct, mid = 0;
371
372         len = cli_sock_read(transport->socket, header, 4);
373         if (len != 4) {
374                 return False;
375         }
376         
377         len = smb_len(header);
378
379         mem_ctx = talloc_init("cli_request_receive_next");
380         
381         /* allocate the incoming buffer at the right size */
382         buffer = talloc(mem_ctx, len+NBT_HDR_SIZE);
383         if (!buffer) {
384                 talloc_destroy(mem_ctx);
385                 return False;
386         }
387
388         /* fill in the already received header */
389         memcpy(buffer, header, NBT_HDR_SIZE);
390
391         ret = cli_sock_read(transport->socket, buffer + NBT_HDR_SIZE, len);
392         /* If the server is not responding, note that now */
393         if (ret != len) {
394                 return False;
395         }
396
397         hdr = buffer+NBT_HDR_SIZE;
398         vwv = hdr + HDR_VWV;
399
400         /* see if it could be an oplock break request */
401         if (handle_oplock_break(transport, len, hdr, vwv)) {
402                 goto done;
403         }
404
405         /* at this point we need to check for a readbraw reply, as these can be any length */
406         if (transport->readbraw_pending) {
407                 transport->readbraw_pending = 0;
408
409                 /* it must match the first entry in the pending queue as the client is not allowed
410                    to have outstanding readbraw requests */
411                 req = transport->pending_requests;
412                 if (!req) goto done;
413
414                 req->in.buffer = buffer;
415                 talloc_steal(mem_ctx, req->mem_ctx, buffer);
416                 req->in.size = len + NBT_HDR_SIZE;
417                 req->in.allocated = req->in.size;
418                 goto async;
419         }
420
421         if (len >= MIN_SMB_SIZE) {
422                 /* extract the mid for matching to pending requests */
423                 mid = SVAL(hdr, HDR_MID);
424                 wct = CVAL(hdr, HDR_WCT);
425         }
426
427         /* match the incoming request against the list of pending requests */
428         for (req=transport->pending_requests; req; req=req->next) {
429                 if (req->mid == mid) break;
430         }
431
432         if (!req) {
433                 DEBUG(3,("Discarding unmatched reply with mid %d\n", mid));
434                 goto done;
435         }
436
437         /* fill in the 'in' portion of the matching request */
438         req->in.buffer = buffer;
439         talloc_steal(mem_ctx, req->mem_ctx, buffer);
440         req->in.size = len + NBT_HDR_SIZE;
441         req->in.allocated = req->in.size;
442
443         /* handle non-SMB replies */
444         if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
445                 goto done;
446         }
447
448         if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
449                 DEBUG(2,("bad reply size for mid %d\n", mid));
450                 req->status = NT_STATUS_UNSUCCESSFUL;
451                 goto done;
452         }
453
454         req->in.hdr = hdr;
455         req->in.vwv = vwv;
456         req->in.wct = wct;
457         if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
458                 req->in.data = req->in.vwv + VWV(wct) + 2;
459                 req->in.data_size = SVAL(req->in.vwv, VWV(wct));
460                 if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
461                         DEBUG(3,("bad data size for mid %d\n", mid));
462                         /* blergh - w2k3 gives a bogus data size values in some
463                            openX replies */
464                         req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
465                 }
466         }
467         req->in.ptr = req->in.data;
468         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
469
470         if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
471                 transport->error.etype = ETYPE_DOS;
472                 transport->error.e.dos.eclass = CVAL(req->in.hdr,HDR_RCLS);
473                 transport->error.e.dos.ecode = SVAL(req->in.hdr,HDR_ERR);
474                 req->status = dos_to_ntstatus(transport->error.e.dos.eclass, 
475                                               transport->error.e.dos.ecode);
476         } else {
477                 transport->error.etype = ETYPE_NT;
478                 transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
479                 req->status = transport->error.e.nt_status;
480         }
481
482         if (!cli_request_check_sign_mac(req)) {
483                 transport->error.etype = ETYPE_SOCKET;
484                 transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
485                 return False;
486         };
487
488 async:
489         /* if this request has an async handler then call that to
490            notify that the reply has been received. This might destroy
491            the request so it must happen last */
492         if (req->async.fn) {
493                 req->async.fn(req);
494         }
495
496 done:
497         talloc_destroy(mem_ctx);
498         return True;
499 }
500
501
502 /*
503   wait for a reply to be received for a packet that just returns an error
504   code and nothing more
505 */
506 NTSTATUS cli_request_simple_recv(struct cli_request *req)
507 {
508         cli_request_receive(req);
509         return cli_request_destroy(req);
510 }
511
512
513 /* Return true if the last packet was in error */
514 BOOL cli_request_is_error(struct cli_request *req)
515 {
516         return NT_STATUS_IS_ERR(req->status);
517 }
518
519 /*
520   append a string into the data portion of the request packet
521
522   return the number of bytes added to the packet
523 */
524 size_t cli_req_append_string(struct cli_request *req, const char *str, unsigned flags)
525 {
526         size_t len;
527
528         /* determine string type to use */
529         if (!(flags & (STR_ASCII|STR_UNICODE))) {
530                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
531         }
532
533         len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;             
534
535         cli_req_grow_allocation(req, len + req->out.data_size);
536
537         len = push_string(NULL, req->out.data + req->out.data_size, str, len, flags);
538
539         cli_req_grow_data(req, len + req->out.data_size);
540
541         return len;
542 }
543
544 /*
545   this is like cli_req_append_string but it also return the
546   non-terminated string byte length, which can be less than the number
547   of bytes consumed in the packet for 2 reasons:
548
549    1) the string in the packet may be null terminated
550    2) the string in the packet may need a 1 byte UCS2 alignment
551
552  this is used in places where the non-terminated string byte length is
553  placed in the packet as a separate field  
554 */
555 size_t cli_req_append_string_len(struct cli_request *req, const char *str, unsigned flags, int *len)
556 {
557         int diff = 0;
558         size_t ret;
559
560         /* determine string type to use */
561         if (!(flags & (STR_ASCII|STR_UNICODE))) {
562                 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
563         }
564
565         /* see if an alignment byte will be used */
566         if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
567                 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
568         }
569
570         /* do the hard work */
571         ret = cli_req_append_string(req, str, flags);
572
573         /* see if we need to subtract the termination */
574         if (flags & STR_TERMINATE) {
575                 diff += (flags & STR_UNICODE) ? 2 : 1;
576         }
577
578         if (ret >= diff) {
579                 (*len) = ret - diff;
580         } else {
581                 (*len) = ret;
582         }
583
584         return ret;
585 }
586
587
588 /*
589   push a string into the data portion of the request packet, growing it if necessary
590   this gets quite tricky - please be very careful to cover all cases when modifying this
591
592   if dest is NULL, then put the string at the end of the data portion of the packet
593
594   if dest_len is -1 then no limit applies
595 */
596 size_t cli_req_append_ascii4(struct cli_request *req, const char *str, unsigned flags)
597 {
598         size_t size;
599         cli_req_append_bytes(req, (const uint8 *)"\4", 1);
600         size = cli_req_append_string(req, str, flags);
601         return size + 1;
602 }
603
604
605 /*
606   push a blob into the data portion of the request packet, growing it if necessary
607   this gets quite tricky - please be very careful to cover all cases when modifying this
608
609   if dest is NULL, then put the blob at the end of the data portion of the packet
610 */
611 size_t cli_req_append_blob(struct cli_request *req, const DATA_BLOB *blob)
612 {
613         cli_req_grow_allocation(req, req->out.data_size + blob->length);
614         memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
615         cli_req_grow_data(req, req->out.data_size + blob->length);
616         return blob->length;
617 }
618
619 /*
620   append raw bytes into the data portion of the request packet
621   return the number of bytes added
622 */
623 size_t cli_req_append_bytes(struct cli_request *req, const uint8 *bytes, size_t byte_len)
624 {
625         cli_req_grow_allocation(req, byte_len + req->out.data_size);
626         memcpy(req->out.data + req->out.data_size, bytes, byte_len);
627         cli_req_grow_data(req, byte_len + req->out.data_size);
628         return byte_len;
629 }
630
631 /*
632   append variable block (type 5 buffer) into the data portion of the request packet
633   return the number of bytes added
634 */
635 size_t cli_req_append_var_block(struct cli_request *req, const uint8 *bytes, uint16 byte_len)
636 {
637         cli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
638         SCVAL(req->out.data + req->out.data_size, 0, 5);
639         SSVAL(req->out.data + req->out.data_size, 1, byte_len);         /* add field length */
640         if (byte_len > 0) {
641                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
642         }
643         cli_req_grow_data(req, byte_len + 3 + req->out.data_size);
644         return byte_len + 3;
645 }
646
647
648 /*
649   pull a UCS2 string from a request packet, returning a talloced unix string
650
651   the string length is limited by the 3 things:
652    - the data size in the request (end of packet)
653    - the passed 'byte_len' if it is not -1
654    - the end of string (null termination)
655
656   Note that 'byte_len' is the number of bytes in the packet
657
658   on failure zero is returned and *dest is set to NULL, otherwise the number
659   of bytes consumed in the packet is returned
660 */
661 static size_t cli_req_pull_ucs2(struct cli_request *req, TALLOC_CTX *mem_ctx,
662                                 char **dest, const char *src, int byte_len, unsigned flags)
663 {
664         int src_len, src_len2, alignment=0;
665         ssize_t ret;
666
667         if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
668                 src++;
669                 alignment=1;
670                 if (byte_len != -1) {
671                         byte_len--;
672                 }
673         }
674
675         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
676         if (src_len < 0) {
677                 *dest = NULL;
678                 return 0;
679         }
680         if (byte_len != -1 && src_len > byte_len) {
681                 src_len = byte_len;
682         }
683
684         src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
685         if (src_len2 < src_len - 2) {
686                 /* include the termination if we didn't reach the end of the packet */
687                 src_len2 += 2;
688         }
689
690         /* ucs2 strings must be at least 2 bytes long */
691         if (src_len2 < 2) {
692                 *dest = NULL;
693                 return 0;
694         }
695
696         ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
697         if (ret == -1) {
698                 *dest = NULL;
699                 return 0;
700         }
701
702         return src_len2 + alignment;
703 }
704
705 /*
706   pull a ascii string from a request packet, returning a talloced string
707
708   the string length is limited by the 3 things:
709    - the data size in the request (end of packet)
710    - the passed 'byte_len' if it is not -1
711    - the end of string (null termination)
712
713   Note that 'byte_len' is the number of bytes in the packet
714
715   on failure zero is returned and *dest is set to NULL, otherwise the number
716   of bytes consumed in the packet is returned
717 */
718 size_t cli_req_pull_ascii(struct cli_request *req, TALLOC_CTX *mem_ctx,
719                           char **dest, const char *src, int byte_len, unsigned flags)
720 {
721         int src_len, src_len2;
722         ssize_t ret;
723
724         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
725         if (src_len < 0) {
726                 *dest = NULL;
727                 return 0;
728         }
729         if (byte_len != -1 && src_len > byte_len) {
730                 src_len = byte_len;
731         }
732         src_len2 = strnlen(src, src_len);
733         if (src_len2 < src_len - 1) {
734                 /* include the termination if we didn't reach the end of the packet */
735                 src_len2++;
736         }
737
738         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
739
740         if (ret == -1) {
741                 *dest = NULL;
742                 return 0;
743         }
744
745         return ret;
746 }
747
748 /*
749   pull a string from a request packet, returning a talloced string
750
751   the string length is limited by the 3 things:
752    - the data size in the request (end of packet)
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 packet
757
758   on failure zero is returned and *dest is set to NULL, otherwise the number
759   of bytes consumed in the packet is returned
760 */
761 size_t cli_req_pull_string(struct cli_request *req, TALLOC_CTX *mem_ctx, 
762                            char **dest, const char *src, int byte_len, unsigned flags)
763 {
764         if (!(flags & STR_ASCII) && 
765             (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
766                 return cli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
767         }
768
769         return cli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
770 }
771
772
773 /*
774   pull a DATA_BLOB from a reply packet, returning a talloced blob
775   make sure we don't go past end of packet
776
777   if byte_len is -1 then limit the blob only by packet size
778 */
779 DATA_BLOB cli_req_pull_blob(struct cli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
780 {
781         int src_len;
782
783         src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
784
785         if (src_len < 0) {
786                 return data_blob(NULL, 0);
787         }
788
789         if (byte_len != -1 && src_len > byte_len) {
790                 src_len = byte_len;
791         }
792
793         return data_blob_talloc(mem_ctx, src, src_len);
794 }
795
796 /* check that a lump of data in a request is within the bounds of the data section of
797    the packet */
798 static BOOL cli_req_data_oob(struct cli_request *req, const char *ptr, uint32 count)
799 {
800         /* be careful with wraparound! */
801         if (ptr < req->in.data ||
802             ptr >= req->in.data + req->in.data_size ||
803             count > req->in.data_size ||
804             ptr + count > req->in.data + req->in.data_size) {
805                 return True;
806         }
807         return False;
808 }
809
810 /*
811   pull a lump of data from a request packet
812
813   return False if any part is outside the data portion of the packet
814 */
815 BOOL cli_raw_pull_data(struct cli_request *req, const char *src, int len, char *dest)
816 {
817         if (len == 0) return True;
818
819         if (cli_req_data_oob(req, src, len)) {
820                 return False;
821         }
822
823         memcpy(dest, src, len);
824         return True;
825 }
826
827
828 /*
829   put a NTTIME into a packet
830 */
831
832 void cli_push_nttime(void *base, uint16 offset, NTTIME *t)
833 {
834         SIVAL(base, offset,   t->low);
835         SIVAL(base, offset+4, t->high);
836 }
837
838 /*
839   pull a NTTIME from a packet
840 */
841 NTTIME cli_pull_nttime(void *base, uint16 offset)
842 {
843         NTTIME ret;
844         ret.low = IVAL(base, offset);
845         ret.high = IVAL(base, offset+4);
846         return ret;
847 }
848
849 /*
850   pull a UCS2 string from a blob, returning a talloced unix string
851
852   the string length is limited by the 3 things:
853    - the data size in the blob
854    - the passed 'byte_len' if it is not -1
855    - the end of string (null termination)
856
857   Note that 'byte_len' is the number of bytes in the packet
858
859   on failure zero is returned and *dest is set to NULL, otherwise the number
860   of bytes consumed in the blob is returned
861 */
862 static size_t cli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
863                                  DATA_BLOB *blob, const char **dest, 
864                                  const char *src, int byte_len, unsigned flags)
865 {
866         int src_len, src_len2, alignment=0;
867         ssize_t ret;
868
869         if (src < (const char *)blob->data ||
870             src >= (const char *)(blob->data + blob->length)) {
871                 *dest = NULL;
872                 return 0;
873         }
874
875         src_len = blob->length - PTR_DIFF(src, blob->data);
876
877         if (byte_len != -1 && src_len > byte_len) {
878                 src_len = byte_len;
879         }
880
881         if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
882                 src++;
883                 alignment=1;
884                 src_len--;
885         }
886
887         if (src_len < 2) {
888                 *dest = NULL;
889                 return 0;
890         }
891
892         src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
893
894         if (src_len2 < src_len - 2) {
895                 /* include the termination if we didn't reach the end of the packet */
896                 src_len2 += 2;
897         }
898
899         ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
900         if (ret == -1) {
901                 *dest = NULL;
902                 return 0;
903         }
904
905         return src_len2 + alignment;
906 }
907
908 /*
909   pull a ascii string from a blob, returning a talloced string
910
911   the string length is limited by the 3 things:
912    - the data size in the blob
913    - the passed 'byte_len' if it is not -1
914    - the end of string (null termination)
915
916   Note that 'byte_len' is the number of bytes in the blob
917
918   on failure zero is returned and *dest is set to NULL, otherwise the number
919   of bytes consumed in the blob is returned
920 */
921 static size_t cli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
922                                   DATA_BLOB *blob, const char **dest, 
923                                   const char *src, int byte_len, unsigned flags)
924 {
925         int src_len, src_len2;
926         ssize_t ret;
927
928         src_len = blob->length - PTR_DIFF(src, blob->data);
929         if (src_len < 0) {
930                 *dest = NULL;
931                 return 0;
932         }
933         if (byte_len != -1 && src_len > byte_len) {
934                 src_len = byte_len;
935         }
936         src_len2 = strnlen(src, src_len);
937
938         if (src_len2 < src_len - 1) {
939                 /* include the termination if we didn't reach the end of the packet */
940                 src_len2++;
941         }
942
943         ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
944
945         if (ret == -1) {
946                 *dest = NULL;
947                 return 0;
948         }
949
950         return ret;
951 }
952
953 /*
954   pull a string from a blob, returning a talloced WIRE_STRING
955
956   the string length is limited by the 3 things:
957    - the data size in the blob
958    - length field on the wire
959    - the end of string (null termination)
960
961    if STR_LEN8BIT is set in the flags then assume the length field is
962    8 bits, instead of 32
963
964   on failure zero is returned and dest->s is set to NULL, otherwise the number
965   of bytes consumed in the blob is returned
966 */
967 size_t cli_blob_pull_string(struct cli_session *session,
968                             TALLOC_CTX *mem_ctx,
969                             DATA_BLOB *blob, 
970                             WIRE_STRING *dest, 
971                             uint16 len_offset, uint16 str_offset, 
972                             unsigned flags)
973 {
974         int extra;
975         dest->s = NULL;
976         
977         if (len_offset > blob->length-4) {
978                 return 0;
979         }
980         if (flags & STR_LEN8BIT) {
981                 dest->private_length = CVAL(blob->data, len_offset);
982         } else {
983                 dest->private_length = IVAL(blob->data, len_offset);
984         }
985         extra = 0;
986         dest->s = NULL;
987         if (!(flags & STR_ASCII) && 
988             ((flags & STR_UNICODE) || 
989              (session->transport->negotiate.capabilities & CAP_UNICODE))) {
990                 int align = 0;
991                 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
992                         align = 1;
993                 }
994                 if (flags & STR_LEN_NOTERM) {
995                         extra = 2;
996                 }
997                 return align + extra + cli_blob_pull_ucs2(mem_ctx, blob, &dest->s, 
998                                                           blob->data+str_offset+align, 
999                                                           dest->private_length, flags);
1000         }
1001
1002         if (flags & STR_LEN_NOTERM) {
1003                 extra = 1;
1004         }
1005
1006         return extra + cli_blob_pull_ascii(mem_ctx, blob, &dest->s, 
1007                                            blob->data+str_offset, dest->private_length, flags);
1008 }
1009
1010 /*
1011   append a string into a blob
1012 */
1013 size_t cli_blob_append_string(struct cli_session *session,
1014                               TALLOC_CTX *mem_ctx, DATA_BLOB *blob, 
1015                               const char *str, unsigned flags)
1016 {
1017         size_t max_len;
1018         int len;
1019
1020         if (!str) return 0;
1021
1022         /* determine string type to use */
1023         if (!(flags & (STR_ASCII|STR_UNICODE))) {
1024                 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
1025         }
1026
1027         max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;         
1028
1029         blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
1030         if (!blob->data) {
1031                 return 0;
1032         }
1033
1034         len = push_string(NULL, blob->data + blob->length, str, max_len, flags);
1035
1036         blob->length += len;
1037
1038         return len;
1039 }