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