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