Ensure convert_string_XXX is always called with a valid converted_size pointer.
[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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21   this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
22 */
23
24 #include "includes.h"
25 #include "smb_server/smb_server.h"
26 #include "smbd/service_stream.h"
27 #include "lib/stream/packet.h"
28 #include "ntvfs/ntvfs.h"
29
30
31 /* we over allocate the data buffer to prevent too many realloc calls */
32 #define REQ_OVER_ALLOCATION 0
33
34 /* setup the bufinfo used for strings and range checking */
35 void smbsrv_setup_bufinfo(struct smbsrv_request *req)
36 {
37         req->in.bufinfo.mem_ctx    = req;
38         req->in.bufinfo.flags      = 0;
39         if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
40                 req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
41         }
42         req->in.bufinfo.align_base = req->in.buffer;
43         req->in.bufinfo.data       = req->in.data;
44         req->in.bufinfo.data_size  = req->in.data_size;
45 }
46
47
48 static int smbsrv_request_destructor(struct smbsrv_request *req)
49 {
50         DLIST_REMOVE(req->smb_conn->requests, req);
51         return 0;
52 }
53
54 /****************************************************************************
55 construct a basic request packet, mostly used to construct async packets
56 such as change notify and oplock break requests
57 ****************************************************************************/
58 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
59 {
60         struct smbsrv_request *req;
61
62         req = talloc_zero(smb_conn, struct smbsrv_request);
63         if (!req) {
64                 return NULL;
65         }
66
67         /* setup the request context */
68         req->smb_conn = smb_conn;
69
70         talloc_set_destructor(req, smbsrv_request_destructor);
71
72         return req;
73 }
74
75
76 /*
77   setup a chained reply in req->out with the given word count and initial data buffer size. 
78 */
79 static void req_setup_chain_reply(struct smbsrv_request *req, unsigned int wct, unsigned int buflen)
80 {
81         uint32_t chain_base_size = req->out.size;
82
83         /* we need room for the wct value, the words, the buffer length and the buffer */
84         req->out.size += 1 + VWV(wct) + 2 + buflen;
85
86         /* over allocate by a small amount */
87         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
88
89         req->out.buffer = talloc_realloc(req, req->out.buffer, 
90                                          uint8_t, req->out.allocated);
91         if (!req->out.buffer) {
92                 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
93                 return;
94         }
95
96         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
97         req->out.vwv = req->out.buffer + chain_base_size + 1;
98         req->out.wct = wct;
99         req->out.data = req->out.vwv + VWV(wct) + 2;
100         req->out.data_size = buflen;
101         req->out.ptr = req->out.data;
102
103         SCVAL(req->out.buffer, chain_base_size, wct);
104         SSVAL(req->out.vwv, VWV(wct), buflen);
105 }
106
107
108 /*
109   setup a reply in req->out with the given word count and initial data buffer size. 
110   the caller will then fill in the command words and data before calling req_send_reply() to 
111   send the reply on its way
112 */
113 void smbsrv_setup_reply(struct smbsrv_request *req, unsigned int wct, size_t buflen)
114 {
115         uint16_t flags2;
116
117         if (req->chain_count != 0) {
118                 req_setup_chain_reply(req, wct, buflen);
119                 return;
120         }
121
122         req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
123
124         /* over allocate by a small amount */
125         req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
126
127         req->out.buffer = talloc_size(req, req->out.allocated);
128         if (!req->out.buffer) {
129                 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
130                 return;
131         }
132
133         flags2 = FLAGS2_LONG_PATH_COMPONENTS | 
134                 FLAGS2_EXTENDED_ATTRIBUTES | 
135                 FLAGS2_IS_LONG_NAME;
136 #define _SMB_FLAGS2_ECHOED_FLAGS ( \
137         FLAGS2_UNICODE_STRINGS | \
138         FLAGS2_EXTENDED_SECURITY | \
139         FLAGS2_SMB_SECURITY_SIGNATURES \
140 )
141         flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
142         if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
143                 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
144         }
145
146         req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
147         req->out.vwv = req->out.hdr + HDR_VWV;
148         req->out.wct = wct;
149         req->out.data = req->out.vwv + VWV(wct) + 2;
150         req->out.data_size = buflen;
151         req->out.ptr = req->out.data;
152
153         SIVAL(req->out.hdr, HDR_RCLS, 0);
154
155         SCVAL(req->out.hdr, HDR_WCT, wct);
156         SSVAL(req->out.vwv, VWV(wct), buflen);
157
158         memcpy(req->out.hdr, "\377SMB", 4);
159         SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES); 
160         SSVAL(req->out.hdr,HDR_FLG2, flags2);
161         SSVAL(req->out.hdr,HDR_PIDHIGH,0);
162         memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
163
164         if (req->in.hdr) {
165                 /* copy the cmd, tid, pid, uid and mid from the request */
166                 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));  
167                 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
168                 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
169                 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
170                 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
171         } else {
172                 SCVAL(req->out.hdr,HDR_COM,0);
173                 SSVAL(req->out.hdr,HDR_TID,0);
174                 SSVAL(req->out.hdr,HDR_PID,0);
175                 SSVAL(req->out.hdr,HDR_UID,0);
176                 SSVAL(req->out.hdr,HDR_MID,0);
177         }
178 }
179
180
181 /*
182   setup a copy of a request, used when the server needs to send
183   more than one reply for a single request packet
184 */
185 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
186 {
187         struct smbsrv_request *req;
188         ptrdiff_t diff;
189
190         req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
191         if (req == NULL) {
192                 return NULL;
193         }
194
195         req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
196         if (req->out.buffer == NULL) {
197                 talloc_free(req);
198                 return NULL;
199         }
200
201         diff = req->out.buffer - old_req->out.buffer;
202
203         req->out.hdr  += diff;
204         req->out.vwv  += diff;
205         req->out.data += diff;
206         req->out.ptr  += diff;
207
208         return req;
209 }
210
211 /*
212   work out the maximum data size we will allow for this reply, given
213   the negotiated max_xmit. The basic reply packet must be setup before
214   this call
215
216   note that this is deliberately a signed integer reply
217 */
218 int req_max_data(struct smbsrv_request *req)
219 {
220         int ret;
221         ret = req->smb_conn->negotiate.max_send;
222         ret -= PTR_DIFF(req->out.data, req->out.hdr);
223         if (ret < 0) ret = 0;
224         return ret;
225 }
226
227
228 /*
229   grow the allocation of the data buffer portion of a reply
230   packet. Note that as this can reallocate the packet buffer this
231   invalidates any local pointers into the packet.
232
233   To cope with this req->out.ptr is supplied. This will be updated to
234   point at the same offset into the packet as before this call
235 */
236 static void req_grow_allocation(struct smbsrv_request *req, unsigned int new_size)
237 {
238         int delta;
239         uint8_t *buf2;
240
241         delta = new_size - req->out.data_size;
242         if (delta + req->out.size <= req->out.allocated) {
243                 /* it fits in the preallocation */
244                 return;
245         }
246
247         /* we need to realloc */
248         req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
249         buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
250         if (buf2 == NULL) {
251                 smb_panic("out of memory in req_grow_allocation");
252         }
253
254         if (buf2 == req->out.buffer) {
255                 /* the malloc library gave us the same pointer */
256                 return;
257         }
258         
259         /* update the pointers into the packet */
260         req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
261         req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
262         req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
263         req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
264
265         req->out.buffer = buf2;
266 }
267
268
269 /*
270   grow the data buffer portion of a reply packet. Note that as this
271   can reallocate the packet buffer this invalidates any local pointers
272   into the packet. 
273
274   To cope with this req->out.ptr is supplied. This will be updated to
275   point at the same offset into the packet as before this call
276 */
277 void req_grow_data(struct smbsrv_request *req, size_t new_size)
278 {
279         int delta;
280
281         if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
282                 smb_panic("reply buffer too large!");
283         }
284
285         req_grow_allocation(req, new_size);
286
287         delta = new_size - req->out.data_size;
288
289         req->out.size += delta;
290         req->out.data_size += delta;
291
292         /* set the BCC to the new data size */
293         SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
294 }
295
296 /*
297   send a reply and destroy the request buffer
298
299   note that this only looks at req->out.buffer and req->out.size, allowing manually 
300   constructed packets to be sent
301 */
302 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
303 {
304         DATA_BLOB blob;
305         NTSTATUS status;
306
307         if (req->smb_conn->connection->event.fde == NULL) {
308                 /* we are in the process of shutting down this connection */
309                 talloc_free(req);
310                 return;
311         }
312
313         if (req->out.size > NBT_HDR_SIZE) {
314                 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
315         }
316
317         blob = data_blob_const(req->out.buffer, req->out.size);
318         status = packet_send(req->smb_conn->packet, blob);
319         if (!NT_STATUS_IS_OK(status)) {
320                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
321         }
322         talloc_free(req);
323 }
324
325 /*
326   possibly sign a message then send a reply and destroy the request buffer
327
328   note that this only looks at req->out.buffer and req->out.size, allowing manually 
329   constructed packets to be sent
330 */
331 void smbsrv_send_reply(struct smbsrv_request *req)
332 {
333         if (req->smb_conn->connection->event.fde == NULL) {
334                 /* we are in the process of shutting down this connection */
335                 talloc_free(req);
336                 return;
337         }
338         smbsrv_sign_packet(req);
339
340         smbsrv_send_reply_nosign(req);
341 }
342
343 /* 
344    setup the header of a reply to include an NTSTATUS code
345 */
346 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
347 {
348         if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
349                 /* convert to DOS error codes */
350                 uint8_t eclass;
351                 uint32_t ecode;
352                 ntstatus_to_dos(status, &eclass, &ecode);
353                 SCVAL(req->out.hdr, HDR_RCLS, eclass);
354                 SSVAL(req->out.hdr, HDR_ERR, ecode);
355                 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
356                 return;
357         }
358
359         if (NT_STATUS_IS_DOS(status)) {
360                 /* its a encoded DOS error, using the reserved range */
361                 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
362                 SSVAL(req->out.hdr, HDR_ERR,  NT_STATUS_DOS_CODE(status));
363                 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
364         } else {
365                 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
366                 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
367         }
368 }
369
370 /* 
371    construct and send an error packet, then destroy the request 
372    auto-converts to DOS error format when appropriate
373 */
374 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
375 {
376         if (req->smb_conn->connection->event.fde == NULL) {
377                 /* the socket has been destroyed - no point trying to send an error! */
378                 talloc_free(req);
379                 return;
380         }
381         smbsrv_setup_reply(req, 0, 0);
382
383         /* error returns never have any data */
384         req_grow_data(req, 0);
385
386         smbsrv_setup_error(req, status);
387         smbsrv_send_reply(req);
388 }
389
390
391 /*
392   push a string into the data portion of the request packet, growing it if necessary
393   this gets quite tricky - please be very careful to cover all cases when modifying this
394
395   if dest is NULL, then put the string at the end of the data portion of the packet
396
397   if dest_len is -1 then no limit applies
398 */
399 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
400 {
401         size_t len;
402         unsigned int grow_size;
403         uint8_t *buf0;
404         const int max_bytes_per_char = 3;
405
406         if (!(flags & (STR_ASCII|STR_UNICODE))) {
407                 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
408         }
409
410         if (dest == NULL) {
411                 dest = req->out.data + req->out.data_size;
412         }
413
414         if (dest_len != -1) {
415                 len = dest_len;
416         } else {
417                 len = (strlen(str)+2) * max_bytes_per_char;
418         }
419
420         grow_size = len + PTR_DIFF(dest, req->out.data);
421         buf0 = req->out.buffer;
422
423         req_grow_allocation(req, grow_size);
424
425         if (buf0 != req->out.buffer) {
426                 dest = req->out.buffer + PTR_DIFF(dest, buf0);
427         }
428
429         len = push_string(dest, str, len, flags);
430
431         grow_size = len + PTR_DIFF(dest, req->out.data);
432
433         if (grow_size > req->out.data_size) {
434                 req_grow_data(req, grow_size);
435         }
436
437         return len;
438 }
439
440 /*
441   append raw bytes into the data portion of the request packet
442   return the number of bytes added
443 */
444 size_t req_append_bytes(struct smbsrv_request *req, 
445                         const uint8_t *bytes, size_t byte_len)
446 {
447         req_grow_allocation(req, byte_len + req->out.data_size);
448         memcpy(req->out.data + req->out.data_size, bytes, byte_len);
449         req_grow_data(req, byte_len + req->out.data_size);
450         return byte_len;
451 }
452 /*
453   append variable block (type 5 buffer) into the data portion of the request packet
454   return the number of bytes added
455 */
456 size_t req_append_var_block(struct smbsrv_request *req, 
457                 const uint8_t *bytes, uint16_t byte_len)
458 {
459         req_grow_allocation(req, byte_len + 3 + req->out.data_size);
460         SCVAL(req->out.data + req->out.data_size, 0, 5);
461         SSVAL(req->out.data + req->out.data_size, 1, byte_len);         /* add field length */
462         if (byte_len > 0) {
463                 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
464         }
465         req_grow_data(req, byte_len + 3 + req->out.data_size);
466         return byte_len + 3;
467 }
468 /**
469   pull a UCS2 string from a request packet, returning a talloced unix string
470
471   the string length is limited by the 3 things:
472    - the data size in the request (end of packet)
473    - the passed 'byte_len' if it is not -1
474    - the end of string (null termination)
475
476   Note that 'byte_len' is the number of bytes in the packet
477
478   on failure zero is returned and *dest is set to NULL, otherwise the number
479   of bytes consumed in the packet is returned
480 */
481 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
482 {
483         int src_len, src_len2, alignment=0;
484         bool ret;
485         char *dest2;
486         size_t converted_size = 0;
487
488         if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
489                 src++;
490                 alignment=1;
491                 if (byte_len != -1) {
492                         byte_len--;
493                 }
494         }
495
496         if (flags & STR_NO_RANGE_CHECK) {
497                 src_len = byte_len;
498         } else {
499                 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
500                 if (byte_len != -1 && src_len > byte_len) {
501                         src_len = byte_len;
502                 }
503         }
504
505         if (src_len < 0) {
506                 *dest = NULL;
507                 return 0;
508         }
509         
510         src_len2 = utf16_len_n(src, src_len);
511         if (src_len2 == 0) {
512                 *dest = talloc_strdup(bufinfo->mem_ctx, "");
513                 return src_len2 + alignment;
514         }
515
516         ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
517
518         if (!ret) {
519                 *dest = NULL;
520                 return 0;
521         }
522         *dest = dest2;
523
524         return src_len2 + alignment;
525 }
526
527 /**
528   pull a ascii string from a request packet, returning a talloced string
529
530   the string length is limited by the 3 things:
531    - the data size in the request (end of packet)
532    - the passed 'byte_len' if it is not -1
533    - the end of string (null termination)
534
535   Note that 'byte_len' is the number of bytes in the packet
536
537   on failure zero is returned and *dest is set to NULL, otherwise the number
538   of bytes consumed in the packet is returned
539 */
540 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
541 {
542         int src_len, src_len2;
543         bool ret;
544         char *dest2;
545         size_t converted_size = 0;
546
547         if (flags & STR_NO_RANGE_CHECK) {
548                 src_len = byte_len;
549         } else {
550                 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
551                 if (src_len < 0) {
552                         *dest = NULL;
553                         return 0;
554                 }
555                 if (byte_len != -1 && src_len > byte_len) {
556                         src_len = byte_len;
557                 }
558         }
559
560         src_len2 = strnlen((const char *)src, src_len);
561         if (src_len2 <= src_len - 1) {
562                 /* include the termination if we didn't reach the end of the packet */
563                 src_len2++;
564         }
565
566         ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
567
568         if (!ret) {
569                 *dest = NULL;
570                 return 0;
571         }
572         *dest = dest2;
573
574         return src_len2;
575 }
576
577 /**
578   pull a string from a request packet, returning a talloced string
579
580   the string length is limited by the 3 things:
581    - the data size in the request (end of packet)
582    - the passed 'byte_len' if it is not -1
583    - the end of string (null termination)
584
585   Note that 'byte_len' is the number of bytes in the packet
586
587   on failure zero is returned and *dest is set to NULL, otherwise the number
588   of bytes consumed in the packet is returned
589 */
590 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
591 {
592         if (!(flags & STR_ASCII) && 
593             (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
594                 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
595         }
596
597         return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
598 }
599
600
601 /**
602   pull a ASCII4 string buffer from a request packet, returning a talloced string
603   
604   an ASCII4 buffer is a null terminated string that has a prefix
605   of the character 0x4. It tends to be used in older parts of the protocol.
606
607   on failure *dest is set to the zero length string. This seems to
608   match win2000 behaviour
609 */
610 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, unsigned int flags)
611 {
612         ssize_t ret;
613
614         if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
615                 /* win2000 treats this as the empty string! */
616                 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
617                 return 0;
618         }
619
620         /* this consumes the 0x4 byte. We don't check whether the byte
621            is actually 0x4 or not. This matches win2000 server
622            behaviour */
623         src++;
624
625         ret = req_pull_string(bufinfo, dest, src, -1, flags);
626         if (ret == -1) {
627                 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
628                 return 1;
629         }
630         
631         return ret + 1;
632 }
633
634 /**
635   pull a DATA_BLOB from a request packet, returning a talloced blob
636
637   return false if any part is outside the data portion of the packet
638 */
639 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
640 {
641         if (len != 0 && req_data_oob(bufinfo, src, len)) {
642                 return false;
643         }
644
645         (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
646
647         return true;
648 }
649
650 /* check that a lump of data in a request is within the bounds of the data section of
651    the packet */
652 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
653 {
654         if (count == 0) {
655                 return false;
656         }
657         
658         /* be careful with wraparound! */
659         if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
660             (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
661             count > bufinfo->data_size ||
662             (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
663                 return true;
664         }
665         return false;
666 }
667
668
669 /* 
670    pull an open file handle from a packet, taking account of the chained_fnum
671 */
672 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
673 {
674         if (req->chained_fnum != -1) {
675                 return req->chained_fnum;
676         }
677         return SVAL(base, offset);
678 }
679
680 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
681 {
682         struct smbsrv_handle *handle;
683         uint16_t fnum = req_fnum(req, base, offset);
684
685         handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
686         if (!handle) {
687                 return NULL;
688         }
689
690         /*
691          * For SMB tcons and sessions can be mixed!
692          * But we need to make sure that file handles
693          * are only accessed by the opening session!
694          *
695          * So check if the handle is valid for the given session!
696          */
697         if (handle->session != req->session) {
698                 return NULL;
699         }
700
701         return handle->ntvfs;
702 }
703
704 void smbsrv_push_fnum(uint8_t *base, unsigned int offset, struct ntvfs_handle *ntvfs)
705 {
706         struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
707                                        struct smbsrv_handle);
708         SSVAL(base, offset, handle->hid);
709 }
710
711 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
712 {
713         struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
714                                      struct smbsrv_request);
715         struct smbsrv_handle *handle;
716         struct ntvfs_handle *h;
717
718         handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
719         if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
720
721         h = talloc_zero(handle, struct ntvfs_handle);
722         if (!h) goto nomem;
723
724         /* 
725          * note: we don't set handle->ntvfs yet,
726          *       this will be done by smbsrv_handle_make_valid()
727          *       this makes sure the handle is invalid for clients
728          *       until the ntvfs subsystem has made it valid
729          */
730         h->ctx          = ntvfs->ctx;
731         h->session_info = ntvfs->session_info;
732         h->smbpid       = ntvfs->smbpid;
733
734         h->frontend_data.private_data = handle;
735
736         *_h = h;
737         return NT_STATUS_OK;
738 nomem:
739         talloc_free(handle);
740         return NT_STATUS_NO_MEMORY;
741 }
742
743 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
744 {
745         struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
746         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
747                                                        struct smbsrv_handle);
748         /* this tells the frontend that the handle is valid */
749         handle->ntvfs = h;
750         /* this moves the smbsrv_request to the smbsrv_tcon memory context */
751         talloc_steal(tcon, handle);
752         return NT_STATUS_OK;
753 }
754
755 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
756 {
757         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
758                                                        struct smbsrv_handle);
759         talloc_free(handle);
760 }
761
762 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
763 {
764         struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
765                                      struct smbsrv_request);
766
767         if (key->length != 2) return NULL;
768
769         return smbsrv_pull_fnum(req, key->data, 0);
770 }
771
772 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
773 {
774         uint8_t key[2];
775
776         smbsrv_push_fnum(key, 0, handle);
777
778         return data_blob_talloc(mem_ctx, key, sizeof(key));
779 }