smbd: use fdos_mode() in do_unlink()
[Samba.git] / source3 / smbd / reply.c
blob00ac4de617a0795d0ad36707339626cd08e366e4
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 "fake_file.h"
35 #include "rpc_client/rpc_client.h"
36 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
37 #include "rpc_client/cli_spoolss.h"
38 #include "rpc_client/init_spoolss.h"
39 #include "rpc_server/rpc_ncacn_np.h"
40 #include "libcli/security/security.h"
41 #include "libsmb/nmblib.h"
42 #include "auth.h"
43 #include "smbprofile.h"
44 #include "../lib/tsocket/tsocket.h"
45 #include "lib/util/tevent_ntstatus.h"
46 #include "libcli/smb/smb_signing.h"
47 #include "lib/util/sys_rw_data.h"
48 #include "librpc/gen_ndr/open_files.h"
49 #include "smb1_utils.h"
50 #include "libcli/smb/smb2_posix.h"
51 #include "lib/util/string_wrappers.h"
53 /****************************************************************************
54 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
55 path or anything including wildcards.
56 We're assuming here that '/' is not the second byte in any multibyte char
57 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
58 set.
59 ****************************************************************************/
61 /* Custom version for processing POSIX paths. */
62 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
64 static NTSTATUS check_path_syntax_internal(char *path,
65 bool posix_path)
67 char *d = path;
68 const char *s = path;
69 NTSTATUS ret = NT_STATUS_OK;
70 bool start_of_name_component = True;
71 bool stream_started = false;
72 bool last_component_contains_wcard = false;
74 while (*s) {
75 if (stream_started) {
76 switch (*s) {
77 case '/':
78 case '\\':
79 return NT_STATUS_OBJECT_NAME_INVALID;
80 case ':':
81 if (s[1] == '\0') {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 if (strchr_m(&s[1], ':')) {
85 return NT_STATUS_OBJECT_NAME_INVALID;
87 break;
91 if ((*s == ':') && !posix_path && !stream_started) {
92 if (last_component_contains_wcard) {
93 return NT_STATUS_OBJECT_NAME_INVALID;
95 /* Stream names allow more characters than file names.
96 We're overloading posix_path here to allow a wider
97 range of characters. If stream_started is true this
98 is still a Windows path even if posix_path is true.
99 JRA.
101 stream_started = true;
102 start_of_name_component = false;
103 posix_path = true;
105 if (s[1] == '\0') {
106 return NT_STATUS_OBJECT_NAME_INVALID;
110 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
112 * Safe to assume is not the second part of a mb char
113 * as this is handled below.
115 /* Eat multiple '/' or '\\' */
116 while (IS_PATH_SEP(*s,posix_path)) {
117 s++;
119 if ((d != path) && (*s != '\0')) {
120 /* We only care about non-leading or trailing '/' or '\\' */
121 *d++ = '/';
124 start_of_name_component = True;
125 /* New component. */
126 last_component_contains_wcard = false;
127 continue;
130 if (start_of_name_component) {
131 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
132 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
135 * No mb char starts with '.' so we're safe checking the directory separator here.
138 /* If we just added a '/' - delete it */
139 if ((d > path) && (*(d-1) == '/')) {
140 *(d-1) = '\0';
141 d--;
144 /* Are we at the start ? Can't go back further if so. */
145 if (d <= path) {
146 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
147 break;
149 /* Go back one level... */
150 /* We know this is safe as '/' cannot be part of a mb sequence. */
151 /* NOTE - if this assumption is invalid we are not in good shape... */
152 /* Decrement d first as d points to the *next* char to write into. */
153 for (d--; d > path; d--) {
154 if (*d == '/')
155 break;
157 s += 2; /* Else go past the .. */
158 /* We're still at the start of a name component, just the previous one. */
159 continue;
161 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
162 if (posix_path) {
163 /* Eat the '.' */
164 s++;
165 continue;
171 if (!(*s & 0x80)) {
172 if (!posix_path) {
173 if (*s <= 0x1f || *s == '|') {
174 return NT_STATUS_OBJECT_NAME_INVALID;
176 switch (*s) {
177 case '*':
178 case '?':
179 case '<':
180 case '>':
181 case '"':
182 last_component_contains_wcard = true;
183 break;
184 default:
185 break;
188 *d++ = *s++;
189 } else {
190 size_t siz;
191 /* Get the size of the next MB character. */
192 next_codepoint(s,&siz);
193 switch(siz) {
194 case 5:
195 *d++ = *s++;
196 FALL_THROUGH;
197 case 4:
198 *d++ = *s++;
199 FALL_THROUGH;
200 case 3:
201 *d++ = *s++;
202 FALL_THROUGH;
203 case 2:
204 *d++ = *s++;
205 FALL_THROUGH;
206 case 1:
207 *d++ = *s++;
208 break;
209 default:
210 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
211 *d = '\0';
212 return NT_STATUS_INVALID_PARAMETER;
215 start_of_name_component = False;
218 *d = '\0';
220 return ret;
223 /****************************************************************************
224 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
225 No wildcards allowed.
226 ****************************************************************************/
228 NTSTATUS check_path_syntax(char *path)
230 return check_path_syntax_internal(path, false);
233 /****************************************************************************
234 Check the path for a POSIX client.
235 We're assuming here that '/' is not the second byte in any multibyte char
236 set (a safe assumption).
237 ****************************************************************************/
239 NTSTATUS check_path_syntax_posix(char *path)
241 return check_path_syntax_internal(path, true);
244 /****************************************************************************
245 Pull a string and check the path allowing a wildcard - provide for error return.
246 Passes in posix flag.
247 ****************************************************************************/
249 static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
250 const char *base_ptr,
251 uint16_t smb_flags2,
252 char **pp_dest,
253 const char *src,
254 size_t src_len,
255 int flags,
256 bool posix_pathnames,
257 NTSTATUS *err)
259 size_t ret;
261 *pp_dest = NULL;
263 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
264 src_len, flags);
266 if (!*pp_dest) {
267 *err = NT_STATUS_INVALID_PARAMETER;
268 return ret;
271 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
273 * For a DFS path the function parse_dfs_path()
274 * will do the path processing, just make a copy.
276 *err = NT_STATUS_OK;
277 return ret;
280 if (posix_pathnames) {
281 *err = check_path_syntax_posix(*pp_dest);
282 } else {
283 *err = check_path_syntax(*pp_dest);
286 return ret;
289 /****************************************************************************
290 Pull a string and check the path - provide for error return.
291 ****************************************************************************/
293 size_t srvstr_get_path(TALLOC_CTX *ctx,
294 const char *base_ptr,
295 uint16_t smb_flags2,
296 char **pp_dest,
297 const char *src,
298 size_t src_len,
299 int flags,
300 NTSTATUS *err)
302 return srvstr_get_path_internal(ctx,
303 base_ptr,
304 smb_flags2,
305 pp_dest,
306 src,
307 src_len,
308 flags,
309 false,
310 err);
313 /****************************************************************************
314 Pull a string and check the path - provide for error return.
315 posix_pathnames version.
316 ****************************************************************************/
318 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
319 const char *base_ptr,
320 uint16_t smb_flags2,
321 char **pp_dest,
322 const char *src,
323 size_t src_len,
324 int flags,
325 NTSTATUS *err)
327 return srvstr_get_path_internal(ctx,
328 base_ptr,
329 smb_flags2,
330 pp_dest,
331 src,
332 src_len,
333 flags,
334 true,
335 err);
339 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
340 char **pp_dest, const char *src, int flags,
341 NTSTATUS *err)
343 ssize_t bufrem = smbreq_bufrem(req, src);
345 if (bufrem < 0) {
346 *err = NT_STATUS_INVALID_PARAMETER;
347 return 0;
350 if (req->posix_pathnames) {
351 return srvstr_get_path_internal(mem_ctx,
352 (const char *)req->inbuf,
353 req->flags2,
354 pp_dest,
355 src,
356 bufrem,
357 flags,
358 true,
359 err);
360 } else {
361 return srvstr_get_path_internal(mem_ctx,
362 (const char *)req->inbuf,
363 req->flags2,
364 pp_dest,
365 src,
366 bufrem,
367 flags,
368 false,
369 err);
374 * pull a string from the smb_buf part of a packet. In this case the
375 * string can either be null terminated or it can be terminated by the
376 * end of the smbbuf area
378 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
379 char **dest, const uint8_t *src, int flags)
381 ssize_t bufrem = smbreq_bufrem(req, src);
383 if (bufrem < 0) {
384 return 0;
387 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
388 bufrem, flags);
391 /****************************************************************************
392 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
393 ****************************************************************************/
395 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
396 files_struct *fsp)
398 if ((fsp == NULL) || (conn == NULL)) {
399 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
400 return False;
402 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
403 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
404 return False;
406 return True;
409 /****************************************************************************
410 Check if we have a correct fsp pointing to a file.
411 ****************************************************************************/
413 bool check_fsp(connection_struct *conn, struct smb_request *req,
414 files_struct *fsp)
416 if (!check_fsp_open(conn, req, fsp)) {
417 return False;
419 if (fsp->fsp_flags.is_directory) {
420 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
421 return False;
423 if (fsp_get_pathref_fd(fsp) == -1) {
424 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
425 return False;
427 fsp->num_smb_operations++;
428 return True;
431 /****************************************************************************
432 Check if we have a correct fsp pointing to a quota fake file. Replacement for
433 the CHECK_NTQUOTA_HANDLE_OK macro.
434 ****************************************************************************/
436 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
437 files_struct *fsp)
439 if (!check_fsp_open(conn, req, fsp)) {
440 return false;
443 if (fsp->fsp_flags.is_directory) {
444 return false;
447 if (fsp->fake_file_handle == NULL) {
448 return false;
451 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
452 return false;
455 if (fsp->fake_file_handle->private_data == NULL) {
456 return false;
459 return true;
462 /****************************************************************************
463 Return the port number we've bound to on a socket.
464 ****************************************************************************/
466 static int get_socket_port(int fd)
468 struct samba_sockaddr saddr = {
469 .sa_socklen = sizeof(struct sockaddr_storage),
472 if (fd == -1) {
473 return -1;
476 if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
477 int level = (errno == ENOTCONN) ? 2 : 0;
478 DEBUG(level, ("getsockname failed. Error was %s\n",
479 strerror(errno)));
480 return -1;
483 #if defined(HAVE_IPV6)
484 if (saddr.u.sa.sa_family == AF_INET6) {
485 return ntohs(saddr.u.in6.sin6_port);
487 #endif
488 if (saddr.u.sa.sa_family == AF_INET) {
489 return ntohs(saddr.u.in.sin_port);
491 return -1;
494 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
495 const char *name, int name_type)
497 char *trim_name;
498 char *trim_name_type;
499 const char *retarget_parm;
500 char *retarget;
501 char *p;
502 int retarget_type = 0x20;
503 int retarget_port = NBT_SMB_PORT;
504 struct sockaddr_storage retarget_addr;
505 struct sockaddr_in *in_addr;
506 bool ret = false;
507 uint8_t outbuf[10];
509 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
510 return false;
513 trim_name = talloc_strdup(talloc_tos(), name);
514 if (trim_name == NULL) {
515 goto fail;
517 trim_char(trim_name, ' ', ' ');
519 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
520 name_type);
521 if (trim_name_type == NULL) {
522 goto fail;
525 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
526 trim_name_type, NULL);
527 if (retarget_parm == NULL) {
528 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
529 trim_name, NULL);
531 if (retarget_parm == NULL) {
532 goto fail;
535 retarget = talloc_strdup(trim_name, retarget_parm);
536 if (retarget == NULL) {
537 goto fail;
540 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
542 p = strchr(retarget, ':');
543 if (p != NULL) {
544 *p++ = '\0';
545 retarget_port = atoi(p);
548 p = strchr_m(retarget, '#');
549 if (p != NULL) {
550 *p++ = '\0';
551 if (sscanf(p, "%x", &retarget_type) != 1) {
552 goto fail;
556 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
557 if (!ret) {
558 DEBUG(10, ("could not resolve %s\n", retarget));
559 goto fail;
562 if (retarget_addr.ss_family != AF_INET) {
563 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
564 goto fail;
567 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
569 _smb_setlen(outbuf, 6);
570 SCVAL(outbuf, 0, 0x84);
571 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
572 *(uint16_t *)(outbuf+8) = htons(retarget_port);
574 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
575 NULL)) {
576 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
577 "failed.");
580 ret = true;
581 fail:
582 TALLOC_FREE(trim_name);
583 return ret;
586 static void reply_called_name_not_present(char *outbuf)
588 smb_setlen(outbuf, 1);
589 SCVAL(outbuf, 0, 0x83);
590 SCVAL(outbuf, 4, 0x82);
593 /****************************************************************************
594 Reply to a (netbios-level) special message.
595 ****************************************************************************/
597 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
599 struct smbd_server_connection *sconn = xconn->client->sconn;
600 int msg_type = CVAL(inbuf,0);
601 int msg_flags = CVAL(inbuf,1);
603 * We only really use 4 bytes of the outbuf, but for the smb_setlen
604 * calculation & friends (srv_send_smb uses that) we need the full smb
605 * header.
607 char outbuf[smb_size];
609 memset(outbuf, '\0', sizeof(outbuf));
611 smb_setlen(outbuf,0);
613 switch (msg_type) {
614 case NBSSrequest: /* session request */
616 /* inbuf_size is guarenteed to be at least 4. */
617 fstring name1,name2;
618 int name_type1, name_type2;
619 int name_len1, name_len2;
621 *name1 = *name2 = 0;
623 if (xconn->transport.nbt.got_session) {
624 exit_server_cleanly("multiple session request not permitted");
627 SCVAL(outbuf,0,NBSSpositive);
628 SCVAL(outbuf,3,0);
630 /* inbuf_size is guaranteed to be at least 4. */
631 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
632 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
633 DEBUG(0,("Invalid name length in session request\n"));
634 reply_called_name_not_present(outbuf);
635 break;
637 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
638 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
639 DEBUG(0,("Invalid name length in session request\n"));
640 reply_called_name_not_present(outbuf);
641 break;
644 name_type1 = name_extract((unsigned char *)inbuf,
645 inbuf_size,(unsigned int)4,name1);
646 name_type2 = name_extract((unsigned char *)inbuf,
647 inbuf_size,(unsigned int)(4 + name_len1),name2);
649 if (name_type1 == -1 || name_type2 == -1) {
650 DEBUG(0,("Invalid name type in session request\n"));
651 reply_called_name_not_present(outbuf);
652 break;
655 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
656 name1, name_type1, name2, name_type2));
658 if (netbios_session_retarget(xconn, name1, name_type1)) {
659 exit_server_cleanly("retargeted client");
663 * Windows NT/2k uses "*SMBSERVER" and XP uses
664 * "*SMBSERV" arrggg!!!
666 if (strequal(name1, "*SMBSERVER ")
667 || strequal(name1, "*SMBSERV ")) {
668 char *raddr;
670 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
671 talloc_tos());
672 if (raddr == NULL) {
673 exit_server_cleanly("could not allocate raddr");
676 fstrcpy(name1, raddr);
679 set_local_machine_name(name1, True);
680 set_remote_machine_name(name2, True);
682 if (is_ipaddress(sconn->remote_hostname)) {
683 char *p = discard_const_p(char, sconn->remote_hostname);
685 talloc_free(p);
687 sconn->remote_hostname = talloc_strdup(sconn,
688 get_remote_machine_name());
689 if (sconn->remote_hostname == NULL) {
690 exit_server_cleanly("could not copy remote name");
692 xconn->remote_hostname = sconn->remote_hostname;
695 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
696 get_local_machine_name(), get_remote_machine_name(),
697 name_type2));
699 if (name_type2 == 'R') {
700 /* We are being asked for a pathworks session ---
701 no thanks! */
702 reply_called_name_not_present(outbuf);
703 break;
706 reload_services(sconn, conn_snum_used, true);
707 reopen_logs();
709 xconn->transport.nbt.got_session = true;
710 break;
713 case 0x89: /* session keepalive request
714 (some old clients produce this?) */
715 SCVAL(outbuf,0,NBSSkeepalive);
716 SCVAL(outbuf,3,0);
717 break;
719 case NBSSpositive: /* positive session response */
720 case NBSSnegative: /* negative session response */
721 case NBSSretarget: /* retarget session response */
722 DEBUG(0,("Unexpected session response\n"));
723 break;
725 case NBSSkeepalive: /* session keepalive */
726 default:
727 return;
730 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
731 msg_type, msg_flags));
733 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
734 exit_server_cleanly("reply_special: srv_send_smb failed.");
737 if (CVAL(outbuf, 0) != 0x82) {
738 exit_server_cleanly("invalid netbios session");
740 return;
743 /****************************************************************************
744 Reply to a tcon.
745 conn POINTER CAN BE NULL HERE !
746 ****************************************************************************/
748 void reply_tcon(struct smb_request *req)
750 connection_struct *conn = req->conn;
751 const char *service;
752 char *service_buf = NULL;
753 char *password = NULL;
754 char *dev = NULL;
755 int pwlen=0;
756 NTSTATUS nt_status;
757 const uint8_t *p;
758 const char *p2;
759 TALLOC_CTX *ctx = talloc_tos();
760 struct smbXsrv_connection *xconn = req->xconn;
761 NTTIME now = timeval_to_nttime(&req->request_time);
763 START_PROFILE(SMBtcon);
765 if (req->buflen < 4) {
766 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
767 END_PROFILE(SMBtcon);
768 return;
771 p = req->buf + 1;
772 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
773 p += 1;
774 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
775 p += pwlen+1;
776 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
777 p += 1;
779 if (service_buf == NULL || password == NULL || dev == NULL) {
780 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
781 END_PROFILE(SMBtcon);
782 return;
784 p2 = strrchr_m(service_buf,'\\');
785 if (p2) {
786 service = p2+1;
787 } else {
788 service = service_buf;
791 conn = make_connection(req, now, service, dev,
792 req->vuid,&nt_status);
793 req->conn = conn;
795 if (!conn) {
796 reply_nterror(req, nt_status);
797 END_PROFILE(SMBtcon);
798 return;
801 reply_outbuf(req, 2, 0);
802 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
803 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
804 SSVAL(req->outbuf,smb_tid,conn->cnum);
806 DEBUG(3,("tcon service=%s cnum=%d\n",
807 service, conn->cnum));
809 END_PROFILE(SMBtcon);
810 return;
813 /****************************************************************************
814 Reply to a tcon and X.
815 conn POINTER CAN BE NULL HERE !
816 ****************************************************************************/
818 void reply_tcon_and_X(struct smb_request *req)
820 const struct loadparm_substitution *lp_sub =
821 loadparm_s3_global_substitution();
822 connection_struct *conn = req->conn;
823 const char *service = NULL;
824 TALLOC_CTX *ctx = talloc_tos();
825 /* what the client thinks the device is */
826 char *client_devicetype = NULL;
827 /* what the server tells the client the share represents */
828 const char *server_devicetype;
829 NTSTATUS nt_status;
830 int passlen;
831 char *path = NULL;
832 const uint8_t *p;
833 const char *q;
834 uint16_t tcon_flags;
835 struct smbXsrv_session *session = NULL;
836 NTTIME now = timeval_to_nttime(&req->request_time);
837 bool session_key_updated = false;
838 uint16_t optional_support = 0;
839 struct smbXsrv_connection *xconn = req->xconn;
841 START_PROFILE(SMBtconX);
843 if (req->wct < 4) {
844 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
845 END_PROFILE(SMBtconX);
846 return;
849 passlen = SVAL(req->vwv+3, 0);
850 tcon_flags = SVAL(req->vwv+2, 0);
852 /* we might have to close an old one */
853 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
854 struct smbXsrv_tcon *tcon;
855 NTSTATUS status;
857 tcon = conn->tcon;
858 req->conn = NULL;
859 conn = NULL;
862 * TODO: cancel all outstanding requests on the tcon
864 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
865 if (!NT_STATUS_IS_OK(status)) {
866 DEBUG(0, ("reply_tcon_and_X: "
867 "smbXsrv_tcon_disconnect() failed: %s\n",
868 nt_errstr(status)));
870 * If we hit this case, there is something completely
871 * wrong, so we better disconnect the transport connection.
873 END_PROFILE(SMBtconX);
874 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
875 return;
878 TALLOC_FREE(tcon);
880 * This tree id is gone. Make sure we can't re-use it
881 * by accident.
883 req->tid = 0;
886 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
887 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
888 END_PROFILE(SMBtconX);
889 return;
892 if (xconn->smb1.negprot.encrypted_passwords) {
893 p = req->buf + passlen;
894 } else {
895 p = req->buf + passlen + 1;
898 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
900 if (path == NULL) {
901 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
902 END_PROFILE(SMBtconX);
903 return;
907 * the service name can be either: \\server\share
908 * or share directly like on the DELL PowerVault 705
910 if (*path=='\\') {
911 q = strchr_m(path+2,'\\');
912 if (!q) {
913 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
914 END_PROFILE(SMBtconX);
915 return;
917 service = q+1;
918 } else {
919 service = path;
922 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
923 &client_devicetype, p,
924 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
926 if (client_devicetype == NULL) {
927 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
928 END_PROFILE(SMBtconX);
929 return;
932 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
934 nt_status = smb1srv_session_lookup(xconn,
935 req->vuid, now, &session);
936 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
937 reply_force_doserror(req, ERRSRV, ERRbaduid);
938 END_PROFILE(SMBtconX);
939 return;
941 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
942 reply_nterror(req, nt_status);
943 END_PROFILE(SMBtconX);
944 return;
946 if (!NT_STATUS_IS_OK(nt_status)) {
947 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
948 END_PROFILE(SMBtconX);
949 return;
952 if (session->global->auth_session_info == NULL) {
953 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
954 END_PROFILE(SMBtconX);
955 return;
959 * If there is no application key defined yet
960 * we create one.
962 * This means we setup the application key on the
963 * first tcon that happens via the given session.
965 * Once the application key is defined, it does not
966 * change any more.
968 if (session->global->application_key.length == 0 &&
969 smb2_signing_key_valid(session->global->signing_key))
971 struct smbXsrv_session *x = session;
972 struct auth_session_info *session_info =
973 session->global->auth_session_info;
974 uint8_t session_key[16];
976 ZERO_STRUCT(session_key);
977 memcpy(session_key, x->global->signing_key->blob.data,
978 MIN(x->global->signing_key->blob.length, sizeof(session_key)));
981 * The application key is truncated/padded to 16 bytes
983 x->global->application_key = data_blob_talloc(x->global,
984 session_key,
985 sizeof(session_key));
986 ZERO_STRUCT(session_key);
987 if (x->global->application_key.data == NULL) {
988 reply_nterror(req, NT_STATUS_NO_MEMORY);
989 END_PROFILE(SMBtconX);
990 return;
993 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
994 NTSTATUS status;
996 status = smb_key_derivation(x->global->application_key.data,
997 x->global->application_key.length,
998 x->global->application_key.data);
999 if (!NT_STATUS_IS_OK(status)) {
1000 DBG_ERR("smb_key_derivation failed: %s\n",
1001 nt_errstr(status));
1002 END_PROFILE(SMBtconX);
1003 return;
1005 optional_support |= SMB_EXTENDED_SIGNATURES;
1009 * Place the application key into the session_info
1011 data_blob_clear_free(&session_info->session_key);
1012 session_info->session_key = data_blob_dup_talloc(session_info,
1013 x->global->application_key);
1014 if (session_info->session_key.data == NULL) {
1015 data_blob_clear_free(&x->global->application_key);
1016 reply_nterror(req, NT_STATUS_NO_MEMORY);
1017 END_PROFILE(SMBtconX);
1018 return;
1020 session_key_updated = true;
1023 conn = make_connection(req, now, service, client_devicetype,
1024 req->vuid, &nt_status);
1025 req->conn =conn;
1027 if (!conn) {
1028 if (session_key_updated) {
1029 struct smbXsrv_session *x = session;
1030 struct auth_session_info *session_info =
1031 session->global->auth_session_info;
1032 data_blob_clear_free(&x->global->application_key);
1033 data_blob_clear_free(&session_info->session_key);
1035 reply_nterror(req, nt_status);
1036 END_PROFILE(SMBtconX);
1037 return;
1040 if ( IS_IPC(conn) )
1041 server_devicetype = "IPC";
1042 else if ( IS_PRINT(conn) )
1043 server_devicetype = "LPT1:";
1044 else
1045 server_devicetype = "A:";
1047 if (get_Protocol() < PROTOCOL_NT1) {
1048 reply_outbuf(req, 2, 0);
1049 if (message_push_string(&req->outbuf, server_devicetype,
1050 STR_TERMINATE|STR_ASCII) == -1) {
1051 reply_nterror(req, NT_STATUS_NO_MEMORY);
1052 END_PROFILE(SMBtconX);
1053 return;
1055 } else {
1056 /* NT sets the fstype of IPC$ to the null string */
1057 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1059 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1060 /* Return permissions. */
1061 uint32_t perm1 = 0;
1062 uint32_t perm2 = 0;
1064 reply_outbuf(req, 7, 0);
1066 if (IS_IPC(conn)) {
1067 perm1 = FILE_ALL_ACCESS;
1068 perm2 = FILE_ALL_ACCESS;
1069 } else {
1070 perm1 = conn->share_access;
1073 SIVAL(req->outbuf, smb_vwv3, perm1);
1074 SIVAL(req->outbuf, smb_vwv5, perm2);
1075 } else {
1076 reply_outbuf(req, 3, 0);
1079 if ((message_push_string(&req->outbuf, server_devicetype,
1080 STR_TERMINATE|STR_ASCII) == -1)
1081 || (message_push_string(&req->outbuf, fstype,
1082 STR_TERMINATE) == -1)) {
1083 reply_nterror(req, NT_STATUS_NO_MEMORY);
1084 END_PROFILE(SMBtconX);
1085 return;
1088 /* what does setting this bit do? It is set by NT4 and
1089 may affect the ability to autorun mounted cdroms */
1090 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1091 optional_support |=
1092 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1094 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1095 DEBUG(2,("Serving %s as a Dfs root\n",
1096 lp_servicename(ctx, lp_sub, SNUM(conn)) ));
1097 optional_support |= SMB_SHARE_IN_DFS;
1100 SSVAL(req->outbuf, smb_vwv2, optional_support);
1103 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1104 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1106 DEBUG(3,("tconX service=%s \n",
1107 service));
1109 /* set the incoming and outgoing tid to the just created one */
1110 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1111 SSVAL(req->outbuf,smb_tid,conn->cnum);
1113 END_PROFILE(SMBtconX);
1115 req->tid = conn->cnum;
1118 /****************************************************************************
1119 Reply to an unknown type.
1120 ****************************************************************************/
1122 void reply_unknown_new(struct smb_request *req, uint8_t type)
1124 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1125 smb_fn_name(type), type, type));
1126 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1127 return;
1130 /****************************************************************************
1131 Reply to an ioctl.
1132 conn POINTER CAN BE NULL HERE !
1133 ****************************************************************************/
1135 void reply_ioctl(struct smb_request *req)
1137 const struct loadparm_substitution *lp_sub =
1138 loadparm_s3_global_substitution();
1139 connection_struct *conn = req->conn;
1140 uint16_t device;
1141 uint16_t function;
1142 uint32_t ioctl_code;
1143 int replysize;
1144 char *p;
1146 START_PROFILE(SMBioctl);
1148 if (req->wct < 3) {
1149 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1150 END_PROFILE(SMBioctl);
1151 return;
1154 device = SVAL(req->vwv+1, 0);
1155 function = SVAL(req->vwv+2, 0);
1156 ioctl_code = (device << 16) + function;
1158 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1160 switch (ioctl_code) {
1161 case IOCTL_QUERY_JOB_INFO:
1162 replysize = 32;
1163 break;
1164 default:
1165 reply_force_doserror(req, ERRSRV, ERRnosupport);
1166 END_PROFILE(SMBioctl);
1167 return;
1170 reply_outbuf(req, 8, replysize+1);
1171 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1172 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1173 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1174 p = smb_buf(req->outbuf);
1175 memset(p, '\0', replysize+1); /* valgrind-safe. */
1176 p += 1; /* Allow for alignment */
1178 switch (ioctl_code) {
1179 case IOCTL_QUERY_JOB_INFO:
1181 NTSTATUS status;
1182 size_t len = 0;
1183 files_struct *fsp = file_fsp(
1184 req, SVAL(req->vwv+0, 0));
1185 if (!fsp) {
1186 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1187 END_PROFILE(SMBioctl);
1188 return;
1190 /* Job number */
1191 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1193 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1194 lp_netbios_name(), 15,
1195 STR_TERMINATE|STR_ASCII, &len);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 reply_nterror(req, status);
1198 END_PROFILE(SMBioctl);
1199 return;
1201 if (conn) {
1202 status = srvstr_push((char *)req->outbuf, req->flags2,
1203 p+18,
1204 lp_servicename(talloc_tos(),
1205 lp_sub,
1206 SNUM(conn)),
1207 13, STR_TERMINATE|STR_ASCII, &len);
1208 if (!NT_STATUS_IS_OK(status)) {
1209 reply_nterror(req, status);
1210 END_PROFILE(SMBioctl);
1211 return;
1213 } else {
1214 memset(p+18, 0, 13);
1216 break;
1220 END_PROFILE(SMBioctl);
1221 return;
1224 /****************************************************************************
1225 Strange checkpath NTSTATUS mapping.
1226 ****************************************************************************/
1228 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1230 /* Strange DOS error code semantics only for checkpath... */
1231 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1232 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1233 /* We need to map to ERRbadpath */
1234 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1237 return status;
1240 /****************************************************************************
1241 Reply to a checkpath.
1242 ****************************************************************************/
1244 void reply_checkpath(struct smb_request *req)
1246 connection_struct *conn = req->conn;
1247 struct smb_filename *smb_fname = NULL;
1248 char *name = NULL;
1249 NTSTATUS status;
1250 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1251 TALLOC_CTX *ctx = talloc_tos();
1253 START_PROFILE(SMBcheckpath);
1255 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1256 STR_TERMINATE, &status);
1258 if (!NT_STATUS_IS_OK(status)) {
1259 status = map_checkpath_error(req->flags2, status);
1260 reply_nterror(req, status);
1261 END_PROFILE(SMBcheckpath);
1262 return;
1265 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1267 status = filename_convert(ctx,
1268 conn,
1269 name,
1270 ucf_flags,
1272 &smb_fname);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1276 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1277 ERRSRV, ERRbadpath);
1278 END_PROFILE(SMBcheckpath);
1279 return;
1281 goto path_err;
1284 if (!VALID_STAT(smb_fname->st) &&
1285 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1286 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1287 smb_fname_str_dbg(smb_fname), strerror(errno)));
1288 status = map_nt_error_from_unix(errno);
1289 goto path_err;
1292 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1293 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1294 ERRDOS, ERRbadpath);
1295 goto out;
1298 reply_outbuf(req, 0, 0);
1300 path_err:
1301 /* We special case this - as when a Windows machine
1302 is parsing a path is steps through the components
1303 one at a time - if a component fails it expects
1304 ERRbadpath, not ERRbadfile.
1306 status = map_checkpath_error(req->flags2, status);
1307 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1309 * Windows returns different error codes if
1310 * the parent directory is valid but not the
1311 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1312 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1313 * if the path is invalid.
1315 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1316 ERRDOS, ERRbadpath);
1317 goto out;
1320 reply_nterror(req, status);
1322 out:
1323 TALLOC_FREE(smb_fname);
1324 END_PROFILE(SMBcheckpath);
1325 return;
1328 /****************************************************************************
1329 Reply to a getatr.
1330 ****************************************************************************/
1332 void reply_getatr(struct smb_request *req)
1334 connection_struct *conn = req->conn;
1335 struct smb_filename *smb_fname = NULL;
1336 char *fname = NULL;
1337 int mode=0;
1338 off_t size=0;
1339 time_t mtime=0;
1340 const char *p;
1341 NTSTATUS status;
1342 TALLOC_CTX *ctx = talloc_tos();
1343 bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1345 START_PROFILE(SMBgetatr);
1347 p = (const char *)req->buf + 1;
1348 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 reply_nterror(req, status);
1351 goto out;
1354 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1355 under WfWg - weird! */
1356 if (*fname == '\0') {
1357 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1358 if (!CAN_WRITE(conn)) {
1359 mode |= FILE_ATTRIBUTE_READONLY;
1361 size = 0;
1362 mtime = 0;
1363 } else {
1364 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1365 status = filename_convert(ctx,
1366 conn,
1367 fname,
1368 ucf_flags,
1370 &smb_fname);
1371 if (!NT_STATUS_IS_OK(status)) {
1372 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1373 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1374 ERRSRV, ERRbadpath);
1375 goto out;
1377 reply_nterror(req, status);
1378 goto out;
1380 if (!VALID_STAT(smb_fname->st) &&
1381 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1382 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1383 smb_fname_str_dbg(smb_fname),
1384 strerror(errno)));
1385 reply_nterror(req, map_nt_error_from_unix(errno));
1386 goto out;
1389 mode = fdos_mode(smb_fname->fsp);
1390 size = smb_fname->st.st_ex_size;
1392 if (ask_sharemode) {
1393 struct timespec write_time_ts;
1394 struct file_id fileid;
1396 ZERO_STRUCT(write_time_ts);
1397 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1398 get_file_infos(fileid, 0, NULL, &write_time_ts);
1399 if (!is_omit_timespec(&write_time_ts)) {
1400 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1404 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1405 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1406 size = 0;
1410 reply_outbuf(req, 10, 0);
1412 SSVAL(req->outbuf,smb_vwv0,mode);
1413 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1414 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1415 } else {
1416 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1418 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1420 if (get_Protocol() >= PROTOCOL_NT1) {
1421 SSVAL(req->outbuf, smb_flg2,
1422 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1425 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1426 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1428 out:
1429 TALLOC_FREE(smb_fname);
1430 TALLOC_FREE(fname);
1431 END_PROFILE(SMBgetatr);
1432 return;
1435 /****************************************************************************
1436 Reply to a setatr.
1437 ****************************************************************************/
1439 void reply_setatr(struct smb_request *req)
1441 struct smb_file_time ft;
1442 connection_struct *conn = req->conn;
1443 struct smb_filename *smb_fname = NULL;
1444 char *fname = NULL;
1445 int mode;
1446 time_t mtime;
1447 const char *p;
1448 NTSTATUS status;
1449 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1450 TALLOC_CTX *ctx = talloc_tos();
1452 START_PROFILE(SMBsetatr);
1453 init_smb_file_time(&ft);
1455 if (req->wct < 2) {
1456 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1457 goto out;
1460 p = (const char *)req->buf + 1;
1461 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1462 if (!NT_STATUS_IS_OK(status)) {
1463 reply_nterror(req, status);
1464 goto out;
1467 status = filename_convert(ctx,
1468 conn,
1469 fname,
1470 ucf_flags,
1472 &smb_fname);
1473 if (!NT_STATUS_IS_OK(status)) {
1474 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1475 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1476 ERRSRV, ERRbadpath);
1477 goto out;
1479 reply_nterror(req, status);
1480 goto out;
1483 if (ISDOT(smb_fname->base_name)) {
1485 * Not sure here is the right place to catch this
1486 * condition. Might be moved to somewhere else later -- vl
1488 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1489 goto out;
1492 mode = SVAL(req->vwv+0, 0);
1493 mtime = srv_make_unix_date3(req->vwv+1);
1495 if (mode != FILE_ATTRIBUTE_NORMAL) {
1496 if (VALID_STAT_OF_DIR(smb_fname->st))
1497 mode |= FILE_ATTRIBUTE_DIRECTORY;
1498 else
1499 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1501 status = smbd_check_access_rights(conn,
1502 conn->cwd_fsp,
1503 smb_fname,
1504 false,
1505 FILE_WRITE_ATTRIBUTES);
1506 if (!NT_STATUS_IS_OK(status)) {
1507 reply_nterror(req, status);
1508 goto out;
1511 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1512 false) != 0) {
1513 reply_nterror(req, map_nt_error_from_unix(errno));
1514 goto out;
1518 ft.mtime = time_t_to_full_timespec(mtime);
1520 status = smb_set_file_time(conn, smb_fname->fsp, smb_fname, &ft, true);
1521 if (!NT_STATUS_IS_OK(status)) {
1522 reply_nterror(req, status);
1523 goto out;
1526 reply_outbuf(req, 0, 0);
1528 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1529 mode));
1530 out:
1531 TALLOC_FREE(smb_fname);
1532 END_PROFILE(SMBsetatr);
1533 return;
1536 /****************************************************************************
1537 Reply to a dskattr.
1538 ****************************************************************************/
1540 void reply_dskattr(struct smb_request *req)
1542 connection_struct *conn = req->conn;
1543 uint64_t ret;
1544 uint64_t dfree,dsize,bsize;
1545 struct smb_filename smb_fname;
1546 START_PROFILE(SMBdskattr);
1548 ZERO_STRUCT(smb_fname);
1549 smb_fname.base_name = discard_const_p(char, ".");
1551 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1552 reply_nterror(req, map_nt_error_from_unix(errno));
1553 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1554 END_PROFILE(SMBdskattr);
1555 return;
1558 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1559 if (ret == (uint64_t)-1) {
1560 reply_nterror(req, map_nt_error_from_unix(errno));
1561 END_PROFILE(SMBdskattr);
1562 return;
1566 * Force max to fit in 16 bit fields.
1568 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1569 dfree /= 2;
1570 dsize /= 2;
1571 bsize *= 2;
1572 if (bsize > (WORDMAX*512)) {
1573 bsize = (WORDMAX*512);
1574 if (dsize > WORDMAX)
1575 dsize = WORDMAX;
1576 if (dfree > WORDMAX)
1577 dfree = WORDMAX;
1578 break;
1582 reply_outbuf(req, 5, 0);
1584 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1585 double total_space, free_space;
1586 /* we need to scale this to a number that DOS6 can handle. We
1587 use floating point so we can handle large drives on systems
1588 that don't have 64 bit integers
1590 we end up displaying a maximum of 2G to DOS systems
1592 total_space = dsize * (double)bsize;
1593 free_space = dfree * (double)bsize;
1595 dsize = (uint64_t)((total_space+63*512) / (64*512));
1596 dfree = (uint64_t)((free_space+63*512) / (64*512));
1598 if (dsize > 0xFFFF) dsize = 0xFFFF;
1599 if (dfree > 0xFFFF) dfree = 0xFFFF;
1601 SSVAL(req->outbuf,smb_vwv0,dsize);
1602 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1603 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1604 SSVAL(req->outbuf,smb_vwv3,dfree);
1605 } else {
1606 SSVAL(req->outbuf,smb_vwv0,dsize);
1607 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1608 SSVAL(req->outbuf,smb_vwv2,512);
1609 SSVAL(req->outbuf,smb_vwv3,dfree);
1612 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1614 END_PROFILE(SMBdskattr);
1615 return;
1619 * Utility function to split the filename from the directory.
1621 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1622 char **fname_dir_out,
1623 char **fname_mask_out)
1625 const char *p = NULL;
1626 char *fname_dir = NULL;
1627 char *fname_mask = NULL;
1629 p = strrchr_m(fname_in, '/');
1630 if (!p) {
1631 fname_dir = talloc_strdup(ctx, ".");
1632 fname_mask = talloc_strdup(ctx, fname_in);
1633 } else {
1634 fname_dir = talloc_strndup(ctx, fname_in,
1635 PTR_DIFF(p, fname_in));
1636 fname_mask = talloc_strdup(ctx, p+1);
1639 if (!fname_dir || !fname_mask) {
1640 TALLOC_FREE(fname_dir);
1641 TALLOC_FREE(fname_mask);
1642 return NT_STATUS_NO_MEMORY;
1645 *fname_dir_out = fname_dir;
1646 *fname_mask_out = fname_mask;
1647 return NT_STATUS_OK;
1650 /****************************************************************************
1651 Make a dir struct.
1652 ****************************************************************************/
1654 static bool make_dir_struct(TALLOC_CTX *ctx,
1655 char *buf,
1656 const char *mask,
1657 const char *fname,
1658 off_t size,
1659 uint32_t mode,
1660 time_t date,
1661 bool uc)
1663 char *p;
1664 char *mask2 = talloc_strdup(ctx, mask);
1666 if (!mask2) {
1667 return False;
1670 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1671 size = 0;
1674 memset(buf+1,' ',11);
1675 if ((p = strchr_m(mask2,'.')) != NULL) {
1676 *p = 0;
1677 push_ascii(buf+1,mask2,8, 0);
1678 push_ascii(buf+9,p+1,3, 0);
1679 *p = '.';
1680 } else {
1681 push_ascii(buf+1,mask2,11, 0);
1684 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1685 SCVAL(buf,21,mode);
1686 srv_put_dos_date(buf,22,date);
1687 SSVAL(buf,26,size & 0xFFFF);
1688 SSVAL(buf,28,(size >> 16)&0xFFFF);
1689 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1690 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1691 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1692 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1693 return True;
1696 /****************************************************************************
1697 Reply to a search.
1698 Can be called from SMBsearch, SMBffirst or SMBfunique.
1699 ****************************************************************************/
1701 void reply_search(struct smb_request *req)
1703 connection_struct *conn = req->conn;
1704 char *path = NULL;
1705 char *mask = NULL;
1706 char *directory = NULL;
1707 struct smb_filename *smb_fname = NULL;
1708 char *fname = NULL;
1709 off_t size;
1710 uint32_t mode;
1711 struct timespec date;
1712 uint32_t dirtype;
1713 unsigned int numentries = 0;
1714 unsigned int maxentries = 0;
1715 bool finished = False;
1716 const char *p;
1717 int status_len;
1718 char status[21];
1719 int dptr_num= -1;
1720 bool check_descend = False;
1721 bool expect_close = False;
1722 NTSTATUS nt_status;
1723 bool mask_contains_wcard = False;
1724 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1725 TALLOC_CTX *ctx = talloc_tos();
1726 bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1727 struct smbXsrv_connection *xconn = req->xconn;
1728 struct smbd_server_connection *sconn = req->sconn;
1729 files_struct *fsp = NULL;
1730 const struct loadparm_substitution *lp_sub =
1731 loadparm_s3_global_substitution();
1733 START_PROFILE(SMBsearch);
1735 if (req->wct < 2) {
1736 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1737 goto out;
1740 if (req->posix_pathnames) {
1741 reply_unknown_new(req, req->cmd);
1742 goto out;
1745 /* If we were called as SMBffirst then we must expect close. */
1746 if(req->cmd == SMBffirst) {
1747 expect_close = True;
1750 reply_outbuf(req, 1, 3);
1751 maxentries = SVAL(req->vwv+0, 0);
1752 dirtype = SVAL(req->vwv+1, 0);
1753 p = (const char *)req->buf + 1;
1754 p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
1755 &nt_status);
1756 if (!NT_STATUS_IS_OK(nt_status)) {
1757 reply_nterror(req, nt_status);
1758 goto out;
1761 if (smbreq_bufrem(req, p) < 3) {
1762 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1763 goto out;
1766 p++;
1767 status_len = SVAL(p, 0);
1768 p += 2;
1770 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1772 if (status_len == 0) {
1773 int ret;
1774 struct smb_filename *smb_dname = NULL;
1775 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1776 ucf_flags_from_smb_request(req);
1777 nt_status = filename_convert(ctx, conn,
1778 path,
1779 ucf_flags,
1781 &smb_fname);
1782 if (!NT_STATUS_IS_OK(nt_status)) {
1783 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1784 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1785 ERRSRV, ERRbadpath);
1786 goto out;
1788 reply_nterror(req, nt_status);
1789 goto out;
1792 directory = smb_fname->base_name;
1794 p = strrchr_m(directory,'/');
1795 if ((p != NULL) && (*directory != '/')) {
1796 mask = talloc_strdup(ctx, p + 1);
1797 directory = talloc_strndup(ctx, directory,
1798 PTR_DIFF(p, directory));
1799 } else {
1800 mask = talloc_strdup(ctx, directory);
1801 directory = talloc_strdup(ctx,".");
1804 if (!directory) {
1805 reply_nterror(req, NT_STATUS_NO_MEMORY);
1806 goto out;
1809 memset((char *)status,'\0',21);
1810 SCVAL(status,0,(dirtype & 0x1F));
1812 smb_dname = synthetic_smb_fname(talloc_tos(),
1813 directory,
1814 NULL,
1815 NULL,
1816 smb_fname->twrp,
1817 smb_fname->flags);
1818 if (smb_dname == NULL) {
1819 reply_nterror(req, NT_STATUS_NO_MEMORY);
1820 goto out;
1824 * As we've cut off the last component from
1825 * smb_fname we need to re-stat smb_dname
1826 * so FILE_OPEN disposition knows the directory
1827 * exists.
1829 ret = vfs_stat(conn, smb_dname);
1830 if (ret == -1) {
1831 nt_status = map_nt_error_from_unix(errno);
1832 reply_nterror(req, nt_status);
1833 goto out;
1836 nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
1837 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1838 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1840 if (!NT_STATUS_IS_OK(nt_status)) {
1841 reply_nterror(req, nt_status);
1842 goto out;
1846 * Open an fsp on this directory for the dptr.
1848 nt_status = SMB_VFS_CREATE_FILE(
1849 conn, /* conn */
1850 req, /* req */
1851 smb_dname, /* dname */
1852 FILE_LIST_DIRECTORY, /* access_mask */
1853 FILE_SHARE_READ|
1854 FILE_SHARE_WRITE, /* share_access */
1855 FILE_OPEN, /* create_disposition*/
1856 FILE_DIRECTORY_FILE, /* create_options */
1857 FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1858 NO_OPLOCK, /* oplock_request */
1859 NULL, /* lease */
1860 0, /* allocation_size */
1861 0, /* private_flags */
1862 NULL, /* sd */
1863 NULL, /* ea_list */
1864 &fsp, /* result */
1865 NULL, /* pinfo */
1866 NULL, /* in_context */
1867 NULL);/* out_context */
1869 if (!NT_STATUS_IS_OK(nt_status)) {
1870 DBG_ERR("failed to open directory %s\n",
1871 smb_fname_str_dbg(smb_dname));
1872 reply_nterror(req, nt_status);
1873 goto out;
1876 nt_status = dptr_create(conn,
1877 NULL, /* req */
1878 fsp, /* fsp */
1879 True,
1880 expect_close,
1881 req->smbpid,
1882 mask,
1883 dirtype,
1884 &fsp->dptr);
1886 TALLOC_FREE(smb_dname);
1888 if (!NT_STATUS_IS_OK(nt_status)) {
1890 * Use NULL here for the first parameter (req)
1891 * as this is not a client visible handle so
1892 * can'tbe part of an SMB1 chain.
1894 close_file(NULL, fsp, NORMAL_CLOSE);
1895 fsp = NULL;
1896 reply_nterror(req, nt_status);
1897 goto out;
1900 dptr_num = dptr_dnum(fsp->dptr);
1902 } else {
1903 int status_dirtype;
1904 const char *dirpath;
1906 if (smbreq_bufrem(req, p) < 21) {
1907 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1908 goto out;
1911 memcpy(status,p,21);
1912 status_dirtype = CVAL(status,0) & 0x1F;
1913 if (status_dirtype != (dirtype & 0x1F)) {
1914 dirtype = status_dirtype;
1917 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
1918 if (fsp == NULL) {
1919 goto SearchEmpty;
1921 dirpath = dptr_path(sconn, dptr_num);
1922 directory = talloc_strdup(ctx, dirpath);
1923 if (!directory) {
1924 reply_nterror(req, NT_STATUS_NO_MEMORY);
1925 goto out;
1928 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1929 if (!mask) {
1930 goto SearchEmpty;
1932 dirtype = dptr_attr(sconn, dptr_num);
1935 mask_contains_wcard = dptr_has_wild(fsp->dptr);
1937 DEBUG(4,("dptr_num is %d\n",dptr_num));
1939 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1940 char buf[DIR_STRUCT_SIZE];
1941 memcpy(buf,status,21);
1942 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1943 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1944 reply_nterror(req, NT_STATUS_NO_MEMORY);
1945 goto out;
1947 dptr_fill(sconn, buf+12,dptr_num);
1948 if (dptr_zero(buf+12) && (status_len==0)) {
1949 numentries = 1;
1950 } else {
1951 numentries = 0;
1953 if (message_push_blob(&req->outbuf,
1954 data_blob_const(buf, sizeof(buf)))
1955 == -1) {
1956 reply_nterror(req, NT_STATUS_NO_MEMORY);
1957 goto out;
1959 } else {
1960 unsigned int i;
1961 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1962 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1964 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1966 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1967 directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
1968 if (in_list(directory, lp_dont_descend(ctx, lp_sub, SNUM(conn)),True)) {
1969 check_descend = True;
1972 for (i=numentries;(i<maxentries) && !finished;i++) {
1973 finished = !get_dir_entry(ctx,
1974 fsp->dptr,
1975 mask,
1976 dirtype,
1977 &fname,
1978 &size,
1979 &mode,
1980 &date,
1981 check_descend,
1982 ask_sharemode);
1983 if (!finished) {
1984 char buf[DIR_STRUCT_SIZE];
1985 memcpy(buf,status,21);
1986 if (!make_dir_struct(ctx,
1987 buf,
1988 mask,
1989 fname,
1990 size,
1991 mode,
1992 convert_timespec_to_time_t(date),
1993 !allow_long_path_components)) {
1994 reply_nterror(req, NT_STATUS_NO_MEMORY);
1995 goto out;
1997 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1998 break;
2000 if (message_push_blob(&req->outbuf,
2001 data_blob_const(buf, sizeof(buf)))
2002 == -1) {
2003 reply_nterror(req, NT_STATUS_NO_MEMORY);
2004 goto out;
2006 numentries++;
2011 SearchEmpty:
2013 /* If we were called as SMBffirst with smb_search_id == NULL
2014 and no entries were found then return error and close fsp->dptr
2015 (X/Open spec) */
2017 if (numentries == 0) {
2018 dptr_num = -1;
2019 if (fsp != NULL) {
2020 close_file(NULL, fsp, NORMAL_CLOSE);
2021 fsp = NULL;
2023 } else if(expect_close && status_len == 0) {
2024 /* Close the dptr - we know it's gone */
2025 dptr_num = -1;
2026 if (fsp != NULL) {
2027 close_file(NULL, fsp, NORMAL_CLOSE);
2028 fsp = NULL;
2032 /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
2033 if(dptr_num >= 0 && req->cmd == SMBfunique) {
2034 dptr_num = -1;
2035 /* fsp may have been closed above. */
2036 if (fsp != NULL) {
2037 close_file(NULL, fsp, NORMAL_CLOSE);
2038 fsp = NULL;
2042 if ((numentries == 0) && !mask_contains_wcard) {
2043 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
2044 goto out;
2047 SSVAL(req->outbuf,smb_vwv0,numentries);
2048 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2049 SCVAL(smb_buf(req->outbuf),0,5);
2050 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2052 /* The replies here are never long name. */
2053 SSVAL(req->outbuf, smb_flg2,
2054 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2055 if (!allow_long_path_components) {
2056 SSVAL(req->outbuf, smb_flg2,
2057 SVAL(req->outbuf, smb_flg2)
2058 & (~FLAGS2_LONG_PATH_COMPONENTS));
2061 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2062 SSVAL(req->outbuf, smb_flg2,
2063 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2065 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2066 smb_fn_name(req->cmd),
2067 mask,
2068 directory,
2069 dirtype,
2070 numentries,
2071 maxentries ));
2072 out:
2073 TALLOC_FREE(directory);
2074 TALLOC_FREE(mask);
2075 TALLOC_FREE(smb_fname);
2076 END_PROFILE(SMBsearch);
2077 return;
2080 /****************************************************************************
2081 Reply to a fclose (stop directory search).
2082 ****************************************************************************/
2084 void reply_fclose(struct smb_request *req)
2086 int status_len;
2087 char status[21];
2088 int dptr_num= -2;
2089 const char *p;
2090 char *path = NULL;
2091 NTSTATUS err;
2092 TALLOC_CTX *ctx = talloc_tos();
2093 struct smbd_server_connection *sconn = req->sconn;
2094 files_struct *fsp = NULL;
2096 START_PROFILE(SMBfclose);
2098 if (req->posix_pathnames) {
2099 reply_unknown_new(req, req->cmd);
2100 END_PROFILE(SMBfclose);
2101 return;
2104 p = (const char *)req->buf + 1;
2105 p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
2106 &err);
2107 if (!NT_STATUS_IS_OK(err)) {
2108 reply_nterror(req, err);
2109 END_PROFILE(SMBfclose);
2110 return;
2113 if (smbreq_bufrem(req, p) < 3) {
2114 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2115 END_PROFILE(SMBfclose);
2116 return;
2119 p++;
2120 status_len = SVAL(p,0);
2121 p += 2;
2123 if (status_len == 0) {
2124 reply_force_doserror(req, ERRSRV, ERRsrverror);
2125 END_PROFILE(SMBfclose);
2126 return;
2129 if (smbreq_bufrem(req, p) < 21) {
2130 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2131 END_PROFILE(SMBfclose);
2132 return;
2135 memcpy(status,p,21);
2137 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
2138 if(fsp != NULL) {
2139 /* Close the file - we know it's gone */
2140 close_file(NULL, fsp, NORMAL_CLOSE);
2141 fsp = NULL;
2142 dptr_num = -1;
2145 reply_outbuf(req, 1, 0);
2146 SSVAL(req->outbuf,smb_vwv0,0);
2148 DEBUG(3,("search close\n"));
2150 END_PROFILE(SMBfclose);
2151 return;
2154 /****************************************************************************
2155 Reply to an open.
2156 ****************************************************************************/
2158 void reply_open(struct smb_request *req)
2160 connection_struct *conn = req->conn;
2161 struct smb_filename *smb_fname = NULL;
2162 char *fname = NULL;
2163 uint32_t fattr=0;
2164 off_t size = 0;
2165 time_t mtime=0;
2166 int info;
2167 files_struct *fsp;
2168 int oplock_request;
2169 int deny_mode;
2170 uint32_t dos_attr;
2171 uint32_t access_mask;
2172 uint32_t share_mode;
2173 uint32_t create_disposition;
2174 uint32_t create_options = 0;
2175 uint32_t private_flags = 0;
2176 NTSTATUS status;
2177 uint32_t ucf_flags;
2178 TALLOC_CTX *ctx = talloc_tos();
2180 START_PROFILE(SMBopen);
2182 if (req->wct < 2) {
2183 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2184 goto out;
2187 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2188 deny_mode = SVAL(req->vwv+0, 0);
2189 dos_attr = SVAL(req->vwv+1, 0);
2191 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2192 STR_TERMINATE, &status);
2193 if (!NT_STATUS_IS_OK(status)) {
2194 reply_nterror(req, status);
2195 goto out;
2198 if (!map_open_params_to_ntcreate(fname, deny_mode,
2199 OPENX_FILE_EXISTS_OPEN, &access_mask,
2200 &share_mode, &create_disposition,
2201 &create_options, &private_flags)) {
2202 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2203 goto out;
2206 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2208 status = filename_convert(ctx,
2209 conn,
2210 fname,
2211 ucf_flags,
2213 &smb_fname);
2214 if (!NT_STATUS_IS_OK(status)) {
2215 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2216 reply_botherror(req,
2217 NT_STATUS_PATH_NOT_COVERED,
2218 ERRSRV, ERRbadpath);
2219 goto out;
2221 reply_nterror(req, status);
2222 goto out;
2225 status = SMB_VFS_CREATE_FILE(
2226 conn, /* conn */
2227 req, /* req */
2228 smb_fname, /* fname */
2229 access_mask, /* access_mask */
2230 share_mode, /* share_access */
2231 create_disposition, /* create_disposition*/
2232 create_options, /* create_options */
2233 dos_attr, /* file_attributes */
2234 oplock_request, /* oplock_request */
2235 NULL, /* lease */
2236 0, /* allocation_size */
2237 private_flags,
2238 NULL, /* sd */
2239 NULL, /* ea_list */
2240 &fsp, /* result */
2241 &info, /* pinfo */
2242 NULL, NULL); /* create context */
2244 if (!NT_STATUS_IS_OK(status)) {
2245 if (open_was_deferred(req->xconn, req->mid)) {
2246 /* We have re-scheduled this call. */
2247 goto out;
2250 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2251 reply_openerror(req, status);
2252 goto out;
2255 fsp = fcb_or_dos_open(
2256 req,
2257 smb_fname,
2258 access_mask,
2259 create_options,
2260 private_flags);
2261 if (fsp == NULL) {
2262 bool ok = defer_smb1_sharing_violation(req);
2263 if (ok) {
2264 goto out;
2266 reply_openerror(req, status);
2267 goto out;
2271 /* Ensure we're pointing at the correct stat struct. */
2272 TALLOC_FREE(smb_fname);
2273 smb_fname = fsp->fsp_name;
2275 size = smb_fname->st.st_ex_size;
2276 fattr = fdos_mode(fsp);
2278 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2280 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2281 DEBUG(3,("attempt to open a directory %s\n",
2282 fsp_str_dbg(fsp)));
2283 close_file(req, fsp, ERROR_CLOSE);
2284 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2285 ERRDOS, ERRnoaccess);
2286 goto out;
2289 reply_outbuf(req, 7, 0);
2290 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2291 SSVAL(req->outbuf,smb_vwv1,fattr);
2292 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2293 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2294 } else {
2295 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2297 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2298 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2300 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2301 SCVAL(req->outbuf,smb_flg,
2302 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2305 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2306 SCVAL(req->outbuf,smb_flg,
2307 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2309 out:
2310 END_PROFILE(SMBopen);
2311 return;
2314 /****************************************************************************
2315 Reply to an open and X.
2316 ****************************************************************************/
2318 void reply_open_and_X(struct smb_request *req)
2320 connection_struct *conn = req->conn;
2321 struct smb_filename *smb_fname = NULL;
2322 char *fname = NULL;
2323 uint16_t open_flags;
2324 int deny_mode;
2325 uint32_t smb_attr;
2326 /* Breakout the oplock request bits so we can set the
2327 reply bits separately. */
2328 int ex_oplock_request;
2329 int core_oplock_request;
2330 int oplock_request;
2331 #if 0
2332 int smb_sattr = SVAL(req->vwv+4, 0);
2333 uint32_t smb_time = make_unix_date3(req->vwv+6);
2334 #endif
2335 int smb_ofun;
2336 uint32_t fattr=0;
2337 int mtime=0;
2338 int smb_action = 0;
2339 files_struct *fsp;
2340 NTSTATUS status;
2341 uint64_t allocation_size;
2342 ssize_t retval = -1;
2343 uint32_t access_mask;
2344 uint32_t share_mode;
2345 uint32_t create_disposition;
2346 uint32_t create_options = 0;
2347 uint32_t private_flags = 0;
2348 uint32_t ucf_flags;
2349 TALLOC_CTX *ctx = talloc_tos();
2351 START_PROFILE(SMBopenX);
2353 if (req->wct < 15) {
2354 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2355 goto out;
2358 open_flags = SVAL(req->vwv+2, 0);
2359 deny_mode = SVAL(req->vwv+3, 0);
2360 smb_attr = SVAL(req->vwv+5, 0);
2361 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2362 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2363 oplock_request = ex_oplock_request | core_oplock_request;
2364 smb_ofun = SVAL(req->vwv+8, 0);
2365 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2367 /* If it's an IPC, pass off the pipe handler. */
2368 if (IS_IPC(conn)) {
2369 if (lp_nt_pipe_support()) {
2370 reply_open_pipe_and_X(conn, req);
2371 } else {
2372 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2374 goto out;
2377 /* XXXX we need to handle passed times, sattr and flags */
2378 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2379 STR_TERMINATE, &status);
2380 if (!NT_STATUS_IS_OK(status)) {
2381 reply_nterror(req, status);
2382 goto out;
2385 if (!map_open_params_to_ntcreate(fname, deny_mode,
2386 smb_ofun,
2387 &access_mask, &share_mode,
2388 &create_disposition,
2389 &create_options,
2390 &private_flags)) {
2391 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2392 goto out;
2395 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2397 status = filename_convert(ctx,
2398 conn,
2399 fname,
2400 ucf_flags,
2402 &smb_fname);
2403 if (!NT_STATUS_IS_OK(status)) {
2404 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2405 reply_botherror(req,
2406 NT_STATUS_PATH_NOT_COVERED,
2407 ERRSRV, ERRbadpath);
2408 goto out;
2410 reply_nterror(req, status);
2411 goto out;
2414 status = SMB_VFS_CREATE_FILE(
2415 conn, /* conn */
2416 req, /* req */
2417 smb_fname, /* fname */
2418 access_mask, /* access_mask */
2419 share_mode, /* share_access */
2420 create_disposition, /* create_disposition*/
2421 create_options, /* create_options */
2422 smb_attr, /* file_attributes */
2423 oplock_request, /* oplock_request */
2424 NULL, /* lease */
2425 0, /* allocation_size */
2426 private_flags,
2427 NULL, /* sd */
2428 NULL, /* ea_list */
2429 &fsp, /* result */
2430 &smb_action, /* pinfo */
2431 NULL, NULL); /* create context */
2433 if (!NT_STATUS_IS_OK(status)) {
2434 if (open_was_deferred(req->xconn, req->mid)) {
2435 /* We have re-scheduled this call. */
2436 goto out;
2439 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2440 reply_openerror(req, status);
2441 goto out;
2444 fsp = fcb_or_dos_open(
2445 req,
2446 smb_fname,
2447 access_mask,
2448 create_options,
2449 private_flags);
2450 if (fsp == NULL) {
2451 bool ok = defer_smb1_sharing_violation(req);
2452 if (ok) {
2453 goto out;
2455 reply_openerror(req, status);
2456 goto out;
2460 smb_action = FILE_WAS_OPENED;
2463 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2464 if the file is truncated or created. */
2465 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2466 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2467 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2468 close_file(req, fsp, ERROR_CLOSE);
2469 reply_nterror(req, NT_STATUS_DISK_FULL);
2470 goto out;
2472 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2473 if (retval < 0) {
2474 close_file(req, fsp, ERROR_CLOSE);
2475 reply_nterror(req, NT_STATUS_DISK_FULL);
2476 goto out;
2478 status = vfs_stat_fsp(fsp);
2479 if (!NT_STATUS_IS_OK(status)) {
2480 close_file(req, fsp, ERROR_CLOSE);
2481 reply_nterror(req, status);
2482 goto out;
2486 fattr = fdos_mode(fsp);
2487 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2488 close_file(req, fsp, ERROR_CLOSE);
2489 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2490 goto out;
2492 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2494 /* If the caller set the extended oplock request bit
2495 and we granted one (by whatever means) - set the
2496 correct bit for extended oplock reply.
2499 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2500 smb_action |= EXTENDED_OPLOCK_GRANTED;
2503 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2504 smb_action |= EXTENDED_OPLOCK_GRANTED;
2507 /* If the caller set the core oplock request bit
2508 and we granted one (by whatever means) - set the
2509 correct bit for core oplock reply.
2512 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2513 reply_outbuf(req, 19, 0);
2514 } else {
2515 reply_outbuf(req, 15, 0);
2518 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2519 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2521 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2522 SCVAL(req->outbuf, smb_flg,
2523 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2526 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2527 SCVAL(req->outbuf, smb_flg,
2528 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2531 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2532 SSVAL(req->outbuf,smb_vwv3,fattr);
2533 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2534 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2535 } else {
2536 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2538 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2539 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2540 SSVAL(req->outbuf,smb_vwv11,smb_action);
2542 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2543 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2546 out:
2547 TALLOC_FREE(smb_fname);
2548 END_PROFILE(SMBopenX);
2549 return;
2552 /****************************************************************************
2553 Reply to a SMBulogoffX.
2554 ****************************************************************************/
2556 static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2557 struct smbXsrv_session *session);
2558 static void reply_ulogoffX_done(struct tevent_req *req);
2560 void reply_ulogoffX(struct smb_request *smb1req)
2562 struct timeval now = timeval_current();
2563 struct smbXsrv_session *session = NULL;
2564 struct tevent_req *req;
2565 NTSTATUS status;
2568 * Don't setup the profile charge here, take
2569 * it in reply_ulogoffX_done(). Not strictly correct
2570 * but better than the other SMB1 async
2571 * code that double-charges at the moment.
2574 status = smb1srv_session_lookup(smb1req->xconn,
2575 smb1req->vuid,
2576 timeval_to_nttime(&now),
2577 &session);
2578 if (!NT_STATUS_IS_OK(status)) {
2579 /* Not going async, profile here. */
2580 START_PROFILE(SMBulogoffX);
2581 DBG_WARNING("ulogoff, vuser id %llu does not map to user.\n",
2582 (unsigned long long)smb1req->vuid);
2584 smb1req->vuid = UID_FIELD_INVALID;
2585 reply_force_doserror(smb1req, ERRSRV, ERRbaduid);
2586 END_PROFILE(SMBulogoffX);
2587 return;
2590 req = reply_ulogoffX_send(smb1req, session);
2591 if (req == NULL) {
2592 /* Not going async, profile here. */
2593 START_PROFILE(SMBulogoffX);
2594 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
2595 END_PROFILE(SMBulogoffX);
2596 return;
2599 /* We're async. This will complete later. */
2600 tevent_req_set_callback(req, reply_ulogoffX_done, smb1req);
2601 return;
2604 struct reply_ulogoffX_state {
2605 struct tevent_queue *wait_queue;
2606 struct smbXsrv_session *session;
2609 static void reply_ulogoffX_wait_done(struct tevent_req *subreq);
2611 /****************************************************************************
2612 Async SMB1 ulogoffX.
2613 Note, on failure here we deallocate and return NULL to allow the caller to
2614 SMB1 return an error of ERRnomem immediately.
2615 ****************************************************************************/
2617 static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2618 struct smbXsrv_session *session)
2620 struct tevent_req *req;
2621 struct reply_ulogoffX_state *state;
2622 struct tevent_req *subreq;
2623 files_struct *fsp;
2624 struct smbd_server_connection *sconn = session->client->sconn;
2625 uint64_t vuid = session->global->session_wire_id;
2627 req = tevent_req_create(smb1req, &state,
2628 struct reply_ulogoffX_state);
2629 if (req == NULL) {
2630 return NULL;
2632 state->wait_queue = tevent_queue_create(state,
2633 "reply_ulogoffX_wait_queue");
2634 if (tevent_req_nomem(state->wait_queue, req)) {
2635 TALLOC_FREE(req);
2636 return NULL;
2638 state->session = session;
2641 * Make sure that no new request will be able to use this session.
2642 * This ensures that once all outstanding fsp->aio_requests
2643 * on this session are done, we are safe to close it.
2645 session->status = NT_STATUS_USER_SESSION_DELETED;
2647 for (fsp = sconn->files; fsp; fsp = fsp->next) {
2648 if (fsp->vuid != vuid) {
2649 continue;
2652 * Flag the file as close in progress.
2653 * This will prevent any more IO being
2654 * done on it.
2656 fsp->fsp_flags.closing = true;
2658 if (fsp->num_aio_requests > 0) {
2660 * Now wait until all aio requests on this fsp are
2661 * finished.
2663 * We don't set a callback, as we just want to block the
2664 * wait queue and the talloc_free() of fsp->aio_request
2665 * will remove the item from the wait queue.
2667 subreq = tevent_queue_wait_send(fsp->aio_requests,
2668 sconn->ev_ctx,
2669 state->wait_queue);
2670 if (tevent_req_nomem(subreq, req)) {
2671 TALLOC_FREE(req);
2672 return NULL;
2678 * Now we add our own waiter to the end of the queue,
2679 * this way we get notified when all pending requests are finished
2680 * and reply to the outstanding SMB1 request.
2682 subreq = tevent_queue_wait_send(state,
2683 sconn->ev_ctx,
2684 state->wait_queue);
2685 if (tevent_req_nomem(subreq, req)) {
2686 TALLOC_FREE(req);
2687 return NULL;
2691 * We're really going async - move the SMB1 request from
2692 * a talloc stackframe above us to the sconn talloc-context.
2693 * We need this to stick around until the wait_done
2694 * callback is invoked.
2696 smb1req = talloc_move(sconn, &smb1req);
2698 tevent_req_set_callback(subreq, reply_ulogoffX_wait_done, req);
2700 return req;
2703 static void reply_ulogoffX_wait_done(struct tevent_req *subreq)
2705 struct tevent_req *req = tevent_req_callback_data(
2706 subreq, struct tevent_req);
2708 tevent_queue_wait_recv(subreq);
2709 TALLOC_FREE(subreq);
2710 tevent_req_done(req);
2713 static NTSTATUS reply_ulogoffX_recv(struct tevent_req *req)
2715 return tevent_req_simple_recv_ntstatus(req);
2718 static void reply_ulogoffX_done(struct tevent_req *req)
2720 struct smb_request *smb1req = tevent_req_callback_data(
2721 req, struct smb_request);
2722 struct reply_ulogoffX_state *state = tevent_req_data(req,
2723 struct reply_ulogoffX_state);
2724 struct smbXsrv_session *session = state->session;
2725 NTSTATUS status;
2728 * Take the profile charge here. Not strictly
2729 * correct but better than the other SMB1 async
2730 * code that double-charges at the moment.
2732 START_PROFILE(SMBulogoffX);
2734 status = reply_ulogoffX_recv(req);
2735 TALLOC_FREE(req);
2736 if (!NT_STATUS_IS_OK(status)) {
2737 TALLOC_FREE(smb1req);
2738 END_PROFILE(SMBulogoffX);
2739 exit_server(__location__ ": reply_ulogoffX_recv failed");
2740 return;
2743 status = smbXsrv_session_logoff(session);
2744 if (!NT_STATUS_IS_OK(status)) {
2745 TALLOC_FREE(smb1req);
2746 END_PROFILE(SMBulogoffX);
2747 exit_server(__location__ ": smbXsrv_session_logoff failed");
2748 return;
2751 TALLOC_FREE(session);
2753 reply_outbuf(smb1req, 2, 0);
2754 SSVAL(smb1req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2755 SSVAL(smb1req->outbuf, smb_vwv1, 0); /* no andx offset */
2757 DBG_NOTICE("ulogoffX vuid=%llu\n",
2758 (unsigned long long)smb1req->vuid);
2760 smb1req->vuid = UID_FIELD_INVALID;
2762 * The following call is needed to push the
2763 * reply data back out the socket after async
2764 * return. Plus it frees smb1req.
2766 smb_request_done(smb1req);
2767 END_PROFILE(SMBulogoffX);
2770 /****************************************************************************
2771 Reply to a mknew or a create.
2772 ****************************************************************************/
2774 void reply_mknew(struct smb_request *req)
2776 connection_struct *conn = req->conn;
2777 struct smb_filename *smb_fname = NULL;
2778 char *fname = NULL;
2779 uint32_t fattr = 0;
2780 struct smb_file_time ft;
2781 files_struct *fsp;
2782 int oplock_request = 0;
2783 NTSTATUS status;
2784 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2785 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2786 uint32_t create_disposition;
2787 uint32_t create_options = 0;
2788 uint32_t ucf_flags;
2789 TALLOC_CTX *ctx = talloc_tos();
2791 START_PROFILE(SMBcreate);
2792 init_smb_file_time(&ft);
2794 if (req->wct < 3) {
2795 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2796 goto out;
2799 fattr = SVAL(req->vwv+0, 0);
2800 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2802 if (req->cmd == SMBmknew) {
2803 /* We should fail if file exists. */
2804 create_disposition = FILE_CREATE;
2805 } else {
2806 /* Create if file doesn't exist, truncate if it does. */
2807 create_disposition = FILE_OVERWRITE_IF;
2810 /* mtime. */
2811 ft.mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+1));
2813 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2814 STR_TERMINATE, &status);
2815 if (!NT_STATUS_IS_OK(status)) {
2816 reply_nterror(req, status);
2817 goto out;
2820 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2821 status = filename_convert(ctx,
2822 conn,
2823 fname,
2824 ucf_flags,
2826 &smb_fname);
2827 if (!NT_STATUS_IS_OK(status)) {
2828 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2829 reply_botherror(req,
2830 NT_STATUS_PATH_NOT_COVERED,
2831 ERRSRV, ERRbadpath);
2832 goto out;
2834 reply_nterror(req, status);
2835 goto out;
2838 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2839 DEBUG(0,("Attempt to create file (%s) with volid set - "
2840 "please report this\n",
2841 smb_fname_str_dbg(smb_fname)));
2844 status = SMB_VFS_CREATE_FILE(
2845 conn, /* conn */
2846 req, /* req */
2847 smb_fname, /* fname */
2848 access_mask, /* access_mask */
2849 share_mode, /* share_access */
2850 create_disposition, /* create_disposition*/
2851 create_options, /* create_options */
2852 fattr, /* file_attributes */
2853 oplock_request, /* oplock_request */
2854 NULL, /* lease */
2855 0, /* allocation_size */
2856 0, /* private_flags */
2857 NULL, /* sd */
2858 NULL, /* ea_list */
2859 &fsp, /* result */
2860 NULL, /* pinfo */
2861 NULL, NULL); /* create context */
2863 if (!NT_STATUS_IS_OK(status)) {
2864 if (open_was_deferred(req->xconn, req->mid)) {
2865 /* We have re-scheduled this call. */
2866 goto out;
2868 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2869 bool ok = defer_smb1_sharing_violation(req);
2870 if (ok) {
2871 goto out;
2874 reply_openerror(req, status);
2875 goto out;
2878 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2879 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2880 if (!NT_STATUS_IS_OK(status)) {
2881 END_PROFILE(SMBcreate);
2882 goto out;
2885 reply_outbuf(req, 1, 0);
2886 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2888 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2889 SCVAL(req->outbuf,smb_flg,
2890 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2893 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2894 SCVAL(req->outbuf,smb_flg,
2895 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2898 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2899 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2900 smb_fname_str_dbg(smb_fname), fsp_get_io_fd(fsp),
2901 (unsigned int)fattr));
2903 out:
2904 TALLOC_FREE(smb_fname);
2905 END_PROFILE(SMBcreate);
2906 return;
2909 /****************************************************************************
2910 Reply to a create temporary file.
2911 ****************************************************************************/
2913 void reply_ctemp(struct smb_request *req)
2915 connection_struct *conn = req->conn;
2916 struct smb_filename *smb_fname = NULL;
2917 char *wire_name = NULL;
2918 char *fname = NULL;
2919 uint32_t fattr;
2920 files_struct *fsp;
2921 int oplock_request;
2922 char *s;
2923 NTSTATUS status;
2924 int i;
2925 uint32_t ucf_flags;
2926 TALLOC_CTX *ctx = talloc_tos();
2928 START_PROFILE(SMBctemp);
2930 if (req->wct < 3) {
2931 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2932 goto out;
2935 fattr = SVAL(req->vwv+0, 0);
2936 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2938 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2939 STR_TERMINATE, &status);
2940 if (!NT_STATUS_IS_OK(status)) {
2941 reply_nterror(req, status);
2942 goto out;
2945 for (i = 0; i < 10; i++) {
2946 if (*wire_name) {
2947 fname = talloc_asprintf(ctx,
2948 "%s/TMP%s",
2949 wire_name,
2950 generate_random_str_list(ctx, 5, "0123456789"));
2951 } else {
2952 fname = talloc_asprintf(ctx,
2953 "TMP%s",
2954 generate_random_str_list(ctx, 5, "0123456789"));
2957 if (!fname) {
2958 reply_nterror(req, NT_STATUS_NO_MEMORY);
2959 goto out;
2962 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2963 status = filename_convert(ctx, conn,
2964 fname,
2965 ucf_flags,
2967 &smb_fname);
2968 if (!NT_STATUS_IS_OK(status)) {
2969 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2970 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2971 ERRSRV, ERRbadpath);
2972 goto out;
2974 reply_nterror(req, status);
2975 goto out;
2978 /* Create the file. */
2979 status = SMB_VFS_CREATE_FILE(
2980 conn, /* conn */
2981 req, /* req */
2982 smb_fname, /* fname */
2983 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2984 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2985 FILE_CREATE, /* create_disposition*/
2986 0, /* create_options */
2987 fattr, /* file_attributes */
2988 oplock_request, /* oplock_request */
2989 NULL, /* lease */
2990 0, /* allocation_size */
2991 0, /* private_flags */
2992 NULL, /* sd */
2993 NULL, /* ea_list */
2994 &fsp, /* result */
2995 NULL, /* pinfo */
2996 NULL, NULL); /* create context */
2998 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2999 TALLOC_FREE(fname);
3000 TALLOC_FREE(smb_fname);
3001 continue;
3004 if (!NT_STATUS_IS_OK(status)) {
3005 if (open_was_deferred(req->xconn, req->mid)) {
3006 /* We have re-scheduled this call. */
3007 goto out;
3009 if (NT_STATUS_EQUAL(
3010 status, NT_STATUS_SHARING_VIOLATION)) {
3011 bool ok = defer_smb1_sharing_violation(req);
3012 if (ok) {
3013 goto out;
3016 reply_openerror(req, status);
3017 goto out;
3020 break;
3023 if (i == 10) {
3024 /* Collision after 10 times... */
3025 reply_nterror(req, status);
3026 goto out;
3029 reply_outbuf(req, 1, 0);
3030 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
3032 /* the returned filename is relative to the directory */
3033 s = strrchr_m(fsp->fsp_name->base_name, '/');
3034 if (!s) {
3035 s = fsp->fsp_name->base_name;
3036 } else {
3037 s++;
3040 #if 0
3041 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
3042 thing in the byte section. JRA */
3043 SSVALS(p, 0, -1); /* what is this? not in spec */
3044 #endif
3045 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
3046 == -1) {
3047 reply_nterror(req, NT_STATUS_NO_MEMORY);
3048 goto out;
3051 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3052 SCVAL(req->outbuf, smb_flg,
3053 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
3056 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3057 SCVAL(req->outbuf, smb_flg,
3058 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
3061 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
3062 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
3063 fsp_get_io_fd(fsp), (unsigned int)smb_fname->st.st_ex_mode));
3064 out:
3065 TALLOC_FREE(smb_fname);
3066 TALLOC_FREE(wire_name);
3067 END_PROFILE(SMBctemp);
3068 return;
3071 /*******************************************************************
3072 Check if a user is allowed to rename a file.
3073 ********************************************************************/
3075 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
3076 uint16_t dirtype)
3078 if (!CAN_WRITE(conn)) {
3079 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3082 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
3083 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
3084 /* Only bother to read the DOS attribute if we might deny the
3085 rename on the grounds of attribute mismatch. */
3086 uint32_t fmode = fdos_mode(fsp);
3087 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
3088 return NT_STATUS_NO_SUCH_FILE;
3092 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
3093 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
3094 return NT_STATUS_OK;
3097 /* If no pathnames are open below this
3098 directory, allow the rename. */
3100 if (lp_strict_rename(SNUM(conn))) {
3102 * Strict rename, check open file db.
3104 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
3105 return NT_STATUS_ACCESS_DENIED;
3107 } else if (file_find_subpath(fsp)) {
3109 * No strict rename, just look in local process.
3111 return NT_STATUS_ACCESS_DENIED;
3113 return NT_STATUS_OK;
3116 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
3117 return NT_STATUS_OK;
3120 return NT_STATUS_ACCESS_DENIED;
3123 /*******************************************************************
3124 * unlink a file with all relevant access checks
3125 *******************************************************************/
3127 static NTSTATUS do_unlink(connection_struct *conn,
3128 struct smb_request *req,
3129 struct smb_filename *smb_fname,
3130 uint32_t dirtype)
3132 uint32_t fattr;
3133 files_struct *fsp;
3134 uint32_t dirtype_orig = dirtype;
3135 NTSTATUS status;
3136 int ret;
3137 struct smb2_create_blobs *posx = NULL;
3139 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
3140 smb_fname_str_dbg(smb_fname),
3141 dirtype));
3143 if (!CAN_WRITE(conn)) {
3144 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3147 ret = vfs_stat(conn, smb_fname);
3148 if (ret != 0) {
3149 return map_nt_error_from_unix(errno);
3152 fattr = fdos_mode(smb_fname->fsp);
3154 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
3155 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
3158 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
3159 if (!dirtype) {
3160 return NT_STATUS_NO_SUCH_FILE;
3163 if (!dir_check_ftype(fattr, dirtype)) {
3164 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3165 return NT_STATUS_FILE_IS_A_DIRECTORY;
3167 return NT_STATUS_NO_SUCH_FILE;
3170 if (dirtype_orig & 0x8000) {
3171 /* These will never be set for POSIX. */
3172 return NT_STATUS_NO_SUCH_FILE;
3175 #if 0
3176 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
3177 return NT_STATUS_FILE_IS_A_DIRECTORY;
3180 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
3181 return NT_STATUS_NO_SUCH_FILE;
3184 if (dirtype & 0xFF00) {
3185 /* These will never be set for POSIX. */
3186 return NT_STATUS_NO_SUCH_FILE;
3189 dirtype &= 0xFF;
3190 if (!dirtype) {
3191 return NT_STATUS_NO_SUCH_FILE;
3194 /* Can't delete a directory. */
3195 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3196 return NT_STATUS_FILE_IS_A_DIRECTORY;
3198 #endif
3200 #if 0 /* JRATEST */
3201 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
3202 return NT_STATUS_OBJECT_NAME_INVALID;
3203 #endif /* JRATEST */
3205 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
3206 status = make_smb2_posix_create_ctx(
3207 talloc_tos(), &posx, 0777);
3208 if (!NT_STATUS_IS_OK(status)) {
3209 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3210 nt_errstr(status));
3211 return status;
3215 /* On open checks the open itself will check the share mode, so
3216 don't do it here as we'll get it wrong. */
3218 status = SMB_VFS_CREATE_FILE
3219 (conn, /* conn */
3220 req, /* req */
3221 smb_fname, /* fname */
3222 DELETE_ACCESS, /* access_mask */
3223 FILE_SHARE_NONE, /* share_access */
3224 FILE_OPEN, /* create_disposition*/
3225 FILE_NON_DIRECTORY_FILE, /* create_options */
3226 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
3227 0, /* oplock_request */
3228 NULL, /* lease */
3229 0, /* allocation_size */
3230 0, /* private_flags */
3231 NULL, /* sd */
3232 NULL, /* ea_list */
3233 &fsp, /* result */
3234 NULL, /* pinfo */
3235 posx, /* in_context_blobs */
3236 NULL); /* out_context_blobs */
3238 TALLOC_FREE(posx);
3240 if (!NT_STATUS_IS_OK(status)) {
3241 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
3242 nt_errstr(status)));
3243 return status;
3246 status = can_set_delete_on_close(fsp, fattr);
3247 if (!NT_STATUS_IS_OK(status)) {
3248 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
3249 "(%s)\n",
3250 smb_fname_str_dbg(smb_fname),
3251 nt_errstr(status)));
3252 close_file(req, fsp, NORMAL_CLOSE);
3253 return status;
3256 /* The set is across all open files on this dev/inode pair. */
3257 if (!set_delete_on_close(fsp, True,
3258 conn->session_info->security_token,
3259 conn->session_info->unix_token)) {
3260 close_file(req, fsp, NORMAL_CLOSE);
3261 return NT_STATUS_ACCESS_DENIED;
3264 return close_file(req, fsp, NORMAL_CLOSE);
3267 /****************************************************************************
3268 The guts of the unlink command, split out so it may be called by the NT SMB
3269 code.
3270 ****************************************************************************/
3272 NTSTATUS unlink_internals(connection_struct *conn,
3273 struct smb_request *req,
3274 uint32_t dirtype,
3275 struct smb_filename *smb_fname,
3276 bool has_wild)
3278 char *fname_dir = NULL;
3279 char *fname_mask = NULL;
3280 int count=0;
3281 NTSTATUS status = NT_STATUS_OK;
3282 struct smb_filename *smb_fname_dir = NULL;
3283 TALLOC_CTX *ctx = talloc_tos();
3285 /* Split up the directory from the filename/mask. */
3286 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3287 &fname_dir, &fname_mask);
3288 if (!NT_STATUS_IS_OK(status)) {
3289 goto out;
3293 * We should only check the mangled cache
3294 * here if unix_convert failed. This means
3295 * that the path in 'mask' doesn't exist
3296 * on the file system and so we need to look
3297 * for a possible mangle. This patch from
3298 * Tine Smukavec <valentin.smukavec@hermes.si>.
3301 if (!VALID_STAT(smb_fname->st) &&
3302 mangle_is_mangled(fname_mask, conn->params)) {
3303 char *new_mask = NULL;
3304 mangle_lookup_name_from_8_3(ctx, fname_mask,
3305 &new_mask, conn->params);
3306 if (new_mask) {
3307 TALLOC_FREE(fname_mask);
3308 fname_mask = new_mask;
3312 if (!has_wild) {
3315 * Only one file needs to be unlinked. Append the mask back
3316 * onto the directory.
3318 TALLOC_FREE(smb_fname->base_name);
3319 if (ISDOT(fname_dir)) {
3320 /* Ensure we use canonical names on open. */
3321 smb_fname->base_name = talloc_asprintf(smb_fname,
3322 "%s",
3323 fname_mask);
3324 } else {
3325 smb_fname->base_name = talloc_asprintf(smb_fname,
3326 "%s/%s",
3327 fname_dir,
3328 fname_mask);
3330 if (!smb_fname->base_name) {
3331 status = NT_STATUS_NO_MEMORY;
3332 goto out;
3334 if (dirtype == 0) {
3335 dirtype = FILE_ATTRIBUTE_NORMAL;
3338 status = check_name(conn, smb_fname);
3339 if (!NT_STATUS_IS_OK(status)) {
3340 goto out;
3343 status = do_unlink(conn, req, smb_fname, dirtype);
3344 if (!NT_STATUS_IS_OK(status)) {
3345 goto out;
3348 count++;
3349 } else {
3350 struct smb_Dir *dir_hnd = NULL;
3351 long offset = 0;
3352 const char *dname = NULL;
3353 char *talloced = NULL;
3355 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3356 status = NT_STATUS_OBJECT_NAME_INVALID;
3357 goto out;
3359 if (dirtype == 0) {
3360 dirtype = FILE_ATTRIBUTE_NORMAL;
3363 if (strequal(fname_mask,"????????.???")) {
3364 TALLOC_FREE(fname_mask);
3365 fname_mask = talloc_strdup(ctx, "*");
3366 if (!fname_mask) {
3367 status = NT_STATUS_NO_MEMORY;
3368 goto out;
3372 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3373 fname_dir,
3374 NULL,
3375 NULL,
3376 smb_fname->twrp,
3377 smb_fname->flags);
3378 if (smb_fname_dir == NULL) {
3379 status = NT_STATUS_NO_MEMORY;
3380 goto out;
3383 status = check_name(conn, smb_fname_dir);
3384 if (!NT_STATUS_IS_OK(status)) {
3385 goto out;
3388 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3389 dirtype);
3390 if (dir_hnd == NULL) {
3391 status = map_nt_error_from_unix(errno);
3392 goto out;
3395 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3396 the pattern matches against the long name, otherwise the short name
3397 We don't implement this yet XXXX
3400 status = NT_STATUS_NO_SUCH_FILE;
3402 while ((dname = ReadDirName(dir_hnd, &offset,
3403 &smb_fname->st, &talloced))) {
3404 TALLOC_CTX *frame = talloc_stackframe();
3405 char *p = NULL;
3406 struct smb_filename *f = NULL;
3408 if (!is_visible_file(conn,
3409 dir_hnd,
3410 dname,
3411 &smb_fname->st,
3412 true)) {
3413 TALLOC_FREE(frame);
3414 TALLOC_FREE(talloced);
3415 continue;
3418 /* Quick check for "." and ".." */
3419 if (ISDOT(dname) || ISDOTDOT(dname)) {
3420 TALLOC_FREE(frame);
3421 TALLOC_FREE(talloced);
3422 continue;
3425 if(!mask_match(dname, fname_mask,
3426 conn->case_sensitive)) {
3427 TALLOC_FREE(frame);
3428 TALLOC_FREE(talloced);
3429 continue;
3432 if (ISDOT(fname_dir)) {
3433 /* Ensure we use canonical names on open. */
3434 p = talloc_asprintf(smb_fname, "%s", dname);
3435 } else {
3436 p = talloc_asprintf(smb_fname, "%s/%s",
3437 fname_dir, dname);
3439 if (p == NULL) {
3440 TALLOC_FREE(dir_hnd);
3441 status = NT_STATUS_NO_MEMORY;
3442 TALLOC_FREE(frame);
3443 TALLOC_FREE(talloced);
3444 goto out;
3446 f = synthetic_smb_fname(frame,
3448 NULL,
3449 &smb_fname->st,
3450 smb_fname->twrp,
3451 smb_fname->flags);
3452 if (f == NULL) {
3453 TALLOC_FREE(dir_hnd);
3454 status = NT_STATUS_NO_MEMORY;
3455 TALLOC_FREE(frame);
3456 TALLOC_FREE(talloced);
3457 goto out;
3460 status = openat_pathref_fsp(conn->cwd_fsp, f);
3461 if (!NT_STATUS_IS_OK(status) &&
3462 !NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
3464 TALLOC_FREE(dir_hnd);
3465 TALLOC_FREE(frame);
3466 TALLOC_FREE(talloced);
3467 goto out;
3470 status = check_name(conn, f);
3471 if (!NT_STATUS_IS_OK(status)) {
3472 TALLOC_FREE(dir_hnd);
3473 TALLOC_FREE(frame);
3474 TALLOC_FREE(talloced);
3475 goto out;
3478 status = do_unlink(conn, req, f, dirtype);
3479 if (!NT_STATUS_IS_OK(status)) {
3480 TALLOC_FREE(dir_hnd);
3481 TALLOC_FREE(frame);
3482 TALLOC_FREE(talloced);
3483 goto out;
3486 count++;
3487 DBG_DEBUG("successful unlink [%s]\n",
3488 smb_fname_str_dbg(f));
3490 TALLOC_FREE(frame);
3491 TALLOC_FREE(talloced);
3493 TALLOC_FREE(dir_hnd);
3496 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3497 status = map_nt_error_from_unix(errno);
3500 out:
3501 TALLOC_FREE(smb_fname_dir);
3502 TALLOC_FREE(fname_dir);
3503 TALLOC_FREE(fname_mask);
3504 return status;
3507 /****************************************************************************
3508 Reply to a unlink
3509 ****************************************************************************/
3511 void reply_unlink(struct smb_request *req)
3513 connection_struct *conn = req->conn;
3514 char *name = NULL;
3515 struct smb_filename *smb_fname = NULL;
3516 uint32_t dirtype;
3517 NTSTATUS status;
3518 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
3519 ucf_flags_from_smb_request(req);
3520 TALLOC_CTX *ctx = talloc_tos();
3521 bool has_wild = false;
3523 START_PROFILE(SMBunlink);
3525 if (req->wct < 1) {
3526 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3527 goto out;
3530 dirtype = SVAL(req->vwv+0, 0);
3532 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
3533 STR_TERMINATE, &status);
3534 if (!NT_STATUS_IS_OK(status)) {
3535 reply_nterror(req, status);
3536 goto out;
3539 status = filename_convert(ctx, conn,
3540 name,
3541 ucf_flags,
3543 &smb_fname);
3544 if (!NT_STATUS_IS_OK(status)) {
3545 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3546 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3547 ERRSRV, ERRbadpath);
3548 goto out;
3550 reply_nterror(req, status);
3551 goto out;
3554 if (req != NULL && !req->posix_pathnames) {
3555 char *lcomp = get_original_lcomp(ctx,
3556 conn,
3557 name,
3558 ucf_flags);
3559 if (lcomp == NULL) {
3560 reply_nterror(req, NT_STATUS_NO_MEMORY);
3561 goto out;
3563 has_wild = ms_has_wild(lcomp);
3564 TALLOC_FREE(lcomp);
3567 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3569 status = unlink_internals(conn, req, dirtype, smb_fname, has_wild);
3570 if (!NT_STATUS_IS_OK(status)) {
3571 if (open_was_deferred(req->xconn, req->mid)) {
3572 /* We have re-scheduled this call. */
3573 goto out;
3575 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3576 bool ok = defer_smb1_sharing_violation(req);
3577 if (ok) {
3578 goto out;
3581 reply_nterror(req, status);
3582 goto out;
3585 reply_outbuf(req, 0, 0);
3586 out:
3587 TALLOC_FREE(smb_fname);
3588 END_PROFILE(SMBunlink);
3589 return;
3592 /****************************************************************************
3593 Fail for readbraw.
3594 ****************************************************************************/
3596 static void fail_readraw(void)
3598 const char *errstr = talloc_asprintf(talloc_tos(),
3599 "FAIL ! reply_readbraw: socket write fail (%s)",
3600 strerror(errno));
3601 if (!errstr) {
3602 errstr = "";
3604 exit_server_cleanly(errstr);
3607 /****************************************************************************
3608 Fake (read/write) sendfile. Returns -1 on read or write fail.
3609 ****************************************************************************/
3611 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3612 off_t startpos, size_t nread)
3614 size_t bufsize;
3615 size_t tosend = nread;
3616 char *buf;
3618 if (nread == 0) {
3619 return 0;
3622 bufsize = MIN(nread, 65536);
3624 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3625 return -1;
3628 while (tosend > 0) {
3629 ssize_t ret;
3630 size_t cur_read;
3632 cur_read = MIN(tosend, bufsize);
3633 ret = read_file(fsp,buf,startpos,cur_read);
3634 if (ret == -1) {
3635 SAFE_FREE(buf);
3636 return -1;
3639 /* If we had a short read, fill with zeros. */
3640 if (ret < cur_read) {
3641 memset(buf + ret, '\0', cur_read - ret);
3644 ret = write_data(xconn->transport.sock, buf, cur_read);
3645 if (ret != cur_read) {
3646 int saved_errno = errno;
3648 * Try and give an error message saying what
3649 * client failed.
3651 DEBUG(0, ("write_data failed for client %s. "
3652 "Error %s\n",
3653 smbXsrv_connection_dbg(xconn),
3654 strerror(saved_errno)));
3655 SAFE_FREE(buf);
3656 errno = saved_errno;
3657 return -1;
3659 tosend -= cur_read;
3660 startpos += cur_read;
3663 SAFE_FREE(buf);
3664 return (ssize_t)nread;
3667 /****************************************************************************
3668 Deal with the case of sendfile reading less bytes from the file than
3669 requested. Fill with zeros (all we can do). Returns 0 on success
3670 ****************************************************************************/
3672 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3673 files_struct *fsp,
3674 ssize_t nread,
3675 size_t headersize,
3676 size_t smb_maxcnt)
3678 #define SHORT_SEND_BUFSIZE 1024
3679 if (nread < headersize) {
3680 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3681 "header for file %s (%s). Terminating\n",
3682 fsp_str_dbg(fsp), strerror(errno)));
3683 return -1;
3686 nread -= headersize;
3688 if (nread < smb_maxcnt) {
3689 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3690 if (!buf) {
3691 DEBUG(0,("sendfile_short_send: malloc failed "
3692 "for file %s (%s). Terminating\n",
3693 fsp_str_dbg(fsp), strerror(errno)));
3694 return -1;
3697 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3698 "with zeros !\n", fsp_str_dbg(fsp)));
3700 while (nread < smb_maxcnt) {
3702 * We asked for the real file size and told sendfile
3703 * to not go beyond the end of the file. But it can
3704 * happen that in between our fstat call and the
3705 * sendfile call the file was truncated. This is very
3706 * bad because we have already announced the larger
3707 * number of bytes to the client.
3709 * The best we can do now is to send 0-bytes, just as
3710 * a read from a hole in a sparse file would do.
3712 * This should happen rarely enough that I don't care
3713 * about efficiency here :-)
3715 size_t to_write;
3716 ssize_t ret;
3718 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3719 ret = write_data(xconn->transport.sock, buf, to_write);
3720 if (ret != to_write) {
3721 int saved_errno = errno;
3723 * Try and give an error message saying what
3724 * client failed.
3726 DEBUG(0, ("write_data failed for client %s. "
3727 "Error %s\n",
3728 smbXsrv_connection_dbg(xconn),
3729 strerror(saved_errno)));
3730 errno = saved_errno;
3731 return -1;
3733 nread += to_write;
3735 SAFE_FREE(buf);
3738 return 0;
3741 /****************************************************************************
3742 Return a readbraw error (4 bytes of zero).
3743 ****************************************************************************/
3745 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3747 char header[4];
3749 SIVAL(header,0,0);
3751 smbd_lock_socket(xconn);
3752 if (write_data(xconn->transport.sock,header,4) != 4) {
3753 int saved_errno = errno;
3755 * Try and give an error message saying what
3756 * client failed.
3758 DEBUG(0, ("write_data failed for client %s. "
3759 "Error %s\n",
3760 smbXsrv_connection_dbg(xconn),
3761 strerror(saved_errno)));
3762 errno = saved_errno;
3764 fail_readraw();
3766 smbd_unlock_socket(xconn);
3769 /*******************************************************************
3770 Ensure we don't use sendfile if server smb signing is active.
3771 ********************************************************************/
3773 static bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state)
3775 bool sign_active = false;
3777 /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
3778 if (get_Protocol() < PROTOCOL_NT1) {
3779 return false;
3781 if (signing_state) {
3782 sign_active = smb_signing_is_active(signing_state);
3784 return (lp__use_sendfile(snum) &&
3785 (get_remote_arch() != RA_WIN95) &&
3786 !sign_active);
3788 /****************************************************************************
3789 Use sendfile in readbraw.
3790 ****************************************************************************/
3792 static void send_file_readbraw(connection_struct *conn,
3793 struct smb_request *req,
3794 files_struct *fsp,
3795 off_t startpos,
3796 size_t nread,
3797 ssize_t mincount)
3799 struct smbXsrv_connection *xconn = req->xconn;
3800 char *outbuf = NULL;
3801 ssize_t ret=0;
3804 * We can only use sendfile on a non-chained packet
3805 * but we can use on a non-oplocked file. tridge proved this
3806 * on a train in Germany :-). JRA.
3807 * reply_readbraw has already checked the length.
3810 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3811 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3812 ssize_t sendfile_read = -1;
3813 char header[4];
3814 DATA_BLOB header_blob;
3816 _smb_setlen(header,nread);
3817 header_blob = data_blob_const(header, 4);
3819 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3820 &header_blob, startpos,
3821 nread);
3822 if (sendfile_read == -1) {
3823 /* Returning ENOSYS means no data at all was sent.
3824 * Do this as a normal read. */
3825 if (errno == ENOSYS) {
3826 goto normal_readbraw;
3830 * Special hack for broken Linux with no working sendfile. If we
3831 * return EINTR we sent the header but not the rest of the data.
3832 * Fake this up by doing read/write calls.
3834 if (errno == EINTR) {
3835 /* Ensure we don't do this again. */
3836 set_use_sendfile(SNUM(conn), False);
3837 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3839 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3840 DEBUG(0,("send_file_readbraw: "
3841 "fake_sendfile failed for "
3842 "file %s (%s).\n",
3843 fsp_str_dbg(fsp),
3844 strerror(errno)));
3845 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3847 return;
3850 DEBUG(0,("send_file_readbraw: sendfile failed for "
3851 "file %s (%s). Terminating\n",
3852 fsp_str_dbg(fsp), strerror(errno)));
3853 exit_server_cleanly("send_file_readbraw sendfile failed");
3854 } else if (sendfile_read == 0) {
3856 * Some sendfile implementations return 0 to indicate
3857 * that there was a short read, but nothing was
3858 * actually written to the socket. In this case,
3859 * fallback to the normal read path so the header gets
3860 * the correct byte count.
3862 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3863 "bytes falling back to the normal read: "
3864 "%s\n", fsp_str_dbg(fsp)));
3865 goto normal_readbraw;
3868 /* Deal with possible short send. */
3869 if (sendfile_read != 4+nread) {
3870 ret = sendfile_short_send(xconn, fsp,
3871 sendfile_read, 4, nread);
3872 if (ret == -1) {
3873 fail_readraw();
3876 return;
3879 normal_readbraw:
3881 outbuf = talloc_array(NULL, char, nread+4);
3882 if (!outbuf) {
3883 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3884 (unsigned)(nread+4)));
3885 reply_readbraw_error(xconn);
3886 return;
3889 if (nread > 0) {
3890 ret = read_file(fsp,outbuf+4,startpos,nread);
3891 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3892 if (ret < mincount)
3893 ret = 0;
3894 #else
3895 if (ret < nread)
3896 ret = 0;
3897 #endif
3900 _smb_setlen(outbuf,ret);
3901 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3902 int saved_errno = errno;
3904 * Try and give an error message saying what
3905 * client failed.
3907 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3908 smbXsrv_connection_dbg(xconn),
3909 strerror(saved_errno)));
3910 errno = saved_errno;
3912 fail_readraw();
3915 TALLOC_FREE(outbuf);
3918 /****************************************************************************
3919 Reply to a readbraw (core+ protocol).
3920 ****************************************************************************/
3922 void reply_readbraw(struct smb_request *req)
3924 connection_struct *conn = req->conn;
3925 struct smbXsrv_connection *xconn = req->xconn;
3926 ssize_t maxcount,mincount;
3927 size_t nread = 0;
3928 off_t startpos;
3929 files_struct *fsp;
3930 struct lock_struct lock;
3931 off_t size = 0;
3932 NTSTATUS status;
3934 START_PROFILE(SMBreadbraw);
3936 if (srv_is_signing_active(xconn) || req->encrypted) {
3937 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3938 "raw reads/writes are disallowed.");
3941 if (req->wct < 8) {
3942 reply_readbraw_error(xconn);
3943 END_PROFILE(SMBreadbraw);
3944 return;
3947 if (xconn->smb1.echo_handler.trusted_fde) {
3948 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3949 "'async smb echo handler = yes'\n"));
3950 reply_readbraw_error(xconn);
3951 END_PROFILE(SMBreadbraw);
3952 return;
3956 * Special check if an oplock break has been issued
3957 * and the readraw request croses on the wire, we must
3958 * return a zero length response here.
3961 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3964 * We have to do a check_fsp by hand here, as
3965 * we must always return 4 zero bytes on error,
3966 * not a NTSTATUS.
3969 if (fsp == NULL ||
3970 conn == NULL ||
3971 conn != fsp->conn ||
3972 req->vuid != fsp->vuid ||
3973 fsp->fsp_flags.is_directory ||
3974 fsp_get_io_fd(fsp) == -1)
3977 * fsp could be NULL here so use the value from the packet. JRA.
3979 DEBUG(3,("reply_readbraw: fnum %d not valid "
3980 "- cache prime?\n",
3981 (int)SVAL(req->vwv+0, 0)));
3982 reply_readbraw_error(xconn);
3983 END_PROFILE(SMBreadbraw);
3984 return;
3987 /* Do a "by hand" version of CHECK_READ. */
3988 if (!(fsp->fsp_flags.can_read ||
3989 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3990 (fsp->access_mask & FILE_EXECUTE)))) {
3991 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3992 (int)SVAL(req->vwv+0, 0)));
3993 reply_readbraw_error(xconn);
3994 END_PROFILE(SMBreadbraw);
3995 return;
3998 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3999 if(req->wct == 10) {
4001 * This is a large offset (64 bit) read.
4004 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
4006 if(startpos < 0) {
4007 DEBUG(0,("reply_readbraw: negative 64 bit "
4008 "readraw offset (%.0f) !\n",
4009 (double)startpos ));
4010 reply_readbraw_error(xconn);
4011 END_PROFILE(SMBreadbraw);
4012 return;
4016 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
4017 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
4019 /* ensure we don't overrun the packet size */
4020 maxcount = MIN(65535,maxcount);
4022 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4023 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
4024 &lock);
4026 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4027 reply_readbraw_error(xconn);
4028 END_PROFILE(SMBreadbraw);
4029 return;
4032 status = vfs_stat_fsp(fsp);
4033 if (NT_STATUS_IS_OK(status)) {
4034 size = fsp->fsp_name->st.st_ex_size;
4037 if (startpos >= size) {
4038 nread = 0;
4039 } else {
4040 nread = MIN(maxcount,(size - startpos));
4043 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
4044 if (nread < mincount)
4045 nread = 0;
4046 #endif
4048 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
4049 "min=%lu nread=%lu\n",
4050 fsp_fnum_dbg(fsp), (double)startpos,
4051 (unsigned long)maxcount,
4052 (unsigned long)mincount,
4053 (unsigned long)nread ) );
4055 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
4057 DEBUG(5,("reply_readbraw finished\n"));
4059 END_PROFILE(SMBreadbraw);
4060 return;
4063 #undef DBGC_CLASS
4064 #define DBGC_CLASS DBGC_LOCKING
4066 /****************************************************************************
4067 Reply to a lockread (core+ protocol).
4068 ****************************************************************************/
4070 static void reply_lockread_locked(struct tevent_req *subreq);
4072 void reply_lockread(struct smb_request *req)
4074 struct tevent_req *subreq = NULL;
4075 connection_struct *conn = req->conn;
4076 files_struct *fsp;
4077 struct smbd_lock_element *lck = NULL;
4079 START_PROFILE(SMBlockread);
4081 if (req->wct < 5) {
4082 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4083 END_PROFILE(SMBlockread);
4084 return;
4087 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4089 if (!check_fsp(conn, req, fsp)) {
4090 END_PROFILE(SMBlockread);
4091 return;
4094 if (!CHECK_READ(fsp,req)) {
4095 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4096 END_PROFILE(SMBlockread);
4097 return;
4100 lck = talloc(req, struct smbd_lock_element);
4101 if (lck == NULL) {
4102 reply_nterror(req, NT_STATUS_NO_MEMORY);
4103 END_PROFILE(SMBlockread);
4104 return;
4108 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
4109 * protocol request that predates the read/write lock concept.
4110 * Thus instead of asking for a read lock here we need to ask
4111 * for a write lock. JRA.
4112 * Note that the requested lock size is unaffected by max_send.
4115 *lck = (struct smbd_lock_element) {
4116 .req_guid = smbd_request_guid(req, 0),
4117 .smblctx = req->smbpid,
4118 .brltype = WRITE_LOCK,
4119 .count = SVAL(req->vwv+1, 0),
4120 .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
4123 subreq = smbd_smb1_do_locks_send(
4124 fsp,
4125 req->sconn->ev_ctx,
4126 &req,
4127 fsp,
4129 false, /* large_offset */
4130 WINDOWS_LOCK,
4132 lck);
4133 if (subreq == NULL) {
4134 reply_nterror(req, NT_STATUS_NO_MEMORY);
4135 END_PROFILE(SMBlockread);
4136 return;
4138 tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
4139 END_PROFILE(SMBlockread);
4142 static void reply_lockread_locked(struct tevent_req *subreq)
4144 struct smb_request *req = NULL;
4145 ssize_t nread = -1;
4146 char *data = NULL;
4147 NTSTATUS status;
4148 bool ok;
4149 off_t startpos;
4150 size_t numtoread, maxtoread;
4151 struct files_struct *fsp = NULL;
4152 char *p = NULL;
4154 START_PROFILE(SMBlockread);
4156 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
4157 SMB_ASSERT(ok);
4159 status = smbd_smb1_do_locks_recv(subreq);
4160 TALLOC_FREE(subreq);
4162 if (!NT_STATUS_IS_OK(status)) {
4163 reply_nterror(req, status);
4164 goto send;
4167 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4168 if (fsp == NULL) {
4169 reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
4170 goto send;
4173 numtoread = SVAL(req->vwv+1, 0);
4174 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4177 * However the requested READ size IS affected by max_send. Insanity.... JRA.
4179 maxtoread = req->xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4181 if (numtoread > maxtoread) {
4182 DBG_WARNING("requested read size (%zu) is greater than "
4183 "maximum allowed (%zu/%d). "
4184 "Returning short read of maximum allowed for "
4185 "compatibility with Windows 2000.\n",
4186 numtoread,
4187 maxtoread,
4188 req->xconn->smb1.sessions.max_send);
4189 numtoread = maxtoread;
4192 reply_outbuf(req, 5, numtoread + 3);
4194 data = smb_buf(req->outbuf) + 3;
4196 nread = read_file(fsp,data,startpos,numtoread);
4198 if (nread < 0) {
4199 reply_nterror(req, map_nt_error_from_unix(errno));
4200 goto send;
4203 srv_set_message((char *)req->outbuf, 5, nread+3, False);
4205 SSVAL(req->outbuf,smb_vwv0,nread);
4206 SSVAL(req->outbuf,smb_vwv5,nread+3);
4207 p = smb_buf(req->outbuf);
4208 SCVAL(p,0,0); /* pad byte. */
4209 SSVAL(p,1,nread);
4211 DEBUG(3,("lockread %s num=%d nread=%d\n",
4212 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4214 send:
4215 ok = srv_send_smb(req->xconn,
4216 (char *)req->outbuf,
4217 true,
4218 req->seqnum+1,
4219 IS_CONN_ENCRYPTED(req->conn),
4220 NULL);
4221 if (!ok) {
4222 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
4224 TALLOC_FREE(req);
4225 END_PROFILE(SMBlockread);
4226 return;
4229 #undef DBGC_CLASS
4230 #define DBGC_CLASS DBGC_ALL
4232 /****************************************************************************
4233 Reply to a read.
4234 ****************************************************************************/
4236 void reply_read(struct smb_request *req)
4238 connection_struct *conn = req->conn;
4239 size_t numtoread;
4240 size_t maxtoread;
4241 ssize_t nread = 0;
4242 char *data;
4243 off_t startpos;
4244 files_struct *fsp;
4245 struct lock_struct lock;
4246 struct smbXsrv_connection *xconn = req->xconn;
4248 START_PROFILE(SMBread);
4250 if (req->wct < 3) {
4251 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4252 END_PROFILE(SMBread);
4253 return;
4256 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4258 if (!check_fsp(conn, req, fsp)) {
4259 END_PROFILE(SMBread);
4260 return;
4263 if (!CHECK_READ(fsp,req)) {
4264 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4265 END_PROFILE(SMBread);
4266 return;
4269 numtoread = SVAL(req->vwv+1, 0);
4270 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4273 * The requested read size cannot be greater than max_send. JRA.
4275 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4277 if (numtoread > maxtoread) {
4278 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
4279 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
4280 (unsigned int)numtoread, (unsigned int)maxtoread,
4281 (unsigned int)xconn->smb1.sessions.max_send));
4282 numtoread = maxtoread;
4285 reply_outbuf(req, 5, numtoread+3);
4287 data = smb_buf(req->outbuf) + 3;
4289 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4290 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
4291 &lock);
4293 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4294 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4295 END_PROFILE(SMBread);
4296 return;
4299 if (numtoread > 0)
4300 nread = read_file(fsp,data,startpos,numtoread);
4302 if (nread < 0) {
4303 reply_nterror(req, map_nt_error_from_unix(errno));
4304 goto out;
4307 srv_set_message((char *)req->outbuf, 5, nread+3, False);
4309 SSVAL(req->outbuf,smb_vwv0,nread);
4310 SSVAL(req->outbuf,smb_vwv5,nread+3);
4311 SCVAL(smb_buf(req->outbuf),0,1);
4312 SSVAL(smb_buf(req->outbuf),1,nread);
4314 DEBUG(3, ("read %s num=%d nread=%d\n",
4315 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4317 out:
4318 END_PROFILE(SMBread);
4319 return;
4322 /****************************************************************************
4323 Setup readX header.
4324 ****************************************************************************/
4326 size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
4328 size_t outsize;
4330 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
4331 False);
4333 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
4335 SCVAL(outbuf,smb_vwv0,0xFF);
4336 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
4337 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
4338 SSVAL(outbuf,smb_vwv6,
4339 (smb_wct - 4) /* offset from smb header to wct */
4340 + 1 /* the wct field */
4341 + 12 * sizeof(uint16_t) /* vwv */
4342 + 2 /* the buflen field */
4343 + 1); /* padding byte */
4344 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
4345 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
4346 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
4347 _smb_setlen_large(outbuf,
4348 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
4349 return outsize;
4352 /****************************************************************************
4353 Reply to a read and X - possibly using sendfile.
4354 ****************************************************************************/
4356 static void send_file_readX(connection_struct *conn, struct smb_request *req,
4357 files_struct *fsp, off_t startpos,
4358 size_t smb_maxcnt)
4360 struct smbXsrv_connection *xconn = req->xconn;
4361 ssize_t nread = -1;
4362 struct lock_struct lock;
4363 int saved_errno = 0;
4364 NTSTATUS status;
4366 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4367 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
4368 &lock);
4370 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4371 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4372 return;
4376 * We can only use sendfile on a non-chained packet
4377 * but we can use on a non-oplocked file. tridge proved this
4378 * on a train in Germany :-). JRA.
4381 if (!req_is_in_chain(req) &&
4382 !req->encrypted &&
4383 (fsp->base_fsp == NULL) &&
4384 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
4385 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
4386 DATA_BLOB header;
4388 status = vfs_stat_fsp(fsp);
4389 if (!NT_STATUS_IS_OK(status)) {
4390 reply_nterror(req, status);
4391 goto out;
4394 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4395 (startpos > fsp->fsp_name->st.st_ex_size) ||
4396 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4398 * We already know that we would do a short read, so don't
4399 * try the sendfile() path.
4401 goto nosendfile_read;
4405 * Set up the packet header before send. We
4406 * assume here the sendfile will work (get the
4407 * correct amount of data).
4410 header = data_blob_const(headerbuf, sizeof(headerbuf));
4412 construct_reply_common_req(req, (char *)headerbuf);
4413 setup_readX_header((char *)headerbuf, smb_maxcnt);
4415 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4416 startpos, smb_maxcnt);
4417 if (nread == -1) {
4418 saved_errno = errno;
4420 /* Returning ENOSYS means no data at all was sent.
4421 Do this as a normal read. */
4422 if (errno == ENOSYS) {
4423 goto normal_read;
4427 * Special hack for broken Linux with no working sendfile. If we
4428 * return EINTR we sent the header but not the rest of the data.
4429 * Fake this up by doing read/write calls.
4432 if (errno == EINTR) {
4433 /* Ensure we don't do this again. */
4434 set_use_sendfile(SNUM(conn), False);
4435 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4436 nread = fake_sendfile(xconn, fsp, startpos,
4437 smb_maxcnt);
4438 if (nread == -1) {
4439 saved_errno = errno;
4440 DEBUG(0,("send_file_readX: "
4441 "fake_sendfile failed for "
4442 "file %s (%s) for client %s. "
4443 "Terminating\n",
4444 fsp_str_dbg(fsp),
4445 smbXsrv_connection_dbg(xconn),
4446 strerror(saved_errno)));
4447 errno = saved_errno;
4448 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4450 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4451 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4452 /* No outbuf here means successful sendfile. */
4453 goto out;
4456 DEBUG(0,("send_file_readX: sendfile failed for file "
4457 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4458 strerror(errno)));
4459 exit_server_cleanly("send_file_readX sendfile failed");
4460 } else if (nread == 0) {
4462 * Some sendfile implementations return 0 to indicate
4463 * that there was a short read, but nothing was
4464 * actually written to the socket. In this case,
4465 * fallback to the normal read path so the header gets
4466 * the correct byte count.
4468 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4469 "falling back to the normal read: %s\n",
4470 fsp_str_dbg(fsp)));
4471 goto normal_read;
4474 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4475 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4477 /* Deal with possible short send. */
4478 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4479 ssize_t ret;
4481 ret = sendfile_short_send(xconn, fsp, nread,
4482 sizeof(headerbuf), smb_maxcnt);
4483 if (ret == -1) {
4484 const char *r;
4485 r = "send_file_readX: sendfile_short_send failed";
4486 DEBUG(0,("%s for file %s (%s).\n",
4487 r, fsp_str_dbg(fsp), strerror(errno)));
4488 exit_server_cleanly(r);
4491 /* No outbuf here means successful sendfile. */
4492 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4493 SMB_PERFCOUNT_END(&req->pcd);
4494 goto out;
4497 normal_read:
4499 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4500 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4501 ssize_t ret;
4503 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4504 (startpos > fsp->fsp_name->st.st_ex_size) ||
4505 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4507 * We already know that we would do a short
4508 * read, so don't try the sendfile() path.
4510 goto nosendfile_read;
4513 construct_reply_common_req(req, (char *)headerbuf);
4514 setup_readX_header((char *)headerbuf, smb_maxcnt);
4516 /* Send out the header. */
4517 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4518 sizeof(headerbuf));
4519 if (ret != sizeof(headerbuf)) {
4520 saved_errno = errno;
4522 * Try and give an error message saying what
4523 * client failed.
4525 DEBUG(0,("send_file_readX: write_data failed for file "
4526 "%s (%s) for client %s. Terminating\n",
4527 fsp_str_dbg(fsp),
4528 smbXsrv_connection_dbg(xconn),
4529 strerror(saved_errno)));
4530 errno = saved_errno;
4531 exit_server_cleanly("send_file_readX sendfile failed");
4533 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4534 if (nread == -1) {
4535 saved_errno = errno;
4536 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4537 "%s (%s) for client %s. Terminating\n",
4538 fsp_str_dbg(fsp),
4539 smbXsrv_connection_dbg(xconn),
4540 strerror(saved_errno)));
4541 errno = saved_errno;
4542 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4544 goto out;
4547 nosendfile_read:
4549 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4550 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4551 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4553 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4554 startpos, smb_maxcnt);
4555 saved_errno = errno;
4557 if (nread < 0) {
4558 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4559 return;
4562 setup_readX_header((char *)req->outbuf, nread);
4564 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4565 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4566 return;
4568 out:
4569 TALLOC_FREE(req->outbuf);
4570 return;
4573 /****************************************************************************
4574 Work out how much space we have for a read return.
4575 ****************************************************************************/
4577 static size_t calc_max_read_pdu(const struct smb_request *req)
4579 struct smbXsrv_connection *xconn = req->xconn;
4581 if (xconn->protocol < PROTOCOL_NT1) {
4582 return xconn->smb1.sessions.max_send;
4585 if (!lp_large_readwrite()) {
4586 return xconn->smb1.sessions.max_send;
4589 if (req_is_in_chain(req)) {
4590 return xconn->smb1.sessions.max_send;
4593 if (req->encrypted) {
4595 * Don't take encrypted traffic up to the
4596 * limit. There are padding considerations
4597 * that make that tricky.
4599 return xconn->smb1.sessions.max_send;
4602 if (srv_is_signing_active(xconn)) {
4603 return 0x1FFFF;
4606 if (!lp_unix_extensions()) {
4607 return 0x1FFFF;
4611 * We can do ultra-large POSIX reads.
4613 return 0xFFFFFF;
4616 /****************************************************************************
4617 Calculate how big a read can be. Copes with all clients. It's always
4618 safe to return a short read - Windows does this.
4619 ****************************************************************************/
4621 static size_t calc_read_size(const struct smb_request *req,
4622 size_t upper_size,
4623 size_t lower_size)
4625 struct smbXsrv_connection *xconn = req->xconn;
4626 size_t max_pdu = calc_max_read_pdu(req);
4627 size_t total_size = 0;
4628 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4629 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4632 * Windows explicitly ignores upper size of 0xFFFF.
4633 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4634 * We must do the same as these will never fit even in
4635 * an extended size NetBIOS packet.
4637 if (upper_size == 0xFFFF) {
4638 upper_size = 0;
4641 if (xconn->protocol < PROTOCOL_NT1) {
4642 upper_size = 0;
4645 total_size = ((upper_size<<16) | lower_size);
4648 * LARGE_READX test shows it's always safe to return
4649 * a short read. Windows does so.
4651 return MIN(total_size, max_len);
4654 /****************************************************************************
4655 Reply to a read and X.
4656 ****************************************************************************/
4658 void reply_read_and_X(struct smb_request *req)
4660 connection_struct *conn = req->conn;
4661 files_struct *fsp;
4662 off_t startpos;
4663 size_t smb_maxcnt;
4664 size_t upper_size;
4665 bool big_readX = False;
4666 #if 0
4667 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4668 #endif
4670 START_PROFILE(SMBreadX);
4672 if ((req->wct != 10) && (req->wct != 12)) {
4673 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4674 return;
4677 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4678 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4679 smb_maxcnt = SVAL(req->vwv+5, 0);
4681 /* If it's an IPC, pass off the pipe handler. */
4682 if (IS_IPC(conn)) {
4683 reply_pipe_read_and_X(req);
4684 END_PROFILE(SMBreadX);
4685 return;
4688 if (!check_fsp(conn, req, fsp)) {
4689 END_PROFILE(SMBreadX);
4690 return;
4693 if (!CHECK_READ(fsp,req)) {
4694 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4695 END_PROFILE(SMBreadX);
4696 return;
4699 upper_size = SVAL(req->vwv+7, 0);
4700 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4701 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4703 * This is a heuristic to avoid keeping large
4704 * outgoing buffers around over long-lived aio
4705 * requests.
4707 big_readX = True;
4710 if (req->wct == 12) {
4712 * This is a large offset (64 bit) read.
4714 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4718 if (!big_readX) {
4719 NTSTATUS status = schedule_aio_read_and_X(conn,
4720 req,
4721 fsp,
4722 startpos,
4723 smb_maxcnt);
4724 if (NT_STATUS_IS_OK(status)) {
4725 /* Read scheduled - we're done. */
4726 goto out;
4728 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4729 /* Real error - report to client. */
4730 END_PROFILE(SMBreadX);
4731 reply_nterror(req, status);
4732 return;
4734 /* NT_STATUS_RETRY - fall back to sync read. */
4737 smbd_lock_socket(req->xconn);
4738 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4739 smbd_unlock_socket(req->xconn);
4741 out:
4742 END_PROFILE(SMBreadX);
4743 return;
4746 /****************************************************************************
4747 Error replies to writebraw must have smb_wct == 1. Fix this up.
4748 ****************************************************************************/
4750 void error_to_writebrawerr(struct smb_request *req)
4752 uint8_t *old_outbuf = req->outbuf;
4754 reply_outbuf(req, 1, 0);
4756 memcpy(req->outbuf, old_outbuf, smb_size);
4757 TALLOC_FREE(old_outbuf);
4760 /****************************************************************************
4761 Read 4 bytes of a smb packet and return the smb length of the packet.
4762 Store the result in the buffer. This version of the function will
4763 never return a session keepalive (length of zero).
4764 Timeout is in milliseconds.
4765 ****************************************************************************/
4767 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4768 size_t *len)
4770 uint8_t msgtype = NBSSkeepalive;
4772 while (msgtype == NBSSkeepalive) {
4773 NTSTATUS status;
4775 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4776 len);
4777 if (!NT_STATUS_IS_OK(status)) {
4778 char addr[INET6_ADDRSTRLEN];
4779 /* Try and give an error message
4780 * saying what client failed. */
4781 DEBUG(0, ("read_smb_length_return_keepalive failed for "
4782 "client %s read error = %s.\n",
4783 get_peer_addr(fd,addr,sizeof(addr)),
4784 nt_errstr(status)));
4785 return status;
4788 msgtype = CVAL(inbuf, 0);
4791 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4792 (unsigned long)len));
4794 return NT_STATUS_OK;
4797 /****************************************************************************
4798 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4799 ****************************************************************************/
4801 void reply_writebraw(struct smb_request *req)
4803 connection_struct *conn = req->conn;
4804 struct smbXsrv_connection *xconn = req->xconn;
4805 char *buf = NULL;
4806 ssize_t nwritten=0;
4807 ssize_t total_written=0;
4808 size_t numtowrite=0;
4809 size_t tcount;
4810 off_t startpos;
4811 const char *data=NULL;
4812 bool write_through;
4813 files_struct *fsp;
4814 struct lock_struct lock;
4815 NTSTATUS status;
4817 START_PROFILE(SMBwritebraw);
4820 * If we ever reply with an error, it must have the SMB command
4821 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4822 * we're finished.
4824 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4826 if (srv_is_signing_active(xconn)) {
4827 END_PROFILE(SMBwritebraw);
4828 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4829 "raw reads/writes are disallowed.");
4832 if (req->wct < 12) {
4833 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4834 error_to_writebrawerr(req);
4835 END_PROFILE(SMBwritebraw);
4836 return;
4839 if (xconn->smb1.echo_handler.trusted_fde) {
4840 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4841 "'async smb echo handler = yes'\n"));
4842 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4843 error_to_writebrawerr(req);
4844 END_PROFILE(SMBwritebraw);
4845 return;
4848 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4849 if (!check_fsp(conn, req, fsp)) {
4850 error_to_writebrawerr(req);
4851 END_PROFILE(SMBwritebraw);
4852 return;
4855 if (!CHECK_WRITE(fsp)) {
4856 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4857 error_to_writebrawerr(req);
4858 END_PROFILE(SMBwritebraw);
4859 return;
4862 tcount = IVAL(req->vwv+1, 0);
4863 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4864 write_through = BITSETW(req->vwv+7,0);
4866 /* We have to deal with slightly different formats depending
4867 on whether we are using the core+ or lanman1.0 protocol */
4869 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4870 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4871 data = smb_buf_const(req->inbuf);
4872 } else {
4873 numtowrite = SVAL(req->vwv+10, 0);
4874 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4877 /* Ensure we don't write bytes past the end of this packet. */
4879 * This already protects us against CVE-2017-12163.
4881 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4882 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4883 error_to_writebrawerr(req);
4884 END_PROFILE(SMBwritebraw);
4885 return;
4888 if (!fsp->print_file) {
4889 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4890 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4891 &lock);
4893 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4894 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4895 error_to_writebrawerr(req);
4896 END_PROFILE(SMBwritebraw);
4897 return;
4901 if (numtowrite>0) {
4902 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4905 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4906 "wrote=%d sync=%d\n",
4907 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4908 (int)nwritten, (int)write_through));
4910 if (nwritten < (ssize_t)numtowrite) {
4911 reply_nterror(req, NT_STATUS_DISK_FULL);
4912 error_to_writebrawerr(req);
4913 goto out;
4916 total_written = nwritten;
4918 /* Allocate a buffer of 64k + length. */
4919 buf = talloc_array(NULL, char, 65540);
4920 if (!buf) {
4921 reply_nterror(req, NT_STATUS_NO_MEMORY);
4922 error_to_writebrawerr(req);
4923 goto out;
4926 /* Return a SMBwritebraw message to the redirector to tell
4927 * it to send more bytes */
4929 memcpy(buf, req->inbuf, smb_size);
4930 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4931 SCVAL(buf,smb_com,SMBwritebraw);
4932 SSVALS(buf,smb_vwv0,0xFFFF);
4933 show_msg(buf);
4934 if (!srv_send_smb(req->xconn,
4935 buf,
4936 false, 0, /* no signing */
4937 IS_CONN_ENCRYPTED(conn),
4938 &req->pcd)) {
4939 exit_server_cleanly("reply_writebraw: srv_send_smb "
4940 "failed.");
4943 /* Now read the raw data into the buffer and write it */
4944 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4945 &numtowrite);
4946 if (!NT_STATUS_IS_OK(status)) {
4947 exit_server_cleanly("secondary writebraw failed");
4950 /* Set up outbuf to return the correct size */
4951 reply_outbuf(req, 1, 0);
4953 if (numtowrite != 0) {
4955 if (numtowrite > 0xFFFF) {
4956 DEBUG(0,("reply_writebraw: Oversize secondary write "
4957 "raw requested (%u). Terminating\n",
4958 (unsigned int)numtowrite ));
4959 exit_server_cleanly("secondary writebraw failed");
4962 if (tcount > nwritten+numtowrite) {
4963 DEBUG(3,("reply_writebraw: Client overestimated the "
4964 "write %d %d %d\n",
4965 (int)tcount,(int)nwritten,(int)numtowrite));
4968 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4969 numtowrite);
4971 if (!NT_STATUS_IS_OK(status)) {
4972 /* Try and give an error message
4973 * saying what client failed. */
4974 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4975 "raw read failed (%s) for client %s. "
4976 "Terminating\n", nt_errstr(status),
4977 smbXsrv_connection_dbg(xconn)));
4978 exit_server_cleanly("secondary writebraw failed");
4982 * We are not vulnerable to CVE-2017-12163
4983 * here as we are guaranteed to have numtowrite
4984 * bytes available - we just read from the client.
4986 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4987 if (nwritten == -1) {
4988 TALLOC_FREE(buf);
4989 reply_nterror(req, map_nt_error_from_unix(errno));
4990 error_to_writebrawerr(req);
4991 goto out;
4994 if (nwritten < (ssize_t)numtowrite) {
4995 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4996 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4999 if (nwritten > 0) {
5000 total_written += nwritten;
5004 TALLOC_FREE(buf);
5005 SSVAL(req->outbuf,smb_vwv0,total_written);
5007 status = sync_file(conn, fsp, write_through);
5008 if (!NT_STATUS_IS_OK(status)) {
5009 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
5010 fsp_str_dbg(fsp), nt_errstr(status)));
5011 reply_nterror(req, status);
5012 error_to_writebrawerr(req);
5013 goto out;
5016 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
5017 "wrote=%d\n",
5018 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
5019 (int)total_written));
5021 /* We won't return a status if write through is not selected - this
5022 * follows what WfWg does */
5023 END_PROFILE(SMBwritebraw);
5025 if (!write_through && total_written==tcount) {
5027 #if RABBIT_PELLET_FIX
5029 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
5030 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
5031 * JRA.
5033 if (!send_keepalive(xconn->transport.sock)) {
5034 exit_server_cleanly("reply_writebraw: send of "
5035 "keepalive failed");
5037 #endif
5038 TALLOC_FREE(req->outbuf);
5040 return;
5042 out:
5043 END_PROFILE(SMBwritebraw);
5044 return;
5047 #undef DBGC_CLASS
5048 #define DBGC_CLASS DBGC_LOCKING
5050 /****************************************************************************
5051 Reply to a writeunlock (core+).
5052 ****************************************************************************/
5054 void reply_writeunlock(struct smb_request *req)
5056 connection_struct *conn = req->conn;
5057 ssize_t nwritten = -1;
5058 size_t numtowrite;
5059 size_t remaining;
5060 off_t startpos;
5061 const char *data;
5062 NTSTATUS status = NT_STATUS_OK;
5063 files_struct *fsp;
5064 struct lock_struct lock;
5065 int saved_errno = 0;
5067 START_PROFILE(SMBwriteunlock);
5069 if (req->wct < 5) {
5070 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5071 END_PROFILE(SMBwriteunlock);
5072 return;
5075 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5077 if (!check_fsp(conn, req, fsp)) {
5078 END_PROFILE(SMBwriteunlock);
5079 return;
5082 if (!CHECK_WRITE(fsp)) {
5083 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5084 END_PROFILE(SMBwriteunlock);
5085 return;
5088 numtowrite = SVAL(req->vwv+1, 0);
5089 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5090 data = (const char *)req->buf + 3;
5093 * Ensure client isn't asking us to write more than
5094 * they sent. CVE-2017-12163.
5096 remaining = smbreq_bufrem(req, data);
5097 if (numtowrite > remaining) {
5098 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5099 END_PROFILE(SMBwriteunlock);
5100 return;
5103 if (!fsp->print_file && numtowrite > 0) {
5104 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5105 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5106 &lock);
5108 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5109 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5110 END_PROFILE(SMBwriteunlock);
5111 return;
5115 /* The special X/Open SMB protocol handling of
5116 zero length writes is *NOT* done for
5117 this call */
5118 if(numtowrite == 0) {
5119 nwritten = 0;
5120 } else {
5121 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5122 saved_errno = errno;
5125 status = sync_file(conn, fsp, False /* write through */);
5126 if (!NT_STATUS_IS_OK(status)) {
5127 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
5128 fsp_str_dbg(fsp), nt_errstr(status)));
5129 reply_nterror(req, status);
5130 goto out;
5133 if(nwritten < 0) {
5134 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5135 goto out;
5138 if((nwritten < numtowrite) && (numtowrite != 0)) {
5139 reply_nterror(req, NT_STATUS_DISK_FULL);
5140 goto out;
5143 if (numtowrite && !fsp->print_file) {
5144 struct smbd_lock_element l = {
5145 .req_guid = smbd_request_guid(req, 0),
5146 .smblctx = req->smbpid,
5147 .brltype = UNLOCK_LOCK,
5148 .offset = startpos,
5149 .count = numtowrite,
5151 status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
5152 if (NT_STATUS_V(status)) {
5153 reply_nterror(req, status);
5154 goto out;
5158 reply_outbuf(req, 1, 0);
5160 SSVAL(req->outbuf,smb_vwv0,nwritten);
5162 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
5163 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5165 out:
5166 END_PROFILE(SMBwriteunlock);
5167 return;
5170 #undef DBGC_CLASS
5171 #define DBGC_CLASS DBGC_ALL
5173 /****************************************************************************
5174 Reply to a write.
5175 ****************************************************************************/
5177 void reply_write(struct smb_request *req)
5179 connection_struct *conn = req->conn;
5180 size_t numtowrite;
5181 size_t remaining;
5182 ssize_t nwritten = -1;
5183 off_t startpos;
5184 const char *data;
5185 files_struct *fsp;
5186 struct lock_struct lock;
5187 NTSTATUS status;
5188 int saved_errno = 0;
5190 START_PROFILE(SMBwrite);
5192 if (req->wct < 5) {
5193 END_PROFILE(SMBwrite);
5194 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5195 return;
5198 /* If it's an IPC, pass off the pipe handler. */
5199 if (IS_IPC(conn)) {
5200 reply_pipe_write(req);
5201 END_PROFILE(SMBwrite);
5202 return;
5205 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5207 if (!check_fsp(conn, req, fsp)) {
5208 END_PROFILE(SMBwrite);
5209 return;
5212 if (!CHECK_WRITE(fsp)) {
5213 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5214 END_PROFILE(SMBwrite);
5215 return;
5218 numtowrite = SVAL(req->vwv+1, 0);
5219 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5220 data = (const char *)req->buf + 3;
5223 * Ensure client isn't asking us to write more than
5224 * they sent. CVE-2017-12163.
5226 remaining = smbreq_bufrem(req, data);
5227 if (numtowrite > remaining) {
5228 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5229 END_PROFILE(SMBwrite);
5230 return;
5233 if (!fsp->print_file) {
5234 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5235 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5236 &lock);
5238 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5239 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5240 END_PROFILE(SMBwrite);
5241 return;
5246 * X/Open SMB protocol says that if smb_vwv1 is
5247 * zero then the file size should be extended or
5248 * truncated to the size given in smb_vwv[2-3].
5251 if(numtowrite == 0) {
5253 * This is actually an allocate call, and set EOF. JRA.
5255 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
5256 if (nwritten < 0) {
5257 reply_nterror(req, NT_STATUS_DISK_FULL);
5258 goto out;
5260 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
5261 if (nwritten < 0) {
5262 reply_nterror(req, NT_STATUS_DISK_FULL);
5263 goto out;
5265 trigger_write_time_update_immediate(fsp);
5266 } else {
5267 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5270 status = sync_file(conn, fsp, False);
5271 if (!NT_STATUS_IS_OK(status)) {
5272 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
5273 fsp_str_dbg(fsp), nt_errstr(status)));
5274 reply_nterror(req, status);
5275 goto out;
5278 if(nwritten < 0) {
5279 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5280 goto out;
5283 if((nwritten == 0) && (numtowrite != 0)) {
5284 reply_nterror(req, NT_STATUS_DISK_FULL);
5285 goto out;
5288 reply_outbuf(req, 1, 0);
5290 SSVAL(req->outbuf,smb_vwv0,nwritten);
5292 if (nwritten < (ssize_t)numtowrite) {
5293 SCVAL(req->outbuf,smb_rcls,ERRHRD);
5294 SSVAL(req->outbuf,smb_err,ERRdiskfull);
5297 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5299 out:
5300 END_PROFILE(SMBwrite);
5301 return;
5304 /****************************************************************************
5305 Ensure a buffer is a valid writeX for recvfile purposes.
5306 ****************************************************************************/
5308 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
5309 (2*14) + /* word count (including bcc) */ \
5310 1 /* pad byte */)
5312 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
5313 const uint8_t *inbuf)
5315 size_t numtowrite;
5316 unsigned int doff = 0;
5317 size_t len = smb_len_large(inbuf);
5318 uint16_t fnum;
5319 struct smbXsrv_open *op = NULL;
5320 struct files_struct *fsp = NULL;
5321 NTSTATUS status;
5323 if (is_encrypted_packet(inbuf)) {
5324 /* Can't do this on encrypted
5325 * connections. */
5326 return false;
5329 if (CVAL(inbuf,smb_com) != SMBwriteX) {
5330 return false;
5333 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
5334 CVAL(inbuf,smb_wct) != 14) {
5335 DEBUG(10,("is_valid_writeX_buffer: chained or "
5336 "invalid word length.\n"));
5337 return false;
5340 fnum = SVAL(inbuf, smb_vwv2);
5341 status = smb1srv_open_lookup(xconn,
5342 fnum,
5343 0, /* now */
5344 &op);
5345 if (!NT_STATUS_IS_OK(status)) {
5346 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
5347 return false;
5349 fsp = op->compat;
5350 if (fsp == NULL) {
5351 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
5352 return false;
5354 if (fsp->conn == NULL) {
5355 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
5356 return false;
5359 if (IS_IPC(fsp->conn)) {
5360 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
5361 return false;
5363 if (IS_PRINT(fsp->conn)) {
5364 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
5365 return false;
5367 if (fsp->base_fsp != NULL) {
5368 DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
5369 return false;
5371 doff = SVAL(inbuf,smb_vwv11);
5373 numtowrite = SVAL(inbuf,smb_vwv10);
5375 if (len > doff && len - doff > 0xFFFF) {
5376 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
5379 if (numtowrite == 0) {
5380 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
5381 return false;
5384 /* Ensure the sizes match up. */
5385 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
5386 /* no pad byte...old smbclient :-( */
5387 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
5388 (unsigned int)doff,
5389 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
5390 return false;
5393 if (len - doff != numtowrite) {
5394 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
5395 "len = %u, doff = %u, numtowrite = %u\n",
5396 (unsigned int)len,
5397 (unsigned int)doff,
5398 (unsigned int)numtowrite ));
5399 return false;
5402 DEBUG(10,("is_valid_writeX_buffer: true "
5403 "len = %u, doff = %u, numtowrite = %u\n",
5404 (unsigned int)len,
5405 (unsigned int)doff,
5406 (unsigned int)numtowrite ));
5408 return true;
5411 /****************************************************************************
5412 Reply to a write and X.
5413 ****************************************************************************/
5415 void reply_write_and_X(struct smb_request *req)
5417 connection_struct *conn = req->conn;
5418 struct smbXsrv_connection *xconn = req->xconn;
5419 files_struct *fsp;
5420 struct lock_struct lock;
5421 off_t startpos;
5422 size_t numtowrite;
5423 bool write_through;
5424 ssize_t nwritten;
5425 unsigned int smb_doff;
5426 unsigned int smblen;
5427 const char *data;
5428 NTSTATUS status;
5429 int saved_errno = 0;
5431 START_PROFILE(SMBwriteX);
5433 if ((req->wct != 12) && (req->wct != 14)) {
5434 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5435 goto out;
5438 numtowrite = SVAL(req->vwv+10, 0);
5439 smb_doff = SVAL(req->vwv+11, 0);
5440 smblen = smb_len(req->inbuf);
5442 if (req->unread_bytes > 0xFFFF ||
5443 (smblen > smb_doff &&
5444 smblen - smb_doff > 0xFFFF)) {
5445 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5448 if (req->unread_bytes) {
5449 /* Can't do a recvfile write on IPC$ */
5450 if (IS_IPC(conn)) {
5451 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5452 goto out;
5454 if (numtowrite != req->unread_bytes) {
5455 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5456 goto out;
5458 } else {
5460 * This already protects us against CVE-2017-12163.
5462 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5463 smb_doff + numtowrite > smblen) {
5464 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5465 goto out;
5469 /* If it's an IPC, pass off the pipe handler. */
5470 if (IS_IPC(conn)) {
5471 if (req->unread_bytes) {
5472 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5473 goto out;
5475 reply_pipe_write_and_X(req);
5476 goto out;
5479 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5480 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5481 write_through = BITSETW(req->vwv+7,0);
5483 if (!check_fsp(conn, req, fsp)) {
5484 goto out;
5487 if (!CHECK_WRITE(fsp)) {
5488 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5489 goto out;
5492 data = smb_base(req->inbuf) + smb_doff;
5494 if(req->wct == 14) {
5496 * This is a large offset (64 bit) write.
5498 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5502 /* X/Open SMB protocol says that, unlike SMBwrite
5503 if the length is zero then NO truncation is
5504 done, just a write of zero. To truncate a file,
5505 use SMBwrite. */
5507 if(numtowrite == 0) {
5508 nwritten = 0;
5509 } else {
5510 if (req->unread_bytes == 0) {
5511 status = schedule_aio_write_and_X(conn,
5512 req,
5513 fsp,
5514 data,
5515 startpos,
5516 numtowrite);
5518 if (NT_STATUS_IS_OK(status)) {
5519 /* write scheduled - we're done. */
5520 goto out;
5522 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5523 /* Real error - report to client. */
5524 reply_nterror(req, status);
5525 goto out;
5527 /* NT_STATUS_RETRY - fall through to sync write. */
5530 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5531 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5532 &lock);
5534 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5535 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5536 goto out;
5539 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5540 saved_errno = errno;
5543 if(nwritten < 0) {
5544 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5545 goto out;
5548 if((nwritten == 0) && (numtowrite != 0)) {
5549 reply_nterror(req, NT_STATUS_DISK_FULL);
5550 goto out;
5553 reply_outbuf(req, 6, 0);
5554 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5555 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5556 SSVAL(req->outbuf,smb_vwv2,nwritten);
5557 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5559 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5560 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5562 status = sync_file(conn, fsp, write_through);
5563 if (!NT_STATUS_IS_OK(status)) {
5564 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5565 fsp_str_dbg(fsp), nt_errstr(status)));
5566 reply_nterror(req, status);
5567 goto out;
5570 END_PROFILE(SMBwriteX);
5571 return;
5573 out:
5574 if (req->unread_bytes) {
5575 /* writeX failed. drain socket. */
5576 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5577 req->unread_bytes) {
5578 smb_panic("failed to drain pending bytes");
5580 req->unread_bytes = 0;
5583 END_PROFILE(SMBwriteX);
5584 return;
5587 /****************************************************************************
5588 Reply to a lseek.
5589 ****************************************************************************/
5591 void reply_lseek(struct smb_request *req)
5593 connection_struct *conn = req->conn;
5594 off_t startpos;
5595 off_t res= -1;
5596 int mode,umode;
5597 files_struct *fsp;
5598 NTSTATUS status;
5600 START_PROFILE(SMBlseek);
5602 if (req->wct < 4) {
5603 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5604 END_PROFILE(SMBlseek);
5605 return;
5608 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5610 if (!check_fsp(conn, req, fsp)) {
5611 return;
5614 mode = SVAL(req->vwv+1, 0) & 3;
5615 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5616 startpos = (off_t)IVALS(req->vwv+2, 0);
5618 switch (mode) {
5619 case 0:
5620 umode = SEEK_SET;
5621 res = startpos;
5622 break;
5623 case 1:
5624 umode = SEEK_CUR;
5625 res = fh_get_pos(fsp->fh) + startpos;
5626 break;
5627 case 2:
5628 umode = SEEK_END;
5629 break;
5630 default:
5631 umode = SEEK_SET;
5632 res = startpos;
5633 break;
5636 if (umode == SEEK_END) {
5637 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5638 if(errno == EINVAL) {
5639 off_t current_pos = startpos;
5641 status = vfs_stat_fsp(fsp);
5642 if (!NT_STATUS_IS_OK(status)) {
5643 reply_nterror(req, status);
5644 END_PROFILE(SMBlseek);
5645 return;
5648 current_pos += fsp->fsp_name->st.st_ex_size;
5649 if(current_pos < 0)
5650 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5654 if(res == -1) {
5655 reply_nterror(req, map_nt_error_from_unix(errno));
5656 END_PROFILE(SMBlseek);
5657 return;
5661 fh_set_pos(fsp->fh, res);
5663 reply_outbuf(req, 2, 0);
5664 SIVAL(req->outbuf,smb_vwv0,res);
5666 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5667 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5669 END_PROFILE(SMBlseek);
5670 return;
5673 static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
5674 void *private_data)
5676 connection_struct *conn = talloc_get_type_abort(
5677 private_data, connection_struct);
5679 if (conn != fsp->conn) {
5680 return NULL;
5682 if (fsp_get_io_fd(fsp) == -1) {
5683 return NULL;
5685 sync_file(conn, fsp, True /* write through */);
5687 if (fsp->fsp_flags.modified) {
5688 trigger_write_time_update_immediate(fsp);
5691 return NULL;
5694 /****************************************************************************
5695 Reply to a flush.
5696 ****************************************************************************/
5698 void reply_flush(struct smb_request *req)
5700 connection_struct *conn = req->conn;
5701 uint16_t fnum;
5702 files_struct *fsp;
5704 START_PROFILE(SMBflush);
5706 if (req->wct < 1) {
5707 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5708 return;
5711 fnum = SVAL(req->vwv+0, 0);
5712 fsp = file_fsp(req, fnum);
5714 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5715 return;
5718 if (!fsp) {
5719 files_forall(req->sconn, file_sync_one_fn, conn);
5720 } else {
5721 NTSTATUS status = sync_file(conn, fsp, True);
5722 if (!NT_STATUS_IS_OK(status)) {
5723 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5724 fsp_str_dbg(fsp), nt_errstr(status)));
5725 reply_nterror(req, status);
5726 END_PROFILE(SMBflush);
5727 return;
5729 if (fsp->fsp_flags.modified) {
5730 trigger_write_time_update_immediate(fsp);
5734 reply_outbuf(req, 0, 0);
5736 DEBUG(3,("flush\n"));
5737 END_PROFILE(SMBflush);
5738 return;
5741 /****************************************************************************
5742 Reply to a exit.
5743 conn POINTER CAN BE NULL HERE !
5744 ****************************************************************************/
5746 static struct tevent_req *reply_exit_send(struct smb_request *smb1req);
5747 static void reply_exit_done(struct tevent_req *req);
5749 void reply_exit(struct smb_request *smb1req)
5751 struct tevent_req *req;
5754 * Don't setup the profile charge here, take
5755 * it in reply_exit_done(). Not strictly correct
5756 * but better than the other SMB1 async
5757 * code that double-charges at the moment.
5759 req = reply_exit_send(smb1req);
5760 if (req == NULL) {
5761 /* Not going async, profile here. */
5762 START_PROFILE(SMBexit);
5763 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
5764 END_PROFILE(SMBexit);
5765 return;
5768 /* We're async. This will complete later. */
5769 tevent_req_set_callback(req, reply_exit_done, smb1req);
5770 return;
5773 struct reply_exit_state {
5774 struct tevent_queue *wait_queue;
5777 static void reply_exit_wait_done(struct tevent_req *subreq);
5779 /****************************************************************************
5780 Async SMB1 exit.
5781 Note, on failure here we deallocate and return NULL to allow the caller to
5782 SMB1 return an error of ERRnomem immediately.
5783 ****************************************************************************/
5785 static struct tevent_req *reply_exit_send(struct smb_request *smb1req)
5787 struct tevent_req *req;
5788 struct reply_exit_state *state;
5789 struct tevent_req *subreq;
5790 files_struct *fsp;
5791 struct smbd_server_connection *sconn = smb1req->sconn;
5793 req = tevent_req_create(smb1req, &state,
5794 struct reply_exit_state);
5795 if (req == NULL) {
5796 return NULL;
5798 state->wait_queue = tevent_queue_create(state,
5799 "reply_exit_wait_queue");
5800 if (tevent_req_nomem(state->wait_queue, req)) {
5801 TALLOC_FREE(req);
5802 return NULL;
5805 for (fsp = sconn->files; fsp; fsp = fsp->next) {
5806 if (fsp->file_pid != smb1req->smbpid) {
5807 continue;
5809 if (fsp->vuid != smb1req->vuid) {
5810 continue;
5813 * Flag the file as close in progress.
5814 * This will prevent any more IO being
5815 * done on it.
5817 fsp->fsp_flags.closing = true;
5819 if (fsp->num_aio_requests > 0) {
5821 * Now wait until all aio requests on this fsp are
5822 * finished.
5824 * We don't set a callback, as we just want to block the
5825 * wait queue and the talloc_free() of fsp->aio_request
5826 * will remove the item from the wait queue.
5828 subreq = tevent_queue_wait_send(fsp->aio_requests,
5829 sconn->ev_ctx,
5830 state->wait_queue);
5831 if (tevent_req_nomem(subreq, req)) {
5832 TALLOC_FREE(req);
5833 return NULL;
5839 * Now we add our own waiter to the end of the queue,
5840 * this way we get notified when all pending requests are finished
5841 * and reply to the outstanding SMB1 request.
5843 subreq = tevent_queue_wait_send(state,
5844 sconn->ev_ctx,
5845 state->wait_queue);
5846 if (tevent_req_nomem(subreq, req)) {
5847 TALLOC_FREE(req);
5848 return NULL;
5852 * We're really going async - move the SMB1 request from
5853 * a talloc stackframe above us to the conn talloc-context.
5854 * We need this to stick around until the wait_done
5855 * callback is invoked.
5857 smb1req = talloc_move(sconn, &smb1req);
5859 tevent_req_set_callback(subreq, reply_exit_wait_done, req);
5861 return req;
5864 static void reply_exit_wait_done(struct tevent_req *subreq)
5866 struct tevent_req *req = tevent_req_callback_data(
5867 subreq, struct tevent_req);
5869 tevent_queue_wait_recv(subreq);
5870 TALLOC_FREE(subreq);
5871 tevent_req_done(req);
5874 static NTSTATUS reply_exit_recv(struct tevent_req *req)
5876 return tevent_req_simple_recv_ntstatus(req);
5879 static void reply_exit_done(struct tevent_req *req)
5881 struct smb_request *smb1req = tevent_req_callback_data(
5882 req, struct smb_request);
5883 struct smbd_server_connection *sconn = smb1req->sconn;
5884 struct smbXsrv_connection *xconn = smb1req->xconn;
5885 NTTIME now = timeval_to_nttime(&smb1req->request_time);
5886 struct smbXsrv_session *session = NULL;
5887 files_struct *fsp, *next;
5888 NTSTATUS status;
5891 * Take the profile charge here. Not strictly
5892 * correct but better than the other SMB1 async
5893 * code that double-charges at the moment.
5895 START_PROFILE(SMBexit);
5897 status = reply_exit_recv(req);
5898 TALLOC_FREE(req);
5899 if (!NT_STATUS_IS_OK(status)) {
5900 TALLOC_FREE(smb1req);
5901 END_PROFILE(SMBexit);
5902 exit_server(__location__ ": reply_exit_recv failed");
5903 return;
5907 * Ensure the session is still valid.
5909 status = smb1srv_session_lookup(xconn,
5910 smb1req->vuid,
5911 now,
5912 &session);
5913 if (!NT_STATUS_IS_OK(status)) {
5914 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5915 smb_request_done(smb1req);
5916 END_PROFILE(SMBexit);
5920 * Ensure the vuid is still valid - no one
5921 * called reply_ulogoffX() in the meantime.
5922 * reply_exit() doesn't have AS_USER set, so
5923 * use set_current_user_info() directly.
5924 * This is the same logic as in switch_message().
5926 if (session->global->auth_session_info != NULL) {
5927 set_current_user_info(
5928 session->global->auth_session_info->unix_info->sanitized_username,
5929 session->global->auth_session_info->unix_info->unix_name,
5930 session->global->auth_session_info->info->domain_name);
5933 /* No more aio - do the actual closes. */
5934 for (fsp = sconn->files; fsp; fsp = next) {
5935 bool ok;
5936 next = fsp->next;
5938 if (fsp->file_pid != smb1req->smbpid) {
5939 continue;
5941 if (fsp->vuid != smb1req->vuid) {
5942 continue;
5944 if (!fsp->fsp_flags.closing) {
5945 continue;
5949 * reply_exit() has the DO_CHDIR flag set.
5951 ok = chdir_current_service(fsp->conn);
5952 if (!ok) {
5953 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5954 smb_request_done(smb1req);
5955 END_PROFILE(SMBexit);
5957 close_file(NULL, fsp, SHUTDOWN_CLOSE);
5960 reply_outbuf(smb1req, 0, 0);
5962 * The following call is needed to push the
5963 * reply data back out the socket after async
5964 * return. Plus it frees smb1req.
5966 smb_request_done(smb1req);
5967 DBG_INFO("reply_exit complete\n");
5968 END_PROFILE(SMBexit);
5969 return;
5972 static struct tevent_req *reply_close_send(struct smb_request *smb1req,
5973 files_struct *fsp);
5974 static void reply_close_done(struct tevent_req *req);
5976 void reply_close(struct smb_request *smb1req)
5978 connection_struct *conn = smb1req->conn;
5979 NTSTATUS status = NT_STATUS_OK;
5980 files_struct *fsp = NULL;
5981 START_PROFILE(SMBclose);
5983 if (smb1req->wct < 3) {
5984 reply_nterror(smb1req, NT_STATUS_INVALID_PARAMETER);
5985 END_PROFILE(SMBclose);
5986 return;
5989 fsp = file_fsp(smb1req, SVAL(smb1req->vwv+0, 0));
5992 * We can only use check_fsp if we know it's not a directory.
5995 if (!check_fsp_open(conn, smb1req, fsp)) {
5996 reply_nterror(smb1req, NT_STATUS_INVALID_HANDLE);
5997 END_PROFILE(SMBclose);
5998 return;
6001 DBG_NOTICE("Close %s fd=%d %s (numopen=%d)\n",
6002 fsp->fsp_flags.is_directory ?
6003 "directory" : "file",
6004 fsp_get_pathref_fd(fsp), fsp_fnum_dbg(fsp),
6005 conn->num_files_open);
6007 if (!fsp->fsp_flags.is_directory) {
6008 time_t t;
6011 * Take care of any time sent in the close.
6014 t = srv_make_unix_date3(smb1req->vwv+1);
6015 set_close_write_time(fsp, time_t_to_full_timespec(t));
6018 if (fsp->num_aio_requests != 0) {
6019 struct tevent_req *req;
6021 req = reply_close_send(smb1req, fsp);
6022 if (req == NULL) {
6023 status = NT_STATUS_NO_MEMORY;
6024 goto done;
6026 /* We're async. This will complete later. */
6027 tevent_req_set_callback(req, reply_close_done, smb1req);
6028 END_PROFILE(SMBclose);
6029 return;
6033 * close_file() returns the unix errno if an error was detected on
6034 * close - normally this is due to a disk full error. If not then it
6035 * was probably an I/O error.
6038 status = close_file(smb1req, fsp, NORMAL_CLOSE);
6039 done:
6040 if (!NT_STATUS_IS_OK(status)) {
6041 reply_nterror(smb1req, status);
6042 END_PROFILE(SMBclose);
6043 return;
6046 reply_outbuf(smb1req, 0, 0);
6047 END_PROFILE(SMBclose);
6048 return;
6051 struct reply_close_state {
6052 files_struct *fsp;
6053 struct tevent_queue *wait_queue;
6056 static void reply_close_wait_done(struct tevent_req *subreq);
6058 /****************************************************************************
6059 Async SMB1 close.
6060 Note, on failure here we deallocate and return NULL to allow the caller to
6061 SMB1 return an error of ERRnomem immediately.
6062 ****************************************************************************/
6064 static struct tevent_req *reply_close_send(struct smb_request *smb1req,
6065 files_struct *fsp)
6067 struct tevent_req *req;
6068 struct reply_close_state *state;
6069 struct tevent_req *subreq;
6070 struct smbd_server_connection *sconn = smb1req->sconn;
6072 req = tevent_req_create(smb1req, &state,
6073 struct reply_close_state);
6074 if (req == NULL) {
6075 return NULL;
6077 state->wait_queue = tevent_queue_create(state,
6078 "reply_close_wait_queue");
6079 if (tevent_req_nomem(state->wait_queue, req)) {
6080 TALLOC_FREE(req);
6081 return NULL;
6085 * Flag the file as close in progress.
6086 * This will prevent any more IO being
6087 * done on it.
6089 fsp->fsp_flags.closing = true;
6092 * Now wait until all aio requests on this fsp are
6093 * finished.
6095 * We don't set a callback, as we just want to block the
6096 * wait queue and the talloc_free() of fsp->aio_request
6097 * will remove the item from the wait queue.
6099 subreq = tevent_queue_wait_send(fsp->aio_requests,
6100 sconn->ev_ctx,
6101 state->wait_queue);
6102 if (tevent_req_nomem(subreq, req)) {
6103 TALLOC_FREE(req);
6104 return NULL;
6108 * Now we add our own waiter to the end of the queue,
6109 * this way we get notified when all pending requests are finished
6110 * and reply to the outstanding SMB1 request.
6112 subreq = tevent_queue_wait_send(state,
6113 sconn->ev_ctx,
6114 state->wait_queue);
6115 if (tevent_req_nomem(subreq, req)) {
6116 TALLOC_FREE(req);
6117 return NULL;
6121 * We're really going async - move the SMB1 request from
6122 * a talloc stackframe above us to the conn talloc-context.
6123 * We need this to stick around until the wait_done
6124 * callback is invoked.
6126 smb1req = talloc_move(sconn, &smb1req);
6128 tevent_req_set_callback(subreq, reply_close_wait_done, req);
6130 return req;
6133 static void reply_close_wait_done(struct tevent_req *subreq)
6135 struct tevent_req *req = tevent_req_callback_data(
6136 subreq, struct tevent_req);
6138 tevent_queue_wait_recv(subreq);
6139 TALLOC_FREE(subreq);
6140 tevent_req_done(req);
6143 static NTSTATUS reply_close_recv(struct tevent_req *req)
6145 return tevent_req_simple_recv_ntstatus(req);
6148 static void reply_close_done(struct tevent_req *req)
6150 struct smb_request *smb1req = tevent_req_callback_data(
6151 req, struct smb_request);
6152 struct reply_close_state *state = tevent_req_data(req,
6153 struct reply_close_state);
6154 NTSTATUS status;
6156 status = reply_close_recv(req);
6157 TALLOC_FREE(req);
6158 if (!NT_STATUS_IS_OK(status)) {
6159 TALLOC_FREE(smb1req);
6160 exit_server(__location__ ": reply_close_recv failed");
6161 return;
6164 status = close_file(smb1req, state->fsp, NORMAL_CLOSE);
6165 if (NT_STATUS_IS_OK(status)) {
6166 reply_outbuf(smb1req, 0, 0);
6167 } else {
6168 reply_nterror(smb1req, status);
6171 * The following call is needed to push the
6172 * reply data back out the socket after async
6173 * return. Plus it frees smb1req.
6175 smb_request_done(smb1req);
6178 /****************************************************************************
6179 Reply to a writeclose (Core+ protocol).
6180 ****************************************************************************/
6182 void reply_writeclose(struct smb_request *req)
6184 connection_struct *conn = req->conn;
6185 size_t numtowrite;
6186 size_t remaining;
6187 ssize_t nwritten = -1;
6188 NTSTATUS close_status = NT_STATUS_OK;
6189 off_t startpos;
6190 const char *data;
6191 struct timespec mtime;
6192 files_struct *fsp;
6193 struct lock_struct lock;
6195 START_PROFILE(SMBwriteclose);
6197 if (req->wct < 6) {
6198 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6199 END_PROFILE(SMBwriteclose);
6200 return;
6203 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6205 if (!check_fsp(conn, req, fsp)) {
6206 END_PROFILE(SMBwriteclose);
6207 return;
6209 if (!CHECK_WRITE(fsp)) {
6210 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6211 END_PROFILE(SMBwriteclose);
6212 return;
6215 numtowrite = SVAL(req->vwv+1, 0);
6216 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
6217 mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+4));
6218 data = (const char *)req->buf + 1;
6221 * Ensure client isn't asking us to write more than
6222 * they sent. CVE-2017-12163.
6224 remaining = smbreq_bufrem(req, data);
6225 if (numtowrite > remaining) {
6226 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6227 END_PROFILE(SMBwriteclose);
6228 return;
6231 if (fsp->print_file == NULL) {
6232 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
6233 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
6234 &lock);
6236 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
6237 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
6238 END_PROFILE(SMBwriteclose);
6239 return;
6243 nwritten = write_file(req,fsp,data,startpos,numtowrite);
6245 set_close_write_time(fsp, mtime);
6248 * More insanity. W2K only closes the file if writelen > 0.
6249 * JRA.
6252 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
6253 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
6254 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
6256 if (numtowrite) {
6257 DEBUG(3,("reply_writeclose: zero length write doesn't close "
6258 "file %s\n", fsp_str_dbg(fsp)));
6259 close_status = close_file(req, fsp, NORMAL_CLOSE);
6260 fsp = NULL;
6263 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
6264 reply_nterror(req, NT_STATUS_DISK_FULL);
6265 goto out;
6268 if(!NT_STATUS_IS_OK(close_status)) {
6269 reply_nterror(req, close_status);
6270 goto out;
6273 reply_outbuf(req, 1, 0);
6275 SSVAL(req->outbuf,smb_vwv0,nwritten);
6277 out:
6279 END_PROFILE(SMBwriteclose);
6280 return;
6283 #undef DBGC_CLASS
6284 #define DBGC_CLASS DBGC_LOCKING
6286 /****************************************************************************
6287 Reply to a lock.
6288 ****************************************************************************/
6290 static void reply_lock_done(struct tevent_req *subreq);
6292 void reply_lock(struct smb_request *req)
6294 struct tevent_req *subreq = NULL;
6295 connection_struct *conn = req->conn;
6296 files_struct *fsp;
6297 struct smbd_lock_element *lck = NULL;
6299 START_PROFILE(SMBlock);
6301 if (req->wct < 5) {
6302 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6303 END_PROFILE(SMBlock);
6304 return;
6307 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6309 if (!check_fsp(conn, req, fsp)) {
6310 END_PROFILE(SMBlock);
6311 return;
6314 lck = talloc(req, struct smbd_lock_element);
6315 if (lck == NULL) {
6316 reply_nterror(req, NT_STATUS_NO_MEMORY);
6317 END_PROFILE(SMBlock);
6318 return;
6321 *lck = (struct smbd_lock_element) {
6322 .req_guid = smbd_request_guid(req, 0),
6323 .smblctx = req->smbpid,
6324 .brltype = WRITE_LOCK,
6325 .count = IVAL(req->vwv+1, 0),
6326 .offset = IVAL(req->vwv+3, 0),
6329 DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
6330 fsp_get_io_fd(fsp),
6331 fsp_fnum_dbg(fsp),
6332 lck->offset,
6333 lck->count);
6335 subreq = smbd_smb1_do_locks_send(
6336 fsp,
6337 req->sconn->ev_ctx,
6338 &req,
6339 fsp,
6341 false, /* large_offset */
6342 WINDOWS_LOCK,
6344 lck);
6345 if (subreq == NULL) {
6346 reply_nterror(req, NT_STATUS_NO_MEMORY);
6347 END_PROFILE(SMBlock);
6348 return;
6350 tevent_req_set_callback(subreq, reply_lock_done, NULL);
6351 END_PROFILE(SMBlock);
6354 static void reply_lock_done(struct tevent_req *subreq)
6356 struct smb_request *req = NULL;
6357 NTSTATUS status;
6358 bool ok;
6360 START_PROFILE(SMBlock);
6362 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
6363 SMB_ASSERT(ok);
6365 status = smbd_smb1_do_locks_recv(subreq);
6366 TALLOC_FREE(subreq);
6368 if (NT_STATUS_IS_OK(status)) {
6369 reply_outbuf(req, 0, 0);
6370 } else {
6371 reply_nterror(req, status);
6374 ok = srv_send_smb(req->xconn,
6375 (char *)req->outbuf,
6376 true,
6377 req->seqnum+1,
6378 IS_CONN_ENCRYPTED(req->conn),
6379 NULL);
6380 if (!ok) {
6381 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
6383 TALLOC_FREE(req);
6384 END_PROFILE(SMBlock);
6387 /****************************************************************************
6388 Reply to a unlock.
6389 ****************************************************************************/
6391 void reply_unlock(struct smb_request *req)
6393 connection_struct *conn = req->conn;
6394 NTSTATUS status;
6395 files_struct *fsp;
6396 struct smbd_lock_element lck;
6398 START_PROFILE(SMBunlock);
6400 if (req->wct < 5) {
6401 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6402 END_PROFILE(SMBunlock);
6403 return;
6406 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6408 if (!check_fsp(conn, req, fsp)) {
6409 END_PROFILE(SMBunlock);
6410 return;
6413 lck = (struct smbd_lock_element) {
6414 .req_guid = smbd_request_guid(req, 0),
6415 .smblctx = req->smbpid,
6416 .brltype = UNLOCK_LOCK,
6417 .offset = IVAL(req->vwv+3, 0),
6418 .count = IVAL(req->vwv+1, 0),
6421 status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
6423 if (!NT_STATUS_IS_OK(status)) {
6424 reply_nterror(req, status);
6425 END_PROFILE(SMBunlock);
6426 return;
6429 DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
6430 fsp_get_io_fd(fsp),
6431 fsp_fnum_dbg(fsp),
6432 lck.offset,
6433 lck.count);
6435 reply_outbuf(req, 0, 0);
6437 END_PROFILE(SMBunlock);
6438 return;
6441 #undef DBGC_CLASS
6442 #define DBGC_CLASS DBGC_ALL
6444 /****************************************************************************
6445 Reply to a tdis.
6446 conn POINTER CAN BE NULL HERE !
6447 ****************************************************************************/
6449 static struct tevent_req *reply_tdis_send(struct smb_request *smb1req);
6450 static void reply_tdis_done(struct tevent_req *req);
6452 void reply_tdis(struct smb_request *smb1req)
6454 connection_struct *conn = smb1req->conn;
6455 struct tevent_req *req;
6458 * Don't setup the profile charge here, take
6459 * it in reply_tdis_done(). Not strictly correct
6460 * but better than the other SMB1 async
6461 * code that double-charges at the moment.
6464 if (conn == NULL) {
6465 /* Not going async, profile here. */
6466 START_PROFILE(SMBtdis);
6467 DBG_INFO("Invalid connection in tdis\n");
6468 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
6469 END_PROFILE(SMBtdis);
6470 return;
6473 req = reply_tdis_send(smb1req);
6474 if (req == NULL) {
6475 /* Not going async, profile here. */
6476 START_PROFILE(SMBtdis);
6477 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
6478 END_PROFILE(SMBtdis);
6479 return;
6481 /* We're async. This will complete later. */
6482 tevent_req_set_callback(req, reply_tdis_done, smb1req);
6483 return;
6486 struct reply_tdis_state {
6487 struct tevent_queue *wait_queue;
6490 static void reply_tdis_wait_done(struct tevent_req *subreq);
6492 /****************************************************************************
6493 Async SMB1 tdis.
6494 Note, on failure here we deallocate and return NULL to allow the caller to
6495 SMB1 return an error of ERRnomem immediately.
6496 ****************************************************************************/
6498 static struct tevent_req *reply_tdis_send(struct smb_request *smb1req)
6500 struct tevent_req *req;
6501 struct reply_tdis_state *state;
6502 struct tevent_req *subreq;
6503 connection_struct *conn = smb1req->conn;
6504 files_struct *fsp;
6506 req = tevent_req_create(smb1req, &state,
6507 struct reply_tdis_state);
6508 if (req == NULL) {
6509 return NULL;
6511 state->wait_queue = tevent_queue_create(state, "reply_tdis_wait_queue");
6512 if (tevent_req_nomem(state->wait_queue, req)) {
6513 TALLOC_FREE(req);
6514 return NULL;
6518 * Make sure that no new request will be able to use this tcon.
6519 * This ensures that once all outstanding fsp->aio_requests
6520 * on this tcon are done, we are safe to close it.
6522 conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
6524 for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
6525 if (fsp->conn != conn) {
6526 continue;
6529 * Flag the file as close in progress.
6530 * This will prevent any more IO being
6531 * done on it. Not strictly needed, but
6532 * doesn't hurt to flag it as closing.
6534 fsp->fsp_flags.closing = true;
6536 if (fsp->num_aio_requests > 0) {
6538 * Now wait until all aio requests on this fsp are
6539 * finished.
6541 * We don't set a callback, as we just want to block the
6542 * wait queue and the talloc_free() of fsp->aio_request
6543 * will remove the item from the wait queue.
6545 subreq = tevent_queue_wait_send(fsp->aio_requests,
6546 conn->sconn->ev_ctx,
6547 state->wait_queue);
6548 if (tevent_req_nomem(subreq, req)) {
6549 TALLOC_FREE(req);
6550 return NULL;
6556 * Now we add our own waiter to the end of the queue,
6557 * this way we get notified when all pending requests are finished
6558 * and reply to the outstanding SMB1 request.
6560 subreq = tevent_queue_wait_send(state,
6561 conn->sconn->ev_ctx,
6562 state->wait_queue);
6563 if (tevent_req_nomem(subreq, req)) {
6564 TALLOC_FREE(req);
6565 return NULL;
6569 * We're really going async - move the SMB1 request from
6570 * a talloc stackframe above us to the sconn talloc-context.
6571 * We need this to stick around until the wait_done
6572 * callback is invoked.
6574 smb1req = talloc_move(smb1req->sconn, &smb1req);
6576 tevent_req_set_callback(subreq, reply_tdis_wait_done, req);
6578 return req;
6581 static void reply_tdis_wait_done(struct tevent_req *subreq)
6583 struct tevent_req *req = tevent_req_callback_data(
6584 subreq, struct tevent_req);
6586 tevent_queue_wait_recv(subreq);
6587 TALLOC_FREE(subreq);
6588 tevent_req_done(req);
6591 static NTSTATUS reply_tdis_recv(struct tevent_req *req)
6593 return tevent_req_simple_recv_ntstatus(req);
6596 static void reply_tdis_done(struct tevent_req *req)
6598 struct smb_request *smb1req = tevent_req_callback_data(
6599 req, struct smb_request);
6600 NTSTATUS status;
6601 struct smbXsrv_tcon *tcon = smb1req->conn->tcon;
6602 bool ok;
6605 * Take the profile charge here. Not strictly
6606 * correct but better than the other SMB1 async
6607 * code that double-charges at the moment.
6609 START_PROFILE(SMBtdis);
6611 status = reply_tdis_recv(req);
6612 TALLOC_FREE(req);
6613 if (!NT_STATUS_IS_OK(status)) {
6614 TALLOC_FREE(smb1req);
6615 END_PROFILE(SMBtdis);
6616 exit_server(__location__ ": reply_tdis_recv failed");
6617 return;
6621 * As we've been awoken, we may have changed
6622 * directory in the meantime.
6623 * reply_tdis() has the DO_CHDIR flag set.
6625 ok = chdir_current_service(smb1req->conn);
6626 if (!ok) {
6627 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
6628 smb_request_done(smb1req);
6629 END_PROFILE(SMBtdis);
6632 status = smbXsrv_tcon_disconnect(tcon,
6633 smb1req->vuid);
6634 if (!NT_STATUS_IS_OK(status)) {
6635 TALLOC_FREE(smb1req);
6636 END_PROFILE(SMBtdis);
6637 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
6638 return;
6641 /* smbXsrv_tcon_disconnect frees smb1req->conn. */
6642 smb1req->conn = NULL;
6644 TALLOC_FREE(tcon);
6646 reply_outbuf(smb1req, 0, 0);
6648 * The following call is needed to push the
6649 * reply data back out the socket after async
6650 * return. Plus it frees smb1req.
6652 smb_request_done(smb1req);
6653 END_PROFILE(SMBtdis);
6656 /****************************************************************************
6657 Reply to a echo.
6658 conn POINTER CAN BE NULL HERE !
6659 ****************************************************************************/
6661 void reply_echo(struct smb_request *req)
6663 connection_struct *conn = req->conn;
6664 struct smb_perfcount_data local_pcd;
6665 struct smb_perfcount_data *cur_pcd;
6666 int smb_reverb;
6667 int seq_num;
6669 START_PROFILE(SMBecho);
6671 smb_init_perfcount_data(&local_pcd);
6673 if (req->wct < 1) {
6674 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6675 END_PROFILE(SMBecho);
6676 return;
6679 smb_reverb = SVAL(req->vwv+0, 0);
6681 reply_outbuf(req, 1, req->buflen);
6683 /* copy any incoming data back out */
6684 if (req->buflen > 0) {
6685 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
6688 if (smb_reverb > 100) {
6689 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
6690 smb_reverb = 100;
6693 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
6695 /* this makes sure we catch the request pcd */
6696 if (seq_num == smb_reverb) {
6697 cur_pcd = &req->pcd;
6698 } else {
6699 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
6700 cur_pcd = &local_pcd;
6703 SSVAL(req->outbuf,smb_vwv0,seq_num);
6705 show_msg((char *)req->outbuf);
6706 if (!srv_send_smb(req->xconn,
6707 (char *)req->outbuf,
6708 true, req->seqnum+1,
6709 IS_CONN_ENCRYPTED(conn)||req->encrypted,
6710 cur_pcd))
6711 exit_server_cleanly("reply_echo: srv_send_smb failed.");
6714 DEBUG(3,("echo %d times\n", smb_reverb));
6716 TALLOC_FREE(req->outbuf);
6718 END_PROFILE(SMBecho);
6719 return;
6722 /****************************************************************************
6723 Reply to a printopen.
6724 ****************************************************************************/
6726 void reply_printopen(struct smb_request *req)
6728 connection_struct *conn = req->conn;
6729 files_struct *fsp;
6730 NTSTATUS status;
6732 START_PROFILE(SMBsplopen);
6734 if (req->wct < 2) {
6735 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6736 END_PROFILE(SMBsplopen);
6737 return;
6740 if (!CAN_PRINT(conn)) {
6741 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6742 END_PROFILE(SMBsplopen);
6743 return;
6746 status = file_new(req, conn, &fsp);
6747 if(!NT_STATUS_IS_OK(status)) {
6748 reply_nterror(req, status);
6749 END_PROFILE(SMBsplopen);
6750 return;
6753 /* Open for exclusive use, write only. */
6754 status = print_spool_open(fsp, NULL, req->vuid);
6756 if (!NT_STATUS_IS_OK(status)) {
6757 file_free(req, fsp);
6758 reply_nterror(req, status);
6759 END_PROFILE(SMBsplopen);
6760 return;
6763 reply_outbuf(req, 1, 0);
6764 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
6766 DEBUG(3,("openprint fd=%d %s\n",
6767 fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
6769 END_PROFILE(SMBsplopen);
6770 return;
6773 /****************************************************************************
6774 Reply to a printclose.
6775 ****************************************************************************/
6777 void reply_printclose(struct smb_request *req)
6779 connection_struct *conn = req->conn;
6780 files_struct *fsp;
6781 NTSTATUS status;
6783 START_PROFILE(SMBsplclose);
6785 if (req->wct < 1) {
6786 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6787 END_PROFILE(SMBsplclose);
6788 return;
6791 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6793 if (!check_fsp(conn, req, fsp)) {
6794 END_PROFILE(SMBsplclose);
6795 return;
6798 if (!CAN_PRINT(conn)) {
6799 reply_force_doserror(req, ERRSRV, ERRerror);
6800 END_PROFILE(SMBsplclose);
6801 return;
6804 DEBUG(3,("printclose fd=%d %s\n",
6805 fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
6807 status = close_file(req, fsp, NORMAL_CLOSE);
6809 if(!NT_STATUS_IS_OK(status)) {
6810 reply_nterror(req, status);
6811 END_PROFILE(SMBsplclose);
6812 return;
6815 reply_outbuf(req, 0, 0);
6817 END_PROFILE(SMBsplclose);
6818 return;
6821 /****************************************************************************
6822 Reply to a printqueue.
6823 ****************************************************************************/
6825 void reply_printqueue(struct smb_request *req)
6827 const struct loadparm_substitution *lp_sub =
6828 loadparm_s3_global_substitution();
6829 connection_struct *conn = req->conn;
6830 int max_count;
6831 int start_index;
6833 START_PROFILE(SMBsplretq);
6835 if (req->wct < 2) {
6836 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6837 END_PROFILE(SMBsplretq);
6838 return;
6841 max_count = SVAL(req->vwv+0, 0);
6842 start_index = SVAL(req->vwv+1, 0);
6844 /* we used to allow the client to get the cnum wrong, but that
6845 is really quite gross and only worked when there was only
6846 one printer - I think we should now only accept it if they
6847 get it right (tridge) */
6848 if (!CAN_PRINT(conn)) {
6849 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6850 END_PROFILE(SMBsplretq);
6851 return;
6854 reply_outbuf(req, 2, 3);
6855 SSVAL(req->outbuf,smb_vwv0,0);
6856 SSVAL(req->outbuf,smb_vwv1,0);
6857 SCVAL(smb_buf(req->outbuf),0,1);
6858 SSVAL(smb_buf(req->outbuf),1,0);
6860 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
6861 start_index, max_count));
6864 TALLOC_CTX *mem_ctx = talloc_tos();
6865 NTSTATUS status;
6866 WERROR werr;
6867 const char *sharename = lp_servicename(mem_ctx, lp_sub, SNUM(conn));
6868 struct rpc_pipe_client *cli = NULL;
6869 struct dcerpc_binding_handle *b = NULL;
6870 struct policy_handle handle;
6871 struct spoolss_DevmodeContainer devmode_ctr;
6872 union spoolss_JobInfo *info;
6873 uint32_t count;
6874 uint32_t num_to_get;
6875 uint32_t first;
6876 uint32_t i;
6878 ZERO_STRUCT(handle);
6880 status = rpc_pipe_open_interface(mem_ctx,
6881 &ndr_table_spoolss,
6882 conn->session_info,
6883 conn->sconn->remote_address,
6884 conn->sconn->local_address,
6885 conn->sconn->msg_ctx,
6886 &cli);
6887 if (!NT_STATUS_IS_OK(status)) {
6888 DEBUG(0, ("reply_printqueue: "
6889 "could not connect to spoolss: %s\n",
6890 nt_errstr(status)));
6891 reply_nterror(req, status);
6892 goto out;
6894 b = cli->binding_handle;
6896 ZERO_STRUCT(devmode_ctr);
6898 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
6899 sharename,
6900 NULL, devmode_ctr,
6901 SEC_FLAG_MAXIMUM_ALLOWED,
6902 &handle,
6903 &werr);
6904 if (!NT_STATUS_IS_OK(status)) {
6905 reply_nterror(req, status);
6906 goto out;
6908 if (!W_ERROR_IS_OK(werr)) {
6909 reply_nterror(req, werror_to_ntstatus(werr));
6910 goto out;
6913 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6914 &handle,
6915 0, /* firstjob */
6916 0xff, /* numjobs */
6917 2, /* level */
6918 0, /* offered */
6919 &count,
6920 &info);
6921 if (!W_ERROR_IS_OK(werr)) {
6922 reply_nterror(req, werror_to_ntstatus(werr));
6923 goto out;
6926 if (max_count > 0) {
6927 first = start_index;
6928 } else {
6929 first = start_index + max_count + 1;
6932 if (first >= count) {
6933 num_to_get = first;
6934 } else {
6935 num_to_get = first + MIN(ABS(max_count), count - first);
6938 for (i = first; i < num_to_get; i++) {
6939 char blob[28];
6940 char *p = blob;
6941 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6942 int qstatus;
6943 size_t len = 0;
6944 uint16_t qrapjobid = pjobid_to_rap(sharename,
6945 info[i].info2.job_id);
6947 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6948 qstatus = 2;
6949 } else {
6950 qstatus = 3;
6953 srv_put_dos_date2(p, 0, qtime);
6954 SCVAL(p, 4, qstatus);
6955 SSVAL(p, 5, qrapjobid);
6956 SIVAL(p, 7, info[i].info2.size);
6957 SCVAL(p, 11, 0);
6958 status = srvstr_push(blob, req->flags2, p+12,
6959 info[i].info2.notify_name, 16, STR_ASCII, &len);
6960 if (!NT_STATUS_IS_OK(status)) {
6961 reply_nterror(req, status);
6962 goto out;
6964 if (message_push_blob(
6965 &req->outbuf,
6966 data_blob_const(
6967 blob, sizeof(blob))) == -1) {
6968 reply_nterror(req, NT_STATUS_NO_MEMORY);
6969 goto out;
6973 if (count > 0) {
6974 SSVAL(req->outbuf,smb_vwv0,count);
6975 SSVAL(req->outbuf,smb_vwv1,
6976 (max_count>0?first+count:first-1));
6977 SCVAL(smb_buf(req->outbuf),0,1);
6978 SSVAL(smb_buf(req->outbuf),1,28*count);
6982 DEBUG(3, ("%u entries returned in queue\n",
6983 (unsigned)count));
6985 out:
6986 if (b && is_valid_policy_hnd(&handle)) {
6987 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6992 END_PROFILE(SMBsplretq);
6993 return;
6996 /****************************************************************************
6997 Reply to a printwrite.
6998 ****************************************************************************/
7000 void reply_printwrite(struct smb_request *req)
7002 connection_struct *conn = req->conn;
7003 int numtowrite;
7004 const char *data;
7005 files_struct *fsp;
7007 START_PROFILE(SMBsplwr);
7009 if (req->wct < 1) {
7010 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7011 END_PROFILE(SMBsplwr);
7012 return;
7015 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7017 if (!check_fsp(conn, req, fsp)) {
7018 END_PROFILE(SMBsplwr);
7019 return;
7022 if (!fsp->print_file) {
7023 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7024 END_PROFILE(SMBsplwr);
7025 return;
7028 if (!CHECK_WRITE(fsp)) {
7029 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7030 END_PROFILE(SMBsplwr);
7031 return;
7034 numtowrite = SVAL(req->buf, 1);
7037 * This already protects us against CVE-2017-12163.
7039 if (req->buflen < numtowrite + 3) {
7040 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7041 END_PROFILE(SMBsplwr);
7042 return;
7045 data = (const char *)req->buf + 3;
7047 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
7048 reply_nterror(req, map_nt_error_from_unix(errno));
7049 END_PROFILE(SMBsplwr);
7050 return;
7053 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
7055 END_PROFILE(SMBsplwr);
7056 return;
7059 /****************************************************************************
7060 Reply to a mkdir.
7061 ****************************************************************************/
7063 void reply_mkdir(struct smb_request *req)
7065 connection_struct *conn = req->conn;
7066 struct smb_filename *smb_dname = NULL;
7067 char *directory = NULL;
7068 NTSTATUS status;
7069 uint32_t ucf_flags;
7070 TALLOC_CTX *ctx = talloc_tos();
7072 START_PROFILE(SMBmkdir);
7074 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
7075 STR_TERMINATE, &status);
7076 if (!NT_STATUS_IS_OK(status)) {
7077 reply_nterror(req, status);
7078 goto out;
7081 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
7082 status = filename_convert(ctx, conn,
7083 directory,
7084 ucf_flags,
7086 &smb_dname);
7087 if (!NT_STATUS_IS_OK(status)) {
7088 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7089 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7090 ERRSRV, ERRbadpath);
7091 goto out;
7093 reply_nterror(req, status);
7094 goto out;
7097 status = create_directory(conn, req, smb_dname);
7099 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
7101 if (!NT_STATUS_IS_OK(status)) {
7103 if (!use_nt_status()
7104 && NT_STATUS_EQUAL(status,
7105 NT_STATUS_OBJECT_NAME_COLLISION)) {
7107 * Yes, in the DOS error code case we get a
7108 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
7109 * samba4 torture test.
7111 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
7114 reply_nterror(req, status);
7115 goto out;
7118 reply_outbuf(req, 0, 0);
7120 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
7121 out:
7122 TALLOC_FREE(smb_dname);
7123 END_PROFILE(SMBmkdir);
7124 return;
7127 /****************************************************************************
7128 Reply to a rmdir.
7129 ****************************************************************************/
7131 void reply_rmdir(struct smb_request *req)
7133 connection_struct *conn = req->conn;
7134 struct smb_filename *smb_dname = NULL;
7135 char *directory = NULL;
7136 NTSTATUS status;
7137 TALLOC_CTX *ctx = talloc_tos();
7138 files_struct *fsp = NULL;
7139 int info = 0;
7140 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
7142 START_PROFILE(SMBrmdir);
7144 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
7145 STR_TERMINATE, &status);
7146 if (!NT_STATUS_IS_OK(status)) {
7147 reply_nterror(req, status);
7148 goto out;
7151 status = filename_convert(ctx, conn,
7152 directory,
7153 ucf_flags,
7155 &smb_dname);
7156 if (!NT_STATUS_IS_OK(status)) {
7157 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7158 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7159 ERRSRV, ERRbadpath);
7160 goto out;
7162 reply_nterror(req, status);
7163 goto out;
7166 if (is_ntfs_stream_smb_fname(smb_dname)) {
7167 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
7168 goto out;
7171 status = SMB_VFS_CREATE_FILE(
7172 conn, /* conn */
7173 req, /* req */
7174 smb_dname, /* fname */
7175 DELETE_ACCESS, /* access_mask */
7176 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7177 FILE_SHARE_DELETE),
7178 FILE_OPEN, /* create_disposition*/
7179 FILE_DIRECTORY_FILE, /* create_options */
7180 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
7181 0, /* oplock_request */
7182 NULL, /* lease */
7183 0, /* allocation_size */
7184 0, /* private_flags */
7185 NULL, /* sd */
7186 NULL, /* ea_list */
7187 &fsp, /* result */
7188 &info, /* pinfo */
7189 NULL, NULL); /* create context */
7191 if (!NT_STATUS_IS_OK(status)) {
7192 if (open_was_deferred(req->xconn, req->mid)) {
7193 /* We have re-scheduled this call. */
7194 goto out;
7196 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
7197 bool ok = defer_smb1_sharing_violation(req);
7198 if (ok) {
7199 goto out;
7202 reply_nterror(req, status);
7203 goto out;
7206 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
7207 if (!NT_STATUS_IS_OK(status)) {
7208 close_file(req, fsp, ERROR_CLOSE);
7209 reply_nterror(req, status);
7210 goto out;
7213 if (!set_delete_on_close(fsp, true,
7214 conn->session_info->security_token,
7215 conn->session_info->unix_token)) {
7216 close_file(req, fsp, ERROR_CLOSE);
7217 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7218 goto out;
7221 status = close_file(req, fsp, NORMAL_CLOSE);
7222 if (!NT_STATUS_IS_OK(status)) {
7223 reply_nterror(req, status);
7224 } else {
7225 reply_outbuf(req, 0, 0);
7228 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
7229 out:
7230 TALLOC_FREE(smb_dname);
7231 END_PROFILE(SMBrmdir);
7232 return;
7235 /*******************************************************************
7236 Resolve wildcards in a filename rename.
7237 ********************************************************************/
7239 static bool resolve_wildcards(TALLOC_CTX *ctx,
7240 const char *name1,
7241 const char *name2,
7242 char **pp_newname)
7244 char *name2_copy = NULL;
7245 char *root1 = NULL;
7246 char *root2 = NULL;
7247 char *ext1 = NULL;
7248 char *ext2 = NULL;
7249 char *p,*p2, *pname1, *pname2;
7251 name2_copy = talloc_strdup(ctx, name2);
7252 if (!name2_copy) {
7253 return False;
7256 pname1 = strrchr_m(name1,'/');
7257 pname2 = strrchr_m(name2_copy,'/');
7259 if (!pname1 || !pname2) {
7260 return False;
7263 /* Truncate the copy of name2 at the last '/' */
7264 *pname2 = '\0';
7266 /* Now go past the '/' */
7267 pname1++;
7268 pname2++;
7270 root1 = talloc_strdup(ctx, pname1);
7271 root2 = talloc_strdup(ctx, pname2);
7273 if (!root1 || !root2) {
7274 return False;
7277 p = strrchr_m(root1,'.');
7278 if (p) {
7279 *p = 0;
7280 ext1 = talloc_strdup(ctx, p+1);
7281 } else {
7282 ext1 = talloc_strdup(ctx, "");
7284 p = strrchr_m(root2,'.');
7285 if (p) {
7286 *p = 0;
7287 ext2 = talloc_strdup(ctx, p+1);
7288 } else {
7289 ext2 = talloc_strdup(ctx, "");
7292 if (!ext1 || !ext2) {
7293 return False;
7296 p = root1;
7297 p2 = root2;
7298 while (*p2) {
7299 if (*p2 == '?') {
7300 /* Hmmm. Should this be mb-aware ? */
7301 *p2 = *p;
7302 p2++;
7303 } else if (*p2 == '*') {
7304 *p2 = '\0';
7305 root2 = talloc_asprintf(ctx, "%s%s",
7306 root2,
7308 if (!root2) {
7309 return False;
7311 break;
7312 } else {
7313 p2++;
7315 if (*p) {
7316 p++;
7320 p = ext1;
7321 p2 = ext2;
7322 while (*p2) {
7323 if (*p2 == '?') {
7324 /* Hmmm. Should this be mb-aware ? */
7325 *p2 = *p;
7326 p2++;
7327 } else if (*p2 == '*') {
7328 *p2 = '\0';
7329 ext2 = talloc_asprintf(ctx, "%s%s",
7330 ext2,
7332 if (!ext2) {
7333 return False;
7335 break;
7336 } else {
7337 p2++;
7339 if (*p) {
7340 p++;
7344 if (*ext2) {
7345 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
7346 name2_copy,
7347 root2,
7348 ext2);
7349 } else {
7350 *pp_newname = talloc_asprintf(ctx, "%s/%s",
7351 name2_copy,
7352 root2);
7355 if (!*pp_newname) {
7356 return False;
7359 return True;
7362 /****************************************************************************
7363 Ensure open files have their names updated. Updated to notify other smbd's
7364 asynchronously.
7365 ****************************************************************************/
7367 static void rename_open_files(connection_struct *conn,
7368 struct share_mode_lock *lck,
7369 struct file_id id,
7370 uint32_t orig_name_hash,
7371 const struct smb_filename *smb_fname_dst)
7373 files_struct *fsp;
7374 bool did_rename = False;
7375 NTSTATUS status;
7376 uint32_t new_name_hash = 0;
7378 for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
7379 fsp = file_find_di_next(fsp, false)) {
7380 struct file_id_buf idbuf;
7381 /* fsp_name is a relative path under the fsp. To change this for other
7382 sharepaths we need to manipulate relative paths. */
7383 /* TODO - create the absolute path and manipulate the newname
7384 relative to the sharepath. */
7385 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
7386 continue;
7388 if (fsp->name_hash != orig_name_hash) {
7389 continue;
7391 DBG_DEBUG("renaming file %s "
7392 "(file_id %s) from %s -> %s\n",
7393 fsp_fnum_dbg(fsp),
7394 file_id_str_buf(fsp->file_id, &idbuf),
7395 fsp_str_dbg(fsp),
7396 smb_fname_str_dbg(smb_fname_dst));
7398 status = fsp_set_smb_fname(fsp, smb_fname_dst);
7399 if (NT_STATUS_IS_OK(status)) {
7400 did_rename = True;
7401 new_name_hash = fsp->name_hash;
7405 if (!did_rename) {
7406 struct file_id_buf idbuf;
7407 DBG_DEBUG("no open files on file_id %s "
7408 "for %s\n",
7409 file_id_str_buf(id, &idbuf),
7410 smb_fname_str_dbg(smb_fname_dst));
7413 /* Send messages to all smbd's (not ourself) that the name has changed. */
7414 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
7415 orig_name_hash, new_name_hash,
7416 smb_fname_dst);
7420 /****************************************************************************
7421 We need to check if the source path is a parent directory of the destination
7422 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
7423 refuse the rename with a sharing violation. Under UNIX the above call can
7424 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
7425 probably need to check that the client is a Windows one before disallowing
7426 this as a UNIX client (one with UNIX extensions) can know the source is a
7427 symlink and make this decision intelligently. Found by an excellent bug
7428 report from <AndyLiebman@aol.com>.
7429 ****************************************************************************/
7431 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
7432 const struct smb_filename *smb_fname_dst)
7434 const char *psrc = smb_fname_src->base_name;
7435 const char *pdst = smb_fname_dst->base_name;
7436 size_t slen;
7438 if (psrc[0] == '.' && psrc[1] == '/') {
7439 psrc += 2;
7441 if (pdst[0] == '.' && pdst[1] == '/') {
7442 pdst += 2;
7444 if ((slen = strlen(psrc)) > strlen(pdst)) {
7445 return False;
7447 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
7451 * Do the notify calls from a rename
7454 static void notify_rename(connection_struct *conn, bool is_dir,
7455 const struct smb_filename *smb_fname_src,
7456 const struct smb_filename *smb_fname_dst)
7458 char *parent_dir_src = NULL;
7459 char *parent_dir_dst = NULL;
7460 uint32_t mask;
7462 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
7463 : FILE_NOTIFY_CHANGE_FILE_NAME;
7465 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
7466 &parent_dir_src, NULL) ||
7467 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
7468 &parent_dir_dst, NULL)) {
7469 goto out;
7472 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
7473 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
7474 smb_fname_src->base_name);
7475 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
7476 smb_fname_dst->base_name);
7478 else {
7479 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
7480 smb_fname_src->base_name);
7481 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
7482 smb_fname_dst->base_name);
7485 /* this is a strange one. w2k3 gives an additional event for
7486 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
7487 files, but not directories */
7488 if (!is_dir) {
7489 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
7490 FILE_NOTIFY_CHANGE_ATTRIBUTES
7491 |FILE_NOTIFY_CHANGE_CREATION,
7492 smb_fname_dst->base_name);
7494 out:
7495 TALLOC_FREE(parent_dir_src);
7496 TALLOC_FREE(parent_dir_dst);
7499 /****************************************************************************
7500 Returns an error if the parent directory for a filename is open in an
7501 incompatible way.
7502 ****************************************************************************/
7504 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
7505 const struct smb_filename *smb_fname_dst_in)
7507 struct smb_filename *smb_fname_parent = NULL;
7508 struct file_id id;
7509 files_struct *fsp = NULL;
7510 int ret;
7511 bool ok;
7513 ok = parent_smb_fname(talloc_tos(),
7514 smb_fname_dst_in,
7515 &smb_fname_parent,
7516 NULL);
7517 if (!ok) {
7518 return NT_STATUS_NO_MEMORY;
7521 ret = SMB_VFS_LSTAT(conn, smb_fname_parent);
7522 if (ret == -1) {
7523 return map_nt_error_from_unix(errno);
7527 * We're only checking on this smbd here, mostly good
7528 * enough.. and will pass tests.
7531 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
7532 for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
7533 fsp = file_find_di_next(fsp, true)) {
7534 if (fsp->access_mask & DELETE_ACCESS) {
7535 return NT_STATUS_SHARING_VIOLATION;
7538 return NT_STATUS_OK;
7541 /****************************************************************************
7542 Rename an open file - given an fsp.
7543 ****************************************************************************/
7545 NTSTATUS rename_internals_fsp(connection_struct *conn,
7546 files_struct *fsp,
7547 struct smb_filename *smb_fname_dst_in,
7548 const char *dst_original_lcomp,
7549 uint32_t attrs,
7550 bool replace_if_exists)
7552 TALLOC_CTX *ctx = talloc_tos();
7553 struct smb_filename *smb_fname_dst = NULL;
7554 NTSTATUS status = NT_STATUS_OK;
7555 struct share_mode_lock *lck = NULL;
7556 uint32_t access_mask = SEC_DIR_ADD_FILE;
7557 bool dst_exists, old_is_stream, new_is_stream;
7558 int ret;
7560 status = check_name(conn, smb_fname_dst_in);
7561 if (!NT_STATUS_IS_OK(status)) {
7562 return status;
7565 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
7566 if (!NT_STATUS_IS_OK(status)) {
7567 return status;
7570 if (file_has_open_streams(fsp)) {
7571 return NT_STATUS_ACCESS_DENIED;
7574 /* Make a copy of the dst smb_fname structs */
7576 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
7577 if (smb_fname_dst == NULL) {
7578 status = NT_STATUS_NO_MEMORY;
7579 goto out;
7583 * Check for special case with case preserving and not
7584 * case sensitive. If the new last component differs from the original
7585 * last component only by case, then we should allow
7586 * the rename (user is trying to change the case of the
7587 * filename).
7589 if (!conn->case_sensitive && conn->case_preserve &&
7590 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7591 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
7592 char *fname_dst_parent = NULL;
7593 const char *fname_dst_lcomp = NULL;
7594 char *orig_lcomp_path = NULL;
7595 char *orig_lcomp_stream = NULL;
7596 bool ok = true;
7599 * Split off the last component of the processed
7600 * destination name. We will compare this to
7601 * the split components of dst_original_lcomp.
7603 if (!parent_dirname(ctx,
7604 smb_fname_dst->base_name,
7605 &fname_dst_parent,
7606 &fname_dst_lcomp)) {
7607 status = NT_STATUS_NO_MEMORY;
7608 goto out;
7612 * The dst_original_lcomp component contains
7613 * the last_component of the path + stream
7614 * name (if a stream exists).
7616 * Split off the stream name so we
7617 * can check them separately.
7620 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
7621 /* POSIX - no stream component. */
7622 orig_lcomp_path = talloc_strdup(ctx,
7623 dst_original_lcomp);
7624 if (orig_lcomp_path == NULL) {
7625 ok = false;
7627 } else {
7628 ok = split_stream_filename(ctx,
7629 dst_original_lcomp,
7630 &orig_lcomp_path,
7631 &orig_lcomp_stream);
7634 if (!ok) {
7635 TALLOC_FREE(fname_dst_parent);
7636 status = NT_STATUS_NO_MEMORY;
7637 goto out;
7640 /* If the base names only differ by case, use original. */
7641 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
7642 char *tmp;
7644 * Replace the modified last component with the
7645 * original.
7647 if (!ISDOT(fname_dst_parent)) {
7648 tmp = talloc_asprintf(smb_fname_dst,
7649 "%s/%s",
7650 fname_dst_parent,
7651 orig_lcomp_path);
7652 } else {
7653 tmp = talloc_strdup(smb_fname_dst,
7654 orig_lcomp_path);
7656 if (tmp == NULL) {
7657 status = NT_STATUS_NO_MEMORY;
7658 TALLOC_FREE(fname_dst_parent);
7659 TALLOC_FREE(orig_lcomp_path);
7660 TALLOC_FREE(orig_lcomp_stream);
7661 goto out;
7663 TALLOC_FREE(smb_fname_dst->base_name);
7664 smb_fname_dst->base_name = tmp;
7667 /* If the stream_names only differ by case, use original. */
7668 if(!strcsequal(smb_fname_dst->stream_name,
7669 orig_lcomp_stream)) {
7670 /* Use the original stream. */
7671 char *tmp = talloc_strdup(smb_fname_dst,
7672 orig_lcomp_stream);
7673 if (tmp == NULL) {
7674 status = NT_STATUS_NO_MEMORY;
7675 TALLOC_FREE(fname_dst_parent);
7676 TALLOC_FREE(orig_lcomp_path);
7677 TALLOC_FREE(orig_lcomp_stream);
7678 goto out;
7680 TALLOC_FREE(smb_fname_dst->stream_name);
7681 smb_fname_dst->stream_name = tmp;
7683 TALLOC_FREE(fname_dst_parent);
7684 TALLOC_FREE(orig_lcomp_path);
7685 TALLOC_FREE(orig_lcomp_stream);
7689 * If the src and dest names are identical - including case,
7690 * don't do the rename, just return success.
7693 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7694 strcsequal(fsp->fsp_name->stream_name,
7695 smb_fname_dst->stream_name)) {
7696 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
7697 "- returning success\n",
7698 smb_fname_str_dbg(smb_fname_dst)));
7699 status = NT_STATUS_OK;
7700 goto out;
7703 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
7704 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
7706 /* Return the correct error code if both names aren't streams. */
7707 if (!old_is_stream && new_is_stream) {
7708 status = NT_STATUS_OBJECT_NAME_INVALID;
7709 goto out;
7712 if (old_is_stream && !new_is_stream) {
7713 status = NT_STATUS_INVALID_PARAMETER;
7714 goto out;
7717 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
7719 if(!replace_if_exists && dst_exists) {
7720 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
7721 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7722 smb_fname_str_dbg(smb_fname_dst)));
7723 status = NT_STATUS_OBJECT_NAME_COLLISION;
7724 goto out;
7728 * Drop the pathref fsp on the destination otherwise we trip upon in in
7729 * the below check for open files check.
7731 if (smb_fname_dst_in->fsp != NULL) {
7732 fd_close(smb_fname_dst_in->fsp);
7733 file_free(NULL, smb_fname_dst_in->fsp);
7734 SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
7737 if (dst_exists) {
7738 struct file_id fileid = vfs_file_id_from_sbuf(conn,
7739 &smb_fname_dst->st);
7740 files_struct *dst_fsp = file_find_di_first(conn->sconn,
7741 fileid, true);
7742 /* The file can be open when renaming a stream */
7743 if (dst_fsp && !new_is_stream) {
7744 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
7745 status = NT_STATUS_ACCESS_DENIED;
7746 goto out;
7750 /* Ensure we have a valid stat struct for the source. */
7751 status = vfs_stat_fsp(fsp);
7752 if (!NT_STATUS_IS_OK(status)) {
7753 goto out;
7756 status = can_rename(conn, fsp, attrs);
7758 if (!NT_STATUS_IS_OK(status)) {
7759 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7760 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7761 smb_fname_str_dbg(smb_fname_dst)));
7762 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
7763 status = NT_STATUS_ACCESS_DENIED;
7764 goto out;
7767 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
7768 status = NT_STATUS_ACCESS_DENIED;
7769 goto out;
7772 /* Do we have rights to move into the destination ? */
7773 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
7774 /* We're moving a directory. */
7775 access_mask = SEC_DIR_ADD_SUBDIR;
7777 status = check_parent_access(conn,
7778 conn->cwd_fsp,
7779 smb_fname_dst,
7780 access_mask);
7781 if (!NT_STATUS_IS_OK(status)) {
7782 DBG_INFO("check_parent_access on "
7783 "dst %s returned %s\n",
7784 smb_fname_str_dbg(smb_fname_dst),
7785 nt_errstr(status));
7786 goto out;
7789 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
7792 * We have the file open ourselves, so not being able to get the
7793 * corresponding share mode lock is a fatal error.
7796 SMB_ASSERT(lck != NULL);
7798 ret = SMB_VFS_RENAMEAT(conn,
7799 conn->cwd_fsp,
7800 fsp->fsp_name,
7801 conn->cwd_fsp,
7802 smb_fname_dst);
7803 if (ret == 0) {
7804 uint32_t create_options = fh_get_private_options(fsp->fh);
7806 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
7807 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7808 smb_fname_str_dbg(smb_fname_dst)));
7810 if (!fsp->fsp_flags.is_directory &&
7811 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
7812 (lp_map_archive(SNUM(conn)) ||
7813 lp_store_dos_attributes(SNUM(conn)))) {
7814 /* We must set the archive bit on the newly
7815 renamed file. */
7816 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
7817 uint32_t old_dosmode = dos_mode(conn,
7818 smb_fname_dst);
7819 file_set_dosmode(conn,
7820 smb_fname_dst,
7821 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
7822 NULL,
7823 true);
7827 notify_rename(conn,
7828 fsp->fsp_flags.is_directory,
7829 fsp->fsp_name,
7830 smb_fname_dst);
7832 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
7833 smb_fname_dst);
7836 * A rename acts as a new file create w.r.t. allowing an initial delete
7837 * on close, probably because in Windows there is a new handle to the
7838 * new file. If initial delete on close was requested but not
7839 * originally set, we need to set it here. This is probably not 100% correct,
7840 * but will work for the CIFSFS client which in non-posix mode
7841 * depends on these semantics. JRA.
7844 if (create_options & FILE_DELETE_ON_CLOSE) {
7845 status = can_set_delete_on_close(fsp, 0);
7847 if (NT_STATUS_IS_OK(status)) {
7848 /* Note that here we set the *initial* delete on close flag,
7849 * not the regular one. The magic gets handled in close. */
7850 fsp->fsp_flags.initial_delete_on_close = true;
7853 TALLOC_FREE(lck);
7854 status = NT_STATUS_OK;
7855 goto out;
7858 TALLOC_FREE(lck);
7860 if (errno == ENOTDIR || errno == EISDIR) {
7861 status = NT_STATUS_OBJECT_NAME_COLLISION;
7862 } else {
7863 status = map_nt_error_from_unix(errno);
7866 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7867 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7868 smb_fname_str_dbg(smb_fname_dst)));
7870 out:
7871 TALLOC_FREE(smb_fname_dst);
7873 return status;
7876 /****************************************************************************
7877 The guts of the rename command, split out so it may be called by the NT SMB
7878 code.
7879 ****************************************************************************/
7881 NTSTATUS rename_internals(TALLOC_CTX *ctx,
7882 connection_struct *conn,
7883 struct smb_request *req,
7884 struct smb_filename *smb_fname_src,
7885 const char *src_original_lcomp,
7886 struct smb_filename *smb_fname_dst,
7887 const char *dst_original_lcomp,
7888 uint32_t attrs,
7889 bool replace_if_exists,
7890 uint32_t access_mask)
7892 char *fname_src_dir = NULL;
7893 struct smb_filename *smb_fname_src_dir = NULL;
7894 char *fname_src_mask = NULL;
7895 int count=0;
7896 NTSTATUS status = NT_STATUS_OK;
7897 struct smb_Dir *dir_hnd = NULL;
7898 const char *dname = NULL;
7899 char *talloced = NULL;
7900 long offset = 0;
7901 int create_options = 0;
7902 struct smb2_create_blobs *posx = NULL;
7903 int rc;
7904 bool src_has_wild = false;
7905 bool dest_has_wild = false;
7908 * Split the old name into directory and last component
7909 * strings. Note that unix_convert may have stripped off a
7910 * leading ./ from both name and newname if the rename is
7911 * at the root of the share. We need to make sure either both
7912 * name and newname contain a / character or neither of them do
7913 * as this is checked in resolve_wildcards().
7916 /* Split up the directory from the filename/mask. */
7917 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7918 &fname_src_dir, &fname_src_mask);
7919 if (!NT_STATUS_IS_OK(status)) {
7920 status = NT_STATUS_NO_MEMORY;
7921 goto out;
7924 if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
7926 * Check the wildcard mask *before*
7927 * unmangling. As mangling is done
7928 * for names that can't be returned
7929 * to Windows the unmangled name may
7930 * contain Windows wildcard characters.
7932 if (src_original_lcomp != NULL) {
7933 src_has_wild = ms_has_wild(src_original_lcomp);
7935 dest_has_wild = ms_has_wild(dst_original_lcomp);
7939 * We should only check the mangled cache
7940 * here if unix_convert failed. This means
7941 * that the path in 'mask' doesn't exist
7942 * on the file system and so we need to look
7943 * for a possible mangle. This patch from
7944 * Tine Smukavec <valentin.smukavec@hermes.si>.
7947 if (!VALID_STAT(smb_fname_src->st) &&
7948 mangle_is_mangled(fname_src_mask, conn->params)) {
7949 char *new_mask = NULL;
7950 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
7951 conn->params);
7952 if (new_mask) {
7953 TALLOC_FREE(fname_src_mask);
7954 fname_src_mask = new_mask;
7958 if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
7959 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
7960 if (!NT_STATUS_IS_OK(status)) {
7961 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
7962 nt_errstr(status));
7963 goto out;
7967 if (!src_has_wild) {
7968 files_struct *fsp;
7971 * Only one file needs to be renamed. Append the mask back
7972 * onto the directory.
7974 TALLOC_FREE(smb_fname_src->base_name);
7975 if (ISDOT(fname_src_dir)) {
7976 /* Ensure we use canonical names on open. */
7977 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7978 "%s",
7979 fname_src_mask);
7980 } else {
7981 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7982 "%s/%s",
7983 fname_src_dir,
7984 fname_src_mask);
7986 if (!smb_fname_src->base_name) {
7987 status = NT_STATUS_NO_MEMORY;
7988 goto out;
7991 DEBUG(3, ("rename_internals: case_sensitive = %d, "
7992 "case_preserve = %d, short case preserve = %d, "
7993 "directory = %s, newname = %s, "
7994 "last_component_dest = %s\n",
7995 conn->case_sensitive, conn->case_preserve,
7996 conn->short_case_preserve,
7997 smb_fname_str_dbg(smb_fname_src),
7998 smb_fname_str_dbg(smb_fname_dst),
7999 dst_original_lcomp));
8001 /* The dest name still may have wildcards. */
8002 if (dest_has_wild) {
8003 char *fname_dst_mod = NULL;
8004 if (!resolve_wildcards(smb_fname_dst,
8005 smb_fname_src->base_name,
8006 smb_fname_dst->base_name,
8007 &fname_dst_mod)) {
8008 DEBUG(6, ("rename_internals: resolve_wildcards "
8009 "%s %s failed\n",
8010 smb_fname_src->base_name,
8011 smb_fname_dst->base_name));
8012 status = NT_STATUS_NO_MEMORY;
8013 goto out;
8015 TALLOC_FREE(smb_fname_dst->base_name);
8016 smb_fname_dst->base_name = fname_dst_mod;
8019 ZERO_STRUCT(smb_fname_src->st);
8021 rc = vfs_stat(conn, smb_fname_src);
8022 if (rc == -1) {
8023 status = map_nt_error_from_unix_common(errno);
8024 goto out;
8027 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8028 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
8029 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8031 if (!NT_STATUS_IS_OK(status)) {
8032 goto out;
8035 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
8036 create_options |= FILE_DIRECTORY_FILE;
8039 status = SMB_VFS_CREATE_FILE(
8040 conn, /* conn */
8041 req, /* req */
8042 smb_fname_src, /* fname */
8043 access_mask, /* access_mask */
8044 (FILE_SHARE_READ | /* share_access */
8045 FILE_SHARE_WRITE),
8046 FILE_OPEN, /* create_disposition*/
8047 create_options, /* create_options */
8048 0, /* file_attributes */
8049 0, /* oplock_request */
8050 NULL, /* lease */
8051 0, /* allocation_size */
8052 0, /* private_flags */
8053 NULL, /* sd */
8054 NULL, /* ea_list */
8055 &fsp, /* result */
8056 NULL, /* pinfo */
8057 posx, /* in_context_blobs */
8058 NULL); /* out_context_blobs */
8060 if (!NT_STATUS_IS_OK(status)) {
8061 DEBUG(3, ("Could not open rename source %s: %s\n",
8062 smb_fname_str_dbg(smb_fname_src),
8063 nt_errstr(status)));
8064 goto out;
8067 status = rename_internals_fsp(conn,
8068 fsp,
8069 smb_fname_dst,
8070 dst_original_lcomp,
8071 attrs,
8072 replace_if_exists);
8074 close_file(req, fsp, NORMAL_CLOSE);
8076 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
8077 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
8078 smb_fname_str_dbg(smb_fname_dst)));
8080 goto out;
8084 * Wildcards - process each file that matches.
8086 if (strequal(fname_src_mask, "????????.???")) {
8087 TALLOC_FREE(fname_src_mask);
8088 fname_src_mask = talloc_strdup(ctx, "*");
8089 if (!fname_src_mask) {
8090 status = NT_STATUS_NO_MEMORY;
8091 goto out;
8095 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
8096 fname_src_dir,
8097 NULL,
8098 NULL,
8099 smb_fname_src->twrp,
8100 smb_fname_src->flags);
8101 if (smb_fname_src_dir == NULL) {
8102 status = NT_STATUS_NO_MEMORY;
8103 goto out;
8106 status = check_name(conn, smb_fname_src_dir);
8107 if (!NT_STATUS_IS_OK(status)) {
8108 goto out;
8111 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
8112 attrs);
8113 if (dir_hnd == NULL) {
8114 status = map_nt_error_from_unix(errno);
8115 goto out;
8118 status = NT_STATUS_NO_SUCH_FILE;
8120 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8121 * - gentest fix. JRA
8124 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
8125 &talloced))) {
8126 files_struct *fsp = NULL;
8127 char *destname = NULL;
8128 bool sysdir_entry = False;
8130 /* Quick check for "." and ".." */
8131 if (ISDOT(dname) || ISDOTDOT(dname)) {
8132 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
8133 sysdir_entry = True;
8134 } else {
8135 TALLOC_FREE(talloced);
8136 continue;
8140 if (!is_visible_file(conn,
8141 dir_hnd,
8142 dname,
8143 &smb_fname_src->st,
8144 false)) {
8145 TALLOC_FREE(talloced);
8146 continue;
8149 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
8150 TALLOC_FREE(talloced);
8151 continue;
8154 if (sysdir_entry) {
8155 status = NT_STATUS_OBJECT_NAME_INVALID;
8156 break;
8159 TALLOC_FREE(smb_fname_src->base_name);
8160 if (ISDOT(fname_src_dir)) {
8161 /* Ensure we use canonical names on open. */
8162 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8163 "%s",
8164 dname);
8165 } else {
8166 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8167 "%s/%s",
8168 fname_src_dir,
8169 dname);
8171 if (!smb_fname_src->base_name) {
8172 status = NT_STATUS_NO_MEMORY;
8173 goto out;
8176 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
8177 smb_fname_dst->base_name,
8178 &destname)) {
8179 DEBUG(6, ("resolve_wildcards %s %s failed\n",
8180 smb_fname_src->base_name, destname));
8181 TALLOC_FREE(talloced);
8182 continue;
8184 if (!destname) {
8185 status = NT_STATUS_NO_MEMORY;
8186 goto out;
8189 TALLOC_FREE(smb_fname_dst->base_name);
8190 smb_fname_dst->base_name = destname;
8192 ZERO_STRUCT(smb_fname_src->st);
8193 vfs_stat(conn, smb_fname_src);
8195 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8196 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
8197 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8199 if (!NT_STATUS_IS_OK(status)) {
8200 DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
8201 smb_fname_str_dbg(smb_fname_src),
8202 nt_errstr(status));
8203 break;
8206 create_options = 0;
8208 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
8209 create_options |= FILE_DIRECTORY_FILE;
8212 status = SMB_VFS_CREATE_FILE(
8213 conn, /* conn */
8214 req, /* req */
8215 smb_fname_src, /* fname */
8216 access_mask, /* access_mask */
8217 (FILE_SHARE_READ | /* share_access */
8218 FILE_SHARE_WRITE),
8219 FILE_OPEN, /* create_disposition*/
8220 create_options, /* create_options */
8221 0, /* file_attributes */
8222 0, /* oplock_request */
8223 NULL, /* lease */
8224 0, /* allocation_size */
8225 0, /* private_flags */
8226 NULL, /* sd */
8227 NULL, /* ea_list */
8228 &fsp, /* result */
8229 NULL, /* pinfo */
8230 posx, /* in_context_blobs */
8231 NULL); /* out_context_blobs */
8233 if (!NT_STATUS_IS_OK(status)) {
8234 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
8235 "returned %s rename %s -> %s\n",
8236 nt_errstr(status),
8237 smb_fname_str_dbg(smb_fname_src),
8238 smb_fname_str_dbg(smb_fname_dst)));
8239 break;
8242 dst_original_lcomp = talloc_strdup(smb_fname_dst, dname);
8243 if (dst_original_lcomp == NULL) {
8244 status = NT_STATUS_NO_MEMORY;
8245 goto out;
8248 status = rename_internals_fsp(conn,
8249 fsp,
8250 smb_fname_dst,
8251 dst_original_lcomp,
8252 attrs,
8253 replace_if_exists);
8255 close_file(req, fsp, NORMAL_CLOSE);
8257 if (!NT_STATUS_IS_OK(status)) {
8258 DEBUG(3, ("rename_internals_fsp returned %s for "
8259 "rename %s -> %s\n", nt_errstr(status),
8260 smb_fname_str_dbg(smb_fname_src),
8261 smb_fname_str_dbg(smb_fname_dst)));
8262 break;
8265 count++;
8267 DEBUG(3,("rename_internals: doing rename on %s -> "
8268 "%s\n", smb_fname_str_dbg(smb_fname_src),
8269 smb_fname_str_dbg(smb_fname_src)));
8270 TALLOC_FREE(talloced);
8272 TALLOC_FREE(dir_hnd);
8274 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
8275 status = map_nt_error_from_unix(errno);
8278 out:
8279 TALLOC_FREE(posx);
8280 TALLOC_FREE(talloced);
8281 TALLOC_FREE(smb_fname_src_dir);
8282 TALLOC_FREE(fname_src_dir);
8283 TALLOC_FREE(fname_src_mask);
8284 return status;
8287 /****************************************************************************
8288 Reply to a mv.
8289 ****************************************************************************/
8291 void reply_mv(struct smb_request *req)
8293 connection_struct *conn = req->conn;
8294 char *name = NULL;
8295 char *newname = NULL;
8296 const char *p;
8297 uint32_t attrs;
8298 NTSTATUS status;
8299 TALLOC_CTX *ctx = talloc_tos();
8300 struct smb_filename *smb_fname_src = NULL;
8301 const char *src_original_lcomp = NULL;
8302 struct smb_filename *smb_fname_dst = NULL;
8303 const char *dst_original_lcomp = NULL;
8304 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
8305 (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
8306 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
8307 (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
8308 bool stream_rename = false;
8310 START_PROFILE(SMBmv);
8312 if (req->wct < 1) {
8313 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8314 goto out;
8317 attrs = SVAL(req->vwv+0, 0);
8319 p = (const char *)req->buf + 1;
8320 p += srvstr_get_path_req(ctx, req, &name, p, STR_TERMINATE,
8321 &status);
8322 if (!NT_STATUS_IS_OK(status)) {
8323 reply_nterror(req, status);
8324 goto out;
8326 p++;
8327 p += srvstr_get_path_req(ctx, req, &newname, p, STR_TERMINATE,
8328 &status);
8329 if (!NT_STATUS_IS_OK(status)) {
8330 reply_nterror(req, status);
8331 goto out;
8334 if (!req->posix_pathnames) {
8335 /* The newname must begin with a ':' if the
8336 name contains a ':'. */
8337 if (strchr_m(name, ':')) {
8338 if (newname[0] != ':') {
8339 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8340 goto out;
8342 stream_rename = true;
8346 status = filename_convert(ctx,
8347 conn,
8348 name,
8349 src_ucf_flags,
8351 &smb_fname_src);
8353 if (!NT_STATUS_IS_OK(status)) {
8354 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8355 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8356 ERRSRV, ERRbadpath);
8357 goto out;
8359 reply_nterror(req, status);
8360 goto out;
8363 /* Get the last component of the source for rename_internals(). */
8364 src_original_lcomp = get_original_lcomp(ctx,
8365 conn,
8366 name,
8367 dst_ucf_flags);
8368 if (src_original_lcomp == NULL) {
8369 reply_nterror(req, NT_STATUS_NO_MEMORY);
8370 goto out;
8373 status = filename_convert(ctx,
8374 conn,
8375 newname,
8376 dst_ucf_flags,
8378 &smb_fname_dst);
8380 if (!NT_STATUS_IS_OK(status)) {
8381 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8382 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8383 ERRSRV, ERRbadpath);
8384 goto out;
8386 reply_nterror(req, status);
8387 goto out;
8390 /* Get the last component of the destination for rename_internals(). */
8391 dst_original_lcomp = get_original_lcomp(ctx,
8392 conn,
8393 newname,
8394 dst_ucf_flags);
8395 if (dst_original_lcomp == NULL) {
8396 reply_nterror(req, NT_STATUS_NO_MEMORY);
8397 goto out;
8400 if (stream_rename) {
8401 /* smb_fname_dst->base_name must be the same as
8402 smb_fname_src->base_name. */
8403 TALLOC_FREE(smb_fname_dst->base_name);
8404 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
8405 smb_fname_src->base_name);
8406 if (!smb_fname_dst->base_name) {
8407 reply_nterror(req, NT_STATUS_NO_MEMORY);
8408 goto out;
8412 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
8413 smb_fname_str_dbg(smb_fname_dst)));
8415 status = rename_internals(ctx,
8416 conn,
8417 req,
8418 smb_fname_src,
8419 src_original_lcomp,
8420 smb_fname_dst,
8421 dst_original_lcomp,
8422 attrs,
8423 false,
8424 DELETE_ACCESS);
8425 if (!NT_STATUS_IS_OK(status)) {
8426 if (open_was_deferred(req->xconn, req->mid)) {
8427 /* We have re-scheduled this call. */
8428 goto out;
8430 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
8431 bool ok = defer_smb1_sharing_violation(req);
8432 if (ok) {
8433 goto out;
8436 reply_nterror(req, status);
8437 goto out;
8440 reply_outbuf(req, 0, 0);
8441 out:
8442 TALLOC_FREE(smb_fname_src);
8443 TALLOC_FREE(smb_fname_dst);
8444 END_PROFILE(SMBmv);
8445 return;
8448 /*******************************************************************
8449 Copy a file as part of a reply_copy.
8450 ******************************************************************/
8453 * TODO: check error codes on all callers
8456 NTSTATUS copy_file(TALLOC_CTX *ctx,
8457 connection_struct *conn,
8458 struct smb_filename *smb_fname_src,
8459 struct smb_filename *smb_fname_dst,
8460 int ofun,
8461 int count,
8462 bool target_is_directory)
8464 struct smb_filename *smb_fname_dst_tmp = NULL;
8465 off_t ret=-1;
8466 files_struct *fsp1,*fsp2;
8467 uint32_t dosattrs;
8468 uint32_t new_create_disposition;
8469 NTSTATUS status;
8472 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
8473 if (smb_fname_dst_tmp == NULL) {
8474 return NT_STATUS_NO_MEMORY;
8478 * If the target is a directory, extract the last component from the
8479 * src filename and append it to the dst filename
8481 if (target_is_directory) {
8482 const char *p;
8484 /* dest/target can't be a stream if it's a directory. */
8485 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
8487 p = strrchr_m(smb_fname_src->base_name,'/');
8488 if (p) {
8489 p++;
8490 } else {
8491 p = smb_fname_src->base_name;
8493 smb_fname_dst_tmp->base_name =
8494 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
8496 if (!smb_fname_dst_tmp->base_name) {
8497 status = NT_STATUS_NO_MEMORY;
8498 goto out;
8502 status = vfs_file_exist(conn, smb_fname_src);
8503 if (!NT_STATUS_IS_OK(status)) {
8504 goto out;
8507 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8508 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
8509 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8511 if (!NT_STATUS_IS_OK(status)) {
8512 goto out;
8515 if (!target_is_directory && count) {
8516 new_create_disposition = FILE_OPEN;
8517 } else {
8518 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
8519 0, ofun,
8520 NULL, NULL,
8521 &new_create_disposition,
8522 NULL,
8523 NULL)) {
8524 status = NT_STATUS_INVALID_PARAMETER;
8525 goto out;
8529 /* Open the src file for reading. */
8530 status = SMB_VFS_CREATE_FILE(
8531 conn, /* conn */
8532 NULL, /* req */
8533 smb_fname_src, /* fname */
8534 FILE_GENERIC_READ, /* access_mask */
8535 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
8536 FILE_OPEN, /* create_disposition*/
8537 0, /* create_options */
8538 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
8539 INTERNAL_OPEN_ONLY, /* oplock_request */
8540 NULL, /* lease */
8541 0, /* allocation_size */
8542 0, /* private_flags */
8543 NULL, /* sd */
8544 NULL, /* ea_list */
8545 &fsp1, /* result */
8546 NULL, /* psbuf */
8547 NULL, NULL); /* create context */
8549 if (!NT_STATUS_IS_OK(status)) {
8550 goto out;
8553 dosattrs = dos_mode(conn, smb_fname_src);
8555 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
8556 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
8559 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
8560 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
8561 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8562 goto out;
8564 if (!NT_STATUS_IS_OK(status) &&
8565 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
8567 goto out;
8570 /* Open the dst file for writing. */
8571 status = SMB_VFS_CREATE_FILE(
8572 conn, /* conn */
8573 NULL, /* req */
8574 smb_fname_dst, /* fname */
8575 FILE_GENERIC_WRITE, /* access_mask */
8576 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
8577 new_create_disposition, /* create_disposition*/
8578 0, /* create_options */
8579 dosattrs, /* file_attributes */
8580 INTERNAL_OPEN_ONLY, /* oplock_request */
8581 NULL, /* lease */
8582 0, /* allocation_size */
8583 0, /* private_flags */
8584 NULL, /* sd */
8585 NULL, /* ea_list */
8586 &fsp2, /* result */
8587 NULL, /* psbuf */
8588 NULL, NULL); /* create context */
8590 if (!NT_STATUS_IS_OK(status)) {
8591 close_file(NULL, fsp1, ERROR_CLOSE);
8592 goto out;
8595 if (ofun & OPENX_FILE_EXISTS_OPEN) {
8596 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
8597 if (ret == -1) {
8598 DEBUG(0, ("error - vfs lseek returned error %s\n",
8599 strerror(errno)));
8600 status = map_nt_error_from_unix(errno);
8601 close_file(NULL, fsp1, ERROR_CLOSE);
8602 close_file(NULL, fsp2, ERROR_CLOSE);
8603 goto out;
8607 /* Do the actual copy. */
8608 if (smb_fname_src->st.st_ex_size) {
8609 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
8610 } else {
8611 ret = 0;
8614 close_file(NULL, fsp1, NORMAL_CLOSE);
8616 /* Ensure the modtime is set correctly on the destination file. */
8617 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
8620 * As we are opening fsp1 read-only we only expect
8621 * an error on close on fsp2 if we are out of space.
8622 * Thus we don't look at the error return from the
8623 * close of fsp1.
8625 status = close_file(NULL, fsp2, NORMAL_CLOSE);
8627 if (!NT_STATUS_IS_OK(status)) {
8628 goto out;
8631 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
8632 status = NT_STATUS_DISK_FULL;
8633 goto out;
8636 status = NT_STATUS_OK;
8638 out:
8639 TALLOC_FREE(smb_fname_dst_tmp);
8640 return status;
8643 /****************************************************************************
8644 Reply to a file copy.
8645 ****************************************************************************/
8647 void reply_copy(struct smb_request *req)
8649 connection_struct *conn = req->conn;
8650 struct smb_filename *smb_fname_src = NULL;
8651 struct smb_filename *smb_fname_src_dir = NULL;
8652 struct smb_filename *smb_fname_dst = NULL;
8653 char *fname_src = NULL;
8654 char *fname_dst = NULL;
8655 char *fname_src_mask = NULL;
8656 char *fname_src_dir = NULL;
8657 const char *p;
8658 int count=0;
8659 int error = ERRnoaccess;
8660 int tid2;
8661 int ofun;
8662 int flags;
8663 bool target_is_directory=False;
8664 bool source_has_wild = False;
8665 bool dest_has_wild = False;
8666 NTSTATUS status;
8667 uint32_t ucf_flags_src = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
8668 ucf_flags_from_smb_request(req);
8669 uint32_t ucf_flags_dst = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
8670 ucf_flags_from_smb_request(req);
8671 TALLOC_CTX *ctx = talloc_tos();
8673 START_PROFILE(SMBcopy);
8675 if (req->wct < 3) {
8676 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8677 goto out;
8680 tid2 = SVAL(req->vwv+0, 0);
8681 ofun = SVAL(req->vwv+1, 0);
8682 flags = SVAL(req->vwv+2, 0);
8684 p = (const char *)req->buf;
8685 p += srvstr_get_path_req(ctx, req, &fname_src, p, STR_TERMINATE,
8686 &status);
8687 if (!NT_STATUS_IS_OK(status)) {
8688 reply_nterror(req, status);
8689 goto out;
8691 p += srvstr_get_path_req(ctx, req, &fname_dst, p, STR_TERMINATE,
8692 &status);
8693 if (!NT_STATUS_IS_OK(status)) {
8694 reply_nterror(req, status);
8695 goto out;
8698 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
8700 if (tid2 != conn->cnum) {
8701 /* can't currently handle inter share copies XXXX */
8702 DEBUG(3,("Rejecting inter-share copy\n"));
8703 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
8704 goto out;
8707 status = filename_convert(ctx, conn,
8708 fname_src,
8709 ucf_flags_src,
8711 &smb_fname_src);
8712 if (!NT_STATUS_IS_OK(status)) {
8713 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8714 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8715 ERRSRV, ERRbadpath);
8716 goto out;
8718 reply_nterror(req, status);
8719 goto out;
8722 status = filename_convert(ctx, conn,
8723 fname_dst,
8724 ucf_flags_dst,
8726 &smb_fname_dst);
8727 if (!NT_STATUS_IS_OK(status)) {
8728 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8729 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8730 ERRSRV, ERRbadpath);
8731 goto out;
8733 reply_nterror(req, status);
8734 goto out;
8737 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
8739 if ((flags&1) && target_is_directory) {
8740 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
8741 goto out;
8744 if ((flags&2) && !target_is_directory) {
8745 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
8746 goto out;
8749 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
8750 /* wants a tree copy! XXXX */
8751 DEBUG(3,("Rejecting tree copy\n"));
8752 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8753 goto out;
8756 /* Split up the directory from the filename/mask. */
8757 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
8758 &fname_src_dir, &fname_src_mask);
8759 if (!NT_STATUS_IS_OK(status)) {
8760 reply_nterror(req, NT_STATUS_NO_MEMORY);
8761 goto out;
8764 if (!req->posix_pathnames) {
8765 char *orig_src_lcomp = NULL;
8766 char *orig_dst_lcomp = NULL;
8768 * Check the wildcard mask *before*
8769 * unmangling. As mangling is done
8770 * for names that can't be returned
8771 * to Windows the unmangled name may
8772 * contain Windows wildcard characters.
8774 orig_src_lcomp = get_original_lcomp(ctx,
8775 conn,
8776 fname_src,
8777 ucf_flags_src);
8778 if (orig_src_lcomp == NULL) {
8779 reply_nterror(req, NT_STATUS_NO_MEMORY);
8780 goto out;
8782 orig_dst_lcomp = get_original_lcomp(ctx,
8783 conn,
8784 fname_dst,
8785 ucf_flags_dst);
8786 if (orig_dst_lcomp == NULL) {
8787 reply_nterror(req, NT_STATUS_NO_MEMORY);
8788 goto out;
8790 source_has_wild = ms_has_wild(orig_src_lcomp);
8791 dest_has_wild = ms_has_wild(orig_dst_lcomp);
8792 TALLOC_FREE(orig_src_lcomp);
8793 TALLOC_FREE(orig_dst_lcomp);
8797 * We should only check the mangled cache
8798 * here if unix_convert failed. This means
8799 * that the path in 'mask' doesn't exist
8800 * on the file system and so we need to look
8801 * for a possible mangle. This patch from
8802 * Tine Smukavec <valentin.smukavec@hermes.si>.
8804 if (!VALID_STAT(smb_fname_src->st) &&
8805 mangle_is_mangled(fname_src_mask, conn->params)) {
8806 char *new_mask = NULL;
8807 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
8808 &new_mask, conn->params);
8810 /* Use demangled name if one was successfully found. */
8811 if (new_mask) {
8812 TALLOC_FREE(fname_src_mask);
8813 fname_src_mask = new_mask;
8817 if (!source_has_wild) {
8820 * Only one file needs to be copied. Append the mask back onto
8821 * the directory.
8823 TALLOC_FREE(smb_fname_src->base_name);
8824 if (ISDOT(fname_src_dir)) {
8825 /* Ensure we use canonical names on open. */
8826 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8827 "%s",
8828 fname_src_mask);
8829 } else {
8830 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8831 "%s/%s",
8832 fname_src_dir,
8833 fname_src_mask);
8835 if (!smb_fname_src->base_name) {
8836 reply_nterror(req, NT_STATUS_NO_MEMORY);
8837 goto out;
8840 if (dest_has_wild) {
8841 char *fname_dst_mod = NULL;
8842 if (!resolve_wildcards(smb_fname_dst,
8843 smb_fname_src->base_name,
8844 smb_fname_dst->base_name,
8845 &fname_dst_mod)) {
8846 reply_nterror(req, NT_STATUS_NO_MEMORY);
8847 goto out;
8849 TALLOC_FREE(smb_fname_dst->base_name);
8850 smb_fname_dst->base_name = fname_dst_mod;
8853 status = check_name(conn, smb_fname_src);
8854 if (!NT_STATUS_IS_OK(status)) {
8855 reply_nterror(req, status);
8856 goto out;
8859 status = check_name(conn, smb_fname_dst);
8860 if (!NT_STATUS_IS_OK(status)) {
8861 reply_nterror(req, status);
8862 goto out;
8865 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
8866 ofun, count, target_is_directory);
8868 if(!NT_STATUS_IS_OK(status)) {
8869 reply_nterror(req, status);
8870 goto out;
8871 } else {
8872 count++;
8874 } else {
8875 struct smb_Dir *dir_hnd = NULL;
8876 const char *dname = NULL;
8877 char *talloced = NULL;
8878 long offset = 0;
8881 * There is a wildcard that requires us to actually read the
8882 * src dir and copy each file matching the mask to the dst.
8883 * Right now streams won't be copied, but this could
8884 * presumably be added with a nested loop for reach dir entry.
8886 SMB_ASSERT(!smb_fname_src->stream_name);
8887 SMB_ASSERT(!smb_fname_dst->stream_name);
8889 smb_fname_src->stream_name = NULL;
8890 smb_fname_dst->stream_name = NULL;
8892 if (strequal(fname_src_mask,"????????.???")) {
8893 TALLOC_FREE(fname_src_mask);
8894 fname_src_mask = talloc_strdup(ctx, "*");
8895 if (!fname_src_mask) {
8896 reply_nterror(req, NT_STATUS_NO_MEMORY);
8897 goto out;
8901 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
8902 fname_src_dir,
8903 NULL,
8904 NULL,
8905 smb_fname_src->twrp,
8906 smb_fname_src->flags);
8907 if (smb_fname_src_dir == NULL) {
8908 reply_nterror(req, NT_STATUS_NO_MEMORY);
8909 goto out;
8912 status = check_name(conn, smb_fname_src_dir);
8913 if (!NT_STATUS_IS_OK(status)) {
8914 reply_nterror(req, status);
8915 goto out;
8918 dir_hnd = OpenDir(ctx,
8919 conn,
8920 smb_fname_src_dir,
8921 fname_src_mask,
8923 if (dir_hnd == NULL) {
8924 status = map_nt_error_from_unix(errno);
8925 reply_nterror(req, status);
8926 goto out;
8929 error = ERRbadfile;
8931 /* Iterate over the src dir copying each entry to the dst. */
8932 while ((dname = ReadDirName(dir_hnd, &offset,
8933 &smb_fname_src->st, &talloced))) {
8934 char *destname = NULL;
8936 if (ISDOT(dname) || ISDOTDOT(dname)) {
8937 TALLOC_FREE(talloced);
8938 continue;
8941 if (!is_visible_file(conn,
8942 dir_hnd,
8943 dname,
8944 &smb_fname_src->st,
8945 false)) {
8946 TALLOC_FREE(talloced);
8947 continue;
8950 if(!mask_match(dname, fname_src_mask,
8951 conn->case_sensitive)) {
8952 TALLOC_FREE(talloced);
8953 continue;
8956 error = ERRnoaccess;
8958 /* Get the src smb_fname struct setup. */
8959 TALLOC_FREE(smb_fname_src->base_name);
8960 if (ISDOT(fname_src_dir)) {
8961 /* Ensure we use canonical names on open. */
8962 smb_fname_src->base_name =
8963 talloc_asprintf(smb_fname_src, "%s",
8964 dname);
8965 } else {
8966 smb_fname_src->base_name =
8967 talloc_asprintf(smb_fname_src, "%s/%s",
8968 fname_src_dir, dname);
8971 if (!smb_fname_src->base_name) {
8972 TALLOC_FREE(dir_hnd);
8973 TALLOC_FREE(talloced);
8974 reply_nterror(req, NT_STATUS_NO_MEMORY);
8975 goto out;
8978 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
8979 smb_fname_dst->base_name,
8980 &destname)) {
8981 TALLOC_FREE(talloced);
8982 continue;
8984 if (!destname) {
8985 TALLOC_FREE(dir_hnd);
8986 TALLOC_FREE(talloced);
8987 reply_nterror(req, NT_STATUS_NO_MEMORY);
8988 goto out;
8991 TALLOC_FREE(smb_fname_dst->base_name);
8992 smb_fname_dst->base_name = destname;
8994 status = check_name(conn, smb_fname_src);
8995 if (!NT_STATUS_IS_OK(status)) {
8996 TALLOC_FREE(dir_hnd);
8997 TALLOC_FREE(talloced);
8998 reply_nterror(req, status);
8999 goto out;
9002 status = check_name(conn, smb_fname_dst);
9003 if (!NT_STATUS_IS_OK(status)) {
9004 TALLOC_FREE(dir_hnd);
9005 TALLOC_FREE(talloced);
9006 reply_nterror(req, status);
9007 goto out;
9010 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
9011 smb_fname_src->base_name,
9012 smb_fname_dst->base_name));
9014 status = copy_file(ctx, conn, smb_fname_src,
9015 smb_fname_dst, ofun, count,
9016 target_is_directory);
9017 if (NT_STATUS_IS_OK(status)) {
9018 count++;
9021 TALLOC_FREE(talloced);
9023 TALLOC_FREE(dir_hnd);
9026 if (count == 0) {
9027 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
9028 goto out;
9031 reply_outbuf(req, 1, 0);
9032 SSVAL(req->outbuf,smb_vwv0,count);
9033 out:
9034 TALLOC_FREE(smb_fname_src);
9035 TALLOC_FREE(smb_fname_src_dir);
9036 TALLOC_FREE(smb_fname_dst);
9037 TALLOC_FREE(fname_src);
9038 TALLOC_FREE(fname_dst);
9039 TALLOC_FREE(fname_src_mask);
9040 TALLOC_FREE(fname_src_dir);
9042 END_PROFILE(SMBcopy);
9043 return;
9046 #undef DBGC_CLASS
9047 #define DBGC_CLASS DBGC_LOCKING
9049 /****************************************************************************
9050 Get a lock pid, dealing with large count requests.
9051 ****************************************************************************/
9053 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
9054 bool large_file_format)
9056 if(!large_file_format)
9057 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
9058 else
9059 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
9062 /****************************************************************************
9063 Get a lock count, dealing with large count requests.
9064 ****************************************************************************/
9066 uint64_t get_lock_count(const uint8_t *data, int data_offset,
9067 bool large_file_format)
9069 uint64_t count = 0;
9071 if(!large_file_format) {
9072 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
9073 } else {
9075 * No BVAL, this is reversed!
9077 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
9078 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
9081 return count;
9084 /****************************************************************************
9085 Get a lock offset, dealing with large offset requests.
9086 ****************************************************************************/
9088 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
9089 bool large_file_format)
9091 uint64_t offset = 0;
9093 if(!large_file_format) {
9094 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
9095 } else {
9097 * No BVAL, this is reversed!
9099 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
9100 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
9103 return offset;
9106 struct smbd_do_unlocking_state {
9107 struct files_struct *fsp;
9108 uint16_t num_ulocks;
9109 struct smbd_lock_element *ulocks;
9110 enum brl_flavour lock_flav;
9111 NTSTATUS status;
9114 static void smbd_do_unlocking_fn(
9115 const uint8_t *buf,
9116 size_t buflen,
9117 bool *pmodified_dependent,
9118 void *private_data)
9120 struct smbd_do_unlocking_state *state = private_data;
9121 struct files_struct *fsp = state->fsp;
9122 enum brl_flavour lock_flav = state->lock_flav;
9123 uint16_t i;
9125 for (i = 0; i < state->num_ulocks; i++) {
9126 struct smbd_lock_element *e = &state->ulocks[i];
9128 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
9129 "pid %"PRIu64", file %s\n",
9130 e->offset,
9131 e->count,
9132 e->smblctx,
9133 fsp_str_dbg(fsp));
9135 if (e->brltype != UNLOCK_LOCK) {
9136 /* this can only happen with SMB2 */
9137 state->status = NT_STATUS_INVALID_PARAMETER;
9138 return;
9141 state->status = do_unlock(
9142 fsp, e->smblctx, e->count, e->offset, lock_flav);
9144 DBG_DEBUG("do_unlock returned %s\n",
9145 nt_errstr(state->status));
9147 if (!NT_STATUS_IS_OK(state->status)) {
9148 return;
9152 *pmodified_dependent = true;
9155 NTSTATUS smbd_do_unlocking(struct smb_request *req,
9156 files_struct *fsp,
9157 uint16_t num_ulocks,
9158 struct smbd_lock_element *ulocks,
9159 enum brl_flavour lock_flav)
9161 struct smbd_do_unlocking_state state = {
9162 .fsp = fsp,
9163 .num_ulocks = num_ulocks,
9164 .ulocks = ulocks,
9165 .lock_flav = lock_flav,
9167 NTSTATUS status;
9169 DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
9171 status = share_mode_do_locked(
9172 fsp->file_id, smbd_do_unlocking_fn, &state);
9174 if (!NT_STATUS_IS_OK(status)) {
9175 DBG_DEBUG("share_mode_do_locked failed: %s\n",
9176 nt_errstr(status));
9177 return status;
9179 if (!NT_STATUS_IS_OK(state.status)) {
9180 DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
9181 nt_errstr(status));
9182 return state.status;
9185 return NT_STATUS_OK;
9188 /****************************************************************************
9189 Reply to a lockingX request.
9190 ****************************************************************************/
9192 static void reply_lockingx_done(struct tevent_req *subreq);
9194 void reply_lockingX(struct smb_request *req)
9196 connection_struct *conn = req->conn;
9197 files_struct *fsp;
9198 unsigned char locktype;
9199 enum brl_type brltype;
9200 unsigned char oplocklevel;
9201 uint16_t num_ulocks;
9202 uint16_t num_locks;
9203 int32_t lock_timeout;
9204 uint16_t i;
9205 const uint8_t *data;
9206 bool large_file_format;
9207 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
9208 struct smbd_lock_element *locks = NULL;
9209 struct tevent_req *subreq = NULL;
9211 START_PROFILE(SMBlockingX);
9213 if (req->wct < 8) {
9214 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9215 END_PROFILE(SMBlockingX);
9216 return;
9219 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
9220 locktype = CVAL(req->vwv+3, 0);
9221 oplocklevel = CVAL(req->vwv+3, 1);
9222 num_ulocks = SVAL(req->vwv+6, 0);
9223 num_locks = SVAL(req->vwv+7, 0);
9224 lock_timeout = IVAL(req->vwv+4, 0);
9225 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
9227 if (!check_fsp(conn, req, fsp)) {
9228 END_PROFILE(SMBlockingX);
9229 return;
9232 data = req->buf;
9234 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
9235 /* we don't support these - and CANCEL_LOCK makes w2k
9236 and XP reboot so I don't really want to be
9237 compatible! (tridge) */
9238 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
9239 END_PROFILE(SMBlockingX);
9240 return;
9243 /* Check if this is an oplock break on a file
9244 we have granted an oplock on.
9246 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
9247 /* Client can insist on breaking to none. */
9248 bool break_to_none = (oplocklevel == 0);
9249 bool result;
9251 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
9252 "for %s\n", (unsigned int)oplocklevel,
9253 fsp_fnum_dbg(fsp)));
9256 * Make sure we have granted an exclusive or batch oplock on
9257 * this file.
9260 if (fsp->oplock_type == 0) {
9262 /* The Samba4 nbench simulator doesn't understand
9263 the difference between break to level2 and break
9264 to none from level2 - it sends oplock break
9265 replies in both cases. Don't keep logging an error
9266 message here - just ignore it. JRA. */
9268 DEBUG(5,("reply_lockingX: Error : oplock break from "
9269 "client for %s (oplock=%d) and no "
9270 "oplock granted on this file (%s).\n",
9271 fsp_fnum_dbg(fsp), fsp->oplock_type,
9272 fsp_str_dbg(fsp)));
9274 /* if this is a pure oplock break request then don't
9275 * send a reply */
9276 if (num_locks == 0 && num_ulocks == 0) {
9277 END_PROFILE(SMBlockingX);
9278 return;
9281 END_PROFILE(SMBlockingX);
9282 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
9283 return;
9286 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
9287 (break_to_none)) {
9288 result = remove_oplock(fsp);
9289 } else {
9290 result = downgrade_oplock(fsp);
9293 if (!result) {
9294 DEBUG(0, ("reply_lockingX: error in removing "
9295 "oplock on file %s\n", fsp_str_dbg(fsp)));
9296 /* Hmmm. Is this panic justified? */
9297 smb_panic("internal tdb error");
9300 /* if this is a pure oplock break request then don't send a
9301 * reply */
9302 if (num_locks == 0 && num_ulocks == 0) {
9303 /* Sanity check - ensure a pure oplock break is not a
9304 chained request. */
9305 if (CVAL(req->vwv+0, 0) != 0xff) {
9306 DEBUG(0,("reply_lockingX: Error : pure oplock "
9307 "break is a chained %d request !\n",
9308 (unsigned int)CVAL(req->vwv+0, 0)));
9310 END_PROFILE(SMBlockingX);
9311 return;
9315 if (req->buflen <
9316 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
9317 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9318 END_PROFILE(SMBlockingX);
9319 return;
9322 if (num_ulocks != 0) {
9323 struct smbd_lock_element *ulocks = NULL;
9324 bool ok;
9326 ulocks = talloc_array(
9327 req, struct smbd_lock_element, num_ulocks);
9328 if (ulocks == NULL) {
9329 reply_nterror(req, NT_STATUS_NO_MEMORY);
9330 END_PROFILE(SMBlockingX);
9331 return;
9335 * Data now points at the beginning of the list of
9336 * smb_unlkrng structs
9338 for (i = 0; i < num_ulocks; i++) {
9339 ulocks[i].req_guid = smbd_request_guid(req,
9340 UINT16_MAX - i),
9341 ulocks[i].smblctx = get_lock_pid(
9342 data, i, large_file_format);
9343 ulocks[i].count = get_lock_count(
9344 data, i, large_file_format);
9345 ulocks[i].offset = get_lock_offset(
9346 data, i, large_file_format);
9347 ulocks[i].brltype = UNLOCK_LOCK;
9351 * Unlock cancels pending locks
9354 ok = smbd_smb1_brl_finish_by_lock(
9355 fsp,
9356 large_file_format,
9357 WINDOWS_LOCK,
9358 ulocks[0],
9359 NT_STATUS_OK);
9360 if (ok) {
9361 reply_outbuf(req, 2, 0);
9362 SSVAL(req->outbuf, smb_vwv0, 0xff);
9363 SSVAL(req->outbuf, smb_vwv1, 0);
9364 END_PROFILE(SMBlockingX);
9365 return;
9368 status = smbd_do_unlocking(
9369 req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
9370 TALLOC_FREE(ulocks);
9371 if (!NT_STATUS_IS_OK(status)) {
9372 END_PROFILE(SMBlockingX);
9373 reply_nterror(req, status);
9374 return;
9378 /* Now do any requested locks */
9379 data += ((large_file_format ? 20 : 10)*num_ulocks);
9381 /* Data now points at the beginning of the list
9382 of smb_lkrng structs */
9384 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
9385 brltype = READ_LOCK;
9386 } else {
9387 brltype = WRITE_LOCK;
9390 locks = talloc_array(req, struct smbd_lock_element, num_locks);
9391 if (locks == NULL) {
9392 reply_nterror(req, NT_STATUS_NO_MEMORY);
9393 END_PROFILE(SMBlockingX);
9394 return;
9397 for (i = 0; i < num_locks; i++) {
9398 locks[i].req_guid = smbd_request_guid(req, i),
9399 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
9400 locks[i].count = get_lock_count(data, i, large_file_format);
9401 locks[i].offset = get_lock_offset(data, i, large_file_format);
9402 locks[i].brltype = brltype;
9405 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
9407 bool ok;
9409 if (num_locks == 0) {
9410 /* See smbtorture3 lock11 test */
9411 reply_outbuf(req, 2, 0);
9412 /* andx chain ends */
9413 SSVAL(req->outbuf, smb_vwv0, 0xff);
9414 SSVAL(req->outbuf, smb_vwv1, 0);
9415 END_PROFILE(SMBlockingX);
9416 return;
9419 ok = smbd_smb1_brl_finish_by_lock(
9420 fsp,
9421 large_file_format,
9422 WINDOWS_LOCK,
9423 locks[0], /* Windows only cancels the first lock */
9424 NT_STATUS_FILE_LOCK_CONFLICT);
9426 if (!ok) {
9427 reply_force_doserror(req, ERRDOS, ERRcancelviolation);
9428 END_PROFILE(SMBlockingX);
9429 return;
9432 reply_outbuf(req, 2, 0);
9433 SSVAL(req->outbuf, smb_vwv0, 0xff);
9434 SSVAL(req->outbuf, smb_vwv1, 0);
9435 END_PROFILE(SMBlockingX);
9436 return;
9439 subreq = smbd_smb1_do_locks_send(
9440 fsp,
9441 req->sconn->ev_ctx,
9442 &req,
9443 fsp,
9444 lock_timeout,
9445 large_file_format,
9446 WINDOWS_LOCK,
9447 num_locks,
9448 locks);
9449 if (subreq == NULL) {
9450 reply_nterror(req, NT_STATUS_NO_MEMORY);
9451 END_PROFILE(SMBlockingX);
9452 return;
9454 tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
9455 END_PROFILE(SMBlockingX);
9458 static void reply_lockingx_done(struct tevent_req *subreq)
9460 struct smb_request *req = NULL;
9461 NTSTATUS status;
9462 bool ok;
9464 START_PROFILE(SMBlockingX);
9466 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
9467 SMB_ASSERT(ok);
9469 status = smbd_smb1_do_locks_recv(subreq);
9470 TALLOC_FREE(subreq);
9472 DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
9474 if (NT_STATUS_IS_OK(status)) {
9475 reply_outbuf(req, 2, 0);
9476 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
9477 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
9478 } else {
9479 reply_nterror(req, status);
9482 ok = srv_send_smb(req->xconn,
9483 (char *)req->outbuf,
9484 true,
9485 req->seqnum+1,
9486 IS_CONN_ENCRYPTED(req->conn),
9487 NULL);
9488 if (!ok) {
9489 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
9491 TALLOC_FREE(req);
9492 END_PROFILE(SMBlockingX);
9495 #undef DBGC_CLASS
9496 #define DBGC_CLASS DBGC_ALL
9498 /****************************************************************************
9499 Reply to a SMBreadbmpx (read block multiplex) request.
9500 Always reply with an error, if someone has a platform really needs this,
9501 please contact vl@samba.org
9502 ****************************************************************************/
9504 void reply_readbmpx(struct smb_request *req)
9506 START_PROFILE(SMBreadBmpx);
9507 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9508 END_PROFILE(SMBreadBmpx);
9509 return;
9512 /****************************************************************************
9513 Reply to a SMBreadbs (read block multiplex secondary) request.
9514 Always reply with an error, if someone has a platform really needs this,
9515 please contact vl@samba.org
9516 ****************************************************************************/
9518 void reply_readbs(struct smb_request *req)
9520 START_PROFILE(SMBreadBs);
9521 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9522 END_PROFILE(SMBreadBs);
9523 return;
9526 /****************************************************************************
9527 Reply to a SMBsetattrE.
9528 ****************************************************************************/
9530 void reply_setattrE(struct smb_request *req)
9532 connection_struct *conn = req->conn;
9533 struct smb_file_time ft;
9534 files_struct *fsp;
9535 NTSTATUS status;
9537 START_PROFILE(SMBsetattrE);
9538 init_smb_file_time(&ft);
9540 if (req->wct < 7) {
9541 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9542 goto out;
9545 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
9547 if(!fsp || (fsp->conn != conn)) {
9548 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
9549 goto out;
9553 * Convert the DOS times into unix times.
9556 ft.atime = time_t_to_full_timespec(
9557 srv_make_unix_date2(req->vwv+3));
9558 ft.mtime = time_t_to_full_timespec(
9559 srv_make_unix_date2(req->vwv+5));
9560 ft.create_time = time_t_to_full_timespec(
9561 srv_make_unix_date2(req->vwv+1));
9563 reply_outbuf(req, 0, 0);
9566 * Patch from Ray Frush <frush@engr.colostate.edu>
9567 * Sometimes times are sent as zero - ignore them.
9570 /* Ensure we have a valid stat struct for the source. */
9571 status = vfs_stat_fsp(fsp);
9572 if (!NT_STATUS_IS_OK(status)) {
9573 reply_nterror(req, status);
9574 goto out;
9577 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
9578 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
9579 goto out;
9582 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
9583 if (!NT_STATUS_IS_OK(status)) {
9584 reply_nterror(req, status);
9585 goto out;
9588 if (fsp->fsp_flags.modified) {
9589 trigger_write_time_update_immediate(fsp);
9592 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
9593 " createtime=%u\n",
9594 fsp_fnum_dbg(fsp),
9595 (unsigned int)ft.atime.tv_sec,
9596 (unsigned int)ft.mtime.tv_sec,
9597 (unsigned int)ft.create_time.tv_sec
9599 out:
9600 END_PROFILE(SMBsetattrE);
9601 return;
9605 /* Back from the dead for OS/2..... JRA. */
9607 /****************************************************************************
9608 Reply to a SMBwritebmpx (write block multiplex primary) request.
9609 Always reply with an error, if someone has a platform really needs this,
9610 please contact vl@samba.org
9611 ****************************************************************************/
9613 void reply_writebmpx(struct smb_request *req)
9615 START_PROFILE(SMBwriteBmpx);
9616 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9617 END_PROFILE(SMBwriteBmpx);
9618 return;
9621 /****************************************************************************
9622 Reply to a SMBwritebs (write block multiplex secondary) request.
9623 Always reply with an error, if someone has a platform really needs this,
9624 please contact vl@samba.org
9625 ****************************************************************************/
9627 void reply_writebs(struct smb_request *req)
9629 START_PROFILE(SMBwriteBs);
9630 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9631 END_PROFILE(SMBwriteBs);
9632 return;
9635 /****************************************************************************
9636 Reply to a SMBgetattrE.
9637 ****************************************************************************/
9639 void reply_getattrE(struct smb_request *req)
9641 connection_struct *conn = req->conn;
9642 int mode;
9643 files_struct *fsp;
9644 struct timespec create_ts;
9645 NTSTATUS status;
9647 START_PROFILE(SMBgetattrE);
9649 if (req->wct < 1) {
9650 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9651 END_PROFILE(SMBgetattrE);
9652 return;
9655 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
9657 if(!fsp || (fsp->conn != conn)) {
9658 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
9659 END_PROFILE(SMBgetattrE);
9660 return;
9663 /* Do an fstat on this file */
9664 status = vfs_stat_fsp(fsp);
9665 if (!NT_STATUS_IS_OK(status)) {
9666 reply_nterror(req, status);
9667 END_PROFILE(SMBgetattrE);
9668 return;
9671 mode = dos_mode(conn, fsp->fsp_name);
9674 * Convert the times into dos times. Set create
9675 * date to be last modify date as UNIX doesn't save
9676 * this.
9679 reply_outbuf(req, 11, 0);
9681 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
9682 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
9683 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
9684 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
9685 /* Should we check pending modtime here ? JRA */
9686 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
9687 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
9689 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
9690 SIVAL(req->outbuf, smb_vwv6, 0);
9691 SIVAL(req->outbuf, smb_vwv8, 0);
9692 } else {
9693 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
9694 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
9695 SIVAL(req->outbuf, smb_vwv8, allocation_size);
9697 SSVAL(req->outbuf,smb_vwv10, mode);
9699 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
9701 END_PROFILE(SMBgetattrE);
9702 return;