ctdb-server: Remove duplicate logic
[samba4-gss.git] / source3 / smbd / smb2_reply.c
blob349c312ff17d45b21ea426add825253aaf11d094
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
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.
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.
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/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
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 #include "source3/smbd/dir.h"
56 /****************************************************************************
57 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
58 path or anything including wildcards.
59 We're assuming here that '/' is not the second byte in any multibyte char
60 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
61 set.
62 ****************************************************************************/
64 /* Custom version for processing POSIX paths. */
65 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
67 NTSTATUS check_path_syntax(char *path, bool posix_path)
69 char *d = path;
70 const char *s = path;
71 NTSTATUS ret = NT_STATUS_OK;
72 bool start_of_name_component = True;
73 bool stream_started = false;
74 bool last_component_contains_wcard = false;
76 while (*s) {
77 if (stream_started) {
78 switch (*s) {
79 case '/':
80 case '\\':
81 return NT_STATUS_OBJECT_NAME_INVALID;
82 case ':':
83 if (s[1] == '\0') {
84 return NT_STATUS_OBJECT_NAME_INVALID;
86 if (strchr_m(&s[1], ':')) {
87 return NT_STATUS_OBJECT_NAME_INVALID;
89 break;
93 if ((*s == ':') && !posix_path && !stream_started) {
94 if (last_component_contains_wcard) {
95 return NT_STATUS_OBJECT_NAME_INVALID;
97 /* Stream names allow more characters than file names.
98 We're overloading posix_path here to allow a wider
99 range of characters. If stream_started is true this
100 is still a Windows path even if posix_path is true.
101 JRA.
103 stream_started = true;
104 start_of_name_component = false;
105 posix_path = true;
107 if (s[1] == '\0') {
108 return NT_STATUS_OBJECT_NAME_INVALID;
112 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
114 * Safe to assume is not the second part of a mb char
115 * as this is handled below.
117 /* Eat multiple '/' or '\\' */
118 while (IS_PATH_SEP(*s,posix_path)) {
119 s++;
121 if ((d != path) && (*s != '\0')) {
122 /* We only care about non-leading or trailing '/' or '\\' */
123 *d++ = '/';
126 start_of_name_component = True;
127 /* New component. */
128 last_component_contains_wcard = false;
129 continue;
132 if (start_of_name_component) {
133 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
134 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
137 * No mb char starts with '.' so we're safe checking the directory separator here.
140 /* If we just added a '/' - delete it */
141 if ((d > path) && (*(d-1) == '/')) {
142 *(d-1) = '\0';
143 d--;
146 /* Are we at the start ? Can't go back further if so. */
147 if (d <= path) {
148 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
149 break;
151 /* Go back one level... */
152 /* We know this is safe as '/' cannot be part of a mb sequence. */
153 /* NOTE - if this assumption is invalid we are not in good shape... */
154 /* Decrement d first as d points to the *next* char to write into. */
155 for (d--; d > path; d--) {
156 if (*d == '/')
157 break;
159 s += 2; /* Else go past the .. */
160 /* We're still at the start of a name component, just the previous one. */
161 continue;
163 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
164 if (posix_path) {
165 /* Eat the '.' */
166 s++;
167 continue;
169 } else if (IS_SMBD_TMPNAME(s, NULL)) {
170 return NT_STATUS_OBJECT_NAME_INVALID;
175 if (!(*s & 0x80)) {
176 if (!posix_path) {
177 if (*s <= 0x1f || *s == '|') {
178 return NT_STATUS_OBJECT_NAME_INVALID;
180 switch (*s) {
181 case '*':
182 case '?':
183 case '<':
184 case '>':
185 case '"':
186 last_component_contains_wcard = true;
187 break;
188 default:
189 break;
192 *d++ = *s++;
193 } else {
194 size_t ch_size;
195 /* Get the size of the next MB character. */
196 next_codepoint(s,&ch_size);
197 switch(ch_size) {
198 case 5:
199 *d++ = *s++;
200 FALL_THROUGH;
201 case 4:
202 *d++ = *s++;
203 FALL_THROUGH;
204 case 3:
205 *d++ = *s++;
206 FALL_THROUGH;
207 case 2:
208 *d++ = *s++;
209 FALL_THROUGH;
210 case 1:
211 *d++ = *s++;
212 break;
213 default:
214 DBG_ERR("character length assumptions invalid !\n");
215 *d = '\0';
216 return NT_STATUS_INVALID_PARAMETER;
219 start_of_name_component = False;
222 *d = '\0';
224 return ret;
227 /****************************************************************************
228 SMB2-only code to strip an MSDFS prefix from an incoming pathname.
229 ****************************************************************************/
231 NTSTATUS smb2_strip_dfs_path(const char *in_path, const char **out_path)
233 const char *path = in_path;
235 /* Match the Windows 2022 behavior for an empty DFS pathname. */
236 if (*path == '\0') {
237 return NT_STATUS_INVALID_PARAMETER;
239 /* Strip any leading '\\' characters - MacOSX client behavior. */
240 while (*path == '\\') {
241 path++;
243 /* We should now be pointing at the server name. Go past it. */
244 for (;;) {
245 if (*path == '\0') {
246 /* End of complete path. Exit OK. */
247 goto out;
249 if (*path == '\\') {
250 /* End of server name. Go past and break. */
251 path++;
252 break;
254 path++; /* Continue looking for end of server name or string. */
257 /* We should now be pointing at the share name. Go past it. */
258 for (;;) {
259 if (*path == '\0') {
260 /* End of complete path. Exit OK. */
261 goto out;
263 if (*path == '\\') {
264 /* End of share name. Go past and break. */
265 path++;
266 break;
268 if (*path == ':') {
269 /* Only invalid character in sharename. */
270 return NT_STATUS_OBJECT_NAME_INVALID;
272 path++; /* Continue looking for end of share name or string. */
275 /* path now points at the start of the real filename (if any). */
277 out:
278 /* We have stripped the DFS path prefix (if any). */
279 *out_path = path;
280 return NT_STATUS_OK;
283 /****************************************************************************
284 Pull a string and check the path allowing a wildcard - provide for error return.
285 Passes in posix flag.
286 ****************************************************************************/
288 static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
289 const char *base_ptr,
290 uint16_t smb_flags2,
291 char **pp_dest,
292 const char *src,
293 size_t src_len,
294 int flags,
295 bool posix_pathnames,
296 NTSTATUS *err)
298 size_t ret;
299 char *dst = NULL;
301 *pp_dest = NULL;
303 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
304 src_len, flags);
306 if (!*pp_dest) {
307 *err = NT_STATUS_INVALID_PARAMETER;
308 return ret;
311 dst = *pp_dest;
313 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
315 * A valid DFS path looks either like
316 * /server/share
317 * \server\share
318 * (there may be more components after).
319 * Either way it must have at least two separators.
321 * Ensure we end up as /server/share
322 * so we don't need to special case
323 * separator characters elsewhere in
324 * the code.
326 char *server = NULL;
327 char *share = NULL;
328 char *remaining_path = NULL;
329 char path_sep = 0;
330 char *p = NULL;
332 if (posix_pathnames && (dst[0] == '/')) {
333 path_sep = dst[0];
334 } else if (dst[0] == '\\') {
335 path_sep = dst[0];
338 if (path_sep == 0) {
339 goto local_path;
342 * May be a DFS path.
343 * We need some heuristics here,
344 * as clients differ on what constitutes
345 * a well-formed DFS path. If the path
346 * appears malformed, just fall back to
347 * processing as a local path.
349 server = dst;
352 * Cosmetic fix for Linux-only DFS clients.
353 * The Linux kernel SMB1 client has a bug - it sends
354 * DFS pathnames as:
356 * \\server\share\path
358 * Causing us to mis-parse server,share,remaining_path here
359 * and jump into 'goto local_path' at 'share\path' instead
360 * of 'path'.
362 * This doesn't cause an error as the limits on share names
363 * are similar to those on pathnames.
365 * parse_dfs_path() which we call before filename parsing
366 * copes with this by calling trim_char on the leading '\'
367 * characters before processing.
368 * Do the same here so logging of pathnames looks better.
370 if (server[1] == path_sep) {
371 trim_char(&server[1], path_sep, '\0');
375 * Look to see if we also have /share following.
377 share = strchr(server+1, path_sep);
378 if (share == NULL) {
379 goto local_path;
382 * Ensure the server name does not contain
383 * any possible path components by converting
384 * them to _'s.
386 for (p = server + 1; p < share; p++) {
387 if (*p == '/' || *p == '\\') {
388 *p = '_';
392 * It's a well formed DFS path with
393 * at least server and share components.
394 * Replace the slashes with '/' and
395 * pass the remainder to local_path.
397 *server = '/';
398 *share = '/';
400 * Skip past share so we don't pass the
401 * sharename into check_path_syntax().
403 remaining_path = strchr(share+1, path_sep);
404 if (remaining_path == NULL) {
406 * Ensure the share name does not contain
407 * any possible path components by converting
408 * them to _'s.
410 for (p = share + 1; *p; p++) {
411 if (*p == '/' || *p == '\\') {
412 *p = '_';
416 * If no remaining path this was
417 * a bare /server/share path. Just return.
419 *err = NT_STATUS_OK;
420 return ret;
423 * Ensure the share name does not contain
424 * any possible path components by converting
425 * them to _'s.
427 for (p = share + 1; p < remaining_path; p++) {
428 if (*p == '/' || *p == '\\') {
429 *p = '_';
432 *remaining_path = '/';
433 dst = remaining_path + 1;
434 /* dst now points at any following components. */
437 local_path:
439 *err = check_path_syntax(dst, posix_pathnames);
441 return ret;
444 /****************************************************************************
445 Pull a string and check the path - provide for error return.
446 ****************************************************************************/
448 size_t srvstr_get_path(TALLOC_CTX *ctx,
449 const char *base_ptr,
450 uint16_t smb_flags2,
451 char **pp_dest,
452 const char *src,
453 size_t src_len,
454 int flags,
455 NTSTATUS *err)
457 return srvstr_get_path_internal(ctx,
458 base_ptr,
459 smb_flags2,
460 pp_dest,
461 src,
462 src_len,
463 flags,
464 false,
465 err);
468 /****************************************************************************
469 Pull a string and check the path - provide for error return.
470 posix_pathnames version.
471 ****************************************************************************/
473 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
474 const char *base_ptr,
475 uint16_t smb_flags2,
476 char **pp_dest,
477 const char *src,
478 size_t src_len,
479 int flags,
480 NTSTATUS *err)
482 return srvstr_get_path_internal(ctx,
483 base_ptr,
484 smb_flags2,
485 pp_dest,
486 src,
487 src_len,
488 flags,
489 true,
490 err);
494 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
495 char **pp_dest, const char *src, int flags,
496 NTSTATUS *err)
498 ssize_t bufrem = smbreq_bufrem(req, src);
500 if (bufrem == 0) {
501 *err = NT_STATUS_INVALID_PARAMETER;
502 return 0;
505 if (req->posix_pathnames) {
506 return srvstr_get_path_internal(mem_ctx,
507 (const char *)req->inbuf,
508 req->flags2,
509 pp_dest,
510 src,
511 bufrem,
512 flags,
513 true,
514 err);
515 } else {
516 return srvstr_get_path_internal(mem_ctx,
517 (const char *)req->inbuf,
518 req->flags2,
519 pp_dest,
520 src,
521 bufrem,
522 flags,
523 false,
524 err);
529 * pull a string from the smb_buf part of a packet. In this case the
530 * string can either be null terminated or it can be terminated by the
531 * end of the smbbuf area
533 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
534 char **dest, const uint8_t *src, int flags)
536 ssize_t bufrem = smbreq_bufrem(req, src);
538 if (bufrem == 0) {
539 *dest = NULL;
540 return 0;
543 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
544 bufrem, flags);
547 /****************************************************************************
548 Check if we have a correct fsp pointing to a quota fake file. Replacement for
549 the CHECK_NTQUOTA_HANDLE_OK macro.
550 ****************************************************************************/
552 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
553 files_struct *fsp)
555 if ((fsp == NULL) || (conn == NULL)) {
556 return false;
559 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
560 return false;
563 if (fsp->fsp_flags.is_directory) {
564 return false;
567 if (fsp->fake_file_handle == NULL) {
568 return false;
571 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
572 return false;
575 if (fsp->fake_file_handle->private_data == NULL) {
576 return false;
579 return true;
582 /****************************************************************************
583 Return the port number we've bound to on a socket.
584 ****************************************************************************/
586 static int get_socket_port(int fd)
588 struct samba_sockaddr saddr = {
589 .sa_socklen = sizeof(struct sockaddr_storage),
592 if (fd == -1) {
593 return -1;
596 if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
597 int level = (errno == ENOTCONN) ? 2 : 0;
598 DEBUG(level, ("getsockname failed. Error was %s\n",
599 strerror(errno)));
600 return -1;
603 #if defined(HAVE_IPV6)
604 if (saddr.u.sa.sa_family == AF_INET6) {
605 return ntohs(saddr.u.in6.sin6_port);
607 #endif
608 if (saddr.u.sa.sa_family == AF_INET) {
609 return ntohs(saddr.u.in.sin_port);
611 return -1;
614 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
615 const char *name, int name_type)
617 char *trim_name;
618 char *trim_name_type;
619 const char *retarget_parm;
620 char *retarget;
621 char *p;
622 int retarget_type = 0x20;
623 int retarget_port = NBT_SMB_PORT;
624 struct sockaddr_storage retarget_addr;
625 struct sockaddr_in *in_addr;
626 bool ret = false;
627 uint8_t outbuf[10];
629 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
630 return false;
633 trim_name = talloc_strdup(talloc_tos(), name);
634 if (trim_name == NULL) {
635 goto fail;
637 trim_char(trim_name, ' ', ' ');
639 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
640 name_type);
641 if (trim_name_type == NULL) {
642 goto fail;
645 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
646 trim_name_type, NULL);
647 if (retarget_parm == NULL) {
648 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
649 trim_name, NULL);
651 if (retarget_parm == NULL) {
652 goto fail;
655 retarget = talloc_strdup(trim_name, retarget_parm);
656 if (retarget == NULL) {
657 goto fail;
660 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
662 p = strchr(retarget, ':');
663 if (p != NULL) {
664 *p++ = '\0';
665 retarget_port = atoi(p);
668 p = strchr_m(retarget, '#');
669 if (p != NULL) {
670 *p++ = '\0';
671 if (sscanf(p, "%x", &retarget_type) != 1) {
672 goto fail;
676 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
677 if (!ret) {
678 DEBUG(10, ("could not resolve %s\n", retarget));
679 goto fail;
682 if (retarget_addr.ss_family != AF_INET) {
683 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
684 goto fail;
687 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
689 _smb_setlen(outbuf, 6);
690 SCVAL(outbuf, 0, 0x84);
691 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
692 *(uint16_t *)(outbuf+8) = htons(retarget_port);
694 if (!smb1_srv_send(xconn, (char *)outbuf, false, 0, false)) {
695 exit_server_cleanly("netbios_session_retarget: smb1_srv_send "
696 "failed.");
699 ret = true;
700 fail:
701 TALLOC_FREE(trim_name);
702 return ret;
705 static void reply_called_name_not_present(char *outbuf)
707 smb_setlen(outbuf, 1);
708 SCVAL(outbuf, 0, 0x83);
709 SCVAL(outbuf, 4, 0x82);
712 /****************************************************************************
713 Reply to a (netbios-level) special message.
714 ****************************************************************************/
716 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
718 struct smbd_server_connection *sconn = xconn->client->sconn;
719 int msg_type = CVAL(inbuf,0);
720 int msg_flags = CVAL(inbuf,1);
722 * We only really use 4 bytes of the outbuf, but for the smb_setlen
723 * calculation & friends (smb1_srv_send uses that) we need the full smb
724 * header.
726 char outbuf[smb_size];
728 memset(outbuf, '\0', sizeof(outbuf));
730 smb_setlen(outbuf,0);
732 switch (msg_type) {
733 case NBSSrequest: /* session request */
735 /* inbuf_size is guaranteed to be at least 4. */
736 fstring name1,name2;
737 int name_type1, name_type2;
738 int name_len1, name_len2;
740 *name1 = *name2 = 0;
742 if (xconn->transport.nbt.got_session) {
743 exit_server_cleanly("multiple session request not permitted");
746 SCVAL(outbuf,0,NBSSpositive);
747 SCVAL(outbuf,3,0);
749 /* inbuf_size is guaranteed to be at least 4. */
750 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
751 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
752 DEBUG(0,("Invalid name length in session request\n"));
753 reply_called_name_not_present(outbuf);
754 break;
756 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
757 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
758 DEBUG(0,("Invalid name length in session request\n"));
759 reply_called_name_not_present(outbuf);
760 break;
763 name_type1 = name_extract((unsigned char *)inbuf,
764 inbuf_size,(unsigned int)4,name1);
765 name_type2 = name_extract((unsigned char *)inbuf,
766 inbuf_size,(unsigned int)(4 + name_len1),name2);
768 if (name_type1 == -1 || name_type2 == -1) {
769 DEBUG(0,("Invalid name type in session request\n"));
770 reply_called_name_not_present(outbuf);
771 break;
774 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
775 name1, name_type1, name2, name_type2));
777 if (netbios_session_retarget(xconn, name1, name_type1)) {
778 exit_server_cleanly("retargeted client");
782 * Windows NT/2k uses "*SMBSERVER" and XP uses
783 * "*SMBSERV" arrggg!!!
785 if (strequal(name1, "*SMBSERVER ")
786 || strequal(name1, "*SMBSERV ")) {
787 char *raddr;
789 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
790 talloc_tos());
791 if (raddr == NULL) {
792 exit_server_cleanly("could not allocate raddr");
795 fstrcpy(name1, raddr);
798 set_local_machine_name(name1, True);
799 set_remote_machine_name(name2, True);
801 if (is_ipaddress(sconn->remote_hostname)) {
802 char *p = discard_const_p(char, sconn->remote_hostname);
804 talloc_free(p);
806 sconn->remote_hostname = talloc_strdup(sconn,
807 get_remote_machine_name());
808 if (sconn->remote_hostname == NULL) {
809 exit_server_cleanly("could not copy remote name");
811 xconn->remote_hostname = sconn->remote_hostname;
814 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
815 get_local_machine_name(), get_remote_machine_name(),
816 name_type2));
818 if (name_type2 == 'R') {
819 /* We are being asked for a pathworks session ---
820 no thanks! */
821 reply_called_name_not_present(outbuf);
822 break;
825 reload_services(sconn, conn_snum_used, true);
826 reopen_logs();
828 xconn->transport.nbt.got_session = true;
829 break;
832 case 0x89: /* session keepalive request
833 (some old clients produce this?) */
834 SCVAL(outbuf,0,NBSSkeepalive);
835 SCVAL(outbuf,3,0);
836 break;
838 case NBSSpositive: /* positive session response */
839 case NBSSnegative: /* negative session response */
840 case NBSSretarget: /* retarget session response */
841 DEBUG(0,("Unexpected session response\n"));
842 break;
844 case NBSSkeepalive: /* session keepalive */
845 default:
846 return;
849 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
850 msg_type, msg_flags));
852 if (!smb1_srv_send(xconn, outbuf, false, 0, false)) {
853 exit_server_cleanly("reply_special: smb1_srv_send failed.");
856 if (CVAL(outbuf, 0) != 0x82) {
857 exit_server_cleanly("invalid netbios session");
859 return;
862 /*******************************************************************
863 * unlink a file with all relevant access checks
864 *******************************************************************/
866 NTSTATUS unlink_internals(connection_struct *conn,
867 struct smb_request *req,
868 uint32_t dirtype,
869 struct files_struct *dirfsp,
870 struct smb_filename *smb_fname)
872 uint32_t fattr;
873 files_struct *fsp;
874 uint32_t dirtype_orig = dirtype;
875 NTSTATUS status;
876 int ret;
877 struct smb2_create_blobs *posx = NULL;
879 if (dirtype == 0) {
880 dirtype = FILE_ATTRIBUTE_NORMAL;
883 DBG_DEBUG("%s, dirtype = %d\n",
884 smb_fname_str_dbg(smb_fname),
885 dirtype);
887 if (!CAN_WRITE(conn)) {
888 return NT_STATUS_MEDIA_WRITE_PROTECTED;
891 ret = vfs_stat(conn, smb_fname);
892 if (ret != 0) {
893 return map_nt_error_from_unix(errno);
896 fattr = fdos_mode(smb_fname->fsp);
898 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
899 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
902 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
903 if (!dirtype) {
904 return NT_STATUS_NO_SUCH_FILE;
907 if (!dir_check_ftype(fattr, dirtype)) {
908 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
909 return NT_STATUS_FILE_IS_A_DIRECTORY;
911 return NT_STATUS_NO_SUCH_FILE;
914 if (dirtype_orig & 0x8000) {
915 /* These will never be set for POSIX. */
916 return NT_STATUS_NO_SUCH_FILE;
919 #if 0
920 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
921 return NT_STATUS_FILE_IS_A_DIRECTORY;
924 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
925 return NT_STATUS_NO_SUCH_FILE;
928 if (dirtype & 0xFF00) {
929 /* These will never be set for POSIX. */
930 return NT_STATUS_NO_SUCH_FILE;
933 dirtype &= 0xFF;
934 if (!dirtype) {
935 return NT_STATUS_NO_SUCH_FILE;
938 /* Can't delete a directory. */
939 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
940 return NT_STATUS_FILE_IS_A_DIRECTORY;
942 #endif
944 #if 0 /* JRATEST */
945 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
946 return NT_STATUS_OBJECT_NAME_INVALID;
947 #endif /* JRATEST */
949 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
950 status = make_smb2_posix_create_ctx(
951 talloc_tos(), &posx, 0777);
952 if (!NT_STATUS_IS_OK(status)) {
953 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
954 nt_errstr(status));
955 return status;
959 /* On open checks the open itself will check the share mode, so
960 don't do it here as we'll get it wrong. */
962 status = SMB_VFS_CREATE_FILE
963 (conn, /* conn */
964 req, /* req */
965 dirfsp, /* dirfsp */
966 smb_fname, /* fname */
967 DELETE_ACCESS, /* access_mask */
968 FILE_SHARE_NONE, /* share_access */
969 FILE_OPEN, /* create_disposition*/
970 FILE_NON_DIRECTORY_FILE |
971 FILE_OPEN_REPARSE_POINT, /* create_options */
972 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
973 0, /* oplock_request */
974 NULL, /* lease */
975 0, /* allocation_size */
976 0, /* private_flags */
977 NULL, /* sd */
978 NULL, /* ea_list */
979 &fsp, /* result */
980 NULL, /* pinfo */
981 posx, /* in_context_blobs */
982 NULL); /* out_context_blobs */
984 TALLOC_FREE(posx);
986 if (!NT_STATUS_IS_OK(status)) {
987 DBG_DEBUG("SMB_VFS_CREATEFILE failed: %s\n",
988 nt_errstr(status));
989 return status;
992 status = can_set_delete_on_close(fsp, fattr);
993 if (!NT_STATUS_IS_OK(status)) {
994 DBG_DEBUG("can_set_delete_on_close for file %s - "
995 "(%s)\n",
996 smb_fname_str_dbg(smb_fname),
997 nt_errstr(status));
998 close_file_free(req, &fsp, NORMAL_CLOSE);
999 return status;
1002 /* The set is across all open files on this dev/inode pair. */
1003 if (!set_delete_on_close(fsp, True,
1004 conn->session_info->security_token,
1005 conn->session_info->unix_token)) {
1006 close_file_free(req, &fsp, NORMAL_CLOSE);
1007 return NT_STATUS_ACCESS_DENIED;
1010 return close_file_free(req, &fsp, NORMAL_CLOSE);
1013 /****************************************************************************
1014 Fake (read/write) sendfile. Returns -1 on read or write fail.
1015 ****************************************************************************/
1017 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
1018 off_t startpos, size_t nread)
1020 size_t bufsize;
1021 size_t tosend = nread;
1022 char *buf;
1024 if (nread == 0) {
1025 return 0;
1028 bufsize = MIN(nread, 65536);
1030 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
1031 return -1;
1034 while (tosend > 0) {
1035 ssize_t ret;
1036 size_t cur_read;
1038 cur_read = MIN(tosend, bufsize);
1039 ret = read_file(fsp,buf,startpos,cur_read);
1040 if (ret == -1) {
1041 SAFE_FREE(buf);
1042 return -1;
1045 /* If we had a short read, fill with zeros. */
1046 if (ret < cur_read) {
1047 memset(buf + ret, '\0', cur_read - ret);
1050 ret = write_data(xconn->transport.sock, buf, cur_read);
1051 if (ret != cur_read) {
1052 int saved_errno = errno;
1054 * Try and give an error message saying what
1055 * client failed.
1057 DEBUG(0, ("write_data failed for client %s. "
1058 "Error %s\n",
1059 smbXsrv_connection_dbg(xconn),
1060 strerror(saved_errno)));
1061 SAFE_FREE(buf);
1062 errno = saved_errno;
1063 return -1;
1065 tosend -= cur_read;
1066 startpos += cur_read;
1069 SAFE_FREE(buf);
1070 return (ssize_t)nread;
1073 /****************************************************************************
1074 Deal with the case of sendfile reading less bytes from the file than
1075 requested. Fill with zeros (all we can do). Returns 0 on success
1076 ****************************************************************************/
1078 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
1079 files_struct *fsp,
1080 ssize_t nread,
1081 size_t headersize,
1082 size_t smb_maxcnt)
1084 #define SHORT_SEND_BUFSIZE 1024
1085 if (nread < headersize) {
1086 DEBUG(0,("sendfile_short_send: sendfile failed to send "
1087 "header for file %s (%s). Terminating\n",
1088 fsp_str_dbg(fsp), strerror(errno)));
1089 return -1;
1092 nread -= headersize;
1094 if (nread < smb_maxcnt) {
1095 char buf[SHORT_SEND_BUFSIZE] = { 0 };
1097 DEBUG(0,("sendfile_short_send: filling truncated file %s "
1098 "with zeros !\n", fsp_str_dbg(fsp)));
1100 while (nread < smb_maxcnt) {
1102 * We asked for the real file size and told sendfile
1103 * to not go beyond the end of the file. But it can
1104 * happen that in between our fstat call and the
1105 * sendfile call the file was truncated. This is very
1106 * bad because we have already announced the larger
1107 * number of bytes to the client.
1109 * The best we can do now is to send 0-bytes, just as
1110 * a read from a hole in a sparse file would do.
1112 * This should happen rarely enough that I don't care
1113 * about efficiency here :-)
1115 size_t to_write;
1116 ssize_t ret;
1118 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
1119 ret = write_data(xconn->transport.sock, buf, to_write);
1120 if (ret != to_write) {
1121 int saved_errno = errno;
1123 * Try and give an error message saying what
1124 * client failed.
1126 DEBUG(0, ("write_data failed for client %s. "
1127 "Error %s\n",
1128 smbXsrv_connection_dbg(xconn),
1129 strerror(saved_errno)));
1130 errno = saved_errno;
1131 return -1;
1133 nread += to_write;
1137 return 0;
1140 /*******************************************************************
1141 Check if a user is allowed to rename a file.
1142 ********************************************************************/
1144 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
1145 uint16_t dirtype)
1147 NTSTATUS status;
1149 if (fsp->fsp_name->twrp != 0) {
1150 /* Get the error right, this is what Windows returns. */
1151 return NT_STATUS_NOT_SAME_DEVICE;
1154 if (!CAN_WRITE(conn)) {
1155 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1158 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
1159 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1160 /* Only bother to read the DOS attribute if we might deny the
1161 rename on the grounds of attribute mismatch. */
1162 uint32_t fmode = fdos_mode(fsp);
1163 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1164 return NT_STATUS_NO_SUCH_FILE;
1168 status = check_any_access_fsp(fsp, DELETE_ACCESS | FILE_WRITE_ATTRIBUTES);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 return status;
1172 return NT_STATUS_OK;
1175 /****************************************************************************
1176 Ensure open files have their names updated. Updated to notify other smbd's
1177 asynchronously.
1178 ****************************************************************************/
1180 static void rename_open_files(connection_struct *conn,
1181 struct share_mode_lock *lck,
1182 struct file_id id,
1183 uint32_t orig_name_hash,
1184 const struct smb_filename *smb_fname_dst)
1186 files_struct *fsp;
1187 bool did_rename = False;
1188 NTSTATUS status;
1189 uint32_t new_name_hash = 0;
1191 for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
1192 fsp = file_find_di_next(fsp, false)) {
1193 SMB_STRUCT_STAT fsp_orig_sbuf;
1194 struct file_id_buf idbuf;
1195 /* fsp_name is a relative path under the fsp. To change this for other
1196 sharepaths we need to manipulate relative paths. */
1197 /* TODO - create the absolute path and manipulate the newname
1198 relative to the sharepath. */
1199 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
1200 continue;
1202 if (fsp->name_hash != orig_name_hash) {
1203 continue;
1205 DBG_DEBUG("renaming file %s "
1206 "(file_id %s) from %s -> %s\n",
1207 fsp_fnum_dbg(fsp),
1208 file_id_str_buf(fsp->file_id, &idbuf),
1209 fsp_str_dbg(fsp),
1210 smb_fname_str_dbg(smb_fname_dst));
1213 * The incoming smb_fname_dst here has an
1214 * invalid stat struct (it must not have
1215 * existed for the rename to succeed).
1216 * Preserve the existing stat from the
1217 * open fsp after fsp_set_smb_fname()
1218 * overwrites with the invalid stat.
1220 * We will do an fstat before returning
1221 * any of this metadata to the client anyway.
1223 fsp_orig_sbuf = fsp->fsp_name->st;
1224 status = fsp_set_smb_fname(fsp, smb_fname_dst);
1225 if (NT_STATUS_IS_OK(status)) {
1226 did_rename = True;
1227 new_name_hash = fsp->name_hash;
1228 /* Restore existing stat. */
1229 fsp->fsp_name->st = fsp_orig_sbuf;
1233 if (!did_rename) {
1234 struct file_id_buf idbuf;
1235 DBG_DEBUG("no open files on file_id %s "
1236 "for %s\n",
1237 file_id_str_buf(id, &idbuf),
1238 smb_fname_str_dbg(smb_fname_dst));
1241 /* Send messages to all smbd's (not ourself) that the name has changed. */
1242 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
1243 orig_name_hash, new_name_hash,
1244 smb_fname_dst);
1248 /****************************************************************************
1249 We need to check if the source path is a parent directory of the destination
1250 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
1251 refuse the rename with a sharing violation. Under UNIX the above call can
1252 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
1253 probably need to check that the client is a Windows one before disallowing
1254 this as a UNIX client (one with UNIX extensions) can know the source is a
1255 symlink and make this decision intelligently. Found by an excellent bug
1256 report from <AndyLiebman@aol.com>.
1257 ****************************************************************************/
1259 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
1260 const struct smb_filename *smb_fname_dst)
1262 const char *psrc = smb_fname_src->base_name;
1263 const char *pdst = smb_fname_dst->base_name;
1264 size_t slen;
1266 if (psrc[0] == '.' && psrc[1] == '/') {
1267 psrc += 2;
1269 if (pdst[0] == '.' && pdst[1] == '/') {
1270 pdst += 2;
1272 if ((slen = strlen(psrc)) > strlen(pdst)) {
1273 return False;
1275 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
1279 * Do the notify calls from a rename
1282 static void notify_rename(struct connection_struct *conn,
1283 struct files_struct *fsp,
1284 const struct smb_filename *smb_fname_src,
1285 const struct smb_filename *smb_fname_dst)
1287 bool is_dir = fsp->fsp_flags.is_directory;
1288 char *parent_dir_src = NULL;
1289 char *parent_dir_dst = NULL;
1290 uint32_t mask;
1292 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
1293 : FILE_NOTIFY_CHANGE_FILE_NAME;
1295 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
1296 &parent_dir_src, NULL) ||
1297 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
1298 &parent_dir_dst, NULL)) {
1299 goto out;
1302 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
1303 notify_fname(conn,
1304 NOTIFY_ACTION_OLD_NAME,
1305 mask,
1306 smb_fname_src,
1307 NULL);
1308 notify_fname(conn,
1309 NOTIFY_ACTION_NEW_NAME |
1310 NOTIFY_ACTION_DIRLEASE_BREAK,
1311 mask,
1312 smb_fname_dst,
1313 fsp_get_smb2_lease(fsp));
1315 else {
1316 notify_fname(conn,
1317 NOTIFY_ACTION_REMOVED |
1318 NOTIFY_ACTION_DIRLEASE_BREAK,
1319 mask,
1320 smb_fname_src,
1321 fsp_get_smb2_lease(fsp));
1322 notify_fname(conn,
1323 NOTIFY_ACTION_ADDED |
1324 NOTIFY_ACTION_DIRLEASE_BREAK,
1325 mask,
1326 smb_fname_dst,
1327 fsp_get_smb2_lease(fsp));
1330 /* this is a strange one. w2k3 gives an additional event for
1331 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
1332 files, but not directories */
1333 if (!is_dir) {
1334 notify_fname(conn,
1335 NOTIFY_ACTION_MODIFIED,
1336 FILE_NOTIFY_CHANGE_ATTRIBUTES |
1337 FILE_NOTIFY_CHANGE_CREATION,
1338 smb_fname_dst,
1339 NULL);
1341 out:
1342 TALLOC_FREE(parent_dir_src);
1343 TALLOC_FREE(parent_dir_dst);
1346 /****************************************************************************
1347 Returns an error if the parent directory for a filename is open in an
1348 incompatible way.
1349 ****************************************************************************/
1351 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
1352 const struct smb_filename *smb_fname_dst_in)
1354 struct smb_filename *smb_fname_parent = NULL;
1355 struct file_id id;
1356 files_struct *fsp = NULL;
1357 int ret;
1358 NTSTATUS status;
1360 status = SMB_VFS_PARENT_PATHNAME(conn,
1361 talloc_tos(),
1362 smb_fname_dst_in,
1363 &smb_fname_parent,
1364 NULL);
1365 if (!NT_STATUS_IS_OK(status)) {
1366 return status;
1369 ret = vfs_stat(conn, smb_fname_parent);
1370 if (ret == -1) {
1371 return map_nt_error_from_unix(errno);
1375 * We're only checking on this smbd here, mostly good
1376 * enough.. and will pass tests.
1379 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
1380 for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
1381 fsp = file_find_di_next(fsp, true)) {
1382 if (fsp->access_mask & DELETE_ACCESS) {
1383 return NT_STATUS_SHARING_VIOLATION;
1386 return NT_STATUS_OK;
1389 /****************************************************************************
1390 Rename an open file - given an fsp.
1391 ****************************************************************************/
1393 NTSTATUS rename_internals_fsp(connection_struct *conn,
1394 files_struct *fsp,
1395 struct share_mode_lock **_lck,
1396 struct smb_filename *smb_fname_dst_in,
1397 const char *dst_original_lcomp,
1398 uint32_t attrs,
1399 bool replace_if_exists)
1401 TALLOC_CTX *ctx = talloc_tos();
1402 struct smb_filename *parent_dir_fname_dst = NULL;
1403 struct smb_filename *parent_dir_fname_dst_atname = NULL;
1404 struct smb_filename *parent_dir_fname_src = NULL;
1405 struct smb_filename *parent_dir_fname_src_atname = NULL;
1406 struct smb_filename *smb_fname_dst = NULL;
1407 NTSTATUS status = NT_STATUS_OK;
1408 struct share_mode_lock *lck = NULL;
1409 uint32_t access_mask = SEC_DIR_ADD_FILE;
1410 bool dst_exists, old_is_stream, new_is_stream;
1411 int ret;
1412 bool case_sensitive = fsp->fsp_flags.posix_open ?
1413 true : conn->case_sensitive;
1414 bool case_preserve = fsp->fsp_flags.posix_open ?
1415 true : conn->case_preserve;
1416 struct vfs_rename_how rhow = { .flags = 0, };
1418 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
1419 if (!NT_STATUS_IS_OK(status)) {
1420 return status;
1423 if (file_has_open_streams(fsp)) {
1424 return NT_STATUS_ACCESS_DENIED;
1427 /* Make a copy of the dst smb_fname structs */
1429 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
1430 if (smb_fname_dst == NULL) {
1431 status = NT_STATUS_NO_MEMORY;
1432 goto out;
1436 * Check for special case with case preserving and not
1437 * case sensitive. If the new last component differs from the original
1438 * last component only by case, then we should allow
1439 * the rename (user is trying to change the case of the
1440 * filename).
1442 if (!case_sensitive && case_preserve &&
1443 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1444 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
1445 char *fname_dst_parent = NULL;
1446 const char *fname_dst_lcomp = NULL;
1447 char *orig_lcomp_path = NULL;
1448 char *orig_lcomp_stream = NULL;
1449 bool ok = true;
1452 * Split off the last component of the processed
1453 * destination name. We will compare this to
1454 * the split components of dst_original_lcomp.
1456 if (!parent_dirname(ctx,
1457 smb_fname_dst->base_name,
1458 &fname_dst_parent,
1459 &fname_dst_lcomp)) {
1460 status = NT_STATUS_NO_MEMORY;
1461 goto out;
1465 * The dst_original_lcomp component contains
1466 * the last_component of the path + stream
1467 * name (if a stream exists).
1469 * Split off the stream name so we
1470 * can check them separately.
1473 if (fsp->fsp_flags.posix_open) {
1474 /* POSIX - no stream component. */
1475 orig_lcomp_path = talloc_strdup(ctx,
1476 dst_original_lcomp);
1477 if (orig_lcomp_path == NULL) {
1478 ok = false;
1480 } else {
1481 ok = split_stream_filename(ctx,
1482 dst_original_lcomp,
1483 &orig_lcomp_path,
1484 &orig_lcomp_stream);
1487 if (!ok) {
1488 TALLOC_FREE(fname_dst_parent);
1489 status = NT_STATUS_NO_MEMORY;
1490 goto out;
1493 /* If the base names only differ by case, use original. */
1494 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
1495 char *tmp;
1497 * Replace the modified last component with the
1498 * original.
1500 if (!ISDOT(fname_dst_parent)) {
1501 tmp = talloc_asprintf(smb_fname_dst,
1502 "%s/%s",
1503 fname_dst_parent,
1504 orig_lcomp_path);
1505 } else {
1506 tmp = talloc_strdup(smb_fname_dst,
1507 orig_lcomp_path);
1509 if (tmp == NULL) {
1510 status = NT_STATUS_NO_MEMORY;
1511 TALLOC_FREE(fname_dst_parent);
1512 TALLOC_FREE(orig_lcomp_path);
1513 TALLOC_FREE(orig_lcomp_stream);
1514 goto out;
1516 TALLOC_FREE(smb_fname_dst->base_name);
1517 smb_fname_dst->base_name = tmp;
1520 /* If the stream_names only differ by case, use original. */
1521 if(!strcsequal(smb_fname_dst->stream_name,
1522 orig_lcomp_stream)) {
1523 /* Use the original stream. */
1524 char *tmp = talloc_strdup(smb_fname_dst,
1525 orig_lcomp_stream);
1526 if (tmp == NULL) {
1527 status = NT_STATUS_NO_MEMORY;
1528 TALLOC_FREE(fname_dst_parent);
1529 TALLOC_FREE(orig_lcomp_path);
1530 TALLOC_FREE(orig_lcomp_stream);
1531 goto out;
1533 TALLOC_FREE(smb_fname_dst->stream_name);
1534 smb_fname_dst->stream_name = tmp;
1536 TALLOC_FREE(fname_dst_parent);
1537 TALLOC_FREE(orig_lcomp_path);
1538 TALLOC_FREE(orig_lcomp_stream);
1542 * If the src and dest names are identical - including case,
1543 * don't do the rename, just return success.
1546 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1547 strcsequal(fsp->fsp_name->stream_name,
1548 smb_fname_dst->stream_name)) {
1549 DBG_NOTICE("identical names in rename %s "
1550 "- returning success\n",
1551 smb_fname_str_dbg(smb_fname_dst));
1552 status = NT_STATUS_OK;
1553 goto out;
1556 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
1557 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
1559 /* Return the correct error code if both names aren't streams. */
1560 if (!old_is_stream && new_is_stream) {
1561 status = NT_STATUS_OBJECT_NAME_INVALID;
1562 goto out;
1565 if (old_is_stream && !new_is_stream) {
1566 status = NT_STATUS_INVALID_PARAMETER;
1567 goto out;
1570 dst_exists = vfs_stat(conn, smb_fname_dst) == 0;
1572 if(!replace_if_exists && dst_exists) {
1573 DBG_NOTICE("dest exists doing rename "
1574 "%s -> %s\n",
1575 smb_fname_str_dbg(fsp->fsp_name),
1576 smb_fname_str_dbg(smb_fname_dst));
1577 status = NT_STATUS_OBJECT_NAME_COLLISION;
1578 goto out;
1582 * Drop the pathref fsp on the destination otherwise we trip upon in in
1583 * the below check for open files check.
1585 if (smb_fname_dst_in->fsp != NULL) {
1586 fd_close(smb_fname_dst_in->fsp);
1587 file_free(NULL, smb_fname_dst_in->fsp);
1588 SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
1591 if (dst_exists) {
1592 struct file_id fileid = vfs_file_id_from_sbuf(conn,
1593 &smb_fname_dst->st);
1594 files_struct *dst_fsp = file_find_di_first(conn->sconn,
1595 fileid, true);
1596 /* The file can be open when renaming a stream */
1597 if (dst_fsp && !new_is_stream) {
1598 DBG_NOTICE("Target file open\n");
1599 status = NT_STATUS_ACCESS_DENIED;
1600 goto out;
1604 /* Ensure we have a valid stat struct for the source. */
1605 status = vfs_stat_fsp(fsp);
1606 if (!NT_STATUS_IS_OK(status)) {
1607 goto out;
1610 status = can_rename(conn, fsp, attrs);
1612 if (!NT_STATUS_IS_OK(status)) {
1613 DBG_NOTICE("Error %s rename %s -> %s\n",
1614 nt_errstr(status),
1615 smb_fname_str_dbg(fsp->fsp_name),
1616 smb_fname_str_dbg(smb_fname_dst));
1617 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
1618 status = NT_STATUS_ACCESS_DENIED;
1619 goto out;
1622 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
1623 status = NT_STATUS_ACCESS_DENIED;
1624 goto out;
1627 /* Do we have rights to move into the destination ? */
1628 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1629 /* We're moving a directory. */
1630 access_mask = SEC_DIR_ADD_SUBDIR;
1634 * Get a pathref on the destination parent directory, so
1635 * we can call check_parent_access_fsp().
1637 status = parent_pathref(ctx,
1638 conn->cwd_fsp,
1639 smb_fname_dst,
1640 &parent_dir_fname_dst,
1641 &parent_dir_fname_dst_atname);
1642 if (!NT_STATUS_IS_OK(status)) {
1643 goto out;
1646 status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
1647 access_mask);
1648 if (!NT_STATUS_IS_OK(status)) {
1649 DBG_INFO("check_parent_access_fsp on "
1650 "dst %s returned %s\n",
1651 smb_fname_str_dbg(smb_fname_dst),
1652 nt_errstr(status));
1653 goto out;
1657 * If the target existed, make sure the destination
1658 * atname has the same stat struct.
1660 parent_dir_fname_dst_atname->st = smb_fname_dst->st;
1663 * It's very common that source and
1664 * destination directories are the same.
1665 * Optimize by not opening the
1666 * second parent_pathref if we know
1667 * this is the case.
1670 status = SMB_VFS_PARENT_PATHNAME(conn,
1671 ctx,
1672 fsp->fsp_name,
1673 &parent_dir_fname_src,
1674 &parent_dir_fname_src_atname);
1675 if (!NT_STATUS_IS_OK(status)) {
1676 goto out;
1680 * We do a case-sensitive string comparison. We want to be *sure*
1681 * this is the same path. The worst that can happen if
1682 * the case doesn't match is we lose out on the optimization,
1683 * the code still works.
1685 * We can ignore twrp fields here. Rename is not allowed on
1686 * shadow copy handles.
1689 if (strcmp(parent_dir_fname_src->base_name,
1690 parent_dir_fname_dst->base_name) == 0) {
1692 * parent directory is the same for source
1693 * and destination.
1695 /* Reparent the src_atname to the parent_dir_dest fname. */
1696 parent_dir_fname_src_atname = talloc_move(
1697 parent_dir_fname_dst,
1698 &parent_dir_fname_src_atname);
1699 /* Free the unneeded duplicate parent name. */
1700 TALLOC_FREE(parent_dir_fname_src);
1702 * And make the source parent name a copy of the
1703 * destination parent name.
1705 parent_dir_fname_src = parent_dir_fname_dst;
1708 * Ensure we have a pathref fsp on the
1709 * parent_dir_fname_src_atname to match the code in the else
1710 * branch where we use parent_pathref().
1712 status = reference_smb_fname_fsp_link(
1713 parent_dir_fname_src_atname,
1714 fsp->fsp_name);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 goto out;
1718 } else {
1720 * source and destination parent directories are
1721 * different.
1723 * Get a pathref on the source parent directory, so
1724 * we can do a relative rename.
1726 TALLOC_FREE(parent_dir_fname_src);
1727 status = parent_pathref(ctx,
1728 conn->cwd_fsp,
1729 fsp->fsp_name,
1730 &parent_dir_fname_src,
1731 &parent_dir_fname_src_atname);
1732 if (!NT_STATUS_IS_OK(status)) {
1733 goto out;
1738 * Some modules depend on the source smb_fname having a valid stat.
1739 * The parent_dir_fname_src_atname is the relative name of the
1740 * currently open file, so just copy the stat from the open fsp.
1742 parent_dir_fname_src_atname->st = fsp->fsp_name->st;
1744 if (_lck != NULL) {
1745 lck = talloc_move(talloc_tos(), _lck);
1746 } else {
1747 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1751 * We have the file open ourselves, so not being able to get the
1752 * corresponding share mode lock is a fatal error.
1755 SMB_ASSERT(lck != NULL);
1757 ret = SMB_VFS_RENAMEAT(conn,
1758 parent_dir_fname_src->fsp,
1759 parent_dir_fname_src_atname,
1760 parent_dir_fname_dst->fsp,
1761 parent_dir_fname_dst_atname,
1762 &rhow);
1763 if (ret == 0) {
1764 uint32_t create_options = fh_get_private_options(fsp->fh);
1765 struct smb_filename *old_fname = NULL;
1767 DBG_NOTICE("succeeded doing rename on "
1768 "%s -> %s\n",
1769 smb_fname_str_dbg(fsp->fsp_name),
1770 smb_fname_str_dbg(smb_fname_dst));
1772 old_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
1773 if (old_fname == NULL) {
1774 status = NT_STATUS_NO_MEMORY;
1775 TALLOC_FREE(lck);
1776 goto out;
1778 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
1779 smb_fname_dst);
1781 if (!fsp->fsp_flags.is_directory &&
1782 (lp_map_archive(SNUM(conn)) ||
1783 lp_store_dos_attributes(SNUM(conn))))
1786 * We must set the archive bit on the newly renamed
1787 * file.
1789 status = vfs_stat_fsp(fsp);
1790 if (NT_STATUS_IS_OK(status)) {
1791 uint32_t old_dosmode;
1792 old_dosmode = fdos_mode(fsp);
1794 * We can use fsp->fsp_name here as it has
1795 * already been changed to the new name.
1797 SMB_ASSERT(fsp->fsp_name->fsp == fsp);
1798 file_set_dosmode(conn,
1799 fsp->fsp_name,
1800 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
1801 NULL,
1802 true);
1807 * A rename acts as a new file create w.r.t. allowing an initial delete
1808 * on close, probably because in Windows there is a new handle to the
1809 * new file. If initial delete on close was requested but not
1810 * originally set, we need to set it here. This is probably not 100% correct,
1811 * but will work for the CIFSFS client which in non-posix mode
1812 * depends on these semantics. JRA.
1815 if (create_options & FILE_DELETE_ON_CLOSE) {
1816 status = can_set_delete_on_close(fsp, 0);
1818 if (NT_STATUS_IS_OK(status)) {
1819 /* Note that here we set the *initial* delete on close flag,
1820 * not the regular one. The magic gets handled in close. */
1821 fsp->fsp_flags.initial_delete_on_close = true;
1825 TALLOC_FREE(lck);
1827 notify_rename(conn,
1828 fsp,
1829 old_fname,
1830 smb_fname_dst);
1832 TALLOC_FREE(old_fname);
1833 status = NT_STATUS_OK;
1834 goto out;
1837 TALLOC_FREE(lck);
1839 if (errno == ENOTDIR || errno == EISDIR) {
1840 status = NT_STATUS_OBJECT_NAME_COLLISION;
1841 } else {
1842 status = map_nt_error_from_unix(errno);
1845 DBG_NOTICE("Error %s rename %s -> %s\n",
1846 nt_errstr(status),
1847 smb_fname_str_dbg(fsp->fsp_name),
1848 smb_fname_str_dbg(smb_fname_dst));
1850 out:
1853 * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
1854 * See the optimization for same source and destination directory
1855 * above. Only free one in that case.
1857 if (parent_dir_fname_src != parent_dir_fname_dst) {
1858 TALLOC_FREE(parent_dir_fname_src);
1860 TALLOC_FREE(parent_dir_fname_dst);
1861 TALLOC_FREE(smb_fname_dst);
1863 return status;
1866 /****************************************************************************
1867 The guts of the rename command, split out so it may be called by the NT SMB
1868 code.
1869 ****************************************************************************/
1871 NTSTATUS rename_internals(TALLOC_CTX *ctx,
1872 connection_struct *conn,
1873 struct smb_request *req,
1874 struct files_struct *src_dirfsp,
1875 struct smb_filename *smb_fname_src,
1876 struct smb_filename *smb_fname_dst,
1877 const char *dst_original_lcomp,
1878 uint32_t attrs,
1879 bool replace_if_exists,
1880 uint32_t access_mask)
1882 NTSTATUS status = NT_STATUS_OK;
1883 int create_options = FILE_OPEN_REPARSE_POINT;
1884 struct smb2_create_blobs *posx = NULL;
1885 struct files_struct *fsp = NULL;
1886 bool posix_pathname = (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH);
1887 bool case_sensitive = posix_pathname ? true : conn->case_sensitive;
1888 bool case_preserve = posix_pathname ? true : conn->case_preserve;
1889 bool short_case_preserve = posix_pathname ? true :
1890 conn->short_case_preserve;
1892 if (posix_pathname) {
1893 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
1894 if (!NT_STATUS_IS_OK(status)) {
1895 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
1896 nt_errstr(status));
1897 goto out;
1901 DBG_NOTICE("case_sensitive = %d, "
1902 "case_preserve = %d, short case preserve = %d, "
1903 "directory = %s, newname = %s, "
1904 "last_component_dest = %s\n",
1905 case_sensitive, case_preserve,
1906 short_case_preserve,
1907 smb_fname_str_dbg(smb_fname_src),
1908 smb_fname_str_dbg(smb_fname_dst),
1909 dst_original_lcomp);
1911 ZERO_STRUCT(smb_fname_src->st);
1913 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1914 if (!NT_STATUS_IS_OK(status)) {
1915 if (!NT_STATUS_EQUAL(status,
1916 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1917 goto out;
1920 * Possible symlink src.
1922 if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
1923 goto out;
1925 if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
1926 goto out;
1930 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
1931 create_options |= FILE_DIRECTORY_FILE;
1934 status = SMB_VFS_CREATE_FILE(
1935 conn, /* conn */
1936 req, /* req */
1937 src_dirfsp, /* dirfsp */
1938 smb_fname_src, /* fname */
1939 access_mask, /* access_mask */
1940 (FILE_SHARE_READ | /* share_access */
1941 FILE_SHARE_WRITE),
1942 FILE_OPEN, /* create_disposition*/
1943 create_options, /* create_options */
1944 0, /* file_attributes */
1945 0, /* oplock_request */
1946 NULL, /* lease */
1947 0, /* allocation_size */
1948 0, /* private_flags */
1949 NULL, /* sd */
1950 NULL, /* ea_list */
1951 &fsp, /* result */
1952 NULL, /* pinfo */
1953 posx, /* in_context_blobs */
1954 NULL); /* out_context_blobs */
1956 if (!NT_STATUS_IS_OK(status)) {
1957 DBG_NOTICE("Could not open rename source %s: %s\n",
1958 smb_fname_str_dbg(smb_fname_src),
1959 nt_errstr(status));
1960 goto out;
1964 * If no pathnames are open below this directory, allow the rename.
1966 if (have_file_open_below(fsp)) {
1967 status = NT_STATUS_ACCESS_DENIED;
1968 close_file_free(req, &fsp, NORMAL_CLOSE);
1969 goto out;
1972 status = rename_internals_fsp(conn,
1973 fsp,
1974 NULL,
1975 smb_fname_dst,
1976 dst_original_lcomp,
1977 attrs,
1978 replace_if_exists);
1980 close_file_free(req, &fsp, NORMAL_CLOSE);
1982 DBG_NOTICE("Error %s rename %s -> %s\n",
1983 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
1984 smb_fname_str_dbg(smb_fname_dst));
1986 out:
1987 TALLOC_FREE(posx);
1988 return status;
1991 /*******************************************************************
1992 Copy a file as part of a reply_copy.
1993 ******************************************************************/
1996 * TODO: check error codes on all callers
1999 NTSTATUS copy_file(TALLOC_CTX *ctx,
2000 connection_struct *conn,
2001 struct smb_filename *smb_fname_src,
2002 struct smb_filename *smb_fname_dst,
2003 uint32_t new_create_disposition)
2005 struct smb_filename *smb_fname_dst_tmp = NULL;
2006 off_t ret=-1;
2007 files_struct *fsp1,*fsp2;
2008 uint32_t dosattrs;
2009 NTSTATUS status;
2012 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
2013 if (smb_fname_dst_tmp == NULL) {
2014 return NT_STATUS_NO_MEMORY;
2017 status = vfs_file_exist(conn, smb_fname_src);
2018 if (!NT_STATUS_IS_OK(status)) {
2019 goto out;
2022 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
2023 if (!NT_STATUS_IS_OK(status)) {
2024 goto out;
2027 /* Open the src file for reading. */
2028 status = SMB_VFS_CREATE_FILE(
2029 conn, /* conn */
2030 NULL, /* req */
2031 NULL, /* dirfsp */
2032 smb_fname_src, /* fname */
2033 FILE_GENERIC_READ, /* access_mask */
2034 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2035 FILE_OPEN, /* create_disposition*/
2036 0, /* create_options */
2037 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2038 INTERNAL_OPEN_ONLY, /* oplock_request */
2039 NULL, /* lease */
2040 0, /* allocation_size */
2041 0, /* private_flags */
2042 NULL, /* sd */
2043 NULL, /* ea_list */
2044 &fsp1, /* result */
2045 NULL, /* psbuf */
2046 NULL, NULL); /* create context */
2048 if (!NT_STATUS_IS_OK(status)) {
2049 goto out;
2052 dosattrs = fdos_mode(fsp1);
2054 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
2055 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
2058 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
2059 if (!NT_STATUS_IS_OK(status) &&
2060 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
2062 goto out;
2065 /* Open the dst file for writing. */
2066 status = SMB_VFS_CREATE_FILE(
2067 conn, /* conn */
2068 NULL, /* req */
2069 NULL, /* dirfsp */
2070 smb_fname_dst, /* fname */
2071 FILE_GENERIC_WRITE, /* access_mask */
2072 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2073 new_create_disposition, /* create_disposition*/
2074 0, /* create_options */
2075 dosattrs, /* file_attributes */
2076 INTERNAL_OPEN_ONLY, /* oplock_request */
2077 NULL, /* lease */
2078 0, /* allocation_size */
2079 0, /* private_flags */
2080 NULL, /* sd */
2081 NULL, /* ea_list */
2082 &fsp2, /* result */
2083 NULL, /* psbuf */
2084 NULL, NULL); /* create context */
2086 if (!NT_STATUS_IS_OK(status)) {
2087 close_file_free(NULL, &fsp1, ERROR_CLOSE);
2088 goto out;
2091 /* Do the actual copy. */
2092 if (smb_fname_src->st.st_ex_size) {
2093 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
2094 } else {
2095 ret = 0;
2098 close_file_free(NULL, &fsp1, NORMAL_CLOSE);
2100 /* Ensure the modtime is set correctly on the destination file. */
2101 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
2104 * As we are opening fsp1 read-only we only expect
2105 * an error on close on fsp2 if we are out of space.
2106 * Thus we don't look at the error return from the
2107 * close of fsp1.
2109 status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
2111 if (!NT_STATUS_IS_OK(status)) {
2112 goto out;
2115 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
2116 status = NT_STATUS_DISK_FULL;
2117 goto out;
2120 status = NT_STATUS_OK;
2122 out:
2123 TALLOC_FREE(smb_fname_dst_tmp);
2124 return status;
2127 /****************************************************************************
2128 Get a lock offset, dealing with large offset requests.
2129 ****************************************************************************/
2131 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
2132 bool large_file_format)
2134 uint64_t offset = 0;
2136 if(!large_file_format) {
2137 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
2138 } else {
2140 * No BVAL, this is reversed!
2142 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
2143 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
2146 return offset;
2149 struct smbd_do_unlocking_state {
2150 struct files_struct *fsp;
2151 uint16_t num_ulocks;
2152 struct smbd_lock_element *ulocks;
2153 NTSTATUS status;
2156 static void smbd_do_unlocking_fn(
2157 struct share_mode_lock *lck,
2158 void *private_data)
2160 struct smbd_do_unlocking_state *state = private_data;
2161 struct files_struct *fsp = state->fsp;
2162 uint16_t i;
2164 for (i = 0; i < state->num_ulocks; i++) {
2165 struct smbd_lock_element *e = &state->ulocks[i];
2167 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
2168 "pid %"PRIu64", file %s\n",
2169 e->offset,
2170 e->count,
2171 e->smblctx,
2172 fsp_str_dbg(fsp));
2174 if (e->brltype != UNLOCK_LOCK) {
2175 /* this can only happen with SMB2 */
2176 state->status = NT_STATUS_INVALID_PARAMETER;
2177 return;
2180 state->status = do_unlock(
2181 fsp, e->smblctx, e->count, e->offset, e->lock_flav);
2183 DBG_DEBUG("do_unlock returned %s\n",
2184 nt_errstr(state->status));
2186 if (!NT_STATUS_IS_OK(state->status)) {
2187 return;
2191 share_mode_wakeup_waiters(fsp->file_id);
2194 NTSTATUS smbd_do_unlocking(struct smb_request *req,
2195 files_struct *fsp,
2196 uint16_t num_ulocks,
2197 struct smbd_lock_element *ulocks)
2199 struct smbd_do_unlocking_state state = {
2200 .fsp = fsp,
2201 .num_ulocks = num_ulocks,
2202 .ulocks = ulocks,
2204 NTSTATUS status;
2206 DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
2208 status = share_mode_do_locked_vfs_allowed(
2209 fsp->file_id, smbd_do_unlocking_fn, &state);
2211 if (!NT_STATUS_IS_OK(status)) {
2212 DBG_DEBUG("share_mode_do_locked_vfs_allowed failed: %s\n",
2213 nt_errstr(status));
2214 return status;
2216 if (!NT_STATUS_IS_OK(state.status)) {
2217 DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
2218 nt_errstr(status));
2219 return state.status;
2222 return NT_STATUS_OK;