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