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