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 "smbd/service_stream.h"
27 #include "lib/stream/packet.h"
28 #include "ntvfs/ntvfs.h"
29
30
31 /* we over allocate the data buffer to prevent too many realloc calls */
32 #define REQ_OVER_ALLOCATION 0
33
34 /* setup the bufinfo used for strings and range checking */
smbsrv_setup_bufinfo(struct smbsrv_request * req)35 void smbsrv_setup_bufinfo(struct smbsrv_request *req)
36 {
37 req->in.bufinfo.mem_ctx = req;
38 req->in.bufinfo.flags = 0;
39 if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
40 req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
41 }
42 req->in.bufinfo.align_base = req->in.buffer;
43 req->in.bufinfo.data = req->in.data;
44 req->in.bufinfo.data_size = req->in.data_size;
45 }
46
47
smbsrv_request_destructor(struct smbsrv_request * req)48 static int smbsrv_request_destructor(struct smbsrv_request *req)
49 {
50 DLIST_REMOVE(req->smb_conn->requests, req);
51 return 0;
52 }
53
54 /****************************************************************************
55 construct a basic request packet, mostly used to construct async packets
56 such as change notify and oplock break requests
57 ****************************************************************************/
smbsrv_init_request(struct smbsrv_connection * smb_conn)58 struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
59 {
60 struct smbsrv_request *req;
61
62 req = talloc_zero(smb_conn, struct smbsrv_request);
63 if (!req) {
64 return NULL;
65 }
66
67 /* setup the request context */
68 req->smb_conn = smb_conn;
69
70 talloc_set_destructor(req, smbsrv_request_destructor);
71
72 return req;
73 }
74
75
76 /*
77 setup a chained reply in req->out with the given word count and initial data buffer size.
78 */
req_setup_chain_reply(struct smbsrv_request * req,unsigned int wct,unsigned int buflen)79 static void req_setup_chain_reply(struct smbsrv_request *req, unsigned int wct, unsigned int buflen)
80 {
81 uint32_t chain_base_size = req->out.size;
82
83 /* we need room for the wct value, the words, the buffer length and the buffer */
84 req->out.size += 1 + VWV(wct) + 2 + buflen;
85
86 /* over allocate by a small amount */
87 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
88
89 req->out.buffer = talloc_realloc(req, req->out.buffer,
90 uint8_t, req->out.allocated);
91 if (!req->out.buffer) {
92 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
93 return;
94 }
95
96 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
97 req->out.vwv = req->out.buffer + chain_base_size + 1;
98 req->out.wct = wct;
99 req->out.data = req->out.vwv + VWV(wct) + 2;
100 req->out.data_size = buflen;
101 req->out.ptr = req->out.data;
102
103 SCVAL(req->out.buffer, chain_base_size, wct);
104 SSVAL(req->out.vwv, VWV(wct), buflen);
105 }
106
107
108 /*
109 setup a reply in req->out with the given word count and initial data buffer size.
110 the caller will then fill in the command words and data before calling req_send_reply() to
111 send the reply on its way
112 */
smbsrv_setup_reply(struct smbsrv_request * req,unsigned int wct,size_t buflen)113 void smbsrv_setup_reply(struct smbsrv_request *req, unsigned int wct, size_t buflen)
114 {
115 uint16_t flags2;
116
117 if (req->chain_count != 0) {
118 req_setup_chain_reply(req, wct, buflen);
119 return;
120 }
121
122 req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
123
124 /* over allocate by a small amount */
125 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
126
127 req->out.buffer = talloc_size(req, req->out.allocated);
128 if (!req->out.buffer) {
129 smbsrv_terminate_connection(req->smb_conn, "allocation failed");
130 return;
131 }
132
133 flags2 = FLAGS2_LONG_PATH_COMPONENTS |
134 FLAGS2_EXTENDED_ATTRIBUTES |
135 FLAGS2_IS_LONG_NAME;
136 #define _SMB_FLAGS2_ECHOED_FLAGS ( \
137 FLAGS2_UNICODE_STRINGS | \
138 FLAGS2_EXTENDED_SECURITY | \
139 FLAGS2_SMB_SECURITY_SIGNATURES \
140 )
141 flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
142 if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
143 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
144 }
145
146 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
147 req->out.vwv = req->out.hdr + HDR_VWV;
148 req->out.wct = wct;
149 req->out.data = req->out.vwv + VWV(wct) + 2;
150 req->out.data_size = buflen;
151 req->out.ptr = req->out.data;
152
153 SIVAL(req->out.hdr, HDR_RCLS, 0);
154
155 SCVAL(req->out.hdr, HDR_WCT, wct);
156 SSVAL(req->out.vwv, VWV(wct), buflen);
157
158 memcpy(req->out.hdr, "\377SMB", 4);
159 SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
160 SSVAL(req->out.hdr,HDR_FLG2, flags2);
161 SSVAL(req->out.hdr,HDR_PIDHIGH,0);
162 memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
163
164 if (req->in.hdr) {
165 /* copy the cmd, tid, pid, uid and mid from the request */
166 SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
167 SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
168 SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
169 SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
170 SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
171 } else {
172 SCVAL(req->out.hdr,HDR_COM,0);
173 SSVAL(req->out.hdr,HDR_TID,0);
174 SSVAL(req->out.hdr,HDR_PID,0);
175 SSVAL(req->out.hdr,HDR_UID,0);
176 SSVAL(req->out.hdr,HDR_MID,0);
177 }
178 }
179
180
181 /*
182 setup a copy of a request, used when the server needs to send
183 more than one reply for a single request packet
184 */
smbsrv_setup_secondary_request(struct smbsrv_request * old_req)185 struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
186 {
187 struct smbsrv_request *req;
188 ptrdiff_t diff;
189
190 req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
191 if (req == NULL) {
192 return NULL;
193 }
194
195 req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
196 if (req->out.buffer == NULL) {
197 talloc_free(req);
198 return NULL;
199 }
200
201 diff = req->out.buffer - old_req->out.buffer;
202
203 req->out.hdr += diff;
204 req->out.vwv += diff;
205 req->out.data += diff;
206 req->out.ptr += diff;
207
208 return req;
209 }
210
211 /*
212 work out the maximum data size we will allow for this reply, given
213 the negotiated max_xmit. The basic reply packet must be setup before
214 this call
215
216 note that this is deliberately a signed integer reply
217 */
req_max_data(struct smbsrv_request * req)218 int req_max_data(struct smbsrv_request *req)
219 {
220 int ret;
221 ret = req->smb_conn->negotiate.max_send;
222 ret -= PTR_DIFF(req->out.data, req->out.hdr);
223 if (ret < 0) ret = 0;
224 return ret;
225 }
226
227
228 /*
229 grow the allocation of the data buffer portion of a reply
230 packet. Note that as this can reallocate the packet buffer this
231 invalidates any local pointers into the packet.
232
233 To cope with this req->out.ptr is supplied. This will be updated to
234 point at the same offset into the packet as before this call
235 */
req_grow_allocation(struct smbsrv_request * req,unsigned int new_size)236 static void req_grow_allocation(struct smbsrv_request *req, unsigned int new_size)
237 {
238 int delta;
239 uint8_t *buf2;
240
241 delta = new_size - req->out.data_size;
242 if (delta + req->out.size <= req->out.allocated) {
243 /* it fits in the preallocation */
244 return;
245 }
246
247 /* we need to realloc */
248 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
249 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
250 if (buf2 == NULL) {
251 smb_panic("out of memory in req_grow_allocation");
252 }
253
254 if (buf2 == req->out.buffer) {
255 /* the malloc library gave us the same pointer */
256 return;
257 }
258
259 /* update the pointers into the packet */
260 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
261 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
262 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
263 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
264
265 req->out.buffer = buf2;
266 }
267
268
269 /*
270 grow the data buffer portion of a reply packet. Note that as this
271 can reallocate the packet buffer this invalidates any local pointers
272 into the packet.
273
274 To cope with this req->out.ptr is supplied. This will be updated to
275 point at the same offset into the packet as before this call
276 */
req_grow_data(struct smbsrv_request * req,size_t new_size)277 void req_grow_data(struct smbsrv_request *req, size_t new_size)
278 {
279 int delta;
280
281 if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
282 smb_panic("reply buffer too large!");
283 }
284
285 req_grow_allocation(req, new_size);
286
287 delta = new_size - req->out.data_size;
288
289 req->out.size += delta;
290 req->out.data_size += delta;
291
292 /* set the BCC to the new data size */
293 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
294 }
295
296 /*
297 send a reply and destroy the request buffer
298
299 note that this only looks at req->out.buffer and req->out.size, allowing manually
300 constructed packets to be sent
301 */
smbsrv_send_reply_nosign(struct smbsrv_request * req)302 void smbsrv_send_reply_nosign(struct smbsrv_request *req)
303 {
304 DATA_BLOB blob;
305 NTSTATUS status;
306
307 if (req->smb_conn->connection->event.fde == NULL) {
308 /* we are in the process of shutting down this connection */
309 talloc_free(req);
310 return;
311 }
312
313 if (req->out.size > NBT_HDR_SIZE) {
314 _smb_setlen_nbt(req->out.buffer, req->out.size - NBT_HDR_SIZE);
315 }
316
317 blob = data_blob_const(req->out.buffer, req->out.size);
318 status = packet_send(req->smb_conn->packet, blob);
319 if (!NT_STATUS_IS_OK(status)) {
320 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
321 }
322 talloc_free(req);
323 }
324
325 /*
326 possibly sign a message then send a reply and destroy the request buffer
327
328 note that this only looks at req->out.buffer and req->out.size, allowing manually
329 constructed packets to be sent
330 */
smbsrv_send_reply(struct smbsrv_request * req)331 void smbsrv_send_reply(struct smbsrv_request *req)
332 {
333 if (req->smb_conn->connection->event.fde == NULL) {
334 /* we are in the process of shutting down this connection */
335 talloc_free(req);
336 return;
337 }
338 smbsrv_sign_packet(req);
339
340 smbsrv_send_reply_nosign(req);
341 }
342
343 /*
344 setup the header of a reply to include an NTSTATUS code
345 */
smbsrv_setup_error(struct smbsrv_request * req,NTSTATUS status)346 void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
347 {
348 if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
349 /* convert to DOS error codes */
350 uint8_t eclass;
351 uint32_t ecode;
352 ntstatus_to_dos(status, &eclass, &ecode);
353 SCVAL(req->out.hdr, HDR_RCLS, eclass);
354 SSVAL(req->out.hdr, HDR_ERR, ecode);
355 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
356 return;
357 }
358
359 if (NT_STATUS_IS_DOS(status)) {
360 /* its a encoded DOS error, using the reserved range */
361 SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
362 SSVAL(req->out.hdr, HDR_ERR, NT_STATUS_DOS_CODE(status));
363 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
364 } else {
365 SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
366 SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
367 }
368 }
369
370 /*
371 construct and send an error packet, then destroy the request
372 auto-converts to DOS error format when appropriate
373 */
smbsrv_send_error(struct smbsrv_request * req,NTSTATUS status)374 void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
375 {
376 if (req->smb_conn->connection->event.fde == NULL) {
377 /* the socket has been destroyed - no point trying to send an error! */
378 talloc_free(req);
379 return;
380 }
381 smbsrv_setup_reply(req, 0, 0);
382
383 /* error returns never have any data */
384 req_grow_data(req, 0);
385
386 smbsrv_setup_error(req, status);
387 smbsrv_send_reply(req);
388 }
389
390
391 /*
392 push a string into the data portion of the request packet, growing it if necessary
393 this gets quite tricky - please be very careful to cover all cases when modifying this
394
395 if dest is NULL, then put the string at the end of the data portion of the packet
396
397 if dest_len is -1 then no limit applies
398 */
req_push_str(struct smbsrv_request * req,uint8_t * dest,const char * str,int dest_len,size_t flags)399 size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
400 {
401 size_t len;
402 unsigned int grow_size;
403 uint8_t *buf0;
404 const int max_bytes_per_char = 3;
405
406 if (!(flags & (STR_ASCII|STR_UNICODE))) {
407 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
408 }
409
410 if (dest == NULL) {
411 dest = req->out.data + req->out.data_size;
412 }
413
414 if (dest_len != -1) {
415 len = dest_len;
416 } else {
417 len = (strlen(str)+2) * max_bytes_per_char;
418 }
419
420 grow_size = len + PTR_DIFF(dest, req->out.data);
421 buf0 = req->out.buffer;
422
423 req_grow_allocation(req, grow_size);
424
425 if (buf0 != req->out.buffer) {
426 dest = req->out.buffer + PTR_DIFF(dest, buf0);
427 }
428
429 len = push_string(dest, str, len, flags);
430
431 grow_size = len + PTR_DIFF(dest, req->out.data);
432
433 if (grow_size > req->out.data_size) {
434 req_grow_data(req, grow_size);
435 }
436
437 return len;
438 }
439
440 /*
441 append raw bytes into the data portion of the request packet
442 return the number of bytes added
443 */
req_append_bytes(struct smbsrv_request * req,const uint8_t * bytes,size_t byte_len)444 size_t req_append_bytes(struct smbsrv_request *req,
445 const uint8_t *bytes, size_t byte_len)
446 {
447 req_grow_allocation(req, byte_len + req->out.data_size);
448 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
449 req_grow_data(req, byte_len + req->out.data_size);
450 return byte_len;
451 }
452 /*
453 append variable block (type 5 buffer) into the data portion of the request packet
454 return the number of bytes added
455 */
req_append_var_block(struct smbsrv_request * req,const uint8_t * bytes,uint16_t byte_len)456 size_t req_append_var_block(struct smbsrv_request *req,
457 const uint8_t *bytes, uint16_t byte_len)
458 {
459 req_grow_allocation(req, byte_len + 3 + req->out.data_size);
460 SCVAL(req->out.data + req->out.data_size, 0, 5);
461 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
462 if (byte_len > 0) {
463 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
464 }
465 req_grow_data(req, byte_len + 3 + req->out.data_size);
466 return byte_len + 3;
467 }
468 /**
469 pull a UCS2 string from a request packet, returning a talloced unix string
470
471 the string length is limited by the 3 things:
472 - the data size in the request (end of packet)
473 - the passed 'byte_len' if it is not -1
474 - the end of string (null termination)
475
476 Note that 'byte_len' is the number of bytes in the packet
477
478 on failure zero is returned and *dest is set to NULL, otherwise the number
479 of bytes consumed in the packet is returned
480 */
req_pull_ucs2(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,int byte_len,unsigned int flags)481 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
482 {
483 int src_len, src_len2, alignment=0;
484 bool ret;
485 char *dest2;
486 size_t converted_size = 0;
487
488 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
489 src++;
490 alignment=1;
491 if (byte_len != -1) {
492 byte_len--;
493 }
494 }
495
496 if (flags & STR_NO_RANGE_CHECK) {
497 src_len = byte_len;
498 } else {
499 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
500 if (byte_len != -1 && src_len > byte_len) {
501 src_len = byte_len;
502 }
503 }
504
505 if (src_len < 0) {
506 *dest = NULL;
507 return 0;
508 }
509
510 src_len2 = utf16_len_n(src, src_len);
511 if (src_len2 == 0) {
512 *dest = talloc_strdup(bufinfo->mem_ctx, "");
513 return src_len2 + alignment;
514 }
515
516 ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
517
518 if (!ret) {
519 *dest = NULL;
520 return 0;
521 }
522 *dest = dest2;
523
524 return src_len2 + alignment;
525 }
526
527 /**
528 pull a ascii string from a request packet, returning a talloced string
529
530 the string length is limited by the 3 things:
531 - the data size in the request (end of packet)
532 - the passed 'byte_len' if it is not -1
533 - the end of string (null termination)
534
535 Note that 'byte_len' is the number of bytes in the packet
536
537 on failure zero is returned and *dest is set to NULL, otherwise the number
538 of bytes consumed in the packet is returned
539 */
req_pull_ascii(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,int byte_len,unsigned int flags)540 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
541 {
542 int src_len, src_len2;
543 bool ret;
544 char *dest2;
545 size_t converted_size = 0;
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, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
567
568 if (!ret) {
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 */
req_pull_string(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,int byte_len,unsigned int flags)590 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int 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 */
req_pull_ascii4(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,unsigned int flags)610 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, unsigned int 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 */
req_pull_blob(struct request_bufinfo * bufinfo,const uint8_t * src,int len,DATA_BLOB * blob)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 */
req_data_oob(struct request_bufinfo * bufinfo,const uint8_t * ptr,uint32_t count)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 */
req_fnum(struct smbsrv_request * req,const uint8_t * base,unsigned int offset)672 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
673 {
674 if (req->chained_fnum != -1) {
675 return req->chained_fnum;
676 }
677 return SVAL(base, offset);
678 }
679
smbsrv_pull_fnum(struct smbsrv_request * req,const uint8_t * base,unsigned int offset)680 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int 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
smbsrv_push_fnum(uint8_t * base,unsigned int offset,struct ntvfs_handle * ntvfs)704 void smbsrv_push_fnum(uint8_t *base, unsigned int 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
smbsrv_handle_create_new(void * private_data,struct ntvfs_request * ntvfs,struct ntvfs_handle ** _h)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
smbsrv_handle_make_valid(void * private_data,struct ntvfs_handle * h)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
smbsrv_handle_destroy(void * private_data,struct ntvfs_handle * h)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
smbsrv_handle_search_by_wire_key(void * private_data,struct ntvfs_request * ntvfs,const DATA_BLOB * key)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
smbsrv_handle_get_wire_key(void * private_data,struct ntvfs_handle * handle,TALLOC_CTX * mem_ctx)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 }
780