Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Main SMB reply routines
4 : Copyright (C) Andrew Tridgell 1992-1998
5 : Copyright (C) Andrew Bartlett 2001
6 : Copyright (C) Jeremy Allison 1992-2007.
7 : Copyright (C) Volker Lendecke 2007
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 : /*
23 : This file handles most of the reply_ calls that the server
24 : makes to handle specific protocols
25 : */
26 :
27 : #include "includes.h"
28 : #include "libsmb/namequery.h"
29 : #include "system/filesys.h"
30 : #include "printing.h"
31 : #include "locking/share_mode_lock.h"
32 : #include "smbd/smbd.h"
33 : #include "smbd/globals.h"
34 : #include "fake_file.h"
35 : #include "rpc_client/rpc_client.h"
36 : #include "../librpc/gen_ndr/ndr_spoolss_c.h"
37 : #include "rpc_client/cli_spoolss.h"
38 : #include "rpc_client/init_spoolss.h"
39 : #include "rpc_server/rpc_ncacn_np.h"
40 : #include "libcli/security/security.h"
41 : #include "libsmb/nmblib.h"
42 : #include "auth.h"
43 : #include "smbprofile.h"
44 : #include "../lib/tsocket/tsocket.h"
45 : #include "lib/util/tevent_ntstatus.h"
46 : #include "libcli/smb/smb_signing.h"
47 : #include "lib/util/sys_rw_data.h"
48 : #include "librpc/gen_ndr/open_files.h"
49 : #include "smb1_utils.h"
50 : #include "libcli/smb/smb2_posix.h"
51 : #include "lib/util/string_wrappers.h"
52 : #include "source3/printing/rap_jobid.h"
53 :
54 : /****************************************************************************
55 : Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
56 : path or anything including wildcards.
57 : We're assuming here that '/' is not the second byte in any multibyte char
58 : set (a safe assumption). '\\' *may* be the second byte in a multibyte char
59 : set.
60 : ****************************************************************************/
61 :
62 : /* Custom version for processing POSIX paths. */
63 : #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
64 :
65 597771 : static NTSTATUS check_path_syntax_internal(char *path,
66 : bool posix_path)
67 : {
68 597771 : char *d = path;
69 597771 : const char *s = path;
70 597771 : NTSTATUS ret = NT_STATUS_OK;
71 597771 : bool start_of_name_component = True;
72 597771 : bool stream_started = false;
73 597771 : bool last_component_contains_wcard = false;
74 :
75 15838869 : while (*s) {
76 14736271 : if (stream_started) {
77 94662 : switch (*s) {
78 24 : case '/':
79 : case '\\':
80 32 : return NT_STATUS_OBJECT_NAME_INVALID;
81 4920 : case ':':
82 4920 : if (s[1] == '\0') {
83 36 : return NT_STATUS_OBJECT_NAME_INVALID;
84 : }
85 4884 : if (strchr_m(&s[1], ':')) {
86 12 : return NT_STATUS_OBJECT_NAME_INVALID;
87 : }
88 4871 : break;
89 : }
90 : }
91 :
92 14736199 : if ((*s == ':') && !posix_path && !stream_started) {
93 6432 : if (last_component_contains_wcard) {
94 12 : return NT_STATUS_OBJECT_NAME_INVALID;
95 : }
96 : /* Stream names allow more characters than file names.
97 : We're overloading posix_path here to allow a wider
98 : range of characters. If stream_started is true this
99 : is still a Windows path even if posix_path is true.
100 : JRA.
101 : */
102 6420 : stream_started = true;
103 6420 : start_of_name_component = false;
104 6420 : posix_path = true;
105 :
106 6420 : if (s[1] == '\0') {
107 8 : return NT_STATUS_OBJECT_NAME_INVALID;
108 : }
109 : }
110 :
111 14736179 : if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
112 : /*
113 : * Safe to assume is not the second part of a mb char
114 : * as this is handled below.
115 : */
116 : /* Eat multiple '/' or '\\' */
117 2594581 : while (IS_PATH_SEP(*s,posix_path)) {
118 925807 : s++;
119 : }
120 925351 : if ((d != path) && (*s != '\0')) {
121 : /* We only care about non-leading or trailing '/' or '\\' */
122 788591 : *d++ = '/';
123 : }
124 :
125 925351 : start_of_name_component = True;
126 : /* New component. */
127 925351 : last_component_contains_wcard = false;
128 925351 : continue;
129 : }
130 :
131 13810828 : if (start_of_name_component) {
132 1380686 : if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
133 : /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
134 :
135 : /*
136 : * No mb char starts with '.' so we're safe checking the directory separator here.
137 : */
138 :
139 : /* If we just added a '/' - delete it */
140 181 : if ((d > path) && (*(d-1) == '/')) {
141 104 : *(d-1) = '\0';
142 104 : d--;
143 : }
144 :
145 : /* Are we at the start ? Can't go back further if so. */
146 181 : if (d <= path) {
147 76 : ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
148 76 : break;
149 : }
150 : /* Go back one level... */
151 : /* We know this is safe as '/' cannot be part of a mb sequence. */
152 : /* NOTE - if this assumption is invalid we are not in good shape... */
153 : /* Decrement d first as d points to the *next* char to write into. */
154 512 : for (d--; d > path; d--) {
155 488 : if (*d == '/')
156 80 : break;
157 : }
158 104 : s += 2; /* Else go past the .. */
159 : /* We're still at the start of a name component, just the previous one. */
160 104 : continue;
161 :
162 1380505 : } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
163 458 : if (posix_path) {
164 : /* Eat the '.' */
165 4 : s++;
166 4 : continue;
167 : }
168 : }
169 :
170 : }
171 :
172 13810643 : if (!(*s & 0x80)) {
173 13679417 : if (!posix_path) {
174 13551223 : if (*s <= 0x1f || *s == '|') {
175 769 : return NT_STATUS_OBJECT_NAME_INVALID;
176 : }
177 13363091 : switch (*s) {
178 12062 : case '*':
179 : case '?':
180 : case '<':
181 : case '>':
182 : case '"':
183 12062 : last_component_contains_wcard = true;
184 12062 : break;
185 13351029 : default:
186 13351029 : break;
187 : }
188 121055 : }
189 13678648 : *d++ = *s++;
190 : } else {
191 : size_t siz;
192 : /* Get the size of the next MB character. */
193 131226 : next_codepoint(s,&siz);
194 131226 : switch(siz) {
195 0 : case 5:
196 0 : *d++ = *s++;
197 : FALL_THROUGH;
198 0 : case 4:
199 0 : *d++ = *s++;
200 : FALL_THROUGH;
201 131166 : case 3:
202 131166 : *d++ = *s++;
203 : FALL_THROUGH;
204 131226 : case 2:
205 131226 : *d++ = *s++;
206 : FALL_THROUGH;
207 131226 : case 1:
208 131226 : *d++ = *s++;
209 131226 : break;
210 0 : default:
211 0 : DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
212 0 : *d = '\0';
213 0 : return NT_STATUS_INVALID_PARAMETER;
214 : }
215 : }
216 13622496 : start_of_name_component = False;
217 : }
218 :
219 596910 : *d = '\0';
220 :
221 596910 : return ret;
222 : }
223 :
224 : /****************************************************************************
225 : Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
226 : No wildcards allowed.
227 : ****************************************************************************/
228 :
229 596141 : NTSTATUS check_path_syntax(char *path)
230 : {
231 596141 : return check_path_syntax_internal(path, false);
232 : }
233 :
234 : /****************************************************************************
235 : Check the path for a POSIX client.
236 : We're assuming here that '/' is not the second byte in any multibyte char
237 : set (a safe assumption).
238 : ****************************************************************************/
239 :
240 1630 : NTSTATUS check_path_syntax_posix(char *path)
241 : {
242 1630 : return check_path_syntax_internal(path, true);
243 : }
244 :
245 : /****************************************************************************
246 : Pull a string and check the path allowing a wildcard - provide for error return.
247 : Passes in posix flag.
248 : ****************************************************************************/
249 :
250 144975 : static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
251 : const char *base_ptr,
252 : uint16_t smb_flags2,
253 : char **pp_dest,
254 : const char *src,
255 : size_t src_len,
256 : int flags,
257 : bool posix_pathnames,
258 : NTSTATUS *err)
259 : {
260 : size_t ret;
261 :
262 144975 : *pp_dest = NULL;
263 :
264 144975 : ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
265 : src_len, flags);
266 :
267 144975 : if (!*pp_dest) {
268 0 : *err = NT_STATUS_INVALID_PARAMETER;
269 0 : return ret;
270 : }
271 :
272 144975 : if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
273 : /*
274 : * For a DFS path the function parse_dfs_path()
275 : * will do the path processing, just make a copy.
276 : */
277 140 : *err = NT_STATUS_OK;
278 140 : return ret;
279 : }
280 :
281 144835 : if (posix_pathnames) {
282 1630 : *err = check_path_syntax_posix(*pp_dest);
283 : } else {
284 143205 : *err = check_path_syntax(*pp_dest);
285 : }
286 :
287 134687 : return ret;
288 : }
289 :
290 : /****************************************************************************
291 : Pull a string and check the path - provide for error return.
292 : ****************************************************************************/
293 :
294 19593 : size_t srvstr_get_path(TALLOC_CTX *ctx,
295 : const char *base_ptr,
296 : uint16_t smb_flags2,
297 : char **pp_dest,
298 : const char *src,
299 : size_t src_len,
300 : int flags,
301 : NTSTATUS *err)
302 : {
303 19593 : return srvstr_get_path_internal(ctx,
304 : base_ptr,
305 : smb_flags2,
306 : pp_dest,
307 : src,
308 : src_len,
309 : flags,
310 : false,
311 : err);
312 : }
313 :
314 : /****************************************************************************
315 : Pull a string and check the path - provide for error return.
316 : posix_pathnames version.
317 : ****************************************************************************/
318 :
319 1442 : size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
320 : const char *base_ptr,
321 : uint16_t smb_flags2,
322 : char **pp_dest,
323 : const char *src,
324 : size_t src_len,
325 : int flags,
326 : NTSTATUS *err)
327 : {
328 1442 : return srvstr_get_path_internal(ctx,
329 : base_ptr,
330 : smb_flags2,
331 : pp_dest,
332 : src,
333 : src_len,
334 : flags,
335 : true,
336 : err);
337 : }
338 :
339 :
340 123940 : size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
341 : char **pp_dest, const char *src, int flags,
342 : NTSTATUS *err)
343 : {
344 123940 : ssize_t bufrem = smbreq_bufrem(req, src);
345 :
346 123940 : if (bufrem < 0) {
347 0 : *err = NT_STATUS_INVALID_PARAMETER;
348 0 : return 0;
349 : }
350 :
351 123940 : if (req->posix_pathnames) {
352 564 : return srvstr_get_path_internal(mem_ctx,
353 188 : (const char *)req->inbuf,
354 188 : req->flags2,
355 : pp_dest,
356 : src,
357 : bufrem,
358 : flags,
359 : true,
360 : err);
361 : } else {
362 329912 : return srvstr_get_path_internal(mem_ctx,
363 123752 : (const char *)req->inbuf,
364 123752 : req->flags2,
365 : pp_dest,
366 : src,
367 : bufrem,
368 : flags,
369 : false,
370 : err);
371 : }
372 : }
373 :
374 : /**
375 : * pull a string from the smb_buf part of a packet. In this case the
376 : * string can either be null terminated or it can be terminated by the
377 : * end of the smbbuf area
378 : */
379 41354 : size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
380 : char **dest, const uint8_t *src, int flags)
381 : {
382 41354 : ssize_t bufrem = smbreq_bufrem(req, src);
383 :
384 41354 : if (bufrem < 0) {
385 0 : return 0;
386 : }
387 :
388 41354 : return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
389 : bufrem, flags);
390 : }
391 :
392 : /****************************************************************************
393 : Check if we have a correct fsp pointing to a file. Basic check for open fsp.
394 : ****************************************************************************/
395 :
396 193549 : bool check_fsp_open(connection_struct *conn, struct smb_request *req,
397 : files_struct *fsp)
398 : {
399 193549 : if ((fsp == NULL) || (conn == NULL)) {
400 2718 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
401 2718 : return False;
402 : }
403 190831 : if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
404 39 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
405 39 : return False;
406 : }
407 189593 : return True;
408 : }
409 :
410 : /****************************************************************************
411 : Check if we have a correct fsp pointing to a file.
412 : ****************************************************************************/
413 :
414 148975 : bool check_fsp(connection_struct *conn, struct smb_request *req,
415 : files_struct *fsp)
416 : {
417 148975 : if (!check_fsp_open(conn, req, fsp)) {
418 96 : return False;
419 : }
420 148865 : if (fsp->fsp_flags.is_directory) {
421 6 : reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
422 6 : return False;
423 : }
424 148859 : if (fsp_get_pathref_fd(fsp) == -1) {
425 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
426 0 : return False;
427 : }
428 148859 : fsp->num_smb_operations++;
429 148859 : return True;
430 : }
431 :
432 : /****************************************************************************
433 : Check if we have a correct fsp pointing to a quota fake file. Replacement for
434 : the CHECK_NTQUOTA_HANDLE_OK macro.
435 : ****************************************************************************/
436 :
437 24 : bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
438 : files_struct *fsp)
439 : {
440 24 : if (!check_fsp_open(conn, req, fsp)) {
441 0 : return false;
442 : }
443 :
444 24 : if (fsp->fsp_flags.is_directory) {
445 4 : return false;
446 : }
447 :
448 20 : if (fsp->fake_file_handle == NULL) {
449 0 : return false;
450 : }
451 :
452 20 : if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
453 0 : return false;
454 : }
455 :
456 20 : if (fsp->fake_file_handle->private_data == NULL) {
457 0 : return false;
458 : }
459 :
460 20 : return true;
461 : }
462 :
463 : /****************************************************************************
464 : Return the port number we've bound to on a socket.
465 : ****************************************************************************/
466 :
467 1082 : static int get_socket_port(int fd)
468 : {
469 1082 : struct samba_sockaddr saddr = {
470 : .sa_socklen = sizeof(struct sockaddr_storage),
471 : };
472 :
473 1082 : if (fd == -1) {
474 0 : return -1;
475 : }
476 :
477 1082 : if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
478 0 : int level = (errno == ENOTCONN) ? 2 : 0;
479 0 : DEBUG(level, ("getsockname failed. Error was %s\n",
480 : strerror(errno)));
481 0 : return -1;
482 : }
483 :
484 : #if defined(HAVE_IPV6)
485 1082 : if (saddr.u.sa.sa_family == AF_INET6) {
486 85 : return ntohs(saddr.u.in6.sin6_port);
487 : }
488 : #endif
489 997 : if (saddr.u.sa.sa_family == AF_INET) {
490 997 : return ntohs(saddr.u.in.sin_port);
491 : }
492 0 : return -1;
493 : }
494 :
495 1082 : static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
496 : const char *name, int name_type)
497 : {
498 : char *trim_name;
499 : char *trim_name_type;
500 : const char *retarget_parm;
501 : char *retarget;
502 : char *p;
503 1082 : int retarget_type = 0x20;
504 1082 : int retarget_port = NBT_SMB_PORT;
505 : struct sockaddr_storage retarget_addr;
506 : struct sockaddr_in *in_addr;
507 1082 : bool ret = false;
508 : uint8_t outbuf[10];
509 :
510 1082 : if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
511 0 : return false;
512 : }
513 :
514 1082 : trim_name = talloc_strdup(talloc_tos(), name);
515 1082 : if (trim_name == NULL) {
516 0 : goto fail;
517 : }
518 1082 : trim_char(trim_name, ' ', ' ');
519 :
520 1082 : trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
521 : name_type);
522 1082 : if (trim_name_type == NULL) {
523 0 : goto fail;
524 : }
525 :
526 1082 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
527 : trim_name_type, NULL);
528 1082 : if (retarget_parm == NULL) {
529 1082 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
530 : trim_name, NULL);
531 : }
532 1082 : if (retarget_parm == NULL) {
533 1082 : goto fail;
534 : }
535 :
536 0 : retarget = talloc_strdup(trim_name, retarget_parm);
537 0 : if (retarget == NULL) {
538 0 : goto fail;
539 : }
540 :
541 0 : DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
542 :
543 0 : p = strchr(retarget, ':');
544 0 : if (p != NULL) {
545 0 : *p++ = '\0';
546 0 : retarget_port = atoi(p);
547 : }
548 :
549 0 : p = strchr_m(retarget, '#');
550 0 : if (p != NULL) {
551 0 : *p++ = '\0';
552 0 : if (sscanf(p, "%x", &retarget_type) != 1) {
553 0 : goto fail;
554 : }
555 : }
556 :
557 0 : ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
558 0 : if (!ret) {
559 0 : DEBUG(10, ("could not resolve %s\n", retarget));
560 0 : goto fail;
561 : }
562 :
563 0 : if (retarget_addr.ss_family != AF_INET) {
564 0 : DEBUG(10, ("Retarget target not an IPv4 addr\n"));
565 0 : goto fail;
566 : }
567 :
568 0 : in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
569 :
570 0 : _smb_setlen(outbuf, 6);
571 0 : SCVAL(outbuf, 0, 0x84);
572 0 : *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
573 0 : *(uint16_t *)(outbuf+8) = htons(retarget_port);
574 :
575 0 : if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
576 : NULL)) {
577 0 : exit_server_cleanly("netbios_session_retarget: srv_send_smb "
578 : "failed.");
579 : }
580 :
581 0 : ret = true;
582 1082 : fail:
583 1082 : TALLOC_FREE(trim_name);
584 1082 : return ret;
585 : }
586 :
587 4 : static void reply_called_name_not_present(char *outbuf)
588 : {
589 4 : smb_setlen(outbuf, 1);
590 4 : SCVAL(outbuf, 0, 0x83);
591 4 : SCVAL(outbuf, 4, 0x82);
592 4 : }
593 :
594 : /****************************************************************************
595 : Reply to a (netbios-level) special message.
596 : ****************************************************************************/
597 :
598 1086 : void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
599 : {
600 1086 : struct smbd_server_connection *sconn = xconn->client->sconn;
601 1086 : int msg_type = CVAL(inbuf,0);
602 1086 : int msg_flags = CVAL(inbuf,1);
603 : /*
604 : * We only really use 4 bytes of the outbuf, but for the smb_setlen
605 : * calculation & friends (srv_send_smb uses that) we need the full smb
606 : * header.
607 : */
608 : char outbuf[smb_size];
609 :
610 1086 : memset(outbuf, '\0', sizeof(outbuf));
611 :
612 1086 : smb_setlen(outbuf,0);
613 :
614 1086 : switch (msg_type) {
615 1086 : case NBSSrequest: /* session request */
616 : {
617 : /* inbuf_size is guarenteed to be at least 4. */
618 : fstring name1,name2;
619 : int name_type1, name_type2;
620 : int name_len1, name_len2;
621 :
622 1086 : *name1 = *name2 = 0;
623 :
624 1086 : if (xconn->transport.nbt.got_session) {
625 0 : exit_server_cleanly("multiple session request not permitted");
626 : }
627 :
628 1086 : SCVAL(outbuf,0,NBSSpositive);
629 1086 : SCVAL(outbuf,3,0);
630 :
631 : /* inbuf_size is guaranteed to be at least 4. */
632 1086 : name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
633 1086 : if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
634 0 : DEBUG(0,("Invalid name length in session request\n"));
635 0 : reply_called_name_not_present(outbuf);
636 0 : break;
637 : }
638 1086 : name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
639 1086 : if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
640 4 : DEBUG(0,("Invalid name length in session request\n"));
641 4 : reply_called_name_not_present(outbuf);
642 4 : break;
643 : }
644 :
645 1082 : name_type1 = name_extract((unsigned char *)inbuf,
646 : inbuf_size,(unsigned int)4,name1);
647 1082 : name_type2 = name_extract((unsigned char *)inbuf,
648 1082 : inbuf_size,(unsigned int)(4 + name_len1),name2);
649 :
650 1082 : if (name_type1 == -1 || name_type2 == -1) {
651 0 : DEBUG(0,("Invalid name type in session request\n"));
652 0 : reply_called_name_not_present(outbuf);
653 0 : break;
654 : }
655 :
656 1082 : DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
657 : name1, name_type1, name2, name_type2));
658 :
659 1082 : if (netbios_session_retarget(xconn, name1, name_type1)) {
660 0 : exit_server_cleanly("retargeted client");
661 : }
662 :
663 : /*
664 : * Windows NT/2k uses "*SMBSERVER" and XP uses
665 : * "*SMBSERV" arrggg!!!
666 : */
667 1082 : if (strequal(name1, "*SMBSERVER ")
668 1082 : || strequal(name1, "*SMBSERV ")) {
669 : char *raddr;
670 :
671 0 : raddr = tsocket_address_inet_addr_string(sconn->remote_address,
672 : talloc_tos());
673 0 : if (raddr == NULL) {
674 0 : exit_server_cleanly("could not allocate raddr");
675 : }
676 :
677 0 : fstrcpy(name1, raddr);
678 : }
679 :
680 1082 : set_local_machine_name(name1, True);
681 1082 : set_remote_machine_name(name2, True);
682 :
683 1082 : if (is_ipaddress(sconn->remote_hostname)) {
684 1082 : char *p = discard_const_p(char, sconn->remote_hostname);
685 :
686 1082 : talloc_free(p);
687 :
688 1082 : sconn->remote_hostname = talloc_strdup(sconn,
689 : get_remote_machine_name());
690 1082 : if (sconn->remote_hostname == NULL) {
691 0 : exit_server_cleanly("could not copy remote name");
692 : }
693 1082 : xconn->remote_hostname = sconn->remote_hostname;
694 : }
695 :
696 1082 : DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
697 : get_local_machine_name(), get_remote_machine_name(),
698 : name_type2));
699 :
700 1082 : if (name_type2 == 'R') {
701 : /* We are being asked for a pathworks session ---
702 : no thanks! */
703 0 : reply_called_name_not_present(outbuf);
704 0 : break;
705 : }
706 :
707 1082 : reload_services(sconn, conn_snum_used, true);
708 1082 : reopen_logs();
709 :
710 1082 : xconn->transport.nbt.got_session = true;
711 1082 : break;
712 : }
713 :
714 0 : case 0x89: /* session keepalive request
715 : (some old clients produce this?) */
716 0 : SCVAL(outbuf,0,NBSSkeepalive);
717 0 : SCVAL(outbuf,3,0);
718 0 : break;
719 :
720 0 : case NBSSpositive: /* positive session response */
721 : case NBSSnegative: /* negative session response */
722 : case NBSSretarget: /* retarget session response */
723 0 : DEBUG(0,("Unexpected session response\n"));
724 0 : break;
725 :
726 0 : case NBSSkeepalive: /* session keepalive */
727 : default:
728 0 : return;
729 : }
730 :
731 1086 : DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
732 : msg_type, msg_flags));
733 :
734 1086 : if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
735 63 : exit_server_cleanly("reply_special: srv_send_smb failed.");
736 : }
737 :
738 1023 : if (CVAL(outbuf, 0) != 0x82) {
739 4 : exit_server_cleanly("invalid netbios session");
740 : }
741 1019 : return;
742 : }
743 :
744 : /****************************************************************************
745 : Reply to a tcon.
746 : conn POINTER CAN BE NULL HERE !
747 : ****************************************************************************/
748 :
749 0 : void reply_tcon(struct smb_request *req)
750 : {
751 0 : connection_struct *conn = req->conn;
752 : const char *service;
753 0 : char *service_buf = NULL;
754 0 : char *password = NULL;
755 0 : char *dev = NULL;
756 0 : int pwlen=0;
757 : NTSTATUS nt_status;
758 : const uint8_t *p;
759 : const char *p2;
760 0 : TALLOC_CTX *ctx = talloc_tos();
761 0 : struct smbXsrv_connection *xconn = req->xconn;
762 0 : NTTIME now = timeval_to_nttime(&req->request_time);
763 :
764 0 : START_PROFILE(SMBtcon);
765 :
766 0 : if (req->buflen < 4) {
767 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
768 0 : END_PROFILE(SMBtcon);
769 0 : return;
770 : }
771 :
772 0 : p = req->buf + 1;
773 0 : p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
774 0 : p += 1;
775 0 : pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
776 0 : p += pwlen+1;
777 0 : p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
778 0 : p += 1;
779 :
780 0 : if (service_buf == NULL || password == NULL || dev == NULL) {
781 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
782 0 : END_PROFILE(SMBtcon);
783 0 : return;
784 : }
785 0 : p2 = strrchr_m(service_buf,'\\');
786 0 : if (p2) {
787 0 : service = p2+1;
788 : } else {
789 0 : service = service_buf;
790 : }
791 :
792 0 : conn = make_connection(req, now, service, dev,
793 : req->vuid,&nt_status);
794 0 : req->conn = conn;
795 :
796 0 : if (!conn) {
797 0 : reply_nterror(req, nt_status);
798 0 : END_PROFILE(SMBtcon);
799 0 : return;
800 : }
801 :
802 0 : reply_outbuf(req, 2, 0);
803 0 : SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
804 0 : SSVAL(req->outbuf,smb_vwv1,conn->cnum);
805 0 : SSVAL(req->outbuf,smb_tid,conn->cnum);
806 :
807 0 : DEBUG(3,("tcon service=%s cnum=%d\n",
808 : service, conn->cnum));
809 :
810 0 : END_PROFILE(SMBtcon);
811 0 : return;
812 : }
813 :
814 : /****************************************************************************
815 : Reply to a tcon and X.
816 : conn POINTER CAN BE NULL HERE !
817 : ****************************************************************************/
818 :
819 7594 : void reply_tcon_and_X(struct smb_request *req)
820 : {
821 7246 : const struct loadparm_substitution *lp_sub =
822 348 : loadparm_s3_global_substitution();
823 7594 : connection_struct *conn = req->conn;
824 7594 : const char *service = NULL;
825 7594 : TALLOC_CTX *ctx = talloc_tos();
826 : /* what the client thinks the device is */
827 7594 : char *client_devicetype = NULL;
828 : /* what the server tells the client the share represents */
829 : const char *server_devicetype;
830 : NTSTATUS nt_status;
831 : int passlen;
832 7594 : char *path = NULL;
833 : const uint8_t *p;
834 : const char *q;
835 : uint16_t tcon_flags;
836 7594 : struct smbXsrv_session *session = NULL;
837 7594 : NTTIME now = timeval_to_nttime(&req->request_time);
838 7594 : bool session_key_updated = false;
839 7594 : uint16_t optional_support = 0;
840 7594 : struct smbXsrv_connection *xconn = req->xconn;
841 :
842 7594 : START_PROFILE(SMBtconX);
843 :
844 7594 : if (req->wct < 4) {
845 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
846 0 : END_PROFILE(SMBtconX);
847 58 : return;
848 : }
849 :
850 7594 : passlen = SVAL(req->vwv+3, 0);
851 7594 : tcon_flags = SVAL(req->vwv+2, 0);
852 :
853 : /* we might have to close an old one */
854 7594 : if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
855 : struct smbXsrv_tcon *tcon;
856 : NTSTATUS status;
857 :
858 0 : tcon = conn->tcon;
859 0 : req->conn = NULL;
860 0 : conn = NULL;
861 :
862 : /*
863 : * TODO: cancel all outstanding requests on the tcon
864 : */
865 0 : status = smbXsrv_tcon_disconnect(tcon, req->vuid);
866 0 : if (!NT_STATUS_IS_OK(status)) {
867 0 : DEBUG(0, ("reply_tcon_and_X: "
868 : "smbXsrv_tcon_disconnect() failed: %s\n",
869 : nt_errstr(status)));
870 : /*
871 : * If we hit this case, there is something completely
872 : * wrong, so we better disconnect the transport connection.
873 : */
874 0 : END_PROFILE(SMBtconX);
875 0 : exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
876 : return;
877 : }
878 :
879 0 : TALLOC_FREE(tcon);
880 : /*
881 : * This tree id is gone. Make sure we can't re-use it
882 : * by accident.
883 : */
884 0 : req->tid = 0;
885 : }
886 :
887 7594 : if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
888 0 : reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
889 0 : END_PROFILE(SMBtconX);
890 0 : return;
891 : }
892 :
893 7594 : if (xconn->smb1.negprot.encrypted_passwords) {
894 7594 : p = req->buf + passlen;
895 : } else {
896 0 : p = req->buf + passlen + 1;
897 : }
898 :
899 7594 : p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
900 :
901 7594 : if (path == NULL) {
902 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
903 0 : END_PROFILE(SMBtconX);
904 0 : return;
905 : }
906 :
907 : /*
908 : * the service name can be either: \\server\share
909 : * or share directly like on the DELL PowerVault 705
910 : */
911 7594 : if (*path=='\\') {
912 7433 : q = strchr_m(path+2,'\\');
913 7433 : if (!q) {
914 0 : reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
915 0 : END_PROFILE(SMBtconX);
916 0 : return;
917 : }
918 7433 : service = q+1;
919 : } else {
920 150 : service = path;
921 : }
922 :
923 7594 : p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
924 : &client_devicetype, p,
925 : MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
926 :
927 7594 : if (client_devicetype == NULL) {
928 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
929 0 : END_PROFILE(SMBtconX);
930 0 : return;
931 : }
932 :
933 7594 : DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
934 :
935 7594 : nt_status = smb1srv_session_lookup(xconn,
936 7594 : req->vuid, now, &session);
937 7594 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
938 0 : reply_force_doserror(req, ERRSRV, ERRbaduid);
939 0 : END_PROFILE(SMBtconX);
940 0 : return;
941 : }
942 7594 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
943 0 : reply_nterror(req, nt_status);
944 0 : END_PROFILE(SMBtconX);
945 0 : return;
946 : }
947 7594 : if (!NT_STATUS_IS_OK(nt_status)) {
948 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
949 0 : END_PROFILE(SMBtconX);
950 0 : return;
951 : }
952 :
953 7594 : if (session->global->auth_session_info == NULL) {
954 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
955 0 : END_PROFILE(SMBtconX);
956 0 : return;
957 : }
958 :
959 : /*
960 : * If there is no application key defined yet
961 : * we create one.
962 : *
963 : * This means we setup the application key on the
964 : * first tcon that happens via the given session.
965 : *
966 : * Once the application key is defined, it does not
967 : * change any more.
968 : */
969 12434 : if (session->global->application_key_blob.length == 0 &&
970 4840 : smb2_signing_key_valid(session->global->signing_key))
971 : {
972 4764 : struct smbXsrv_session *x = session;
973 4764 : struct auth_session_info *session_info =
974 4764 : session->global->auth_session_info;
975 : uint8_t session_key[16];
976 :
977 4764 : ZERO_STRUCT(session_key);
978 4896 : memcpy(session_key, x->global->signing_key->blob.data,
979 4764 : MIN(x->global->signing_key->blob.length, sizeof(session_key)));
980 :
981 : /*
982 : * The application key is truncated/padded to 16 bytes
983 : */
984 4764 : x->global->application_key_blob = data_blob_talloc(x->global,
985 : session_key,
986 : sizeof(session_key));
987 4764 : ZERO_STRUCT(session_key);
988 4764 : if (x->global->application_key_blob.data == NULL) {
989 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
990 0 : END_PROFILE(SMBtconX);
991 0 : return;
992 : }
993 4764 : talloc_keep_secret(x->global->application_key_blob.data);
994 :
995 4764 : if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
996 : NTSTATUS status;
997 :
998 9078 : status = smb_key_derivation(x->global->application_key_blob.data,
999 4630 : x->global->application_key_blob.length,
1000 4762 : x->global->application_key_blob.data);
1001 4762 : if (!NT_STATUS_IS_OK(status)) {
1002 0 : DBG_ERR("smb_key_derivation failed: %s\n",
1003 : nt_errstr(status));
1004 0 : END_PROFILE(SMBtconX);
1005 0 : return;
1006 : }
1007 4762 : optional_support |= SMB_EXTENDED_SIGNATURES;
1008 : }
1009 :
1010 : /*
1011 : * Place the application key into the session_info
1012 : */
1013 4764 : data_blob_clear_free(&session_info->session_key);
1014 4764 : session_info->session_key = data_blob_dup_talloc(session_info,
1015 : x->global->application_key_blob);
1016 4764 : if (session_info->session_key.data == NULL) {
1017 0 : data_blob_clear_free(&x->global->application_key_blob);
1018 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1019 0 : END_PROFILE(SMBtconX);
1020 0 : return;
1021 : }
1022 4764 : talloc_keep_secret(session_info->session_key.data);
1023 4764 : session_key_updated = true;
1024 : }
1025 :
1026 7594 : conn = make_connection(req, now, service, client_devicetype,
1027 : req->vuid, &nt_status);
1028 7594 : req->conn =conn;
1029 :
1030 7594 : if (!conn) {
1031 66 : if (session_key_updated) {
1032 4 : struct smbXsrv_session *x = session;
1033 4 : struct auth_session_info *session_info =
1034 4 : session->global->auth_session_info;
1035 4 : data_blob_clear_free(&x->global->application_key_blob);
1036 4 : data_blob_clear_free(&session_info->session_key);
1037 : }
1038 66 : reply_nterror(req, nt_status);
1039 66 : END_PROFILE(SMBtconX);
1040 60 : return;
1041 : }
1042 :
1043 7528 : if ( IS_IPC(conn) )
1044 2828 : server_devicetype = "IPC";
1045 4690 : else if ( IS_PRINT(conn) )
1046 2 : server_devicetype = "LPT1:";
1047 : else
1048 4688 : server_devicetype = "A:";
1049 :
1050 7528 : if (get_Protocol() < PROTOCOL_NT1) {
1051 22 : reply_outbuf(req, 2, 0);
1052 22 : if (message_push_string(&req->outbuf, server_devicetype,
1053 : STR_TERMINATE|STR_ASCII) == -1) {
1054 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1055 0 : END_PROFILE(SMBtconX);
1056 0 : return;
1057 : }
1058 : } else {
1059 : /* NT sets the fstype of IPC$ to the null string */
1060 7506 : const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1061 :
1062 7506 : if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1063 : /* Return permissions. */
1064 7506 : uint32_t perm1 = 0;
1065 7506 : uint32_t perm2 = 0;
1066 :
1067 7506 : reply_outbuf(req, 7, 0);
1068 :
1069 7506 : if (IS_IPC(conn)) {
1070 2828 : perm1 = FILE_ALL_ACCESS;
1071 2828 : perm2 = FILE_ALL_ACCESS;
1072 : } else {
1073 4668 : perm1 = conn->share_access;
1074 : }
1075 :
1076 7506 : SIVAL(req->outbuf, smb_vwv3, perm1);
1077 7506 : SIVAL(req->outbuf, smb_vwv5, perm2);
1078 : } else {
1079 0 : reply_outbuf(req, 3, 0);
1080 : }
1081 :
1082 7506 : if ((message_push_string(&req->outbuf, server_devicetype,
1083 : STR_TERMINATE|STR_ASCII) == -1)
1084 7506 : || (message_push_string(&req->outbuf, fstype,
1085 : STR_TERMINATE) == -1)) {
1086 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1087 0 : END_PROFILE(SMBtconX);
1088 0 : return;
1089 : }
1090 :
1091 : /* what does setting this bit do? It is set by NT4 and
1092 : may affect the ability to autorun mounted cdroms */
1093 7506 : optional_support |= SMB_SUPPORT_SEARCH_BITS;
1094 7506 : optional_support |=
1095 7506 : (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1096 :
1097 7506 : if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1098 26 : DEBUG(2,("Serving %s as a Dfs root\n",
1099 : lp_servicename(ctx, lp_sub, SNUM(conn)) ));
1100 26 : optional_support |= SMB_SHARE_IN_DFS;
1101 : }
1102 :
1103 7506 : SSVAL(req->outbuf, smb_vwv2, optional_support);
1104 : }
1105 :
1106 7528 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1107 7528 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1108 :
1109 7528 : DEBUG(3,("tconX service=%s \n",
1110 : service));
1111 :
1112 : /* set the incoming and outgoing tid to the just created one */
1113 7528 : SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1114 7528 : SSVAL(req->outbuf,smb_tid,conn->cnum);
1115 :
1116 7528 : END_PROFILE(SMBtconX);
1117 :
1118 7528 : req->tid = conn->cnum;
1119 : }
1120 :
1121 : /****************************************************************************
1122 : Reply to an unknown type.
1123 : ****************************************************************************/
1124 :
1125 0 : void reply_unknown_new(struct smb_request *req, uint8_t type)
1126 : {
1127 0 : DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1128 : smb_fn_name(type), type, type));
1129 0 : reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1130 0 : return;
1131 : }
1132 :
1133 : /****************************************************************************
1134 : Reply to an ioctl.
1135 : conn POINTER CAN BE NULL HERE !
1136 : ****************************************************************************/
1137 :
1138 262152 : void reply_ioctl(struct smb_request *req)
1139 : {
1140 262152 : const struct loadparm_substitution *lp_sub =
1141 0 : loadparm_s3_global_substitution();
1142 262152 : connection_struct *conn = req->conn;
1143 : uint16_t device;
1144 : uint16_t function;
1145 : uint32_t ioctl_code;
1146 : int replysize;
1147 : char *p;
1148 :
1149 262152 : START_PROFILE(SMBioctl);
1150 :
1151 262152 : if (req->wct < 3) {
1152 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1153 0 : END_PROFILE(SMBioctl);
1154 0 : return;
1155 : }
1156 :
1157 262152 : device = SVAL(req->vwv+1, 0);
1158 262152 : function = SVAL(req->vwv+2, 0);
1159 262152 : ioctl_code = (device << 16) + function;
1160 :
1161 262152 : DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1162 :
1163 262152 : switch (ioctl_code) {
1164 8 : case IOCTL_QUERY_JOB_INFO:
1165 8 : replysize = 32;
1166 8 : break;
1167 262144 : default:
1168 262144 : reply_force_doserror(req, ERRSRV, ERRnosupport);
1169 262144 : END_PROFILE(SMBioctl);
1170 262144 : return;
1171 : }
1172 :
1173 8 : reply_outbuf(req, 8, replysize+1);
1174 8 : SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1175 8 : SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1176 8 : SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1177 8 : p = smb_buf(req->outbuf);
1178 8 : memset(p, '\0', replysize+1); /* valgrind-safe. */
1179 8 : p += 1; /* Allow for alignment */
1180 :
1181 8 : switch (ioctl_code) {
1182 8 : case IOCTL_QUERY_JOB_INFO:
1183 : {
1184 : NTSTATUS status;
1185 8 : size_t len = 0;
1186 8 : files_struct *fsp = file_fsp(
1187 8 : req, SVAL(req->vwv+0, 0));
1188 8 : if (!fsp) {
1189 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1190 0 : END_PROFILE(SMBioctl);
1191 0 : return;
1192 : }
1193 : /* Job number */
1194 8 : SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1195 :
1196 8 : status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1197 : lp_netbios_name(), 15,
1198 : STR_TERMINATE|STR_ASCII, &len);
1199 8 : if (!NT_STATUS_IS_OK(status)) {
1200 0 : reply_nterror(req, status);
1201 0 : END_PROFILE(SMBioctl);
1202 0 : return;
1203 : }
1204 8 : if (conn) {
1205 8 : status = srvstr_push((char *)req->outbuf, req->flags2,
1206 : p+18,
1207 : lp_servicename(talloc_tos(),
1208 : lp_sub,
1209 : SNUM(conn)),
1210 : 13, STR_TERMINATE|STR_ASCII, &len);
1211 8 : if (!NT_STATUS_IS_OK(status)) {
1212 0 : reply_nterror(req, status);
1213 0 : END_PROFILE(SMBioctl);
1214 0 : return;
1215 : }
1216 : } else {
1217 0 : memset(p+18, 0, 13);
1218 : }
1219 8 : break;
1220 : }
1221 : }
1222 :
1223 8 : END_PROFILE(SMBioctl);
1224 8 : return;
1225 : }
1226 :
1227 : /****************************************************************************
1228 : Strange checkpath NTSTATUS mapping.
1229 : ****************************************************************************/
1230 :
1231 1966 : static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1232 : {
1233 : /* Strange DOS error code semantics only for checkpath... */
1234 1970 : if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1235 32 : if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1236 : /* We need to map to ERRbadpath */
1237 20 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1238 : }
1239 : }
1240 1946 : return status;
1241 : }
1242 :
1243 : /****************************************************************************
1244 : Reply to a checkpath.
1245 : ****************************************************************************/
1246 :
1247 1999 : void reply_checkpath(struct smb_request *req)
1248 : {
1249 1999 : connection_struct *conn = req->conn;
1250 1999 : struct smb_filename *smb_fname = NULL;
1251 1999 : char *name = NULL;
1252 : NTSTATUS status;
1253 1999 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1254 1999 : TALLOC_CTX *ctx = talloc_tos();
1255 :
1256 1999 : START_PROFILE(SMBcheckpath);
1257 :
1258 1999 : srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1259 : STR_TERMINATE, &status);
1260 :
1261 1999 : if (!NT_STATUS_IS_OK(status)) {
1262 172 : status = map_checkpath_error(req->flags2, status);
1263 172 : reply_nterror(req, status);
1264 172 : END_PROFILE(SMBcheckpath);
1265 172 : return;
1266 : }
1267 :
1268 1827 : DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1269 :
1270 1827 : status = filename_convert(ctx,
1271 : conn,
1272 : name,
1273 : ucf_flags,
1274 : 0,
1275 : &smb_fname);
1276 :
1277 1827 : if (!NT_STATUS_IS_OK(status)) {
1278 197 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1279 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1280 : ERRSRV, ERRbadpath);
1281 0 : END_PROFILE(SMBcheckpath);
1282 0 : return;
1283 : }
1284 196 : goto path_err;
1285 : }
1286 :
1287 2047 : if (!VALID_STAT(smb_fname->st) &&
1288 417 : (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1289 417 : DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1290 : smb_fname_str_dbg(smb_fname), strerror(errno)));
1291 417 : status = map_nt_error_from_unix(errno);
1292 417 : goto path_err;
1293 : }
1294 :
1295 1213 : if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1296 29 : reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1297 : ERRDOS, ERRbadpath);
1298 29 : goto out;
1299 : }
1300 :
1301 1184 : reply_outbuf(req, 0, 0);
1302 :
1303 1798 : path_err:
1304 : /* We special case this - as when a Windows machine
1305 : is parsing a path is steps through the components
1306 : one at a time - if a component fails it expects
1307 : ERRbadpath, not ERRbadfile.
1308 : */
1309 1802 : status = map_checkpath_error(req->flags2, status);
1310 1798 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1311 : /*
1312 : * Windows returns different error codes if
1313 : * the parent directory is valid but not the
1314 : * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1315 : * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1316 : * if the path is invalid.
1317 : */
1318 417 : reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1319 : ERRDOS, ERRbadpath);
1320 417 : goto out;
1321 : }
1322 :
1323 1381 : reply_nterror(req, status);
1324 :
1325 1827 : out:
1326 1827 : TALLOC_FREE(smb_fname);
1327 1827 : END_PROFILE(SMBcheckpath);
1328 1822 : return;
1329 : }
1330 :
1331 : /****************************************************************************
1332 : Reply to a getatr.
1333 : ****************************************************************************/
1334 :
1335 1412 : void reply_getatr(struct smb_request *req)
1336 : {
1337 1412 : connection_struct *conn = req->conn;
1338 1412 : struct smb_filename *smb_fname = NULL;
1339 1412 : char *fname = NULL;
1340 1412 : int mode=0;
1341 1412 : off_t size=0;
1342 1412 : time_t mtime=0;
1343 : const char *p;
1344 : NTSTATUS status;
1345 1412 : TALLOC_CTX *ctx = talloc_tos();
1346 1412 : bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1347 :
1348 1412 : START_PROFILE(SMBgetatr);
1349 :
1350 1412 : p = (const char *)req->buf + 1;
1351 1412 : p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1352 1412 : if (!NT_STATUS_IS_OK(status)) {
1353 24 : reply_nterror(req, status);
1354 24 : goto out;
1355 : }
1356 :
1357 : /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1358 : under WfWg - weird! */
1359 1388 : if (*fname == '\0') {
1360 0 : mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1361 0 : if (!CAN_WRITE(conn)) {
1362 0 : mode |= FILE_ATTRIBUTE_READONLY;
1363 : }
1364 0 : size = 0;
1365 0 : mtime = 0;
1366 : } else {
1367 1388 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1368 1388 : status = filename_convert(ctx,
1369 : conn,
1370 : fname,
1371 : ucf_flags,
1372 : 0,
1373 : &smb_fname);
1374 1388 : if (!NT_STATUS_IS_OK(status)) {
1375 24 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1376 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1377 : ERRSRV, ERRbadpath);
1378 0 : goto out;
1379 : }
1380 24 : reply_nterror(req, status);
1381 24 : goto out;
1382 : }
1383 1436 : if (!VALID_STAT(smb_fname->st) &&
1384 72 : (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1385 72 : DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1386 : smb_fname_str_dbg(smb_fname),
1387 : strerror(errno)));
1388 72 : reply_nterror(req, map_nt_error_from_unix(errno));
1389 72 : goto out;
1390 : }
1391 :
1392 1292 : mode = fdos_mode(smb_fname->fsp);
1393 1292 : size = smb_fname->st.st_ex_size;
1394 :
1395 1292 : if (ask_sharemode) {
1396 : struct timespec write_time_ts;
1397 : struct file_id fileid;
1398 :
1399 1292 : ZERO_STRUCT(write_time_ts);
1400 1292 : fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1401 1292 : get_file_infos(fileid, 0, NULL, &write_time_ts);
1402 1292 : if (!is_omit_timespec(&write_time_ts)) {
1403 12 : update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1404 : }
1405 : }
1406 :
1407 1292 : mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1408 1292 : if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1409 48 : size = 0;
1410 : }
1411 : }
1412 :
1413 1292 : reply_outbuf(req, 10, 0);
1414 :
1415 1292 : SSVAL(req->outbuf,smb_vwv0,mode);
1416 1292 : if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1417 0 : srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1418 : } else {
1419 1292 : srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1420 : }
1421 1292 : SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1422 :
1423 1292 : if (get_Protocol() >= PROTOCOL_NT1) {
1424 1292 : SSVAL(req->outbuf, smb_flg2,
1425 : SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1426 : }
1427 :
1428 1292 : DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1429 : smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1430 :
1431 1412 : out:
1432 1412 : TALLOC_FREE(smb_fname);
1433 1412 : TALLOC_FREE(fname);
1434 1412 : END_PROFILE(SMBgetatr);
1435 1412 : return;
1436 : }
1437 :
1438 : /****************************************************************************
1439 : Reply to a setatr.
1440 : ****************************************************************************/
1441 :
1442 2169 : void reply_setatr(struct smb_request *req)
1443 : {
1444 : struct smb_file_time ft;
1445 2169 : connection_struct *conn = req->conn;
1446 2169 : struct smb_filename *smb_fname = NULL;
1447 2169 : char *fname = NULL;
1448 : int mode;
1449 : time_t mtime;
1450 : const char *p;
1451 : NTSTATUS status;
1452 2169 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1453 2169 : TALLOC_CTX *ctx = talloc_tos();
1454 :
1455 2169 : START_PROFILE(SMBsetatr);
1456 2169 : init_smb_file_time(&ft);
1457 :
1458 2169 : if (req->wct < 2) {
1459 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1460 0 : goto out;
1461 : }
1462 :
1463 2169 : p = (const char *)req->buf + 1;
1464 2169 : p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1465 2169 : if (!NT_STATUS_IS_OK(status)) {
1466 155 : reply_nterror(req, status);
1467 155 : goto out;
1468 : }
1469 :
1470 2014 : status = filename_convert(ctx,
1471 : conn,
1472 : fname,
1473 : ucf_flags,
1474 : 0,
1475 : &smb_fname);
1476 2014 : if (!NT_STATUS_IS_OK(status)) {
1477 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1478 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1479 : ERRSRV, ERRbadpath);
1480 0 : goto out;
1481 : }
1482 0 : reply_nterror(req, status);
1483 0 : goto out;
1484 : }
1485 :
1486 2014 : if (ISDOT(smb_fname->base_name)) {
1487 : /*
1488 : * Not sure here is the right place to catch this
1489 : * condition. Might be moved to somewhere else later -- vl
1490 : */
1491 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1492 0 : goto out;
1493 : }
1494 :
1495 2014 : if (smb_fname->fsp == NULL) {
1496 : /* Can't set access rights on a symlink. */
1497 535 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1498 535 : goto out;
1499 : }
1500 :
1501 1479 : mode = SVAL(req->vwv+0, 0);
1502 1479 : mtime = srv_make_unix_date3(req->vwv+1);
1503 :
1504 1479 : if (mode != FILE_ATTRIBUTE_NORMAL) {
1505 739 : if (VALID_STAT_OF_DIR(smb_fname->st))
1506 34 : mode |= FILE_ATTRIBUTE_DIRECTORY;
1507 : else
1508 705 : mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1509 :
1510 739 : status = smbd_check_access_rights_fsp(conn->cwd_fsp,
1511 712 : smb_fname->fsp,
1512 : false,
1513 : FILE_WRITE_ATTRIBUTES);
1514 739 : if (!NT_STATUS_IS_OK(status)) {
1515 0 : reply_nterror(req, status);
1516 0 : goto out;
1517 : }
1518 :
1519 739 : if (file_set_dosmode(conn, smb_fname, mode, NULL,
1520 : false) != 0) {
1521 0 : reply_nterror(req, map_nt_error_from_unix(errno));
1522 0 : goto out;
1523 : }
1524 : }
1525 :
1526 1479 : ft.mtime = time_t_to_full_timespec(mtime);
1527 :
1528 1479 : status = smb_set_file_time(conn, smb_fname->fsp, smb_fname, &ft, true);
1529 1479 : if (!NT_STATUS_IS_OK(status)) {
1530 0 : reply_nterror(req, status);
1531 0 : goto out;
1532 : }
1533 :
1534 1479 : reply_outbuf(req, 0, 0);
1535 :
1536 1479 : DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1537 : mode));
1538 2169 : out:
1539 2169 : TALLOC_FREE(smb_fname);
1540 2169 : END_PROFILE(SMBsetatr);
1541 2169 : return;
1542 : }
1543 :
1544 : /****************************************************************************
1545 : Reply to a dskattr.
1546 : ****************************************************************************/
1547 :
1548 0 : void reply_dskattr(struct smb_request *req)
1549 : {
1550 0 : connection_struct *conn = req->conn;
1551 : uint64_t ret;
1552 : uint64_t dfree,dsize,bsize;
1553 : struct smb_filename smb_fname;
1554 0 : START_PROFILE(SMBdskattr);
1555 :
1556 0 : ZERO_STRUCT(smb_fname);
1557 0 : smb_fname.base_name = discard_const_p(char, ".");
1558 :
1559 0 : if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1560 0 : reply_nterror(req, map_nt_error_from_unix(errno));
1561 0 : DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1562 0 : END_PROFILE(SMBdskattr);
1563 0 : return;
1564 : }
1565 :
1566 0 : ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1567 0 : if (ret == (uint64_t)-1) {
1568 0 : reply_nterror(req, map_nt_error_from_unix(errno));
1569 0 : END_PROFILE(SMBdskattr);
1570 0 : return;
1571 : }
1572 :
1573 : /*
1574 : * Force max to fit in 16 bit fields.
1575 : */
1576 0 : while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1577 0 : dfree /= 2;
1578 0 : dsize /= 2;
1579 0 : bsize *= 2;
1580 0 : if (bsize > (WORDMAX*512)) {
1581 0 : bsize = (WORDMAX*512);
1582 0 : if (dsize > WORDMAX)
1583 0 : dsize = WORDMAX;
1584 0 : if (dfree > WORDMAX)
1585 0 : dfree = WORDMAX;
1586 0 : break;
1587 : }
1588 : }
1589 :
1590 0 : reply_outbuf(req, 5, 0);
1591 :
1592 0 : if (get_Protocol() <= PROTOCOL_LANMAN2) {
1593 : double total_space, free_space;
1594 : /* we need to scale this to a number that DOS6 can handle. We
1595 : use floating point so we can handle large drives on systems
1596 : that don't have 64 bit integers
1597 :
1598 : we end up displaying a maximum of 2G to DOS systems
1599 : */
1600 0 : total_space = dsize * (double)bsize;
1601 0 : free_space = dfree * (double)bsize;
1602 :
1603 0 : dsize = (uint64_t)((total_space+63*512) / (64*512));
1604 0 : dfree = (uint64_t)((free_space+63*512) / (64*512));
1605 :
1606 0 : if (dsize > 0xFFFF) dsize = 0xFFFF;
1607 0 : if (dfree > 0xFFFF) dfree = 0xFFFF;
1608 :
1609 0 : SSVAL(req->outbuf,smb_vwv0,dsize);
1610 0 : SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1611 0 : SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1612 0 : SSVAL(req->outbuf,smb_vwv3,dfree);
1613 : } else {
1614 0 : SSVAL(req->outbuf,smb_vwv0,dsize);
1615 0 : SSVAL(req->outbuf,smb_vwv1,bsize/512);
1616 0 : SSVAL(req->outbuf,smb_vwv2,512);
1617 0 : SSVAL(req->outbuf,smb_vwv3,dfree);
1618 : }
1619 :
1620 0 : DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1621 :
1622 0 : END_PROFILE(SMBdskattr);
1623 0 : return;
1624 : }
1625 :
1626 : /*
1627 : * Utility function to split the filename from the directory.
1628 : */
1629 20029 : static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1630 : char **fname_dir_out,
1631 : char **fname_mask_out)
1632 : {
1633 20029 : const char *p = NULL;
1634 20029 : char *fname_dir = NULL;
1635 20029 : char *fname_mask = NULL;
1636 :
1637 20029 : p = strrchr_m(fname_in, '/');
1638 20029 : if (!p) {
1639 4611 : fname_dir = talloc_strdup(ctx, ".");
1640 4611 : fname_mask = talloc_strdup(ctx, fname_in);
1641 : } else {
1642 15418 : fname_dir = talloc_strndup(ctx, fname_in,
1643 15418 : PTR_DIFF(p, fname_in));
1644 15418 : fname_mask = talloc_strdup(ctx, p+1);
1645 : }
1646 :
1647 20029 : if (!fname_dir || !fname_mask) {
1648 0 : TALLOC_FREE(fname_dir);
1649 0 : TALLOC_FREE(fname_mask);
1650 0 : return NT_STATUS_NO_MEMORY;
1651 : }
1652 :
1653 20029 : *fname_dir_out = fname_dir;
1654 20029 : *fname_mask_out = fname_mask;
1655 20029 : return NT_STATUS_OK;
1656 : }
1657 :
1658 : /****************************************************************************
1659 : Make a dir struct.
1660 : ****************************************************************************/
1661 :
1662 20594 : static bool make_dir_struct(TALLOC_CTX *ctx,
1663 : char *buf,
1664 : const char *mask,
1665 : const char *fname,
1666 : off_t size,
1667 : uint32_t mode,
1668 : time_t date,
1669 : bool uc)
1670 : {
1671 : char *p;
1672 20594 : char *mask2 = talloc_strdup(ctx, mask);
1673 :
1674 20594 : if (!mask2) {
1675 0 : return False;
1676 : }
1677 :
1678 20594 : if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1679 8016 : size = 0;
1680 : }
1681 :
1682 20594 : memset(buf+1,' ',11);
1683 20594 : if ((p = strchr_m(mask2,'.')) != NULL) {
1684 4578 : *p = 0;
1685 4578 : push_ascii(buf+1,mask2,8, 0);
1686 4578 : push_ascii(buf+9,p+1,3, 0);
1687 4578 : *p = '.';
1688 : } else {
1689 16016 : push_ascii(buf+1,mask2,11, 0);
1690 : }
1691 :
1692 20594 : memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1693 20594 : SCVAL(buf,21,mode);
1694 20594 : srv_put_dos_date(buf,22,date);
1695 20594 : SSVAL(buf,26,size & 0xFFFF);
1696 20594 : SSVAL(buf,28,(size >> 16)&0xFFFF);
1697 : /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1698 : Strange, but verified on W2K3. Needed for OS/2. JRA. */
1699 20594 : push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1700 20594 : DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1701 20594 : return True;
1702 : }
1703 :
1704 : /****************************************************************************
1705 : Reply to a search.
1706 : Can be called from SMBsearch, SMBffirst or SMBfunique.
1707 : ****************************************************************************/
1708 :
1709 496 : void reply_search(struct smb_request *req)
1710 : {
1711 496 : connection_struct *conn = req->conn;
1712 496 : char *path = NULL;
1713 496 : char *mask = NULL;
1714 496 : char *directory = NULL;
1715 496 : struct smb_filename *smb_fname = NULL;
1716 496 : char *fname = NULL;
1717 : off_t size;
1718 : uint32_t mode;
1719 : struct timespec date;
1720 : uint32_t dirtype;
1721 496 : unsigned int numentries = 0;
1722 496 : unsigned int maxentries = 0;
1723 496 : bool finished = False;
1724 : const char *p;
1725 : int status_len;
1726 : char status[21];
1727 496 : int dptr_num= -1;
1728 496 : bool check_descend = False;
1729 496 : bool expect_close = False;
1730 : NTSTATUS nt_status;
1731 496 : bool mask_contains_wcard = False;
1732 496 : bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1733 496 : TALLOC_CTX *ctx = talloc_tos();
1734 496 : bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1735 496 : struct smbXsrv_connection *xconn = req->xconn;
1736 496 : struct smbd_server_connection *sconn = req->sconn;
1737 496 : files_struct *fsp = NULL;
1738 409 : const struct loadparm_substitution *lp_sub =
1739 87 : loadparm_s3_global_substitution();
1740 :
1741 496 : START_PROFILE(SMBsearch);
1742 :
1743 496 : if (req->wct < 2) {
1744 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1745 0 : goto out;
1746 : }
1747 :
1748 496 : if (req->posix_pathnames) {
1749 0 : reply_unknown_new(req, req->cmd);
1750 0 : goto out;
1751 : }
1752 :
1753 : /* If we were called as SMBffirst then we must expect close. */
1754 496 : if(req->cmd == SMBffirst) {
1755 12 : expect_close = True;
1756 : }
1757 :
1758 496 : reply_outbuf(req, 1, 3);
1759 496 : maxentries = SVAL(req->vwv+0, 0);
1760 496 : dirtype = SVAL(req->vwv+1, 0);
1761 496 : p = (const char *)req->buf + 1;
1762 496 : p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
1763 : &nt_status);
1764 496 : if (!NT_STATUS_IS_OK(nt_status)) {
1765 0 : reply_nterror(req, nt_status);
1766 0 : goto out;
1767 : }
1768 :
1769 496 : if (smbreq_bufrem(req, p) < 3) {
1770 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1771 0 : goto out;
1772 : }
1773 :
1774 496 : p++;
1775 496 : status_len = SVAL(p, 0);
1776 496 : p += 2;
1777 :
1778 : /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1779 :
1780 496 : if (status_len == 0) {
1781 : int ret;
1782 174 : struct smb_filename *smb_dname = NULL;
1783 174 : uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1784 174 : ucf_flags_from_smb_request(req);
1785 174 : nt_status = filename_convert(ctx, conn,
1786 : path,
1787 : ucf_flags,
1788 : 0,
1789 : &smb_fname);
1790 174 : if (!NT_STATUS_IS_OK(nt_status)) {
1791 0 : if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1792 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1793 : ERRSRV, ERRbadpath);
1794 0 : goto out;
1795 : }
1796 0 : reply_nterror(req, nt_status);
1797 0 : goto out;
1798 : }
1799 :
1800 174 : directory = smb_fname->base_name;
1801 :
1802 174 : p = strrchr_m(directory,'/');
1803 174 : if ((p != NULL) && (*directory != '/')) {
1804 138 : mask = talloc_strdup(ctx, p + 1);
1805 138 : directory = talloc_strndup(ctx, directory,
1806 138 : PTR_DIFF(p, directory));
1807 : } else {
1808 36 : mask = talloc_strdup(ctx, directory);
1809 36 : directory = talloc_strdup(ctx,".");
1810 : }
1811 :
1812 174 : if (!directory) {
1813 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1814 0 : goto out;
1815 : }
1816 :
1817 174 : memset((char *)status,'\0',21);
1818 174 : SCVAL(status,0,(dirtype & 0x1F));
1819 :
1820 318 : smb_dname = synthetic_smb_fname(talloc_tos(),
1821 : directory,
1822 : NULL,
1823 : NULL,
1824 174 : smb_fname->twrp,
1825 174 : smb_fname->flags);
1826 174 : if (smb_dname == NULL) {
1827 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1828 0 : goto out;
1829 : }
1830 :
1831 : /*
1832 : * As we've cut off the last component from
1833 : * smb_fname we need to re-stat smb_dname
1834 : * so FILE_OPEN disposition knows the directory
1835 : * exists.
1836 : */
1837 174 : ret = vfs_stat(conn, smb_dname);
1838 174 : if (ret == -1) {
1839 0 : nt_status = map_nt_error_from_unix(errno);
1840 0 : reply_nterror(req, nt_status);
1841 0 : goto out;
1842 : }
1843 :
1844 174 : nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
1845 174 : if (!NT_STATUS_IS_OK(nt_status)) {
1846 0 : reply_nterror(req, nt_status);
1847 0 : goto out;
1848 : }
1849 :
1850 : /*
1851 : * Open an fsp on this directory for the dptr.
1852 : */
1853 174 : nt_status = SMB_VFS_CREATE_FILE(
1854 : conn, /* conn */
1855 : req, /* req */
1856 : smb_dname, /* dname */
1857 : FILE_LIST_DIRECTORY, /* access_mask */
1858 : FILE_SHARE_READ|
1859 : FILE_SHARE_WRITE, /* share_access */
1860 : FILE_OPEN, /* create_disposition*/
1861 : FILE_DIRECTORY_FILE, /* create_options */
1862 : FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1863 : NO_OPLOCK, /* oplock_request */
1864 : NULL, /* lease */
1865 : 0, /* allocation_size */
1866 : 0, /* private_flags */
1867 : NULL, /* sd */
1868 : NULL, /* ea_list */
1869 : &fsp, /* result */
1870 : NULL, /* pinfo */
1871 : NULL, /* in_context */
1872 : NULL);/* out_context */
1873 :
1874 174 : if (!NT_STATUS_IS_OK(nt_status)) {
1875 0 : DBG_ERR("failed to open directory %s\n",
1876 : smb_fname_str_dbg(smb_dname));
1877 0 : reply_nterror(req, nt_status);
1878 0 : goto out;
1879 : }
1880 :
1881 318 : nt_status = dptr_create(conn,
1882 : NULL, /* req */
1883 : fsp, /* fsp */
1884 : True,
1885 : expect_close,
1886 174 : req->smbpid,
1887 : mask,
1888 : dirtype,
1889 174 : &fsp->dptr);
1890 :
1891 174 : TALLOC_FREE(smb_dname);
1892 :
1893 174 : if (!NT_STATUS_IS_OK(nt_status)) {
1894 : /*
1895 : * Use NULL here for the first parameter (req)
1896 : * as this is not a client visible handle so
1897 : * can'tbe part of an SMB1 chain.
1898 : */
1899 0 : close_file(NULL, fsp, NORMAL_CLOSE);
1900 0 : fsp = NULL;
1901 0 : reply_nterror(req, nt_status);
1902 0 : goto out;
1903 : }
1904 :
1905 174 : dptr_num = dptr_dnum(fsp->dptr);
1906 :
1907 : } else {
1908 : int status_dirtype;
1909 : const char *dirpath;
1910 :
1911 322 : if (smbreq_bufrem(req, p) < 21) {
1912 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1913 0 : goto out;
1914 : }
1915 :
1916 322 : memcpy(status,p,21);
1917 322 : status_dirtype = CVAL(status,0) & 0x1F;
1918 322 : if (status_dirtype != (dirtype & 0x1F)) {
1919 0 : dirtype = status_dirtype;
1920 : }
1921 :
1922 322 : fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
1923 322 : if (fsp == NULL) {
1924 0 : goto SearchEmpty;
1925 : }
1926 322 : dirpath = dptr_path(sconn, dptr_num);
1927 322 : directory = talloc_strdup(ctx, dirpath);
1928 322 : if (!directory) {
1929 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1930 0 : goto out;
1931 : }
1932 :
1933 322 : mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1934 322 : if (!mask) {
1935 0 : goto SearchEmpty;
1936 : }
1937 322 : dirtype = dptr_attr(sconn, dptr_num);
1938 : }
1939 :
1940 496 : mask_contains_wcard = dptr_has_wild(fsp->dptr);
1941 :
1942 496 : DEBUG(4,("dptr_num is %d\n",dptr_num));
1943 :
1944 496 : if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1945 : char buf[DIR_STRUCT_SIZE];
1946 0 : memcpy(buf,status,21);
1947 0 : if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1948 0 : 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1949 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1950 0 : goto out;
1951 : }
1952 0 : dptr_fill(sconn, buf+12,dptr_num);
1953 0 : if (dptr_zero(buf+12) && (status_len==0)) {
1954 0 : numentries = 1;
1955 : } else {
1956 0 : numentries = 0;
1957 : }
1958 0 : if (message_push_blob(&req->outbuf,
1959 : data_blob_const(buf, sizeof(buf)))
1960 : == -1) {
1961 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
1962 0 : goto out;
1963 : }
1964 : } else {
1965 : unsigned int i;
1966 496 : size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1967 496 : size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1968 :
1969 496 : maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1970 :
1971 496 : DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1972 : directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
1973 496 : if (in_list(directory, lp_dont_descend(ctx, lp_sub, SNUM(conn)),True)) {
1974 0 : check_descend = True;
1975 : }
1976 :
1977 37016 : for (i=numentries;(i<maxentries) && !finished;i++) {
1978 57138 : finished = !get_dir_entry(ctx,
1979 20638 : fsp->dptr,
1980 : mask,
1981 : dirtype,
1982 : &fname,
1983 : &size,
1984 : &mode,
1985 : &date,
1986 : check_descend,
1987 20638 : ask_sharemode);
1988 20638 : if (!finished) {
1989 : char buf[DIR_STRUCT_SIZE];
1990 20594 : memcpy(buf,status,21);
1991 20594 : if (!make_dir_struct(ctx,
1992 : buf,
1993 : mask,
1994 : fname,
1995 : size,
1996 : mode,
1997 : convert_timespec_to_time_t(date),
1998 20594 : !allow_long_path_components)) {
1999 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2000 0 : goto out;
2001 : }
2002 20594 : if (!dptr_fill(sconn, buf+12,dptr_num)) {
2003 0 : break;
2004 : }
2005 20594 : if (message_push_blob(&req->outbuf,
2006 : data_blob_const(buf, sizeof(buf)))
2007 : == -1) {
2008 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2009 0 : goto out;
2010 : }
2011 20594 : numentries++;
2012 : }
2013 : }
2014 : }
2015 :
2016 496 : SearchEmpty:
2017 :
2018 : /* If we were called as SMBffirst with smb_search_id == NULL
2019 : and no entries were found then return error and close fsp->dptr
2020 : (X/Open spec) */
2021 :
2022 496 : if (numentries == 0) {
2023 36 : dptr_num = -1;
2024 36 : if (fsp != NULL) {
2025 36 : close_file(NULL, fsp, NORMAL_CLOSE);
2026 36 : fsp = NULL;
2027 : }
2028 460 : } else if(expect_close && status_len == 0) {
2029 : /* Close the dptr - we know it's gone */
2030 6 : dptr_num = -1;
2031 6 : if (fsp != NULL) {
2032 6 : close_file(NULL, fsp, NORMAL_CLOSE);
2033 6 : fsp = NULL;
2034 : }
2035 : }
2036 :
2037 : /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
2038 496 : if(dptr_num >= 0 && req->cmd == SMBfunique) {
2039 6 : dptr_num = -1;
2040 : /* fsp may have been closed above. */
2041 6 : if (fsp != NULL) {
2042 6 : close_file(NULL, fsp, NORMAL_CLOSE);
2043 6 : fsp = NULL;
2044 : }
2045 : }
2046 :
2047 496 : if ((numentries == 0) && !mask_contains_wcard) {
2048 18 : reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
2049 18 : goto out;
2050 : }
2051 :
2052 478 : SSVAL(req->outbuf,smb_vwv0,numentries);
2053 478 : SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2054 478 : SCVAL(smb_buf(req->outbuf),0,5);
2055 478 : SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2056 :
2057 : /* The replies here are never long name. */
2058 478 : SSVAL(req->outbuf, smb_flg2,
2059 : SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2060 478 : if (!allow_long_path_components) {
2061 0 : SSVAL(req->outbuf, smb_flg2,
2062 : SVAL(req->outbuf, smb_flg2)
2063 : & (~FLAGS2_LONG_PATH_COMPONENTS));
2064 : }
2065 :
2066 : /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2067 478 : SSVAL(req->outbuf, smb_flg2,
2068 : (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2069 :
2070 478 : DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2071 : smb_fn_name(req->cmd),
2072 : mask,
2073 : directory,
2074 : dirtype,
2075 : numentries,
2076 : maxentries ));
2077 496 : out:
2078 496 : TALLOC_FREE(directory);
2079 496 : TALLOC_FREE(mask);
2080 496 : TALLOC_FREE(smb_fname);
2081 496 : END_PROFILE(SMBsearch);
2082 496 : return;
2083 : }
2084 :
2085 : /****************************************************************************
2086 : Reply to a fclose (stop directory search).
2087 : ****************************************************************************/
2088 :
2089 6 : void reply_fclose(struct smb_request *req)
2090 : {
2091 : int status_len;
2092 : char status[21];
2093 6 : int dptr_num= -2;
2094 : const char *p;
2095 6 : char *path = NULL;
2096 : NTSTATUS err;
2097 6 : TALLOC_CTX *ctx = talloc_tos();
2098 6 : struct smbd_server_connection *sconn = req->sconn;
2099 6 : files_struct *fsp = NULL;
2100 :
2101 6 : START_PROFILE(SMBfclose);
2102 :
2103 6 : if (req->posix_pathnames) {
2104 0 : reply_unknown_new(req, req->cmd);
2105 0 : END_PROFILE(SMBfclose);
2106 0 : return;
2107 : }
2108 :
2109 6 : p = (const char *)req->buf + 1;
2110 6 : p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
2111 : &err);
2112 6 : if (!NT_STATUS_IS_OK(err)) {
2113 0 : reply_nterror(req, err);
2114 0 : END_PROFILE(SMBfclose);
2115 0 : return;
2116 : }
2117 :
2118 6 : if (smbreq_bufrem(req, p) < 3) {
2119 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2120 0 : END_PROFILE(SMBfclose);
2121 0 : return;
2122 : }
2123 :
2124 6 : p++;
2125 6 : status_len = SVAL(p,0);
2126 6 : p += 2;
2127 :
2128 6 : if (status_len == 0) {
2129 0 : reply_force_doserror(req, ERRSRV, ERRsrverror);
2130 0 : END_PROFILE(SMBfclose);
2131 0 : return;
2132 : }
2133 :
2134 6 : if (smbreq_bufrem(req, p) < 21) {
2135 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2136 0 : END_PROFILE(SMBfclose);
2137 0 : return;
2138 : }
2139 :
2140 6 : memcpy(status,p,21);
2141 :
2142 6 : fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
2143 6 : if(fsp != NULL) {
2144 : /* Close the file - we know it's gone */
2145 0 : close_file(NULL, fsp, NORMAL_CLOSE);
2146 0 : fsp = NULL;
2147 0 : dptr_num = -1;
2148 : }
2149 :
2150 6 : reply_outbuf(req, 1, 0);
2151 6 : SSVAL(req->outbuf,smb_vwv0,0);
2152 :
2153 6 : DEBUG(3,("search close\n"));
2154 :
2155 6 : END_PROFILE(SMBfclose);
2156 6 : return;
2157 : }
2158 :
2159 : /****************************************************************************
2160 : Reply to an open.
2161 : ****************************************************************************/
2162 :
2163 55 : void reply_open(struct smb_request *req)
2164 : {
2165 55 : connection_struct *conn = req->conn;
2166 55 : struct smb_filename *smb_fname = NULL;
2167 55 : char *fname = NULL;
2168 55 : uint32_t fattr=0;
2169 55 : off_t size = 0;
2170 55 : time_t mtime=0;
2171 : int info;
2172 : files_struct *fsp;
2173 : int oplock_request;
2174 : int deny_mode;
2175 : uint32_t dos_attr;
2176 : uint32_t access_mask;
2177 : uint32_t share_mode;
2178 : uint32_t create_disposition;
2179 55 : uint32_t create_options = 0;
2180 55 : uint32_t private_flags = 0;
2181 : NTSTATUS status;
2182 : uint32_t ucf_flags;
2183 55 : TALLOC_CTX *ctx = talloc_tos();
2184 :
2185 55 : START_PROFILE(SMBopen);
2186 :
2187 55 : if (req->wct < 2) {
2188 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2189 0 : goto out;
2190 : }
2191 :
2192 55 : oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2193 55 : deny_mode = SVAL(req->vwv+0, 0);
2194 55 : dos_attr = SVAL(req->vwv+1, 0);
2195 :
2196 55 : srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2197 : STR_TERMINATE, &status);
2198 55 : if (!NT_STATUS_IS_OK(status)) {
2199 0 : reply_nterror(req, status);
2200 0 : goto out;
2201 : }
2202 :
2203 55 : if (!map_open_params_to_ntcreate(fname, deny_mode,
2204 : OPENX_FILE_EXISTS_OPEN, &access_mask,
2205 : &share_mode, &create_disposition,
2206 : &create_options, &private_flags)) {
2207 0 : reply_force_doserror(req, ERRDOS, ERRbadaccess);
2208 0 : goto out;
2209 : }
2210 :
2211 55 : ucf_flags = filename_create_ucf_flags(req, create_disposition);
2212 :
2213 55 : status = filename_convert(ctx,
2214 : conn,
2215 : fname,
2216 : ucf_flags,
2217 : 0,
2218 : &smb_fname);
2219 55 : if (!NT_STATUS_IS_OK(status)) {
2220 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2221 0 : reply_botherror(req,
2222 : NT_STATUS_PATH_NOT_COVERED,
2223 : ERRSRV, ERRbadpath);
2224 0 : goto out;
2225 : }
2226 0 : reply_nterror(req, status);
2227 0 : goto out;
2228 : }
2229 :
2230 55 : status = SMB_VFS_CREATE_FILE(
2231 : conn, /* conn */
2232 : req, /* req */
2233 : smb_fname, /* fname */
2234 : access_mask, /* access_mask */
2235 : share_mode, /* share_access */
2236 : create_disposition, /* create_disposition*/
2237 : create_options, /* create_options */
2238 : dos_attr, /* file_attributes */
2239 : oplock_request, /* oplock_request */
2240 : NULL, /* lease */
2241 : 0, /* allocation_size */
2242 : private_flags,
2243 : NULL, /* sd */
2244 : NULL, /* ea_list */
2245 : &fsp, /* result */
2246 : &info, /* pinfo */
2247 : NULL, NULL); /* create context */
2248 :
2249 55 : if (!NT_STATUS_IS_OK(status)) {
2250 20 : if (open_was_deferred(req->xconn, req->mid)) {
2251 : /* We have re-scheduled this call. */
2252 0 : goto out;
2253 : }
2254 :
2255 20 : if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2256 5 : reply_openerror(req, status);
2257 5 : goto out;
2258 : }
2259 :
2260 15 : fsp = fcb_or_dos_open(
2261 : req,
2262 : smb_fname,
2263 : access_mask,
2264 : create_options,
2265 : private_flags);
2266 15 : if (fsp == NULL) {
2267 10 : bool ok = defer_smb1_sharing_violation(req);
2268 10 : if (ok) {
2269 4 : goto out;
2270 : }
2271 5 : reply_openerror(req, status);
2272 5 : goto out;
2273 : }
2274 : }
2275 :
2276 : /* Ensure we're pointing at the correct stat struct. */
2277 40 : TALLOC_FREE(smb_fname);
2278 40 : smb_fname = fsp->fsp_name;
2279 :
2280 40 : size = smb_fname->st.st_ex_size;
2281 40 : fattr = fdos_mode(fsp);
2282 :
2283 40 : mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2284 :
2285 40 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2286 0 : DEBUG(3,("attempt to open a directory %s\n",
2287 : fsp_str_dbg(fsp)));
2288 0 : close_file(req, fsp, ERROR_CLOSE);
2289 0 : reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2290 : ERRDOS, ERRnoaccess);
2291 0 : goto out;
2292 : }
2293 :
2294 40 : reply_outbuf(req, 7, 0);
2295 40 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2296 40 : SSVAL(req->outbuf,smb_vwv1,fattr);
2297 40 : if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2298 0 : srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2299 : } else {
2300 40 : srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2301 : }
2302 40 : SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2303 40 : SSVAL(req->outbuf,smb_vwv6,deny_mode);
2304 :
2305 40 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2306 0 : SCVAL(req->outbuf,smb_flg,
2307 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2308 : }
2309 :
2310 40 : if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2311 0 : SCVAL(req->outbuf,smb_flg,
2312 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2313 : }
2314 85 : out:
2315 55 : END_PROFILE(SMBopen);
2316 55 : return;
2317 : }
2318 :
2319 : /****************************************************************************
2320 : Reply to an open and X.
2321 : ****************************************************************************/
2322 :
2323 23332 : void reply_open_and_X(struct smb_request *req)
2324 : {
2325 23332 : connection_struct *conn = req->conn;
2326 23332 : struct smb_filename *smb_fname = NULL;
2327 23332 : char *fname = NULL;
2328 : uint16_t open_flags;
2329 : int deny_mode;
2330 : uint32_t smb_attr;
2331 : /* Breakout the oplock request bits so we can set the
2332 : reply bits separately. */
2333 : int ex_oplock_request;
2334 : int core_oplock_request;
2335 : int oplock_request;
2336 : #if 0
2337 : int smb_sattr = SVAL(req->vwv+4, 0);
2338 : uint32_t smb_time = make_unix_date3(req->vwv+6);
2339 : #endif
2340 : int smb_ofun;
2341 23332 : uint32_t fattr=0;
2342 23332 : int mtime=0;
2343 23332 : int smb_action = 0;
2344 : files_struct *fsp;
2345 : NTSTATUS status;
2346 : uint64_t allocation_size;
2347 23332 : ssize_t retval = -1;
2348 : uint32_t access_mask;
2349 : uint32_t share_mode;
2350 : uint32_t create_disposition;
2351 23332 : uint32_t create_options = 0;
2352 23332 : uint32_t private_flags = 0;
2353 : uint32_t ucf_flags;
2354 23332 : TALLOC_CTX *ctx = talloc_tos();
2355 :
2356 23332 : START_PROFILE(SMBopenX);
2357 :
2358 23332 : if (req->wct < 15) {
2359 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2360 0 : goto out;
2361 : }
2362 :
2363 23332 : open_flags = SVAL(req->vwv+2, 0);
2364 23332 : deny_mode = SVAL(req->vwv+3, 0);
2365 23332 : smb_attr = SVAL(req->vwv+5, 0);
2366 23332 : ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2367 23332 : core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2368 23332 : oplock_request = ex_oplock_request | core_oplock_request;
2369 23332 : smb_ofun = SVAL(req->vwv+8, 0);
2370 23332 : allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2371 :
2372 : /* If it's an IPC, pass off the pipe handler. */
2373 23332 : if (IS_IPC(conn)) {
2374 40 : if (lp_nt_pipe_support()) {
2375 40 : reply_open_pipe_and_X(conn, req);
2376 : } else {
2377 0 : reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2378 : }
2379 40 : goto out;
2380 : }
2381 :
2382 : /* XXXX we need to handle passed times, sattr and flags */
2383 23292 : srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2384 : STR_TERMINATE, &status);
2385 23292 : if (!NT_STATUS_IS_OK(status)) {
2386 32 : reply_nterror(req, status);
2387 32 : goto out;
2388 : }
2389 :
2390 23260 : if (!map_open_params_to_ntcreate(fname, deny_mode,
2391 : smb_ofun,
2392 : &access_mask, &share_mode,
2393 : &create_disposition,
2394 : &create_options,
2395 : &private_flags)) {
2396 18 : reply_force_doserror(req, ERRDOS, ERRbadaccess);
2397 18 : goto out;
2398 : }
2399 :
2400 23242 : ucf_flags = filename_create_ucf_flags(req, create_disposition);
2401 :
2402 23242 : status = filename_convert(ctx,
2403 : conn,
2404 : fname,
2405 : ucf_flags,
2406 : 0,
2407 : &smb_fname);
2408 23242 : if (!NT_STATUS_IS_OK(status)) {
2409 40 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2410 0 : reply_botherror(req,
2411 : NT_STATUS_PATH_NOT_COVERED,
2412 : ERRSRV, ERRbadpath);
2413 0 : goto out;
2414 : }
2415 40 : reply_nterror(req, status);
2416 40 : goto out;
2417 : }
2418 :
2419 23202 : status = SMB_VFS_CREATE_FILE(
2420 : conn, /* conn */
2421 : req, /* req */
2422 : smb_fname, /* fname */
2423 : access_mask, /* access_mask */
2424 : share_mode, /* share_access */
2425 : create_disposition, /* create_disposition*/
2426 : create_options, /* create_options */
2427 : smb_attr, /* file_attributes */
2428 : oplock_request, /* oplock_request */
2429 : NULL, /* lease */
2430 : 0, /* allocation_size */
2431 : private_flags,
2432 : NULL, /* sd */
2433 : NULL, /* ea_list */
2434 : &fsp, /* result */
2435 : &smb_action, /* pinfo */
2436 : NULL, NULL); /* create context */
2437 :
2438 23202 : if (!NT_STATUS_IS_OK(status)) {
2439 4609 : if (open_was_deferred(req->xconn, req->mid)) {
2440 : /* We have re-scheduled this call. */
2441 24 : goto out;
2442 : }
2443 :
2444 4585 : if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2445 185 : reply_openerror(req, status);
2446 185 : goto out;
2447 : }
2448 :
2449 4400 : fsp = fcb_or_dos_open(
2450 : req,
2451 : smb_fname,
2452 : access_mask,
2453 : create_options,
2454 : private_flags);
2455 4400 : if (fsp == NULL) {
2456 4292 : bool ok = defer_smb1_sharing_violation(req);
2457 4292 : if (ok) {
2458 2144 : goto out;
2459 : }
2460 2146 : reply_openerror(req, status);
2461 2146 : goto out;
2462 : }
2463 :
2464 :
2465 108 : smb_action = FILE_WAS_OPENED;
2466 : }
2467 :
2468 : /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2469 : if the file is truncated or created. */
2470 18701 : if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2471 44 : fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2472 44 : if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2473 0 : close_file(req, fsp, ERROR_CLOSE);
2474 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
2475 0 : goto out;
2476 : }
2477 44 : retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2478 44 : if (retval < 0) {
2479 0 : close_file(req, fsp, ERROR_CLOSE);
2480 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
2481 0 : goto out;
2482 : }
2483 44 : status = vfs_stat_fsp(fsp);
2484 44 : if (!NT_STATUS_IS_OK(status)) {
2485 0 : close_file(req, fsp, ERROR_CLOSE);
2486 0 : reply_nterror(req, status);
2487 0 : goto out;
2488 : }
2489 : }
2490 :
2491 18701 : fattr = fdos_mode(fsp);
2492 18701 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2493 0 : close_file(req, fsp, ERROR_CLOSE);
2494 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2495 0 : goto out;
2496 : }
2497 18701 : mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2498 :
2499 : /* If the caller set the extended oplock request bit
2500 : and we granted one (by whatever means) - set the
2501 : correct bit for extended oplock reply.
2502 : */
2503 :
2504 18701 : if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2505 0 : smb_action |= EXTENDED_OPLOCK_GRANTED;
2506 : }
2507 :
2508 18701 : if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2509 16 : smb_action |= EXTENDED_OPLOCK_GRANTED;
2510 : }
2511 :
2512 : /* If the caller set the core oplock request bit
2513 : and we granted one (by whatever means) - set the
2514 : correct bit for core oplock reply.
2515 : */
2516 :
2517 18701 : if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2518 5 : reply_outbuf(req, 19, 0);
2519 : } else {
2520 18696 : reply_outbuf(req, 15, 0);
2521 : }
2522 :
2523 18701 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2524 18701 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2525 :
2526 18701 : if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2527 0 : SCVAL(req->outbuf, smb_flg,
2528 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2529 : }
2530 :
2531 18701 : if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2532 16 : SCVAL(req->outbuf, smb_flg,
2533 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2534 : }
2535 :
2536 18701 : SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2537 18701 : SSVAL(req->outbuf,smb_vwv3,fattr);
2538 18701 : if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2539 0 : srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2540 : } else {
2541 18701 : srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2542 : }
2543 18701 : SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2544 18701 : SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2545 18701 : SSVAL(req->outbuf,smb_vwv11,smb_action);
2546 :
2547 18701 : if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2548 5 : SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2549 : }
2550 :
2551 39631 : out:
2552 23332 : TALLOC_FREE(smb_fname);
2553 23332 : END_PROFILE(SMBopenX);
2554 23332 : return;
2555 : }
2556 :
2557 : /****************************************************************************
2558 : Reply to a SMBulogoffX.
2559 : ****************************************************************************/
2560 :
2561 : static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2562 : struct smbXsrv_session *session);
2563 : static void reply_ulogoffX_done(struct tevent_req *req);
2564 :
2565 12 : void reply_ulogoffX(struct smb_request *smb1req)
2566 : {
2567 12 : struct timeval now = timeval_current();
2568 12 : struct smbXsrv_session *session = NULL;
2569 : struct tevent_req *req;
2570 : NTSTATUS status;
2571 :
2572 : /*
2573 : * Don't setup the profile charge here, take
2574 : * it in reply_ulogoffX_done(). Not strictly correct
2575 : * but better than the other SMB1 async
2576 : * code that double-charges at the moment.
2577 : */
2578 :
2579 23 : status = smb1srv_session_lookup(smb1req->xconn,
2580 12 : smb1req->vuid,
2581 : timeval_to_nttime(&now),
2582 : &session);
2583 12 : if (!NT_STATUS_IS_OK(status)) {
2584 : /* Not going async, profile here. */
2585 0 : START_PROFILE(SMBulogoffX);
2586 0 : DBG_WARNING("ulogoff, vuser id %llu does not map to user.\n",
2587 : (unsigned long long)smb1req->vuid);
2588 :
2589 0 : smb1req->vuid = UID_FIELD_INVALID;
2590 0 : reply_force_doserror(smb1req, ERRSRV, ERRbaduid);
2591 0 : END_PROFILE(SMBulogoffX);
2592 0 : return;
2593 : }
2594 :
2595 12 : req = reply_ulogoffX_send(smb1req, session);
2596 12 : if (req == NULL) {
2597 : /* Not going async, profile here. */
2598 0 : START_PROFILE(SMBulogoffX);
2599 0 : reply_force_doserror(smb1req, ERRDOS, ERRnomem);
2600 0 : END_PROFILE(SMBulogoffX);
2601 0 : return;
2602 : }
2603 :
2604 : /* We're async. This will complete later. */
2605 12 : tevent_req_set_callback(req, reply_ulogoffX_done, smb1req);
2606 12 : return;
2607 : }
2608 :
2609 : struct reply_ulogoffX_state {
2610 : struct tevent_queue *wait_queue;
2611 : struct smbXsrv_session *session;
2612 : };
2613 :
2614 : static void reply_ulogoffX_wait_done(struct tevent_req *subreq);
2615 :
2616 : /****************************************************************************
2617 : Async SMB1 ulogoffX.
2618 : Note, on failure here we deallocate and return NULL to allow the caller to
2619 : SMB1 return an error of ERRnomem immediately.
2620 : ****************************************************************************/
2621 :
2622 12 : static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2623 : struct smbXsrv_session *session)
2624 : {
2625 : struct tevent_req *req;
2626 : struct reply_ulogoffX_state *state;
2627 : struct tevent_req *subreq;
2628 : files_struct *fsp;
2629 12 : struct smbd_server_connection *sconn = session->client->sconn;
2630 12 : uint64_t vuid = session->global->session_wire_id;
2631 :
2632 12 : req = tevent_req_create(smb1req, &state,
2633 : struct reply_ulogoffX_state);
2634 12 : if (req == NULL) {
2635 0 : return NULL;
2636 : }
2637 12 : state->wait_queue = tevent_queue_create(state,
2638 : "reply_ulogoffX_wait_queue");
2639 12 : if (tevent_req_nomem(state->wait_queue, req)) {
2640 0 : TALLOC_FREE(req);
2641 0 : return NULL;
2642 : }
2643 12 : state->session = session;
2644 :
2645 : /*
2646 : * Make sure that no new request will be able to use this session.
2647 : * This ensures that once all outstanding fsp->aio_requests
2648 : * on this session are done, we are safe to close it.
2649 : */
2650 12 : session->status = NT_STATUS_USER_SESSION_DELETED;
2651 :
2652 20 : for (fsp = sconn->files; fsp; fsp = fsp->next) {
2653 8 : if (fsp->vuid != vuid) {
2654 0 : continue;
2655 : }
2656 : /*
2657 : * Flag the file as close in progress.
2658 : * This will prevent any more IO being
2659 : * done on it.
2660 : */
2661 8 : fsp->fsp_flags.closing = true;
2662 :
2663 8 : if (fsp->num_aio_requests > 0) {
2664 : /*
2665 : * Now wait until all aio requests on this fsp are
2666 : * finished.
2667 : *
2668 : * We don't set a callback, as we just want to block the
2669 : * wait queue and the talloc_free() of fsp->aio_request
2670 : * will remove the item from the wait queue.
2671 : */
2672 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
2673 : sconn->ev_ctx,
2674 0 : state->wait_queue);
2675 0 : if (tevent_req_nomem(subreq, req)) {
2676 0 : TALLOC_FREE(req);
2677 0 : return NULL;
2678 : }
2679 : }
2680 : }
2681 :
2682 : /*
2683 : * Now we add our own waiter to the end of the queue,
2684 : * this way we get notified when all pending requests are finished
2685 : * and reply to the outstanding SMB1 request.
2686 : */
2687 12 : subreq = tevent_queue_wait_send(state,
2688 : sconn->ev_ctx,
2689 12 : state->wait_queue);
2690 12 : if (tevent_req_nomem(subreq, req)) {
2691 0 : TALLOC_FREE(req);
2692 0 : return NULL;
2693 : }
2694 :
2695 : /*
2696 : * We're really going async - move the SMB1 request from
2697 : * a talloc stackframe above us to the sconn talloc-context.
2698 : * We need this to stick around until the wait_done
2699 : * callback is invoked.
2700 : */
2701 12 : smb1req = talloc_move(sconn, &smb1req);
2702 :
2703 12 : tevent_req_set_callback(subreq, reply_ulogoffX_wait_done, req);
2704 :
2705 12 : return req;
2706 : }
2707 :
2708 12 : static void reply_ulogoffX_wait_done(struct tevent_req *subreq)
2709 : {
2710 12 : struct tevent_req *req = tevent_req_callback_data(
2711 : subreq, struct tevent_req);
2712 :
2713 12 : tevent_queue_wait_recv(subreq);
2714 12 : TALLOC_FREE(subreq);
2715 12 : tevent_req_done(req);
2716 12 : }
2717 :
2718 12 : static NTSTATUS reply_ulogoffX_recv(struct tevent_req *req)
2719 : {
2720 12 : return tevent_req_simple_recv_ntstatus(req);
2721 : }
2722 :
2723 12 : static void reply_ulogoffX_done(struct tevent_req *req)
2724 : {
2725 12 : struct smb_request *smb1req = tevent_req_callback_data(
2726 : req, struct smb_request);
2727 12 : struct reply_ulogoffX_state *state = tevent_req_data(req,
2728 : struct reply_ulogoffX_state);
2729 12 : struct smbXsrv_session *session = state->session;
2730 : NTSTATUS status;
2731 :
2732 : /*
2733 : * Take the profile charge here. Not strictly
2734 : * correct but better than the other SMB1 async
2735 : * code that double-charges at the moment.
2736 : */
2737 12 : START_PROFILE(SMBulogoffX);
2738 :
2739 12 : status = reply_ulogoffX_recv(req);
2740 12 : TALLOC_FREE(req);
2741 12 : if (!NT_STATUS_IS_OK(status)) {
2742 0 : TALLOC_FREE(smb1req);
2743 0 : END_PROFILE(SMBulogoffX);
2744 0 : exit_server(__location__ ": reply_ulogoffX_recv failed");
2745 : return;
2746 : }
2747 :
2748 12 : status = smbXsrv_session_logoff(session);
2749 12 : if (!NT_STATUS_IS_OK(status)) {
2750 0 : TALLOC_FREE(smb1req);
2751 0 : END_PROFILE(SMBulogoffX);
2752 0 : exit_server(__location__ ": smbXsrv_session_logoff failed");
2753 : return;
2754 : }
2755 :
2756 12 : TALLOC_FREE(session);
2757 :
2758 12 : reply_outbuf(smb1req, 2, 0);
2759 12 : SSVAL(smb1req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2760 12 : SSVAL(smb1req->outbuf, smb_vwv1, 0); /* no andx offset */
2761 :
2762 12 : DBG_NOTICE("ulogoffX vuid=%llu\n",
2763 : (unsigned long long)smb1req->vuid);
2764 :
2765 12 : smb1req->vuid = UID_FIELD_INVALID;
2766 : /*
2767 : * The following call is needed to push the
2768 : * reply data back out the socket after async
2769 : * return. Plus it frees smb1req.
2770 : */
2771 12 : smb_request_done(smb1req);
2772 12 : END_PROFILE(SMBulogoffX);
2773 11 : }
2774 :
2775 : /****************************************************************************
2776 : Reply to a mknew or a create.
2777 : ****************************************************************************/
2778 :
2779 40 : void reply_mknew(struct smb_request *req)
2780 : {
2781 40 : connection_struct *conn = req->conn;
2782 40 : struct smb_filename *smb_fname = NULL;
2783 40 : char *fname = NULL;
2784 40 : uint32_t fattr = 0;
2785 : struct smb_file_time ft;
2786 : files_struct *fsp;
2787 40 : int oplock_request = 0;
2788 : NTSTATUS status;
2789 40 : uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2790 40 : uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2791 : uint32_t create_disposition;
2792 40 : uint32_t create_options = 0;
2793 : uint32_t ucf_flags;
2794 40 : TALLOC_CTX *ctx = talloc_tos();
2795 :
2796 40 : START_PROFILE(SMBcreate);
2797 40 : init_smb_file_time(&ft);
2798 :
2799 40 : if (req->wct < 3) {
2800 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2801 0 : goto out;
2802 : }
2803 :
2804 40 : fattr = SVAL(req->vwv+0, 0);
2805 40 : oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2806 :
2807 40 : if (req->cmd == SMBmknew) {
2808 : /* We should fail if file exists. */
2809 16 : create_disposition = FILE_CREATE;
2810 : } else {
2811 : /* Create if file doesn't exist, truncate if it does. */
2812 20 : create_disposition = FILE_OVERWRITE_IF;
2813 : }
2814 :
2815 : /* mtime. */
2816 40 : ft.mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+1));
2817 :
2818 40 : srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2819 : STR_TERMINATE, &status);
2820 40 : if (!NT_STATUS_IS_OK(status)) {
2821 0 : reply_nterror(req, status);
2822 0 : goto out;
2823 : }
2824 :
2825 40 : ucf_flags = filename_create_ucf_flags(req, create_disposition);
2826 40 : status = filename_convert(ctx,
2827 : conn,
2828 : fname,
2829 : ucf_flags,
2830 : 0,
2831 : &smb_fname);
2832 40 : if (!NT_STATUS_IS_OK(status)) {
2833 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2834 0 : reply_botherror(req,
2835 : NT_STATUS_PATH_NOT_COVERED,
2836 : ERRSRV, ERRbadpath);
2837 0 : goto out;
2838 : }
2839 0 : reply_nterror(req, status);
2840 0 : goto out;
2841 : }
2842 :
2843 40 : if (fattr & FILE_ATTRIBUTE_VOLUME) {
2844 0 : DEBUG(0,("Attempt to create file (%s) with volid set - "
2845 : "please report this\n",
2846 : smb_fname_str_dbg(smb_fname)));
2847 : }
2848 :
2849 40 : status = SMB_VFS_CREATE_FILE(
2850 : conn, /* conn */
2851 : req, /* req */
2852 : smb_fname, /* fname */
2853 : access_mask, /* access_mask */
2854 : share_mode, /* share_access */
2855 : create_disposition, /* create_disposition*/
2856 : create_options, /* create_options */
2857 : fattr, /* file_attributes */
2858 : oplock_request, /* oplock_request */
2859 : NULL, /* lease */
2860 : 0, /* allocation_size */
2861 : 0, /* private_flags */
2862 : NULL, /* sd */
2863 : NULL, /* ea_list */
2864 : &fsp, /* result */
2865 : NULL, /* pinfo */
2866 : NULL, NULL); /* create context */
2867 :
2868 40 : if (!NT_STATUS_IS_OK(status)) {
2869 5 : if (open_was_deferred(req->xconn, req->mid)) {
2870 : /* We have re-scheduled this call. */
2871 0 : goto out;
2872 : }
2873 5 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2874 0 : bool ok = defer_smb1_sharing_violation(req);
2875 0 : if (ok) {
2876 0 : goto out;
2877 : }
2878 : }
2879 5 : reply_openerror(req, status);
2880 5 : goto out;
2881 : }
2882 :
2883 35 : ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2884 35 : status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2885 35 : if (!NT_STATUS_IS_OK(status)) {
2886 0 : END_PROFILE(SMBcreate);
2887 0 : goto out;
2888 : }
2889 :
2890 35 : reply_outbuf(req, 1, 0);
2891 35 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2892 :
2893 35 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2894 0 : SCVAL(req->outbuf,smb_flg,
2895 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2896 : }
2897 :
2898 35 : if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2899 0 : SCVAL(req->outbuf,smb_flg,
2900 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2901 : }
2902 :
2903 35 : DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2904 35 : DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2905 : smb_fname_str_dbg(smb_fname), fsp_get_io_fd(fsp),
2906 : (unsigned int)fattr));
2907 :
2908 40 : out:
2909 40 : TALLOC_FREE(smb_fname);
2910 40 : END_PROFILE(SMBcreate);
2911 40 : return;
2912 : }
2913 :
2914 : /****************************************************************************
2915 : Reply to a create temporary file.
2916 : ****************************************************************************/
2917 :
2918 14 : void reply_ctemp(struct smb_request *req)
2919 : {
2920 14 : connection_struct *conn = req->conn;
2921 14 : struct smb_filename *smb_fname = NULL;
2922 14 : char *wire_name = NULL;
2923 14 : char *fname = NULL;
2924 : uint32_t fattr;
2925 : files_struct *fsp;
2926 : int oplock_request;
2927 : char *s;
2928 : NTSTATUS status;
2929 : int i;
2930 : uint32_t ucf_flags;
2931 14 : TALLOC_CTX *ctx = talloc_tos();
2932 :
2933 14 : START_PROFILE(SMBctemp);
2934 :
2935 14 : if (req->wct < 3) {
2936 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2937 0 : goto out;
2938 : }
2939 :
2940 14 : fattr = SVAL(req->vwv+0, 0);
2941 14 : oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2942 :
2943 14 : srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2944 : STR_TERMINATE, &status);
2945 14 : if (!NT_STATUS_IS_OK(status)) {
2946 0 : reply_nterror(req, status);
2947 0 : goto out;
2948 : }
2949 :
2950 24 : for (i = 0; i < 10; i++) {
2951 14 : if (*wire_name) {
2952 5 : fname = talloc_asprintf(ctx,
2953 : "%s/TMP%s",
2954 : wire_name,
2955 : generate_random_str_list(ctx, 5, "0123456789"));
2956 : } else {
2957 9 : fname = talloc_asprintf(ctx,
2958 : "TMP%s",
2959 : generate_random_str_list(ctx, 5, "0123456789"));
2960 : }
2961 :
2962 14 : if (!fname) {
2963 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
2964 0 : goto out;
2965 : }
2966 :
2967 14 : ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2968 14 : status = filename_convert(ctx, conn,
2969 : fname,
2970 : ucf_flags,
2971 : 0,
2972 : &smb_fname);
2973 14 : if (!NT_STATUS_IS_OK(status)) {
2974 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2975 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2976 : ERRSRV, ERRbadpath);
2977 0 : goto out;
2978 : }
2979 0 : reply_nterror(req, status);
2980 0 : goto out;
2981 : }
2982 :
2983 : /* Create the file. */
2984 14 : status = SMB_VFS_CREATE_FILE(
2985 : conn, /* conn */
2986 : req, /* req */
2987 : smb_fname, /* fname */
2988 : FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2989 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2990 : FILE_CREATE, /* create_disposition*/
2991 : 0, /* create_options */
2992 : fattr, /* file_attributes */
2993 : oplock_request, /* oplock_request */
2994 : NULL, /* lease */
2995 : 0, /* allocation_size */
2996 : 0, /* private_flags */
2997 : NULL, /* sd */
2998 : NULL, /* ea_list */
2999 : &fsp, /* result */
3000 : NULL, /* pinfo */
3001 : NULL, NULL); /* create context */
3002 :
3003 14 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
3004 0 : TALLOC_FREE(fname);
3005 0 : TALLOC_FREE(smb_fname);
3006 0 : continue;
3007 : }
3008 :
3009 14 : if (!NT_STATUS_IS_OK(status)) {
3010 0 : if (open_was_deferred(req->xconn, req->mid)) {
3011 : /* We have re-scheduled this call. */
3012 0 : goto out;
3013 : }
3014 0 : if (NT_STATUS_EQUAL(
3015 : status, NT_STATUS_SHARING_VIOLATION)) {
3016 0 : bool ok = defer_smb1_sharing_violation(req);
3017 0 : if (ok) {
3018 0 : goto out;
3019 : }
3020 : }
3021 0 : reply_openerror(req, status);
3022 0 : goto out;
3023 : }
3024 :
3025 12 : break;
3026 : }
3027 :
3028 14 : if (i == 10) {
3029 : /* Collision after 10 times... */
3030 0 : reply_nterror(req, status);
3031 0 : goto out;
3032 : }
3033 :
3034 14 : reply_outbuf(req, 1, 0);
3035 14 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
3036 :
3037 : /* the returned filename is relative to the directory */
3038 14 : s = strrchr_m(fsp->fsp_name->base_name, '/');
3039 14 : if (!s) {
3040 9 : s = fsp->fsp_name->base_name;
3041 : } else {
3042 5 : s++;
3043 : }
3044 :
3045 : #if 0
3046 : /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
3047 : thing in the byte section. JRA */
3048 : SSVALS(p, 0, -1); /* what is this? not in spec */
3049 : #endif
3050 14 : if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
3051 : == -1) {
3052 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
3053 0 : goto out;
3054 : }
3055 :
3056 14 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3057 0 : SCVAL(req->outbuf, smb_flg,
3058 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
3059 : }
3060 :
3061 14 : if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3062 0 : SCVAL(req->outbuf, smb_flg,
3063 : CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
3064 : }
3065 :
3066 14 : DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
3067 14 : DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
3068 : fsp_get_io_fd(fsp), (unsigned int)smb_fname->st.st_ex_mode));
3069 14 : out:
3070 14 : TALLOC_FREE(smb_fname);
3071 14 : TALLOC_FREE(wire_name);
3072 14 : END_PROFILE(SMBctemp);
3073 14 : return;
3074 : }
3075 :
3076 : /*******************************************************************
3077 : Check if a user is allowed to rename a file.
3078 : ********************************************************************/
3079 :
3080 614 : static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
3081 : uint16_t dirtype)
3082 : {
3083 614 : if (!CAN_WRITE(conn)) {
3084 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
3085 : }
3086 :
3087 614 : if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
3088 : (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
3089 : /* Only bother to read the DOS attribute if we might deny the
3090 : rename on the grounds of attribute mismatch. */
3091 175 : uint32_t fmode = fdos_mode(fsp);
3092 175 : if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
3093 10 : return NT_STATUS_NO_SUCH_FILE;
3094 : }
3095 : }
3096 :
3097 604 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
3098 267 : if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
3099 8 : return NT_STATUS_OK;
3100 : }
3101 :
3102 : /* If no pathnames are open below this
3103 : directory, allow the rename. */
3104 :
3105 259 : if (lp_strict_rename(SNUM(conn))) {
3106 : /*
3107 : * Strict rename, check open file db.
3108 : */
3109 180 : if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
3110 12 : return NT_STATUS_ACCESS_DENIED;
3111 : }
3112 79 : } else if (file_find_subpath(fsp)) {
3113 : /*
3114 : * No strict rename, just look in local process.
3115 : */
3116 5 : return NT_STATUS_ACCESS_DENIED;
3117 : }
3118 242 : return NT_STATUS_OK;
3119 : }
3120 :
3121 337 : if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
3122 337 : return NT_STATUS_OK;
3123 : }
3124 :
3125 0 : return NT_STATUS_ACCESS_DENIED;
3126 : }
3127 :
3128 : /*******************************************************************
3129 : * unlink a file with all relevant access checks
3130 : *******************************************************************/
3131 :
3132 26949 : static NTSTATUS do_unlink(connection_struct *conn,
3133 : struct smb_request *req,
3134 : struct smb_filename *smb_fname,
3135 : uint32_t dirtype)
3136 : {
3137 : uint32_t fattr;
3138 : files_struct *fsp;
3139 26949 : uint32_t dirtype_orig = dirtype;
3140 : NTSTATUS status;
3141 : int ret;
3142 26949 : struct smb2_create_blobs *posx = NULL;
3143 :
3144 26949 : DEBUG(10,("do_unlink: %s, dirtype = %d\n",
3145 : smb_fname_str_dbg(smb_fname),
3146 : dirtype));
3147 :
3148 26949 : if (!CAN_WRITE(conn)) {
3149 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
3150 : }
3151 :
3152 26949 : ret = vfs_stat(conn, smb_fname);
3153 26949 : if (ret != 0) {
3154 2599 : return map_nt_error_from_unix(errno);
3155 : }
3156 :
3157 24350 : fattr = fdos_mode(smb_fname->fsp);
3158 :
3159 24350 : if (dirtype & FILE_ATTRIBUTE_NORMAL) {
3160 84 : dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
3161 : }
3162 :
3163 24350 : dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
3164 24350 : if (!dirtype) {
3165 0 : return NT_STATUS_NO_SUCH_FILE;
3166 : }
3167 :
3168 24350 : if (!dir_check_ftype(fattr, dirtype)) {
3169 115 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3170 111 : return NT_STATUS_FILE_IS_A_DIRECTORY;
3171 : }
3172 4 : return NT_STATUS_NO_SUCH_FILE;
3173 : }
3174 :
3175 24235 : if (dirtype_orig & 0x8000) {
3176 : /* These will never be set for POSIX. */
3177 0 : return NT_STATUS_NO_SUCH_FILE;
3178 : }
3179 :
3180 : #if 0
3181 : if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
3182 : return NT_STATUS_FILE_IS_A_DIRECTORY;
3183 : }
3184 :
3185 : if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
3186 : return NT_STATUS_NO_SUCH_FILE;
3187 : }
3188 :
3189 : if (dirtype & 0xFF00) {
3190 : /* These will never be set for POSIX. */
3191 : return NT_STATUS_NO_SUCH_FILE;
3192 : }
3193 :
3194 : dirtype &= 0xFF;
3195 : if (!dirtype) {
3196 : return NT_STATUS_NO_SUCH_FILE;
3197 : }
3198 :
3199 : /* Can't delete a directory. */
3200 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3201 : return NT_STATUS_FILE_IS_A_DIRECTORY;
3202 : }
3203 : #endif
3204 :
3205 : #if 0 /* JRATEST */
3206 : else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
3207 : return NT_STATUS_OBJECT_NAME_INVALID;
3208 : #endif /* JRATEST */
3209 :
3210 24235 : if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
3211 6 : status = make_smb2_posix_create_ctx(
3212 : talloc_tos(), &posx, 0777);
3213 6 : if (!NT_STATUS_IS_OK(status)) {
3214 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3215 : nt_errstr(status));
3216 0 : return status;
3217 : }
3218 : }
3219 :
3220 : /* On open checks the open itself will check the share mode, so
3221 : don't do it here as we'll get it wrong. */
3222 :
3223 24235 : status = SMB_VFS_CREATE_FILE
3224 : (conn, /* conn */
3225 : req, /* req */
3226 : smb_fname, /* fname */
3227 : DELETE_ACCESS, /* access_mask */
3228 : FILE_SHARE_NONE, /* share_access */
3229 : FILE_OPEN, /* create_disposition*/
3230 : FILE_NON_DIRECTORY_FILE, /* create_options */
3231 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
3232 : 0, /* oplock_request */
3233 : NULL, /* lease */
3234 : 0, /* allocation_size */
3235 : 0, /* private_flags */
3236 : NULL, /* sd */
3237 : NULL, /* ea_list */
3238 : &fsp, /* result */
3239 : NULL, /* pinfo */
3240 : posx, /* in_context_blobs */
3241 : NULL); /* out_context_blobs */
3242 :
3243 24235 : TALLOC_FREE(posx);
3244 :
3245 24235 : if (!NT_STATUS_IS_OK(status)) {
3246 1045 : DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
3247 : nt_errstr(status)));
3248 1045 : return status;
3249 : }
3250 :
3251 23190 : status = can_set_delete_on_close(fsp, fattr);
3252 23190 : if (!NT_STATUS_IS_OK(status)) {
3253 8 : DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
3254 : "(%s)\n",
3255 : smb_fname_str_dbg(smb_fname),
3256 : nt_errstr(status)));
3257 8 : close_file(req, fsp, NORMAL_CLOSE);
3258 8 : return status;
3259 : }
3260 :
3261 : /* The set is across all open files on this dev/inode pair. */
3262 23182 : if (!set_delete_on_close(fsp, True,
3263 23182 : conn->session_info->security_token,
3264 23182 : conn->session_info->unix_token)) {
3265 0 : close_file(req, fsp, NORMAL_CLOSE);
3266 0 : return NT_STATUS_ACCESS_DENIED;
3267 : }
3268 :
3269 23182 : return close_file(req, fsp, NORMAL_CLOSE);
3270 : }
3271 :
3272 : /****************************************************************************
3273 : The guts of the unlink command, split out so it may be called by the NT SMB
3274 : code.
3275 : ****************************************************************************/
3276 :
3277 19573 : NTSTATUS unlink_internals(connection_struct *conn,
3278 : struct smb_request *req,
3279 : uint32_t dirtype,
3280 : struct smb_filename *smb_fname,
3281 : bool has_wild)
3282 : {
3283 19573 : char *fname_dir = NULL;
3284 19573 : char *fname_mask = NULL;
3285 19573 : int count=0;
3286 19573 : NTSTATUS status = NT_STATUS_OK;
3287 19573 : struct smb_filename *smb_fname_dir = NULL;
3288 19573 : TALLOC_CTX *ctx = talloc_tos();
3289 : int ret;
3290 :
3291 : /* Split up the directory from the filename/mask. */
3292 19573 : status = split_fname_dir_mask(ctx, smb_fname->base_name,
3293 : &fname_dir, &fname_mask);
3294 19573 : if (!NT_STATUS_IS_OK(status)) {
3295 0 : goto out;
3296 : }
3297 :
3298 : /*
3299 : * We should only check the mangled cache
3300 : * here if unix_convert failed. This means
3301 : * that the path in 'mask' doesn't exist
3302 : * on the file system and so we need to look
3303 : * for a possible mangle. This patch from
3304 : * Tine Smukavec <valentin.smukavec@hermes.si>.
3305 : */
3306 :
3307 27268 : if (!VALID_STAT(smb_fname->st) &&
3308 7695 : mangle_is_mangled(fname_mask, conn->params)) {
3309 0 : char *new_mask = NULL;
3310 0 : mangle_lookup_name_from_8_3(ctx, fname_mask,
3311 0 : &new_mask, conn->params);
3312 0 : if (new_mask) {
3313 0 : TALLOC_FREE(fname_mask);
3314 0 : fname_mask = new_mask;
3315 : }
3316 : }
3317 :
3318 19573 : if (!has_wild) {
3319 :
3320 : /*
3321 : * Only one file needs to be unlinked. Append the mask back
3322 : * onto the directory.
3323 : */
3324 14477 : TALLOC_FREE(smb_fname->base_name);
3325 14477 : if (ISDOT(fname_dir)) {
3326 : /* Ensure we use canonical names on open. */
3327 4534 : smb_fname->base_name = talloc_asprintf(smb_fname,
3328 : "%s",
3329 : fname_mask);
3330 : } else {
3331 9943 : smb_fname->base_name = talloc_asprintf(smb_fname,
3332 : "%s/%s",
3333 : fname_dir,
3334 : fname_mask);
3335 : }
3336 14477 : if (!smb_fname->base_name) {
3337 0 : status = NT_STATUS_NO_MEMORY;
3338 0 : goto out;
3339 : }
3340 14477 : if (dirtype == 0) {
3341 92 : dirtype = FILE_ATTRIBUTE_NORMAL;
3342 : }
3343 :
3344 14477 : status = check_name(conn, smb_fname);
3345 14477 : if (!NT_STATUS_IS_OK(status)) {
3346 0 : goto out;
3347 : }
3348 :
3349 14477 : status = do_unlink(conn, req, smb_fname, dirtype);
3350 14477 : if (!NT_STATUS_IS_OK(status)) {
3351 3390 : goto out;
3352 : }
3353 :
3354 10744 : count++;
3355 : } else {
3356 5096 : struct smb_Dir *dir_hnd = NULL;
3357 5096 : long offset = 0;
3358 5096 : const char *dname = NULL;
3359 5096 : char *talloced = NULL;
3360 :
3361 5096 : if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3362 20 : status = NT_STATUS_OBJECT_NAME_INVALID;
3363 141 : goto out;
3364 : }
3365 5076 : if (dirtype == 0) {
3366 20 : dirtype = FILE_ATTRIBUTE_NORMAL;
3367 : }
3368 :
3369 5076 : if (strequal(fname_mask,"????????.???")) {
3370 0 : TALLOC_FREE(fname_mask);
3371 0 : fname_mask = talloc_strdup(ctx, "*");
3372 0 : if (!fname_mask) {
3373 0 : status = NT_STATUS_NO_MEMORY;
3374 0 : goto out;
3375 : }
3376 : }
3377 :
3378 5076 : smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3379 : fname_dir,
3380 : NULL,
3381 : NULL,
3382 : smb_fname->twrp,
3383 : smb_fname->flags);
3384 5076 : if (smb_fname_dir == NULL) {
3385 0 : status = NT_STATUS_NO_MEMORY;
3386 0 : goto out;
3387 : }
3388 :
3389 5076 : status = check_name(conn, smb_fname_dir);
3390 5076 : if (!NT_STATUS_IS_OK(status)) {
3391 0 : goto out;
3392 : }
3393 :
3394 5076 : dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3395 : dirtype);
3396 5076 : if (dir_hnd == NULL) {
3397 0 : status = map_nt_error_from_unix(errno);
3398 0 : goto out;
3399 : }
3400 :
3401 : /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3402 : the pattern matches against the long name, otherwise the short name
3403 : We don't implement this yet XXXX
3404 : */
3405 :
3406 5028 : status = NT_STATUS_NO_SUCH_FILE;
3407 :
3408 31469 : while ((dname = ReadDirName(dir_hnd, &offset,
3409 : &smb_fname->st, &talloced))) {
3410 22632 : TALLOC_CTX *frame = talloc_stackframe();
3411 22632 : char *p = NULL;
3412 22632 : struct smb_filename *f = NULL;
3413 :
3414 : /* Quick check for "." and ".." */
3415 22632 : if (ISDOT(dname) || ISDOTDOT(dname)) {
3416 10152 : TALLOC_FREE(frame);
3417 10152 : TALLOC_FREE(talloced);
3418 10152 : continue;
3419 : }
3420 :
3421 12480 : if (IS_VETO_PATH(conn, dname)) {
3422 0 : TALLOC_FREE(frame);
3423 0 : TALLOC_FREE(talloced);
3424 0 : continue;
3425 : }
3426 :
3427 12480 : if(!mask_match(dname, fname_mask,
3428 12480 : conn->case_sensitive)) {
3429 8 : TALLOC_FREE(frame);
3430 8 : TALLOC_FREE(talloced);
3431 8 : continue;
3432 : }
3433 :
3434 12472 : if (ISDOT(fname_dir)) {
3435 : /* Ensure we use canonical names on open. */
3436 0 : p = talloc_asprintf(smb_fname, "%s", dname);
3437 : } else {
3438 12472 : p = talloc_asprintf(smb_fname, "%s/%s",
3439 : fname_dir, dname);
3440 : }
3441 12472 : if (p == NULL) {
3442 0 : TALLOC_FREE(dir_hnd);
3443 0 : status = NT_STATUS_NO_MEMORY;
3444 0 : TALLOC_FREE(frame);
3445 0 : TALLOC_FREE(talloced);
3446 0 : goto out;
3447 : }
3448 22298 : f = synthetic_smb_fname(frame,
3449 : p,
3450 : NULL,
3451 12432 : &smb_fname->st,
3452 : smb_fname->twrp,
3453 : smb_fname->flags);
3454 12472 : if (f == NULL) {
3455 0 : TALLOC_FREE(dir_hnd);
3456 0 : status = NT_STATUS_NO_MEMORY;
3457 0 : TALLOC_FREE(frame);
3458 0 : TALLOC_FREE(talloced);
3459 0 : goto out;
3460 : }
3461 :
3462 12472 : ret = vfs_stat(conn, f);
3463 12472 : if (ret != 0) {
3464 0 : status = map_nt_error_from_unix(errno);
3465 0 : TALLOC_FREE(dir_hnd);
3466 0 : TALLOC_FREE(frame);
3467 0 : TALLOC_FREE(talloced);
3468 0 : goto out;
3469 : }
3470 :
3471 12472 : status = openat_pathref_fsp(conn->cwd_fsp, f);
3472 12472 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
3473 0 : (f->flags & SMB_FILENAME_POSIX_PATH) &&
3474 0 : S_ISLNK(f->st.st_ex_mode))
3475 : {
3476 0 : status = NT_STATUS_OK;
3477 : }
3478 12472 : if (!NT_STATUS_IS_OK(status)) {
3479 0 : TALLOC_FREE(dir_hnd);
3480 0 : TALLOC_FREE(frame);
3481 0 : TALLOC_FREE(talloced);
3482 0 : goto out;
3483 : }
3484 :
3485 12472 : if (!is_visible_fsp(f->fsp)) {
3486 0 : TALLOC_FREE(frame);
3487 0 : TALLOC_FREE(talloced);
3488 0 : continue;
3489 : }
3490 :
3491 12472 : status = check_name(conn, f);
3492 12472 : if (!NT_STATUS_IS_OK(status)) {
3493 0 : TALLOC_FREE(dir_hnd);
3494 0 : TALLOC_FREE(frame);
3495 0 : TALLOC_FREE(talloced);
3496 0 : goto out;
3497 : }
3498 :
3499 12472 : status = do_unlink(conn, req, f, dirtype);
3500 12472 : if (!NT_STATUS_IS_OK(status)) {
3501 135 : TALLOC_FREE(dir_hnd);
3502 135 : TALLOC_FREE(frame);
3503 135 : TALLOC_FREE(talloced);
3504 126 : goto out;
3505 : }
3506 :
3507 12337 : count++;
3508 12337 : DBG_DEBUG("successful unlink [%s]\n",
3509 : smb_fname_str_dbg(f));
3510 :
3511 12337 : TALLOC_FREE(frame);
3512 12337 : TALLOC_FREE(talloced);
3513 : }
3514 4941 : TALLOC_FREE(dir_hnd);
3515 : }
3516 :
3517 19011 : if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3518 0 : status = map_nt_error_from_unix(errno);
3519 : }
3520 :
3521 32648 : out:
3522 19573 : TALLOC_FREE(smb_fname_dir);
3523 19573 : TALLOC_FREE(fname_dir);
3524 19573 : TALLOC_FREE(fname_mask);
3525 19573 : return status;
3526 : }
3527 :
3528 : /****************************************************************************
3529 : Reply to a unlink
3530 : ****************************************************************************/
3531 :
3532 19971 : void reply_unlink(struct smb_request *req)
3533 : {
3534 19971 : connection_struct *conn = req->conn;
3535 19971 : char *name = NULL;
3536 19971 : struct smb_filename *smb_fname = NULL;
3537 : uint32_t dirtype;
3538 : NTSTATUS status;
3539 19971 : uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
3540 19971 : ucf_flags_from_smb_request(req);
3541 19971 : TALLOC_CTX *ctx = talloc_tos();
3542 19971 : bool has_wild = false;
3543 :
3544 19971 : START_PROFILE(SMBunlink);
3545 :
3546 19971 : if (req->wct < 1) {
3547 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3548 0 : goto out;
3549 : }
3550 :
3551 19971 : dirtype = SVAL(req->vwv+0, 0);
3552 :
3553 19971 : srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
3554 : STR_TERMINATE, &status);
3555 19971 : if (!NT_STATUS_IS_OK(status)) {
3556 167 : reply_nterror(req, status);
3557 167 : goto out;
3558 : }
3559 :
3560 19804 : status = filename_convert(ctx, conn,
3561 : name,
3562 : ucf_flags,
3563 : 0,
3564 : &smb_fname);
3565 19804 : if (!NT_STATUS_IS_OK(status)) {
3566 231 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3567 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3568 : ERRSRV, ERRbadpath);
3569 0 : goto out;
3570 : }
3571 231 : reply_nterror(req, status);
3572 231 : goto out;
3573 : }
3574 :
3575 19573 : if (!req->posix_pathnames) {
3576 19565 : char *lcomp = get_original_lcomp(ctx,
3577 : conn,
3578 : name,
3579 : ucf_flags);
3580 19565 : if (lcomp == NULL) {
3581 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
3582 0 : goto out;
3583 : }
3584 19565 : has_wild = ms_has_wild(lcomp);
3585 19565 : TALLOC_FREE(lcomp);
3586 : }
3587 :
3588 19573 : DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3589 :
3590 19573 : status = unlink_internals(conn, req, dirtype, smb_fname, has_wild);
3591 19573 : if (!NT_STATUS_IS_OK(status)) {
3592 8158 : if (open_was_deferred(req->xconn, req->mid)) {
3593 : /* We have re-scheduled this call. */
3594 18 : goto out;
3595 : }
3596 8140 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3597 182 : bool ok = defer_smb1_sharing_violation(req);
3598 182 : if (ok) {
3599 82 : goto out;
3600 : }
3601 : }
3602 8051 : reply_nterror(req, status);
3603 8051 : goto out;
3604 : }
3605 :
3606 11415 : reply_outbuf(req, 0, 0);
3607 19978 : out:
3608 19971 : TALLOC_FREE(smb_fname);
3609 19971 : END_PROFILE(SMBunlink);
3610 19971 : return;
3611 : }
3612 :
3613 : /****************************************************************************
3614 : Fail for readbraw.
3615 : ****************************************************************************/
3616 :
3617 0 : static void fail_readraw(void)
3618 : {
3619 0 : const char *errstr = talloc_asprintf(talloc_tos(),
3620 : "FAIL ! reply_readbraw: socket write fail (%s)",
3621 0 : strerror(errno));
3622 0 : if (!errstr) {
3623 0 : errstr = "";
3624 : }
3625 0 : exit_server_cleanly(errstr);
3626 : }
3627 :
3628 : /****************************************************************************
3629 : Fake (read/write) sendfile. Returns -1 on read or write fail.
3630 : ****************************************************************************/
3631 :
3632 12 : ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3633 : off_t startpos, size_t nread)
3634 : {
3635 : size_t bufsize;
3636 12 : size_t tosend = nread;
3637 : char *buf;
3638 :
3639 12 : if (nread == 0) {
3640 0 : return 0;
3641 : }
3642 :
3643 12 : bufsize = MIN(nread, 65536);
3644 :
3645 12 : if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3646 0 : return -1;
3647 : }
3648 :
3649 1728 : while (tosend > 0) {
3650 : ssize_t ret;
3651 : size_t cur_read;
3652 :
3653 1704 : cur_read = MIN(tosend, bufsize);
3654 1704 : ret = read_file(fsp,buf,startpos,cur_read);
3655 1704 : if (ret == -1) {
3656 0 : SAFE_FREE(buf);
3657 0 : return -1;
3658 : }
3659 :
3660 : /* If we had a short read, fill with zeros. */
3661 1704 : if (ret < cur_read) {
3662 0 : memset(buf + ret, '\0', cur_read - ret);
3663 : }
3664 :
3665 1704 : ret = write_data(xconn->transport.sock, buf, cur_read);
3666 1704 : if (ret != cur_read) {
3667 0 : int saved_errno = errno;
3668 : /*
3669 : * Try and give an error message saying what
3670 : * client failed.
3671 : */
3672 0 : DEBUG(0, ("write_data failed for client %s. "
3673 : "Error %s\n",
3674 : smbXsrv_connection_dbg(xconn),
3675 : strerror(saved_errno)));
3676 0 : SAFE_FREE(buf);
3677 0 : errno = saved_errno;
3678 0 : return -1;
3679 : }
3680 1704 : tosend -= cur_read;
3681 1704 : startpos += cur_read;
3682 : }
3683 :
3684 12 : SAFE_FREE(buf);
3685 12 : return (ssize_t)nread;
3686 : }
3687 :
3688 : /****************************************************************************
3689 : Deal with the case of sendfile reading less bytes from the file than
3690 : requested. Fill with zeros (all we can do). Returns 0 on success
3691 : ****************************************************************************/
3692 :
3693 0 : ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3694 : files_struct *fsp,
3695 : ssize_t nread,
3696 : size_t headersize,
3697 : size_t smb_maxcnt)
3698 : {
3699 : #define SHORT_SEND_BUFSIZE 1024
3700 0 : if (nread < headersize) {
3701 0 : DEBUG(0,("sendfile_short_send: sendfile failed to send "
3702 : "header for file %s (%s). Terminating\n",
3703 : fsp_str_dbg(fsp), strerror(errno)));
3704 0 : return -1;
3705 : }
3706 :
3707 0 : nread -= headersize;
3708 :
3709 0 : if (nread < smb_maxcnt) {
3710 0 : char buf[SHORT_SEND_BUFSIZE] = { 0 };
3711 :
3712 0 : DEBUG(0,("sendfile_short_send: filling truncated file %s "
3713 : "with zeros !\n", fsp_str_dbg(fsp)));
3714 :
3715 0 : while (nread < smb_maxcnt) {
3716 : /*
3717 : * We asked for the real file size and told sendfile
3718 : * to not go beyond the end of the file. But it can
3719 : * happen that in between our fstat call and the
3720 : * sendfile call the file was truncated. This is very
3721 : * bad because we have already announced the larger
3722 : * number of bytes to the client.
3723 : *
3724 : * The best we can do now is to send 0-bytes, just as
3725 : * a read from a hole in a sparse file would do.
3726 : *
3727 : * This should happen rarely enough that I don't care
3728 : * about efficiency here :-)
3729 : */
3730 : size_t to_write;
3731 : ssize_t ret;
3732 :
3733 0 : to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3734 0 : ret = write_data(xconn->transport.sock, buf, to_write);
3735 0 : if (ret != to_write) {
3736 0 : int saved_errno = errno;
3737 : /*
3738 : * Try and give an error message saying what
3739 : * client failed.
3740 : */
3741 0 : DEBUG(0, ("write_data failed for client %s. "
3742 : "Error %s\n",
3743 : smbXsrv_connection_dbg(xconn),
3744 : strerror(saved_errno)));
3745 0 : errno = saved_errno;
3746 0 : return -1;
3747 : }
3748 0 : nread += to_write;
3749 : }
3750 : }
3751 :
3752 0 : return 0;
3753 : }
3754 :
3755 : /****************************************************************************
3756 : Return a readbraw error (4 bytes of zero).
3757 : ****************************************************************************/
3758 :
3759 16 : static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3760 : {
3761 : char header[4];
3762 :
3763 16 : SIVAL(header,0,0);
3764 :
3765 16 : smbd_lock_socket(xconn);
3766 16 : if (write_data(xconn->transport.sock,header,4) != 4) {
3767 0 : int saved_errno = errno;
3768 : /*
3769 : * Try and give an error message saying what
3770 : * client failed.
3771 : */
3772 0 : DEBUG(0, ("write_data failed for client %s. "
3773 : "Error %s\n",
3774 : smbXsrv_connection_dbg(xconn),
3775 : strerror(saved_errno)));
3776 0 : errno = saved_errno;
3777 :
3778 0 : fail_readraw();
3779 : }
3780 16 : smbd_unlock_socket(xconn);
3781 16 : }
3782 :
3783 : /*******************************************************************
3784 : Ensure we don't use sendfile if server smb signing is active.
3785 : ********************************************************************/
3786 :
3787 47 : static bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state)
3788 : {
3789 47 : bool sign_active = false;
3790 :
3791 : /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
3792 47 : if (get_Protocol() < PROTOCOL_NT1) {
3793 0 : return false;
3794 : }
3795 47 : if (signing_state) {
3796 47 : sign_active = smb_signing_is_active(signing_state);
3797 : }
3798 47 : return (lp__use_sendfile(snum) &&
3799 47 : (get_remote_arch() != RA_WIN95) &&
3800 0 : !sign_active);
3801 : }
3802 : /****************************************************************************
3803 : Use sendfile in readbraw.
3804 : ****************************************************************************/
3805 :
3806 32 : static void send_file_readbraw(connection_struct *conn,
3807 : struct smb_request *req,
3808 : files_struct *fsp,
3809 : off_t startpos,
3810 : size_t nread,
3811 : ssize_t mincount)
3812 : {
3813 32 : struct smbXsrv_connection *xconn = req->xconn;
3814 32 : char *outbuf = NULL;
3815 32 : ssize_t ret=0;
3816 :
3817 : /*
3818 : * We can only use sendfile on a non-chained packet
3819 : * but we can use on a non-oplocked file. tridge proved this
3820 : * on a train in Germany :-). JRA.
3821 : * reply_readbraw has already checked the length.
3822 : */
3823 :
3824 72 : if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3825 20 : lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3826 0 : ssize_t sendfile_read = -1;
3827 : char header[4];
3828 : DATA_BLOB header_blob;
3829 :
3830 0 : _smb_setlen(header,nread);
3831 0 : header_blob = data_blob_const(header, 4);
3832 :
3833 0 : sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3834 : &header_blob, startpos,
3835 : nread);
3836 0 : if (sendfile_read == -1) {
3837 : /* Returning ENOSYS means no data at all was sent.
3838 : * Do this as a normal read. */
3839 0 : if (errno == ENOSYS) {
3840 0 : goto normal_readbraw;
3841 : }
3842 :
3843 : /*
3844 : * Special hack for broken Linux with no working sendfile. If we
3845 : * return EINTR we sent the header but not the rest of the data.
3846 : * Fake this up by doing read/write calls.
3847 : */
3848 0 : if (errno == EINTR) {
3849 : /* Ensure we don't do this again. */
3850 0 : set_use_sendfile(SNUM(conn), False);
3851 0 : DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3852 :
3853 0 : if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3854 0 : DEBUG(0,("send_file_readbraw: "
3855 : "fake_sendfile failed for "
3856 : "file %s (%s).\n",
3857 : fsp_str_dbg(fsp),
3858 : strerror(errno)));
3859 0 : exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3860 : }
3861 0 : return;
3862 : }
3863 :
3864 0 : DEBUG(0,("send_file_readbraw: sendfile failed for "
3865 : "file %s (%s). Terminating\n",
3866 : fsp_str_dbg(fsp), strerror(errno)));
3867 0 : exit_server_cleanly("send_file_readbraw sendfile failed");
3868 0 : } else if (sendfile_read == 0) {
3869 : /*
3870 : * Some sendfile implementations return 0 to indicate
3871 : * that there was a short read, but nothing was
3872 : * actually written to the socket. In this case,
3873 : * fallback to the normal read path so the header gets
3874 : * the correct byte count.
3875 : */
3876 0 : DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3877 : "bytes falling back to the normal read: "
3878 : "%s\n", fsp_str_dbg(fsp)));
3879 0 : goto normal_readbraw;
3880 : }
3881 :
3882 : /* Deal with possible short send. */
3883 0 : if (sendfile_read != 4+nread) {
3884 0 : ret = sendfile_short_send(xconn, fsp,
3885 : sendfile_read, 4, nread);
3886 0 : if (ret == -1) {
3887 0 : fail_readraw();
3888 : }
3889 : }
3890 0 : return;
3891 : }
3892 :
3893 32 : normal_readbraw:
3894 :
3895 32 : outbuf = talloc_array(NULL, char, nread+4);
3896 32 : if (!outbuf) {
3897 0 : DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3898 : (unsigned)(nread+4)));
3899 0 : reply_readbraw_error(xconn);
3900 0 : return;
3901 : }
3902 :
3903 32 : if (nread > 0) {
3904 20 : ret = read_file(fsp,outbuf+4,startpos,nread);
3905 : #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3906 : if (ret < mincount)
3907 : ret = 0;
3908 : #else
3909 20 : if (ret < nread)
3910 0 : ret = 0;
3911 : #endif
3912 : }
3913 :
3914 32 : _smb_setlen(outbuf,ret);
3915 32 : if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3916 0 : int saved_errno = errno;
3917 : /*
3918 : * Try and give an error message saying what
3919 : * client failed.
3920 : */
3921 0 : DEBUG(0, ("write_data failed for client %s. Error %s\n",
3922 : smbXsrv_connection_dbg(xconn),
3923 : strerror(saved_errno)));
3924 0 : errno = saved_errno;
3925 :
3926 0 : fail_readraw();
3927 : }
3928 :
3929 32 : TALLOC_FREE(outbuf);
3930 : }
3931 :
3932 : /****************************************************************************
3933 : Reply to a readbraw (core+ protocol).
3934 : ****************************************************************************/
3935 :
3936 48 : void reply_readbraw(struct smb_request *req)
3937 : {
3938 48 : connection_struct *conn = req->conn;
3939 48 : struct smbXsrv_connection *xconn = req->xconn;
3940 : ssize_t maxcount,mincount;
3941 48 : size_t nread = 0;
3942 : off_t startpos;
3943 : files_struct *fsp;
3944 : struct lock_struct lock;
3945 48 : off_t size = 0;
3946 : NTSTATUS status;
3947 :
3948 48 : START_PROFILE(SMBreadbraw);
3949 :
3950 48 : if (srv_is_signing_active(xconn) || req->encrypted) {
3951 0 : exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3952 : "raw reads/writes are disallowed.");
3953 : }
3954 :
3955 48 : if (req->wct < 8) {
3956 0 : reply_readbraw_error(xconn);
3957 0 : END_PROFILE(SMBreadbraw);
3958 0 : return;
3959 : }
3960 :
3961 48 : if (xconn->smb1.echo_handler.trusted_fde) {
3962 0 : DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3963 : "'async smb echo handler = yes'\n"));
3964 0 : reply_readbraw_error(xconn);
3965 0 : END_PROFILE(SMBreadbraw);
3966 0 : return;
3967 : }
3968 :
3969 : /*
3970 : * Special check if an oplock break has been issued
3971 : * and the readraw request croses on the wire, we must
3972 : * return a zero length response here.
3973 : */
3974 :
3975 48 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3976 :
3977 : /*
3978 : * We have to do a check_fsp by hand here, as
3979 : * we must always return 4 zero bytes on error,
3980 : * not a NTSTATUS.
3981 : */
3982 :
3983 48 : if (fsp == NULL ||
3984 44 : conn == NULL ||
3985 88 : conn != fsp->conn ||
3986 88 : req->vuid != fsp->vuid ||
3987 44 : fsp->fsp_flags.is_directory ||
3988 44 : fsp_get_io_fd(fsp) == -1)
3989 : {
3990 : /*
3991 : * fsp could be NULL here so use the value from the packet. JRA.
3992 : */
3993 4 : DEBUG(3,("reply_readbraw: fnum %d not valid "
3994 : "- cache prime?\n",
3995 : (int)SVAL(req->vwv+0, 0)));
3996 4 : reply_readbraw_error(xconn);
3997 4 : END_PROFILE(SMBreadbraw);
3998 4 : return;
3999 : }
4000 :
4001 : /* Do a "by hand" version of CHECK_READ. */
4002 44 : if (!(fsp->fsp_flags.can_read ||
4003 0 : ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
4004 0 : (fsp->access_mask & FILE_EXECUTE)))) {
4005 0 : DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
4006 : (int)SVAL(req->vwv+0, 0)));
4007 0 : reply_readbraw_error(xconn);
4008 0 : END_PROFILE(SMBreadbraw);
4009 0 : return;
4010 : }
4011 :
4012 44 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
4013 44 : if(req->wct == 10) {
4014 : /*
4015 : * This is a large offset (64 bit) read.
4016 : */
4017 :
4018 44 : startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
4019 :
4020 44 : if(startpos < 0) {
4021 4 : DEBUG(0,("reply_readbraw: negative 64 bit "
4022 : "readraw offset (%.0f) !\n",
4023 : (double)startpos ));
4024 4 : reply_readbraw_error(xconn);
4025 4 : END_PROFILE(SMBreadbraw);
4026 4 : return;
4027 : }
4028 : }
4029 :
4030 40 : maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
4031 40 : mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
4032 :
4033 : /* ensure we don't overrun the packet size */
4034 40 : maxcount = MIN(65535,maxcount);
4035 :
4036 40 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4037 : (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
4038 : &lock);
4039 :
4040 40 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4041 8 : reply_readbraw_error(xconn);
4042 8 : END_PROFILE(SMBreadbraw);
4043 8 : return;
4044 : }
4045 :
4046 32 : status = vfs_stat_fsp(fsp);
4047 32 : if (NT_STATUS_IS_OK(status)) {
4048 32 : size = fsp->fsp_name->st.st_ex_size;
4049 : }
4050 :
4051 32 : if (startpos >= size) {
4052 12 : nread = 0;
4053 : } else {
4054 20 : nread = MIN(maxcount,(size - startpos));
4055 : }
4056 :
4057 : #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
4058 : if (nread < mincount)
4059 : nread = 0;
4060 : #endif
4061 :
4062 32 : DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
4063 : "min=%lu nread=%lu\n",
4064 : fsp_fnum_dbg(fsp), (double)startpos,
4065 : (unsigned long)maxcount,
4066 : (unsigned long)mincount,
4067 : (unsigned long)nread ) );
4068 :
4069 32 : send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
4070 :
4071 32 : DEBUG(5,("reply_readbraw finished\n"));
4072 :
4073 32 : END_PROFILE(SMBreadbraw);
4074 32 : return;
4075 : }
4076 :
4077 : #undef DBGC_CLASS
4078 : #define DBGC_CLASS DBGC_LOCKING
4079 :
4080 : /****************************************************************************
4081 : Reply to a lockread (core+ protocol).
4082 : ****************************************************************************/
4083 :
4084 : static void reply_lockread_locked(struct tevent_req *subreq);
4085 :
4086 91 : void reply_lockread(struct smb_request *req)
4087 : {
4088 91 : struct tevent_req *subreq = NULL;
4089 91 : connection_struct *conn = req->conn;
4090 : files_struct *fsp;
4091 91 : struct smbd_lock_element *lck = NULL;
4092 :
4093 91 : START_PROFILE(SMBlockread);
4094 :
4095 91 : if (req->wct < 5) {
4096 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4097 0 : END_PROFILE(SMBlockread);
4098 5 : return;
4099 : }
4100 :
4101 91 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4102 :
4103 91 : if (!check_fsp(conn, req, fsp)) {
4104 7 : END_PROFILE(SMBlockread);
4105 6 : return;
4106 : }
4107 :
4108 84 : if (!CHECK_READ(fsp,req)) {
4109 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4110 0 : END_PROFILE(SMBlockread);
4111 0 : return;
4112 : }
4113 :
4114 84 : lck = talloc(req, struct smbd_lock_element);
4115 84 : if (lck == NULL) {
4116 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4117 0 : END_PROFILE(SMBlockread);
4118 0 : return;
4119 : }
4120 :
4121 : /*
4122 : * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
4123 : * protocol request that predates the read/write lock concept.
4124 : * Thus instead of asking for a read lock here we need to ask
4125 : * for a write lock. JRA.
4126 : * Note that the requested lock size is unaffected by max_send.
4127 : */
4128 :
4129 84 : *lck = (struct smbd_lock_element) {
4130 84 : .req_guid = smbd_request_guid(req, 0),
4131 84 : .smblctx = req->smbpid,
4132 : .brltype = WRITE_LOCK,
4133 84 : .count = SVAL(req->vwv+1, 0),
4134 84 : .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
4135 : };
4136 :
4137 84 : subreq = smbd_smb1_do_locks_send(
4138 : fsp,
4139 84 : req->sconn->ev_ctx,
4140 : &req,
4141 : fsp,
4142 : 0,
4143 : false, /* large_offset */
4144 : WINDOWS_LOCK,
4145 : 1,
4146 : lck);
4147 84 : if (subreq == NULL) {
4148 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4149 0 : END_PROFILE(SMBlockread);
4150 0 : return;
4151 : }
4152 84 : tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
4153 84 : END_PROFILE(SMBlockread);
4154 : }
4155 :
4156 84 : static void reply_lockread_locked(struct tevent_req *subreq)
4157 : {
4158 84 : struct smb_request *req = NULL;
4159 84 : ssize_t nread = -1;
4160 84 : char *data = NULL;
4161 : NTSTATUS status;
4162 : bool ok;
4163 : off_t startpos;
4164 : size_t numtoread, maxtoread;
4165 84 : struct files_struct *fsp = NULL;
4166 84 : char *p = NULL;
4167 :
4168 84 : START_PROFILE(SMBlockread);
4169 :
4170 84 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
4171 84 : SMB_ASSERT(ok);
4172 :
4173 84 : status = smbd_smb1_do_locks_recv(subreq);
4174 84 : TALLOC_FREE(subreq);
4175 :
4176 84 : if (!NT_STATUS_IS_OK(status)) {
4177 42 : reply_nterror(req, status);
4178 42 : goto send;
4179 : }
4180 :
4181 42 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4182 42 : if (fsp == NULL) {
4183 0 : reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
4184 0 : goto send;
4185 : }
4186 :
4187 42 : numtoread = SVAL(req->vwv+1, 0);
4188 42 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4189 :
4190 : /*
4191 : * However the requested READ size IS affected by max_send. Insanity.... JRA.
4192 : */
4193 42 : maxtoread = req->xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4194 :
4195 42 : if (numtoread > maxtoread) {
4196 7 : DBG_WARNING("requested read size (%zu) is greater than "
4197 : "maximum allowed (%zu/%d). "
4198 : "Returning short read of maximum allowed for "
4199 : "compatibility with Windows 2000.\n",
4200 : numtoread,
4201 : maxtoread,
4202 : req->xconn->smb1.sessions.max_send);
4203 6 : numtoread = maxtoread;
4204 : }
4205 :
4206 42 : reply_outbuf(req, 5, numtoread + 3);
4207 :
4208 42 : data = smb_buf(req->outbuf) + 3;
4209 :
4210 42 : nread = read_file(fsp,data,startpos,numtoread);
4211 :
4212 42 : if (nread < 0) {
4213 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4214 0 : goto send;
4215 : }
4216 :
4217 42 : srv_set_message((char *)req->outbuf, 5, nread+3, False);
4218 :
4219 42 : SSVAL(req->outbuf,smb_vwv0,nread);
4220 42 : SSVAL(req->outbuf,smb_vwv5,nread+3);
4221 42 : p = smb_buf(req->outbuf);
4222 42 : SCVAL(p,0,0); /* pad byte. */
4223 42 : SSVAL(p,1,nread);
4224 :
4225 42 : DEBUG(3,("lockread %s num=%d nread=%d\n",
4226 : fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4227 :
4228 84 : send:
4229 228 : ok = srv_send_smb(req->xconn,
4230 84 : (char *)req->outbuf,
4231 : true,
4232 84 : req->seqnum+1,
4233 84 : IS_CONN_ENCRYPTED(req->conn),
4234 : NULL);
4235 84 : if (!ok) {
4236 0 : exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
4237 : }
4238 84 : TALLOC_FREE(req);
4239 84 : END_PROFILE(SMBlockread);
4240 84 : return;
4241 : }
4242 :
4243 : #undef DBGC_CLASS
4244 : #define DBGC_CLASS DBGC_ALL
4245 :
4246 : /****************************************************************************
4247 : Reply to a read.
4248 : ****************************************************************************/
4249 :
4250 56 : void reply_read(struct smb_request *req)
4251 : {
4252 56 : connection_struct *conn = req->conn;
4253 : size_t numtoread;
4254 : size_t maxtoread;
4255 56 : ssize_t nread = 0;
4256 : char *data;
4257 : off_t startpos;
4258 : files_struct *fsp;
4259 : struct lock_struct lock;
4260 56 : struct smbXsrv_connection *xconn = req->xconn;
4261 :
4262 56 : START_PROFILE(SMBread);
4263 :
4264 56 : if (req->wct < 3) {
4265 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4266 0 : END_PROFILE(SMBread);
4267 0 : return;
4268 : }
4269 :
4270 56 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4271 :
4272 56 : if (!check_fsp(conn, req, fsp)) {
4273 7 : END_PROFILE(SMBread);
4274 6 : return;
4275 : }
4276 :
4277 49 : if (!CHECK_READ(fsp,req)) {
4278 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4279 0 : END_PROFILE(SMBread);
4280 0 : return;
4281 : }
4282 :
4283 49 : numtoread = SVAL(req->vwv+1, 0);
4284 49 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4285 :
4286 : /*
4287 : * The requested read size cannot be greater than max_send. JRA.
4288 : */
4289 49 : maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4290 :
4291 49 : if (numtoread > maxtoread) {
4292 14 : DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
4293 : Returning short read of maximum allowed for compatibility with Windows 2000.\n",
4294 : (unsigned int)numtoread, (unsigned int)maxtoread,
4295 : (unsigned int)xconn->smb1.sessions.max_send));
4296 12 : numtoread = maxtoread;
4297 : }
4298 :
4299 49 : reply_outbuf(req, 5, numtoread+3);
4300 :
4301 49 : data = smb_buf(req->outbuf) + 3;
4302 :
4303 49 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4304 : (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
4305 : &lock);
4306 :
4307 49 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4308 7 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4309 7 : END_PROFILE(SMBread);
4310 6 : return;
4311 : }
4312 :
4313 42 : if (numtoread > 0)
4314 35 : nread = read_file(fsp,data,startpos,numtoread);
4315 :
4316 41 : if (nread < 0) {
4317 0 : reply_nterror(req, map_nt_error_from_unix(errno));
4318 0 : goto out;
4319 : }
4320 :
4321 42 : srv_set_message((char *)req->outbuf, 5, nread+3, False);
4322 :
4323 42 : SSVAL(req->outbuf,smb_vwv0,nread);
4324 42 : SSVAL(req->outbuf,smb_vwv5,nread+3);
4325 42 : SCVAL(smb_buf(req->outbuf),0,1);
4326 42 : SSVAL(smb_buf(req->outbuf),1,nread);
4327 :
4328 42 : DEBUG(3, ("read %s num=%d nread=%d\n",
4329 : fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4330 :
4331 42 : out:
4332 42 : END_PROFILE(SMBread);
4333 36 : return;
4334 : }
4335 :
4336 : /****************************************************************************
4337 : Setup readX header.
4338 : ****************************************************************************/
4339 :
4340 9401 : size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
4341 : {
4342 : size_t outsize;
4343 :
4344 9401 : outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
4345 : False);
4346 :
4347 9446 : memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
4348 :
4349 9401 : SCVAL(outbuf,smb_vwv0,0xFF);
4350 9401 : SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
4351 9401 : SSVAL(outbuf,smb_vwv5,smb_maxcnt);
4352 9401 : SSVAL(outbuf,smb_vwv6,
4353 : (smb_wct - 4) /* offset from smb header to wct */
4354 : + 1 /* the wct field */
4355 : + 12 * sizeof(uint16_t) /* vwv */
4356 : + 2 /* the buflen field */
4357 : + 1); /* padding byte */
4358 9401 : SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
4359 9401 : SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
4360 : /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
4361 9401 : _smb_setlen_large(outbuf,
4362 : smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
4363 9401 : return outsize;
4364 : }
4365 :
4366 : /****************************************************************************
4367 : Reply to a read and X - possibly using sendfile.
4368 : ****************************************************************************/
4369 :
4370 65 : static void send_file_readX(connection_struct *conn, struct smb_request *req,
4371 : files_struct *fsp, off_t startpos,
4372 : size_t smb_maxcnt)
4373 : {
4374 65 : struct smbXsrv_connection *xconn = req->xconn;
4375 65 : ssize_t nread = -1;
4376 : struct lock_struct lock;
4377 65 : int saved_errno = 0;
4378 : NTSTATUS status;
4379 :
4380 65 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4381 : (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
4382 : &lock);
4383 :
4384 65 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4385 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4386 0 : return;
4387 : }
4388 :
4389 : /*
4390 : * We can only use sendfile on a non-chained packet
4391 : * but we can use on a non-oplocked file. tridge proved this
4392 : * on a train in Germany :-). JRA.
4393 : */
4394 :
4395 112 : if (!req_is_in_chain(req) &&
4396 102 : !req->encrypted &&
4397 82 : (fsp->base_fsp == NULL) &&
4398 27 : lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
4399 : uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
4400 : DATA_BLOB header;
4401 :
4402 0 : status = vfs_stat_fsp(fsp);
4403 0 : if (!NT_STATUS_IS_OK(status)) {
4404 0 : reply_nterror(req, status);
4405 0 : goto out;
4406 : }
4407 :
4408 0 : if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4409 0 : (startpos > fsp->fsp_name->st.st_ex_size) ||
4410 0 : (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4411 : /*
4412 : * We already know that we would do a short read, so don't
4413 : * try the sendfile() path.
4414 : */
4415 0 : goto nosendfile_read;
4416 : }
4417 :
4418 : /*
4419 : * Set up the packet header before send. We
4420 : * assume here the sendfile will work (get the
4421 : * correct amount of data).
4422 : */
4423 :
4424 0 : header = data_blob_const(headerbuf, sizeof(headerbuf));
4425 :
4426 0 : construct_reply_common_req(req, (char *)headerbuf);
4427 0 : setup_readX_header((char *)headerbuf, smb_maxcnt);
4428 :
4429 0 : nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4430 : startpos, smb_maxcnt);
4431 0 : if (nread == -1) {
4432 0 : saved_errno = errno;
4433 :
4434 : /* Returning ENOSYS means no data at all was sent.
4435 : Do this as a normal read. */
4436 0 : if (errno == ENOSYS) {
4437 0 : goto normal_read;
4438 : }
4439 :
4440 : /*
4441 : * Special hack for broken Linux with no working sendfile. If we
4442 : * return EINTR we sent the header but not the rest of the data.
4443 : * Fake this up by doing read/write calls.
4444 : */
4445 :
4446 0 : if (errno == EINTR) {
4447 : /* Ensure we don't do this again. */
4448 0 : set_use_sendfile(SNUM(conn), False);
4449 0 : DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4450 0 : nread = fake_sendfile(xconn, fsp, startpos,
4451 : smb_maxcnt);
4452 0 : if (nread == -1) {
4453 0 : saved_errno = errno;
4454 0 : DEBUG(0,("send_file_readX: "
4455 : "fake_sendfile failed for "
4456 : "file %s (%s) for client %s. "
4457 : "Terminating\n",
4458 : fsp_str_dbg(fsp),
4459 : smbXsrv_connection_dbg(xconn),
4460 : strerror(saved_errno)));
4461 0 : errno = saved_errno;
4462 0 : exit_server_cleanly("send_file_readX: fake_sendfile failed");
4463 : }
4464 0 : DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4465 : fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4466 : /* No outbuf here means successful sendfile. */
4467 0 : goto out;
4468 : }
4469 :
4470 0 : DEBUG(0,("send_file_readX: sendfile failed for file "
4471 : "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4472 : strerror(errno)));
4473 0 : exit_server_cleanly("send_file_readX sendfile failed");
4474 0 : } else if (nread == 0) {
4475 : /*
4476 : * Some sendfile implementations return 0 to indicate
4477 : * that there was a short read, but nothing was
4478 : * actually written to the socket. In this case,
4479 : * fallback to the normal read path so the header gets
4480 : * the correct byte count.
4481 : */
4482 0 : DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4483 : "falling back to the normal read: %s\n",
4484 : fsp_str_dbg(fsp)));
4485 0 : goto normal_read;
4486 : }
4487 :
4488 0 : DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4489 : fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4490 :
4491 : /* Deal with possible short send. */
4492 0 : if (nread != smb_maxcnt + sizeof(headerbuf)) {
4493 : ssize_t ret;
4494 :
4495 0 : ret = sendfile_short_send(xconn, fsp, nread,
4496 : sizeof(headerbuf), smb_maxcnt);
4497 0 : if (ret == -1) {
4498 : const char *r;
4499 0 : r = "send_file_readX: sendfile_short_send failed";
4500 0 : DEBUG(0,("%s for file %s (%s).\n",
4501 : r, fsp_str_dbg(fsp), strerror(errno)));
4502 0 : exit_server_cleanly(r);
4503 : }
4504 : }
4505 : /* No outbuf here means successful sendfile. */
4506 0 : SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4507 0 : SMB_PERFCOUNT_END(&req->pcd);
4508 0 : goto out;
4509 : }
4510 :
4511 117 : normal_read:
4512 :
4513 65 : if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4514 : uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4515 : ssize_t ret;
4516 :
4517 24 : if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4518 24 : (startpos > fsp->fsp_name->st.st_ex_size) ||
4519 12 : (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4520 : /*
4521 : * We already know that we would do a short
4522 : * read, so don't try the sendfile() path.
4523 : */
4524 0 : goto nosendfile_read;
4525 : }
4526 :
4527 12 : construct_reply_common_req(req, (char *)headerbuf);
4528 12 : setup_readX_header((char *)headerbuf, smb_maxcnt);
4529 :
4530 : /* Send out the header. */
4531 12 : ret = write_data(xconn->transport.sock, (char *)headerbuf,
4532 : sizeof(headerbuf));
4533 12 : if (ret != sizeof(headerbuf)) {
4534 0 : saved_errno = errno;
4535 : /*
4536 : * Try and give an error message saying what
4537 : * client failed.
4538 : */
4539 0 : DEBUG(0,("send_file_readX: write_data failed for file "
4540 : "%s (%s) for client %s. Terminating\n",
4541 : fsp_str_dbg(fsp),
4542 : smbXsrv_connection_dbg(xconn),
4543 : strerror(saved_errno)));
4544 0 : errno = saved_errno;
4545 0 : exit_server_cleanly("send_file_readX sendfile failed");
4546 : }
4547 12 : nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4548 12 : if (nread == -1) {
4549 0 : saved_errno = errno;
4550 0 : DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4551 : "%s (%s) for client %s. Terminating\n",
4552 : fsp_str_dbg(fsp),
4553 : smbXsrv_connection_dbg(xconn),
4554 : strerror(saved_errno)));
4555 0 : errno = saved_errno;
4556 0 : exit_server_cleanly("send_file_readX: fake_sendfile failed");
4557 : }
4558 12 : goto out;
4559 : }
4560 :
4561 93 : nosendfile_read:
4562 :
4563 53 : reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4564 53 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4565 53 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4566 :
4567 53 : nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4568 : startpos, smb_maxcnt);
4569 53 : saved_errno = errno;
4570 :
4571 53 : if (nread < 0) {
4572 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
4573 0 : return;
4574 : }
4575 :
4576 53 : setup_readX_header((char *)req->outbuf, nread);
4577 :
4578 53 : DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4579 : fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4580 50 : return;
4581 :
4582 12 : out:
4583 12 : TALLOC_FREE(req->outbuf);
4584 12 : return;
4585 : }
4586 :
4587 : /****************************************************************************
4588 : Work out how much space we have for a read return.
4589 : ****************************************************************************/
4590 :
4591 9422 : static size_t calc_max_read_pdu(const struct smb_request *req)
4592 : {
4593 9422 : struct smbXsrv_connection *xconn = req->xconn;
4594 :
4595 9422 : if (xconn->protocol < PROTOCOL_NT1) {
4596 0 : return xconn->smb1.sessions.max_send;
4597 : }
4598 :
4599 9422 : if (!lp_large_readwrite()) {
4600 0 : return xconn->smb1.sessions.max_send;
4601 : }
4602 :
4603 9422 : if (req_is_in_chain(req)) {
4604 10 : return xconn->smb1.sessions.max_send;
4605 : }
4606 :
4607 9412 : if (req->encrypted) {
4608 : /*
4609 : * Don't take encrypted traffic up to the
4610 : * limit. There are padding considerations
4611 : * that make that tricky.
4612 : */
4613 3001 : return xconn->smb1.sessions.max_send;
4614 : }
4615 :
4616 6411 : if (srv_is_signing_active(xconn)) {
4617 909 : return 0x1FFFF;
4618 : }
4619 :
4620 5458 : if (!lp_unix_extensions()) {
4621 0 : return 0x1FFFF;
4622 : }
4623 :
4624 : /*
4625 : * We can do ultra-large POSIX reads.
4626 : */
4627 5458 : return 0xFFFFFF;
4628 : }
4629 :
4630 : /****************************************************************************
4631 : Calculate how big a read can be. Copes with all clients. It's always
4632 : safe to return a short read - Windows does this.
4633 : ****************************************************************************/
4634 :
4635 9422 : static size_t calc_read_size(const struct smb_request *req,
4636 : size_t upper_size,
4637 : size_t lower_size)
4638 : {
4639 9422 : struct smbXsrv_connection *xconn = req->xconn;
4640 9422 : size_t max_pdu = calc_max_read_pdu(req);
4641 9422 : size_t total_size = 0;
4642 9422 : size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4643 9422 : size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4644 :
4645 : /*
4646 : * Windows explicitly ignores upper size of 0xFFFF.
4647 : * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4648 : * We must do the same as these will never fit even in
4649 : * an extended size NetBIOS packet.
4650 : */
4651 9422 : if (upper_size == 0xFFFF) {
4652 6 : upper_size = 0;
4653 : }
4654 :
4655 9422 : if (xconn->protocol < PROTOCOL_NT1) {
4656 0 : upper_size = 0;
4657 : }
4658 :
4659 9422 : total_size = ((upper_size<<16) | lower_size);
4660 :
4661 : /*
4662 : * LARGE_READX test shows it's always safe to return
4663 : * a short read. Windows does so.
4664 : */
4665 9422 : return MIN(total_size, max_len);
4666 : }
4667 :
4668 : /****************************************************************************
4669 : Reply to a read and X.
4670 : ****************************************************************************/
4671 :
4672 9836 : void reply_read_and_X(struct smb_request *req)
4673 : {
4674 9836 : connection_struct *conn = req->conn;
4675 : files_struct *fsp;
4676 : off_t startpos;
4677 : size_t smb_maxcnt;
4678 : size_t upper_size;
4679 9836 : bool big_readX = False;
4680 : #if 0
4681 : size_t smb_mincnt = SVAL(req->vwv+6, 0);
4682 : #endif
4683 :
4684 9836 : START_PROFILE(SMBreadX);
4685 :
4686 9836 : if ((req->wct != 10) && (req->wct != 12)) {
4687 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4688 0 : return;
4689 : }
4690 :
4691 9836 : fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4692 9836 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4693 9836 : smb_maxcnt = SVAL(req->vwv+5, 0);
4694 :
4695 : /* If it's an IPC, pass off the pipe handler. */
4696 9836 : if (IS_IPC(conn)) {
4697 28 : reply_pipe_read_and_X(req);
4698 28 : END_PROFILE(SMBreadX);
4699 28 : return;
4700 : }
4701 :
4702 9808 : if (!check_fsp(conn, req, fsp)) {
4703 39 : END_PROFILE(SMBreadX);
4704 38 : return;
4705 : }
4706 :
4707 9769 : if (!CHECK_READ(fsp,req)) {
4708 347 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4709 347 : END_PROFILE(SMBreadX);
4710 345 : return;
4711 : }
4712 :
4713 9422 : upper_size = SVAL(req->vwv+7, 0);
4714 9422 : smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4715 9422 : if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4716 : /*
4717 : * This is a heuristic to avoid keeping large
4718 : * outgoing buffers around over long-lived aio
4719 : * requests.
4720 : */
4721 12 : big_readX = True;
4722 : }
4723 :
4724 9422 : if (req->wct == 12) {
4725 : /*
4726 : * This is a large offset (64 bit) read.
4727 : */
4728 9422 : startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4729 :
4730 : }
4731 :
4732 9422 : if (!big_readX) {
4733 9410 : NTSTATUS status = schedule_aio_read_and_X(conn,
4734 : req,
4735 : fsp,
4736 : startpos,
4737 : smb_maxcnt);
4738 9410 : if (NT_STATUS_IS_OK(status)) {
4739 : /* Read scheduled - we're done. */
4740 9294 : goto out;
4741 : }
4742 74 : if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4743 : /* Real error - report to client. */
4744 21 : END_PROFILE(SMBreadX);
4745 21 : reply_nterror(req, status);
4746 21 : return;
4747 : }
4748 : /* NT_STATUS_RETRY - fall back to sync read. */
4749 : }
4750 :
4751 65 : smbd_lock_socket(req->xconn);
4752 65 : send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4753 65 : smbd_unlock_socket(req->xconn);
4754 :
4755 9401 : out:
4756 9401 : END_PROFILE(SMBreadX);
4757 9356 : return;
4758 : }
4759 :
4760 : /****************************************************************************
4761 : Error replies to writebraw must have smb_wct == 1. Fix this up.
4762 : ****************************************************************************/
4763 :
4764 0 : void error_to_writebrawerr(struct smb_request *req)
4765 : {
4766 0 : uint8_t *old_outbuf = req->outbuf;
4767 :
4768 0 : reply_outbuf(req, 1, 0);
4769 :
4770 0 : memcpy(req->outbuf, old_outbuf, smb_size);
4771 0 : TALLOC_FREE(old_outbuf);
4772 0 : }
4773 :
4774 : /****************************************************************************
4775 : Read 4 bytes of a smb packet and return the smb length of the packet.
4776 : Store the result in the buffer. This version of the function will
4777 : never return a session keepalive (length of zero).
4778 : Timeout is in milliseconds.
4779 : ****************************************************************************/
4780 :
4781 0 : static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4782 : size_t *len)
4783 : {
4784 0 : uint8_t msgtype = NBSSkeepalive;
4785 :
4786 0 : while (msgtype == NBSSkeepalive) {
4787 : NTSTATUS status;
4788 :
4789 0 : status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4790 : len);
4791 0 : if (!NT_STATUS_IS_OK(status)) {
4792 : char addr[INET6_ADDRSTRLEN];
4793 : /* Try and give an error message
4794 : * saying what client failed. */
4795 0 : DEBUG(0, ("read_smb_length_return_keepalive failed for "
4796 : "client %s read error = %s.\n",
4797 : get_peer_addr(fd,addr,sizeof(addr)),
4798 : nt_errstr(status)));
4799 0 : return status;
4800 : }
4801 :
4802 0 : msgtype = CVAL(inbuf, 0);
4803 : }
4804 :
4805 0 : DEBUG(10,("read_smb_length: got smb length of %lu\n",
4806 : (unsigned long)len));
4807 :
4808 0 : return NT_STATUS_OK;
4809 : }
4810 :
4811 : /****************************************************************************
4812 : Reply to a writebraw (core+ or LANMAN1.0 protocol).
4813 : ****************************************************************************/
4814 :
4815 0 : void reply_writebraw(struct smb_request *req)
4816 : {
4817 0 : connection_struct *conn = req->conn;
4818 0 : struct smbXsrv_connection *xconn = req->xconn;
4819 0 : char *buf = NULL;
4820 0 : ssize_t nwritten=0;
4821 0 : ssize_t total_written=0;
4822 0 : size_t numtowrite=0;
4823 : size_t tcount;
4824 : off_t startpos;
4825 0 : const char *data=NULL;
4826 : bool write_through;
4827 : files_struct *fsp;
4828 : struct lock_struct lock;
4829 : NTSTATUS status;
4830 :
4831 0 : START_PROFILE(SMBwritebraw);
4832 :
4833 : /*
4834 : * If we ever reply with an error, it must have the SMB command
4835 : * type of SMBwritec, not SMBwriteBraw, as this tells the client
4836 : * we're finished.
4837 : */
4838 0 : SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4839 :
4840 0 : if (srv_is_signing_active(xconn)) {
4841 0 : END_PROFILE(SMBwritebraw);
4842 0 : exit_server_cleanly("reply_writebraw: SMB signing is active - "
4843 : "raw reads/writes are disallowed.");
4844 : }
4845 :
4846 0 : if (req->wct < 12) {
4847 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4848 0 : error_to_writebrawerr(req);
4849 0 : END_PROFILE(SMBwritebraw);
4850 0 : return;
4851 : }
4852 :
4853 0 : if (xconn->smb1.echo_handler.trusted_fde) {
4854 0 : DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4855 : "'async smb echo handler = yes'\n"));
4856 0 : reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4857 0 : error_to_writebrawerr(req);
4858 0 : END_PROFILE(SMBwritebraw);
4859 0 : return;
4860 : }
4861 :
4862 0 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4863 0 : if (!check_fsp(conn, req, fsp)) {
4864 0 : error_to_writebrawerr(req);
4865 0 : END_PROFILE(SMBwritebraw);
4866 0 : return;
4867 : }
4868 :
4869 0 : if (!CHECK_WRITE(fsp)) {
4870 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4871 0 : error_to_writebrawerr(req);
4872 0 : END_PROFILE(SMBwritebraw);
4873 0 : return;
4874 : }
4875 :
4876 0 : tcount = IVAL(req->vwv+1, 0);
4877 0 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4878 0 : write_through = BITSETW(req->vwv+7,0);
4879 :
4880 : /* We have to deal with slightly different formats depending
4881 : on whether we are using the core+ or lanman1.0 protocol */
4882 :
4883 0 : if(get_Protocol() <= PROTOCOL_COREPLUS) {
4884 0 : numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4885 0 : data = smb_buf_const(req->inbuf);
4886 : } else {
4887 0 : numtowrite = SVAL(req->vwv+10, 0);
4888 0 : data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4889 : }
4890 :
4891 : /* Ensure we don't write bytes past the end of this packet. */
4892 : /*
4893 : * This already protects us against CVE-2017-12163.
4894 : */
4895 0 : if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4896 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4897 0 : error_to_writebrawerr(req);
4898 0 : END_PROFILE(SMBwritebraw);
4899 0 : return;
4900 : }
4901 :
4902 0 : if (!fsp->print_file) {
4903 0 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4904 : (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4905 : &lock);
4906 :
4907 0 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4908 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4909 0 : error_to_writebrawerr(req);
4910 0 : END_PROFILE(SMBwritebraw);
4911 0 : return;
4912 : }
4913 : }
4914 :
4915 0 : if (numtowrite>0) {
4916 0 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
4917 : }
4918 :
4919 0 : DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4920 : "wrote=%d sync=%d\n",
4921 : fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4922 : (int)nwritten, (int)write_through));
4923 :
4924 0 : if (nwritten < (ssize_t)numtowrite) {
4925 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
4926 0 : error_to_writebrawerr(req);
4927 0 : goto out;
4928 : }
4929 :
4930 0 : total_written = nwritten;
4931 :
4932 : /* Allocate a buffer of 64k + length. */
4933 0 : buf = talloc_array(NULL, char, 65540);
4934 0 : if (!buf) {
4935 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
4936 0 : error_to_writebrawerr(req);
4937 0 : goto out;
4938 : }
4939 :
4940 : /* Return a SMBwritebraw message to the redirector to tell
4941 : * it to send more bytes */
4942 :
4943 0 : memcpy(buf, req->inbuf, smb_size);
4944 0 : srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4945 0 : SCVAL(buf,smb_com,SMBwritebraw);
4946 0 : SSVALS(buf,smb_vwv0,0xFFFF);
4947 0 : show_msg(buf);
4948 0 : if (!srv_send_smb(req->xconn,
4949 : buf,
4950 : false, 0, /* no signing */
4951 0 : IS_CONN_ENCRYPTED(conn),
4952 : &req->pcd)) {
4953 0 : exit_server_cleanly("reply_writebraw: srv_send_smb "
4954 : "failed.");
4955 : }
4956 :
4957 : /* Now read the raw data into the buffer and write it */
4958 0 : status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4959 : &numtowrite);
4960 0 : if (!NT_STATUS_IS_OK(status)) {
4961 0 : exit_server_cleanly("secondary writebraw failed");
4962 : }
4963 :
4964 : /* Set up outbuf to return the correct size */
4965 0 : reply_outbuf(req, 1, 0);
4966 :
4967 0 : if (numtowrite != 0) {
4968 :
4969 0 : if (numtowrite > 0xFFFF) {
4970 0 : DEBUG(0,("reply_writebraw: Oversize secondary write "
4971 : "raw requested (%u). Terminating\n",
4972 : (unsigned int)numtowrite ));
4973 0 : exit_server_cleanly("secondary writebraw failed");
4974 : }
4975 :
4976 0 : if (tcount > nwritten+numtowrite) {
4977 0 : DEBUG(3,("reply_writebraw: Client overestimated the "
4978 : "write %d %d %d\n",
4979 : (int)tcount,(int)nwritten,(int)numtowrite));
4980 : }
4981 :
4982 0 : status = read_data_ntstatus(xconn->transport.sock, buf+4,
4983 : numtowrite);
4984 :
4985 0 : if (!NT_STATUS_IS_OK(status)) {
4986 : /* Try and give an error message
4987 : * saying what client failed. */
4988 0 : DEBUG(0, ("reply_writebraw: Oversize secondary write "
4989 : "raw read failed (%s) for client %s. "
4990 : "Terminating\n", nt_errstr(status),
4991 : smbXsrv_connection_dbg(xconn)));
4992 0 : exit_server_cleanly("secondary writebraw failed");
4993 : }
4994 :
4995 : /*
4996 : * We are not vulnerable to CVE-2017-12163
4997 : * here as we are guaranteed to have numtowrite
4998 : * bytes available - we just read from the client.
4999 : */
5000 0 : nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
5001 0 : if (nwritten == -1) {
5002 0 : TALLOC_FREE(buf);
5003 0 : reply_nterror(req, map_nt_error_from_unix(errno));
5004 0 : error_to_writebrawerr(req);
5005 0 : goto out;
5006 : }
5007 :
5008 0 : if (nwritten < (ssize_t)numtowrite) {
5009 0 : SCVAL(req->outbuf,smb_rcls,ERRHRD);
5010 0 : SSVAL(req->outbuf,smb_err,ERRdiskfull);
5011 : }
5012 :
5013 0 : if (nwritten > 0) {
5014 0 : total_written += nwritten;
5015 : }
5016 : }
5017 :
5018 0 : TALLOC_FREE(buf);
5019 0 : SSVAL(req->outbuf,smb_vwv0,total_written);
5020 :
5021 0 : status = sync_file(conn, fsp, write_through);
5022 0 : if (!NT_STATUS_IS_OK(status)) {
5023 0 : DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
5024 : fsp_str_dbg(fsp), nt_errstr(status)));
5025 0 : reply_nterror(req, status);
5026 0 : error_to_writebrawerr(req);
5027 0 : goto out;
5028 : }
5029 :
5030 0 : DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
5031 : "wrote=%d\n",
5032 : fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
5033 : (int)total_written));
5034 :
5035 : /* We won't return a status if write through is not selected - this
5036 : * follows what WfWg does */
5037 0 : END_PROFILE(SMBwritebraw);
5038 :
5039 0 : if (!write_through && total_written==tcount) {
5040 :
5041 : #if RABBIT_PELLET_FIX
5042 : /*
5043 : * Fix for "rabbit pellet" mode, trigger an early TCP ack by
5044 : * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
5045 : * JRA.
5046 : */
5047 0 : if (!send_keepalive(xconn->transport.sock)) {
5048 0 : exit_server_cleanly("reply_writebraw: send of "
5049 : "keepalive failed");
5050 : }
5051 : #endif
5052 0 : TALLOC_FREE(req->outbuf);
5053 : }
5054 0 : return;
5055 :
5056 0 : out:
5057 0 : END_PROFILE(SMBwritebraw);
5058 0 : return;
5059 : }
5060 :
5061 : #undef DBGC_CLASS
5062 : #define DBGC_CLASS DBGC_LOCKING
5063 :
5064 : /****************************************************************************
5065 : Reply to a writeunlock (core+).
5066 : ****************************************************************************/
5067 :
5068 35 : void reply_writeunlock(struct smb_request *req)
5069 : {
5070 35 : connection_struct *conn = req->conn;
5071 35 : ssize_t nwritten = -1;
5072 : size_t numtowrite;
5073 : size_t remaining;
5074 : off_t startpos;
5075 : const char *data;
5076 35 : NTSTATUS status = NT_STATUS_OK;
5077 : files_struct *fsp;
5078 : struct lock_struct lock;
5079 35 : int saved_errno = 0;
5080 :
5081 35 : START_PROFILE(SMBwriteunlock);
5082 :
5083 35 : if (req->wct < 5) {
5084 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5085 0 : END_PROFILE(SMBwriteunlock);
5086 0 : return;
5087 : }
5088 :
5089 35 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5090 :
5091 35 : if (!check_fsp(conn, req, fsp)) {
5092 5 : END_PROFILE(SMBwriteunlock);
5093 4 : return;
5094 : }
5095 :
5096 30 : if (!CHECK_WRITE(fsp)) {
5097 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5098 0 : END_PROFILE(SMBwriteunlock);
5099 0 : return;
5100 : }
5101 :
5102 30 : numtowrite = SVAL(req->vwv+1, 0);
5103 30 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5104 30 : data = (const char *)req->buf + 3;
5105 :
5106 : /*
5107 : * Ensure client isn't asking us to write more than
5108 : * they sent. CVE-2017-12163.
5109 : */
5110 30 : remaining = smbreq_bufrem(req, data);
5111 30 : if (numtowrite > remaining) {
5112 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5113 0 : END_PROFILE(SMBwriteunlock);
5114 0 : return;
5115 : }
5116 :
5117 30 : if (!fsp->print_file && numtowrite > 0) {
5118 25 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5119 : (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5120 : &lock);
5121 :
5122 25 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5123 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5124 0 : END_PROFILE(SMBwriteunlock);
5125 0 : return;
5126 : }
5127 : }
5128 :
5129 : /* The special X/Open SMB protocol handling of
5130 : zero length writes is *NOT* done for
5131 : this call */
5132 30 : if(numtowrite == 0) {
5133 4 : nwritten = 0;
5134 : } else {
5135 25 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
5136 25 : saved_errno = errno;
5137 : }
5138 :
5139 30 : status = sync_file(conn, fsp, False /* write through */);
5140 30 : if (!NT_STATUS_IS_OK(status)) {
5141 0 : DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
5142 : fsp_str_dbg(fsp), nt_errstr(status)));
5143 0 : reply_nterror(req, status);
5144 0 : goto out;
5145 : }
5146 :
5147 30 : if(nwritten < 0) {
5148 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
5149 0 : goto out;
5150 : }
5151 :
5152 30 : if((nwritten < numtowrite) && (numtowrite != 0)) {
5153 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
5154 0 : goto out;
5155 : }
5156 :
5157 30 : if (numtowrite && !fsp->print_file) {
5158 45 : struct smbd_lock_element l = {
5159 5 : .req_guid = smbd_request_guid(req, 0),
5160 25 : .smblctx = req->smbpid,
5161 : .brltype = UNLOCK_LOCK,
5162 : .offset = startpos,
5163 : .count = numtowrite,
5164 : };
5165 25 : status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
5166 25 : if (NT_STATUS_V(status)) {
5167 10 : reply_nterror(req, status);
5168 10 : goto out;
5169 : }
5170 : }
5171 :
5172 20 : reply_outbuf(req, 1, 0);
5173 :
5174 20 : SSVAL(req->outbuf,smb_vwv0,nwritten);
5175 :
5176 20 : DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
5177 : fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5178 :
5179 30 : out:
5180 30 : END_PROFILE(SMBwriteunlock);
5181 24 : return;
5182 : }
5183 :
5184 : #undef DBGC_CLASS
5185 : #define DBGC_CLASS DBGC_ALL
5186 :
5187 : /****************************************************************************
5188 : Reply to a write.
5189 : ****************************************************************************/
5190 :
5191 199 : void reply_write(struct smb_request *req)
5192 : {
5193 199 : connection_struct *conn = req->conn;
5194 : size_t numtowrite;
5195 : size_t remaining;
5196 199 : ssize_t nwritten = -1;
5197 : off_t startpos;
5198 : const char *data;
5199 : files_struct *fsp;
5200 : struct lock_struct lock;
5201 : NTSTATUS status;
5202 199 : int saved_errno = 0;
5203 :
5204 199 : START_PROFILE(SMBwrite);
5205 :
5206 199 : if (req->wct < 5) {
5207 0 : END_PROFILE(SMBwrite);
5208 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5209 0 : return;
5210 : }
5211 :
5212 : /* If it's an IPC, pass off the pipe handler. */
5213 199 : if (IS_IPC(conn)) {
5214 0 : reply_pipe_write(req);
5215 0 : END_PROFILE(SMBwrite);
5216 0 : return;
5217 : }
5218 :
5219 199 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5220 :
5221 199 : if (!check_fsp(conn, req, fsp)) {
5222 5 : END_PROFILE(SMBwrite);
5223 4 : return;
5224 : }
5225 :
5226 194 : if (!CHECK_WRITE(fsp)) {
5227 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5228 0 : END_PROFILE(SMBwrite);
5229 0 : return;
5230 : }
5231 :
5232 194 : numtowrite = SVAL(req->vwv+1, 0);
5233 194 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5234 194 : data = (const char *)req->buf + 3;
5235 :
5236 : /*
5237 : * Ensure client isn't asking us to write more than
5238 : * they sent. CVE-2017-12163.
5239 : */
5240 194 : remaining = smbreq_bufrem(req, data);
5241 194 : if (numtowrite > remaining) {
5242 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5243 0 : END_PROFILE(SMBwrite);
5244 0 : return;
5245 : }
5246 :
5247 194 : if (!fsp->print_file) {
5248 194 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5249 : (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5250 : &lock);
5251 :
5252 194 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5253 4 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5254 4 : END_PROFILE(SMBwrite);
5255 4 : return;
5256 : }
5257 : }
5258 :
5259 : /*
5260 : * X/Open SMB protocol says that if smb_vwv1 is
5261 : * zero then the file size should be extended or
5262 : * truncated to the size given in smb_vwv[2-3].
5263 : */
5264 :
5265 190 : if(numtowrite == 0) {
5266 : /*
5267 : * This is actually an allocate call, and set EOF. JRA.
5268 : */
5269 57 : nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
5270 57 : if (nwritten < 0) {
5271 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
5272 0 : goto out;
5273 : }
5274 57 : nwritten = vfs_set_filelen(fsp, (off_t)startpos);
5275 57 : if (nwritten < 0) {
5276 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
5277 0 : goto out;
5278 : }
5279 57 : trigger_write_time_update_immediate(fsp);
5280 : } else {
5281 133 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
5282 : }
5283 :
5284 190 : status = sync_file(conn, fsp, False);
5285 190 : if (!NT_STATUS_IS_OK(status)) {
5286 0 : DEBUG(5,("reply_write: sync_file for %s returned %s\n",
5287 : fsp_str_dbg(fsp), nt_errstr(status)));
5288 0 : reply_nterror(req, status);
5289 0 : goto out;
5290 : }
5291 :
5292 190 : if(nwritten < 0) {
5293 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
5294 0 : goto out;
5295 : }
5296 :
5297 190 : if((nwritten == 0) && (numtowrite != 0)) {
5298 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
5299 0 : goto out;
5300 : }
5301 :
5302 190 : reply_outbuf(req, 1, 0);
5303 :
5304 190 : SSVAL(req->outbuf,smb_vwv0,nwritten);
5305 :
5306 190 : if (nwritten < (ssize_t)numtowrite) {
5307 0 : SCVAL(req->outbuf,smb_rcls,ERRHRD);
5308 0 : SSVAL(req->outbuf,smb_err,ERRdiskfull);
5309 : }
5310 :
5311 190 : DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5312 :
5313 190 : out:
5314 190 : END_PROFILE(SMBwrite);
5315 186 : return;
5316 : }
5317 :
5318 : /****************************************************************************
5319 : Ensure a buffer is a valid writeX for recvfile purposes.
5320 : ****************************************************************************/
5321 :
5322 : #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
5323 : (2*14) + /* word count (including bcc) */ \
5324 : 1 /* pad byte */)
5325 :
5326 0 : bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
5327 : const uint8_t *inbuf)
5328 : {
5329 : size_t numtowrite;
5330 0 : unsigned int doff = 0;
5331 0 : size_t len = smb_len_large(inbuf);
5332 : uint16_t fnum;
5333 0 : struct smbXsrv_open *op = NULL;
5334 0 : struct files_struct *fsp = NULL;
5335 : NTSTATUS status;
5336 :
5337 0 : if (is_encrypted_packet(inbuf)) {
5338 : /* Can't do this on encrypted
5339 : * connections. */
5340 0 : return false;
5341 : }
5342 :
5343 0 : if (CVAL(inbuf,smb_com) != SMBwriteX) {
5344 0 : return false;
5345 : }
5346 :
5347 0 : if (CVAL(inbuf,smb_vwv0) != 0xFF ||
5348 0 : CVAL(inbuf,smb_wct) != 14) {
5349 0 : DEBUG(10,("is_valid_writeX_buffer: chained or "
5350 : "invalid word length.\n"));
5351 0 : return false;
5352 : }
5353 :
5354 0 : fnum = SVAL(inbuf, smb_vwv2);
5355 0 : status = smb1srv_open_lookup(xconn,
5356 : fnum,
5357 : 0, /* now */
5358 : &op);
5359 0 : if (!NT_STATUS_IS_OK(status)) {
5360 0 : DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
5361 0 : return false;
5362 : }
5363 0 : fsp = op->compat;
5364 0 : if (fsp == NULL) {
5365 0 : DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
5366 0 : return false;
5367 : }
5368 0 : if (fsp->conn == NULL) {
5369 0 : DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
5370 0 : return false;
5371 : }
5372 :
5373 0 : if (IS_IPC(fsp->conn)) {
5374 0 : DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
5375 0 : return false;
5376 : }
5377 0 : if (IS_PRINT(fsp->conn)) {
5378 0 : DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
5379 0 : return false;
5380 : }
5381 0 : if (fsp->base_fsp != NULL) {
5382 0 : DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
5383 0 : return false;
5384 : }
5385 0 : doff = SVAL(inbuf,smb_vwv11);
5386 :
5387 0 : numtowrite = SVAL(inbuf,smb_vwv10);
5388 :
5389 0 : if (len > doff && len - doff > 0xFFFF) {
5390 0 : numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
5391 : }
5392 :
5393 0 : if (numtowrite == 0) {
5394 0 : DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
5395 0 : return false;
5396 : }
5397 :
5398 : /* Ensure the sizes match up. */
5399 0 : if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
5400 : /* no pad byte...old smbclient :-( */
5401 0 : DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
5402 : (unsigned int)doff,
5403 : (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
5404 0 : return false;
5405 : }
5406 :
5407 0 : if (len - doff != numtowrite) {
5408 0 : DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
5409 : "len = %u, doff = %u, numtowrite = %u\n",
5410 : (unsigned int)len,
5411 : (unsigned int)doff,
5412 : (unsigned int)numtowrite ));
5413 0 : return false;
5414 : }
5415 :
5416 0 : DEBUG(10,("is_valid_writeX_buffer: true "
5417 : "len = %u, doff = %u, numtowrite = %u\n",
5418 : (unsigned int)len,
5419 : (unsigned int)doff,
5420 : (unsigned int)numtowrite ));
5421 :
5422 0 : return true;
5423 : }
5424 :
5425 : /****************************************************************************
5426 : Reply to a write and X.
5427 : ****************************************************************************/
5428 :
5429 132900 : void reply_write_and_X(struct smb_request *req)
5430 : {
5431 132900 : connection_struct *conn = req->conn;
5432 132900 : struct smbXsrv_connection *xconn = req->xconn;
5433 : files_struct *fsp;
5434 : struct lock_struct lock;
5435 : off_t startpos;
5436 : size_t numtowrite;
5437 : bool write_through;
5438 : ssize_t nwritten;
5439 : unsigned int smb_doff;
5440 : unsigned int smblen;
5441 : const char *data;
5442 : NTSTATUS status;
5443 132900 : int saved_errno = 0;
5444 :
5445 132900 : START_PROFILE(SMBwriteX);
5446 :
5447 132900 : if ((req->wct != 12) && (req->wct != 14)) {
5448 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5449 0 : goto out;
5450 : }
5451 :
5452 132900 : numtowrite = SVAL(req->vwv+10, 0);
5453 132900 : smb_doff = SVAL(req->vwv+11, 0);
5454 132900 : smblen = smb_len(req->inbuf);
5455 :
5456 132900 : if (req->unread_bytes > 0xFFFF ||
5457 132895 : (smblen > smb_doff &&
5458 132895 : smblen - smb_doff > 0xFFFF)) {
5459 1367 : numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5460 : }
5461 :
5462 132900 : if (req->unread_bytes) {
5463 : /* Can't do a recvfile write on IPC$ */
5464 0 : if (IS_IPC(conn)) {
5465 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5466 0 : goto out;
5467 : }
5468 0 : if (numtowrite != req->unread_bytes) {
5469 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5470 0 : goto out;
5471 : }
5472 : } else {
5473 : /*
5474 : * This already protects us against CVE-2017-12163.
5475 : */
5476 265508 : if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5477 132900 : smb_doff + numtowrite > smblen) {
5478 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5479 0 : goto out;
5480 : }
5481 : }
5482 :
5483 : /* If it's an IPC, pass off the pipe handler. */
5484 132900 : if (IS_IPC(conn)) {
5485 8 : if (req->unread_bytes) {
5486 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5487 0 : goto out;
5488 : }
5489 8 : reply_pipe_write_and_X(req);
5490 8 : goto out;
5491 : }
5492 :
5493 132892 : fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5494 132892 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5495 132892 : write_through = BITSETW(req->vwv+7,0);
5496 :
5497 132892 : if (!check_fsp(conn, req, fsp)) {
5498 12 : goto out;
5499 : }
5500 :
5501 132878 : if (!CHECK_WRITE(fsp)) {
5502 294 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5503 294 : goto out;
5504 : }
5505 :
5506 132584 : data = smb_base(req->inbuf) + smb_doff;
5507 :
5508 132584 : if(req->wct == 14) {
5509 : /*
5510 : * This is a large offset (64 bit) write.
5511 : */
5512 132584 : startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5513 :
5514 : }
5515 :
5516 : /* X/Open SMB protocol says that, unlike SMBwrite
5517 : if the length is zero then NO truncation is
5518 : done, just a write of zero. To truncate a file,
5519 : use SMBwrite. */
5520 :
5521 132584 : if(numtowrite == 0) {
5522 4 : nwritten = 0;
5523 : } else {
5524 132579 : if (req->unread_bytes == 0) {
5525 132579 : status = schedule_aio_write_and_X(conn,
5526 : req,
5527 : fsp,
5528 : data,
5529 : startpos,
5530 : numtowrite);
5531 :
5532 132579 : if (NT_STATUS_IS_OK(status)) {
5533 : /* write scheduled - we're done. */
5534 132442 : goto out;
5535 : }
5536 85 : if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5537 : /* Real error - report to client. */
5538 45 : reply_nterror(req, status);
5539 45 : goto out;
5540 : }
5541 : /* NT_STATUS_RETRY - fall through to sync write. */
5542 : }
5543 :
5544 40 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5545 : (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5546 : &lock);
5547 :
5548 40 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5549 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5550 0 : goto out;
5551 : }
5552 :
5553 40 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
5554 40 : saved_errno = errno;
5555 : }
5556 :
5557 44 : if(nwritten < 0) {
5558 0 : reply_nterror(req, map_nt_error_from_unix(saved_errno));
5559 0 : goto out;
5560 : }
5561 :
5562 45 : if((nwritten == 0) && (numtowrite != 0)) {
5563 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
5564 0 : goto out;
5565 : }
5566 :
5567 45 : reply_outbuf(req, 6, 0);
5568 45 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5569 45 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5570 45 : SSVAL(req->outbuf,smb_vwv2,nwritten);
5571 45 : SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5572 :
5573 45 : DEBUG(3,("writeX %s num=%d wrote=%d\n",
5574 : fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5575 :
5576 45 : status = sync_file(conn, fsp, write_through);
5577 45 : if (!NT_STATUS_IS_OK(status)) {
5578 0 : DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5579 : fsp_str_dbg(fsp), nt_errstr(status)));
5580 0 : reply_nterror(req, status);
5581 0 : goto out;
5582 : }
5583 :
5584 45 : END_PROFILE(SMBwriteX);
5585 44 : return;
5586 :
5587 132909 : out:
5588 132855 : if (req->unread_bytes) {
5589 : /* writeX failed. drain socket. */
5590 0 : if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5591 0 : req->unread_bytes) {
5592 0 : smb_panic("failed to drain pending bytes");
5593 : }
5594 0 : req->unread_bytes = 0;
5595 : }
5596 :
5597 132855 : END_PROFILE(SMBwriteX);
5598 132797 : return;
5599 : }
5600 :
5601 : /****************************************************************************
5602 : Reply to a lseek.
5603 : ****************************************************************************/
5604 :
5605 40 : void reply_lseek(struct smb_request *req)
5606 : {
5607 40 : connection_struct *conn = req->conn;
5608 : off_t startpos;
5609 40 : off_t res= -1;
5610 : int mode,umode;
5611 : files_struct *fsp;
5612 : NTSTATUS status;
5613 :
5614 40 : START_PROFILE(SMBlseek);
5615 :
5616 40 : if (req->wct < 4) {
5617 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5618 0 : END_PROFILE(SMBlseek);
5619 0 : return;
5620 : }
5621 :
5622 40 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5623 :
5624 40 : if (!check_fsp(conn, req, fsp)) {
5625 4 : return;
5626 : }
5627 :
5628 35 : mode = SVAL(req->vwv+1, 0) & 3;
5629 : /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5630 35 : startpos = (off_t)IVALS(req->vwv+2, 0);
5631 :
5632 35 : switch (mode) {
5633 8 : case 0:
5634 8 : umode = SEEK_SET;
5635 8 : res = startpos;
5636 8 : break;
5637 20 : case 1:
5638 20 : umode = SEEK_CUR;
5639 20 : res = fh_get_pos(fsp->fh) + startpos;
5640 16 : break;
5641 4 : case 2:
5642 5 : umode = SEEK_END;
5643 4 : break;
5644 0 : default:
5645 0 : umode = SEEK_SET;
5646 0 : res = startpos;
5647 0 : break;
5648 : }
5649 :
5650 28 : if (umode == SEEK_END) {
5651 5 : if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5652 0 : if(errno == EINVAL) {
5653 0 : off_t current_pos = startpos;
5654 :
5655 0 : status = vfs_stat_fsp(fsp);
5656 0 : if (!NT_STATUS_IS_OK(status)) {
5657 0 : reply_nterror(req, status);
5658 0 : END_PROFILE(SMBlseek);
5659 0 : return;
5660 : }
5661 :
5662 0 : current_pos += fsp->fsp_name->st.st_ex_size;
5663 0 : if(current_pos < 0)
5664 0 : res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5665 : }
5666 : }
5667 :
5668 5 : if(res == -1) {
5669 0 : reply_nterror(req, map_nt_error_from_unix(errno));
5670 0 : END_PROFILE(SMBlseek);
5671 0 : return;
5672 : }
5673 : }
5674 :
5675 35 : fh_set_pos(fsp->fh, res);
5676 :
5677 35 : reply_outbuf(req, 2, 0);
5678 35 : SIVAL(req->outbuf,smb_vwv0,res);
5679 :
5680 35 : DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5681 : fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5682 :
5683 35 : END_PROFILE(SMBlseek);
5684 28 : return;
5685 : }
5686 :
5687 0 : static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
5688 : void *private_data)
5689 : {
5690 0 : connection_struct *conn = talloc_get_type_abort(
5691 : private_data, connection_struct);
5692 :
5693 0 : if (conn != fsp->conn) {
5694 0 : return NULL;
5695 : }
5696 0 : if (fsp_get_io_fd(fsp) == -1) {
5697 0 : return NULL;
5698 : }
5699 0 : sync_file(conn, fsp, True /* write through */);
5700 :
5701 0 : if (fsp->fsp_flags.modified) {
5702 0 : trigger_write_time_update_immediate(fsp);
5703 : }
5704 :
5705 0 : return NULL;
5706 : }
5707 :
5708 : /****************************************************************************
5709 : Reply to a flush.
5710 : ****************************************************************************/
5711 :
5712 22 : void reply_flush(struct smb_request *req)
5713 : {
5714 22 : connection_struct *conn = req->conn;
5715 : uint16_t fnum;
5716 : files_struct *fsp;
5717 :
5718 22 : START_PROFILE(SMBflush);
5719 :
5720 22 : if (req->wct < 1) {
5721 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5722 0 : return;
5723 : }
5724 :
5725 22 : fnum = SVAL(req->vwv+0, 0);
5726 22 : fsp = file_fsp(req, fnum);
5727 :
5728 22 : if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5729 8 : return;
5730 : }
5731 :
5732 12 : if (!fsp) {
5733 5 : files_forall(req->sconn, file_sync_one_fn, conn);
5734 : } else {
5735 7 : NTSTATUS status = sync_file(conn, fsp, True);
5736 7 : if (!NT_STATUS_IS_OK(status)) {
5737 0 : DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5738 : fsp_str_dbg(fsp), nt_errstr(status)));
5739 0 : reply_nterror(req, status);
5740 0 : END_PROFILE(SMBflush);
5741 0 : return;
5742 : }
5743 7 : if (fsp->fsp_flags.modified) {
5744 7 : trigger_write_time_update_immediate(fsp);
5745 : }
5746 : }
5747 :
5748 12 : reply_outbuf(req, 0, 0);
5749 :
5750 12 : DEBUG(3,("flush\n"));
5751 12 : END_PROFILE(SMBflush);
5752 10 : return;
5753 : }
5754 :
5755 : /****************************************************************************
5756 : Reply to a exit.
5757 : conn POINTER CAN BE NULL HERE !
5758 : ****************************************************************************/
5759 :
5760 : static struct tevent_req *reply_exit_send(struct smb_request *smb1req);
5761 : static void reply_exit_done(struct tevent_req *req);
5762 :
5763 1787 : void reply_exit(struct smb_request *smb1req)
5764 : {
5765 : struct tevent_req *req;
5766 :
5767 : /*
5768 : * Don't setup the profile charge here, take
5769 : * it in reply_exit_done(). Not strictly correct
5770 : * but better than the other SMB1 async
5771 : * code that double-charges at the moment.
5772 : */
5773 1787 : req = reply_exit_send(smb1req);
5774 1787 : if (req == NULL) {
5775 : /* Not going async, profile here. */
5776 0 : START_PROFILE(SMBexit);
5777 0 : reply_force_doserror(smb1req, ERRDOS, ERRnomem);
5778 0 : END_PROFILE(SMBexit);
5779 0 : return;
5780 : }
5781 :
5782 : /* We're async. This will complete later. */
5783 1787 : tevent_req_set_callback(req, reply_exit_done, smb1req);
5784 1787 : return;
5785 : }
5786 :
5787 : struct reply_exit_state {
5788 : struct tevent_queue *wait_queue;
5789 : };
5790 :
5791 : static void reply_exit_wait_done(struct tevent_req *subreq);
5792 :
5793 : /****************************************************************************
5794 : Async SMB1 exit.
5795 : Note, on failure here we deallocate and return NULL to allow the caller to
5796 : SMB1 return an error of ERRnomem immediately.
5797 : ****************************************************************************/
5798 :
5799 1787 : static struct tevent_req *reply_exit_send(struct smb_request *smb1req)
5800 : {
5801 : struct tevent_req *req;
5802 : struct reply_exit_state *state;
5803 : struct tevent_req *subreq;
5804 : files_struct *fsp;
5805 1787 : struct smbd_server_connection *sconn = smb1req->sconn;
5806 :
5807 1787 : req = tevent_req_create(smb1req, &state,
5808 : struct reply_exit_state);
5809 1787 : if (req == NULL) {
5810 0 : return NULL;
5811 : }
5812 1787 : state->wait_queue = tevent_queue_create(state,
5813 : "reply_exit_wait_queue");
5814 1787 : if (tevent_req_nomem(state->wait_queue, req)) {
5815 0 : TALLOC_FREE(req);
5816 0 : return NULL;
5817 : }
5818 :
5819 2069 : for (fsp = sconn->files; fsp; fsp = fsp->next) {
5820 282 : if (fsp->file_pid != smb1req->smbpid) {
5821 36 : continue;
5822 : }
5823 246 : if (fsp->vuid != smb1req->vuid) {
5824 0 : continue;
5825 : }
5826 : /*
5827 : * Flag the file as close in progress.
5828 : * This will prevent any more IO being
5829 : * done on it.
5830 : */
5831 246 : fsp->fsp_flags.closing = true;
5832 :
5833 246 : if (fsp->num_aio_requests > 0) {
5834 : /*
5835 : * Now wait until all aio requests on this fsp are
5836 : * finished.
5837 : *
5838 : * We don't set a callback, as we just want to block the
5839 : * wait queue and the talloc_free() of fsp->aio_request
5840 : * will remove the item from the wait queue.
5841 : */
5842 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
5843 : sconn->ev_ctx,
5844 0 : state->wait_queue);
5845 0 : if (tevent_req_nomem(subreq, req)) {
5846 0 : TALLOC_FREE(req);
5847 0 : return NULL;
5848 : }
5849 : }
5850 : }
5851 :
5852 : /*
5853 : * Now we add our own waiter to the end of the queue,
5854 : * this way we get notified when all pending requests are finished
5855 : * and reply to the outstanding SMB1 request.
5856 : */
5857 1787 : subreq = tevent_queue_wait_send(state,
5858 : sconn->ev_ctx,
5859 1787 : state->wait_queue);
5860 1787 : if (tevent_req_nomem(subreq, req)) {
5861 0 : TALLOC_FREE(req);
5862 0 : return NULL;
5863 : }
5864 :
5865 : /*
5866 : * We're really going async - move the SMB1 request from
5867 : * a talloc stackframe above us to the conn talloc-context.
5868 : * We need this to stick around until the wait_done
5869 : * callback is invoked.
5870 : */
5871 1787 : smb1req = talloc_move(sconn, &smb1req);
5872 :
5873 1787 : tevent_req_set_callback(subreq, reply_exit_wait_done, req);
5874 :
5875 1787 : return req;
5876 : }
5877 :
5878 1787 : static void reply_exit_wait_done(struct tevent_req *subreq)
5879 : {
5880 1787 : struct tevent_req *req = tevent_req_callback_data(
5881 : subreq, struct tevent_req);
5882 :
5883 1787 : tevent_queue_wait_recv(subreq);
5884 1787 : TALLOC_FREE(subreq);
5885 1787 : tevent_req_done(req);
5886 1787 : }
5887 :
5888 1660 : static NTSTATUS reply_exit_recv(struct tevent_req *req)
5889 : {
5890 1787 : return tevent_req_simple_recv_ntstatus(req);
5891 : }
5892 :
5893 1787 : static void reply_exit_done(struct tevent_req *req)
5894 : {
5895 1787 : struct smb_request *smb1req = tevent_req_callback_data(
5896 : req, struct smb_request);
5897 1787 : struct smbd_server_connection *sconn = smb1req->sconn;
5898 1787 : struct smbXsrv_connection *xconn = smb1req->xconn;
5899 1787 : NTTIME now = timeval_to_nttime(&smb1req->request_time);
5900 1787 : struct smbXsrv_session *session = NULL;
5901 : files_struct *fsp, *next;
5902 : NTSTATUS status;
5903 :
5904 : /*
5905 : * Take the profile charge here. Not strictly
5906 : * correct but better than the other SMB1 async
5907 : * code that double-charges at the moment.
5908 : */
5909 1787 : START_PROFILE(SMBexit);
5910 :
5911 1787 : status = reply_exit_recv(req);
5912 1787 : TALLOC_FREE(req);
5913 1787 : if (!NT_STATUS_IS_OK(status)) {
5914 0 : TALLOC_FREE(smb1req);
5915 0 : END_PROFILE(SMBexit);
5916 0 : exit_server(__location__ ": reply_exit_recv failed");
5917 : return;
5918 : }
5919 :
5920 : /*
5921 : * Ensure the session is still valid.
5922 : */
5923 1787 : status = smb1srv_session_lookup(xconn,
5924 1787 : smb1req->vuid,
5925 : now,
5926 : &session);
5927 1787 : if (!NT_STATUS_IS_OK(status)) {
5928 0 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5929 0 : smb_request_done(smb1req);
5930 0 : END_PROFILE(SMBexit);
5931 : }
5932 :
5933 : /*
5934 : * Ensure the vuid is still valid - no one
5935 : * called reply_ulogoffX() in the meantime.
5936 : * reply_exit() doesn't have AS_USER set, so
5937 : * use set_current_user_info() directly.
5938 : * This is the same logic as in switch_message().
5939 : */
5940 1787 : if (session->global->auth_session_info != NULL) {
5941 4810 : set_current_user_info(
5942 1660 : session->global->auth_session_info->unix_info->sanitized_username,
5943 1787 : session->global->auth_session_info->unix_info->unix_name,
5944 1787 : session->global->auth_session_info->info->domain_name);
5945 : }
5946 :
5947 : /* No more aio - do the actual closes. */
5948 2196 : for (fsp = sconn->files; fsp; fsp = next) {
5949 : bool ok;
5950 282 : next = fsp->next;
5951 :
5952 282 : if (fsp->file_pid != smb1req->smbpid) {
5953 36 : continue;
5954 : }
5955 246 : if (fsp->vuid != smb1req->vuid) {
5956 0 : continue;
5957 : }
5958 246 : if (!fsp->fsp_flags.closing) {
5959 0 : continue;
5960 : }
5961 :
5962 : /*
5963 : * reply_exit() has the DO_CHDIR flag set.
5964 : */
5965 246 : ok = chdir_current_service(fsp->conn);
5966 246 : if (!ok) {
5967 0 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5968 0 : smb_request_done(smb1req);
5969 0 : END_PROFILE(SMBexit);
5970 : }
5971 246 : close_file(NULL, fsp, SHUTDOWN_CLOSE);
5972 : }
5973 :
5974 1787 : reply_outbuf(smb1req, 0, 0);
5975 : /*
5976 : * The following call is needed to push the
5977 : * reply data back out the socket after async
5978 : * return. Plus it frees smb1req.
5979 : */
5980 1787 : smb_request_done(smb1req);
5981 1787 : DBG_INFO("reply_exit complete\n");
5982 1787 : END_PROFILE(SMBexit);
5983 1787 : return;
5984 : }
5985 :
5986 : static struct tevent_req *reply_close_send(struct smb_request *smb1req,
5987 : files_struct *fsp);
5988 : static void reply_close_done(struct tevent_req *req);
5989 :
5990 35414 : void reply_close(struct smb_request *smb1req)
5991 : {
5992 35414 : connection_struct *conn = smb1req->conn;
5993 35414 : NTSTATUS status = NT_STATUS_OK;
5994 35414 : files_struct *fsp = NULL;
5995 35414 : START_PROFILE(SMBclose);
5996 :
5997 35414 : if (smb1req->wct < 3) {
5998 0 : reply_nterror(smb1req, NT_STATUS_INVALID_PARAMETER);
5999 0 : END_PROFILE(SMBclose);
6000 0 : return;
6001 : }
6002 :
6003 35414 : fsp = file_fsp(smb1req, SVAL(smb1req->vwv+0, 0));
6004 :
6005 : /*
6006 : * We can only use check_fsp if we know it's not a directory.
6007 : */
6008 :
6009 35414 : if (!check_fsp_open(conn, smb1req, fsp)) {
6010 2503 : reply_nterror(smb1req, NT_STATUS_INVALID_HANDLE);
6011 2503 : END_PROFILE(SMBclose);
6012 2458 : return;
6013 : }
6014 :
6015 32911 : DBG_NOTICE("Close %s fd=%d %s (numopen=%d)\n",
6016 : fsp->fsp_flags.is_directory ?
6017 : "directory" : "file",
6018 : fsp_get_pathref_fd(fsp), fsp_fnum_dbg(fsp),
6019 : conn->num_files_open);
6020 :
6021 32911 : if (!fsp->fsp_flags.is_directory) {
6022 : time_t t;
6023 :
6024 : /*
6025 : * Take care of any time sent in the close.
6026 : */
6027 :
6028 30827 : t = srv_make_unix_date3(smb1req->vwv+1);
6029 30827 : set_close_write_time(fsp, time_t_to_full_timespec(t));
6030 : }
6031 :
6032 32911 : if (fsp->num_aio_requests != 0) {
6033 : struct tevent_req *req;
6034 :
6035 0 : req = reply_close_send(smb1req, fsp);
6036 0 : if (req == NULL) {
6037 0 : status = NT_STATUS_NO_MEMORY;
6038 0 : goto done;
6039 : }
6040 : /* We're async. This will complete later. */
6041 0 : tevent_req_set_callback(req, reply_close_done, smb1req);
6042 0 : END_PROFILE(SMBclose);
6043 0 : return;
6044 : }
6045 :
6046 : /*
6047 : * close_file() returns the unix errno if an error was detected on
6048 : * close - normally this is due to a disk full error. If not then it
6049 : * was probably an I/O error.
6050 : */
6051 :
6052 32911 : status = close_file(smb1req, fsp, NORMAL_CLOSE);
6053 32911 : done:
6054 32911 : if (!NT_STATUS_IS_OK(status)) {
6055 0 : reply_nterror(smb1req, status);
6056 0 : END_PROFILE(SMBclose);
6057 0 : return;
6058 : }
6059 :
6060 32911 : reply_outbuf(smb1req, 0, 0);
6061 32911 : END_PROFILE(SMBclose);
6062 32603 : return;
6063 : }
6064 :
6065 : struct reply_close_state {
6066 : files_struct *fsp;
6067 : struct tevent_queue *wait_queue;
6068 : };
6069 :
6070 : static void reply_close_wait_done(struct tevent_req *subreq);
6071 :
6072 : /****************************************************************************
6073 : Async SMB1 close.
6074 : Note, on failure here we deallocate and return NULL to allow the caller to
6075 : SMB1 return an error of ERRnomem immediately.
6076 : ****************************************************************************/
6077 :
6078 0 : static struct tevent_req *reply_close_send(struct smb_request *smb1req,
6079 : files_struct *fsp)
6080 : {
6081 : struct tevent_req *req;
6082 : struct reply_close_state *state;
6083 : struct tevent_req *subreq;
6084 0 : struct smbd_server_connection *sconn = smb1req->sconn;
6085 :
6086 0 : req = tevent_req_create(smb1req, &state,
6087 : struct reply_close_state);
6088 0 : if (req == NULL) {
6089 0 : return NULL;
6090 : }
6091 0 : state->wait_queue = tevent_queue_create(state,
6092 : "reply_close_wait_queue");
6093 0 : if (tevent_req_nomem(state->wait_queue, req)) {
6094 0 : TALLOC_FREE(req);
6095 0 : return NULL;
6096 : }
6097 :
6098 : /*
6099 : * Flag the file as close in progress.
6100 : * This will prevent any more IO being
6101 : * done on it.
6102 : */
6103 0 : fsp->fsp_flags.closing = true;
6104 :
6105 : /*
6106 : * Now wait until all aio requests on this fsp are
6107 : * finished.
6108 : *
6109 : * We don't set a callback, as we just want to block the
6110 : * wait queue and the talloc_free() of fsp->aio_request
6111 : * will remove the item from the wait queue.
6112 : */
6113 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
6114 : sconn->ev_ctx,
6115 0 : state->wait_queue);
6116 0 : if (tevent_req_nomem(subreq, req)) {
6117 0 : TALLOC_FREE(req);
6118 0 : return NULL;
6119 : }
6120 :
6121 : /*
6122 : * Now we add our own waiter to the end of the queue,
6123 : * this way we get notified when all pending requests are finished
6124 : * and reply to the outstanding SMB1 request.
6125 : */
6126 0 : subreq = tevent_queue_wait_send(state,
6127 : sconn->ev_ctx,
6128 0 : state->wait_queue);
6129 0 : if (tevent_req_nomem(subreq, req)) {
6130 0 : TALLOC_FREE(req);
6131 0 : return NULL;
6132 : }
6133 :
6134 : /*
6135 : * We're really going async - move the SMB1 request from
6136 : * a talloc stackframe above us to the conn talloc-context.
6137 : * We need this to stick around until the wait_done
6138 : * callback is invoked.
6139 : */
6140 0 : smb1req = talloc_move(sconn, &smb1req);
6141 :
6142 0 : tevent_req_set_callback(subreq, reply_close_wait_done, req);
6143 :
6144 0 : return req;
6145 : }
6146 :
6147 0 : static void reply_close_wait_done(struct tevent_req *subreq)
6148 : {
6149 0 : struct tevent_req *req = tevent_req_callback_data(
6150 : subreq, struct tevent_req);
6151 :
6152 0 : tevent_queue_wait_recv(subreq);
6153 0 : TALLOC_FREE(subreq);
6154 0 : tevent_req_done(req);
6155 0 : }
6156 :
6157 0 : static NTSTATUS reply_close_recv(struct tevent_req *req)
6158 : {
6159 0 : return tevent_req_simple_recv_ntstatus(req);
6160 : }
6161 :
6162 0 : static void reply_close_done(struct tevent_req *req)
6163 : {
6164 0 : struct smb_request *smb1req = tevent_req_callback_data(
6165 : req, struct smb_request);
6166 0 : struct reply_close_state *state = tevent_req_data(req,
6167 : struct reply_close_state);
6168 : NTSTATUS status;
6169 :
6170 0 : status = reply_close_recv(req);
6171 0 : TALLOC_FREE(req);
6172 0 : if (!NT_STATUS_IS_OK(status)) {
6173 0 : TALLOC_FREE(smb1req);
6174 0 : exit_server(__location__ ": reply_close_recv failed");
6175 : return;
6176 : }
6177 :
6178 0 : status = close_file(smb1req, state->fsp, NORMAL_CLOSE);
6179 0 : if (NT_STATUS_IS_OK(status)) {
6180 0 : reply_outbuf(smb1req, 0, 0);
6181 : } else {
6182 0 : reply_nterror(smb1req, status);
6183 : }
6184 : /*
6185 : * The following call is needed to push the
6186 : * reply data back out the socket after async
6187 : * return. Plus it frees smb1req.
6188 : */
6189 0 : smb_request_done(smb1req);
6190 0 : }
6191 :
6192 : /****************************************************************************
6193 : Reply to a writeclose (Core+ protocol).
6194 : ****************************************************************************/
6195 :
6196 45 : void reply_writeclose(struct smb_request *req)
6197 : {
6198 45 : connection_struct *conn = req->conn;
6199 : size_t numtowrite;
6200 : size_t remaining;
6201 45 : ssize_t nwritten = -1;
6202 45 : NTSTATUS close_status = NT_STATUS_OK;
6203 : off_t startpos;
6204 : const char *data;
6205 : struct timespec mtime;
6206 : files_struct *fsp;
6207 : struct lock_struct lock;
6208 :
6209 45 : START_PROFILE(SMBwriteclose);
6210 :
6211 45 : if (req->wct < 6) {
6212 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6213 0 : END_PROFILE(SMBwriteclose);
6214 0 : return;
6215 : }
6216 :
6217 45 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6218 :
6219 45 : if (!check_fsp(conn, req, fsp)) {
6220 15 : END_PROFILE(SMBwriteclose);
6221 12 : return;
6222 : }
6223 30 : if (!CHECK_WRITE(fsp)) {
6224 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6225 0 : END_PROFILE(SMBwriteclose);
6226 0 : return;
6227 : }
6228 :
6229 30 : numtowrite = SVAL(req->vwv+1, 0);
6230 30 : startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
6231 30 : mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+4));
6232 30 : data = (const char *)req->buf + 1;
6233 :
6234 : /*
6235 : * Ensure client isn't asking us to write more than
6236 : * they sent. CVE-2017-12163.
6237 : */
6238 30 : remaining = smbreq_bufrem(req, data);
6239 30 : if (numtowrite > remaining) {
6240 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6241 0 : END_PROFILE(SMBwriteclose);
6242 0 : return;
6243 : }
6244 :
6245 30 : if (fsp->print_file == NULL) {
6246 30 : init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
6247 : (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
6248 : &lock);
6249 :
6250 30 : if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
6251 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
6252 0 : END_PROFILE(SMBwriteclose);
6253 0 : return;
6254 : }
6255 : }
6256 :
6257 30 : nwritten = write_file(req,fsp,data,startpos,numtowrite);
6258 :
6259 30 : set_close_write_time(fsp, mtime);
6260 :
6261 : /*
6262 : * More insanity. W2K only closes the file if writelen > 0.
6263 : * JRA.
6264 : */
6265 :
6266 30 : DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
6267 : fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
6268 : (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
6269 :
6270 30 : if (numtowrite) {
6271 20 : DEBUG(3,("reply_writeclose: zero length write doesn't close "
6272 : "file %s\n", fsp_str_dbg(fsp)));
6273 20 : close_status = close_file(req, fsp, NORMAL_CLOSE);
6274 20 : fsp = NULL;
6275 : }
6276 :
6277 30 : if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
6278 0 : reply_nterror(req, NT_STATUS_DISK_FULL);
6279 0 : goto out;
6280 : }
6281 :
6282 30 : if(!NT_STATUS_IS_OK(close_status)) {
6283 0 : reply_nterror(req, close_status);
6284 0 : goto out;
6285 : }
6286 :
6287 30 : reply_outbuf(req, 1, 0);
6288 :
6289 30 : SSVAL(req->outbuf,smb_vwv0,nwritten);
6290 :
6291 30 : out:
6292 :
6293 30 : END_PROFILE(SMBwriteclose);
6294 24 : return;
6295 : }
6296 :
6297 : #undef DBGC_CLASS
6298 : #define DBGC_CLASS DBGC_LOCKING
6299 :
6300 : /****************************************************************************
6301 : Reply to a lock.
6302 : ****************************************************************************/
6303 :
6304 : static void reply_lock_done(struct tevent_req *subreq);
6305 :
6306 22 : void reply_lock(struct smb_request *req)
6307 : {
6308 22 : struct tevent_req *subreq = NULL;
6309 22 : connection_struct *conn = req->conn;
6310 : files_struct *fsp;
6311 22 : struct smbd_lock_element *lck = NULL;
6312 :
6313 22 : START_PROFILE(SMBlock);
6314 :
6315 22 : if (req->wct < 5) {
6316 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6317 0 : END_PROFILE(SMBlock);
6318 0 : return;
6319 : }
6320 :
6321 22 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6322 :
6323 22 : if (!check_fsp(conn, req, fsp)) {
6324 0 : END_PROFILE(SMBlock);
6325 0 : return;
6326 : }
6327 :
6328 22 : lck = talloc(req, struct smbd_lock_element);
6329 22 : if (lck == NULL) {
6330 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6331 0 : END_PROFILE(SMBlock);
6332 0 : return;
6333 : }
6334 :
6335 22 : *lck = (struct smbd_lock_element) {
6336 22 : .req_guid = smbd_request_guid(req, 0),
6337 22 : .smblctx = req->smbpid,
6338 : .brltype = WRITE_LOCK,
6339 22 : .count = IVAL(req->vwv+1, 0),
6340 22 : .offset = IVAL(req->vwv+3, 0),
6341 : };
6342 :
6343 22 : DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
6344 : fsp_get_io_fd(fsp),
6345 : fsp_fnum_dbg(fsp),
6346 : lck->offset,
6347 : lck->count);
6348 :
6349 22 : subreq = smbd_smb1_do_locks_send(
6350 : fsp,
6351 22 : req->sconn->ev_ctx,
6352 : &req,
6353 : fsp,
6354 : 0,
6355 : false, /* large_offset */
6356 : WINDOWS_LOCK,
6357 : 1,
6358 : lck);
6359 22 : if (subreq == NULL) {
6360 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6361 0 : END_PROFILE(SMBlock);
6362 0 : return;
6363 : }
6364 22 : tevent_req_set_callback(subreq, reply_lock_done, NULL);
6365 22 : END_PROFILE(SMBlock);
6366 : }
6367 :
6368 22 : static void reply_lock_done(struct tevent_req *subreq)
6369 : {
6370 22 : struct smb_request *req = NULL;
6371 : NTSTATUS status;
6372 : bool ok;
6373 :
6374 22 : START_PROFILE(SMBlock);
6375 :
6376 22 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
6377 22 : SMB_ASSERT(ok);
6378 :
6379 22 : status = smbd_smb1_do_locks_recv(subreq);
6380 22 : TALLOC_FREE(subreq);
6381 :
6382 22 : if (NT_STATUS_IS_OK(status)) {
6383 14 : reply_outbuf(req, 0, 0);
6384 : } else {
6385 8 : reply_nterror(req, status);
6386 : }
6387 :
6388 66 : ok = srv_send_smb(req->xconn,
6389 22 : (char *)req->outbuf,
6390 : true,
6391 22 : req->seqnum+1,
6392 22 : IS_CONN_ENCRYPTED(req->conn),
6393 : NULL);
6394 22 : if (!ok) {
6395 0 : exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
6396 : }
6397 22 : TALLOC_FREE(req);
6398 22 : END_PROFILE(SMBlock);
6399 22 : }
6400 :
6401 : /****************************************************************************
6402 : Reply to a unlock.
6403 : ****************************************************************************/
6404 :
6405 22 : void reply_unlock(struct smb_request *req)
6406 : {
6407 22 : connection_struct *conn = req->conn;
6408 : NTSTATUS status;
6409 : files_struct *fsp;
6410 : struct smbd_lock_element lck;
6411 :
6412 22 : START_PROFILE(SMBunlock);
6413 :
6414 22 : if (req->wct < 5) {
6415 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6416 0 : END_PROFILE(SMBunlock);
6417 0 : return;
6418 : }
6419 :
6420 22 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6421 :
6422 22 : if (!check_fsp(conn, req, fsp)) {
6423 0 : END_PROFILE(SMBunlock);
6424 0 : return;
6425 : }
6426 :
6427 22 : lck = (struct smbd_lock_element) {
6428 22 : .req_guid = smbd_request_guid(req, 0),
6429 22 : .smblctx = req->smbpid,
6430 : .brltype = UNLOCK_LOCK,
6431 22 : .offset = IVAL(req->vwv+3, 0),
6432 22 : .count = IVAL(req->vwv+1, 0),
6433 : };
6434 :
6435 22 : status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
6436 :
6437 22 : if (!NT_STATUS_IS_OK(status)) {
6438 10 : reply_nterror(req, status);
6439 10 : END_PROFILE(SMBunlock);
6440 10 : return;
6441 : }
6442 :
6443 12 : DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
6444 : fsp_get_io_fd(fsp),
6445 : fsp_fnum_dbg(fsp),
6446 : lck.offset,
6447 : lck.count);
6448 :
6449 12 : reply_outbuf(req, 0, 0);
6450 :
6451 12 : END_PROFILE(SMBunlock);
6452 12 : return;
6453 : }
6454 :
6455 : #undef DBGC_CLASS
6456 : #define DBGC_CLASS DBGC_ALL
6457 :
6458 : /****************************************************************************
6459 : Reply to a tdis.
6460 : conn POINTER CAN BE NULL HERE !
6461 : ****************************************************************************/
6462 :
6463 : static struct tevent_req *reply_tdis_send(struct smb_request *smb1req);
6464 : static void reply_tdis_done(struct tevent_req *req);
6465 :
6466 5501 : void reply_tdis(struct smb_request *smb1req)
6467 : {
6468 5501 : connection_struct *conn = smb1req->conn;
6469 : struct tevent_req *req;
6470 :
6471 : /*
6472 : * Don't setup the profile charge here, take
6473 : * it in reply_tdis_done(). Not strictly correct
6474 : * but better than the other SMB1 async
6475 : * code that double-charges at the moment.
6476 : */
6477 :
6478 5501 : if (conn == NULL) {
6479 : /* Not going async, profile here. */
6480 16 : START_PROFILE(SMBtdis);
6481 16 : DBG_INFO("Invalid connection in tdis\n");
6482 16 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
6483 16 : END_PROFILE(SMBtdis);
6484 16 : return;
6485 : }
6486 :
6487 5485 : req = reply_tdis_send(smb1req);
6488 5485 : if (req == NULL) {
6489 : /* Not going async, profile here. */
6490 0 : START_PROFILE(SMBtdis);
6491 0 : reply_force_doserror(smb1req, ERRDOS, ERRnomem);
6492 0 : END_PROFILE(SMBtdis);
6493 0 : return;
6494 : }
6495 : /* We're async. This will complete later. */
6496 5485 : tevent_req_set_callback(req, reply_tdis_done, smb1req);
6497 5485 : return;
6498 : }
6499 :
6500 : struct reply_tdis_state {
6501 : struct tevent_queue *wait_queue;
6502 : };
6503 :
6504 : static void reply_tdis_wait_done(struct tevent_req *subreq);
6505 :
6506 : /****************************************************************************
6507 : Async SMB1 tdis.
6508 : Note, on failure here we deallocate and return NULL to allow the caller to
6509 : SMB1 return an error of ERRnomem immediately.
6510 : ****************************************************************************/
6511 :
6512 5485 : static struct tevent_req *reply_tdis_send(struct smb_request *smb1req)
6513 : {
6514 : struct tevent_req *req;
6515 : struct reply_tdis_state *state;
6516 : struct tevent_req *subreq;
6517 5485 : connection_struct *conn = smb1req->conn;
6518 : files_struct *fsp;
6519 :
6520 5485 : req = tevent_req_create(smb1req, &state,
6521 : struct reply_tdis_state);
6522 5485 : if (req == NULL) {
6523 0 : return NULL;
6524 : }
6525 5485 : state->wait_queue = tevent_queue_create(state, "reply_tdis_wait_queue");
6526 5485 : if (tevent_req_nomem(state->wait_queue, req)) {
6527 0 : TALLOC_FREE(req);
6528 0 : return NULL;
6529 : }
6530 :
6531 : /*
6532 : * Make sure that no new request will be able to use this tcon.
6533 : * This ensures that once all outstanding fsp->aio_requests
6534 : * on this tcon are done, we are safe to close it.
6535 : */
6536 5485 : conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
6537 :
6538 5570 : for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
6539 85 : if (fsp->conn != conn) {
6540 4 : continue;
6541 : }
6542 : /*
6543 : * Flag the file as close in progress.
6544 : * This will prevent any more IO being
6545 : * done on it. Not strictly needed, but
6546 : * doesn't hurt to flag it as closing.
6547 : */
6548 81 : fsp->fsp_flags.closing = true;
6549 :
6550 81 : if (fsp->num_aio_requests > 0) {
6551 : /*
6552 : * Now wait until all aio requests on this fsp are
6553 : * finished.
6554 : *
6555 : * We don't set a callback, as we just want to block the
6556 : * wait queue and the talloc_free() of fsp->aio_request
6557 : * will remove the item from the wait queue.
6558 : */
6559 0 : subreq = tevent_queue_wait_send(fsp->aio_requests,
6560 0 : conn->sconn->ev_ctx,
6561 0 : state->wait_queue);
6562 0 : if (tevent_req_nomem(subreq, req)) {
6563 0 : TALLOC_FREE(req);
6564 0 : return NULL;
6565 : }
6566 : }
6567 : }
6568 :
6569 : /*
6570 : * Now we add our own waiter to the end of the queue,
6571 : * this way we get notified when all pending requests are finished
6572 : * and reply to the outstanding SMB1 request.
6573 : */
6574 10922 : subreq = tevent_queue_wait_send(state,
6575 5485 : conn->sconn->ev_ctx,
6576 5485 : state->wait_queue);
6577 5485 : if (tevent_req_nomem(subreq, req)) {
6578 0 : TALLOC_FREE(req);
6579 0 : return NULL;
6580 : }
6581 :
6582 : /*
6583 : * We're really going async - move the SMB1 request from
6584 : * a talloc stackframe above us to the sconn talloc-context.
6585 : * We need this to stick around until the wait_done
6586 : * callback is invoked.
6587 : */
6588 5485 : smb1req = talloc_move(smb1req->sconn, &smb1req);
6589 :
6590 5485 : tevent_req_set_callback(subreq, reply_tdis_wait_done, req);
6591 :
6592 5485 : return req;
6593 : }
6594 :
6595 5485 : static void reply_tdis_wait_done(struct tevent_req *subreq)
6596 : {
6597 5485 : struct tevent_req *req = tevent_req_callback_data(
6598 : subreq, struct tevent_req);
6599 :
6600 5485 : tevent_queue_wait_recv(subreq);
6601 5485 : TALLOC_FREE(subreq);
6602 5485 : tevent_req_done(req);
6603 5485 : }
6604 :
6605 5469 : static NTSTATUS reply_tdis_recv(struct tevent_req *req)
6606 : {
6607 5485 : return tevent_req_simple_recv_ntstatus(req);
6608 : }
6609 :
6610 5485 : static void reply_tdis_done(struct tevent_req *req)
6611 : {
6612 5485 : struct smb_request *smb1req = tevent_req_callback_data(
6613 : req, struct smb_request);
6614 : NTSTATUS status;
6615 5485 : struct smbXsrv_tcon *tcon = smb1req->conn->tcon;
6616 : bool ok;
6617 :
6618 : /*
6619 : * Take the profile charge here. Not strictly
6620 : * correct but better than the other SMB1 async
6621 : * code that double-charges at the moment.
6622 : */
6623 5485 : START_PROFILE(SMBtdis);
6624 :
6625 5485 : status = reply_tdis_recv(req);
6626 5485 : TALLOC_FREE(req);
6627 5485 : if (!NT_STATUS_IS_OK(status)) {
6628 0 : TALLOC_FREE(smb1req);
6629 0 : END_PROFILE(SMBtdis);
6630 0 : exit_server(__location__ ": reply_tdis_recv failed");
6631 : return;
6632 : }
6633 :
6634 : /*
6635 : * As we've been awoken, we may have changed
6636 : * directory in the meantime.
6637 : * reply_tdis() has the DO_CHDIR flag set.
6638 : */
6639 5485 : ok = chdir_current_service(smb1req->conn);
6640 5485 : if (!ok) {
6641 0 : reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
6642 0 : smb_request_done(smb1req);
6643 0 : END_PROFILE(SMBtdis);
6644 : }
6645 :
6646 5485 : status = smbXsrv_tcon_disconnect(tcon,
6647 : smb1req->vuid);
6648 5485 : if (!NT_STATUS_IS_OK(status)) {
6649 0 : TALLOC_FREE(smb1req);
6650 0 : END_PROFILE(SMBtdis);
6651 0 : exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
6652 : return;
6653 : }
6654 :
6655 : /* smbXsrv_tcon_disconnect frees smb1req->conn. */
6656 5485 : smb1req->conn = NULL;
6657 :
6658 5485 : TALLOC_FREE(tcon);
6659 :
6660 5485 : reply_outbuf(smb1req, 0, 0);
6661 : /*
6662 : * The following call is needed to push the
6663 : * reply data back out the socket after async
6664 : * return. Plus it frees smb1req.
6665 : */
6666 5485 : smb_request_done(smb1req);
6667 5485 : END_PROFILE(SMBtdis);
6668 5437 : }
6669 :
6670 : /****************************************************************************
6671 : Reply to a echo.
6672 : conn POINTER CAN BE NULL HERE !
6673 : ****************************************************************************/
6674 :
6675 23 : void reply_echo(struct smb_request *req)
6676 : {
6677 23 : connection_struct *conn = req->conn;
6678 : struct smb_perfcount_data local_pcd;
6679 : struct smb_perfcount_data *cur_pcd;
6680 : int smb_reverb;
6681 : int seq_num;
6682 :
6683 23 : START_PROFILE(SMBecho);
6684 :
6685 23 : smb_init_perfcount_data(&local_pcd);
6686 :
6687 23 : if (req->wct < 1) {
6688 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6689 0 : END_PROFILE(SMBecho);
6690 0 : return;
6691 : }
6692 :
6693 23 : smb_reverb = SVAL(req->vwv+0, 0);
6694 :
6695 23 : reply_outbuf(req, 1, req->buflen);
6696 :
6697 : /* copy any incoming data back out */
6698 23 : if (req->buflen > 0) {
6699 21 : memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
6700 : }
6701 :
6702 23 : if (smb_reverb > 100) {
6703 0 : DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
6704 0 : smb_reverb = 100;
6705 : }
6706 :
6707 46 : for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
6708 :
6709 : /* this makes sure we catch the request pcd */
6710 23 : if (seq_num == smb_reverb) {
6711 23 : cur_pcd = &req->pcd;
6712 : } else {
6713 0 : SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
6714 0 : cur_pcd = &local_pcd;
6715 : }
6716 :
6717 23 : SSVAL(req->outbuf,smb_vwv0,seq_num);
6718 :
6719 23 : show_msg((char *)req->outbuf);
6720 67 : if (!srv_send_smb(req->xconn,
6721 23 : (char *)req->outbuf,
6722 23 : true, req->seqnum+1,
6723 23 : IS_CONN_ENCRYPTED(conn)||req->encrypted,
6724 : cur_pcd))
6725 0 : exit_server_cleanly("reply_echo: srv_send_smb failed.");
6726 : }
6727 :
6728 23 : DEBUG(3,("echo %d times\n", smb_reverb));
6729 :
6730 23 : TALLOC_FREE(req->outbuf);
6731 :
6732 23 : END_PROFILE(SMBecho);
6733 23 : return;
6734 : }
6735 :
6736 : /****************************************************************************
6737 : Reply to a printopen.
6738 : ****************************************************************************/
6739 :
6740 0 : void reply_printopen(struct smb_request *req)
6741 : {
6742 0 : connection_struct *conn = req->conn;
6743 : files_struct *fsp;
6744 : NTSTATUS status;
6745 :
6746 0 : START_PROFILE(SMBsplopen);
6747 :
6748 0 : if (req->wct < 2) {
6749 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6750 0 : END_PROFILE(SMBsplopen);
6751 0 : return;
6752 : }
6753 :
6754 0 : if (!CAN_PRINT(conn)) {
6755 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6756 0 : END_PROFILE(SMBsplopen);
6757 0 : return;
6758 : }
6759 :
6760 0 : status = file_new(req, conn, &fsp);
6761 0 : if(!NT_STATUS_IS_OK(status)) {
6762 0 : reply_nterror(req, status);
6763 0 : END_PROFILE(SMBsplopen);
6764 0 : return;
6765 : }
6766 :
6767 : /* Open for exclusive use, write only. */
6768 0 : status = print_spool_open(fsp, NULL, req->vuid);
6769 :
6770 0 : if (!NT_STATUS_IS_OK(status)) {
6771 0 : file_free(req, fsp);
6772 0 : reply_nterror(req, status);
6773 0 : END_PROFILE(SMBsplopen);
6774 0 : return;
6775 : }
6776 :
6777 0 : reply_outbuf(req, 1, 0);
6778 0 : SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
6779 :
6780 0 : DEBUG(3,("openprint fd=%d %s\n",
6781 : fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
6782 :
6783 0 : END_PROFILE(SMBsplopen);
6784 0 : return;
6785 : }
6786 :
6787 : /****************************************************************************
6788 : Reply to a printclose.
6789 : ****************************************************************************/
6790 :
6791 5 : void reply_printclose(struct smb_request *req)
6792 : {
6793 5 : connection_struct *conn = req->conn;
6794 : files_struct *fsp;
6795 : NTSTATUS status;
6796 :
6797 5 : START_PROFILE(SMBsplclose);
6798 :
6799 5 : if (req->wct < 1) {
6800 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6801 0 : END_PROFILE(SMBsplclose);
6802 0 : return;
6803 : }
6804 :
6805 5 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6806 :
6807 5 : if (!check_fsp(conn, req, fsp)) {
6808 0 : END_PROFILE(SMBsplclose);
6809 0 : return;
6810 : }
6811 :
6812 5 : if (!CAN_PRINT(conn)) {
6813 5 : reply_force_doserror(req, ERRSRV, ERRerror);
6814 5 : END_PROFILE(SMBsplclose);
6815 4 : return;
6816 : }
6817 :
6818 0 : DEBUG(3,("printclose fd=%d %s\n",
6819 : fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
6820 :
6821 0 : status = close_file(req, fsp, NORMAL_CLOSE);
6822 :
6823 0 : if(!NT_STATUS_IS_OK(status)) {
6824 0 : reply_nterror(req, status);
6825 0 : END_PROFILE(SMBsplclose);
6826 0 : return;
6827 : }
6828 :
6829 0 : reply_outbuf(req, 0, 0);
6830 :
6831 0 : END_PROFILE(SMBsplclose);
6832 0 : return;
6833 : }
6834 :
6835 : /****************************************************************************
6836 : Reply to a printqueue.
6837 : ****************************************************************************/
6838 :
6839 0 : void reply_printqueue(struct smb_request *req)
6840 : {
6841 0 : const struct loadparm_substitution *lp_sub =
6842 0 : loadparm_s3_global_substitution();
6843 0 : connection_struct *conn = req->conn;
6844 : int max_count;
6845 : int start_index;
6846 :
6847 0 : START_PROFILE(SMBsplretq);
6848 :
6849 0 : if (req->wct < 2) {
6850 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6851 0 : END_PROFILE(SMBsplretq);
6852 0 : return;
6853 : }
6854 :
6855 0 : max_count = SVAL(req->vwv+0, 0);
6856 0 : start_index = SVAL(req->vwv+1, 0);
6857 :
6858 : /* we used to allow the client to get the cnum wrong, but that
6859 : is really quite gross and only worked when there was only
6860 : one printer - I think we should now only accept it if they
6861 : get it right (tridge) */
6862 0 : if (!CAN_PRINT(conn)) {
6863 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6864 0 : END_PROFILE(SMBsplretq);
6865 0 : return;
6866 : }
6867 :
6868 0 : reply_outbuf(req, 2, 3);
6869 0 : SSVAL(req->outbuf,smb_vwv0,0);
6870 0 : SSVAL(req->outbuf,smb_vwv1,0);
6871 0 : SCVAL(smb_buf(req->outbuf),0,1);
6872 0 : SSVAL(smb_buf(req->outbuf),1,0);
6873 :
6874 0 : DEBUG(3,("printqueue start_index=%d max_count=%d\n",
6875 : start_index, max_count));
6876 :
6877 : {
6878 0 : TALLOC_CTX *mem_ctx = talloc_tos();
6879 : NTSTATUS status;
6880 : WERROR werr;
6881 0 : const char *sharename = lp_servicename(mem_ctx, lp_sub, SNUM(conn));
6882 0 : struct rpc_pipe_client *cli = NULL;
6883 0 : struct dcerpc_binding_handle *b = NULL;
6884 : struct policy_handle handle;
6885 : struct spoolss_DevmodeContainer devmode_ctr;
6886 : union spoolss_JobInfo *info;
6887 : uint32_t count;
6888 : uint32_t num_to_get;
6889 : uint32_t first;
6890 : uint32_t i;
6891 :
6892 0 : ZERO_STRUCT(handle);
6893 :
6894 0 : status = rpc_pipe_open_interface(mem_ctx,
6895 : &ndr_table_spoolss,
6896 0 : conn->session_info,
6897 0 : conn->sconn->remote_address,
6898 0 : conn->sconn->local_address,
6899 0 : conn->sconn->msg_ctx,
6900 : &cli);
6901 0 : if (!NT_STATUS_IS_OK(status)) {
6902 0 : DEBUG(0, ("reply_printqueue: "
6903 : "could not connect to spoolss: %s\n",
6904 : nt_errstr(status)));
6905 0 : reply_nterror(req, status);
6906 0 : goto out;
6907 : }
6908 0 : b = cli->binding_handle;
6909 :
6910 0 : ZERO_STRUCT(devmode_ctr);
6911 :
6912 0 : status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
6913 : sharename,
6914 : NULL, devmode_ctr,
6915 : SEC_FLAG_MAXIMUM_ALLOWED,
6916 : &handle,
6917 : &werr);
6918 0 : if (!NT_STATUS_IS_OK(status)) {
6919 0 : reply_nterror(req, status);
6920 0 : goto out;
6921 : }
6922 0 : if (!W_ERROR_IS_OK(werr)) {
6923 0 : reply_nterror(req, werror_to_ntstatus(werr));
6924 0 : goto out;
6925 : }
6926 :
6927 0 : werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6928 : &handle,
6929 : 0, /* firstjob */
6930 : 0xff, /* numjobs */
6931 : 2, /* level */
6932 : 0, /* offered */
6933 : &count,
6934 : &info);
6935 0 : if (!W_ERROR_IS_OK(werr)) {
6936 0 : reply_nterror(req, werror_to_ntstatus(werr));
6937 0 : goto out;
6938 : }
6939 :
6940 0 : if (max_count > 0) {
6941 0 : first = start_index;
6942 : } else {
6943 0 : first = start_index + max_count + 1;
6944 : }
6945 :
6946 0 : if (first >= count) {
6947 0 : num_to_get = first;
6948 : } else {
6949 0 : num_to_get = first + MIN(ABS(max_count), count - first);
6950 : }
6951 :
6952 0 : for (i = first; i < num_to_get; i++) {
6953 : char blob[28];
6954 0 : char *p = blob;
6955 0 : time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6956 : int qstatus;
6957 0 : size_t len = 0;
6958 0 : uint16_t qrapjobid = pjobid_to_rap(sharename,
6959 0 : info[i].info2.job_id);
6960 :
6961 0 : if (info[i].info2.status == JOB_STATUS_PRINTING) {
6962 0 : qstatus = 2;
6963 : } else {
6964 0 : qstatus = 3;
6965 : }
6966 :
6967 0 : srv_put_dos_date2(p, 0, qtime);
6968 0 : SCVAL(p, 4, qstatus);
6969 0 : SSVAL(p, 5, qrapjobid);
6970 0 : SIVAL(p, 7, info[i].info2.size);
6971 0 : SCVAL(p, 11, 0);
6972 0 : status = srvstr_push(blob, req->flags2, p+12,
6973 : info[i].info2.notify_name, 16, STR_ASCII, &len);
6974 0 : if (!NT_STATUS_IS_OK(status)) {
6975 0 : reply_nterror(req, status);
6976 0 : goto out;
6977 : }
6978 0 : if (message_push_blob(
6979 : &req->outbuf,
6980 : data_blob_const(
6981 : blob, sizeof(blob))) == -1) {
6982 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
6983 0 : goto out;
6984 : }
6985 : }
6986 :
6987 0 : if (count > 0) {
6988 0 : SSVAL(req->outbuf,smb_vwv0,count);
6989 0 : SSVAL(req->outbuf,smb_vwv1,
6990 : (max_count>0?first+count:first-1));
6991 0 : SCVAL(smb_buf(req->outbuf),0,1);
6992 0 : SSVAL(smb_buf(req->outbuf),1,28*count);
6993 : }
6994 :
6995 :
6996 0 : DEBUG(3, ("%u entries returned in queue\n",
6997 : (unsigned)count));
6998 :
6999 0 : out:
7000 0 : if (b && is_valid_policy_hnd(&handle)) {
7001 0 : dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
7002 : }
7003 :
7004 : }
7005 :
7006 0 : END_PROFILE(SMBsplretq);
7007 0 : return;
7008 : }
7009 :
7010 : /****************************************************************************
7011 : Reply to a printwrite.
7012 : ****************************************************************************/
7013 :
7014 0 : void reply_printwrite(struct smb_request *req)
7015 : {
7016 0 : connection_struct *conn = req->conn;
7017 : int numtowrite;
7018 : const char *data;
7019 : files_struct *fsp;
7020 :
7021 0 : START_PROFILE(SMBsplwr);
7022 :
7023 0 : if (req->wct < 1) {
7024 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7025 0 : END_PROFILE(SMBsplwr);
7026 0 : return;
7027 : }
7028 :
7029 0 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7030 :
7031 0 : if (!check_fsp(conn, req, fsp)) {
7032 0 : END_PROFILE(SMBsplwr);
7033 0 : return;
7034 : }
7035 :
7036 0 : if (!fsp->print_file) {
7037 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7038 0 : END_PROFILE(SMBsplwr);
7039 0 : return;
7040 : }
7041 :
7042 0 : if (!CHECK_WRITE(fsp)) {
7043 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7044 0 : END_PROFILE(SMBsplwr);
7045 0 : return;
7046 : }
7047 :
7048 0 : numtowrite = SVAL(req->buf, 1);
7049 :
7050 : /*
7051 : * This already protects us against CVE-2017-12163.
7052 : */
7053 0 : if (req->buflen < numtowrite + 3) {
7054 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7055 0 : END_PROFILE(SMBsplwr);
7056 0 : return;
7057 : }
7058 :
7059 0 : data = (const char *)req->buf + 3;
7060 :
7061 0 : if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
7062 0 : reply_nterror(req, map_nt_error_from_unix(errno));
7063 0 : END_PROFILE(SMBsplwr);
7064 0 : return;
7065 : }
7066 :
7067 0 : DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
7068 :
7069 0 : reply_outbuf(req, 0, 0);
7070 :
7071 0 : END_PROFILE(SMBsplwr);
7072 0 : return;
7073 : }
7074 :
7075 : /****************************************************************************
7076 : Reply to a mkdir.
7077 : ****************************************************************************/
7078 :
7079 5643 : void reply_mkdir(struct smb_request *req)
7080 : {
7081 5643 : connection_struct *conn = req->conn;
7082 5643 : struct smb_filename *smb_dname = NULL;
7083 5643 : char *directory = NULL;
7084 : NTSTATUS status;
7085 : uint32_t ucf_flags;
7086 5643 : TALLOC_CTX *ctx = talloc_tos();
7087 :
7088 5643 : START_PROFILE(SMBmkdir);
7089 :
7090 5643 : srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
7091 : STR_TERMINATE, &status);
7092 5643 : if (!NT_STATUS_IS_OK(status)) {
7093 5 : reply_nterror(req, status);
7094 5 : goto out;
7095 : }
7096 :
7097 5638 : ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
7098 5638 : status = filename_convert(ctx, conn,
7099 : directory,
7100 : ucf_flags,
7101 : 0,
7102 : &smb_dname);
7103 5638 : if (!NT_STATUS_IS_OK(status)) {
7104 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7105 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7106 : ERRSRV, ERRbadpath);
7107 0 : goto out;
7108 : }
7109 0 : reply_nterror(req, status);
7110 0 : goto out;
7111 : }
7112 :
7113 5638 : status = create_directory(conn, req, smb_dname);
7114 :
7115 5638 : DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
7116 :
7117 5638 : if (!NT_STATUS_IS_OK(status)) {
7118 :
7119 18 : if (!use_nt_status()
7120 4 : && NT_STATUS_EQUAL(status,
7121 : NT_STATUS_OBJECT_NAME_COLLISION)) {
7122 : /*
7123 : * Yes, in the DOS error code case we get a
7124 : * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
7125 : * samba4 torture test.
7126 : */
7127 4 : status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
7128 : }
7129 :
7130 18 : reply_nterror(req, status);
7131 18 : goto out;
7132 : }
7133 :
7134 5620 : reply_outbuf(req, 0, 0);
7135 :
7136 5620 : DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
7137 5643 : out:
7138 5643 : TALLOC_FREE(smb_dname);
7139 5643 : END_PROFILE(SMBmkdir);
7140 5643 : return;
7141 : }
7142 :
7143 : /****************************************************************************
7144 : Reply to a rmdir.
7145 : ****************************************************************************/
7146 :
7147 6675 : void reply_rmdir(struct smb_request *req)
7148 : {
7149 6675 : connection_struct *conn = req->conn;
7150 6675 : struct smb_filename *smb_dname = NULL;
7151 6675 : char *directory = NULL;
7152 : NTSTATUS status;
7153 6675 : TALLOC_CTX *ctx = talloc_tos();
7154 6675 : files_struct *fsp = NULL;
7155 6675 : int info = 0;
7156 6675 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
7157 :
7158 6675 : START_PROFILE(SMBrmdir);
7159 :
7160 6675 : srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
7161 : STR_TERMINATE, &status);
7162 6675 : if (!NT_STATUS_IS_OK(status)) {
7163 0 : reply_nterror(req, status);
7164 0 : goto out;
7165 : }
7166 :
7167 6675 : status = filename_convert(ctx, conn,
7168 : directory,
7169 : ucf_flags,
7170 : 0,
7171 : &smb_dname);
7172 6675 : if (!NT_STATUS_IS_OK(status)) {
7173 11 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7174 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7175 : ERRSRV, ERRbadpath);
7176 0 : goto out;
7177 : }
7178 11 : reply_nterror(req, status);
7179 11 : goto out;
7180 : }
7181 :
7182 6664 : if (is_ntfs_stream_smb_fname(smb_dname)) {
7183 0 : reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
7184 0 : goto out;
7185 : }
7186 :
7187 6664 : status = SMB_VFS_CREATE_FILE(
7188 : conn, /* conn */
7189 : req, /* req */
7190 : smb_dname, /* fname */
7191 : DELETE_ACCESS, /* access_mask */
7192 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7193 : FILE_SHARE_DELETE),
7194 : FILE_OPEN, /* create_disposition*/
7195 : FILE_DIRECTORY_FILE, /* create_options */
7196 : FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
7197 : 0, /* oplock_request */
7198 : NULL, /* lease */
7199 : 0, /* allocation_size */
7200 : 0, /* private_flags */
7201 : NULL, /* sd */
7202 : NULL, /* ea_list */
7203 : &fsp, /* result */
7204 : &info, /* pinfo */
7205 : NULL, NULL); /* create context */
7206 :
7207 6664 : if (!NT_STATUS_IS_OK(status)) {
7208 243 : if (open_was_deferred(req->xconn, req->mid)) {
7209 : /* We have re-scheduled this call. */
7210 0 : goto out;
7211 : }
7212 243 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
7213 32 : bool ok = defer_smb1_sharing_violation(req);
7214 32 : if (ok) {
7215 16 : goto out;
7216 : }
7217 : }
7218 227 : reply_nterror(req, status);
7219 227 : goto out;
7220 : }
7221 :
7222 6421 : status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
7223 6421 : if (!NT_STATUS_IS_OK(status)) {
7224 38 : close_file(req, fsp, ERROR_CLOSE);
7225 38 : reply_nterror(req, status);
7226 38 : goto out;
7227 : }
7228 :
7229 6383 : if (!set_delete_on_close(fsp, true,
7230 6383 : conn->session_info->security_token,
7231 6383 : conn->session_info->unix_token)) {
7232 0 : close_file(req, fsp, ERROR_CLOSE);
7233 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7234 0 : goto out;
7235 : }
7236 :
7237 6383 : status = close_file(req, fsp, NORMAL_CLOSE);
7238 6383 : if (!NT_STATUS_IS_OK(status)) {
7239 0 : reply_nterror(req, status);
7240 : } else {
7241 6383 : reply_outbuf(req, 0, 0);
7242 : }
7243 :
7244 6383 : DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
7245 6675 : out:
7246 6675 : TALLOC_FREE(smb_dname);
7247 6675 : END_PROFILE(SMBrmdir);
7248 6675 : return;
7249 : }
7250 :
7251 : /*******************************************************************
7252 : Resolve wildcards in a filename rename.
7253 : ********************************************************************/
7254 :
7255 29 : static bool resolve_wildcards(TALLOC_CTX *ctx,
7256 : const char *name1,
7257 : const char *name2,
7258 : char **pp_newname)
7259 : {
7260 29 : char *name2_copy = NULL;
7261 29 : char *root1 = NULL;
7262 29 : char *root2 = NULL;
7263 29 : char *ext1 = NULL;
7264 29 : char *ext2 = NULL;
7265 : char *p,*p2, *pname1, *pname2;
7266 :
7267 29 : name2_copy = talloc_strdup(ctx, name2);
7268 29 : if (!name2_copy) {
7269 0 : return False;
7270 : }
7271 :
7272 29 : pname1 = strrchr_m(name1,'/');
7273 29 : pname2 = strrchr_m(name2_copy,'/');
7274 :
7275 29 : if (!pname1 || !pname2) {
7276 0 : return False;
7277 : }
7278 :
7279 : /* Truncate the copy of name2 at the last '/' */
7280 29 : *pname2 = '\0';
7281 :
7282 : /* Now go past the '/' */
7283 29 : pname1++;
7284 29 : pname2++;
7285 :
7286 29 : root1 = talloc_strdup(ctx, pname1);
7287 29 : root2 = talloc_strdup(ctx, pname2);
7288 :
7289 29 : if (!root1 || !root2) {
7290 0 : return False;
7291 : }
7292 :
7293 29 : p = strrchr_m(root1,'.');
7294 29 : if (p) {
7295 25 : *p = 0;
7296 25 : ext1 = talloc_strdup(ctx, p+1);
7297 : } else {
7298 4 : ext1 = talloc_strdup(ctx, "");
7299 : }
7300 29 : p = strrchr_m(root2,'.');
7301 29 : if (p) {
7302 25 : *p = 0;
7303 25 : ext2 = talloc_strdup(ctx, p+1);
7304 : } else {
7305 4 : ext2 = talloc_strdup(ctx, "");
7306 : }
7307 :
7308 29 : if (!ext1 || !ext2) {
7309 0 : return False;
7310 : }
7311 :
7312 24 : p = root1;
7313 24 : p2 = root2;
7314 106 : while (*p2) {
7315 77 : if (*p2 == '?') {
7316 : /* Hmmm. Should this be mb-aware ? */
7317 0 : *p2 = *p;
7318 0 : p2++;
7319 77 : } else if (*p2 == '*') {
7320 19 : *p2 = '\0';
7321 19 : root2 = talloc_asprintf(ctx, "%s%s",
7322 : root2,
7323 : p);
7324 19 : if (!root2) {
7325 0 : return False;
7326 : }
7327 16 : break;
7328 : } else {
7329 58 : p2++;
7330 : }
7331 58 : if (*p) {
7332 58 : p++;
7333 : }
7334 : }
7335 :
7336 29 : p = ext1;
7337 29 : p2 = ext2;
7338 128 : while (*p2) {
7339 75 : if (*p2 == '?') {
7340 : /* Hmmm. Should this be mb-aware ? */
7341 0 : *p2 = *p;
7342 0 : p2++;
7343 75 : } else if (*p2 == '*') {
7344 0 : *p2 = '\0';
7345 0 : ext2 = talloc_asprintf(ctx, "%s%s",
7346 : ext2,
7347 : p);
7348 0 : if (!ext2) {
7349 0 : return False;
7350 : }
7351 0 : break;
7352 : } else {
7353 75 : p2++;
7354 : }
7355 75 : if (*p) {
7356 75 : p++;
7357 : }
7358 : }
7359 :
7360 29 : if (*ext2) {
7361 25 : *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
7362 : name2_copy,
7363 : root2,
7364 : ext2);
7365 : } else {
7366 4 : *pp_newname = talloc_asprintf(ctx, "%s/%s",
7367 : name2_copy,
7368 : root2);
7369 : }
7370 :
7371 29 : if (!*pp_newname) {
7372 0 : return False;
7373 : }
7374 :
7375 29 : return True;
7376 : }
7377 :
7378 : /****************************************************************************
7379 : Ensure open files have their names updated. Updated to notify other smbd's
7380 : asynchronously.
7381 : ****************************************************************************/
7382 :
7383 577 : static void rename_open_files(connection_struct *conn,
7384 : struct share_mode_lock *lck,
7385 : struct file_id id,
7386 : uint32_t orig_name_hash,
7387 : const struct smb_filename *smb_fname_dst)
7388 : {
7389 : files_struct *fsp;
7390 577 : bool did_rename = False;
7391 : NTSTATUS status;
7392 577 : uint32_t new_name_hash = 0;
7393 :
7394 1710 : for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
7395 634 : fsp = file_find_di_next(fsp, false)) {
7396 : struct file_id_buf idbuf;
7397 : /* fsp_name is a relative path under the fsp. To change this for other
7398 : sharepaths we need to manipulate relative paths. */
7399 : /* TODO - create the absolute path and manipulate the newname
7400 : relative to the sharepath. */
7401 634 : if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
7402 0 : continue;
7403 : }
7404 634 : if (fsp->name_hash != orig_name_hash) {
7405 0 : continue;
7406 : }
7407 634 : DBG_DEBUG("renaming file %s "
7408 : "(file_id %s) from %s -> %s\n",
7409 : fsp_fnum_dbg(fsp),
7410 : file_id_str_buf(fsp->file_id, &idbuf),
7411 : fsp_str_dbg(fsp),
7412 : smb_fname_str_dbg(smb_fname_dst));
7413 :
7414 634 : status = fsp_set_smb_fname(fsp, smb_fname_dst);
7415 634 : if (NT_STATUS_IS_OK(status)) {
7416 634 : did_rename = True;
7417 634 : new_name_hash = fsp->name_hash;
7418 : }
7419 : }
7420 :
7421 577 : if (!did_rename) {
7422 : struct file_id_buf idbuf;
7423 0 : DBG_DEBUG("no open files on file_id %s "
7424 : "for %s\n",
7425 : file_id_str_buf(id, &idbuf),
7426 : smb_fname_str_dbg(smb_fname_dst));
7427 : }
7428 :
7429 : /* Send messages to all smbd's (not ourself) that the name has changed. */
7430 577 : rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
7431 : orig_name_hash, new_name_hash,
7432 : smb_fname_dst);
7433 :
7434 577 : }
7435 :
7436 : /****************************************************************************
7437 : We need to check if the source path is a parent directory of the destination
7438 : (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
7439 : refuse the rename with a sharing violation. Under UNIX the above call can
7440 : *succeed* if /foo/bar/baz is a symlink to another area in the share. We
7441 : probably need to check that the client is a Windows one before disallowing
7442 : this as a UNIX client (one with UNIX extensions) can know the source is a
7443 : symlink and make this decision intelligently. Found by an excellent bug
7444 : report from <AndyLiebman@aol.com>.
7445 : ****************************************************************************/
7446 :
7447 587 : static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
7448 : const struct smb_filename *smb_fname_dst)
7449 : {
7450 587 : const char *psrc = smb_fname_src->base_name;
7451 587 : const char *pdst = smb_fname_dst->base_name;
7452 : size_t slen;
7453 :
7454 587 : if (psrc[0] == '.' && psrc[1] == '/') {
7455 0 : psrc += 2;
7456 : }
7457 587 : if (pdst[0] == '.' && pdst[1] == '/') {
7458 0 : pdst += 2;
7459 : }
7460 587 : if ((slen = strlen(psrc)) > strlen(pdst)) {
7461 36 : return False;
7462 : }
7463 547 : return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
7464 : }
7465 :
7466 : /*
7467 : * Do the notify calls from a rename
7468 : */
7469 :
7470 577 : static void notify_rename(connection_struct *conn, bool is_dir,
7471 : const struct smb_filename *smb_fname_src,
7472 : const struct smb_filename *smb_fname_dst)
7473 : {
7474 577 : char *parent_dir_src = NULL;
7475 577 : char *parent_dir_dst = NULL;
7476 : uint32_t mask;
7477 :
7478 577 : mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
7479 577 : : FILE_NOTIFY_CHANGE_FILE_NAME;
7480 :
7481 577 : if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
7482 577 : &parent_dir_src, NULL) ||
7483 577 : !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
7484 : &parent_dir_dst, NULL)) {
7485 0 : goto out;
7486 : }
7487 :
7488 577 : if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
7489 549 : notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
7490 549 : smb_fname_src->base_name);
7491 549 : notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
7492 549 : smb_fname_dst->base_name);
7493 : }
7494 : else {
7495 28 : notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
7496 28 : smb_fname_src->base_name);
7497 28 : notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
7498 28 : smb_fname_dst->base_name);
7499 : }
7500 :
7501 : /* this is a strange one. w2k3 gives an additional event for
7502 : CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
7503 : files, but not directories */
7504 577 : if (!is_dir) {
7505 331 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
7506 : FILE_NOTIFY_CHANGE_ATTRIBUTES
7507 : |FILE_NOTIFY_CHANGE_CREATION,
7508 331 : smb_fname_dst->base_name);
7509 : }
7510 745 : out:
7511 577 : TALLOC_FREE(parent_dir_src);
7512 577 : TALLOC_FREE(parent_dir_dst);
7513 577 : }
7514 :
7515 : /****************************************************************************
7516 : Returns an error if the parent directory for a filename is open in an
7517 : incompatible way.
7518 : ****************************************************************************/
7519 :
7520 730 : static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
7521 : const struct smb_filename *smb_fname_dst_in)
7522 : {
7523 730 : struct smb_filename *smb_fname_parent = NULL;
7524 : struct file_id id;
7525 730 : files_struct *fsp = NULL;
7526 : int ret;
7527 : NTSTATUS status;
7528 :
7529 730 : status = SMB_VFS_PARENT_PATHNAME(conn,
7530 : talloc_tos(),
7531 : smb_fname_dst_in,
7532 : &smb_fname_parent,
7533 : NULL);
7534 730 : if (!NT_STATUS_IS_OK(status)) {
7535 0 : return status;
7536 : }
7537 :
7538 730 : ret = SMB_VFS_LSTAT(conn, smb_fname_parent);
7539 730 : if (ret == -1) {
7540 0 : return map_nt_error_from_unix(errno);
7541 : }
7542 :
7543 : /*
7544 : * We're only checking on this smbd here, mostly good
7545 : * enough.. and will pass tests.
7546 : */
7547 :
7548 730 : id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
7549 1377 : for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
7550 20 : fsp = file_find_di_next(fsp, true)) {
7551 50 : if (fsp->access_mask & DELETE_ACCESS) {
7552 30 : return NT_STATUS_SHARING_VIOLATION;
7553 : }
7554 : }
7555 700 : return NT_STATUS_OK;
7556 : }
7557 :
7558 : /****************************************************************************
7559 : Rename an open file - given an fsp.
7560 : ****************************************************************************/
7561 :
7562 730 : NTSTATUS rename_internals_fsp(connection_struct *conn,
7563 : files_struct *fsp,
7564 : struct smb_filename *smb_fname_dst_in,
7565 : const char *dst_original_lcomp,
7566 : uint32_t attrs,
7567 : bool replace_if_exists)
7568 : {
7569 730 : TALLOC_CTX *ctx = talloc_tos();
7570 730 : struct smb_filename *parent_dir_fname_dst = NULL;
7571 730 : struct smb_filename *parent_dir_fname_dst_atname = NULL;
7572 730 : struct smb_filename *parent_dir_fname_src = NULL;
7573 730 : struct smb_filename *parent_dir_fname_src_atname = NULL;
7574 730 : struct smb_filename *smb_fname_dst = NULL;
7575 730 : NTSTATUS status = NT_STATUS_OK;
7576 730 : struct share_mode_lock *lck = NULL;
7577 730 : uint32_t access_mask = SEC_DIR_ADD_FILE;
7578 : bool dst_exists, old_is_stream, new_is_stream;
7579 : int ret;
7580 :
7581 730 : status = check_name(conn, smb_fname_dst_in);
7582 730 : if (!NT_STATUS_IS_OK(status)) {
7583 0 : return status;
7584 : }
7585 :
7586 730 : status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
7587 730 : if (!NT_STATUS_IS_OK(status)) {
7588 30 : return status;
7589 : }
7590 :
7591 700 : if (file_has_open_streams(fsp)) {
7592 16 : return NT_STATUS_ACCESS_DENIED;
7593 : }
7594 :
7595 : /* Make a copy of the dst smb_fname structs */
7596 :
7597 684 : smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
7598 684 : if (smb_fname_dst == NULL) {
7599 0 : status = NT_STATUS_NO_MEMORY;
7600 0 : goto out;
7601 : }
7602 :
7603 : /*
7604 : * Check for special case with case preserving and not
7605 : * case sensitive. If the new last component differs from the original
7606 : * last component only by case, then we should allow
7607 : * the rename (user is trying to change the case of the
7608 : * filename).
7609 : */
7610 1368 : if (!conn->case_sensitive && conn->case_preserve &&
7611 757 : strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7612 73 : strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
7613 33 : char *fname_dst_parent = NULL;
7614 33 : const char *fname_dst_lcomp = NULL;
7615 33 : char *orig_lcomp_path = NULL;
7616 33 : char *orig_lcomp_stream = NULL;
7617 33 : bool ok = true;
7618 :
7619 : /*
7620 : * Split off the last component of the processed
7621 : * destination name. We will compare this to
7622 : * the split components of dst_original_lcomp.
7623 : */
7624 33 : if (!parent_dirname(ctx,
7625 33 : smb_fname_dst->base_name,
7626 : &fname_dst_parent,
7627 : &fname_dst_lcomp)) {
7628 0 : status = NT_STATUS_NO_MEMORY;
7629 0 : goto out;
7630 : }
7631 :
7632 : /*
7633 : * The dst_original_lcomp component contains
7634 : * the last_component of the path + stream
7635 : * name (if a stream exists).
7636 : *
7637 : * Split off the stream name so we
7638 : * can check them separately.
7639 : */
7640 :
7641 33 : if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
7642 : /* POSIX - no stream component. */
7643 0 : orig_lcomp_path = talloc_strdup(ctx,
7644 : dst_original_lcomp);
7645 0 : if (orig_lcomp_path == NULL) {
7646 0 : ok = false;
7647 : }
7648 : } else {
7649 33 : ok = split_stream_filename(ctx,
7650 : dst_original_lcomp,
7651 : &orig_lcomp_path,
7652 : &orig_lcomp_stream);
7653 : }
7654 :
7655 33 : if (!ok) {
7656 0 : TALLOC_FREE(fname_dst_parent);
7657 0 : status = NT_STATUS_NO_MEMORY;
7658 0 : goto out;
7659 : }
7660 :
7661 : /* If the base names only differ by case, use original. */
7662 33 : if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
7663 : char *tmp;
7664 : /*
7665 : * Replace the modified last component with the
7666 : * original.
7667 : */
7668 10 : if (!ISDOT(fname_dst_parent)) {
7669 10 : tmp = talloc_asprintf(smb_fname_dst,
7670 : "%s/%s",
7671 : fname_dst_parent,
7672 : orig_lcomp_path);
7673 : } else {
7674 0 : tmp = talloc_strdup(smb_fname_dst,
7675 : orig_lcomp_path);
7676 : }
7677 10 : if (tmp == NULL) {
7678 0 : status = NT_STATUS_NO_MEMORY;
7679 0 : TALLOC_FREE(fname_dst_parent);
7680 0 : TALLOC_FREE(orig_lcomp_path);
7681 0 : TALLOC_FREE(orig_lcomp_stream);
7682 0 : goto out;
7683 : }
7684 10 : TALLOC_FREE(smb_fname_dst->base_name);
7685 10 : smb_fname_dst->base_name = tmp;
7686 : }
7687 :
7688 : /* If the stream_names only differ by case, use original. */
7689 33 : if(!strcsequal(smb_fname_dst->stream_name,
7690 : orig_lcomp_stream)) {
7691 : /* Use the original stream. */
7692 0 : char *tmp = talloc_strdup(smb_fname_dst,
7693 : orig_lcomp_stream);
7694 0 : if (tmp == NULL) {
7695 0 : status = NT_STATUS_NO_MEMORY;
7696 0 : TALLOC_FREE(fname_dst_parent);
7697 0 : TALLOC_FREE(orig_lcomp_path);
7698 0 : TALLOC_FREE(orig_lcomp_stream);
7699 0 : goto out;
7700 : }
7701 0 : TALLOC_FREE(smb_fname_dst->stream_name);
7702 0 : smb_fname_dst->stream_name = tmp;
7703 : }
7704 33 : TALLOC_FREE(fname_dst_parent);
7705 33 : TALLOC_FREE(orig_lcomp_path);
7706 33 : TALLOC_FREE(orig_lcomp_stream);
7707 : }
7708 :
7709 : /*
7710 : * If the src and dest names are identical - including case,
7711 : * don't do the rename, just return success.
7712 : */
7713 :
7714 747 : if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7715 63 : strcsequal(fsp->fsp_name->stream_name,
7716 63 : smb_fname_dst->stream_name)) {
7717 23 : DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
7718 : "- returning success\n",
7719 : smb_fname_str_dbg(smb_fname_dst)));
7720 20 : status = NT_STATUS_OK;
7721 20 : goto out;
7722 : }
7723 :
7724 661 : old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
7725 661 : new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
7726 :
7727 : /* Return the correct error code if both names aren't streams. */
7728 661 : if (!old_is_stream && new_is_stream) {
7729 4 : status = NT_STATUS_OBJECT_NAME_INVALID;
7730 4 : goto out;
7731 : }
7732 :
7733 657 : if (old_is_stream && !new_is_stream) {
7734 0 : status = NT_STATUS_INVALID_PARAMETER;
7735 0 : goto out;
7736 : }
7737 :
7738 657 : dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
7739 :
7740 657 : if(!replace_if_exists && dst_exists) {
7741 35 : DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
7742 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7743 : smb_fname_str_dbg(smb_fname_dst)));
7744 35 : status = NT_STATUS_OBJECT_NAME_COLLISION;
7745 35 : goto out;
7746 : }
7747 :
7748 : /*
7749 : * Drop the pathref fsp on the destination otherwise we trip upon in in
7750 : * the below check for open files check.
7751 : */
7752 622 : if (smb_fname_dst_in->fsp != NULL) {
7753 26 : fd_close(smb_fname_dst_in->fsp);
7754 26 : file_free(NULL, smb_fname_dst_in->fsp);
7755 26 : SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
7756 : }
7757 :
7758 622 : if (dst_exists) {
7759 32 : struct file_id fileid = vfs_file_id_from_sbuf(conn,
7760 32 : &smb_fname_dst->st);
7761 32 : files_struct *dst_fsp = file_find_di_first(conn->sconn,
7762 : fileid, true);
7763 : /* The file can be open when renaming a stream */
7764 32 : if (dst_fsp && !new_is_stream) {
7765 8 : DEBUG(3, ("rename_internals_fsp: Target file open\n"));
7766 8 : status = NT_STATUS_ACCESS_DENIED;
7767 8 : goto out;
7768 : }
7769 : }
7770 :
7771 : /* Ensure we have a valid stat struct for the source. */
7772 614 : status = vfs_stat_fsp(fsp);
7773 614 : if (!NT_STATUS_IS_OK(status)) {
7774 0 : goto out;
7775 : }
7776 :
7777 614 : status = can_rename(conn, fsp, attrs);
7778 :
7779 614 : if (!NT_STATUS_IS_OK(status)) {
7780 27 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7781 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7782 : smb_fname_str_dbg(smb_fname_dst)));
7783 27 : if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
7784 0 : status = NT_STATUS_ACCESS_DENIED;
7785 24 : goto out;
7786 : }
7787 :
7788 587 : if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
7789 0 : status = NT_STATUS_ACCESS_DENIED;
7790 0 : goto out;
7791 : }
7792 :
7793 : /* Do we have rights to move into the destination ? */
7794 587 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
7795 : /* We're moving a directory. */
7796 250 : access_mask = SEC_DIR_ADD_SUBDIR;
7797 : }
7798 :
7799 : /*
7800 : * Get a pathref on the destination parent directory, so
7801 : * we can call check_parent_access_fsp().
7802 : */
7803 587 : status = parent_pathref(ctx,
7804 : conn->cwd_fsp,
7805 : smb_fname_dst,
7806 : &parent_dir_fname_dst,
7807 : &parent_dir_fname_dst_atname);
7808 587 : if (!NT_STATUS_IS_OK(status)) {
7809 0 : goto out;
7810 : }
7811 :
7812 587 : status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
7813 : access_mask);
7814 587 : if (!NT_STATUS_IS_OK(status)) {
7815 10 : DBG_INFO("check_parent_access_fsp on "
7816 : "dst %s returned %s\n",
7817 : smb_fname_str_dbg(smb_fname_dst),
7818 : nt_errstr(status));
7819 10 : goto out;
7820 : }
7821 :
7822 : /*
7823 : * If the target existed, make sure the destination
7824 : * atname has the same stat struct.
7825 : */
7826 577 : parent_dir_fname_dst_atname->st = smb_fname_dst->st;
7827 :
7828 : /*
7829 : * It's very common that source and
7830 : * destination directories are the same.
7831 : * Optimize by not opening the
7832 : * second parent_pathref if we know
7833 : * this is the case.
7834 : */
7835 :
7836 577 : status = SMB_VFS_PARENT_PATHNAME(conn,
7837 : ctx,
7838 : fsp->fsp_name,
7839 : &parent_dir_fname_src,
7840 : &parent_dir_fname_src_atname);
7841 577 : if (!NT_STATUS_IS_OK(status)) {
7842 0 : goto out;
7843 : }
7844 :
7845 : /*
7846 : * We do a case-sensitive string comparison. We want to be *sure*
7847 : * this is the same path. The worst that can happen if
7848 : * the case doesn't match is we lose out on the optimization,
7849 : * the code still works.
7850 : *
7851 : * We can ignore twrp fields here. Rename is not allowed on
7852 : * shadow copy handles.
7853 : */
7854 :
7855 577 : if (strcmp(parent_dir_fname_src->base_name,
7856 577 : parent_dir_fname_dst->base_name) == 0) {
7857 : /*
7858 : * parent directory is the same for source
7859 : * and destination.
7860 : */
7861 : /* Reparent the src_atname to the parent_dir_dest fname. */
7862 549 : parent_dir_fname_src_atname = talloc_move(
7863 : parent_dir_fname_dst,
7864 : &parent_dir_fname_src_atname);
7865 : /* Free the unneeded duplicate parent name. */
7866 549 : TALLOC_FREE(parent_dir_fname_src);
7867 : /*
7868 : * And make the source parent name a copy of the
7869 : * destination parent name.
7870 : */
7871 549 : parent_dir_fname_src = parent_dir_fname_dst;
7872 : } else {
7873 : /*
7874 : * source and destingation parent directories are
7875 : * different.
7876 : *
7877 : * Get a pathref on the source parent directory, so
7878 : * we can do a relative rename.
7879 : */
7880 28 : TALLOC_FREE(parent_dir_fname_src);
7881 28 : status = parent_pathref(ctx,
7882 : conn->cwd_fsp,
7883 28 : fsp->fsp_name,
7884 : &parent_dir_fname_src,
7885 : &parent_dir_fname_src_atname);
7886 28 : if (!NT_STATUS_IS_OK(status)) {
7887 0 : goto out;
7888 : }
7889 : }
7890 :
7891 : /*
7892 : * Some modules depend on the source smb_fname having a valid stat.
7893 : * The parent_dir_fname_src_atname is the relative name of the
7894 : * currently open file, so just copy the stat from the open fsp.
7895 : */
7896 577 : parent_dir_fname_src_atname->st = fsp->fsp_name->st;
7897 :
7898 577 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
7899 :
7900 : /*
7901 : * We have the file open ourselves, so not being able to get the
7902 : * corresponding share mode lock is a fatal error.
7903 : */
7904 :
7905 577 : SMB_ASSERT(lck != NULL);
7906 :
7907 577 : ret = SMB_VFS_RENAMEAT(conn,
7908 : parent_dir_fname_src->fsp,
7909 : parent_dir_fname_src_atname,
7910 : parent_dir_fname_dst->fsp,
7911 : parent_dir_fname_dst_atname);
7912 577 : if (ret == 0) {
7913 577 : uint32_t create_options = fh_get_private_options(fsp->fh);
7914 :
7915 577 : DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
7916 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7917 : smb_fname_str_dbg(smb_fname_dst)));
7918 :
7919 577 : notify_rename(conn,
7920 577 : fsp->fsp_flags.is_directory,
7921 577 : fsp->fsp_name,
7922 : smb_fname_dst);
7923 :
7924 577 : rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
7925 : smb_fname_dst);
7926 :
7927 867 : if (!fsp->fsp_flags.is_directory &&
7928 654 : !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
7929 412 : (lp_map_archive(SNUM(conn)) ||
7930 89 : lp_store_dos_attributes(SNUM(conn))))
7931 : {
7932 : /*
7933 : * We must set the archive bit on the newly renamed
7934 : * file.
7935 : */
7936 323 : ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
7937 323 : if (ret == 0) {
7938 : uint32_t old_dosmode;
7939 323 : old_dosmode = fdos_mode(fsp);
7940 : /*
7941 : * We can use fsp->fsp_name here as it has
7942 : * already been changed to the new name.
7943 : */
7944 323 : SMB_ASSERT(fsp->fsp_name->fsp == fsp);
7945 323 : file_set_dosmode(conn,
7946 : fsp->fsp_name,
7947 : old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
7948 : NULL,
7949 : true);
7950 : }
7951 : }
7952 :
7953 : /*
7954 : * A rename acts as a new file create w.r.t. allowing an initial delete
7955 : * on close, probably because in Windows there is a new handle to the
7956 : * new file. If initial delete on close was requested but not
7957 : * originally set, we need to set it here. This is probably not 100% correct,
7958 : * but will work for the CIFSFS client which in non-posix mode
7959 : * depends on these semantics. JRA.
7960 : */
7961 :
7962 577 : if (create_options & FILE_DELETE_ON_CLOSE) {
7963 0 : status = can_set_delete_on_close(fsp, 0);
7964 :
7965 0 : if (NT_STATUS_IS_OK(status)) {
7966 : /* Note that here we set the *initial* delete on close flag,
7967 : * not the regular one. The magic gets handled in close. */
7968 0 : fsp->fsp_flags.initial_delete_on_close = true;
7969 : }
7970 : }
7971 577 : TALLOC_FREE(lck);
7972 577 : status = NT_STATUS_OK;
7973 577 : goto out;
7974 : }
7975 :
7976 0 : TALLOC_FREE(lck);
7977 :
7978 0 : if (errno == ENOTDIR || errno == EISDIR) {
7979 0 : status = NT_STATUS_OBJECT_NAME_COLLISION;
7980 : } else {
7981 0 : status = map_nt_error_from_unix(errno);
7982 : }
7983 :
7984 0 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7985 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7986 : smb_fname_str_dbg(smb_fname_dst)));
7987 :
7988 684 : out:
7989 :
7990 : /*
7991 : * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
7992 : * See the optimization for same source and destination directory
7993 : * above. Only free one in that case.
7994 : */
7995 684 : if (parent_dir_fname_src != parent_dir_fname_dst) {
7996 38 : TALLOC_FREE(parent_dir_fname_src);
7997 : }
7998 684 : TALLOC_FREE(parent_dir_fname_dst);
7999 684 : TALLOC_FREE(smb_fname_dst);
8000 :
8001 684 : return status;
8002 : }
8003 :
8004 : /****************************************************************************
8005 : The guts of the rename command, split out so it may be called by the NT SMB
8006 : code.
8007 : ****************************************************************************/
8008 :
8009 456 : NTSTATUS rename_internals(TALLOC_CTX *ctx,
8010 : connection_struct *conn,
8011 : struct smb_request *req,
8012 : struct smb_filename *smb_fname_src,
8013 : const char *src_original_lcomp,
8014 : struct smb_filename *smb_fname_dst,
8015 : const char *dst_original_lcomp,
8016 : uint32_t attrs,
8017 : bool replace_if_exists,
8018 : uint32_t access_mask)
8019 : {
8020 456 : char *fname_src_dir = NULL;
8021 456 : struct smb_filename *smb_fname_src_dir = NULL;
8022 456 : char *fname_src_mask = NULL;
8023 456 : int count=0;
8024 456 : NTSTATUS status = NT_STATUS_OK;
8025 456 : struct smb_Dir *dir_hnd = NULL;
8026 456 : const char *dname = NULL;
8027 456 : char *talloced = NULL;
8028 456 : long offset = 0;
8029 456 : int create_options = 0;
8030 456 : struct smb2_create_blobs *posx = NULL;
8031 : int rc;
8032 456 : bool src_has_wild = false;
8033 456 : bool dest_has_wild = false;
8034 :
8035 : /*
8036 : * Split the old name into directory and last component
8037 : * strings. Note that unix_convert may have stripped off a
8038 : * leading ./ from both name and newname if the rename is
8039 : * at the root of the share. We need to make sure either both
8040 : * name and newname contain a / character or neither of them do
8041 : * as this is checked in resolve_wildcards().
8042 : */
8043 :
8044 : /* Split up the directory from the filename/mask. */
8045 456 : status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
8046 : &fname_src_dir, &fname_src_mask);
8047 456 : if (!NT_STATUS_IS_OK(status)) {
8048 0 : status = NT_STATUS_NO_MEMORY;
8049 0 : goto out;
8050 : }
8051 :
8052 456 : if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
8053 : /*
8054 : * Check the wildcard mask *before*
8055 : * unmangling. As mangling is done
8056 : * for names that can't be returned
8057 : * to Windows the unmangled name may
8058 : * contain Windows wildcard characters.
8059 : */
8060 448 : if (src_original_lcomp != NULL) {
8061 347 : src_has_wild = ms_has_wild(src_original_lcomp);
8062 : }
8063 448 : dest_has_wild = ms_has_wild(dst_original_lcomp);
8064 : }
8065 :
8066 : /*
8067 : * We should only check the mangled cache
8068 : * here if unix_convert failed. This means
8069 : * that the path in 'mask' doesn't exist
8070 : * on the file system and so we need to look
8071 : * for a possible mangle. This patch from
8072 : * Tine Smukavec <valentin.smukavec@hermes.si>.
8073 : */
8074 :
8075 486 : if (!VALID_STAT(smb_fname_src->st) &&
8076 30 : mangle_is_mangled(fname_src_mask, conn->params)) {
8077 0 : char *new_mask = NULL;
8078 0 : mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
8079 0 : conn->params);
8080 0 : if (new_mask) {
8081 0 : TALLOC_FREE(fname_src_mask);
8082 0 : fname_src_mask = new_mask;
8083 : }
8084 : }
8085 :
8086 456 : if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
8087 8 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
8088 8 : if (!NT_STATUS_IS_OK(status)) {
8089 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
8090 : nt_errstr(status));
8091 0 : goto out;
8092 : }
8093 : }
8094 :
8095 456 : if (!src_has_wild) {
8096 : files_struct *fsp;
8097 :
8098 : /*
8099 : * Only one file needs to be renamed. Append the mask back
8100 : * onto the directory.
8101 : */
8102 436 : TALLOC_FREE(smb_fname_src->base_name);
8103 436 : if (ISDOT(fname_src_dir)) {
8104 : /* Ensure we use canonical names on open. */
8105 77 : smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8106 : "%s",
8107 : fname_src_mask);
8108 : } else {
8109 359 : smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8110 : "%s/%s",
8111 : fname_src_dir,
8112 : fname_src_mask);
8113 : }
8114 436 : if (!smb_fname_src->base_name) {
8115 0 : status = NT_STATUS_NO_MEMORY;
8116 0 : goto out;
8117 : }
8118 :
8119 436 : DEBUG(3, ("rename_internals: case_sensitive = %d, "
8120 : "case_preserve = %d, short case preserve = %d, "
8121 : "directory = %s, newname = %s, "
8122 : "last_component_dest = %s\n",
8123 : conn->case_sensitive, conn->case_preserve,
8124 : conn->short_case_preserve,
8125 : smb_fname_str_dbg(smb_fname_src),
8126 : smb_fname_str_dbg(smb_fname_dst),
8127 : dst_original_lcomp));
8128 :
8129 : /* The dest name still may have wildcards. */
8130 436 : if (dest_has_wild) {
8131 14 : char *fname_dst_mod = NULL;
8132 14 : if (!resolve_wildcards(smb_fname_dst,
8133 14 : smb_fname_src->base_name,
8134 14 : smb_fname_dst->base_name,
8135 : &fname_dst_mod)) {
8136 0 : DEBUG(6, ("rename_internals: resolve_wildcards "
8137 : "%s %s failed\n",
8138 : smb_fname_src->base_name,
8139 : smb_fname_dst->base_name));
8140 0 : status = NT_STATUS_NO_MEMORY;
8141 0 : goto out;
8142 : }
8143 14 : TALLOC_FREE(smb_fname_dst->base_name);
8144 14 : smb_fname_dst->base_name = fname_dst_mod;
8145 : }
8146 :
8147 436 : ZERO_STRUCT(smb_fname_src->st);
8148 :
8149 436 : rc = vfs_stat(conn, smb_fname_src);
8150 436 : if (rc == -1) {
8151 10 : status = map_nt_error_from_unix_common(errno);
8152 10 : goto out;
8153 : }
8154 :
8155 426 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8156 426 : if (!NT_STATUS_IS_OK(status)) {
8157 8 : if (!NT_STATUS_EQUAL(status,
8158 : NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
8159 0 : goto out;
8160 : }
8161 : /*
8162 : * Possible symlink src.
8163 : */
8164 8 : if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
8165 0 : goto out;
8166 : }
8167 8 : if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
8168 0 : goto out;
8169 : }
8170 : }
8171 :
8172 426 : if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
8173 107 : create_options |= FILE_DIRECTORY_FILE;
8174 : }
8175 :
8176 426 : status = SMB_VFS_CREATE_FILE(
8177 : conn, /* conn */
8178 : req, /* req */
8179 : smb_fname_src, /* fname */
8180 : access_mask, /* access_mask */
8181 : (FILE_SHARE_READ | /* share_access */
8182 : FILE_SHARE_WRITE),
8183 : FILE_OPEN, /* create_disposition*/
8184 : create_options, /* create_options */
8185 : 0, /* file_attributes */
8186 : 0, /* oplock_request */
8187 : NULL, /* lease */
8188 : 0, /* allocation_size */
8189 : 0, /* private_flags */
8190 : NULL, /* sd */
8191 : NULL, /* ea_list */
8192 : &fsp, /* result */
8193 : NULL, /* pinfo */
8194 : posx, /* in_context_blobs */
8195 : NULL); /* out_context_blobs */
8196 :
8197 426 : if (!NT_STATUS_IS_OK(status)) {
8198 72 : DEBUG(3, ("Could not open rename source %s: %s\n",
8199 : smb_fname_str_dbg(smb_fname_src),
8200 : nt_errstr(status)));
8201 68 : goto out;
8202 : }
8203 :
8204 354 : status = rename_internals_fsp(conn,
8205 : fsp,
8206 : smb_fname_dst,
8207 : dst_original_lcomp,
8208 : attrs,
8209 : replace_if_exists);
8210 :
8211 354 : close_file(req, fsp, NORMAL_CLOSE);
8212 :
8213 354 : DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
8214 : nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
8215 : smb_fname_str_dbg(smb_fname_dst)));
8216 :
8217 334 : goto out;
8218 : }
8219 :
8220 : /*
8221 : * Wildcards - process each file that matches.
8222 : */
8223 20 : if (strequal(fname_src_mask, "????????.???")) {
8224 0 : TALLOC_FREE(fname_src_mask);
8225 0 : fname_src_mask = talloc_strdup(ctx, "*");
8226 0 : if (!fname_src_mask) {
8227 0 : status = NT_STATUS_NO_MEMORY;
8228 0 : goto out;
8229 : }
8230 : }
8231 :
8232 20 : smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
8233 : fname_src_dir,
8234 : NULL,
8235 : NULL,
8236 : smb_fname_src->twrp,
8237 : smb_fname_src->flags);
8238 20 : if (smb_fname_src_dir == NULL) {
8239 0 : status = NT_STATUS_NO_MEMORY;
8240 0 : goto out;
8241 : }
8242 :
8243 20 : status = check_name(conn, smb_fname_src_dir);
8244 20 : if (!NT_STATUS_IS_OK(status)) {
8245 0 : goto out;
8246 : }
8247 :
8248 20 : dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
8249 : attrs);
8250 20 : if (dir_hnd == NULL) {
8251 0 : status = map_nt_error_from_unix(errno);
8252 0 : goto out;
8253 : }
8254 :
8255 16 : status = NT_STATUS_NO_SUCH_FILE;
8256 : /*
8257 : * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8258 : * - gentest fix. JRA
8259 : */
8260 :
8261 92 : while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
8262 : &talloced))) {
8263 60 : files_struct *fsp = NULL;
8264 60 : char *destname = NULL;
8265 60 : bool sysdir_entry = False;
8266 :
8267 : /* Quick check for "." and ".." */
8268 60 : if (ISDOT(dname) || ISDOTDOT(dname)) {
8269 40 : if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
8270 0 : sysdir_entry = True;
8271 : } else {
8272 40 : TALLOC_FREE(talloced);
8273 77 : continue;
8274 : }
8275 : }
8276 :
8277 20 : if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
8278 5 : TALLOC_FREE(talloced);
8279 5 : continue;
8280 : }
8281 :
8282 15 : if (sysdir_entry) {
8283 0 : status = NT_STATUS_OBJECT_NAME_INVALID;
8284 0 : break;
8285 : }
8286 :
8287 15 : TALLOC_FREE(smb_fname_src->base_name);
8288 15 : if (ISDOT(fname_src_dir)) {
8289 : /* Ensure we use canonical names on open. */
8290 0 : smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8291 : "%s",
8292 : dname);
8293 : } else {
8294 15 : smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8295 : "%s/%s",
8296 : fname_src_dir,
8297 : dname);
8298 : }
8299 15 : if (!smb_fname_src->base_name) {
8300 0 : status = NT_STATUS_NO_MEMORY;
8301 0 : goto out;
8302 : }
8303 :
8304 15 : if (!resolve_wildcards(ctx, smb_fname_src->base_name,
8305 15 : smb_fname_dst->base_name,
8306 : &destname)) {
8307 0 : DEBUG(6, ("resolve_wildcards %s %s failed\n",
8308 : smb_fname_src->base_name, destname));
8309 0 : TALLOC_FREE(talloced);
8310 0 : continue;
8311 : }
8312 15 : if (!destname) {
8313 0 : status = NT_STATUS_NO_MEMORY;
8314 0 : goto out;
8315 : }
8316 :
8317 15 : TALLOC_FREE(smb_fname_dst->base_name);
8318 15 : smb_fname_dst->base_name = destname;
8319 :
8320 15 : ZERO_STRUCT(smb_fname_src->st);
8321 15 : vfs_stat(conn, smb_fname_src);
8322 :
8323 15 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8324 15 : if (!NT_STATUS_IS_OK(status)) {
8325 0 : DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
8326 : smb_fname_str_dbg(smb_fname_src),
8327 : nt_errstr(status));
8328 0 : break;
8329 : }
8330 :
8331 15 : if (!is_visible_fsp(smb_fname_src->fsp)) {
8332 0 : TALLOC_FREE(talloced);
8333 0 : continue;
8334 : }
8335 :
8336 15 : create_options = 0;
8337 :
8338 15 : if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
8339 0 : create_options |= FILE_DIRECTORY_FILE;
8340 : }
8341 :
8342 15 : status = SMB_VFS_CREATE_FILE(
8343 : conn, /* conn */
8344 : req, /* req */
8345 : smb_fname_src, /* fname */
8346 : access_mask, /* access_mask */
8347 : (FILE_SHARE_READ | /* share_access */
8348 : FILE_SHARE_WRITE),
8349 : FILE_OPEN, /* create_disposition*/
8350 : create_options, /* create_options */
8351 : 0, /* file_attributes */
8352 : 0, /* oplock_request */
8353 : NULL, /* lease */
8354 : 0, /* allocation_size */
8355 : 0, /* private_flags */
8356 : NULL, /* sd */
8357 : NULL, /* ea_list */
8358 : &fsp, /* result */
8359 : NULL, /* pinfo */
8360 : posx, /* in_context_blobs */
8361 : NULL); /* out_context_blobs */
8362 :
8363 15 : if (!NT_STATUS_IS_OK(status)) {
8364 0 : DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
8365 : "returned %s rename %s -> %s\n",
8366 : nt_errstr(status),
8367 : smb_fname_str_dbg(smb_fname_src),
8368 : smb_fname_str_dbg(smb_fname_dst)));
8369 0 : break;
8370 : }
8371 :
8372 15 : dst_original_lcomp = talloc_strdup(smb_fname_dst, dname);
8373 15 : if (dst_original_lcomp == NULL) {
8374 0 : status = NT_STATUS_NO_MEMORY;
8375 0 : goto out;
8376 : }
8377 :
8378 15 : status = rename_internals_fsp(conn,
8379 : fsp,
8380 : smb_fname_dst,
8381 : dst_original_lcomp,
8382 : attrs,
8383 : replace_if_exists);
8384 :
8385 15 : close_file(req, fsp, NORMAL_CLOSE);
8386 :
8387 15 : if (!NT_STATUS_IS_OK(status)) {
8388 0 : DEBUG(3, ("rename_internals_fsp returned %s for "
8389 : "rename %s -> %s\n", nt_errstr(status),
8390 : smb_fname_str_dbg(smb_fname_src),
8391 : smb_fname_str_dbg(smb_fname_dst)));
8392 0 : break;
8393 : }
8394 :
8395 15 : count++;
8396 :
8397 15 : DEBUG(3,("rename_internals: doing rename on %s -> "
8398 : "%s\n", smb_fname_str_dbg(smb_fname_src),
8399 : smb_fname_str_dbg(smb_fname_src)));
8400 15 : TALLOC_FREE(talloced);
8401 : }
8402 20 : TALLOC_FREE(dir_hnd);
8403 :
8404 24 : if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
8405 0 : status = map_nt_error_from_unix(errno);
8406 : }
8407 :
8408 430 : out:
8409 456 : TALLOC_FREE(posx);
8410 456 : TALLOC_FREE(talloced);
8411 456 : TALLOC_FREE(smb_fname_src_dir);
8412 456 : TALLOC_FREE(fname_src_dir);
8413 456 : TALLOC_FREE(fname_src_mask);
8414 456 : return status;
8415 : }
8416 :
8417 : /****************************************************************************
8418 : Reply to a mv.
8419 : ****************************************************************************/
8420 :
8421 355 : void reply_mv(struct smb_request *req)
8422 : {
8423 355 : connection_struct *conn = req->conn;
8424 355 : char *name = NULL;
8425 355 : char *newname = NULL;
8426 : const char *p;
8427 : uint32_t attrs;
8428 : NTSTATUS status;
8429 355 : TALLOC_CTX *ctx = talloc_tos();
8430 355 : struct smb_filename *smb_fname_src = NULL;
8431 355 : const char *src_original_lcomp = NULL;
8432 355 : struct smb_filename *smb_fname_dst = NULL;
8433 355 : const char *dst_original_lcomp = NULL;
8434 682 : uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
8435 355 : (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
8436 682 : uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
8437 355 : (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
8438 355 : bool stream_rename = false;
8439 :
8440 355 : START_PROFILE(SMBmv);
8441 :
8442 355 : if (req->wct < 1) {
8443 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8444 0 : goto out;
8445 : }
8446 :
8447 355 : attrs = SVAL(req->vwv+0, 0);
8448 :
8449 355 : p = (const char *)req->buf + 1;
8450 355 : p += srvstr_get_path_req(ctx, req, &name, p, STR_TERMINATE,
8451 : &status);
8452 355 : if (!NT_STATUS_IS_OK(status)) {
8453 0 : reply_nterror(req, status);
8454 0 : goto out;
8455 : }
8456 355 : p++;
8457 355 : p += srvstr_get_path_req(ctx, req, &newname, p, STR_TERMINATE,
8458 : &status);
8459 355 : if (!NT_STATUS_IS_OK(status)) {
8460 0 : reply_nterror(req, status);
8461 0 : goto out;
8462 : }
8463 :
8464 355 : if (!req->posix_pathnames) {
8465 : /* The newname must begin with a ':' if the
8466 : name contains a ':'. */
8467 347 : if (strchr_m(name, ':')) {
8468 4 : if (newname[0] != ':') {
8469 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8470 0 : goto out;
8471 : }
8472 4 : stream_rename = true;
8473 : }
8474 : }
8475 :
8476 355 : status = filename_convert(ctx,
8477 : conn,
8478 : name,
8479 : src_ucf_flags,
8480 : 0,
8481 : &smb_fname_src);
8482 :
8483 355 : if (!NT_STATUS_IS_OK(status)) {
8484 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8485 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8486 : ERRSRV, ERRbadpath);
8487 0 : goto out;
8488 : }
8489 0 : reply_nterror(req, status);
8490 0 : goto out;
8491 : }
8492 :
8493 : /* Get the last component of the source for rename_internals(). */
8494 355 : src_original_lcomp = get_original_lcomp(ctx,
8495 : conn,
8496 : name,
8497 : dst_ucf_flags);
8498 355 : if (src_original_lcomp == NULL) {
8499 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8500 0 : goto out;
8501 : }
8502 :
8503 355 : status = filename_convert(ctx,
8504 : conn,
8505 : newname,
8506 : dst_ucf_flags,
8507 : 0,
8508 : &smb_fname_dst);
8509 :
8510 355 : if (!NT_STATUS_IS_OK(status)) {
8511 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8512 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8513 : ERRSRV, ERRbadpath);
8514 0 : goto out;
8515 : }
8516 0 : reply_nterror(req, status);
8517 0 : goto out;
8518 : }
8519 :
8520 : /* Get the last component of the destination for rename_internals(). */
8521 355 : dst_original_lcomp = get_original_lcomp(ctx,
8522 : conn,
8523 : newname,
8524 : dst_ucf_flags);
8525 355 : if (dst_original_lcomp == NULL) {
8526 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8527 0 : goto out;
8528 : }
8529 :
8530 355 : if (stream_rename) {
8531 : /* smb_fname_dst->base_name must be the same as
8532 : smb_fname_src->base_name. */
8533 4 : TALLOC_FREE(smb_fname_dst->base_name);
8534 5 : smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
8535 4 : smb_fname_src->base_name);
8536 4 : if (!smb_fname_dst->base_name) {
8537 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8538 0 : goto out;
8539 : }
8540 : }
8541 :
8542 355 : DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
8543 : smb_fname_str_dbg(smb_fname_dst)));
8544 :
8545 355 : status = rename_internals(ctx,
8546 : conn,
8547 : req,
8548 : smb_fname_src,
8549 : src_original_lcomp,
8550 : smb_fname_dst,
8551 : dst_original_lcomp,
8552 : attrs,
8553 : false,
8554 : DELETE_ACCESS);
8555 355 : if (!NT_STATUS_IS_OK(status)) {
8556 86 : if (open_was_deferred(req->xconn, req->mid)) {
8557 : /* We have re-scheduled this call. */
8558 4 : goto out;
8559 : }
8560 82 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
8561 46 : bool ok = defer_smb1_sharing_violation(req);
8562 46 : if (ok) {
8563 22 : goto out;
8564 : }
8565 : }
8566 59 : reply_nterror(req, status);
8567 59 : goto out;
8568 : }
8569 :
8570 269 : reply_outbuf(req, 0, 0);
8571 356 : out:
8572 355 : TALLOC_FREE(smb_fname_src);
8573 355 : TALLOC_FREE(smb_fname_dst);
8574 355 : END_PROFILE(SMBmv);
8575 355 : return;
8576 : }
8577 :
8578 : /*******************************************************************
8579 : Copy a file as part of a reply_copy.
8580 : ******************************************************************/
8581 :
8582 : /*
8583 : * TODO: check error codes on all callers
8584 : */
8585 :
8586 16 : NTSTATUS copy_file(TALLOC_CTX *ctx,
8587 : connection_struct *conn,
8588 : struct smb_filename *smb_fname_src,
8589 : struct smb_filename *smb_fname_dst,
8590 : int ofun,
8591 : int count,
8592 : bool target_is_directory)
8593 : {
8594 16 : struct smb_filename *smb_fname_dst_tmp = NULL;
8595 16 : off_t ret=-1;
8596 : files_struct *fsp1,*fsp2;
8597 : uint32_t dosattrs;
8598 : uint32_t new_create_disposition;
8599 : NTSTATUS status;
8600 :
8601 :
8602 16 : smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
8603 16 : if (smb_fname_dst_tmp == NULL) {
8604 0 : return NT_STATUS_NO_MEMORY;
8605 : }
8606 :
8607 : /*
8608 : * If the target is a directory, extract the last component from the
8609 : * src filename and append it to the dst filename
8610 : */
8611 16 : if (target_is_directory) {
8612 : const char *p;
8613 :
8614 : /* dest/target can't be a stream if it's a directory. */
8615 0 : SMB_ASSERT(smb_fname_dst->stream_name == NULL);
8616 :
8617 0 : p = strrchr_m(smb_fname_src->base_name,'/');
8618 0 : if (p) {
8619 0 : p++;
8620 : } else {
8621 0 : p = smb_fname_src->base_name;
8622 : }
8623 0 : smb_fname_dst_tmp->base_name =
8624 0 : talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
8625 : p);
8626 0 : if (!smb_fname_dst_tmp->base_name) {
8627 0 : status = NT_STATUS_NO_MEMORY;
8628 0 : goto out;
8629 : }
8630 : }
8631 :
8632 16 : status = vfs_file_exist(conn, smb_fname_src);
8633 16 : if (!NT_STATUS_IS_OK(status)) {
8634 0 : goto out;
8635 : }
8636 :
8637 16 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8638 16 : if (!NT_STATUS_IS_OK(status)) {
8639 0 : goto out;
8640 : }
8641 :
8642 16 : if (!target_is_directory && count) {
8643 0 : new_create_disposition = FILE_OPEN;
8644 : } else {
8645 16 : if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
8646 : 0, ofun,
8647 : NULL, NULL,
8648 : &new_create_disposition,
8649 : NULL,
8650 : NULL)) {
8651 0 : status = NT_STATUS_INVALID_PARAMETER;
8652 0 : goto out;
8653 : }
8654 : }
8655 :
8656 : /* Open the src file for reading. */
8657 16 : status = SMB_VFS_CREATE_FILE(
8658 : conn, /* conn */
8659 : NULL, /* req */
8660 : smb_fname_src, /* fname */
8661 : FILE_GENERIC_READ, /* access_mask */
8662 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
8663 : FILE_OPEN, /* create_disposition*/
8664 : 0, /* create_options */
8665 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
8666 : INTERNAL_OPEN_ONLY, /* oplock_request */
8667 : NULL, /* lease */
8668 : 0, /* allocation_size */
8669 : 0, /* private_flags */
8670 : NULL, /* sd */
8671 : NULL, /* ea_list */
8672 : &fsp1, /* result */
8673 : NULL, /* psbuf */
8674 : NULL, NULL); /* create context */
8675 :
8676 16 : if (!NT_STATUS_IS_OK(status)) {
8677 0 : goto out;
8678 : }
8679 :
8680 16 : dosattrs = fdos_mode(fsp1);
8681 :
8682 16 : if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
8683 16 : ZERO_STRUCTP(&smb_fname_dst_tmp->st);
8684 : }
8685 :
8686 16 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
8687 32 : if (!NT_STATUS_IS_OK(status) &&
8688 16 : !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
8689 : {
8690 0 : goto out;
8691 : }
8692 :
8693 : /* Open the dst file for writing. */
8694 16 : status = SMB_VFS_CREATE_FILE(
8695 : conn, /* conn */
8696 : NULL, /* req */
8697 : smb_fname_dst, /* fname */
8698 : FILE_GENERIC_WRITE, /* access_mask */
8699 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
8700 : new_create_disposition, /* create_disposition*/
8701 : 0, /* create_options */
8702 : dosattrs, /* file_attributes */
8703 : INTERNAL_OPEN_ONLY, /* oplock_request */
8704 : NULL, /* lease */
8705 : 0, /* allocation_size */
8706 : 0, /* private_flags */
8707 : NULL, /* sd */
8708 : NULL, /* ea_list */
8709 : &fsp2, /* result */
8710 : NULL, /* psbuf */
8711 : NULL, NULL); /* create context */
8712 :
8713 16 : if (!NT_STATUS_IS_OK(status)) {
8714 0 : close_file(NULL, fsp1, ERROR_CLOSE);
8715 0 : goto out;
8716 : }
8717 :
8718 16 : if (ofun & OPENX_FILE_EXISTS_OPEN) {
8719 0 : ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
8720 0 : if (ret == -1) {
8721 0 : DEBUG(0, ("error - vfs lseek returned error %s\n",
8722 : strerror(errno)));
8723 0 : status = map_nt_error_from_unix(errno);
8724 0 : close_file(NULL, fsp1, ERROR_CLOSE);
8725 0 : close_file(NULL, fsp2, ERROR_CLOSE);
8726 0 : goto out;
8727 : }
8728 : }
8729 :
8730 : /* Do the actual copy. */
8731 16 : if (smb_fname_src->st.st_ex_size) {
8732 16 : ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
8733 : } else {
8734 0 : ret = 0;
8735 : }
8736 :
8737 16 : close_file(NULL, fsp1, NORMAL_CLOSE);
8738 :
8739 : /* Ensure the modtime is set correctly on the destination file. */
8740 16 : set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
8741 :
8742 : /*
8743 : * As we are opening fsp1 read-only we only expect
8744 : * an error on close on fsp2 if we are out of space.
8745 : * Thus we don't look at the error return from the
8746 : * close of fsp1.
8747 : */
8748 16 : status = close_file(NULL, fsp2, NORMAL_CLOSE);
8749 :
8750 16 : if (!NT_STATUS_IS_OK(status)) {
8751 0 : goto out;
8752 : }
8753 :
8754 16 : if (ret != (off_t)smb_fname_src->st.st_ex_size) {
8755 0 : status = NT_STATUS_DISK_FULL;
8756 0 : goto out;
8757 : }
8758 :
8759 16 : status = NT_STATUS_OK;
8760 :
8761 16 : out:
8762 16 : TALLOC_FREE(smb_fname_dst_tmp);
8763 16 : return status;
8764 : }
8765 :
8766 : /****************************************************************************
8767 : Reply to a file copy.
8768 : ****************************************************************************/
8769 :
8770 0 : void reply_copy(struct smb_request *req)
8771 : {
8772 0 : connection_struct *conn = req->conn;
8773 0 : struct smb_filename *smb_fname_src = NULL;
8774 0 : struct smb_filename *smb_fname_src_dir = NULL;
8775 0 : struct smb_filename *smb_fname_dst = NULL;
8776 0 : char *fname_src = NULL;
8777 0 : char *fname_dst = NULL;
8778 0 : char *fname_src_mask = NULL;
8779 0 : char *fname_src_dir = NULL;
8780 : const char *p;
8781 0 : int count=0;
8782 0 : int error = ERRnoaccess;
8783 : int tid2;
8784 : int ofun;
8785 : int flags;
8786 0 : bool target_is_directory=False;
8787 0 : bool source_has_wild = False;
8788 0 : bool dest_has_wild = False;
8789 : NTSTATUS status;
8790 0 : uint32_t ucf_flags_src = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
8791 0 : ucf_flags_from_smb_request(req);
8792 0 : uint32_t ucf_flags_dst = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
8793 0 : ucf_flags_from_smb_request(req);
8794 0 : TALLOC_CTX *ctx = talloc_tos();
8795 :
8796 0 : START_PROFILE(SMBcopy);
8797 :
8798 0 : if (req->wct < 3) {
8799 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8800 0 : goto out;
8801 : }
8802 :
8803 0 : tid2 = SVAL(req->vwv+0, 0);
8804 0 : ofun = SVAL(req->vwv+1, 0);
8805 0 : flags = SVAL(req->vwv+2, 0);
8806 :
8807 0 : p = (const char *)req->buf;
8808 0 : p += srvstr_get_path_req(ctx, req, &fname_src, p, STR_TERMINATE,
8809 : &status);
8810 0 : if (!NT_STATUS_IS_OK(status)) {
8811 0 : reply_nterror(req, status);
8812 0 : goto out;
8813 : }
8814 0 : p += srvstr_get_path_req(ctx, req, &fname_dst, p, STR_TERMINATE,
8815 : &status);
8816 0 : if (!NT_STATUS_IS_OK(status)) {
8817 0 : reply_nterror(req, status);
8818 0 : goto out;
8819 : }
8820 :
8821 0 : DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
8822 :
8823 0 : if (tid2 != conn->cnum) {
8824 : /* can't currently handle inter share copies XXXX */
8825 0 : DEBUG(3,("Rejecting inter-share copy\n"));
8826 0 : reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
8827 0 : goto out;
8828 : }
8829 :
8830 0 : status = filename_convert(ctx, conn,
8831 : fname_src,
8832 : ucf_flags_src,
8833 : 0,
8834 : &smb_fname_src);
8835 0 : if (!NT_STATUS_IS_OK(status)) {
8836 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8837 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8838 : ERRSRV, ERRbadpath);
8839 0 : goto out;
8840 : }
8841 0 : reply_nterror(req, status);
8842 0 : goto out;
8843 : }
8844 :
8845 0 : status = filename_convert(ctx, conn,
8846 : fname_dst,
8847 : ucf_flags_dst,
8848 : 0,
8849 : &smb_fname_dst);
8850 0 : if (!NT_STATUS_IS_OK(status)) {
8851 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8852 0 : reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8853 : ERRSRV, ERRbadpath);
8854 0 : goto out;
8855 : }
8856 0 : reply_nterror(req, status);
8857 0 : goto out;
8858 : }
8859 :
8860 0 : target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
8861 :
8862 0 : if ((flags&1) && target_is_directory) {
8863 0 : reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
8864 0 : goto out;
8865 : }
8866 :
8867 0 : if ((flags&2) && !target_is_directory) {
8868 0 : reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
8869 0 : goto out;
8870 : }
8871 :
8872 0 : if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
8873 : /* wants a tree copy! XXXX */
8874 0 : DEBUG(3,("Rejecting tree copy\n"));
8875 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8876 0 : goto out;
8877 : }
8878 :
8879 : /* Split up the directory from the filename/mask. */
8880 0 : status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
8881 : &fname_src_dir, &fname_src_mask);
8882 0 : if (!NT_STATUS_IS_OK(status)) {
8883 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8884 0 : goto out;
8885 : }
8886 :
8887 0 : if (!req->posix_pathnames) {
8888 0 : char *orig_src_lcomp = NULL;
8889 0 : char *orig_dst_lcomp = NULL;
8890 : /*
8891 : * Check the wildcard mask *before*
8892 : * unmangling. As mangling is done
8893 : * for names that can't be returned
8894 : * to Windows the unmangled name may
8895 : * contain Windows wildcard characters.
8896 : */
8897 0 : orig_src_lcomp = get_original_lcomp(ctx,
8898 : conn,
8899 : fname_src,
8900 : ucf_flags_src);
8901 0 : if (orig_src_lcomp == NULL) {
8902 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8903 0 : goto out;
8904 : }
8905 0 : orig_dst_lcomp = get_original_lcomp(ctx,
8906 : conn,
8907 : fname_dst,
8908 : ucf_flags_dst);
8909 0 : if (orig_dst_lcomp == NULL) {
8910 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8911 0 : goto out;
8912 : }
8913 0 : source_has_wild = ms_has_wild(orig_src_lcomp);
8914 0 : dest_has_wild = ms_has_wild(orig_dst_lcomp);
8915 0 : TALLOC_FREE(orig_src_lcomp);
8916 0 : TALLOC_FREE(orig_dst_lcomp);
8917 : }
8918 :
8919 : /*
8920 : * We should only check the mangled cache
8921 : * here if unix_convert failed. This means
8922 : * that the path in 'mask' doesn't exist
8923 : * on the file system and so we need to look
8924 : * for a possible mangle. This patch from
8925 : * Tine Smukavec <valentin.smukavec@hermes.si>.
8926 : */
8927 0 : if (!VALID_STAT(smb_fname_src->st) &&
8928 0 : mangle_is_mangled(fname_src_mask, conn->params)) {
8929 0 : char *new_mask = NULL;
8930 0 : mangle_lookup_name_from_8_3(ctx, fname_src_mask,
8931 0 : &new_mask, conn->params);
8932 :
8933 : /* Use demangled name if one was successfully found. */
8934 0 : if (new_mask) {
8935 0 : TALLOC_FREE(fname_src_mask);
8936 0 : fname_src_mask = new_mask;
8937 : }
8938 : }
8939 :
8940 0 : if (!source_has_wild) {
8941 :
8942 : /*
8943 : * Only one file needs to be copied. Append the mask back onto
8944 : * the directory.
8945 : */
8946 0 : TALLOC_FREE(smb_fname_src->base_name);
8947 0 : if (ISDOT(fname_src_dir)) {
8948 : /* Ensure we use canonical names on open. */
8949 0 : smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8950 : "%s",
8951 : fname_src_mask);
8952 : } else {
8953 0 : smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8954 : "%s/%s",
8955 : fname_src_dir,
8956 : fname_src_mask);
8957 : }
8958 0 : if (!smb_fname_src->base_name) {
8959 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8960 0 : goto out;
8961 : }
8962 :
8963 0 : if (dest_has_wild) {
8964 0 : char *fname_dst_mod = NULL;
8965 0 : if (!resolve_wildcards(smb_fname_dst,
8966 0 : smb_fname_src->base_name,
8967 0 : smb_fname_dst->base_name,
8968 : &fname_dst_mod)) {
8969 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
8970 0 : goto out;
8971 : }
8972 0 : TALLOC_FREE(smb_fname_dst->base_name);
8973 0 : smb_fname_dst->base_name = fname_dst_mod;
8974 : }
8975 :
8976 0 : status = check_name(conn, smb_fname_src);
8977 0 : if (!NT_STATUS_IS_OK(status)) {
8978 0 : reply_nterror(req, status);
8979 0 : goto out;
8980 : }
8981 :
8982 0 : status = check_name(conn, smb_fname_dst);
8983 0 : if (!NT_STATUS_IS_OK(status)) {
8984 0 : reply_nterror(req, status);
8985 0 : goto out;
8986 : }
8987 :
8988 0 : status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
8989 : ofun, count, target_is_directory);
8990 :
8991 0 : if(!NT_STATUS_IS_OK(status)) {
8992 0 : reply_nterror(req, status);
8993 0 : goto out;
8994 : } else {
8995 0 : count++;
8996 : }
8997 : } else {
8998 0 : struct smb_Dir *dir_hnd = NULL;
8999 0 : const char *dname = NULL;
9000 0 : char *talloced = NULL;
9001 0 : long offset = 0;
9002 :
9003 : /*
9004 : * There is a wildcard that requires us to actually read the
9005 : * src dir and copy each file matching the mask to the dst.
9006 : * Right now streams won't be copied, but this could
9007 : * presumably be added with a nested loop for reach dir entry.
9008 : */
9009 0 : SMB_ASSERT(!smb_fname_src->stream_name);
9010 0 : SMB_ASSERT(!smb_fname_dst->stream_name);
9011 :
9012 0 : smb_fname_src->stream_name = NULL;
9013 0 : smb_fname_dst->stream_name = NULL;
9014 :
9015 0 : if (strequal(fname_src_mask,"????????.???")) {
9016 0 : TALLOC_FREE(fname_src_mask);
9017 0 : fname_src_mask = talloc_strdup(ctx, "*");
9018 0 : if (!fname_src_mask) {
9019 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9020 0 : goto out;
9021 : }
9022 : }
9023 :
9024 0 : smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
9025 : fname_src_dir,
9026 : NULL,
9027 : NULL,
9028 0 : smb_fname_src->twrp,
9029 0 : smb_fname_src->flags);
9030 0 : if (smb_fname_src_dir == NULL) {
9031 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9032 0 : goto out;
9033 : }
9034 :
9035 0 : status = check_name(conn, smb_fname_src_dir);
9036 0 : if (!NT_STATUS_IS_OK(status)) {
9037 0 : reply_nterror(req, status);
9038 0 : goto out;
9039 : }
9040 :
9041 0 : dir_hnd = OpenDir(ctx,
9042 : conn,
9043 : smb_fname_src_dir,
9044 : fname_src_mask,
9045 : 0);
9046 0 : if (dir_hnd == NULL) {
9047 0 : status = map_nt_error_from_unix(errno);
9048 0 : reply_nterror(req, status);
9049 0 : goto out;
9050 : }
9051 :
9052 0 : error = ERRbadfile;
9053 :
9054 : /* Iterate over the src dir copying each entry to the dst. */
9055 0 : while ((dname = ReadDirName(dir_hnd, &offset,
9056 0 : &smb_fname_src->st, &talloced))) {
9057 0 : char *destname = NULL;
9058 :
9059 0 : if (ISDOT(dname) || ISDOTDOT(dname)) {
9060 0 : TALLOC_FREE(talloced);
9061 0 : continue;
9062 : }
9063 :
9064 0 : if (IS_VETO_PATH(conn, dname)) {
9065 0 : TALLOC_FREE(talloced);
9066 0 : continue;
9067 : }
9068 :
9069 0 : if(!mask_match(dname, fname_src_mask,
9070 0 : conn->case_sensitive)) {
9071 0 : TALLOC_FREE(talloced);
9072 0 : continue;
9073 : }
9074 :
9075 0 : error = ERRnoaccess;
9076 :
9077 : /* Get the src smb_fname struct setup. */
9078 0 : TALLOC_FREE(smb_fname_src->base_name);
9079 0 : if (ISDOT(fname_src_dir)) {
9080 : /* Ensure we use canonical names on open. */
9081 0 : smb_fname_src->base_name =
9082 0 : talloc_asprintf(smb_fname_src, "%s",
9083 : dname);
9084 : } else {
9085 0 : smb_fname_src->base_name =
9086 0 : talloc_asprintf(smb_fname_src, "%s/%s",
9087 : fname_src_dir, dname);
9088 : }
9089 :
9090 0 : if (!smb_fname_src->base_name) {
9091 0 : TALLOC_FREE(dir_hnd);
9092 0 : TALLOC_FREE(talloced);
9093 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9094 0 : goto out;
9095 : }
9096 :
9097 0 : if (!resolve_wildcards(ctx, smb_fname_src->base_name,
9098 0 : smb_fname_dst->base_name,
9099 : &destname)) {
9100 0 : TALLOC_FREE(talloced);
9101 0 : continue;
9102 : }
9103 0 : if (!destname) {
9104 0 : TALLOC_FREE(dir_hnd);
9105 0 : TALLOC_FREE(talloced);
9106 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9107 0 : goto out;
9108 : }
9109 :
9110 0 : TALLOC_FREE(smb_fname_dst->base_name);
9111 0 : smb_fname_dst->base_name = destname;
9112 :
9113 0 : ZERO_STRUCT(smb_fname_src->st);
9114 0 : vfs_stat(conn, smb_fname_src);
9115 :
9116 0 : status = openat_pathref_fsp(conn->cwd_fsp,
9117 : smb_fname_src);
9118 0 : if (!NT_STATUS_IS_OK(status)) {
9119 0 : DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
9120 : smb_fname_str_dbg(smb_fname_src),
9121 : nt_errstr(status));
9122 0 : break;
9123 : }
9124 :
9125 0 : if (!is_visible_fsp(smb_fname_src->fsp)) {
9126 0 : TALLOC_FREE(talloced);
9127 0 : continue;
9128 : }
9129 :
9130 0 : status = check_name(conn, smb_fname_src);
9131 0 : if (!NT_STATUS_IS_OK(status)) {
9132 0 : TALLOC_FREE(dir_hnd);
9133 0 : TALLOC_FREE(talloced);
9134 0 : reply_nterror(req, status);
9135 0 : goto out;
9136 : }
9137 :
9138 0 : status = check_name(conn, smb_fname_dst);
9139 0 : if (!NT_STATUS_IS_OK(status)) {
9140 0 : TALLOC_FREE(dir_hnd);
9141 0 : TALLOC_FREE(talloced);
9142 0 : reply_nterror(req, status);
9143 0 : goto out;
9144 : }
9145 :
9146 0 : DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
9147 : smb_fname_src->base_name,
9148 : smb_fname_dst->base_name));
9149 :
9150 0 : status = copy_file(ctx, conn, smb_fname_src,
9151 : smb_fname_dst, ofun, count,
9152 : target_is_directory);
9153 0 : if (NT_STATUS_IS_OK(status)) {
9154 0 : count++;
9155 : }
9156 :
9157 0 : TALLOC_FREE(talloced);
9158 : }
9159 0 : TALLOC_FREE(dir_hnd);
9160 : }
9161 :
9162 0 : if (count == 0) {
9163 0 : reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
9164 0 : goto out;
9165 : }
9166 :
9167 0 : reply_outbuf(req, 1, 0);
9168 0 : SSVAL(req->outbuf,smb_vwv0,count);
9169 0 : out:
9170 0 : TALLOC_FREE(smb_fname_src);
9171 0 : TALLOC_FREE(smb_fname_src_dir);
9172 0 : TALLOC_FREE(smb_fname_dst);
9173 0 : TALLOC_FREE(fname_src);
9174 0 : TALLOC_FREE(fname_dst);
9175 0 : TALLOC_FREE(fname_src_mask);
9176 0 : TALLOC_FREE(fname_src_dir);
9177 :
9178 0 : END_PROFILE(SMBcopy);
9179 0 : return;
9180 : }
9181 :
9182 : #undef DBGC_CLASS
9183 : #define DBGC_CLASS DBGC_LOCKING
9184 :
9185 : /****************************************************************************
9186 : Get a lock pid, dealing with large count requests.
9187 : ****************************************************************************/
9188 :
9189 5671 : uint64_t get_lock_pid(const uint8_t *data, int data_offset,
9190 : bool large_file_format)
9191 : {
9192 5671 : if(!large_file_format)
9193 5151 : return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
9194 : else
9195 520 : return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
9196 : }
9197 :
9198 : /****************************************************************************
9199 : Get a lock count, dealing with large count requests.
9200 : ****************************************************************************/
9201 :
9202 5671 : uint64_t get_lock_count(const uint8_t *data, int data_offset,
9203 : bool large_file_format)
9204 : {
9205 5671 : uint64_t count = 0;
9206 :
9207 5671 : if(!large_file_format) {
9208 5151 : count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
9209 : } else {
9210 : /*
9211 : * No BVAL, this is reversed!
9212 : */
9213 1036 : count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
9214 520 : ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
9215 : }
9216 :
9217 5671 : return count;
9218 : }
9219 :
9220 : /****************************************************************************
9221 : Get a lock offset, dealing with large offset requests.
9222 : ****************************************************************************/
9223 :
9224 5671 : uint64_t get_lock_offset(const uint8_t *data, int data_offset,
9225 : bool large_file_format)
9226 : {
9227 5671 : uint64_t offset = 0;
9228 :
9229 5671 : if(!large_file_format) {
9230 5151 : offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
9231 : } else {
9232 : /*
9233 : * No BVAL, this is reversed!
9234 : */
9235 1036 : offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
9236 520 : ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
9237 : }
9238 :
9239 5671 : return offset;
9240 : }
9241 :
9242 : struct smbd_do_unlocking_state {
9243 : struct files_struct *fsp;
9244 : uint16_t num_ulocks;
9245 : struct smbd_lock_element *ulocks;
9246 : enum brl_flavour lock_flav;
9247 : NTSTATUS status;
9248 : };
9249 :
9250 2286 : static void smbd_do_unlocking_fn(
9251 : const uint8_t *buf,
9252 : size_t buflen,
9253 : bool *pmodified_dependent,
9254 : void *private_data)
9255 : {
9256 2286 : struct smbd_do_unlocking_state *state = private_data;
9257 2286 : struct files_struct *fsp = state->fsp;
9258 2286 : enum brl_flavour lock_flav = state->lock_flav;
9259 : uint16_t i;
9260 :
9261 4404 : for (i = 0; i < state->num_ulocks; i++) {
9262 2328 : struct smbd_lock_element *e = &state->ulocks[i];
9263 :
9264 2328 : DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
9265 : "pid %"PRIu64", file %s\n",
9266 : e->offset,
9267 : e->count,
9268 : e->smblctx,
9269 : fsp_str_dbg(fsp));
9270 :
9271 2328 : if (e->brltype != UNLOCK_LOCK) {
9272 : /* this can only happen with SMB2 */
9273 8 : state->status = NT_STATUS_INVALID_PARAMETER;
9274 8 : return;
9275 : }
9276 :
9277 2320 : state->status = do_unlock(
9278 : fsp, e->smblctx, e->count, e->offset, lock_flav);
9279 :
9280 2320 : DBG_DEBUG("do_unlock returned %s\n",
9281 : nt_errstr(state->status));
9282 :
9283 2320 : if (!NT_STATUS_IS_OK(state->status)) {
9284 200 : return;
9285 : }
9286 : }
9287 :
9288 2076 : *pmodified_dependent = true;
9289 : }
9290 :
9291 2286 : NTSTATUS smbd_do_unlocking(struct smb_request *req,
9292 : files_struct *fsp,
9293 : uint16_t num_ulocks,
9294 : struct smbd_lock_element *ulocks,
9295 : enum brl_flavour lock_flav)
9296 : {
9297 2286 : struct smbd_do_unlocking_state state = {
9298 : .fsp = fsp,
9299 : .num_ulocks = num_ulocks,
9300 : .ulocks = ulocks,
9301 : .lock_flav = lock_flav,
9302 : };
9303 : NTSTATUS status;
9304 :
9305 2286 : DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
9306 :
9307 2286 : status = share_mode_do_locked(
9308 : fsp->file_id, smbd_do_unlocking_fn, &state);
9309 :
9310 2286 : if (!NT_STATUS_IS_OK(status)) {
9311 0 : DBG_DEBUG("share_mode_do_locked failed: %s\n",
9312 : nt_errstr(status));
9313 0 : return status;
9314 : }
9315 2286 : if (!NT_STATUS_IS_OK(state.status)) {
9316 210 : DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
9317 : nt_errstr(status));
9318 210 : return state.status;
9319 : }
9320 :
9321 2076 : return NT_STATUS_OK;
9322 : }
9323 :
9324 : /****************************************************************************
9325 : Reply to a lockingX request.
9326 : ****************************************************************************/
9327 :
9328 : static void reply_lockingx_done(struct tevent_req *subreq);
9329 :
9330 5733 : void reply_lockingX(struct smb_request *req)
9331 : {
9332 5733 : connection_struct *conn = req->conn;
9333 : files_struct *fsp;
9334 : unsigned char locktype;
9335 : enum brl_type brltype;
9336 : unsigned char oplocklevel;
9337 : uint16_t num_ulocks;
9338 : uint16_t num_locks;
9339 : int32_t lock_timeout;
9340 : uint16_t i;
9341 : const uint8_t *data;
9342 : bool large_file_format;
9343 5733 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
9344 5733 : struct smbd_lock_element *locks = NULL;
9345 5733 : struct tevent_req *subreq = NULL;
9346 :
9347 5733 : START_PROFILE(SMBlockingX);
9348 :
9349 5733 : if (req->wct < 8) {
9350 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9351 0 : END_PROFILE(SMBlockingX);
9352 199 : return;
9353 : }
9354 :
9355 5733 : fsp = file_fsp(req, SVAL(req->vwv+2, 0));
9356 5733 : locktype = CVAL(req->vwv+3, 0);
9357 5733 : oplocklevel = CVAL(req->vwv+3, 1);
9358 5733 : num_ulocks = SVAL(req->vwv+6, 0);
9359 5733 : num_locks = SVAL(req->vwv+7, 0);
9360 5733 : lock_timeout = IVAL(req->vwv+4, 0);
9361 5733 : large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
9362 :
9363 5733 : if (!check_fsp(conn, req, fsp)) {
9364 4 : END_PROFILE(SMBlockingX);
9365 4 : return;
9366 : }
9367 :
9368 5729 : data = req->buf;
9369 :
9370 5729 : if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
9371 : /* we don't support these - and CANCEL_LOCK makes w2k
9372 : and XP reboot so I don't really want to be
9373 : compatible! (tridge) */
9374 8 : reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
9375 8 : END_PROFILE(SMBlockingX);
9376 8 : return;
9377 : }
9378 :
9379 : /* Check if this is an oplock break on a file
9380 : we have granted an oplock on.
9381 : */
9382 5721 : if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
9383 : /* Client can insist on breaking to none. */
9384 96 : bool break_to_none = (oplocklevel == 0);
9385 : bool result;
9386 :
9387 96 : DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
9388 : "for %s\n", (unsigned int)oplocklevel,
9389 : fsp_fnum_dbg(fsp)));
9390 :
9391 : /*
9392 : * Make sure we have granted an exclusive or batch oplock on
9393 : * this file.
9394 : */
9395 :
9396 96 : if (fsp->oplock_type == 0) {
9397 :
9398 : /* The Samba4 nbench simulator doesn't understand
9399 : the difference between break to level2 and break
9400 : to none from level2 - it sends oplock break
9401 : replies in both cases. Don't keep logging an error
9402 : message here - just ignore it. JRA. */
9403 :
9404 26 : DEBUG(5,("reply_lockingX: Error : oplock break from "
9405 : "client for %s (oplock=%d) and no "
9406 : "oplock granted on this file (%s).\n",
9407 : fsp_fnum_dbg(fsp), fsp->oplock_type,
9408 : fsp_str_dbg(fsp)));
9409 :
9410 : /* if this is a pure oplock break request then don't
9411 : * send a reply */
9412 26 : if (num_locks == 0 && num_ulocks == 0) {
9413 26 : END_PROFILE(SMBlockingX);
9414 26 : return;
9415 : }
9416 :
9417 0 : END_PROFILE(SMBlockingX);
9418 0 : reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
9419 0 : return;
9420 : }
9421 :
9422 70 : if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
9423 : (break_to_none)) {
9424 24 : result = remove_oplock(fsp);
9425 : } else {
9426 46 : result = downgrade_oplock(fsp);
9427 : }
9428 :
9429 70 : if (!result) {
9430 0 : DEBUG(0, ("reply_lockingX: error in removing "
9431 : "oplock on file %s\n", fsp_str_dbg(fsp)));
9432 : /* Hmmm. Is this panic justified? */
9433 0 : smb_panic("internal tdb error");
9434 : }
9435 :
9436 : /* if this is a pure oplock break request then don't send a
9437 : * reply */
9438 70 : if (num_locks == 0 && num_ulocks == 0) {
9439 : /* Sanity check - ensure a pure oplock break is not a
9440 : chained request. */
9441 70 : if (CVAL(req->vwv+0, 0) != 0xff) {
9442 0 : DEBUG(0,("reply_lockingX: Error : pure oplock "
9443 : "break is a chained %d request !\n",
9444 : (unsigned int)CVAL(req->vwv+0, 0)));
9445 : }
9446 70 : END_PROFILE(SMBlockingX);
9447 70 : return;
9448 : }
9449 : }
9450 :
9451 11250 : if (req->buflen <
9452 5625 : (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
9453 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9454 0 : END_PROFILE(SMBlockingX);
9455 0 : return;
9456 : }
9457 :
9458 5625 : if (num_ulocks != 0) {
9459 1569 : struct smbd_lock_element *ulocks = NULL;
9460 : bool ok;
9461 :
9462 1569 : ulocks = talloc_array(
9463 : req, struct smbd_lock_element, num_ulocks);
9464 1569 : if (ulocks == NULL) {
9465 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9466 0 : END_PROFILE(SMBlockingX);
9467 0 : return;
9468 : }
9469 :
9470 : /*
9471 : * Data now points at the beginning of the list of
9472 : * smb_unlkrng structs
9473 : */
9474 3145 : for (i = 0; i < num_ulocks; i++) {
9475 1581 : ulocks[i].req_guid = smbd_request_guid(req,
9476 1581 : UINT16_MAX - i),
9477 1581 : ulocks[i].smblctx = get_lock_pid(
9478 : data, i, large_file_format);
9479 1581 : ulocks[i].count = get_lock_count(
9480 : data, i, large_file_format);
9481 1581 : ulocks[i].offset = get_lock_offset(
9482 : data, i, large_file_format);
9483 1581 : ulocks[i].brltype = UNLOCK_LOCK;
9484 : }
9485 :
9486 : /*
9487 : * Unlock cancels pending locks
9488 : */
9489 :
9490 1569 : ok = smbd_smb1_brl_finish_by_lock(
9491 : fsp,
9492 : large_file_format,
9493 : WINDOWS_LOCK,
9494 : ulocks[0],
9495 1569 : NT_STATUS_OK);
9496 1569 : if (ok) {
9497 2 : reply_outbuf(req, 2, 0);
9498 2 : SSVAL(req->outbuf, smb_vwv0, 0xff);
9499 2 : SSVAL(req->outbuf, smb_vwv1, 0);
9500 2 : END_PROFILE(SMBlockingX);
9501 2 : return;
9502 : }
9503 :
9504 1567 : status = smbd_do_unlocking(
9505 : req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
9506 1567 : TALLOC_FREE(ulocks);
9507 1567 : if (!NT_STATUS_IS_OK(status)) {
9508 66 : END_PROFILE(SMBlockingX);
9509 66 : reply_nterror(req, status);
9510 66 : return;
9511 : }
9512 : }
9513 :
9514 : /* Now do any requested locks */
9515 5557 : data += ((large_file_format ? 20 : 10)*num_ulocks);
9516 :
9517 : /* Data now points at the beginning of the list
9518 : of smb_lkrng structs */
9519 :
9520 5557 : if (locktype & LOCKING_ANDX_SHARED_LOCK) {
9521 216 : brltype = READ_LOCK;
9522 : } else {
9523 5341 : brltype = WRITE_LOCK;
9524 : }
9525 :
9526 5557 : locks = talloc_array(req, struct smbd_lock_element, num_locks);
9527 5557 : if (locks == NULL) {
9528 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9529 0 : END_PROFILE(SMBlockingX);
9530 0 : return;
9531 : }
9532 :
9533 9632 : for (i = 0; i < num_locks; i++) {
9534 4090 : locks[i].req_guid = smbd_request_guid(req, i),
9535 4090 : locks[i].smblctx = get_lock_pid(data, i, large_file_format);
9536 4090 : locks[i].count = get_lock_count(data, i, large_file_format);
9537 4090 : locks[i].offset = get_lock_offset(data, i, large_file_format);
9538 4090 : locks[i].brltype = brltype;
9539 : }
9540 :
9541 5557 : if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
9542 :
9543 : bool ok;
9544 :
9545 24 : if (num_locks == 0) {
9546 : /* See smbtorture3 lock11 test */
9547 4 : reply_outbuf(req, 2, 0);
9548 : /* andx chain ends */
9549 4 : SSVAL(req->outbuf, smb_vwv0, 0xff);
9550 4 : SSVAL(req->outbuf, smb_vwv1, 0);
9551 4 : END_PROFILE(SMBlockingX);
9552 4 : return;
9553 : }
9554 :
9555 20 : ok = smbd_smb1_brl_finish_by_lock(
9556 : fsp,
9557 : large_file_format,
9558 : WINDOWS_LOCK,
9559 : locks[0], /* Windows only cancels the first lock */
9560 20 : NT_STATUS_FILE_LOCK_CONFLICT);
9561 :
9562 20 : if (!ok) {
9563 10 : reply_force_doserror(req, ERRDOS, ERRcancelviolation);
9564 10 : END_PROFILE(SMBlockingX);
9565 10 : return;
9566 : }
9567 :
9568 10 : reply_outbuf(req, 2, 0);
9569 10 : SSVAL(req->outbuf, smb_vwv0, 0xff);
9570 10 : SSVAL(req->outbuf, smb_vwv1, 0);
9571 10 : END_PROFILE(SMBlockingX);
9572 10 : return;
9573 : }
9574 :
9575 11029 : subreq = smbd_smb1_do_locks_send(
9576 : fsp,
9577 5533 : req->sconn->ev_ctx,
9578 : &req,
9579 : fsp,
9580 : lock_timeout,
9581 : large_file_format,
9582 : WINDOWS_LOCK,
9583 : num_locks,
9584 : locks);
9585 5533 : if (subreq == NULL) {
9586 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
9587 0 : END_PROFILE(SMBlockingX);
9588 0 : return;
9589 : }
9590 5533 : tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
9591 5533 : END_PROFILE(SMBlockingX);
9592 : }
9593 :
9594 5533 : static void reply_lockingx_done(struct tevent_req *subreq)
9595 : {
9596 5533 : struct smb_request *req = NULL;
9597 : NTSTATUS status;
9598 : bool ok;
9599 :
9600 5533 : START_PROFILE(SMBlockingX);
9601 :
9602 5533 : ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
9603 5533 : SMB_ASSERT(ok);
9604 :
9605 5533 : status = smbd_smb1_do_locks_recv(subreq);
9606 5533 : TALLOC_FREE(subreq);
9607 :
9608 5533 : DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
9609 :
9610 5533 : if (NT_STATUS_IS_OK(status)) {
9611 3381 : reply_outbuf(req, 2, 0);
9612 3381 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
9613 3381 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
9614 : } else {
9615 2152 : reply_nterror(req, status);
9616 : }
9617 :
9618 16525 : ok = srv_send_smb(req->xconn,
9619 5533 : (char *)req->outbuf,
9620 : true,
9621 5533 : req->seqnum+1,
9622 5533 : IS_CONN_ENCRYPTED(req->conn),
9623 : NULL);
9624 5533 : if (!ok) {
9625 0 : exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
9626 : }
9627 5533 : TALLOC_FREE(req);
9628 5533 : END_PROFILE(SMBlockingX);
9629 5533 : }
9630 :
9631 : #undef DBGC_CLASS
9632 : #define DBGC_CLASS DBGC_ALL
9633 :
9634 : /****************************************************************************
9635 : Reply to a SMBreadbmpx (read block multiplex) request.
9636 : Always reply with an error, if someone has a platform really needs this,
9637 : please contact vl@samba.org
9638 : ****************************************************************************/
9639 :
9640 0 : void reply_readbmpx(struct smb_request *req)
9641 : {
9642 0 : START_PROFILE(SMBreadBmpx);
9643 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
9644 0 : END_PROFILE(SMBreadBmpx);
9645 0 : return;
9646 : }
9647 :
9648 : /****************************************************************************
9649 : Reply to a SMBreadbs (read block multiplex secondary) request.
9650 : Always reply with an error, if someone has a platform really needs this,
9651 : please contact vl@samba.org
9652 : ****************************************************************************/
9653 :
9654 0 : void reply_readbs(struct smb_request *req)
9655 : {
9656 0 : START_PROFILE(SMBreadBs);
9657 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
9658 0 : END_PROFILE(SMBreadBs);
9659 0 : return;
9660 : }
9661 :
9662 : /****************************************************************************
9663 : Reply to a SMBsetattrE.
9664 : ****************************************************************************/
9665 :
9666 0 : void reply_setattrE(struct smb_request *req)
9667 : {
9668 0 : connection_struct *conn = req->conn;
9669 : struct smb_file_time ft;
9670 : files_struct *fsp;
9671 : NTSTATUS status;
9672 :
9673 0 : START_PROFILE(SMBsetattrE);
9674 0 : init_smb_file_time(&ft);
9675 :
9676 0 : if (req->wct < 7) {
9677 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9678 0 : goto out;
9679 : }
9680 :
9681 0 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
9682 :
9683 0 : if(!fsp || (fsp->conn != conn)) {
9684 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
9685 0 : goto out;
9686 : }
9687 :
9688 : /*
9689 : * Convert the DOS times into unix times.
9690 : */
9691 :
9692 0 : ft.atime = time_t_to_full_timespec(
9693 0 : srv_make_unix_date2(req->vwv+3));
9694 0 : ft.mtime = time_t_to_full_timespec(
9695 0 : srv_make_unix_date2(req->vwv+5));
9696 0 : ft.create_time = time_t_to_full_timespec(
9697 0 : srv_make_unix_date2(req->vwv+1));
9698 :
9699 0 : reply_outbuf(req, 0, 0);
9700 :
9701 : /*
9702 : * Patch from Ray Frush <frush@engr.colostate.edu>
9703 : * Sometimes times are sent as zero - ignore them.
9704 : */
9705 :
9706 : /* Ensure we have a valid stat struct for the source. */
9707 0 : status = vfs_stat_fsp(fsp);
9708 0 : if (!NT_STATUS_IS_OK(status)) {
9709 0 : reply_nterror(req, status);
9710 0 : goto out;
9711 : }
9712 :
9713 0 : if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
9714 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
9715 0 : goto out;
9716 : }
9717 :
9718 0 : status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
9719 0 : if (!NT_STATUS_IS_OK(status)) {
9720 0 : reply_nterror(req, status);
9721 0 : goto out;
9722 : }
9723 :
9724 0 : if (fsp->fsp_flags.modified) {
9725 0 : trigger_write_time_update_immediate(fsp);
9726 : }
9727 :
9728 0 : DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
9729 : " createtime=%u\n",
9730 : fsp_fnum_dbg(fsp),
9731 : (unsigned int)ft.atime.tv_sec,
9732 : (unsigned int)ft.mtime.tv_sec,
9733 : (unsigned int)ft.create_time.tv_sec
9734 : ));
9735 0 : out:
9736 0 : END_PROFILE(SMBsetattrE);
9737 0 : return;
9738 : }
9739 :
9740 :
9741 : /* Back from the dead for OS/2..... JRA. */
9742 :
9743 : /****************************************************************************
9744 : Reply to a SMBwritebmpx (write block multiplex primary) request.
9745 : Always reply with an error, if someone has a platform really needs this,
9746 : please contact vl@samba.org
9747 : ****************************************************************************/
9748 :
9749 0 : void reply_writebmpx(struct smb_request *req)
9750 : {
9751 0 : START_PROFILE(SMBwriteBmpx);
9752 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
9753 0 : END_PROFILE(SMBwriteBmpx);
9754 0 : return;
9755 : }
9756 :
9757 : /****************************************************************************
9758 : Reply to a SMBwritebs (write block multiplex secondary) request.
9759 : Always reply with an error, if someone has a platform really needs this,
9760 : please contact vl@samba.org
9761 : ****************************************************************************/
9762 :
9763 0 : void reply_writebs(struct smb_request *req)
9764 : {
9765 0 : START_PROFILE(SMBwriteBs);
9766 0 : reply_force_doserror(req, ERRSRV, ERRuseSTD);
9767 0 : END_PROFILE(SMBwriteBs);
9768 0 : return;
9769 : }
9770 :
9771 : /****************************************************************************
9772 : Reply to a SMBgetattrE.
9773 : ****************************************************************************/
9774 :
9775 10 : void reply_getattrE(struct smb_request *req)
9776 : {
9777 10 : connection_struct *conn = req->conn;
9778 : int mode;
9779 : files_struct *fsp;
9780 : struct timespec create_ts;
9781 : NTSTATUS status;
9782 :
9783 10 : START_PROFILE(SMBgetattrE);
9784 :
9785 10 : if (req->wct < 1) {
9786 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9787 0 : END_PROFILE(SMBgetattrE);
9788 0 : return;
9789 : }
9790 :
9791 10 : fsp = file_fsp(req, SVAL(req->vwv+0, 0));
9792 :
9793 10 : if(!fsp || (fsp->conn != conn)) {
9794 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
9795 0 : END_PROFILE(SMBgetattrE);
9796 0 : return;
9797 : }
9798 :
9799 : /* Do an fstat on this file */
9800 10 : status = vfs_stat_fsp(fsp);
9801 10 : if (!NT_STATUS_IS_OK(status)) {
9802 0 : reply_nterror(req, status);
9803 0 : END_PROFILE(SMBgetattrE);
9804 0 : return;
9805 : }
9806 :
9807 10 : mode = fdos_mode(fsp);
9808 :
9809 : /*
9810 : * Convert the times into dos times. Set create
9811 : * date to be last modify date as UNIX doesn't save
9812 : * this.
9813 : */
9814 :
9815 10 : reply_outbuf(req, 11, 0);
9816 :
9817 10 : create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
9818 10 : srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
9819 10 : srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
9820 10 : convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
9821 : /* Should we check pending modtime here ? JRA */
9822 10 : srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
9823 10 : convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
9824 :
9825 10 : if (mode & FILE_ATTRIBUTE_DIRECTORY) {
9826 0 : SIVAL(req->outbuf, smb_vwv6, 0);
9827 0 : SIVAL(req->outbuf, smb_vwv8, 0);
9828 : } else {
9829 10 : uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
9830 10 : SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
9831 10 : SIVAL(req->outbuf, smb_vwv8, allocation_size);
9832 : }
9833 10 : SSVAL(req->outbuf,smb_vwv10, mode);
9834 :
9835 10 : DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
9836 :
9837 10 : END_PROFILE(SMBgetattrE);
9838 8 : return;
9839 : }
|