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