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