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