s4:auth: Let dsdb gMSA time influence NTLM previous password allowed period
[Samba.git] / source3 / smbd / smb2_reply.c
blob2b65fb30d76a807c444b0fbd059932c529df6774
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;
173 if (!(*s & 0x80)) {
174 if (!posix_path) {
175 if (*s <= 0x1f || *s == '|') {
176 return NT_STATUS_OBJECT_NAME_INVALID;
178 switch (*s) {
179 case '*':
180 case '?':
181 case '<':
182 case '>':
183 case '"':
184 last_component_contains_wcard = true;
185 break;
186 default:
187 break;
190 *d++ = *s++;
191 } else {
192 size_t ch_size;
193 /* Get the size of the next MB character. */
194 next_codepoint(s,&ch_size);
195 switch(ch_size) {
196 case 5:
197 *d++ = *s++;
198 FALL_THROUGH;
199 case 4:
200 *d++ = *s++;
201 FALL_THROUGH;
202 case 3:
203 *d++ = *s++;
204 FALL_THROUGH;
205 case 2:
206 *d++ = *s++;
207 FALL_THROUGH;
208 case 1:
209 *d++ = *s++;
210 break;
211 default:
212 DBG_ERR("character length assumptions invalid !\n");
213 *d = '\0';
214 return NT_STATUS_INVALID_PARAMETER;
217 start_of_name_component = False;
220 *d = '\0';
222 return ret;
225 /****************************************************************************
226 SMB2-only code to strip an MSDFS prefix from an incoming pathname.
227 ****************************************************************************/
229 NTSTATUS smb2_strip_dfs_path(const char *in_path, const char **out_path)
231 const char *path = in_path;
233 /* Match the Windows 2022 behavior for an empty DFS pathname. */
234 if (*path == '\0') {
235 return NT_STATUS_INVALID_PARAMETER;
237 /* Strip any leading '\\' characters - MacOSX client behavior. */
238 while (*path == '\\') {
239 path++;
241 /* We should now be pointing at the server name. Go past it. */
242 for (;;) {
243 if (*path == '\0') {
244 /* End of complete path. Exit OK. */
245 goto out;
247 if (*path == '\\') {
248 /* End of server name. Go past and break. */
249 path++;
250 break;
252 path++; /* Continue looking for end of server name or string. */
255 /* We should now be pointing at the share name. Go past it. */
256 for (;;) {
257 if (*path == '\0') {
258 /* End of complete path. Exit OK. */
259 goto out;
261 if (*path == '\\') {
262 /* End of share name. Go past and break. */
263 path++;
264 break;
266 if (*path == ':') {
267 /* Only invalid character in sharename. */
268 return NT_STATUS_OBJECT_NAME_INVALID;
270 path++; /* Continue looking for end of share name or string. */
273 /* path now points at the start of the real filename (if any). */
275 out:
276 /* We have stripped the DFS path prefix (if any). */
277 *out_path = path;
278 return NT_STATUS_OK;
281 /****************************************************************************
282 Pull a string and check the path allowing a wildcard - provide for error return.
283 Passes in posix flag.
284 ****************************************************************************/
286 static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
287 const char *base_ptr,
288 uint16_t smb_flags2,
289 char **pp_dest,
290 const char *src,
291 size_t src_len,
292 int flags,
293 bool posix_pathnames,
294 NTSTATUS *err)
296 size_t ret;
297 char *dst = NULL;
299 *pp_dest = NULL;
301 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
302 src_len, flags);
304 if (!*pp_dest) {
305 *err = NT_STATUS_INVALID_PARAMETER;
306 return ret;
309 dst = *pp_dest;
311 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
313 * A valid DFS path looks either like
314 * /server/share
315 * \server\share
316 * (there may be more components after).
317 * Either way it must have at least two separators.
319 * Ensure we end up as /server/share
320 * so we don't need to special case
321 * separator characters elsewhere in
322 * the code.
324 char *server = NULL;
325 char *share = NULL;
326 char *remaining_path = NULL;
327 char path_sep = 0;
328 char *p = NULL;
330 if (posix_pathnames && (dst[0] == '/')) {
331 path_sep = dst[0];
332 } else if (dst[0] == '\\') {
333 path_sep = dst[0];
336 if (path_sep == 0) {
337 goto local_path;
340 * May be a DFS path.
341 * We need some heuristics here,
342 * as clients differ on what constitutes
343 * a well-formed DFS path. If the path
344 * appears malformed, just fall back to
345 * processing as a local path.
347 server = dst;
350 * Cosmetic fix for Linux-only DFS clients.
351 * The Linux kernel SMB1 client has a bug - it sends
352 * DFS pathnames as:
354 * \\server\share\path
356 * Causing us to mis-parse server,share,remaining_path here
357 * and jump into 'goto local_path' at 'share\path' instead
358 * of 'path'.
360 * This doesn't cause an error as the limits on share names
361 * are similar to those on pathnames.
363 * parse_dfs_path() which we call before filename parsing
364 * copes with this by calling trim_char on the leading '\'
365 * characters before processing.
366 * Do the same here so logging of pathnames looks better.
368 if (server[1] == path_sep) {
369 trim_char(&server[1], path_sep, '\0');
373 * Look to see if we also have /share following.
375 share = strchr(server+1, path_sep);
376 if (share == NULL) {
377 goto local_path;
380 * Ensure the server name does not contain
381 * any possible path components by converting
382 * them to _'s.
384 for (p = server + 1; p < share; p++) {
385 if (*p == '/' || *p == '\\') {
386 *p = '_';
390 * It's a well formed DFS path with
391 * at least server and share components.
392 * Replace the slashes with '/' and
393 * pass the remainder to local_path.
395 *server = '/';
396 *share = '/';
398 * Skip past share so we don't pass the
399 * sharename into check_path_syntax().
401 remaining_path = strchr(share+1, path_sep);
402 if (remaining_path == NULL) {
404 * Ensure the share name does not contain
405 * any possible path components by converting
406 * them to _'s.
408 for (p = share + 1; *p; p++) {
409 if (*p == '/' || *p == '\\') {
410 *p = '_';
414 * If no remaining path this was
415 * a bare /server/share path. Just return.
417 *err = NT_STATUS_OK;
418 return ret;
421 * Ensure the share name does not contain
422 * any possible path components by converting
423 * them to _'s.
425 for (p = share + 1; p < remaining_path; p++) {
426 if (*p == '/' || *p == '\\') {
427 *p = '_';
430 *remaining_path = '/';
431 dst = remaining_path + 1;
432 /* dst now points at any following components. */
435 local_path:
437 *err = check_path_syntax(dst, posix_pathnames);
439 return ret;
442 /****************************************************************************
443 Pull a string and check the path - provide for error return.
444 ****************************************************************************/
446 size_t srvstr_get_path(TALLOC_CTX *ctx,
447 const char *base_ptr,
448 uint16_t smb_flags2,
449 char **pp_dest,
450 const char *src,
451 size_t src_len,
452 int flags,
453 NTSTATUS *err)
455 return srvstr_get_path_internal(ctx,
456 base_ptr,
457 smb_flags2,
458 pp_dest,
459 src,
460 src_len,
461 flags,
462 false,
463 err);
466 /****************************************************************************
467 Pull a string and check the path - provide for error return.
468 posix_pathnames version.
469 ****************************************************************************/
471 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
472 const char *base_ptr,
473 uint16_t smb_flags2,
474 char **pp_dest,
475 const char *src,
476 size_t src_len,
477 int flags,
478 NTSTATUS *err)
480 return srvstr_get_path_internal(ctx,
481 base_ptr,
482 smb_flags2,
483 pp_dest,
484 src,
485 src_len,
486 flags,
487 true,
488 err);
492 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
493 char **pp_dest, const char *src, int flags,
494 NTSTATUS *err)
496 ssize_t bufrem = smbreq_bufrem(req, src);
498 if (bufrem == 0) {
499 *err = NT_STATUS_INVALID_PARAMETER;
500 return 0;
503 if (req->posix_pathnames) {
504 return srvstr_get_path_internal(mem_ctx,
505 (const char *)req->inbuf,
506 req->flags2,
507 pp_dest,
508 src,
509 bufrem,
510 flags,
511 true,
512 err);
513 } else {
514 return srvstr_get_path_internal(mem_ctx,
515 (const char *)req->inbuf,
516 req->flags2,
517 pp_dest,
518 src,
519 bufrem,
520 flags,
521 false,
522 err);
527 * pull a string from the smb_buf part of a packet. In this case the
528 * string can either be null terminated or it can be terminated by the
529 * end of the smbbuf area
531 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
532 char **dest, const uint8_t *src, int flags)
534 ssize_t bufrem = smbreq_bufrem(req, src);
536 if (bufrem == 0) {
537 *dest = NULL;
538 return 0;
541 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
542 bufrem, flags);
545 /****************************************************************************
546 Check if we have a correct fsp pointing to a quota fake file. Replacement for
547 the CHECK_NTQUOTA_HANDLE_OK macro.
548 ****************************************************************************/
550 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
551 files_struct *fsp)
553 if ((fsp == NULL) || (conn == NULL)) {
554 return false;
557 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
558 return false;
561 if (fsp->fsp_flags.is_directory) {
562 return false;
565 if (fsp->fake_file_handle == NULL) {
566 return false;
569 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
570 return false;
573 if (fsp->fake_file_handle->private_data == NULL) {
574 return false;
577 return true;
580 /****************************************************************************
581 Return the port number we've bound to on a socket.
582 ****************************************************************************/
584 static int get_socket_port(int fd)
586 struct samba_sockaddr saddr = {
587 .sa_socklen = sizeof(struct sockaddr_storage),
590 if (fd == -1) {
591 return -1;
594 if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
595 int level = (errno == ENOTCONN) ? 2 : 0;
596 DEBUG(level, ("getsockname failed. Error was %s\n",
597 strerror(errno)));
598 return -1;
601 #if defined(HAVE_IPV6)
602 if (saddr.u.sa.sa_family == AF_INET6) {
603 return ntohs(saddr.u.in6.sin6_port);
605 #endif
606 if (saddr.u.sa.sa_family == AF_INET) {
607 return ntohs(saddr.u.in.sin_port);
609 return -1;
612 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
613 const char *name, int name_type)
615 char *trim_name;
616 char *trim_name_type;
617 const char *retarget_parm;
618 char *retarget;
619 char *p;
620 int retarget_type = 0x20;
621 int retarget_port = NBT_SMB_PORT;
622 struct sockaddr_storage retarget_addr;
623 struct sockaddr_in *in_addr;
624 bool ret = false;
625 uint8_t outbuf[10];
627 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
628 return false;
631 trim_name = talloc_strdup(talloc_tos(), name);
632 if (trim_name == NULL) {
633 goto fail;
635 trim_char(trim_name, ' ', ' ');
637 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
638 name_type);
639 if (trim_name_type == NULL) {
640 goto fail;
643 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
644 trim_name_type, NULL);
645 if (retarget_parm == NULL) {
646 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
647 trim_name, NULL);
649 if (retarget_parm == NULL) {
650 goto fail;
653 retarget = talloc_strdup(trim_name, retarget_parm);
654 if (retarget == NULL) {
655 goto fail;
658 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
660 p = strchr(retarget, ':');
661 if (p != NULL) {
662 *p++ = '\0';
663 retarget_port = atoi(p);
666 p = strchr_m(retarget, '#');
667 if (p != NULL) {
668 *p++ = '\0';
669 if (sscanf(p, "%x", &retarget_type) != 1) {
670 goto fail;
674 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
675 if (!ret) {
676 DEBUG(10, ("could not resolve %s\n", retarget));
677 goto fail;
680 if (retarget_addr.ss_family != AF_INET) {
681 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
682 goto fail;
685 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
687 _smb_setlen(outbuf, 6);
688 SCVAL(outbuf, 0, 0x84);
689 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
690 *(uint16_t *)(outbuf+8) = htons(retarget_port);
692 if (!smb1_srv_send(xconn, (char *)outbuf, false, 0, false)) {
693 exit_server_cleanly("netbios_session_retarget: smb1_srv_send "
694 "failed.");
697 ret = true;
698 fail:
699 TALLOC_FREE(trim_name);
700 return ret;
703 static void reply_called_name_not_present(char *outbuf)
705 smb_setlen(outbuf, 1);
706 SCVAL(outbuf, 0, 0x83);
707 SCVAL(outbuf, 4, 0x82);
710 /****************************************************************************
711 Reply to a (netbios-level) special message.
712 ****************************************************************************/
714 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
716 struct smbd_server_connection *sconn = xconn->client->sconn;
717 int msg_type = CVAL(inbuf,0);
718 int msg_flags = CVAL(inbuf,1);
720 * We only really use 4 bytes of the outbuf, but for the smb_setlen
721 * calculation & friends (smb1_srv_send uses that) we need the full smb
722 * header.
724 char outbuf[smb_size];
726 memset(outbuf, '\0', sizeof(outbuf));
728 smb_setlen(outbuf,0);
730 switch (msg_type) {
731 case NBSSrequest: /* session request */
733 /* inbuf_size is guaranteed to be at least 4. */
734 fstring name1,name2;
735 int name_type1, name_type2;
736 int name_len1, name_len2;
738 *name1 = *name2 = 0;
740 if (xconn->transport.nbt.got_session) {
741 exit_server_cleanly("multiple session request not permitted");
744 SCVAL(outbuf,0,NBSSpositive);
745 SCVAL(outbuf,3,0);
747 /* inbuf_size is guaranteed to be at least 4. */
748 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
749 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
750 DEBUG(0,("Invalid name length in session request\n"));
751 reply_called_name_not_present(outbuf);
752 break;
754 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
755 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
756 DEBUG(0,("Invalid name length in session request\n"));
757 reply_called_name_not_present(outbuf);
758 break;
761 name_type1 = name_extract((unsigned char *)inbuf,
762 inbuf_size,(unsigned int)4,name1);
763 name_type2 = name_extract((unsigned char *)inbuf,
764 inbuf_size,(unsigned int)(4 + name_len1),name2);
766 if (name_type1 == -1 || name_type2 == -1) {
767 DEBUG(0,("Invalid name type in session request\n"));
768 reply_called_name_not_present(outbuf);
769 break;
772 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
773 name1, name_type1, name2, name_type2));
775 if (netbios_session_retarget(xconn, name1, name_type1)) {
776 exit_server_cleanly("retargeted client");
780 * Windows NT/2k uses "*SMBSERVER" and XP uses
781 * "*SMBSERV" arrggg!!!
783 if (strequal(name1, "*SMBSERVER ")
784 || strequal(name1, "*SMBSERV ")) {
785 char *raddr;
787 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
788 talloc_tos());
789 if (raddr == NULL) {
790 exit_server_cleanly("could not allocate raddr");
793 fstrcpy(name1, raddr);
796 set_local_machine_name(name1, True);
797 set_remote_machine_name(name2, True);
799 if (is_ipaddress(sconn->remote_hostname)) {
800 char *p = discard_const_p(char, sconn->remote_hostname);
802 talloc_free(p);
804 sconn->remote_hostname = talloc_strdup(sconn,
805 get_remote_machine_name());
806 if (sconn->remote_hostname == NULL) {
807 exit_server_cleanly("could not copy remote name");
809 xconn->remote_hostname = sconn->remote_hostname;
812 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
813 get_local_machine_name(), get_remote_machine_name(),
814 name_type2));
816 if (name_type2 == 'R') {
817 /* We are being asked for a pathworks session ---
818 no thanks! */
819 reply_called_name_not_present(outbuf);
820 break;
823 reload_services(sconn, conn_snum_used, true);
824 reopen_logs();
826 xconn->transport.nbt.got_session = true;
827 break;
830 case 0x89: /* session keepalive request
831 (some old clients produce this?) */
832 SCVAL(outbuf,0,NBSSkeepalive);
833 SCVAL(outbuf,3,0);
834 break;
836 case NBSSpositive: /* positive session response */
837 case NBSSnegative: /* negative session response */
838 case NBSSretarget: /* retarget session response */
839 DEBUG(0,("Unexpected session response\n"));
840 break;
842 case NBSSkeepalive: /* session keepalive */
843 default:
844 return;
847 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
848 msg_type, msg_flags));
850 if (!smb1_srv_send(xconn, outbuf, false, 0, false)) {
851 exit_server_cleanly("reply_special: smb1_srv_send failed.");
854 if (CVAL(outbuf, 0) != 0x82) {
855 exit_server_cleanly("invalid netbios session");
857 return;
860 /*******************************************************************
861 * unlink a file with all relevant access checks
862 *******************************************************************/
864 NTSTATUS unlink_internals(connection_struct *conn,
865 struct smb_request *req,
866 uint32_t dirtype,
867 struct files_struct *dirfsp,
868 struct smb_filename *smb_fname)
870 uint32_t fattr;
871 files_struct *fsp;
872 uint32_t dirtype_orig = dirtype;
873 NTSTATUS status;
874 int ret;
875 struct smb2_create_blobs *posx = NULL;
877 if (dirtype == 0) {
878 dirtype = FILE_ATTRIBUTE_NORMAL;
881 DBG_DEBUG("%s, dirtype = %d\n",
882 smb_fname_str_dbg(smb_fname),
883 dirtype);
885 if (!CAN_WRITE(conn)) {
886 return NT_STATUS_MEDIA_WRITE_PROTECTED;
889 ret = vfs_stat(conn, smb_fname);
890 if (ret != 0) {
891 return map_nt_error_from_unix(errno);
894 fattr = fdos_mode(smb_fname->fsp);
896 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
897 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
900 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
901 if (!dirtype) {
902 return NT_STATUS_NO_SUCH_FILE;
905 if (!dir_check_ftype(fattr, dirtype)) {
906 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
907 return NT_STATUS_FILE_IS_A_DIRECTORY;
909 return NT_STATUS_NO_SUCH_FILE;
912 if (dirtype_orig & 0x8000) {
913 /* These will never be set for POSIX. */
914 return NT_STATUS_NO_SUCH_FILE;
917 #if 0
918 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
919 return NT_STATUS_FILE_IS_A_DIRECTORY;
922 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
923 return NT_STATUS_NO_SUCH_FILE;
926 if (dirtype & 0xFF00) {
927 /* These will never be set for POSIX. */
928 return NT_STATUS_NO_SUCH_FILE;
931 dirtype &= 0xFF;
932 if (!dirtype) {
933 return NT_STATUS_NO_SUCH_FILE;
936 /* Can't delete a directory. */
937 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
938 return NT_STATUS_FILE_IS_A_DIRECTORY;
940 #endif
942 #if 0 /* JRATEST */
943 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
944 return NT_STATUS_OBJECT_NAME_INVALID;
945 #endif /* JRATEST */
947 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
948 status = make_smb2_posix_create_ctx(
949 talloc_tos(), &posx, 0777);
950 if (!NT_STATUS_IS_OK(status)) {
951 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
952 nt_errstr(status));
953 return status;
957 /* On open checks the open itself will check the share mode, so
958 don't do it here as we'll get it wrong. */
960 status = SMB_VFS_CREATE_FILE
961 (conn, /* conn */
962 req, /* req */
963 dirfsp, /* dirfsp */
964 smb_fname, /* fname */
965 DELETE_ACCESS, /* access_mask */
966 FILE_SHARE_NONE, /* share_access */
967 FILE_OPEN, /* create_disposition*/
968 FILE_NON_DIRECTORY_FILE |
969 FILE_OPEN_REPARSE_POINT, /* create_options */
970 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
971 0, /* oplock_request */
972 NULL, /* lease */
973 0, /* allocation_size */
974 0, /* private_flags */
975 NULL, /* sd */
976 NULL, /* ea_list */
977 &fsp, /* result */
978 NULL, /* pinfo */
979 posx, /* in_context_blobs */
980 NULL); /* out_context_blobs */
982 TALLOC_FREE(posx);
984 if (!NT_STATUS_IS_OK(status)) {
985 DBG_DEBUG("SMB_VFS_CREATEFILE failed: %s\n",
986 nt_errstr(status));
987 return status;
990 status = can_set_delete_on_close(fsp, fattr);
991 if (!NT_STATUS_IS_OK(status)) {
992 DBG_DEBUG("can_set_delete_on_close for file %s - "
993 "(%s)\n",
994 smb_fname_str_dbg(smb_fname),
995 nt_errstr(status));
996 close_file_free(req, &fsp, NORMAL_CLOSE);
997 return status;
1000 /* The set is across all open files on this dev/inode pair. */
1001 if (!set_delete_on_close(fsp, True,
1002 conn->session_info->security_token,
1003 conn->session_info->unix_token)) {
1004 close_file_free(req, &fsp, NORMAL_CLOSE);
1005 return NT_STATUS_ACCESS_DENIED;
1008 return close_file_free(req, &fsp, NORMAL_CLOSE);
1011 /****************************************************************************
1012 Fake (read/write) sendfile. Returns -1 on read or write fail.
1013 ****************************************************************************/
1015 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
1016 off_t startpos, size_t nread)
1018 size_t bufsize;
1019 size_t tosend = nread;
1020 char *buf;
1022 if (nread == 0) {
1023 return 0;
1026 bufsize = MIN(nread, 65536);
1028 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
1029 return -1;
1032 while (tosend > 0) {
1033 ssize_t ret;
1034 size_t cur_read;
1036 cur_read = MIN(tosend, bufsize);
1037 ret = read_file(fsp,buf,startpos,cur_read);
1038 if (ret == -1) {
1039 SAFE_FREE(buf);
1040 return -1;
1043 /* If we had a short read, fill with zeros. */
1044 if (ret < cur_read) {
1045 memset(buf + ret, '\0', cur_read - ret);
1048 ret = write_data(xconn->transport.sock, buf, cur_read);
1049 if (ret != cur_read) {
1050 int saved_errno = errno;
1052 * Try and give an error message saying what
1053 * client failed.
1055 DEBUG(0, ("write_data failed for client %s. "
1056 "Error %s\n",
1057 smbXsrv_connection_dbg(xconn),
1058 strerror(saved_errno)));
1059 SAFE_FREE(buf);
1060 errno = saved_errno;
1061 return -1;
1063 tosend -= cur_read;
1064 startpos += cur_read;
1067 SAFE_FREE(buf);
1068 return (ssize_t)nread;
1071 /****************************************************************************
1072 Deal with the case of sendfile reading less bytes from the file than
1073 requested. Fill with zeros (all we can do). Returns 0 on success
1074 ****************************************************************************/
1076 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
1077 files_struct *fsp,
1078 ssize_t nread,
1079 size_t headersize,
1080 size_t smb_maxcnt)
1082 #define SHORT_SEND_BUFSIZE 1024
1083 if (nread < headersize) {
1084 DEBUG(0,("sendfile_short_send: sendfile failed to send "
1085 "header for file %s (%s). Terminating\n",
1086 fsp_str_dbg(fsp), strerror(errno)));
1087 return -1;
1090 nread -= headersize;
1092 if (nread < smb_maxcnt) {
1093 char buf[SHORT_SEND_BUFSIZE] = { 0 };
1095 DEBUG(0,("sendfile_short_send: filling truncated file %s "
1096 "with zeros !\n", fsp_str_dbg(fsp)));
1098 while (nread < smb_maxcnt) {
1100 * We asked for the real file size and told sendfile
1101 * to not go beyond the end of the file. But it can
1102 * happen that in between our fstat call and the
1103 * sendfile call the file was truncated. This is very
1104 * bad because we have already announced the larger
1105 * number of bytes to the client.
1107 * The best we can do now is to send 0-bytes, just as
1108 * a read from a hole in a sparse file would do.
1110 * This should happen rarely enough that I don't care
1111 * about efficiency here :-)
1113 size_t to_write;
1114 ssize_t ret;
1116 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
1117 ret = write_data(xconn->transport.sock, buf, to_write);
1118 if (ret != to_write) {
1119 int saved_errno = errno;
1121 * Try and give an error message saying what
1122 * client failed.
1124 DEBUG(0, ("write_data failed for client %s. "
1125 "Error %s\n",
1126 smbXsrv_connection_dbg(xconn),
1127 strerror(saved_errno)));
1128 errno = saved_errno;
1129 return -1;
1131 nread += to_write;
1135 return 0;
1138 /*******************************************************************
1139 Check if a user is allowed to rename a file.
1140 ********************************************************************/
1142 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
1143 uint16_t dirtype)
1145 NTSTATUS status;
1147 if (fsp->fsp_name->twrp != 0) {
1148 /* Get the error right, this is what Windows returns. */
1149 return NT_STATUS_NOT_SAME_DEVICE;
1152 if (!CAN_WRITE(conn)) {
1153 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1156 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
1157 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1158 /* Only bother to read the DOS attribute if we might deny the
1159 rename on the grounds of attribute mismatch. */
1160 uint32_t fmode = fdos_mode(fsp);
1161 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1162 return NT_STATUS_NO_SUCH_FILE;
1166 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1167 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
1168 return NT_STATUS_OK;
1171 /* If no pathnames are open below this
1172 directory, allow the rename. */
1174 if (lp_strict_rename(SNUM(conn))) {
1176 * Strict rename, check open file db.
1178 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
1179 return NT_STATUS_ACCESS_DENIED;
1181 } else if (file_find_subpath(fsp)) {
1183 * No strict rename, just look in local process.
1185 return NT_STATUS_ACCESS_DENIED;
1187 return NT_STATUS_OK;
1190 status = check_any_access_fsp(fsp, DELETE_ACCESS | FILE_WRITE_ATTRIBUTES);
1191 if (!NT_STATUS_IS_OK(status)) {
1192 return status;
1194 return NT_STATUS_OK;
1197 /****************************************************************************
1198 Ensure open files have their names updated. Updated to notify other smbd's
1199 asynchronously.
1200 ****************************************************************************/
1202 static void rename_open_files(connection_struct *conn,
1203 struct share_mode_lock *lck,
1204 struct file_id id,
1205 uint32_t orig_name_hash,
1206 const struct smb_filename *smb_fname_dst)
1208 files_struct *fsp;
1209 bool did_rename = False;
1210 NTSTATUS status;
1211 uint32_t new_name_hash = 0;
1213 for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
1214 fsp = file_find_di_next(fsp, false)) {
1215 SMB_STRUCT_STAT fsp_orig_sbuf;
1216 struct file_id_buf idbuf;
1217 /* fsp_name is a relative path under the fsp. To change this for other
1218 sharepaths we need to manipulate relative paths. */
1219 /* TODO - create the absolute path and manipulate the newname
1220 relative to the sharepath. */
1221 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
1222 continue;
1224 if (fsp->name_hash != orig_name_hash) {
1225 continue;
1227 DBG_DEBUG("renaming file %s "
1228 "(file_id %s) from %s -> %s\n",
1229 fsp_fnum_dbg(fsp),
1230 file_id_str_buf(fsp->file_id, &idbuf),
1231 fsp_str_dbg(fsp),
1232 smb_fname_str_dbg(smb_fname_dst));
1235 * The incoming smb_fname_dst here has an
1236 * invalid stat struct (it must not have
1237 * existed for the rename to succeed).
1238 * Preserve the existing stat from the
1239 * open fsp after fsp_set_smb_fname()
1240 * overwrites with the invalid stat.
1242 * We will do an fstat before returning
1243 * any of this metadata to the client anyway.
1245 fsp_orig_sbuf = fsp->fsp_name->st;
1246 status = fsp_set_smb_fname(fsp, smb_fname_dst);
1247 if (NT_STATUS_IS_OK(status)) {
1248 did_rename = True;
1249 new_name_hash = fsp->name_hash;
1250 /* Restore existing stat. */
1251 fsp->fsp_name->st = fsp_orig_sbuf;
1255 if (!did_rename) {
1256 struct file_id_buf idbuf;
1257 DBG_DEBUG("no open files on file_id %s "
1258 "for %s\n",
1259 file_id_str_buf(id, &idbuf),
1260 smb_fname_str_dbg(smb_fname_dst));
1263 /* Send messages to all smbd's (not ourself) that the name has changed. */
1264 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
1265 orig_name_hash, new_name_hash,
1266 smb_fname_dst);
1270 /****************************************************************************
1271 We need to check if the source path is a parent directory of the destination
1272 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
1273 refuse the rename with a sharing violation. Under UNIX the above call can
1274 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
1275 probably need to check that the client is a Windows one before disallowing
1276 this as a UNIX client (one with UNIX extensions) can know the source is a
1277 symlink and make this decision intelligently. Found by an excellent bug
1278 report from <AndyLiebman@aol.com>.
1279 ****************************************************************************/
1281 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
1282 const struct smb_filename *smb_fname_dst)
1284 const char *psrc = smb_fname_src->base_name;
1285 const char *pdst = smb_fname_dst->base_name;
1286 size_t slen;
1288 if (psrc[0] == '.' && psrc[1] == '/') {
1289 psrc += 2;
1291 if (pdst[0] == '.' && pdst[1] == '/') {
1292 pdst += 2;
1294 if ((slen = strlen(psrc)) > strlen(pdst)) {
1295 return False;
1297 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
1301 * Do the notify calls from a rename
1304 static void notify_rename(connection_struct *conn, bool is_dir,
1305 const struct smb_filename *smb_fname_src,
1306 const struct smb_filename *smb_fname_dst)
1308 char *parent_dir_src = NULL;
1309 char *parent_dir_dst = NULL;
1310 uint32_t mask;
1312 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
1313 : FILE_NOTIFY_CHANGE_FILE_NAME;
1315 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
1316 &parent_dir_src, NULL) ||
1317 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
1318 &parent_dir_dst, NULL)) {
1319 goto out;
1322 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
1323 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
1324 smb_fname_src->base_name);
1325 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
1326 smb_fname_dst->base_name);
1328 else {
1329 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
1330 smb_fname_src->base_name);
1331 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
1332 smb_fname_dst->base_name);
1335 /* this is a strange one. w2k3 gives an additional event for
1336 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
1337 files, but not directories */
1338 if (!is_dir) {
1339 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1340 FILE_NOTIFY_CHANGE_ATTRIBUTES
1341 |FILE_NOTIFY_CHANGE_CREATION,
1342 smb_fname_dst->base_name);
1344 out:
1345 TALLOC_FREE(parent_dir_src);
1346 TALLOC_FREE(parent_dir_dst);
1349 /****************************************************************************
1350 Returns an error if the parent directory for a filename is open in an
1351 incompatible way.
1352 ****************************************************************************/
1354 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
1355 const struct smb_filename *smb_fname_dst_in)
1357 struct smb_filename *smb_fname_parent = NULL;
1358 struct file_id id;
1359 files_struct *fsp = NULL;
1360 int ret;
1361 NTSTATUS status;
1363 status = SMB_VFS_PARENT_PATHNAME(conn,
1364 talloc_tos(),
1365 smb_fname_dst_in,
1366 &smb_fname_parent,
1367 NULL);
1368 if (!NT_STATUS_IS_OK(status)) {
1369 return status;
1372 ret = vfs_stat(conn, smb_fname_parent);
1373 if (ret == -1) {
1374 return map_nt_error_from_unix(errno);
1378 * We're only checking on this smbd here, mostly good
1379 * enough.. and will pass tests.
1382 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
1383 for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
1384 fsp = file_find_di_next(fsp, true)) {
1385 if (fsp->access_mask & DELETE_ACCESS) {
1386 return NT_STATUS_SHARING_VIOLATION;
1389 return NT_STATUS_OK;
1392 /****************************************************************************
1393 Rename an open file - given an fsp.
1394 ****************************************************************************/
1396 NTSTATUS rename_internals_fsp(connection_struct *conn,
1397 files_struct *fsp,
1398 struct smb_filename *smb_fname_dst_in,
1399 const char *dst_original_lcomp,
1400 uint32_t attrs,
1401 bool replace_if_exists)
1403 TALLOC_CTX *ctx = talloc_tos();
1404 struct smb_filename *parent_dir_fname_dst = NULL;
1405 struct smb_filename *parent_dir_fname_dst_atname = NULL;
1406 struct smb_filename *parent_dir_fname_src = NULL;
1407 struct smb_filename *parent_dir_fname_src_atname = NULL;
1408 struct smb_filename *smb_fname_dst = NULL;
1409 NTSTATUS status = NT_STATUS_OK;
1410 struct share_mode_lock *lck = NULL;
1411 uint32_t access_mask = SEC_DIR_ADD_FILE;
1412 bool dst_exists, old_is_stream, new_is_stream;
1413 int ret;
1414 bool case_sensitive = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1415 true : conn->case_sensitive;
1416 bool case_preserve = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1417 true : conn->case_preserve;
1419 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 return status;
1424 if (file_has_open_streams(fsp)) {
1425 return NT_STATUS_ACCESS_DENIED;
1428 /* Make a copy of the dst smb_fname structs */
1430 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
1431 if (smb_fname_dst == NULL) {
1432 status = NT_STATUS_NO_MEMORY;
1433 goto out;
1437 * Check for special case with case preserving and not
1438 * case sensitive. If the new last component differs from the original
1439 * last component only by case, then we should allow
1440 * the rename (user is trying to change the case of the
1441 * filename).
1443 if (!case_sensitive && case_preserve &&
1444 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1445 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
1446 char *fname_dst_parent = NULL;
1447 const char *fname_dst_lcomp = NULL;
1448 char *orig_lcomp_path = NULL;
1449 char *orig_lcomp_stream = NULL;
1450 bool ok = true;
1453 * Split off the last component of the processed
1454 * destination name. We will compare this to
1455 * the split components of dst_original_lcomp.
1457 if (!parent_dirname(ctx,
1458 smb_fname_dst->base_name,
1459 &fname_dst_parent,
1460 &fname_dst_lcomp)) {
1461 status = NT_STATUS_NO_MEMORY;
1462 goto out;
1466 * The dst_original_lcomp component contains
1467 * the last_component of the path + stream
1468 * name (if a stream exists).
1470 * Split off the stream name so we
1471 * can check them separately.
1474 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
1475 /* POSIX - no stream component. */
1476 orig_lcomp_path = talloc_strdup(ctx,
1477 dst_original_lcomp);
1478 if (orig_lcomp_path == NULL) {
1479 ok = false;
1481 } else {
1482 ok = split_stream_filename(ctx,
1483 dst_original_lcomp,
1484 &orig_lcomp_path,
1485 &orig_lcomp_stream);
1488 if (!ok) {
1489 TALLOC_FREE(fname_dst_parent);
1490 status = NT_STATUS_NO_MEMORY;
1491 goto out;
1494 /* If the base names only differ by case, use original. */
1495 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
1496 char *tmp;
1498 * Replace the modified last component with the
1499 * original.
1501 if (!ISDOT(fname_dst_parent)) {
1502 tmp = talloc_asprintf(smb_fname_dst,
1503 "%s/%s",
1504 fname_dst_parent,
1505 orig_lcomp_path);
1506 } else {
1507 tmp = talloc_strdup(smb_fname_dst,
1508 orig_lcomp_path);
1510 if (tmp == NULL) {
1511 status = NT_STATUS_NO_MEMORY;
1512 TALLOC_FREE(fname_dst_parent);
1513 TALLOC_FREE(orig_lcomp_path);
1514 TALLOC_FREE(orig_lcomp_stream);
1515 goto out;
1517 TALLOC_FREE(smb_fname_dst->base_name);
1518 smb_fname_dst->base_name = tmp;
1521 /* If the stream_names only differ by case, use original. */
1522 if(!strcsequal(smb_fname_dst->stream_name,
1523 orig_lcomp_stream)) {
1524 /* Use the original stream. */
1525 char *tmp = talloc_strdup(smb_fname_dst,
1526 orig_lcomp_stream);
1527 if (tmp == NULL) {
1528 status = NT_STATUS_NO_MEMORY;
1529 TALLOC_FREE(fname_dst_parent);
1530 TALLOC_FREE(orig_lcomp_path);
1531 TALLOC_FREE(orig_lcomp_stream);
1532 goto out;
1534 TALLOC_FREE(smb_fname_dst->stream_name);
1535 smb_fname_dst->stream_name = tmp;
1537 TALLOC_FREE(fname_dst_parent);
1538 TALLOC_FREE(orig_lcomp_path);
1539 TALLOC_FREE(orig_lcomp_stream);
1543 * If the src and dest names are identical - including case,
1544 * don't do the rename, just return success.
1547 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1548 strcsequal(fsp->fsp_name->stream_name,
1549 smb_fname_dst->stream_name)) {
1550 DBG_NOTICE("identical names in rename %s "
1551 "- returning success\n",
1552 smb_fname_str_dbg(smb_fname_dst));
1553 status = NT_STATUS_OK;
1554 goto out;
1557 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
1558 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
1560 /* Return the correct error code if both names aren't streams. */
1561 if (!old_is_stream && new_is_stream) {
1562 status = NT_STATUS_OBJECT_NAME_INVALID;
1563 goto out;
1566 if (old_is_stream && !new_is_stream) {
1567 status = NT_STATUS_INVALID_PARAMETER;
1568 goto out;
1571 dst_exists = vfs_stat(conn, smb_fname_dst) == 0;
1573 if(!replace_if_exists && dst_exists) {
1574 DBG_NOTICE("dest exists doing rename "
1575 "%s -> %s\n",
1576 smb_fname_str_dbg(fsp->fsp_name),
1577 smb_fname_str_dbg(smb_fname_dst));
1578 status = NT_STATUS_OBJECT_NAME_COLLISION;
1579 goto out;
1583 * Drop the pathref fsp on the destination otherwise we trip upon in in
1584 * the below check for open files check.
1586 if (smb_fname_dst_in->fsp != NULL) {
1587 fd_close(smb_fname_dst_in->fsp);
1588 file_free(NULL, smb_fname_dst_in->fsp);
1589 SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
1592 if (dst_exists) {
1593 struct file_id fileid = vfs_file_id_from_sbuf(conn,
1594 &smb_fname_dst->st);
1595 files_struct *dst_fsp = file_find_di_first(conn->sconn,
1596 fileid, true);
1597 /* The file can be open when renaming a stream */
1598 if (dst_fsp && !new_is_stream) {
1599 DBG_NOTICE("Target file open\n");
1600 status = NT_STATUS_ACCESS_DENIED;
1601 goto out;
1605 /* Ensure we have a valid stat struct for the source. */
1606 status = vfs_stat_fsp(fsp);
1607 if (!NT_STATUS_IS_OK(status)) {
1608 goto out;
1611 status = can_rename(conn, fsp, attrs);
1613 if (!NT_STATUS_IS_OK(status)) {
1614 DBG_NOTICE("Error %s rename %s -> %s\n",
1615 nt_errstr(status),
1616 smb_fname_str_dbg(fsp->fsp_name),
1617 smb_fname_str_dbg(smb_fname_dst));
1618 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
1619 status = NT_STATUS_ACCESS_DENIED;
1620 goto out;
1623 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
1624 status = NT_STATUS_ACCESS_DENIED;
1625 goto out;
1628 /* Do we have rights to move into the destination ? */
1629 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1630 /* We're moving a directory. */
1631 access_mask = SEC_DIR_ADD_SUBDIR;
1635 * Get a pathref on the destination parent directory, so
1636 * we can call check_parent_access_fsp().
1638 status = parent_pathref(ctx,
1639 conn->cwd_fsp,
1640 smb_fname_dst,
1641 &parent_dir_fname_dst,
1642 &parent_dir_fname_dst_atname);
1643 if (!NT_STATUS_IS_OK(status)) {
1644 goto out;
1647 status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
1648 access_mask);
1649 if (!NT_STATUS_IS_OK(status)) {
1650 DBG_INFO("check_parent_access_fsp on "
1651 "dst %s returned %s\n",
1652 smb_fname_str_dbg(smb_fname_dst),
1653 nt_errstr(status));
1654 goto out;
1658 * If the target existed, make sure the destination
1659 * atname has the same stat struct.
1661 parent_dir_fname_dst_atname->st = smb_fname_dst->st;
1664 * It's very common that source and
1665 * destination directories are the same.
1666 * Optimize by not opening the
1667 * second parent_pathref if we know
1668 * this is the case.
1671 status = SMB_VFS_PARENT_PATHNAME(conn,
1672 ctx,
1673 fsp->fsp_name,
1674 &parent_dir_fname_src,
1675 &parent_dir_fname_src_atname);
1676 if (!NT_STATUS_IS_OK(status)) {
1677 goto out;
1681 * We do a case-sensitive string comparison. We want to be *sure*
1682 * this is the same path. The worst that can happen if
1683 * the case doesn't match is we lose out on the optimization,
1684 * the code still works.
1686 * We can ignore twrp fields here. Rename is not allowed on
1687 * shadow copy handles.
1690 if (strcmp(parent_dir_fname_src->base_name,
1691 parent_dir_fname_dst->base_name) == 0) {
1693 * parent directory is the same for source
1694 * and destination.
1696 /* Reparent the src_atname to the parent_dir_dest fname. */
1697 parent_dir_fname_src_atname = talloc_move(
1698 parent_dir_fname_dst,
1699 &parent_dir_fname_src_atname);
1700 /* Free the unneeded duplicate parent name. */
1701 TALLOC_FREE(parent_dir_fname_src);
1703 * And make the source parent name a copy of the
1704 * destination parent name.
1706 parent_dir_fname_src = parent_dir_fname_dst;
1709 * Ensure we have a pathref fsp on the
1710 * parent_dir_fname_src_atname to match the code in the else
1711 * branch where we use parent_pathref().
1713 status = reference_smb_fname_fsp_link(
1714 parent_dir_fname_src_atname,
1715 fsp->fsp_name);
1716 if (!NT_STATUS_IS_OK(status)) {
1717 goto out;
1719 } else {
1721 * source and destination parent directories are
1722 * different.
1724 * Get a pathref on the source parent directory, so
1725 * we can do a relative rename.
1727 TALLOC_FREE(parent_dir_fname_src);
1728 status = parent_pathref(ctx,
1729 conn->cwd_fsp,
1730 fsp->fsp_name,
1731 &parent_dir_fname_src,
1732 &parent_dir_fname_src_atname);
1733 if (!NT_STATUS_IS_OK(status)) {
1734 goto out;
1739 * Some modules depend on the source smb_fname having a valid stat.
1740 * The parent_dir_fname_src_atname is the relative name of the
1741 * currently open file, so just copy the stat from the open fsp.
1743 parent_dir_fname_src_atname->st = fsp->fsp_name->st;
1745 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1748 * We have the file open ourselves, so not being able to get the
1749 * corresponding share mode lock is a fatal error.
1752 SMB_ASSERT(lck != NULL);
1754 ret = SMB_VFS_RENAMEAT(conn,
1755 parent_dir_fname_src->fsp,
1756 parent_dir_fname_src_atname,
1757 parent_dir_fname_dst->fsp,
1758 parent_dir_fname_dst_atname);
1759 if (ret == 0) {
1760 uint32_t create_options = fh_get_private_options(fsp->fh);
1762 DBG_NOTICE("succeeded doing rename on "
1763 "%s -> %s\n",
1764 smb_fname_str_dbg(fsp->fsp_name),
1765 smb_fname_str_dbg(smb_fname_dst));
1767 notify_rename(conn,
1768 fsp->fsp_flags.is_directory,
1769 fsp->fsp_name,
1770 smb_fname_dst);
1772 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
1773 smb_fname_dst);
1775 if (!fsp->fsp_flags.is_directory &&
1776 (lp_map_archive(SNUM(conn)) ||
1777 lp_store_dos_attributes(SNUM(conn))))
1780 * We must set the archive bit on the newly renamed
1781 * file.
1783 status = vfs_stat_fsp(fsp);
1784 if (NT_STATUS_IS_OK(status)) {
1785 uint32_t old_dosmode;
1786 old_dosmode = fdos_mode(fsp);
1788 * We can use fsp->fsp_name here as it has
1789 * already been changed to the new name.
1791 SMB_ASSERT(fsp->fsp_name->fsp == fsp);
1792 file_set_dosmode(conn,
1793 fsp->fsp_name,
1794 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
1795 NULL,
1796 true);
1801 * A rename acts as a new file create w.r.t. allowing an initial delete
1802 * on close, probably because in Windows there is a new handle to the
1803 * new file. If initial delete on close was requested but not
1804 * originally set, we need to set it here. This is probably not 100% correct,
1805 * but will work for the CIFSFS client which in non-posix mode
1806 * depends on these semantics. JRA.
1809 if (create_options & FILE_DELETE_ON_CLOSE) {
1810 status = can_set_delete_on_close(fsp, 0);
1812 if (NT_STATUS_IS_OK(status)) {
1813 /* Note that here we set the *initial* delete on close flag,
1814 * not the regular one. The magic gets handled in close. */
1815 fsp->fsp_flags.initial_delete_on_close = true;
1818 TALLOC_FREE(lck);
1819 status = NT_STATUS_OK;
1820 goto out;
1823 TALLOC_FREE(lck);
1825 if (errno == ENOTDIR || errno == EISDIR) {
1826 status = NT_STATUS_OBJECT_NAME_COLLISION;
1827 } else {
1828 status = map_nt_error_from_unix(errno);
1831 DBG_NOTICE("Error %s rename %s -> %s\n",
1832 nt_errstr(status),
1833 smb_fname_str_dbg(fsp->fsp_name),
1834 smb_fname_str_dbg(smb_fname_dst));
1836 out:
1839 * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
1840 * See the optimization for same source and destination directory
1841 * above. Only free one in that case.
1843 if (parent_dir_fname_src != parent_dir_fname_dst) {
1844 TALLOC_FREE(parent_dir_fname_src);
1846 TALLOC_FREE(parent_dir_fname_dst);
1847 TALLOC_FREE(smb_fname_dst);
1849 return status;
1852 /****************************************************************************
1853 The guts of the rename command, split out so it may be called by the NT SMB
1854 code.
1855 ****************************************************************************/
1857 NTSTATUS rename_internals(TALLOC_CTX *ctx,
1858 connection_struct *conn,
1859 struct smb_request *req,
1860 struct files_struct *src_dirfsp,
1861 struct smb_filename *smb_fname_src,
1862 struct smb_filename *smb_fname_dst,
1863 const char *dst_original_lcomp,
1864 uint32_t attrs,
1865 bool replace_if_exists,
1866 uint32_t access_mask)
1868 NTSTATUS status = NT_STATUS_OK;
1869 int create_options = FILE_OPEN_REPARSE_POINT;
1870 struct smb2_create_blobs *posx = NULL;
1871 struct files_struct *fsp = NULL;
1872 bool posix_pathname = (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH);
1873 bool case_sensitive = posix_pathname ? true : conn->case_sensitive;
1874 bool case_preserve = posix_pathname ? true : conn->case_preserve;
1875 bool short_case_preserve = posix_pathname ? true :
1876 conn->short_case_preserve;
1878 if (posix_pathname) {
1879 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
1880 if (!NT_STATUS_IS_OK(status)) {
1881 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
1882 nt_errstr(status));
1883 goto out;
1887 DBG_NOTICE("case_sensitive = %d, "
1888 "case_preserve = %d, short case preserve = %d, "
1889 "directory = %s, newname = %s, "
1890 "last_component_dest = %s\n",
1891 case_sensitive, case_preserve,
1892 short_case_preserve,
1893 smb_fname_str_dbg(smb_fname_src),
1894 smb_fname_str_dbg(smb_fname_dst),
1895 dst_original_lcomp);
1897 ZERO_STRUCT(smb_fname_src->st);
1899 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1900 if (!NT_STATUS_IS_OK(status)) {
1901 if (!NT_STATUS_EQUAL(status,
1902 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1903 goto out;
1906 * Possible symlink src.
1908 if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
1909 goto out;
1911 if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
1912 goto out;
1916 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
1917 create_options |= FILE_DIRECTORY_FILE;
1920 status = SMB_VFS_CREATE_FILE(
1921 conn, /* conn */
1922 req, /* req */
1923 src_dirfsp, /* dirfsp */
1924 smb_fname_src, /* fname */
1925 access_mask, /* access_mask */
1926 (FILE_SHARE_READ | /* share_access */
1927 FILE_SHARE_WRITE),
1928 FILE_OPEN, /* create_disposition*/
1929 create_options, /* create_options */
1930 0, /* file_attributes */
1931 0, /* oplock_request */
1932 NULL, /* lease */
1933 0, /* allocation_size */
1934 0, /* private_flags */
1935 NULL, /* sd */
1936 NULL, /* ea_list */
1937 &fsp, /* result */
1938 NULL, /* pinfo */
1939 posx, /* in_context_blobs */
1940 NULL); /* out_context_blobs */
1942 if (!NT_STATUS_IS_OK(status)) {
1943 DBG_NOTICE("Could not open rename source %s: %s\n",
1944 smb_fname_str_dbg(smb_fname_src),
1945 nt_errstr(status));
1946 goto out;
1949 status = rename_internals_fsp(conn,
1950 fsp,
1951 smb_fname_dst,
1952 dst_original_lcomp,
1953 attrs,
1954 replace_if_exists);
1956 close_file_free(req, &fsp, NORMAL_CLOSE);
1958 DBG_NOTICE("Error %s rename %s -> %s\n",
1959 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
1960 smb_fname_str_dbg(smb_fname_dst));
1962 out:
1963 TALLOC_FREE(posx);
1964 return status;
1967 /*******************************************************************
1968 Copy a file as part of a reply_copy.
1969 ******************************************************************/
1972 * TODO: check error codes on all callers
1975 NTSTATUS copy_file(TALLOC_CTX *ctx,
1976 connection_struct *conn,
1977 struct smb_filename *smb_fname_src,
1978 struct smb_filename *smb_fname_dst,
1979 uint32_t new_create_disposition)
1981 struct smb_filename *smb_fname_dst_tmp = NULL;
1982 off_t ret=-1;
1983 files_struct *fsp1,*fsp2;
1984 uint32_t dosattrs;
1985 NTSTATUS status;
1988 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
1989 if (smb_fname_dst_tmp == NULL) {
1990 return NT_STATUS_NO_MEMORY;
1993 status = vfs_file_exist(conn, smb_fname_src);
1994 if (!NT_STATUS_IS_OK(status)) {
1995 goto out;
1998 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1999 if (!NT_STATUS_IS_OK(status)) {
2000 goto out;
2003 /* Open the src file for reading. */
2004 status = SMB_VFS_CREATE_FILE(
2005 conn, /* conn */
2006 NULL, /* req */
2007 NULL, /* dirfsp */
2008 smb_fname_src, /* fname */
2009 FILE_GENERIC_READ, /* access_mask */
2010 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2011 FILE_OPEN, /* create_disposition*/
2012 0, /* create_options */
2013 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2014 INTERNAL_OPEN_ONLY, /* oplock_request */
2015 NULL, /* lease */
2016 0, /* allocation_size */
2017 0, /* private_flags */
2018 NULL, /* sd */
2019 NULL, /* ea_list */
2020 &fsp1, /* result */
2021 NULL, /* psbuf */
2022 NULL, NULL); /* create context */
2024 if (!NT_STATUS_IS_OK(status)) {
2025 goto out;
2028 dosattrs = fdos_mode(fsp1);
2030 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
2031 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
2034 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
2035 if (!NT_STATUS_IS_OK(status) &&
2036 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
2038 goto out;
2041 /* Open the dst file for writing. */
2042 status = SMB_VFS_CREATE_FILE(
2043 conn, /* conn */
2044 NULL, /* req */
2045 NULL, /* dirfsp */
2046 smb_fname_dst, /* fname */
2047 FILE_GENERIC_WRITE, /* access_mask */
2048 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2049 new_create_disposition, /* create_disposition*/
2050 0, /* create_options */
2051 dosattrs, /* file_attributes */
2052 INTERNAL_OPEN_ONLY, /* oplock_request */
2053 NULL, /* lease */
2054 0, /* allocation_size */
2055 0, /* private_flags */
2056 NULL, /* sd */
2057 NULL, /* ea_list */
2058 &fsp2, /* result */
2059 NULL, /* psbuf */
2060 NULL, NULL); /* create context */
2062 if (!NT_STATUS_IS_OK(status)) {
2063 close_file_free(NULL, &fsp1, ERROR_CLOSE);
2064 goto out;
2067 /* Do the actual copy. */
2068 if (smb_fname_src->st.st_ex_size) {
2069 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
2070 } else {
2071 ret = 0;
2074 close_file_free(NULL, &fsp1, NORMAL_CLOSE);
2076 /* Ensure the modtime is set correctly on the destination file. */
2077 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
2080 * As we are opening fsp1 read-only we only expect
2081 * an error on close on fsp2 if we are out of space.
2082 * Thus we don't look at the error return from the
2083 * close of fsp1.
2085 status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
2087 if (!NT_STATUS_IS_OK(status)) {
2088 goto out;
2091 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
2092 status = NT_STATUS_DISK_FULL;
2093 goto out;
2096 status = NT_STATUS_OK;
2098 out:
2099 TALLOC_FREE(smb_fname_dst_tmp);
2100 return status;
2103 /****************************************************************************
2104 Get a lock offset, dealing with large offset requests.
2105 ****************************************************************************/
2107 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
2108 bool large_file_format)
2110 uint64_t offset = 0;
2112 if(!large_file_format) {
2113 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
2114 } else {
2116 * No BVAL, this is reversed!
2118 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
2119 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
2122 return offset;
2125 struct smbd_do_unlocking_state {
2126 struct files_struct *fsp;
2127 uint16_t num_ulocks;
2128 struct smbd_lock_element *ulocks;
2129 NTSTATUS status;
2132 static void smbd_do_unlocking_fn(
2133 struct share_mode_lock *lck,
2134 void *private_data)
2136 struct smbd_do_unlocking_state *state = private_data;
2137 struct files_struct *fsp = state->fsp;
2138 uint16_t i;
2140 for (i = 0; i < state->num_ulocks; i++) {
2141 struct smbd_lock_element *e = &state->ulocks[i];
2143 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
2144 "pid %"PRIu64", file %s\n",
2145 e->offset,
2146 e->count,
2147 e->smblctx,
2148 fsp_str_dbg(fsp));
2150 if (e->brltype != UNLOCK_LOCK) {
2151 /* this can only happen with SMB2 */
2152 state->status = NT_STATUS_INVALID_PARAMETER;
2153 return;
2156 state->status = do_unlock(
2157 fsp, e->smblctx, e->count, e->offset, e->lock_flav);
2159 DBG_DEBUG("do_unlock returned %s\n",
2160 nt_errstr(state->status));
2162 if (!NT_STATUS_IS_OK(state->status)) {
2163 return;
2167 share_mode_wakeup_waiters(fsp->file_id);
2170 NTSTATUS smbd_do_unlocking(struct smb_request *req,
2171 files_struct *fsp,
2172 uint16_t num_ulocks,
2173 struct smbd_lock_element *ulocks)
2175 struct smbd_do_unlocking_state state = {
2176 .fsp = fsp,
2177 .num_ulocks = num_ulocks,
2178 .ulocks = ulocks,
2180 NTSTATUS status;
2182 DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
2184 status = share_mode_do_locked_vfs_allowed(
2185 fsp->file_id, smbd_do_unlocking_fn, &state);
2187 if (!NT_STATUS_IS_OK(status)) {
2188 DBG_DEBUG("share_mode_do_locked_vfs_allowed failed: %s\n",
2189 nt_errstr(status));
2190 return status;
2192 if (!NT_STATUS_IS_OK(state.status)) {
2193 DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
2194 nt_errstr(status));
2195 return state.status;
2198 return NT_STATUS_OK;