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