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