r14541: separate smbsrv_request and ntvfs_request,
[bbaumbach/samba-autobuild/.git] / source4 / smb_server / smb / request.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Andrew Tridgell              2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22   this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
23 */
24
25 #include "includes.h"
26 #include "smb_server/smb_server.h"
27 #include "smbd/service_stream.h"
28 #include "lib/stream/packet.h"
29 #include "ntvfs/ntvfs.h"
30
31
32 /* we over allocate the data buffer to prevent too many realloc calls */
33 #define REQ_OVER_ALLOCATION 0
34
35 /****************************************************************************
36 construct a basic request packet, mostly used to construct async packets
37 such as change notify and oplock break requests
38 ****************************************************************************/
39 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
40 {
41         struct smbsrv_request *req;
42
43         req = talloc_zero(smb_conn, struct smbsrv_request);
44         if (!req) {
45                 return NULL;
46         }
47
48         /* setup the request context */
49         req->smb_conn = smb_conn;
50
51         return req;
52 }
53
54
55 /*
56   setup a chained reply in req->out with the given word count and initial data buffer size. 
57 */
58 static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
59 {
60         uint32_t chain_base_size = req->out.size;
61
62         /* we need room for the wct value, the words, the buffer length and the buffer */
63         req->out.size += 1 + VWV(wct) + 2 + buflen;
64
65         /* over allocate by a small amount */
66         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
67
68         req->out.buffer = talloc_realloc(req, req->out.buffer, 
69                                          uint8_t, req->out.allocated);
70         if (!req->out.buffer) {
71                 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
72                 return;
73         }
74
75         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
76         req->out.vwv = req->out.buffer + chain_base_size + 1;
77         req->out.wct = wct;
78         req->out.data = req->out.vwv + VWV(wct) + 2;
79         req->out.data_size = buflen;
80         req->out.ptr = req->out.data;
81
82         SCVAL(req->out.buffer, chain_base_size, wct);
83         SSVAL(req->out.vwv, VWV(wct), buflen);
84 }
85
86
87 /*
88   setup a reply in req->out with the given word count and initial data buffer size. 
89   the caller will then fill in the command words and data before calling req_send_reply() to 
90   send the reply on its way
91 */
92 void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
93 {
94         uint16_t flags2;
95
96         if (req->chain_count != 0) {
97                 req_setup_chain_reply(req, wct, buflen);
98                 return;
99         }
100
101         req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
102
103         /* over allocate by a small amount */
104         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
105
106         req->out.buffer = talloc_size(req, req->out.allocated);
107         if (!req->out.buffer) {
108                 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
109                 return;
110         }
111
112         flags2 = FLAGS2_LONG_PATH_COMPONENTS | 
113                 FLAGS2_EXTENDED_ATTRIBUTES | 
114                 FLAGS2_IS_LONG_NAME;
115         flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
116         if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
117                 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
118         }
119
120         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
121         req->out.vwv = req->out.hdr + HDR_VWV;
122         req->out.wct = wct;
123         req->out.data = req->out.vwv + VWV(wct) + 2;
124         req->out.data_size = buflen;
125         req->out.ptr = req->out.data;
126
127         SIVAL(req->out.hdr, HDR_RCLS, 0);
128
129         SCVAL(req->out.hdr, HDR_WCT, wct);
130         SSVAL(req->out.vwv, VWV(wct), buflen);
131
132         memcpy(req->out.hdr, "\377SMB", 4);
133         SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES); 
134         SSVAL(req->out.hdr,HDR_FLG2, flags2);
135         SSVAL(req->out.hdr,HDR_PIDHIGH,0);
136         memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
137
138         if (req->in.hdr) {
139                 /* copy the cmd, tid, pid, uid and mid from the request */
140                 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));  
141                 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
142                 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
143                 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
144                 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
145         } else {
146                 SCVAL(req->out.hdr,HDR_COM,0);
147                 SSVAL(req->out.hdr,HDR_TID,0);
148                 SSVAL(req->out.hdr,HDR_PID,0);
149                 SSVAL(req->out.hdr,HDR_UID,0);
150                 SSVAL(req->out.hdr,HDR_MID,0);
151         }
152 }
153
154
155 /*
156   setup a copy of a request, used when the server needs to send
157   more than one reply for a single request packet
158 */
159 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
160 {
161         struct smbsrv_request *req;
162         ptrdiff_t diff;
163
164         req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
165         if (req == NULL) {
166                 return NULL;
167         }
168
169         req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
170         if (req->out.buffer == NULL) {
171                 talloc_free(req);
172                 return NULL;
173         }
174
175         diff = req->out.buffer - old_req->out.buffer;
176
177         req->out.hdr  += diff;
178         req->out.vwv  += diff;
179         req->out.data += diff;
180         req->out.ptr  += diff;
181
182         return req;
183 }
184
185 /*
186   work out the maximum data size we will allow for this reply, given
187   the negotiated max_xmit. The basic reply packet must be setup before
188   this call
189
190   note that this is deliberately a signed integer reply
191 */
192 int req_max_data(struct smbsrv_request *req)
193 {
194         int ret;
195         ret = req->smb_conn->negotiate.max_send;
196         ret -= PTR_DIFF(req->out.data, req->out.hdr);
197         if (ret < 0) ret = 0;
198         return ret;
199 }
200
201
202 /*
203   grow the allocation of the data buffer portion of a reply
204   packet. Note that as this can reallocate the packet buffer this
205   invalidates any local pointers into the packet.
206
207   To cope with this req->out.ptr is supplied. This will be updated to
208   point at the same offset into the packet as before this call
209 */
210 static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
211 {
212         int delta;
213         uint8_t *buf2;
214
215         delta = new_size - req->out.data_size;
216         if (delta + req->out.size <= req->out.allocated) {
217                 /* it fits in the preallocation */
218                 return;
219         }
220
221         /* we need to realloc */
222         req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
223         buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
224         if (buf2 == NULL) {
225                 smb_panic("out of memory in req_grow_allocation");
226         }
227
228         if (buf2 == req->out.buffer) {
229                 /* the malloc library gave us the same pointer */
230                 return;
231         }
232         
233         /* update the pointers into the packet */
234         req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
235         req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
236         req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
237         req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
238
239         req->out.buffer = buf2;
240 }
241
242
243 /*
244   grow the data buffer portion of a reply packet. Note that as this
245   can reallocate the packet buffer this invalidates any local pointers
246   into the packet. 
247
248   To cope with this req->out.ptr is supplied. This will be updated to
249   point at the same offset into the packet as before this call
250 */
251 void req_grow_data(struct smbsrv_request *req, uint_t new_size)
252 {
253         int delta;
254
255         if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
256                 smb_panic("reply buffer too large!");
257         }
258
259         req_grow_allocation(req, new_size);
260
261         delta = new_size - req->out.data_size;
262
263         req->out.size += delta;
264         req->out.data_size += delta;
265
266         /* set the BCC to the new data size */
267         SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
268 }
269
270 /*
271   send a reply and destroy the request buffer
272
273   note that this only looks at req->out.buffer and req->out.size, allowing manually 
274   constructed packets to be sent
275 */
276 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
277 {
278         DATA_BLOB blob;
279         NTSTATUS status;
280
281         if (req->out.size > NBT_HDR_SIZE) {
282                 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
283         }
284
285         blob = data_blob_const(req->out.buffer, req->out.size);
286         status = packet_send(req->smb_conn->packet, blob);
287         if (!NT_STATUS_IS_OK(status)) {
288                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
289         }
290         talloc_free(req);
291 }
292
293 /*
294   possibly sign a message then send a reply and destroy the request buffer
295
296   note that this only looks at req->out.buffer and req->out.size, allowing manually 
297   constructed packets to be sent
298 */
299 void smbsrv_send_reply(struct smbsrv_request *req)
300 {
301         smbsrv_sign_packet(req);
302
303         smbsrv_send_reply_nosign(req);
304 }
305
306 /* 
307    setup the header of a reply to include an NTSTATUS code
308 */
309 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
310 {
311         if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
312                 /* convert to DOS error codes */
313                 uint8_t eclass;
314                 uint32_t ecode;
315                 ntstatus_to_dos(status, &eclass, &ecode);
316                 SCVAL(req->out.hdr, HDR_RCLS, eclass);
317                 SSVAL(req->out.hdr, HDR_ERR, ecode);
318                 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
319                 return;
320         }
321
322         if (NT_STATUS_IS_DOS(status)) {
323                 /* its a encoded DOS error, using the reserved range */
324                 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
325                 SSVAL(req->out.hdr, HDR_ERR,  NT_STATUS_DOS_CODE(status));
326                 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
327         } else {
328                 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
329                 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
330         }
331 }
332
333 /* 
334    construct and send an error packet, then destroy the request 
335    auto-converts to DOS error format when appropriate
336 */
337 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
338 {
339         if (req->smb_conn->connection->event.fde == NULL) {
340                 /* the socket has been destroyed - no point trying to send an error! */
341                 talloc_free(req);
342                 return;
343         }
344         smbsrv_setup_reply(req, 0, 0);
345
346         /* error returns never have any data */
347         req_grow_data(req, 0);
348
349         smbsrv_setup_error(req, status);
350         smbsrv_send_reply(req);
351 }
352
353
354 /*
355   push a string into the data portion of the request packet, growing it if necessary
356   this gets quite tricky - please be very careful to cover all cases when modifying this
357
358   if dest is NULL, then put the string at the end of the data portion of the packet
359
360   if dest_len is -1 then no limit applies
361 */
362 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
363 {
364         size_t len;
365         uint_t grow_size;
366         uint8_t *buf0;
367         const int max_bytes_per_char = 3;
368
369         if (!(flags & (STR_ASCII|STR_UNICODE))) {
370                 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
371         }
372
373         if (dest == NULL) {
374                 dest = req->out.data + req->out.data_size;
375         }
376
377         if (dest_len != -1) {
378                 len = dest_len;
379         } else {
380                 len = (strlen(str)+2) * max_bytes_per_char;
381         }
382
383         grow_size = len + PTR_DIFF(dest, req->out.data);
384         buf0 = req->out.buffer;
385
386         req_grow_allocation(req, grow_size);
387
388         if (buf0 != req->out.buffer) {
389                 dest = req->out.buffer + PTR_DIFF(dest, buf0);
390         }
391
392         len = push_string(dest, str, len, flags);
393
394         grow_size = len + PTR_DIFF(dest, req->out.data);
395
396         if (grow_size > req->out.data_size) {
397                 req_grow_data(req, grow_size);
398         }
399
400         return len;
401 }
402
403 /*
404   append raw bytes into the data portion of the request packet
405   return the number of bytes added
406 */
407 size_t req_append_bytes(struct smbsrv_request *req, 
408                         const uint8_t *bytes, size_t byte_len)
409 {
410         req_grow_allocation(req, byte_len + req->out.data_size);
411         memcpy(req->out.data + req->out.data_size, bytes, byte_len);
412         req_grow_data(req, byte_len + req->out.data_size);
413         return byte_len;
414 }
415 /*
416   append variable block (type 5 buffer) into the data portion of the request packet
417   return the number of bytes added
418 */
419 size_t req_append_var_block(struct smbsrv_request *req, 
420                 const uint8_t *bytes, uint16_t byte_len)
421 {
422         req_grow_allocation(req, byte_len + 3 + req->out.data_size);
423         SCVAL(req->out.data + req->out.data_size, 0, 5);
424         SSVAL(req->out.data + req->out.data_size, 1, byte_len);         /* add field length */
425         if (byte_len > 0) {
426                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
427         }
428         req_grow_data(req, byte_len + 3 + req->out.data_size);
429         return byte_len + 3;
430 }
431 /*
432   pull a UCS2 string from a request packet, returning a talloced unix string
433
434   the string length is limited by the 3 things:
435    - the data size in the request (end of packet)
436    - the passed 'byte_len' if it is not -1
437    - the end of string (null termination)
438
439   Note that 'byte_len' is the number of bytes in the packet
440
441   on failure zero is returned and *dest is set to NULL, otherwise the number
442   of bytes consumed in the packet is returned
443 */
444 static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
445 {
446         int src_len, src_len2, alignment=0;
447         ssize_t ret;
448         char *dest2;
449
450         if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
451                 src++;
452                 alignment=1;
453                 if (byte_len != -1) {
454                         byte_len--;
455                 }
456         }
457
458         if (flags & STR_NO_RANGE_CHECK) {
459                 src_len = byte_len;
460         } else {
461                 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
462                 if (byte_len != -1 && src_len > byte_len) {
463                         src_len = byte_len;
464                 }
465         }
466
467         if (src_len < 0) {
468                 *dest = NULL;
469                 return 0;
470         }
471         
472         src_len2 = utf16_len_n(src, src_len);
473         if (src_len2 == 0) {
474                 *dest = talloc_strdup(req, "");
475                 return src_len2 + alignment;
476         }
477
478         ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
479
480         if (ret == -1) {
481                 *dest = NULL;
482                 return 0;
483         }
484         *dest = dest2;
485
486         return src_len2 + alignment;
487 }
488
489 /*
490   pull a ascii string from a request packet, returning a talloced string
491
492   the string length is limited by the 3 things:
493    - the data size in the request (end of packet)
494    - the passed 'byte_len' if it is not -1
495    - the end of string (null termination)
496
497   Note that 'byte_len' is the number of bytes in the packet
498
499   on failure zero is returned and *dest is set to NULL, otherwise the number
500   of bytes consumed in the packet is returned
501 */
502 static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
503 {
504         int src_len, src_len2;
505         ssize_t ret;
506         char *dest2;
507
508         if (flags & STR_NO_RANGE_CHECK) {
509                 src_len = byte_len;
510         } else {
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
521         src_len2 = strnlen((const char *)src, src_len);
522         if (src_len2 <= src_len - 1) {
523                 /* include the termination if we didn't reach the end of the packet */
524                 src_len2++;
525         }
526
527         ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
528
529         if (ret == -1) {
530                 *dest = NULL;
531                 return 0;
532         }
533         *dest = dest2;
534
535         return src_len2;
536 }
537
538 /*
539   pull a string from a request packet, returning a talloced string
540
541   the string length is limited by the 3 things:
542    - the data size in the request (end of packet)
543    - the passed 'byte_len' if it is not -1
544    - the end of string (null termination)
545
546   Note that 'byte_len' is the number of bytes in the packet
547
548   on failure zero is returned and *dest is set to NULL, otherwise the number
549   of bytes consumed in the packet is returned
550 */
551 size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
552 {
553         if (!(flags & STR_ASCII) && 
554             (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
555                 return req_pull_ucs2(req, dest, src, byte_len, flags);
556         }
557
558         return req_pull_ascii(req, dest, src, byte_len, flags);
559 }
560
561
562 /*
563   pull a ASCII4 string buffer from a request packet, returning a talloced string
564   
565   an ASCII4 buffer is a null terminated string that has a prefix
566   of the character 0x4. It tends to be used in older parts of the protocol.
567
568   on failure *dest is set to the zero length string. This seems to
569   match win2000 behaviour
570 */
571 size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
572 {
573         ssize_t ret;
574
575         if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
576                 /* win2000 treats this as the empty string! */
577                 (*dest) = talloc_strdup(req, "");
578                 return 0;
579         }
580
581         /* this consumes the 0x4 byte. We don't check whether the byte
582            is actually 0x4 or not. This matches win2000 server
583            behaviour */
584         src++;
585
586         ret = req_pull_string(req, dest, src, -1, flags);
587         if (ret == -1) {
588                 (*dest) = talloc_strdup(req, "");
589                 return 1;
590         }
591         
592         return ret + 1;
593 }
594
595 /*
596   pull a DATA_BLOB from a request packet, returning a talloced blob
597
598   return False if any part is outside the data portion of the packet
599 */
600 BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
601 {
602         if (len != 0 && req_data_oob(req, src, len)) {
603                 return False;
604         }
605
606         (*blob) = data_blob_talloc(req, src, len);
607
608         return True;
609 }
610
611 /* check that a lump of data in a request is within the bounds of the data section of
612    the packet */
613 BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
614 {
615         if (count == 0) {
616                 return False;
617         }
618         
619         /* be careful with wraparound! */
620         if (ptr < req->in.data ||
621             ptr >= req->in.data + req->in.data_size ||
622             count > req->in.data_size ||
623             ptr + count > req->in.data + req->in.data_size) {
624                 return True;
625         }
626         return False;
627 }
628
629
630 /* 
631    pull an open file handle from a packet, taking account of the chained_fnum
632 */
633 uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
634 {
635         if (req->chained_fnum != -1) {
636                 return req->chained_fnum;
637         }
638         return SVAL(base, offset);
639 }