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 "smbd/smbXsrv_open.h"
35 : #include "fake_file.h"
36 : #include "rpc_client/rpc_client.h"
37 : #include "../librpc/gen_ndr/ndr_spoolss_c.h"
38 : #include "rpc_client/cli_spoolss.h"
39 : #include "rpc_client/init_spoolss.h"
40 : #include "rpc_server/rpc_ncacn_np.h"
41 : #include "libcli/security/security.h"
42 : #include "libsmb/nmblib.h"
43 : #include "auth.h"
44 : #include "smbprofile.h"
45 : #include "../lib/tsocket/tsocket.h"
46 : #include "lib/util/tevent_ntstatus.h"
47 : #include "libcli/smb/smb_signing.h"
48 : #include "lib/util/sys_rw_data.h"
49 : #include "librpc/gen_ndr/open_files.h"
50 : #include "libcli/smb/smb2_posix.h"
51 : #include "lib/util/string_wrappers.h"
52 : #include "source3/printing/rap_jobid.h"
53 : #include "source3/lib/substitute.h"
54 :
55 : /****************************************************************************
56 : Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
57 : path or anything including wildcards.
58 : We're assuming here that '/' is not the second byte in any multibyte char
59 : set (a safe assumption). '\\' *may* be the second byte in a multibyte char
60 : set.
61 : ****************************************************************************/
62 :
63 : /* Custom version for processing POSIX paths. */
64 : #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
65 :
66 636770 : NTSTATUS check_path_syntax(char *path, bool posix_path)
67 : {
68 636770 : char *d = path;
69 636770 : const char *s = path;
70 636770 : NTSTATUS ret = NT_STATUS_OK;
71 636770 : bool start_of_name_component = True;
72 636770 : bool stream_started = false;
73 636770 : bool last_component_contains_wcard = false;
74 :
75 15706089 : while (*s) {
76 15069963 : if (stream_started) {
77 95944 : switch (*s) {
78 24 : case '/':
79 : case '\\':
80 74 : return NT_STATUS_OBJECT_NAME_INVALID;
81 4944 : case ':':
82 4944 : if (s[1] == '\0') {
83 36 : return NT_STATUS_OBJECT_NAME_INVALID;
84 : }
85 4908 : if (strchr_m(&s[1], ':')) {
86 14 : return NT_STATUS_OBJECT_NAME_INVALID;
87 : }
88 4893 : break;
89 : }
90 : }
91 :
92 15069889 : if ((*s == ':') && !posix_path && !stream_started) {
93 6608 : 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 6596 : stream_started = true;
103 6596 : start_of_name_component = false;
104 6596 : posix_path = true;
105 :
106 6596 : if (s[1] == '\0') {
107 0 : return NT_STATUS_OBJECT_NAME_INVALID;
108 : }
109 : }
110 :
111 15069877 : 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 2070564 : while (IS_PATH_SEP(*s,posix_path)) {
118 1035338 : s++;
119 : }
120 1035226 : if ((d != path) && (*s != '\0')) {
121 : /* We only care about non-leading or trailing '/' or '\\' */
122 887377 : *d++ = '/';
123 : }
124 :
125 1035226 : start_of_name_component = True;
126 : /* New component. */
127 1035226 : last_component_contains_wcard = false;
128 1035226 : continue;
129 : }
130 :
131 14034651 : if (start_of_name_component) {
132 1483365 : 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 69 : if ((d > path) && (*(d-1) == '/')) {
141 24 : *(d-1) = '\0';
142 24 : d--;
143 : }
144 :
145 : /* Are we at the start ? Can't go back further if so. */
146 69 : if (d <= path) {
147 44 : ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
148 44 : 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 144 : for (d--; d > path; d--) {
155 136 : if (*d == '/')
156 16 : break;
157 : }
158 24 : s += 2; /* Else go past the .. */
159 : /* We're still at the start of a name component, just the previous one. */
160 24 : continue;
161 :
162 1483296 : } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
163 36 : if (posix_path) {
164 : /* Eat the '.' */
165 4 : s++;
166 4 : continue;
167 : }
168 : }
169 :
170 : }
171 :
172 14034578 : if (!(*s & 0x80)) {
173 13903352 : if (!posix_path) {
174 13733922 : if (*s <= 0x1f || *s == '|') {
175 513 : return NT_STATUS_OBJECT_NAME_INVALID;
176 : }
177 13733409 : switch (*s) {
178 12620 : case '*':
179 : case '?':
180 : case '<':
181 : case '>':
182 : case '"':
183 12620 : last_component_contains_wcard = true;
184 12620 : break;
185 13519180 : default:
186 13519180 : break;
187 : }
188 : }
189 13902839 : *d++ = *s++;
190 : } else {
191 0 : size_t ch_size;
192 : /* Get the size of the next MB character. */
193 131226 : next_codepoint(s,&ch_size);
194 131226 : switch(ch_size) {
195 0 : case 5:
196 0 : *d++ = *s++;
197 0 : FALL_THROUGH;
198 0 : case 4:
199 0 : *d++ = *s++;
200 0 : FALL_THROUGH;
201 131166 : case 3:
202 131166 : *d++ = *s++;
203 0 : FALL_THROUGH;
204 131226 : case 2:
205 131226 : *d++ = *s++;
206 0 : FALL_THROUGH;
207 131226 : case 1:
208 131226 : *d++ = *s++;
209 131226 : break;
210 0 : default:
211 0 : DBG_ERR("character length assumptions invalid !\n");
212 0 : *d = '\0';
213 0 : return NT_STATUS_INVALID_PARAMETER;
214 : }
215 : }
216 13832346 : start_of_name_component = False;
217 : }
218 :
219 636171 : *d = '\0';
220 :
221 636171 : return ret;
222 : }
223 :
224 : /****************************************************************************
225 : SMB2-only code to strip an MSDFS prefix from an incoming pathname.
226 : ****************************************************************************/
227 :
228 12584 : NTSTATUS smb2_strip_dfs_path(const char *in_path, const char **out_path)
229 : {
230 12584 : const char *path = in_path;
231 :
232 : /* Match the Windows 2022 behavior for an empty DFS pathname. */
233 12584 : if (*path == '\0') {
234 2 : return NT_STATUS_INVALID_PARAMETER;
235 : }
236 : /* Strip any leading '\\' characters - MacOSX client behavior. */
237 12598 : while (*path == '\\') {
238 16 : path++;
239 : }
240 : /* We should now be pointing at the server name. Go past it. */
241 0 : for (;;) {
242 166834 : if (*path == '\0') {
243 : /* End of complete path. Exit OK. */
244 6 : goto out;
245 : }
246 166828 : if (*path == '\\') {
247 : /* End of server name. Go past and break. */
248 12576 : path++;
249 12576 : break;
250 : }
251 154252 : path++; /* Continue looking for end of server name or string. */
252 : }
253 :
254 : /* We should now be pointing at the share name. Go past it. */
255 0 : for (;;) {
256 178014 : if (*path == '\0') {
257 : /* End of complete path. Exit OK. */
258 424 : goto out;
259 : }
260 177590 : if (*path == '\\') {
261 : /* End of share name. Go past and break. */
262 12150 : path++;
263 12150 : break;
264 : }
265 165440 : if (*path == ':') {
266 : /* Only invalid character in sharename. */
267 2 : return NT_STATUS_OBJECT_NAME_INVALID;
268 : }
269 165438 : path++; /* Continue looking for end of share name or string. */
270 : }
271 :
272 : /* path now points at the start of the real filename (if any). */
273 :
274 12580 : out:
275 : /* We have stripped the DFS path prefix (if any). */
276 12580 : *out_path = path;
277 12580 : return NT_STATUS_OK;
278 : }
279 :
280 : /****************************************************************************
281 : Pull a string and check the path allowing a wildcard - provide for error return.
282 : Passes in posix flag.
283 : ****************************************************************************/
284 :
285 158216 : static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
286 : const char *base_ptr,
287 : uint16_t smb_flags2,
288 : char **pp_dest,
289 : const char *src,
290 : size_t src_len,
291 : int flags,
292 : bool posix_pathnames,
293 : NTSTATUS *err)
294 : {
295 10176 : size_t ret;
296 158216 : char *dst = NULL;
297 :
298 158216 : *pp_dest = NULL;
299 :
300 158216 : ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
301 : src_len, flags);
302 :
303 158216 : if (!*pp_dest) {
304 0 : *err = NT_STATUS_INVALID_PARAMETER;
305 0 : return ret;
306 : }
307 :
308 158216 : dst = *pp_dest;
309 :
310 158216 : if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
311 : /*
312 : * A valid DFS path looks either like
313 : * /server/share
314 : * \server\share
315 : * (there may be more components after).
316 : * Either way it must have at least two separators.
317 : *
318 : * Ensure we end up as /server/share
319 : * so we don't need to special case
320 : * separator characters elsewhere in
321 : * the code.
322 : */
323 1590 : char *server = NULL;
324 1590 : char *share = NULL;
325 1590 : char *remaining_path = NULL;
326 1590 : char path_sep = 0;
327 1590 : char *p = NULL;
328 :
329 1590 : if (posix_pathnames && (dst[0] == '/')) {
330 0 : path_sep = dst[0];
331 1590 : } else if (dst[0] == '\\') {
332 1536 : path_sep = dst[0];
333 : }
334 :
335 1590 : if (path_sep == 0) {
336 54 : goto local_path;
337 : }
338 : /*
339 : * May be a DFS path.
340 : * We need some heuristics here,
341 : * as clients differ on what constitutes
342 : * a well-formed DFS path. If the path
343 : * appears malformed, just fall back to
344 : * processing as a local path.
345 : */
346 1536 : server = dst;
347 :
348 : /*
349 : * Cosmetic fix for Linux-only DFS clients.
350 : * The Linux kernel SMB1 client has a bug - it sends
351 : * DFS pathnames as:
352 : *
353 : * \\server\share\path
354 : *
355 : * Causing us to mis-parse server,share,remaining_path here
356 : * and jump into 'goto local_path' at 'share\path' instead
357 : * of 'path'.
358 : *
359 : * This doesn't cause an error as the limits on share names
360 : * are similar to those on pathnames.
361 : *
362 : * parse_dfs_path() which we call before filename parsing
363 : * copes with this by calling trim_char on the leading '\'
364 : * characters before processing.
365 : * Do the same here so logging of pathnames looks better.
366 : */
367 1536 : if (server[1] == path_sep) {
368 18 : trim_char(&server[1], path_sep, '\0');
369 : }
370 :
371 : /*
372 : * Look to see if we also have /share following.
373 : */
374 1536 : share = strchr(server+1, path_sep);
375 1536 : if (share == NULL) {
376 22 : goto local_path;
377 : }
378 : /*
379 : * Ensure the server name does not contain
380 : * any possible path components by converting
381 : * them to _'s.
382 : */
383 26840 : for (p = server + 1; p < share; p++) {
384 25326 : if (*p == '/' || *p == '\\') {
385 4 : *p = '_';
386 : }
387 : }
388 : /*
389 : * It's a well formed DFS path with
390 : * at least server and share components.
391 : * Replace the slashes with '/' and
392 : * pass the remainder to local_path.
393 : */
394 1514 : *server = '/';
395 1514 : *share = '/';
396 : /*
397 : * Skip past share so we don't pass the
398 : * sharename into check_path_syntax().
399 : */
400 1514 : remaining_path = strchr(share+1, path_sep);
401 1514 : if (remaining_path == NULL) {
402 : /*
403 : * Ensure the share name does not contain
404 : * any possible path components by converting
405 : * them to _'s.
406 : */
407 322 : for (p = share + 1; *p; p++) {
408 290 : if (*p == '/' || *p == '\\') {
409 2 : *p = '_';
410 : }
411 : }
412 : /*
413 : * If no remaining path this was
414 : * a bare /server/share path. Just return.
415 : */
416 32 : *err = NT_STATUS_OK;
417 32 : return ret;
418 : }
419 : /*
420 : * Ensure the share name does not contain
421 : * any possible path components by converting
422 : * them to _'s.
423 : */
424 17854 : for (p = share + 1; p < remaining_path; p++) {
425 16372 : if (*p == '/' || *p == '\\') {
426 0 : *p = '_';
427 : }
428 : }
429 1482 : *remaining_path = '/';
430 1482 : dst = remaining_path + 1;
431 : /* dst now points at any following components. */
432 : }
433 :
434 156626 : local_path:
435 :
436 158184 : *err = check_path_syntax(dst, posix_pathnames);
437 :
438 158184 : return ret;
439 : }
440 :
441 : /****************************************************************************
442 : Pull a string and check the path - provide for error return.
443 : ****************************************************************************/
444 :
445 20415 : size_t srvstr_get_path(TALLOC_CTX *ctx,
446 : const char *base_ptr,
447 : uint16_t smb_flags2,
448 : char **pp_dest,
449 : const char *src,
450 : size_t src_len,
451 : int flags,
452 : NTSTATUS *err)
453 : {
454 20415 : return srvstr_get_path_internal(ctx,
455 : base_ptr,
456 : smb_flags2,
457 : pp_dest,
458 : src,
459 : src_len,
460 : flags,
461 : false,
462 : err);
463 : }
464 :
465 : /****************************************************************************
466 : Pull a string and check the path - provide for error return.
467 : posix_pathnames version.
468 : ****************************************************************************/
469 :
470 1860 : size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
471 : const char *base_ptr,
472 : uint16_t smb_flags2,
473 : char **pp_dest,
474 : const char *src,
475 : size_t src_len,
476 : int flags,
477 : NTSTATUS *err)
478 : {
479 1860 : return srvstr_get_path_internal(ctx,
480 : base_ptr,
481 : smb_flags2,
482 : pp_dest,
483 : src,
484 : src_len,
485 : flags,
486 : true,
487 : err);
488 : }
489 :
490 :
491 135941 : size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
492 : char **pp_dest, const char *src, int flags,
493 : NTSTATUS *err)
494 : {
495 135941 : ssize_t bufrem = smbreq_bufrem(req, src);
496 :
497 135941 : if (bufrem == 0) {
498 0 : *err = NT_STATUS_INVALID_PARAMETER;
499 0 : return 0;
500 : }
501 :
502 135941 : if (req->posix_pathnames) {
503 407 : return srvstr_get_path_internal(mem_ctx,
504 407 : (const char *)req->inbuf,
505 407 : req->flags2,
506 : pp_dest,
507 : src,
508 : bufrem,
509 : flags,
510 : true,
511 : err);
512 : } else {
513 135534 : return srvstr_get_path_internal(mem_ctx,
514 135534 : (const char *)req->inbuf,
515 135534 : req->flags2,
516 : pp_dest,
517 : src,
518 : bufrem,
519 : flags,
520 : false,
521 : err);
522 : }
523 : }
524 :
525 : /**
526 : * pull a string from the smb_buf part of a packet. In this case the
527 : * string can either be null terminated or it can be terminated by the
528 : * end of the smbbuf area
529 : */
530 49529 : size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
531 : char **dest, const uint8_t *src, int flags)
532 : {
533 49529 : ssize_t bufrem = smbreq_bufrem(req, src);
534 :
535 49529 : if (bufrem == 0) {
536 7220 : *dest = NULL;
537 7220 : return 0;
538 : }
539 :
540 42309 : return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
541 : bufrem, flags);
542 : }
543 :
544 : /****************************************************************************
545 : Check if we have a correct fsp pointing to a quota fake file. Replacement for
546 : the CHECK_NTQUOTA_HANDLE_OK macro.
547 : ****************************************************************************/
548 :
549 24 : bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
550 : files_struct *fsp)
551 : {
552 24 : if ((fsp == NULL) || (conn == NULL)) {
553 0 : return false;
554 : }
555 :
556 24 : if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
557 0 : return false;
558 : }
559 :
560 24 : if (fsp->fsp_flags.is_directory) {
561 4 : return false;
562 : }
563 :
564 20 : if (fsp->fake_file_handle == NULL) {
565 0 : return false;
566 : }
567 :
568 20 : if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
569 0 : return false;
570 : }
571 :
572 20 : if (fsp->fake_file_handle->private_data == NULL) {
573 0 : return false;
574 : }
575 :
576 20 : return true;
577 : }
578 :
579 : /****************************************************************************
580 : Return the port number we've bound to on a socket.
581 : ****************************************************************************/
582 :
583 1035 : static int get_socket_port(int fd)
584 : {
585 1035 : struct samba_sockaddr saddr = {
586 : .sa_socklen = sizeof(struct sockaddr_storage),
587 : };
588 :
589 1035 : if (fd == -1) {
590 0 : return -1;
591 : }
592 :
593 1035 : if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
594 0 : int level = (errno == ENOTCONN) ? 2 : 0;
595 0 : DEBUG(level, ("getsockname failed. Error was %s\n",
596 : strerror(errno)));
597 0 : return -1;
598 : }
599 :
600 : #if defined(HAVE_IPV6)
601 1035 : if (saddr.u.sa.sa_family == AF_INET6) {
602 22 : return ntohs(saddr.u.in6.sin6_port);
603 : }
604 : #endif
605 1013 : if (saddr.u.sa.sa_family == AF_INET) {
606 1013 : return ntohs(saddr.u.in.sin_port);
607 : }
608 0 : return -1;
609 : }
610 :
611 1035 : static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
612 : const char *name, int name_type)
613 : {
614 0 : char *trim_name;
615 0 : char *trim_name_type;
616 0 : const char *retarget_parm;
617 0 : char *retarget;
618 0 : char *p;
619 1035 : int retarget_type = 0x20;
620 1035 : int retarget_port = NBT_SMB_PORT;
621 0 : struct sockaddr_storage retarget_addr;
622 0 : struct sockaddr_in *in_addr;
623 1035 : bool ret = false;
624 0 : uint8_t outbuf[10];
625 :
626 1035 : if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
627 0 : return false;
628 : }
629 :
630 1035 : trim_name = talloc_strdup(talloc_tos(), name);
631 1035 : if (trim_name == NULL) {
632 0 : goto fail;
633 : }
634 1035 : trim_char(trim_name, ' ', ' ');
635 :
636 1035 : trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
637 : name_type);
638 1035 : if (trim_name_type == NULL) {
639 0 : goto fail;
640 : }
641 :
642 1035 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
643 : trim_name_type, NULL);
644 1035 : if (retarget_parm == NULL) {
645 1035 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
646 : trim_name, NULL);
647 : }
648 1035 : if (retarget_parm == NULL) {
649 1035 : goto fail;
650 : }
651 :
652 0 : retarget = talloc_strdup(trim_name, retarget_parm);
653 0 : if (retarget == NULL) {
654 0 : goto fail;
655 : }
656 :
657 0 : DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
658 :
659 0 : p = strchr(retarget, ':');
660 0 : if (p != NULL) {
661 0 : *p++ = '\0';
662 0 : retarget_port = atoi(p);
663 : }
664 :
665 0 : p = strchr_m(retarget, '#');
666 0 : if (p != NULL) {
667 0 : *p++ = '\0';
668 0 : if (sscanf(p, "%x", &retarget_type) != 1) {
669 0 : goto fail;
670 : }
671 : }
672 :
673 0 : ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
674 0 : if (!ret) {
675 0 : DEBUG(10, ("could not resolve %s\n", retarget));
676 0 : goto fail;
677 : }
678 :
679 0 : if (retarget_addr.ss_family != AF_INET) {
680 0 : DEBUG(10, ("Retarget target not an IPv4 addr\n"));
681 0 : goto fail;
682 : }
683 :
684 0 : in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
685 :
686 0 : _smb_setlen(outbuf, 6);
687 0 : SCVAL(outbuf, 0, 0x84);
688 0 : *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
689 0 : *(uint16_t *)(outbuf+8) = htons(retarget_port);
690 :
691 0 : if (!smb1_srv_send(xconn, (char *)outbuf, false, 0, false)) {
692 0 : exit_server_cleanly("netbios_session_retarget: smb1_srv_send "
693 : "failed.");
694 : }
695 :
696 0 : ret = true;
697 1035 : fail:
698 1035 : TALLOC_FREE(trim_name);
699 1035 : return ret;
700 : }
701 :
702 4 : static void reply_called_name_not_present(char *outbuf)
703 : {
704 4 : smb_setlen(outbuf, 1);
705 4 : SCVAL(outbuf, 0, 0x83);
706 4 : SCVAL(outbuf, 4, 0x82);
707 4 : }
708 :
709 : /****************************************************************************
710 : Reply to a (netbios-level) special message.
711 : ****************************************************************************/
712 :
713 1039 : void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
714 : {
715 1039 : struct smbd_server_connection *sconn = xconn->client->sconn;
716 1039 : int msg_type = CVAL(inbuf,0);
717 1039 : int msg_flags = CVAL(inbuf,1);
718 : /*
719 : * We only really use 4 bytes of the outbuf, but for the smb_setlen
720 : * calculation & friends (smb1_srv_send uses that) we need the full smb
721 : * header.
722 : */
723 0 : char outbuf[smb_size];
724 :
725 1039 : memset(outbuf, '\0', sizeof(outbuf));
726 :
727 1039 : smb_setlen(outbuf,0);
728 :
729 1039 : switch (msg_type) {
730 1039 : case NBSSrequest: /* session request */
731 : {
732 : /* inbuf_size is guaranteed to be at least 4. */
733 0 : fstring name1,name2;
734 0 : int name_type1, name_type2;
735 0 : int name_len1, name_len2;
736 :
737 1039 : *name1 = *name2 = 0;
738 :
739 1039 : if (xconn->transport.nbt.got_session) {
740 0 : exit_server_cleanly("multiple session request not permitted");
741 : }
742 :
743 1039 : SCVAL(outbuf,0,NBSSpositive);
744 1039 : SCVAL(outbuf,3,0);
745 :
746 : /* inbuf_size is guaranteed to be at least 4. */
747 1039 : name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
748 1039 : if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
749 0 : DEBUG(0,("Invalid name length in session request\n"));
750 0 : reply_called_name_not_present(outbuf);
751 0 : break;
752 : }
753 1039 : name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
754 1039 : if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
755 4 : DEBUG(0,("Invalid name length in session request\n"));
756 4 : reply_called_name_not_present(outbuf);
757 4 : break;
758 : }
759 :
760 1035 : name_type1 = name_extract((unsigned char *)inbuf,
761 : inbuf_size,(unsigned int)4,name1);
762 1035 : name_type2 = name_extract((unsigned char *)inbuf,
763 1035 : inbuf_size,(unsigned int)(4 + name_len1),name2);
764 :
765 1035 : if (name_type1 == -1 || name_type2 == -1) {
766 0 : DEBUG(0,("Invalid name type in session request\n"));
767 0 : reply_called_name_not_present(outbuf);
768 0 : break;
769 : }
770 :
771 1035 : DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
772 : name1, name_type1, name2, name_type2));
773 :
774 1035 : if (netbios_session_retarget(xconn, name1, name_type1)) {
775 0 : exit_server_cleanly("retargeted client");
776 : }
777 :
778 : /*
779 : * Windows NT/2k uses "*SMBSERVER" and XP uses
780 : * "*SMBSERV" arrggg!!!
781 : */
782 1035 : if (strequal(name1, "*SMBSERVER ")
783 1035 : || strequal(name1, "*SMBSERV ")) {
784 0 : char *raddr;
785 :
786 0 : raddr = tsocket_address_inet_addr_string(sconn->remote_address,
787 : talloc_tos());
788 0 : if (raddr == NULL) {
789 0 : exit_server_cleanly("could not allocate raddr");
790 : }
791 :
792 0 : fstrcpy(name1, raddr);
793 : }
794 :
795 1035 : set_local_machine_name(name1, True);
796 1035 : set_remote_machine_name(name2, True);
797 :
798 1035 : if (is_ipaddress(sconn->remote_hostname)) {
799 1035 : char *p = discard_const_p(char, sconn->remote_hostname);
800 :
801 1035 : talloc_free(p);
802 :
803 1035 : sconn->remote_hostname = talloc_strdup(sconn,
804 : get_remote_machine_name());
805 1035 : if (sconn->remote_hostname == NULL) {
806 0 : exit_server_cleanly("could not copy remote name");
807 : }
808 1035 : xconn->remote_hostname = sconn->remote_hostname;
809 : }
810 :
811 1035 : DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
812 : get_local_machine_name(), get_remote_machine_name(),
813 : name_type2));
814 :
815 1035 : if (name_type2 == 'R') {
816 : /* We are being asked for a pathworks session ---
817 : no thanks! */
818 0 : reply_called_name_not_present(outbuf);
819 0 : break;
820 : }
821 :
822 1035 : reload_services(sconn, conn_snum_used, true);
823 1035 : reopen_logs();
824 :
825 1035 : xconn->transport.nbt.got_session = true;
826 1035 : break;
827 : }
828 :
829 0 : case 0x89: /* session keepalive request
830 : (some old clients produce this?) */
831 0 : SCVAL(outbuf,0,NBSSkeepalive);
832 0 : SCVAL(outbuf,3,0);
833 0 : break;
834 :
835 0 : case NBSSpositive: /* positive session response */
836 : case NBSSnegative: /* negative session response */
837 : case NBSSretarget: /* retarget session response */
838 0 : DEBUG(0,("Unexpected session response\n"));
839 0 : break;
840 :
841 0 : case NBSSkeepalive: /* session keepalive */
842 : default:
843 0 : return;
844 : }
845 :
846 1039 : DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
847 : msg_type, msg_flags));
848 :
849 1039 : if (!smb1_srv_send(xconn, outbuf, false, 0, false)) {
850 0 : exit_server_cleanly("reply_special: smb1_srv_send failed.");
851 : }
852 :
853 1039 : if (CVAL(outbuf, 0) != 0x82) {
854 4 : exit_server_cleanly("invalid netbios session");
855 : }
856 1035 : return;
857 : }
858 :
859 : /*******************************************************************
860 : * unlink a file with all relevant access checks
861 : *******************************************************************/
862 :
863 26903 : NTSTATUS unlink_internals(connection_struct *conn,
864 : struct smb_request *req,
865 : uint32_t dirtype,
866 : struct files_struct *dirfsp,
867 : struct smb_filename *smb_fname)
868 : {
869 381 : uint32_t fattr;
870 381 : files_struct *fsp;
871 26903 : uint32_t dirtype_orig = dirtype;
872 381 : NTSTATUS status;
873 381 : int ret;
874 26903 : struct smb2_create_blobs *posx = NULL;
875 :
876 26903 : if (dirtype == 0) {
877 88 : dirtype = FILE_ATTRIBUTE_NORMAL;
878 : }
879 :
880 26903 : DBG_DEBUG("%s, dirtype = %d\n",
881 : smb_fname_str_dbg(smb_fname),
882 : dirtype);
883 :
884 26903 : if (!CAN_WRITE(conn)) {
885 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
886 : }
887 :
888 26903 : ret = vfs_stat(conn, smb_fname);
889 26903 : if (ret != 0) {
890 2621 : return map_nt_error_from_unix(errno);
891 : }
892 :
893 24282 : fattr = fdos_mode(smb_fname->fsp);
894 :
895 24282 : if (dirtype & FILE_ATTRIBUTE_NORMAL) {
896 72 : dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
897 : }
898 :
899 24282 : dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
900 24282 : if (!dirtype) {
901 0 : return NT_STATUS_NO_SUCH_FILE;
902 : }
903 :
904 24282 : if (!dir_check_ftype(fattr, dirtype)) {
905 24 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
906 20 : return NT_STATUS_FILE_IS_A_DIRECTORY;
907 : }
908 4 : return NT_STATUS_NO_SUCH_FILE;
909 : }
910 :
911 24258 : if (dirtype_orig & 0x8000) {
912 : /* These will never be set for POSIX. */
913 0 : return NT_STATUS_NO_SUCH_FILE;
914 : }
915 :
916 : #if 0
917 : if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
918 : return NT_STATUS_FILE_IS_A_DIRECTORY;
919 : }
920 :
921 : if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
922 : return NT_STATUS_NO_SUCH_FILE;
923 : }
924 :
925 : if (dirtype & 0xFF00) {
926 : /* These will never be set for POSIX. */
927 : return NT_STATUS_NO_SUCH_FILE;
928 : }
929 :
930 : dirtype &= 0xFF;
931 : if (!dirtype) {
932 : return NT_STATUS_NO_SUCH_FILE;
933 : }
934 :
935 : /* Can't delete a directory. */
936 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
937 : return NT_STATUS_FILE_IS_A_DIRECTORY;
938 : }
939 : #endif
940 :
941 : #if 0 /* JRATEST */
942 : else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
943 : return NT_STATUS_OBJECT_NAME_INVALID;
944 : #endif /* JRATEST */
945 :
946 24258 : if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
947 22 : status = make_smb2_posix_create_ctx(
948 : talloc_tos(), &posx, 0777);
949 22 : if (!NT_STATUS_IS_OK(status)) {
950 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
951 : nt_errstr(status));
952 0 : return status;
953 : }
954 : }
955 :
956 : /* On open checks the open itself will check the share mode, so
957 : don't do it here as we'll get it wrong. */
958 :
959 24258 : status = SMB_VFS_CREATE_FILE
960 : (conn, /* conn */
961 : req, /* req */
962 : dirfsp, /* dirfsp */
963 : smb_fname, /* fname */
964 : DELETE_ACCESS, /* access_mask */
965 : FILE_SHARE_NONE, /* share_access */
966 : FILE_OPEN, /* create_disposition*/
967 : FILE_NON_DIRECTORY_FILE |
968 : FILE_OPEN_REPARSE_POINT, /* create_options */
969 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
970 : 0, /* oplock_request */
971 : NULL, /* lease */
972 : 0, /* allocation_size */
973 : 0, /* private_flags */
974 : NULL, /* sd */
975 : NULL, /* ea_list */
976 : &fsp, /* result */
977 : NULL, /* pinfo */
978 : posx, /* in_context_blobs */
979 : NULL); /* out_context_blobs */
980 :
981 24258 : TALLOC_FREE(posx);
982 :
983 24258 : if (!NT_STATUS_IS_OK(status)) {
984 1039 : DBG_DEBUG("SMB_VFS_CREATEFILE failed: %s\n",
985 : nt_errstr(status));
986 1039 : return status;
987 : }
988 :
989 23219 : status = can_set_delete_on_close(fsp, fattr);
990 23219 : if (!NT_STATUS_IS_OK(status)) {
991 8 : DBG_DEBUG("can_set_delete_on_close for file %s - "
992 : "(%s)\n",
993 : smb_fname_str_dbg(smb_fname),
994 : nt_errstr(status));
995 8 : close_file_free(req, &fsp, NORMAL_CLOSE);
996 8 : return status;
997 : }
998 :
999 : /* The set is across all open files on this dev/inode pair. */
1000 23211 : if (!set_delete_on_close(fsp, True,
1001 23211 : conn->session_info->security_token,
1002 23211 : conn->session_info->unix_token)) {
1003 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
1004 0 : return NT_STATUS_ACCESS_DENIED;
1005 : }
1006 :
1007 23211 : return close_file_free(req, &fsp, NORMAL_CLOSE);
1008 : }
1009 :
1010 : /****************************************************************************
1011 : Fake (read/write) sendfile. Returns -1 on read or write fail.
1012 : ****************************************************************************/
1013 :
1014 12 : ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
1015 : off_t startpos, size_t nread)
1016 : {
1017 0 : size_t bufsize;
1018 12 : size_t tosend = nread;
1019 0 : char *buf;
1020 :
1021 12 : if (nread == 0) {
1022 0 : return 0;
1023 : }
1024 :
1025 12 : bufsize = MIN(nread, 65536);
1026 :
1027 12 : if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
1028 0 : return -1;
1029 : }
1030 :
1031 1716 : while (tosend > 0) {
1032 0 : ssize_t ret;
1033 0 : size_t cur_read;
1034 :
1035 1704 : cur_read = MIN(tosend, bufsize);
1036 1704 : ret = read_file(fsp,buf,startpos,cur_read);
1037 1704 : if (ret == -1) {
1038 0 : SAFE_FREE(buf);
1039 0 : return -1;
1040 : }
1041 :
1042 : /* If we had a short read, fill with zeros. */
1043 1704 : if (ret < cur_read) {
1044 0 : memset(buf + ret, '\0', cur_read - ret);
1045 : }
1046 :
1047 1704 : ret = write_data(xconn->transport.sock, buf, cur_read);
1048 1704 : if (ret != cur_read) {
1049 0 : int saved_errno = errno;
1050 : /*
1051 : * Try and give an error message saying what
1052 : * client failed.
1053 : */
1054 0 : DEBUG(0, ("write_data failed for client %s. "
1055 : "Error %s\n",
1056 : smbXsrv_connection_dbg(xconn),
1057 : strerror(saved_errno)));
1058 0 : SAFE_FREE(buf);
1059 0 : errno = saved_errno;
1060 0 : return -1;
1061 : }
1062 1704 : tosend -= cur_read;
1063 1704 : startpos += cur_read;
1064 : }
1065 :
1066 12 : SAFE_FREE(buf);
1067 12 : return (ssize_t)nread;
1068 : }
1069 :
1070 : /****************************************************************************
1071 : Deal with the case of sendfile reading less bytes from the file than
1072 : requested. Fill with zeros (all we can do). Returns 0 on success
1073 : ****************************************************************************/
1074 :
1075 0 : ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
1076 : files_struct *fsp,
1077 : ssize_t nread,
1078 : size_t headersize,
1079 : size_t smb_maxcnt)
1080 : {
1081 : #define SHORT_SEND_BUFSIZE 1024
1082 0 : if (nread < headersize) {
1083 0 : DEBUG(0,("sendfile_short_send: sendfile failed to send "
1084 : "header for file %s (%s). Terminating\n",
1085 : fsp_str_dbg(fsp), strerror(errno)));
1086 0 : return -1;
1087 : }
1088 :
1089 0 : nread -= headersize;
1090 :
1091 0 : if (nread < smb_maxcnt) {
1092 0 : char buf[SHORT_SEND_BUFSIZE] = { 0 };
1093 :
1094 0 : DEBUG(0,("sendfile_short_send: filling truncated file %s "
1095 : "with zeros !\n", fsp_str_dbg(fsp)));
1096 :
1097 0 : while (nread < smb_maxcnt) {
1098 : /*
1099 : * We asked for the real file size and told sendfile
1100 : * to not go beyond the end of the file. But it can
1101 : * happen that in between our fstat call and the
1102 : * sendfile call the file was truncated. This is very
1103 : * bad because we have already announced the larger
1104 : * number of bytes to the client.
1105 : *
1106 : * The best we can do now is to send 0-bytes, just as
1107 : * a read from a hole in a sparse file would do.
1108 : *
1109 : * This should happen rarely enough that I don't care
1110 : * about efficiency here :-)
1111 : */
1112 0 : size_t to_write;
1113 0 : ssize_t ret;
1114 :
1115 0 : to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
1116 0 : ret = write_data(xconn->transport.sock, buf, to_write);
1117 0 : if (ret != to_write) {
1118 0 : int saved_errno = errno;
1119 : /*
1120 : * Try and give an error message saying what
1121 : * client failed.
1122 : */
1123 0 : DEBUG(0, ("write_data failed for client %s. "
1124 : "Error %s\n",
1125 : smbXsrv_connection_dbg(xconn),
1126 : strerror(saved_errno)));
1127 0 : errno = saved_errno;
1128 0 : return -1;
1129 : }
1130 0 : nread += to_write;
1131 : }
1132 : }
1133 :
1134 0 : return 0;
1135 : }
1136 :
1137 : /*******************************************************************
1138 : Check if a user is allowed to rename a file.
1139 : ********************************************************************/
1140 :
1141 990 : static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
1142 : uint16_t dirtype)
1143 : {
1144 990 : if (!CAN_WRITE(conn)) {
1145 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
1146 : }
1147 :
1148 990 : if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
1149 : (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1150 : /* Only bother to read the DOS attribute if we might deny the
1151 : rename on the grounds of attribute mismatch. */
1152 161 : uint32_t fmode = fdos_mode(fsp);
1153 161 : if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1154 5 : return NT_STATUS_NO_SUCH_FILE;
1155 : }
1156 : }
1157 :
1158 985 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1159 207 : if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
1160 8 : return NT_STATUS_OK;
1161 : }
1162 :
1163 : /* If no pathnames are open below this
1164 : directory, allow the rename. */
1165 :
1166 199 : if (lp_strict_rename(SNUM(conn))) {
1167 : /*
1168 : * Strict rename, check open file db.
1169 : */
1170 180 : if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
1171 12 : return NT_STATUS_ACCESS_DENIED;
1172 : }
1173 19 : } else if (file_find_subpath(fsp)) {
1174 : /*
1175 : * No strict rename, just look in local process.
1176 : */
1177 3 : return NT_STATUS_ACCESS_DENIED;
1178 : }
1179 184 : return NT_STATUS_OK;
1180 : }
1181 :
1182 778 : if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
1183 778 : return NT_STATUS_OK;
1184 : }
1185 :
1186 0 : return NT_STATUS_ACCESS_DENIED;
1187 : }
1188 :
1189 : /****************************************************************************
1190 : Ensure open files have their names updated. Updated to notify other smbd's
1191 : asynchronously.
1192 : ****************************************************************************/
1193 :
1194 960 : static void rename_open_files(connection_struct *conn,
1195 : struct share_mode_lock *lck,
1196 : struct file_id id,
1197 : uint32_t orig_name_hash,
1198 : const struct smb_filename *smb_fname_dst)
1199 : {
1200 16 : files_struct *fsp;
1201 960 : bool did_rename = False;
1202 16 : NTSTATUS status;
1203 960 : uint32_t new_name_hash = 0;
1204 :
1205 1979 : for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
1206 1019 : fsp = file_find_di_next(fsp, false)) {
1207 21 : SMB_STRUCT_STAT fsp_orig_sbuf;
1208 21 : struct file_id_buf idbuf;
1209 : /* fsp_name is a relative path under the fsp. To change this for other
1210 : sharepaths we need to manipulate relative paths. */
1211 : /* TODO - create the absolute path and manipulate the newname
1212 : relative to the sharepath. */
1213 1019 : if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
1214 0 : continue;
1215 : }
1216 1019 : if (fsp->name_hash != orig_name_hash) {
1217 0 : continue;
1218 : }
1219 1019 : DBG_DEBUG("renaming file %s "
1220 : "(file_id %s) from %s -> %s\n",
1221 : fsp_fnum_dbg(fsp),
1222 : file_id_str_buf(fsp->file_id, &idbuf),
1223 : fsp_str_dbg(fsp),
1224 : smb_fname_str_dbg(smb_fname_dst));
1225 :
1226 : /*
1227 : * The incoming smb_fname_dst here has an
1228 : * invalid stat struct (it must not have
1229 : * existed for the rename to succeed).
1230 : * Preserve the existing stat from the
1231 : * open fsp after fsp_set_smb_fname()
1232 : * overwrites with the invalid stat.
1233 : *
1234 : * We will do an fstat before returning
1235 : * any of this metadata to the client anyway.
1236 : */
1237 1019 : fsp_orig_sbuf = fsp->fsp_name->st;
1238 1019 : status = fsp_set_smb_fname(fsp, smb_fname_dst);
1239 1019 : if (NT_STATUS_IS_OK(status)) {
1240 1019 : did_rename = True;
1241 1019 : new_name_hash = fsp->name_hash;
1242 : /* Restore existing stat. */
1243 1019 : fsp->fsp_name->st = fsp_orig_sbuf;
1244 : }
1245 : }
1246 :
1247 960 : if (!did_rename) {
1248 0 : struct file_id_buf idbuf;
1249 0 : DBG_DEBUG("no open files on file_id %s "
1250 : "for %s\n",
1251 : file_id_str_buf(id, &idbuf),
1252 : smb_fname_str_dbg(smb_fname_dst));
1253 : }
1254 :
1255 : /* Send messages to all smbd's (not ourself) that the name has changed. */
1256 960 : rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
1257 : orig_name_hash, new_name_hash,
1258 : smb_fname_dst);
1259 :
1260 960 : }
1261 :
1262 : /****************************************************************************
1263 : We need to check if the source path is a parent directory of the destination
1264 : (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
1265 : refuse the rename with a sharing violation. Under UNIX the above call can
1266 : *succeed* if /foo/bar/baz is a symlink to another area in the share. We
1267 : probably need to check that the client is a Windows one before disallowing
1268 : this as a UNIX client (one with UNIX extensions) can know the source is a
1269 : symlink and make this decision intelligently. Found by an excellent bug
1270 : report from <AndyLiebman@aol.com>.
1271 : ****************************************************************************/
1272 :
1273 970 : static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
1274 : const struct smb_filename *smb_fname_dst)
1275 : {
1276 970 : const char *psrc = smb_fname_src->base_name;
1277 970 : const char *pdst = smb_fname_dst->base_name;
1278 16 : size_t slen;
1279 :
1280 970 : if (psrc[0] == '.' && psrc[1] == '/') {
1281 0 : psrc += 2;
1282 : }
1283 970 : if (pdst[0] == '.' && pdst[1] == '/') {
1284 0 : pdst += 2;
1285 : }
1286 970 : if ((slen = strlen(psrc)) > strlen(pdst)) {
1287 66 : return False;
1288 : }
1289 912 : return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
1290 : }
1291 :
1292 : /*
1293 : * Do the notify calls from a rename
1294 : */
1295 :
1296 960 : static void notify_rename(connection_struct *conn, bool is_dir,
1297 : const struct smb_filename *smb_fname_src,
1298 : const struct smb_filename *smb_fname_dst)
1299 : {
1300 960 : char *parent_dir_src = NULL;
1301 960 : char *parent_dir_dst = NULL;
1302 16 : uint32_t mask;
1303 :
1304 976 : mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
1305 960 : : FILE_NOTIFY_CHANGE_FILE_NAME;
1306 :
1307 960 : if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
1308 960 : &parent_dir_src, NULL) ||
1309 960 : !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
1310 : &parent_dir_dst, NULL)) {
1311 0 : goto out;
1312 : }
1313 :
1314 960 : if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
1315 932 : notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
1316 932 : smb_fname_src->base_name);
1317 932 : notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
1318 932 : smb_fname_dst->base_name);
1319 : }
1320 : else {
1321 28 : notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
1322 28 : smb_fname_src->base_name);
1323 28 : notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
1324 28 : smb_fname_dst->base_name);
1325 : }
1326 :
1327 : /* this is a strange one. w2k3 gives an additional event for
1328 : CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
1329 : files, but not directories */
1330 960 : if (!is_dir) {
1331 772 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1332 : FILE_NOTIFY_CHANGE_ATTRIBUTES
1333 : |FILE_NOTIFY_CHANGE_CREATION,
1334 772 : smb_fname_dst->base_name);
1335 : }
1336 188 : out:
1337 960 : TALLOC_FREE(parent_dir_src);
1338 960 : TALLOC_FREE(parent_dir_dst);
1339 960 : }
1340 :
1341 : /****************************************************************************
1342 : Returns an error if the parent directory for a filename is open in an
1343 : incompatible way.
1344 : ****************************************************************************/
1345 :
1346 1119 : static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
1347 : const struct smb_filename *smb_fname_dst_in)
1348 : {
1349 1119 : struct smb_filename *smb_fname_parent = NULL;
1350 20 : struct file_id id;
1351 1119 : files_struct *fsp = NULL;
1352 20 : int ret;
1353 20 : NTSTATUS status;
1354 :
1355 1119 : status = SMB_VFS_PARENT_PATHNAME(conn,
1356 : talloc_tos(),
1357 : smb_fname_dst_in,
1358 : &smb_fname_parent,
1359 : NULL);
1360 1119 : if (!NT_STATUS_IS_OK(status)) {
1361 0 : return status;
1362 : }
1363 :
1364 1119 : ret = vfs_stat(conn, smb_fname_parent);
1365 1119 : if (ret == -1) {
1366 0 : return map_nt_error_from_unix(errno);
1367 : }
1368 :
1369 : /*
1370 : * We're only checking on this smbd here, mostly good
1371 : * enough.. and will pass tests.
1372 : */
1373 :
1374 1119 : id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
1375 1533 : for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
1376 414 : fsp = file_find_di_next(fsp, true)) {
1377 440 : if (fsp->access_mask & DELETE_ACCESS) {
1378 26 : return NT_STATUS_SHARING_VIOLATION;
1379 : }
1380 : }
1381 1093 : return NT_STATUS_OK;
1382 : }
1383 :
1384 : /****************************************************************************
1385 : Rename an open file - given an fsp.
1386 : ****************************************************************************/
1387 :
1388 1119 : NTSTATUS rename_internals_fsp(connection_struct *conn,
1389 : files_struct *fsp,
1390 : struct smb_filename *smb_fname_dst_in,
1391 : const char *dst_original_lcomp,
1392 : uint32_t attrs,
1393 : bool replace_if_exists)
1394 : {
1395 1119 : TALLOC_CTX *ctx = talloc_tos();
1396 1119 : struct smb_filename *parent_dir_fname_dst = NULL;
1397 1119 : struct smb_filename *parent_dir_fname_dst_atname = NULL;
1398 1119 : struct smb_filename *parent_dir_fname_src = NULL;
1399 1119 : struct smb_filename *parent_dir_fname_src_atname = NULL;
1400 1119 : struct smb_filename *smb_fname_dst = NULL;
1401 1119 : NTSTATUS status = NT_STATUS_OK;
1402 1119 : struct share_mode_lock *lck = NULL;
1403 1119 : uint32_t access_mask = SEC_DIR_ADD_FILE;
1404 20 : bool dst_exists, old_is_stream, new_is_stream;
1405 20 : int ret;
1406 2238 : bool case_sensitive = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1407 1119 : true : conn->case_sensitive;
1408 2238 : bool case_preserve = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1409 1119 : true : conn->case_preserve;
1410 :
1411 1119 : status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
1412 1119 : if (!NT_STATUS_IS_OK(status)) {
1413 26 : return status;
1414 : }
1415 :
1416 1093 : if (file_has_open_streams(fsp)) {
1417 16 : return NT_STATUS_ACCESS_DENIED;
1418 : }
1419 :
1420 : /* Make a copy of the dst smb_fname structs */
1421 :
1422 1077 : smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
1423 1077 : if (smb_fname_dst == NULL) {
1424 0 : status = NT_STATUS_NO_MEMORY;
1425 0 : goto out;
1426 : }
1427 :
1428 : /*
1429 : * Check for special case with case preserving and not
1430 : * case sensitive. If the new last component differs from the original
1431 : * last component only by case, then we should allow
1432 : * the rename (user is trying to change the case of the
1433 : * filename).
1434 : */
1435 2124 : if (!case_sensitive && case_preserve &&
1436 1115 : strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1437 68 : strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
1438 28 : char *fname_dst_parent = NULL;
1439 28 : const char *fname_dst_lcomp = NULL;
1440 28 : char *orig_lcomp_path = NULL;
1441 28 : char *orig_lcomp_stream = NULL;
1442 28 : bool ok = true;
1443 :
1444 : /*
1445 : * Split off the last component of the processed
1446 : * destination name. We will compare this to
1447 : * the split components of dst_original_lcomp.
1448 : */
1449 28 : if (!parent_dirname(ctx,
1450 28 : smb_fname_dst->base_name,
1451 : &fname_dst_parent,
1452 : &fname_dst_lcomp)) {
1453 0 : status = NT_STATUS_NO_MEMORY;
1454 0 : goto out;
1455 : }
1456 :
1457 : /*
1458 : * The dst_original_lcomp component contains
1459 : * the last_component of the path + stream
1460 : * name (if a stream exists).
1461 : *
1462 : * Split off the stream name so we
1463 : * can check them separately.
1464 : */
1465 :
1466 28 : if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
1467 : /* POSIX - no stream component. */
1468 0 : orig_lcomp_path = talloc_strdup(ctx,
1469 : dst_original_lcomp);
1470 0 : if (orig_lcomp_path == NULL) {
1471 0 : ok = false;
1472 : }
1473 : } else {
1474 28 : ok = split_stream_filename(ctx,
1475 : dst_original_lcomp,
1476 : &orig_lcomp_path,
1477 : &orig_lcomp_stream);
1478 : }
1479 :
1480 28 : if (!ok) {
1481 0 : TALLOC_FREE(fname_dst_parent);
1482 0 : status = NT_STATUS_NO_MEMORY;
1483 0 : goto out;
1484 : }
1485 :
1486 : /* If the base names only differ by case, use original. */
1487 28 : if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
1488 2 : char *tmp;
1489 : /*
1490 : * Replace the modified last component with the
1491 : * original.
1492 : */
1493 10 : if (!ISDOT(fname_dst_parent)) {
1494 10 : tmp = talloc_asprintf(smb_fname_dst,
1495 : "%s/%s",
1496 : fname_dst_parent,
1497 : orig_lcomp_path);
1498 : } else {
1499 0 : tmp = talloc_strdup(smb_fname_dst,
1500 : orig_lcomp_path);
1501 : }
1502 10 : if (tmp == NULL) {
1503 0 : status = NT_STATUS_NO_MEMORY;
1504 0 : TALLOC_FREE(fname_dst_parent);
1505 0 : TALLOC_FREE(orig_lcomp_path);
1506 0 : TALLOC_FREE(orig_lcomp_stream);
1507 0 : goto out;
1508 : }
1509 10 : TALLOC_FREE(smb_fname_dst->base_name);
1510 10 : smb_fname_dst->base_name = tmp;
1511 : }
1512 :
1513 : /* If the stream_names only differ by case, use original. */
1514 28 : if(!strcsequal(smb_fname_dst->stream_name,
1515 : orig_lcomp_stream)) {
1516 : /* Use the original stream. */
1517 0 : char *tmp = talloc_strdup(smb_fname_dst,
1518 : orig_lcomp_stream);
1519 0 : if (tmp == NULL) {
1520 0 : status = NT_STATUS_NO_MEMORY;
1521 0 : TALLOC_FREE(fname_dst_parent);
1522 0 : TALLOC_FREE(orig_lcomp_path);
1523 0 : TALLOC_FREE(orig_lcomp_stream);
1524 0 : goto out;
1525 : }
1526 0 : TALLOC_FREE(smb_fname_dst->stream_name);
1527 0 : smb_fname_dst->stream_name = tmp;
1528 : }
1529 28 : TALLOC_FREE(fname_dst_parent);
1530 28 : TALLOC_FREE(orig_lcomp_path);
1531 28 : TALLOC_FREE(orig_lcomp_stream);
1532 : }
1533 :
1534 : /*
1535 : * If the src and dest names are identical - including case,
1536 : * don't do the rename, just return success.
1537 : */
1538 :
1539 1135 : if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1540 58 : strcsequal(fsp->fsp_name->stream_name,
1541 58 : smb_fname_dst->stream_name)) {
1542 18 : DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
1543 : "- returning success\n",
1544 : smb_fname_str_dbg(smb_fname_dst)));
1545 18 : status = NT_STATUS_OK;
1546 18 : goto out;
1547 : }
1548 :
1549 1059 : old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
1550 1059 : new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
1551 :
1552 : /* Return the correct error code if both names aren't streams. */
1553 1059 : if (!old_is_stream && new_is_stream) {
1554 4 : status = NT_STATUS_OBJECT_NAME_INVALID;
1555 4 : goto out;
1556 : }
1557 :
1558 1055 : if (old_is_stream && !new_is_stream) {
1559 0 : status = NT_STATUS_INVALID_PARAMETER;
1560 0 : goto out;
1561 : }
1562 :
1563 1055 : dst_exists = vfs_stat(conn, smb_fname_dst) == 0;
1564 :
1565 1055 : if(!replace_if_exists && dst_exists) {
1566 57 : DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
1567 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
1568 : smb_fname_str_dbg(smb_fname_dst)));
1569 57 : status = NT_STATUS_OBJECT_NAME_COLLISION;
1570 57 : goto out;
1571 : }
1572 :
1573 : /*
1574 : * Drop the pathref fsp on the destination otherwise we trip upon in in
1575 : * the below check for open files check.
1576 : */
1577 998 : if (smb_fname_dst_in->fsp != NULL) {
1578 26 : fd_close(smb_fname_dst_in->fsp);
1579 26 : file_free(NULL, smb_fname_dst_in->fsp);
1580 26 : SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
1581 : }
1582 :
1583 998 : if (dst_exists) {
1584 32 : struct file_id fileid = vfs_file_id_from_sbuf(conn,
1585 32 : &smb_fname_dst->st);
1586 32 : files_struct *dst_fsp = file_find_di_first(conn->sconn,
1587 : fileid, true);
1588 : /* The file can be open when renaming a stream */
1589 32 : if (dst_fsp && !new_is_stream) {
1590 8 : DEBUG(3, ("rename_internals_fsp: Target file open\n"));
1591 8 : status = NT_STATUS_ACCESS_DENIED;
1592 8 : goto out;
1593 : }
1594 : }
1595 :
1596 : /* Ensure we have a valid stat struct for the source. */
1597 990 : status = vfs_stat_fsp(fsp);
1598 990 : if (!NT_STATUS_IS_OK(status)) {
1599 0 : goto out;
1600 : }
1601 :
1602 990 : status = can_rename(conn, fsp, attrs);
1603 :
1604 990 : if (!NT_STATUS_IS_OK(status)) {
1605 20 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
1606 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
1607 : smb_fname_str_dbg(smb_fname_dst)));
1608 20 : if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
1609 0 : status = NT_STATUS_ACCESS_DENIED;
1610 20 : goto out;
1611 : }
1612 :
1613 970 : if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
1614 0 : status = NT_STATUS_ACCESS_DENIED;
1615 0 : goto out;
1616 : }
1617 :
1618 : /* Do we have rights to move into the destination ? */
1619 970 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1620 : /* We're moving a directory. */
1621 192 : access_mask = SEC_DIR_ADD_SUBDIR;
1622 : }
1623 :
1624 : /*
1625 : * Get a pathref on the destination parent directory, so
1626 : * we can call check_parent_access_fsp().
1627 : */
1628 970 : status = parent_pathref(ctx,
1629 : conn->cwd_fsp,
1630 : smb_fname_dst,
1631 : &parent_dir_fname_dst,
1632 : &parent_dir_fname_dst_atname);
1633 970 : if (!NT_STATUS_IS_OK(status)) {
1634 0 : goto out;
1635 : }
1636 :
1637 970 : status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
1638 : access_mask);
1639 970 : if (!NT_STATUS_IS_OK(status)) {
1640 10 : DBG_INFO("check_parent_access_fsp on "
1641 : "dst %s returned %s\n",
1642 : smb_fname_str_dbg(smb_fname_dst),
1643 : nt_errstr(status));
1644 10 : goto out;
1645 : }
1646 :
1647 : /*
1648 : * If the target existed, make sure the destination
1649 : * atname has the same stat struct.
1650 : */
1651 960 : parent_dir_fname_dst_atname->st = smb_fname_dst->st;
1652 :
1653 : /*
1654 : * It's very common that source and
1655 : * destination directories are the same.
1656 : * Optimize by not opening the
1657 : * second parent_pathref if we know
1658 : * this is the case.
1659 : */
1660 :
1661 960 : status = SMB_VFS_PARENT_PATHNAME(conn,
1662 : ctx,
1663 : fsp->fsp_name,
1664 : &parent_dir_fname_src,
1665 : &parent_dir_fname_src_atname);
1666 960 : if (!NT_STATUS_IS_OK(status)) {
1667 0 : goto out;
1668 : }
1669 :
1670 : /*
1671 : * We do a case-sensitive string comparison. We want to be *sure*
1672 : * this is the same path. The worst that can happen if
1673 : * the case doesn't match is we lose out on the optimization,
1674 : * the code still works.
1675 : *
1676 : * We can ignore twrp fields here. Rename is not allowed on
1677 : * shadow copy handles.
1678 : */
1679 :
1680 960 : if (strcmp(parent_dir_fname_src->base_name,
1681 960 : parent_dir_fname_dst->base_name) == 0) {
1682 : /*
1683 : * parent directory is the same for source
1684 : * and destination.
1685 : */
1686 : /* Reparent the src_atname to the parent_dir_dest fname. */
1687 932 : parent_dir_fname_src_atname = talloc_move(
1688 : parent_dir_fname_dst,
1689 : &parent_dir_fname_src_atname);
1690 : /* Free the unneeded duplicate parent name. */
1691 932 : TALLOC_FREE(parent_dir_fname_src);
1692 : /*
1693 : * And make the source parent name a copy of the
1694 : * destination parent name.
1695 : */
1696 932 : parent_dir_fname_src = parent_dir_fname_dst;
1697 :
1698 : /*
1699 : * Ensure we have a pathref fsp on the
1700 : * parent_dir_fname_src_atname to match the code in the else
1701 : * branch where we use parent_pathref().
1702 : */
1703 948 : status = reference_smb_fname_fsp_link(
1704 : parent_dir_fname_src_atname,
1705 932 : fsp->fsp_name);
1706 932 : if (!NT_STATUS_IS_OK(status)) {
1707 0 : goto out;
1708 : }
1709 : } else {
1710 : /*
1711 : * source and destination parent directories are
1712 : * different.
1713 : *
1714 : * Get a pathref on the source parent directory, so
1715 : * we can do a relative rename.
1716 : */
1717 28 : TALLOC_FREE(parent_dir_fname_src);
1718 28 : status = parent_pathref(ctx,
1719 : conn->cwd_fsp,
1720 28 : fsp->fsp_name,
1721 : &parent_dir_fname_src,
1722 : &parent_dir_fname_src_atname);
1723 28 : if (!NT_STATUS_IS_OK(status)) {
1724 0 : goto out;
1725 : }
1726 : }
1727 :
1728 : /*
1729 : * Some modules depend on the source smb_fname having a valid stat.
1730 : * The parent_dir_fname_src_atname is the relative name of the
1731 : * currently open file, so just copy the stat from the open fsp.
1732 : */
1733 960 : parent_dir_fname_src_atname->st = fsp->fsp_name->st;
1734 :
1735 960 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1736 :
1737 : /*
1738 : * We have the file open ourselves, so not being able to get the
1739 : * corresponding share mode lock is a fatal error.
1740 : */
1741 :
1742 960 : SMB_ASSERT(lck != NULL);
1743 :
1744 960 : ret = SMB_VFS_RENAMEAT(conn,
1745 : parent_dir_fname_src->fsp,
1746 : parent_dir_fname_src_atname,
1747 : parent_dir_fname_dst->fsp,
1748 : parent_dir_fname_dst_atname);
1749 960 : if (ret == 0) {
1750 960 : uint32_t create_options = fh_get_private_options(fsp->fh);
1751 :
1752 960 : DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
1753 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
1754 : smb_fname_str_dbg(smb_fname_dst)));
1755 :
1756 960 : notify_rename(conn,
1757 960 : fsp->fsp_flags.is_directory,
1758 960 : fsp->fsp_name,
1759 : smb_fname_dst);
1760 :
1761 960 : rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
1762 : smb_fname_dst);
1763 :
1764 1732 : if (!fsp->fsp_flags.is_directory &&
1765 1040 : (lp_map_archive(SNUM(conn)) ||
1766 268 : lp_store_dos_attributes(SNUM(conn))))
1767 : {
1768 : /*
1769 : * We must set the archive bit on the newly renamed
1770 : * file.
1771 : */
1772 772 : status = vfs_stat_fsp(fsp);
1773 772 : if (NT_STATUS_IS_OK(status)) {
1774 12 : uint32_t old_dosmode;
1775 772 : old_dosmode = fdos_mode(fsp);
1776 : /*
1777 : * We can use fsp->fsp_name here as it has
1778 : * already been changed to the new name.
1779 : */
1780 772 : SMB_ASSERT(fsp->fsp_name->fsp == fsp);
1781 772 : file_set_dosmode(conn,
1782 : fsp->fsp_name,
1783 : old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
1784 : NULL,
1785 : true);
1786 : }
1787 : }
1788 :
1789 : /*
1790 : * A rename acts as a new file create w.r.t. allowing an initial delete
1791 : * on close, probably because in Windows there is a new handle to the
1792 : * new file. If initial delete on close was requested but not
1793 : * originally set, we need to set it here. This is probably not 100% correct,
1794 : * but will work for the CIFSFS client which in non-posix mode
1795 : * depends on these semantics. JRA.
1796 : */
1797 :
1798 960 : if (create_options & FILE_DELETE_ON_CLOSE) {
1799 0 : status = can_set_delete_on_close(fsp, 0);
1800 :
1801 0 : if (NT_STATUS_IS_OK(status)) {
1802 : /* Note that here we set the *initial* delete on close flag,
1803 : * not the regular one. The magic gets handled in close. */
1804 0 : fsp->fsp_flags.initial_delete_on_close = true;
1805 : }
1806 : }
1807 960 : TALLOC_FREE(lck);
1808 960 : status = NT_STATUS_OK;
1809 960 : goto out;
1810 : }
1811 :
1812 0 : TALLOC_FREE(lck);
1813 :
1814 0 : if (errno == ENOTDIR || errno == EISDIR) {
1815 0 : status = NT_STATUS_OBJECT_NAME_COLLISION;
1816 : } else {
1817 0 : status = map_nt_error_from_unix(errno);
1818 : }
1819 :
1820 0 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
1821 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
1822 : smb_fname_str_dbg(smb_fname_dst)));
1823 :
1824 1077 : out:
1825 :
1826 : /*
1827 : * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
1828 : * See the optimization for same source and destination directory
1829 : * above. Only free one in that case.
1830 : */
1831 1077 : if (parent_dir_fname_src != parent_dir_fname_dst) {
1832 38 : TALLOC_FREE(parent_dir_fname_src);
1833 : }
1834 1077 : TALLOC_FREE(parent_dir_fname_dst);
1835 1077 : TALLOC_FREE(smb_fname_dst);
1836 :
1837 1077 : return status;
1838 : }
1839 :
1840 : /****************************************************************************
1841 : The guts of the rename command, split out so it may be called by the NT SMB
1842 : code.
1843 : ****************************************************************************/
1844 :
1845 464 : NTSTATUS rename_internals(TALLOC_CTX *ctx,
1846 : connection_struct *conn,
1847 : struct smb_request *req,
1848 : struct files_struct *src_dirfsp,
1849 : struct smb_filename *smb_fname_src,
1850 : struct smb_filename *smb_fname_dst,
1851 : const char *dst_original_lcomp,
1852 : uint32_t attrs,
1853 : bool replace_if_exists,
1854 : uint32_t access_mask)
1855 : {
1856 464 : NTSTATUS status = NT_STATUS_OK;
1857 464 : int create_options = FILE_OPEN_REPARSE_POINT;
1858 464 : struct smb2_create_blobs *posx = NULL;
1859 464 : struct files_struct *fsp = NULL;
1860 464 : bool posix_pathname = (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH);
1861 464 : bool case_sensitive = posix_pathname ? true : conn->case_sensitive;
1862 464 : bool case_preserve = posix_pathname ? true : conn->case_preserve;
1863 464 : bool short_case_preserve = posix_pathname ? true :
1864 438 : conn->short_case_preserve;
1865 :
1866 464 : if (posix_pathname) {
1867 26 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
1868 26 : if (!NT_STATUS_IS_OK(status)) {
1869 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
1870 : nt_errstr(status));
1871 0 : goto out;
1872 : }
1873 : }
1874 :
1875 464 : DBG_NOTICE("case_sensitive = %d, "
1876 : "case_preserve = %d, short case preserve = %d, "
1877 : "directory = %s, newname = %s, "
1878 : "last_component_dest = %s\n",
1879 : case_sensitive, case_preserve,
1880 : short_case_preserve,
1881 : smb_fname_str_dbg(smb_fname_src),
1882 : smb_fname_str_dbg(smb_fname_dst),
1883 : dst_original_lcomp);
1884 :
1885 464 : ZERO_STRUCT(smb_fname_src->st);
1886 :
1887 464 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1888 464 : if (!NT_STATUS_IS_OK(status)) {
1889 14 : if (!NT_STATUS_EQUAL(status,
1890 : NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1891 0 : goto out;
1892 : }
1893 : /*
1894 : * Possible symlink src.
1895 : */
1896 14 : if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
1897 14 : goto out;
1898 : }
1899 0 : if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
1900 0 : goto out;
1901 : }
1902 : }
1903 :
1904 450 : if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
1905 0 : create_options |= FILE_DIRECTORY_FILE;
1906 : }
1907 :
1908 450 : status = SMB_VFS_CREATE_FILE(
1909 : conn, /* conn */
1910 : req, /* req */
1911 : src_dirfsp, /* dirfsp */
1912 : smb_fname_src, /* fname */
1913 : access_mask, /* access_mask */
1914 : (FILE_SHARE_READ | /* share_access */
1915 : FILE_SHARE_WRITE),
1916 : FILE_OPEN, /* create_disposition*/
1917 : create_options, /* create_options */
1918 : 0, /* file_attributes */
1919 : 0, /* oplock_request */
1920 : NULL, /* lease */
1921 : 0, /* allocation_size */
1922 : 0, /* private_flags */
1923 : NULL, /* sd */
1924 : NULL, /* ea_list */
1925 : &fsp, /* result */
1926 : NULL, /* pinfo */
1927 : posx, /* in_context_blobs */
1928 : NULL); /* out_context_blobs */
1929 :
1930 450 : if (!NT_STATUS_IS_OK(status)) {
1931 72 : DBG_NOTICE("Could not open rename source %s: %s\n",
1932 : smb_fname_str_dbg(smb_fname_src),
1933 : nt_errstr(status));
1934 72 : goto out;
1935 : }
1936 :
1937 378 : status = rename_internals_fsp(conn,
1938 : fsp,
1939 : smb_fname_dst,
1940 : dst_original_lcomp,
1941 : attrs,
1942 : replace_if_exists);
1943 :
1944 378 : close_file_free(req, &fsp, NORMAL_CLOSE);
1945 :
1946 378 : DBG_NOTICE("Error %s rename %s -> %s\n",
1947 : nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
1948 : smb_fname_str_dbg(smb_fname_dst));
1949 :
1950 464 : out:
1951 464 : TALLOC_FREE(posx);
1952 464 : return status;
1953 : }
1954 :
1955 : /*******************************************************************
1956 : Copy a file as part of a reply_copy.
1957 : ******************************************************************/
1958 :
1959 : /*
1960 : * TODO: check error codes on all callers
1961 : */
1962 :
1963 16 : NTSTATUS copy_file(TALLOC_CTX *ctx,
1964 : connection_struct *conn,
1965 : struct smb_filename *smb_fname_src,
1966 : struct smb_filename *smb_fname_dst,
1967 : uint32_t new_create_disposition)
1968 : {
1969 16 : struct smb_filename *smb_fname_dst_tmp = NULL;
1970 16 : off_t ret=-1;
1971 0 : files_struct *fsp1,*fsp2;
1972 0 : uint32_t dosattrs;
1973 0 : NTSTATUS status;
1974 :
1975 :
1976 16 : smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
1977 16 : if (smb_fname_dst_tmp == NULL) {
1978 0 : return NT_STATUS_NO_MEMORY;
1979 : }
1980 :
1981 16 : status = vfs_file_exist(conn, smb_fname_src);
1982 16 : if (!NT_STATUS_IS_OK(status)) {
1983 0 : goto out;
1984 : }
1985 :
1986 16 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1987 16 : if (!NT_STATUS_IS_OK(status)) {
1988 0 : goto out;
1989 : }
1990 :
1991 : /* Open the src file for reading. */
1992 16 : status = SMB_VFS_CREATE_FILE(
1993 : conn, /* conn */
1994 : NULL, /* req */
1995 : NULL, /* dirfsp */
1996 : smb_fname_src, /* fname */
1997 : FILE_GENERIC_READ, /* access_mask */
1998 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1999 : FILE_OPEN, /* create_disposition*/
2000 : 0, /* create_options */
2001 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2002 : INTERNAL_OPEN_ONLY, /* oplock_request */
2003 : NULL, /* lease */
2004 : 0, /* allocation_size */
2005 : 0, /* private_flags */
2006 : NULL, /* sd */
2007 : NULL, /* ea_list */
2008 : &fsp1, /* result */
2009 : NULL, /* psbuf */
2010 : NULL, NULL); /* create context */
2011 :
2012 16 : if (!NT_STATUS_IS_OK(status)) {
2013 0 : goto out;
2014 : }
2015 :
2016 16 : dosattrs = fdos_mode(fsp1);
2017 :
2018 16 : if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
2019 16 : ZERO_STRUCTP(&smb_fname_dst_tmp->st);
2020 : }
2021 :
2022 16 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
2023 16 : if (!NT_STATUS_IS_OK(status) &&
2024 16 : !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
2025 : {
2026 0 : goto out;
2027 : }
2028 :
2029 : /* Open the dst file for writing. */
2030 16 : status = SMB_VFS_CREATE_FILE(
2031 : conn, /* conn */
2032 : NULL, /* req */
2033 : NULL, /* dirfsp */
2034 : smb_fname_dst, /* fname */
2035 : FILE_GENERIC_WRITE, /* access_mask */
2036 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2037 : new_create_disposition, /* create_disposition*/
2038 : 0, /* create_options */
2039 : dosattrs, /* file_attributes */
2040 : INTERNAL_OPEN_ONLY, /* oplock_request */
2041 : NULL, /* lease */
2042 : 0, /* allocation_size */
2043 : 0, /* private_flags */
2044 : NULL, /* sd */
2045 : NULL, /* ea_list */
2046 : &fsp2, /* result */
2047 : NULL, /* psbuf */
2048 : NULL, NULL); /* create context */
2049 :
2050 16 : if (!NT_STATUS_IS_OK(status)) {
2051 0 : close_file_free(NULL, &fsp1, ERROR_CLOSE);
2052 0 : goto out;
2053 : }
2054 :
2055 : /* Do the actual copy. */
2056 16 : if (smb_fname_src->st.st_ex_size) {
2057 16 : ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
2058 : } else {
2059 0 : ret = 0;
2060 : }
2061 :
2062 16 : close_file_free(NULL, &fsp1, NORMAL_CLOSE);
2063 :
2064 : /* Ensure the modtime is set correctly on the destination file. */
2065 16 : set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
2066 :
2067 : /*
2068 : * As we are opening fsp1 read-only we only expect
2069 : * an error on close on fsp2 if we are out of space.
2070 : * Thus we don't look at the error return from the
2071 : * close of fsp1.
2072 : */
2073 16 : status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
2074 :
2075 16 : if (!NT_STATUS_IS_OK(status)) {
2076 0 : goto out;
2077 : }
2078 :
2079 16 : if (ret != (off_t)smb_fname_src->st.st_ex_size) {
2080 0 : status = NT_STATUS_DISK_FULL;
2081 0 : goto out;
2082 : }
2083 :
2084 16 : status = NT_STATUS_OK;
2085 :
2086 16 : out:
2087 16 : TALLOC_FREE(smb_fname_dst_tmp);
2088 16 : return status;
2089 : }
2090 :
2091 : /****************************************************************************
2092 : Get a lock offset, dealing with large offset requests.
2093 : ****************************************************************************/
2094 :
2095 5671 : uint64_t get_lock_offset(const uint8_t *data, int data_offset,
2096 : bool large_file_format)
2097 : {
2098 5671 : uint64_t offset = 0;
2099 :
2100 5671 : if(!large_file_format) {
2101 5151 : offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
2102 : } else {
2103 : /*
2104 : * No BVAL, this is reversed!
2105 : */
2106 520 : offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
2107 520 : ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
2108 : }
2109 :
2110 5671 : return offset;
2111 : }
2112 :
2113 : struct smbd_do_unlocking_state {
2114 : struct files_struct *fsp;
2115 : uint16_t num_ulocks;
2116 : struct smbd_lock_element *ulocks;
2117 : NTSTATUS status;
2118 : };
2119 :
2120 2296 : static void smbd_do_unlocking_fn(
2121 : struct share_mode_lock *lck,
2122 : void *private_data)
2123 : {
2124 2296 : struct smbd_do_unlocking_state *state = private_data;
2125 2296 : struct files_struct *fsp = state->fsp;
2126 14 : uint16_t i;
2127 :
2128 4422 : for (i = 0; i < state->num_ulocks; i++) {
2129 2338 : struct smbd_lock_element *e = &state->ulocks[i];
2130 :
2131 2338 : DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
2132 : "pid %"PRIu64", file %s\n",
2133 : e->offset,
2134 : e->count,
2135 : e->smblctx,
2136 : fsp_str_dbg(fsp));
2137 :
2138 2338 : if (e->brltype != UNLOCK_LOCK) {
2139 : /* this can only happen with SMB2 */
2140 8 : state->status = NT_STATUS_INVALID_PARAMETER;
2141 8 : return;
2142 : }
2143 :
2144 2330 : state->status = do_unlock(
2145 : fsp, e->smblctx, e->count, e->offset, e->lock_flav);
2146 :
2147 2330 : DBG_DEBUG("do_unlock returned %s\n",
2148 : nt_errstr(state->status));
2149 :
2150 2330 : if (!NT_STATUS_IS_OK(state->status)) {
2151 200 : return;
2152 : }
2153 : }
2154 :
2155 2084 : share_mode_wakeup_waiters(fsp->file_id);
2156 : }
2157 :
2158 2296 : NTSTATUS smbd_do_unlocking(struct smb_request *req,
2159 : files_struct *fsp,
2160 : uint16_t num_ulocks,
2161 : struct smbd_lock_element *ulocks)
2162 : {
2163 2296 : struct smbd_do_unlocking_state state = {
2164 : .fsp = fsp,
2165 : .num_ulocks = num_ulocks,
2166 : .ulocks = ulocks,
2167 : };
2168 14 : NTSTATUS status;
2169 :
2170 2296 : DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
2171 :
2172 2296 : status = share_mode_do_locked_vfs_allowed(
2173 : fsp->file_id, smbd_do_unlocking_fn, &state);
2174 :
2175 2296 : if (!NT_STATUS_IS_OK(status)) {
2176 0 : DBG_DEBUG("share_mode_do_locked_vfs_allowed failed: %s\n",
2177 : nt_errstr(status));
2178 0 : return status;
2179 : }
2180 2296 : if (!NT_STATUS_IS_OK(state.status)) {
2181 212 : DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
2182 : nt_errstr(status));
2183 212 : return state.status;
2184 : }
2185 :
2186 2084 : return NT_STATUS_OK;
2187 : }
|