59a34a0b136c91bc0af49c8a464056b88ea17015
[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
487         if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
488                 src++;
489                 alignment=1;
490                 if (byte_len != -1) {
491                         byte_len--;
492                 }
493         }
494
495         if (flags & STR_NO_RANGE_CHECK) {
496                 src_len = byte_len;
497         } else {
498                 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
499                 if (byte_len != -1 && src_len > byte_len) {
500                         src_len = byte_len;
501                 }
502         }
503
504         if (src_len < 0) {
505                 *dest = NULL;
506                 return 0;
507         }
508         
509         src_len2 = utf16_len_n(src, src_len);
510         if (src_len2 == 0) {
511                 *dest = talloc_strdup(bufinfo->mem_ctx, "");
512                 return src_len2 + alignment;
513         }
514
515         ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, NULL);
516
517         if (!ret) {
518                 *dest = NULL;
519                 return 0;
520         }
521         *dest = dest2;
522
523         return src_len2 + alignment;
524 }
525
526 /**
527   pull a ascii string from a request packet, returning a talloced string
528
529   the string length is limited by the 3 things:
530    - the data size in the request (end of packet)
531    - the passed 'byte_len' if it is not -1
532    - the end of string (null termination)
533
534   Note that 'byte_len' is the number of bytes in the packet
535
536   on failure zero is returned and *dest is set to NULL, otherwise the number
537   of bytes consumed in the packet is returned
538 */
539 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
540 {
541         int src_len, src_len2;
542         bool ret;
543         char *dest2;
544
545         if (flags & STR_NO_RANGE_CHECK) {
546                 src_len = byte_len;
547         } else {
548                 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
549                 if (src_len < 0) {
550                         *dest = NULL;
551                         return 0;
552                 }
553                 if (byte_len != -1 && src_len > byte_len) {
554                         src_len = byte_len;
555                 }
556         }
557
558         src_len2 = strnlen((const char *)src, src_len);
559         if (src_len2 <= src_len - 1) {
560                 /* include the termination if we didn't reach the end of the packet */
561                 src_len2++;
562         }
563
564         ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, NULL);
565
566         if (!ret) {
567                 *dest = NULL;
568                 return 0;
569         }
570         *dest = dest2;
571
572         return src_len2;
573 }
574
575 /**
576   pull a string from a request packet, returning a talloced string
577
578   the string length is limited by the 3 things:
579    - the data size in the request (end of packet)
580    - the passed 'byte_len' if it is not -1
581    - the end of string (null termination)
582
583   Note that 'byte_len' is the number of bytes in the packet
584
585   on failure zero is returned and *dest is set to NULL, otherwise the number
586   of bytes consumed in the packet is returned
587 */
588 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
589 {
590         if (!(flags & STR_ASCII) && 
591             (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
592                 return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
593         }
594
595         return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
596 }
597
598
599 /**
600   pull a ASCII4 string buffer from a request packet, returning a talloced string
601   
602   an ASCII4 buffer is a null terminated string that has a prefix
603   of the character 0x4. It tends to be used in older parts of the protocol.
604
605   on failure *dest is set to the zero length string. This seems to
606   match win2000 behaviour
607 */
608 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, unsigned int flags)
609 {
610         ssize_t ret;
611
612         if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
613                 /* win2000 treats this as the empty string! */
614                 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
615                 return 0;
616         }
617
618         /* this consumes the 0x4 byte. We don't check whether the byte
619            is actually 0x4 or not. This matches win2000 server
620            behaviour */
621         src++;
622
623         ret = req_pull_string(bufinfo, dest, src, -1, flags);
624         if (ret == -1) {
625                 (*dest) = talloc_strdup(bufinfo->mem_ctx, "");
626                 return 1;
627         }
628         
629         return ret + 1;
630 }
631
632 /**
633   pull a DATA_BLOB from a request packet, returning a talloced blob
634
635   return false if any part is outside the data portion of the packet
636 */
637 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
638 {
639         if (len != 0 && req_data_oob(bufinfo, src, len)) {
640                 return false;
641         }
642
643         (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
644
645         return true;
646 }
647
648 /* check that a lump of data in a request is within the bounds of the data section of
649    the packet */
650 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
651 {
652         if (count == 0) {
653                 return false;
654         }
655         
656         /* be careful with wraparound! */
657         if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
658             (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
659             count > bufinfo->data_size ||
660             (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
661                 return true;
662         }
663         return false;
664 }
665
666
667 /* 
668    pull an open file handle from a packet, taking account of the chained_fnum
669 */
670 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
671 {
672         if (req->chained_fnum != -1) {
673                 return req->chained_fnum;
674         }
675         return SVAL(base, offset);
676 }
677
678 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
679 {
680         struct smbsrv_handle *handle;
681         uint16_t fnum = req_fnum(req, base, offset);
682
683         handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
684         if (!handle) {
685                 return NULL;
686         }
687
688         /*
689          * For SMB tcons and sessions can be mixed!
690          * But we need to make sure that file handles
691          * are only accessed by the opening session!
692          *
693          * So check if the handle is valid for the given session!
694          */
695         if (handle->session != req->session) {
696                 return NULL;
697         }
698
699         return handle->ntvfs;
700 }
701
702 void smbsrv_push_fnum(uint8_t *base, unsigned int offset, struct ntvfs_handle *ntvfs)
703 {
704         struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
705                                        struct smbsrv_handle);
706         SSVAL(base, offset, handle->hid);
707 }
708
709 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
710 {
711         struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
712                                      struct smbsrv_request);
713         struct smbsrv_handle *handle;
714         struct ntvfs_handle *h;
715
716         handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
717         if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
718
719         h = talloc_zero(handle, struct ntvfs_handle);
720         if (!h) goto nomem;
721
722         /* 
723          * note: we don't set handle->ntvfs yet,
724          *       this will be done by smbsrv_handle_make_valid()
725          *       this makes sure the handle is invalid for clients
726          *       until the ntvfs subsystem has made it valid
727          */
728         h->ctx          = ntvfs->ctx;
729         h->session_info = ntvfs->session_info;
730         h->smbpid       = ntvfs->smbpid;
731
732         h->frontend_data.private_data = handle;
733
734         *_h = h;
735         return NT_STATUS_OK;
736 nomem:
737         talloc_free(handle);
738         return NT_STATUS_NO_MEMORY;
739 }
740
741 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
742 {
743         struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
744         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
745                                                        struct smbsrv_handle);
746         /* this tells the frontend that the handle is valid */
747         handle->ntvfs = h;
748         /* this moves the smbsrv_request to the smbsrv_tcon memory context */
749         talloc_steal(tcon, handle);
750         return NT_STATUS_OK;
751 }
752
753 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
754 {
755         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
756                                                        struct smbsrv_handle);
757         talloc_free(handle);
758 }
759
760 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
761 {
762         struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
763                                      struct smbsrv_request);
764
765         if (key->length != 2) return NULL;
766
767         return smbsrv_pull_fnum(req, key->data, 0);
768 }
769
770 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
771 {
772         uint8_t key[2];
773
774         smbsrv_push_fnum(key, 0, handle);
775
776         return data_blob_talloc(mem_ctx, key, sizeof(key));
777 }