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