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