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