s3:smbd: Remove unnessesary NULL check for req
[Samba.git] / source3 / smbd / reply.c
blobabec78579515c6d4818e3dae187069feef9a3119
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"
52 #include "source3/printing/rap_jobid.h"
54 /****************************************************************************
55 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
56 path or anything including wildcards.
57 We're assuming here that '/' is not the second byte in any multibyte char
58 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
59 set.
60 ****************************************************************************/
62 /* Custom version for processing POSIX paths. */
63 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
65 static NTSTATUS check_path_syntax_internal(char *path,
66 bool posix_path)
68 char *d = path;
69 const char *s = path;
70 NTSTATUS ret = NT_STATUS_OK;
71 bool start_of_name_component = True;
72 bool stream_started = false;
73 bool last_component_contains_wcard = false;
75 while (*s) {
76 if (stream_started) {
77 switch (*s) {
78 case '/':
79 case '\\':
80 return NT_STATUS_OBJECT_NAME_INVALID;
81 case ':':
82 if (s[1] == '\0') {
83 return NT_STATUS_OBJECT_NAME_INVALID;
85 if (strchr_m(&s[1], ':')) {
86 return NT_STATUS_OBJECT_NAME_INVALID;
88 break;
92 if ((*s == ':') && !posix_path && !stream_started) {
93 if (last_component_contains_wcard) {
94 return NT_STATUS_OBJECT_NAME_INVALID;
96 /* Stream names allow more characters than file names.
97 We're overloading posix_path here to allow a wider
98 range of characters. If stream_started is true this
99 is still a Windows path even if posix_path is true.
100 JRA.
102 stream_started = true;
103 start_of_name_component = false;
104 posix_path = true;
106 if (s[1] == '\0') {
107 return NT_STATUS_OBJECT_NAME_INVALID;
111 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
113 * Safe to assume is not the second part of a mb char
114 * as this is handled below.
116 /* Eat multiple '/' or '\\' */
117 while (IS_PATH_SEP(*s,posix_path)) {
118 s++;
120 if ((d != path) && (*s != '\0')) {
121 /* We only care about non-leading or trailing '/' or '\\' */
122 *d++ = '/';
125 start_of_name_component = True;
126 /* New component. */
127 last_component_contains_wcard = false;
128 continue;
131 if (start_of_name_component) {
132 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
133 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
136 * No mb char starts with '.' so we're safe checking the directory separator here.
139 /* If we just added a '/' - delete it */
140 if ((d > path) && (*(d-1) == '/')) {
141 *(d-1) = '\0';
142 d--;
145 /* Are we at the start ? Can't go back further if so. */
146 if (d <= path) {
147 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
148 break;
150 /* Go back one level... */
151 /* We know this is safe as '/' cannot be part of a mb sequence. */
152 /* NOTE - if this assumption is invalid we are not in good shape... */
153 /* Decrement d first as d points to the *next* char to write into. */
154 for (d--; d > path; d--) {
155 if (*d == '/')
156 break;
158 s += 2; /* Else go past the .. */
159 /* We're still at the start of a name component, just the previous one. */
160 continue;
162 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
163 if (posix_path) {
164 /* Eat the '.' */
165 s++;
166 continue;
172 if (!(*s & 0x80)) {
173 if (!posix_path) {
174 if (*s <= 0x1f || *s == '|') {
175 return NT_STATUS_OBJECT_NAME_INVALID;
177 switch (*s) {
178 case '*':
179 case '?':
180 case '<':
181 case '>':
182 case '"':
183 last_component_contains_wcard = true;
184 break;
185 default:
186 break;
189 *d++ = *s++;
190 } else {
191 size_t siz;
192 /* Get the size of the next MB character. */
193 next_codepoint(s,&siz);
194 switch(siz) {
195 case 5:
196 *d++ = *s++;
197 FALL_THROUGH;
198 case 4:
199 *d++ = *s++;
200 FALL_THROUGH;
201 case 3:
202 *d++ = *s++;
203 FALL_THROUGH;
204 case 2:
205 *d++ = *s++;
206 FALL_THROUGH;
207 case 1:
208 *d++ = *s++;
209 break;
210 default:
211 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
212 *d = '\0';
213 return NT_STATUS_INVALID_PARAMETER;
216 start_of_name_component = False;
219 *d = '\0';
221 return ret;
224 /****************************************************************************
225 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
226 No wildcards allowed.
227 ****************************************************************************/
229 NTSTATUS check_path_syntax(char *path)
231 return check_path_syntax_internal(path, false);
234 /****************************************************************************
235 Check the path for a POSIX client.
236 We're assuming here that '/' is not the second byte in any multibyte char
237 set (a safe assumption).
238 ****************************************************************************/
240 NTSTATUS check_path_syntax_posix(char *path)
242 return check_path_syntax_internal(path, true);
245 /****************************************************************************
246 Pull a string and check the path allowing a wildcard - provide for error return.
247 Passes in posix flag.
248 ****************************************************************************/
250 static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
251 const char *base_ptr,
252 uint16_t smb_flags2,
253 char **pp_dest,
254 const char *src,
255 size_t src_len,
256 int flags,
257 bool posix_pathnames,
258 NTSTATUS *err)
260 size_t ret;
262 *pp_dest = NULL;
264 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
265 src_len, flags);
267 if (!*pp_dest) {
268 *err = NT_STATUS_INVALID_PARAMETER;
269 return ret;
272 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
274 * For a DFS path the function parse_dfs_path()
275 * will do the path processing, just make a copy.
277 *err = NT_STATUS_OK;
278 return ret;
281 if (posix_pathnames) {
282 *err = check_path_syntax_posix(*pp_dest);
283 } else {
284 *err = check_path_syntax(*pp_dest);
287 return ret;
290 /****************************************************************************
291 Pull a string and check the path - provide for error return.
292 ****************************************************************************/
294 size_t srvstr_get_path(TALLOC_CTX *ctx,
295 const char *base_ptr,
296 uint16_t smb_flags2,
297 char **pp_dest,
298 const char *src,
299 size_t src_len,
300 int flags,
301 NTSTATUS *err)
303 return srvstr_get_path_internal(ctx,
304 base_ptr,
305 smb_flags2,
306 pp_dest,
307 src,
308 src_len,
309 flags,
310 false,
311 err);
314 /****************************************************************************
315 Pull a string and check the path - provide for error return.
316 posix_pathnames version.
317 ****************************************************************************/
319 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
320 const char *base_ptr,
321 uint16_t smb_flags2,
322 char **pp_dest,
323 const char *src,
324 size_t src_len,
325 int flags,
326 NTSTATUS *err)
328 return srvstr_get_path_internal(ctx,
329 base_ptr,
330 smb_flags2,
331 pp_dest,
332 src,
333 src_len,
334 flags,
335 true,
336 err);
340 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
341 char **pp_dest, const char *src, int flags,
342 NTSTATUS *err)
344 ssize_t bufrem = smbreq_bufrem(req, src);
346 if (bufrem < 0) {
347 *err = NT_STATUS_INVALID_PARAMETER;
348 return 0;
351 if (req->posix_pathnames) {
352 return srvstr_get_path_internal(mem_ctx,
353 (const char *)req->inbuf,
354 req->flags2,
355 pp_dest,
356 src,
357 bufrem,
358 flags,
359 true,
360 err);
361 } else {
362 return srvstr_get_path_internal(mem_ctx,
363 (const char *)req->inbuf,
364 req->flags2,
365 pp_dest,
366 src,
367 bufrem,
368 flags,
369 false,
370 err);
375 * pull a string from the smb_buf part of a packet. In this case the
376 * string can either be null terminated or it can be terminated by the
377 * end of the smbbuf area
379 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
380 char **dest, const uint8_t *src, int flags)
382 ssize_t bufrem = smbreq_bufrem(req, src);
384 if (bufrem < 0) {
385 return 0;
388 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
389 bufrem, flags);
392 /****************************************************************************
393 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
394 ****************************************************************************/
396 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
397 files_struct *fsp)
399 if ((fsp == NULL) || (conn == NULL)) {
400 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
401 return False;
403 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
404 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
405 return False;
407 return True;
410 /****************************************************************************
411 Check if we have a correct fsp pointing to a file.
412 ****************************************************************************/
414 bool check_fsp(connection_struct *conn, struct smb_request *req,
415 files_struct *fsp)
417 if (!check_fsp_open(conn, req, fsp)) {
418 return False;
420 if (fsp->fsp_flags.is_directory) {
421 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
422 return False;
424 if (fsp_get_pathref_fd(fsp) == -1) {
425 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
426 return False;
428 fsp->num_smb_operations++;
429 return True;
432 /****************************************************************************
433 Check if we have a correct fsp pointing to a quota fake file. Replacement for
434 the CHECK_NTQUOTA_HANDLE_OK macro.
435 ****************************************************************************/
437 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
438 files_struct *fsp)
440 if (!check_fsp_open(conn, req, fsp)) {
441 return false;
444 if (fsp->fsp_flags.is_directory) {
445 return false;
448 if (fsp->fake_file_handle == NULL) {
449 return false;
452 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
453 return false;
456 if (fsp->fake_file_handle->private_data == NULL) {
457 return false;
460 return true;
463 /****************************************************************************
464 Return the port number we've bound to on a socket.
465 ****************************************************************************/
467 static int get_socket_port(int fd)
469 struct samba_sockaddr saddr = {
470 .sa_socklen = sizeof(struct sockaddr_storage),
473 if (fd == -1) {
474 return -1;
477 if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
478 int level = (errno == ENOTCONN) ? 2 : 0;
479 DEBUG(level, ("getsockname failed. Error was %s\n",
480 strerror(errno)));
481 return -1;
484 #if defined(HAVE_IPV6)
485 if (saddr.u.sa.sa_family == AF_INET6) {
486 return ntohs(saddr.u.in6.sin6_port);
488 #endif
489 if (saddr.u.sa.sa_family == AF_INET) {
490 return ntohs(saddr.u.in.sin_port);
492 return -1;
495 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
496 const char *name, int name_type)
498 char *trim_name;
499 char *trim_name_type;
500 const char *retarget_parm;
501 char *retarget;
502 char *p;
503 int retarget_type = 0x20;
504 int retarget_port = NBT_SMB_PORT;
505 struct sockaddr_storage retarget_addr;
506 struct sockaddr_in *in_addr;
507 bool ret = false;
508 uint8_t outbuf[10];
510 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
511 return false;
514 trim_name = talloc_strdup(talloc_tos(), name);
515 if (trim_name == NULL) {
516 goto fail;
518 trim_char(trim_name, ' ', ' ');
520 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
521 name_type);
522 if (trim_name_type == NULL) {
523 goto fail;
526 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
527 trim_name_type, NULL);
528 if (retarget_parm == NULL) {
529 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
530 trim_name, NULL);
532 if (retarget_parm == NULL) {
533 goto fail;
536 retarget = talloc_strdup(trim_name, retarget_parm);
537 if (retarget == NULL) {
538 goto fail;
541 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
543 p = strchr(retarget, ':');
544 if (p != NULL) {
545 *p++ = '\0';
546 retarget_port = atoi(p);
549 p = strchr_m(retarget, '#');
550 if (p != NULL) {
551 *p++ = '\0';
552 if (sscanf(p, "%x", &retarget_type) != 1) {
553 goto fail;
557 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
558 if (!ret) {
559 DEBUG(10, ("could not resolve %s\n", retarget));
560 goto fail;
563 if (retarget_addr.ss_family != AF_INET) {
564 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
565 goto fail;
568 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
570 _smb_setlen(outbuf, 6);
571 SCVAL(outbuf, 0, 0x84);
572 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
573 *(uint16_t *)(outbuf+8) = htons(retarget_port);
575 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
576 NULL)) {
577 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
578 "failed.");
581 ret = true;
582 fail:
583 TALLOC_FREE(trim_name);
584 return ret;
587 static void reply_called_name_not_present(char *outbuf)
589 smb_setlen(outbuf, 1);
590 SCVAL(outbuf, 0, 0x83);
591 SCVAL(outbuf, 4, 0x82);
594 /****************************************************************************
595 Reply to a (netbios-level) special message.
596 ****************************************************************************/
598 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
600 struct smbd_server_connection *sconn = xconn->client->sconn;
601 int msg_type = CVAL(inbuf,0);
602 int msg_flags = CVAL(inbuf,1);
604 * We only really use 4 bytes of the outbuf, but for the smb_setlen
605 * calculation & friends (srv_send_smb uses that) we need the full smb
606 * header.
608 char outbuf[smb_size];
610 memset(outbuf, '\0', sizeof(outbuf));
612 smb_setlen(outbuf,0);
614 switch (msg_type) {
615 case NBSSrequest: /* session request */
617 /* inbuf_size is guarenteed to be at least 4. */
618 fstring name1,name2;
619 int name_type1, name_type2;
620 int name_len1, name_len2;
622 *name1 = *name2 = 0;
624 if (xconn->transport.nbt.got_session) {
625 exit_server_cleanly("multiple session request not permitted");
628 SCVAL(outbuf,0,NBSSpositive);
629 SCVAL(outbuf,3,0);
631 /* inbuf_size is guaranteed to be at least 4. */
632 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
633 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
634 DEBUG(0,("Invalid name length in session request\n"));
635 reply_called_name_not_present(outbuf);
636 break;
638 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
639 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
640 DEBUG(0,("Invalid name length in session request\n"));
641 reply_called_name_not_present(outbuf);
642 break;
645 name_type1 = name_extract((unsigned char *)inbuf,
646 inbuf_size,(unsigned int)4,name1);
647 name_type2 = name_extract((unsigned char *)inbuf,
648 inbuf_size,(unsigned int)(4 + name_len1),name2);
650 if (name_type1 == -1 || name_type2 == -1) {
651 DEBUG(0,("Invalid name type in session request\n"));
652 reply_called_name_not_present(outbuf);
653 break;
656 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
657 name1, name_type1, name2, name_type2));
659 if (netbios_session_retarget(xconn, name1, name_type1)) {
660 exit_server_cleanly("retargeted client");
664 * Windows NT/2k uses "*SMBSERVER" and XP uses
665 * "*SMBSERV" arrggg!!!
667 if (strequal(name1, "*SMBSERVER ")
668 || strequal(name1, "*SMBSERV ")) {
669 char *raddr;
671 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
672 talloc_tos());
673 if (raddr == NULL) {
674 exit_server_cleanly("could not allocate raddr");
677 fstrcpy(name1, raddr);
680 set_local_machine_name(name1, True);
681 set_remote_machine_name(name2, True);
683 if (is_ipaddress(sconn->remote_hostname)) {
684 char *p = discard_const_p(char, sconn->remote_hostname);
686 talloc_free(p);
688 sconn->remote_hostname = talloc_strdup(sconn,
689 get_remote_machine_name());
690 if (sconn->remote_hostname == NULL) {
691 exit_server_cleanly("could not copy remote name");
693 xconn->remote_hostname = sconn->remote_hostname;
696 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
697 get_local_machine_name(), get_remote_machine_name(),
698 name_type2));
700 if (name_type2 == 'R') {
701 /* We are being asked for a pathworks session ---
702 no thanks! */
703 reply_called_name_not_present(outbuf);
704 break;
707 reload_services(sconn, conn_snum_used, true);
708 reopen_logs();
710 xconn->transport.nbt.got_session = true;
711 break;
714 case 0x89: /* session keepalive request
715 (some old clients produce this?) */
716 SCVAL(outbuf,0,NBSSkeepalive);
717 SCVAL(outbuf,3,0);
718 break;
720 case NBSSpositive: /* positive session response */
721 case NBSSnegative: /* negative session response */
722 case NBSSretarget: /* retarget session response */
723 DEBUG(0,("Unexpected session response\n"));
724 break;
726 case NBSSkeepalive: /* session keepalive */
727 default:
728 return;
731 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
732 msg_type, msg_flags));
734 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
735 exit_server_cleanly("reply_special: srv_send_smb failed.");
738 if (CVAL(outbuf, 0) != 0x82) {
739 exit_server_cleanly("invalid netbios session");
741 return;
744 /****************************************************************************
745 Reply to a tcon.
746 conn POINTER CAN BE NULL HERE !
747 ****************************************************************************/
749 void reply_tcon(struct smb_request *req)
751 connection_struct *conn = req->conn;
752 const char *service;
753 char *service_buf = NULL;
754 char *password = NULL;
755 char *dev = NULL;
756 int pwlen=0;
757 NTSTATUS nt_status;
758 const uint8_t *p;
759 const char *p2;
760 TALLOC_CTX *ctx = talloc_tos();
761 struct smbXsrv_connection *xconn = req->xconn;
762 NTTIME now = timeval_to_nttime(&req->request_time);
764 START_PROFILE(SMBtcon);
766 if (req->buflen < 4) {
767 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
768 END_PROFILE(SMBtcon);
769 return;
772 p = req->buf + 1;
773 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
774 p += 1;
775 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
776 p += pwlen+1;
777 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
778 p += 1;
780 if (service_buf == NULL || password == NULL || dev == NULL) {
781 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
782 END_PROFILE(SMBtcon);
783 return;
785 p2 = strrchr_m(service_buf,'\\');
786 if (p2) {
787 service = p2+1;
788 } else {
789 service = service_buf;
792 conn = make_connection(req, now, service, dev,
793 req->vuid,&nt_status);
794 req->conn = conn;
796 if (!conn) {
797 reply_nterror(req, nt_status);
798 END_PROFILE(SMBtcon);
799 return;
802 reply_outbuf(req, 2, 0);
803 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
804 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
805 SSVAL(req->outbuf,smb_tid,conn->cnum);
807 DEBUG(3,("tcon service=%s cnum=%d\n",
808 service, conn->cnum));
810 END_PROFILE(SMBtcon);
811 return;
814 /****************************************************************************
815 Reply to a tcon and X.
816 conn POINTER CAN BE NULL HERE !
817 ****************************************************************************/
819 void reply_tcon_and_X(struct smb_request *req)
821 const struct loadparm_substitution *lp_sub =
822 loadparm_s3_global_substitution();
823 connection_struct *conn = req->conn;
824 const char *service = NULL;
825 TALLOC_CTX *ctx = talloc_tos();
826 /* what the client thinks the device is */
827 char *client_devicetype = NULL;
828 /* what the server tells the client the share represents */
829 const char *server_devicetype;
830 NTSTATUS nt_status;
831 int passlen;
832 char *path = NULL;
833 const uint8_t *p;
834 const char *q;
835 uint16_t tcon_flags;
836 struct smbXsrv_session *session = NULL;
837 NTTIME now = timeval_to_nttime(&req->request_time);
838 bool session_key_updated = false;
839 uint16_t optional_support = 0;
840 struct smbXsrv_connection *xconn = req->xconn;
842 START_PROFILE(SMBtconX);
844 if (req->wct < 4) {
845 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
846 END_PROFILE(SMBtconX);
847 return;
850 passlen = SVAL(req->vwv+3, 0);
851 tcon_flags = SVAL(req->vwv+2, 0);
853 /* we might have to close an old one */
854 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
855 struct smbXsrv_tcon *tcon;
856 NTSTATUS status;
858 tcon = conn->tcon;
859 req->conn = NULL;
860 conn = NULL;
863 * TODO: cancel all outstanding requests on the tcon
865 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
866 if (!NT_STATUS_IS_OK(status)) {
867 DEBUG(0, ("reply_tcon_and_X: "
868 "smbXsrv_tcon_disconnect() failed: %s\n",
869 nt_errstr(status)));
871 * If we hit this case, there is something completely
872 * wrong, so we better disconnect the transport connection.
874 END_PROFILE(SMBtconX);
875 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
876 return;
879 TALLOC_FREE(tcon);
881 * This tree id is gone. Make sure we can't re-use it
882 * by accident.
884 req->tid = 0;
887 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
888 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
889 END_PROFILE(SMBtconX);
890 return;
893 if (xconn->smb1.negprot.encrypted_passwords) {
894 p = req->buf + passlen;
895 } else {
896 p = req->buf + passlen + 1;
899 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
901 if (path == NULL) {
902 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
903 END_PROFILE(SMBtconX);
904 return;
908 * the service name can be either: \\server\share
909 * or share directly like on the DELL PowerVault 705
911 if (*path=='\\') {
912 q = strchr_m(path+2,'\\');
913 if (!q) {
914 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
915 END_PROFILE(SMBtconX);
916 return;
918 service = q+1;
919 } else {
920 service = path;
923 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
924 &client_devicetype, p,
925 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
927 if (client_devicetype == NULL) {
928 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
929 END_PROFILE(SMBtconX);
930 return;
933 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
935 nt_status = smb1srv_session_lookup(xconn,
936 req->vuid, now, &session);
937 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
938 reply_force_doserror(req, ERRSRV, ERRbaduid);
939 END_PROFILE(SMBtconX);
940 return;
942 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
943 reply_nterror(req, nt_status);
944 END_PROFILE(SMBtconX);
945 return;
947 if (!NT_STATUS_IS_OK(nt_status)) {
948 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
949 END_PROFILE(SMBtconX);
950 return;
953 if (session->global->auth_session_info == NULL) {
954 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
955 END_PROFILE(SMBtconX);
956 return;
960 * If there is no application key defined yet
961 * we create one.
963 * This means we setup the application key on the
964 * first tcon that happens via the given session.
966 * Once the application key is defined, it does not
967 * change any more.
969 if (session->global->application_key_blob.length == 0 &&
970 smb2_signing_key_valid(session->global->signing_key))
972 struct smbXsrv_session *x = session;
973 struct auth_session_info *session_info =
974 session->global->auth_session_info;
975 uint8_t session_key[16];
977 ZERO_STRUCT(session_key);
978 memcpy(session_key, x->global->signing_key->blob.data,
979 MIN(x->global->signing_key->blob.length, sizeof(session_key)));
982 * The application key is truncated/padded to 16 bytes
984 x->global->application_key_blob = data_blob_talloc(x->global,
985 session_key,
986 sizeof(session_key));
987 ZERO_STRUCT(session_key);
988 if (x->global->application_key_blob.data == NULL) {
989 reply_nterror(req, NT_STATUS_NO_MEMORY);
990 END_PROFILE(SMBtconX);
991 return;
993 talloc_keep_secret(x->global->application_key_blob.data);
995 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
996 NTSTATUS status;
998 status = smb_key_derivation(x->global->application_key_blob.data,
999 x->global->application_key_blob.length,
1000 x->global->application_key_blob.data);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 DBG_ERR("smb_key_derivation failed: %s\n",
1003 nt_errstr(status));
1004 END_PROFILE(SMBtconX);
1005 return;
1007 optional_support |= SMB_EXTENDED_SIGNATURES;
1011 * Place the application key into the session_info
1013 data_blob_clear_free(&session_info->session_key);
1014 session_info->session_key = data_blob_dup_talloc(session_info,
1015 x->global->application_key_blob);
1016 if (session_info->session_key.data == NULL) {
1017 data_blob_clear_free(&x->global->application_key_blob);
1018 reply_nterror(req, NT_STATUS_NO_MEMORY);
1019 END_PROFILE(SMBtconX);
1020 return;
1022 talloc_keep_secret(session_info->session_key.data);
1023 session_key_updated = true;
1026 conn = make_connection(req, now, service, client_devicetype,
1027 req->vuid, &nt_status);
1028 req->conn =conn;
1030 if (!conn) {
1031 if (session_key_updated) {
1032 struct smbXsrv_session *x = session;
1033 struct auth_session_info *session_info =
1034 session->global->auth_session_info;
1035 data_blob_clear_free(&x->global->application_key_blob);
1036 data_blob_clear_free(&session_info->session_key);
1038 reply_nterror(req, nt_status);
1039 END_PROFILE(SMBtconX);
1040 return;
1043 if ( IS_IPC(conn) )
1044 server_devicetype = "IPC";
1045 else if ( IS_PRINT(conn) )
1046 server_devicetype = "LPT1:";
1047 else
1048 server_devicetype = "A:";
1050 if (get_Protocol() < PROTOCOL_NT1) {
1051 reply_outbuf(req, 2, 0);
1052 if (message_push_string(&req->outbuf, server_devicetype,
1053 STR_TERMINATE|STR_ASCII) == -1) {
1054 reply_nterror(req, NT_STATUS_NO_MEMORY);
1055 END_PROFILE(SMBtconX);
1056 return;
1058 } else {
1059 /* NT sets the fstype of IPC$ to the null string */
1060 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1062 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1063 /* Return permissions. */
1064 uint32_t perm1 = 0;
1065 uint32_t perm2 = 0;
1067 reply_outbuf(req, 7, 0);
1069 if (IS_IPC(conn)) {
1070 perm1 = FILE_ALL_ACCESS;
1071 perm2 = FILE_ALL_ACCESS;
1072 } else {
1073 perm1 = conn->share_access;
1076 SIVAL(req->outbuf, smb_vwv3, perm1);
1077 SIVAL(req->outbuf, smb_vwv5, perm2);
1078 } else {
1079 reply_outbuf(req, 3, 0);
1082 if ((message_push_string(&req->outbuf, server_devicetype,
1083 STR_TERMINATE|STR_ASCII) == -1)
1084 || (message_push_string(&req->outbuf, fstype,
1085 STR_TERMINATE) == -1)) {
1086 reply_nterror(req, NT_STATUS_NO_MEMORY);
1087 END_PROFILE(SMBtconX);
1088 return;
1091 /* what does setting this bit do? It is set by NT4 and
1092 may affect the ability to autorun mounted cdroms */
1093 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1094 optional_support |=
1095 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1097 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1098 DEBUG(2,("Serving %s as a Dfs root\n",
1099 lp_servicename(ctx, lp_sub, SNUM(conn)) ));
1100 optional_support |= SMB_SHARE_IN_DFS;
1103 SSVAL(req->outbuf, smb_vwv2, optional_support);
1106 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1107 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1109 DEBUG(3,("tconX service=%s \n",
1110 service));
1112 /* set the incoming and outgoing tid to the just created one */
1113 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1114 SSVAL(req->outbuf,smb_tid,conn->cnum);
1116 END_PROFILE(SMBtconX);
1118 req->tid = conn->cnum;
1121 /****************************************************************************
1122 Reply to an unknown type.
1123 ****************************************************************************/
1125 void reply_unknown_new(struct smb_request *req, uint8_t type)
1127 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1128 smb_fn_name(type), type, type));
1129 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1130 return;
1133 /****************************************************************************
1134 Reply to an ioctl.
1135 conn POINTER CAN BE NULL HERE !
1136 ****************************************************************************/
1138 void reply_ioctl(struct smb_request *req)
1140 const struct loadparm_substitution *lp_sub =
1141 loadparm_s3_global_substitution();
1142 connection_struct *conn = req->conn;
1143 uint16_t device;
1144 uint16_t function;
1145 uint32_t ioctl_code;
1146 int replysize;
1147 char *p;
1149 START_PROFILE(SMBioctl);
1151 if (req->wct < 3) {
1152 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1153 END_PROFILE(SMBioctl);
1154 return;
1157 device = SVAL(req->vwv+1, 0);
1158 function = SVAL(req->vwv+2, 0);
1159 ioctl_code = (device << 16) + function;
1161 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1163 switch (ioctl_code) {
1164 case IOCTL_QUERY_JOB_INFO:
1165 replysize = 32;
1166 break;
1167 default:
1168 reply_force_doserror(req, ERRSRV, ERRnosupport);
1169 END_PROFILE(SMBioctl);
1170 return;
1173 reply_outbuf(req, 8, replysize+1);
1174 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1175 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1176 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1177 p = smb_buf(req->outbuf);
1178 memset(p, '\0', replysize+1); /* valgrind-safe. */
1179 p += 1; /* Allow for alignment */
1181 switch (ioctl_code) {
1182 case IOCTL_QUERY_JOB_INFO:
1184 NTSTATUS status;
1185 size_t len = 0;
1186 files_struct *fsp = file_fsp(
1187 req, SVAL(req->vwv+0, 0));
1188 if (!fsp) {
1189 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1190 END_PROFILE(SMBioctl);
1191 return;
1193 /* Job number */
1194 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1196 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1197 lp_netbios_name(), 15,
1198 STR_TERMINATE|STR_ASCII, &len);
1199 if (!NT_STATUS_IS_OK(status)) {
1200 reply_nterror(req, status);
1201 END_PROFILE(SMBioctl);
1202 return;
1204 if (conn) {
1205 status = srvstr_push((char *)req->outbuf, req->flags2,
1206 p+18,
1207 lp_servicename(talloc_tos(),
1208 lp_sub,
1209 SNUM(conn)),
1210 13, STR_TERMINATE|STR_ASCII, &len);
1211 if (!NT_STATUS_IS_OK(status)) {
1212 reply_nterror(req, status);
1213 END_PROFILE(SMBioctl);
1214 return;
1216 } else {
1217 memset(p+18, 0, 13);
1219 break;
1223 END_PROFILE(SMBioctl);
1224 return;
1227 /****************************************************************************
1228 Strange checkpath NTSTATUS mapping.
1229 ****************************************************************************/
1231 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1233 /* Strange DOS error code semantics only for checkpath... */
1234 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1235 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1236 /* We need to map to ERRbadpath */
1237 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1240 return status;
1243 /****************************************************************************
1244 Reply to a checkpath.
1245 ****************************************************************************/
1247 void reply_checkpath(struct smb_request *req)
1249 connection_struct *conn = req->conn;
1250 struct smb_filename *smb_fname = NULL;
1251 char *name = NULL;
1252 NTSTATUS status;
1253 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1254 TALLOC_CTX *ctx = talloc_tos();
1256 START_PROFILE(SMBcheckpath);
1258 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1259 STR_TERMINATE, &status);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 status = map_checkpath_error(req->flags2, status);
1263 reply_nterror(req, status);
1264 END_PROFILE(SMBcheckpath);
1265 return;
1268 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1270 status = filename_convert(ctx,
1271 conn,
1272 name,
1273 ucf_flags,
1275 &smb_fname);
1277 if (!NT_STATUS_IS_OK(status)) {
1278 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1279 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1280 ERRSRV, ERRbadpath);
1281 END_PROFILE(SMBcheckpath);
1282 return;
1284 goto path_err;
1287 if (!VALID_STAT(smb_fname->st) &&
1288 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1289 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1290 smb_fname_str_dbg(smb_fname), strerror(errno)));
1291 status = map_nt_error_from_unix(errno);
1292 goto path_err;
1295 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1296 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1297 ERRDOS, ERRbadpath);
1298 goto out;
1301 reply_outbuf(req, 0, 0);
1303 path_err:
1304 /* We special case this - as when a Windows machine
1305 is parsing a path is steps through the components
1306 one at a time - if a component fails it expects
1307 ERRbadpath, not ERRbadfile.
1309 status = map_checkpath_error(req->flags2, status);
1310 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1312 * Windows returns different error codes if
1313 * the parent directory is valid but not the
1314 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1315 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1316 * if the path is invalid.
1318 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1319 ERRDOS, ERRbadpath);
1320 goto out;
1323 reply_nterror(req, status);
1325 out:
1326 TALLOC_FREE(smb_fname);
1327 END_PROFILE(SMBcheckpath);
1328 return;
1331 /****************************************************************************
1332 Reply to a getatr.
1333 ****************************************************************************/
1335 void reply_getatr(struct smb_request *req)
1337 connection_struct *conn = req->conn;
1338 struct smb_filename *smb_fname = NULL;
1339 char *fname = NULL;
1340 int mode=0;
1341 off_t size=0;
1342 time_t mtime=0;
1343 const char *p;
1344 NTSTATUS status;
1345 TALLOC_CTX *ctx = talloc_tos();
1346 bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1348 START_PROFILE(SMBgetatr);
1350 p = (const char *)req->buf + 1;
1351 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1352 if (!NT_STATUS_IS_OK(status)) {
1353 reply_nterror(req, status);
1354 goto out;
1357 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1358 under WfWg - weird! */
1359 if (*fname == '\0') {
1360 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1361 if (!CAN_WRITE(conn)) {
1362 mode |= FILE_ATTRIBUTE_READONLY;
1364 size = 0;
1365 mtime = 0;
1366 } else {
1367 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1368 status = filename_convert(ctx,
1369 conn,
1370 fname,
1371 ucf_flags,
1373 &smb_fname);
1374 if (!NT_STATUS_IS_OK(status)) {
1375 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1376 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1377 ERRSRV, ERRbadpath);
1378 goto out;
1380 reply_nterror(req, status);
1381 goto out;
1383 if (!VALID_STAT(smb_fname->st) &&
1384 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1385 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1386 smb_fname_str_dbg(smb_fname),
1387 strerror(errno)));
1388 reply_nterror(req, map_nt_error_from_unix(errno));
1389 goto out;
1392 mode = fdos_mode(smb_fname->fsp);
1393 size = smb_fname->st.st_ex_size;
1395 if (ask_sharemode) {
1396 struct timespec write_time_ts;
1397 struct file_id fileid;
1399 ZERO_STRUCT(write_time_ts);
1400 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1401 get_file_infos(fileid, 0, NULL, &write_time_ts);
1402 if (!is_omit_timespec(&write_time_ts)) {
1403 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1407 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1408 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1409 size = 0;
1413 reply_outbuf(req, 10, 0);
1415 SSVAL(req->outbuf,smb_vwv0,mode);
1416 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1417 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1418 } else {
1419 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1421 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1423 if (get_Protocol() >= PROTOCOL_NT1) {
1424 SSVAL(req->outbuf, smb_flg2,
1425 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1428 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1429 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1431 out:
1432 TALLOC_FREE(smb_fname);
1433 TALLOC_FREE(fname);
1434 END_PROFILE(SMBgetatr);
1435 return;
1438 /****************************************************************************
1439 Reply to a setatr.
1440 ****************************************************************************/
1442 void reply_setatr(struct smb_request *req)
1444 struct smb_file_time ft;
1445 connection_struct *conn = req->conn;
1446 struct smb_filename *smb_fname = NULL;
1447 char *fname = NULL;
1448 int mode;
1449 time_t mtime;
1450 const char *p;
1451 NTSTATUS status;
1452 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1453 TALLOC_CTX *ctx = talloc_tos();
1455 START_PROFILE(SMBsetatr);
1456 init_smb_file_time(&ft);
1458 if (req->wct < 2) {
1459 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1460 goto out;
1463 p = (const char *)req->buf + 1;
1464 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 reply_nterror(req, status);
1467 goto out;
1470 status = filename_convert(ctx,
1471 conn,
1472 fname,
1473 ucf_flags,
1475 &smb_fname);
1476 if (!NT_STATUS_IS_OK(status)) {
1477 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1478 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1479 ERRSRV, ERRbadpath);
1480 goto out;
1482 reply_nterror(req, status);
1483 goto out;
1486 if (ISDOT(smb_fname->base_name)) {
1488 * Not sure here is the right place to catch this
1489 * condition. Might be moved to somewhere else later -- vl
1491 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1492 goto out;
1495 if (smb_fname->fsp == NULL) {
1496 /* Can't set access rights on a symlink. */
1497 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1498 goto out;
1501 mode = SVAL(req->vwv+0, 0);
1502 mtime = srv_make_unix_date3(req->vwv+1);
1504 if (mode != FILE_ATTRIBUTE_NORMAL) {
1505 if (VALID_STAT_OF_DIR(smb_fname->st))
1506 mode |= FILE_ATTRIBUTE_DIRECTORY;
1507 else
1508 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1510 status = smbd_check_access_rights_fsp(conn->cwd_fsp,
1511 smb_fname->fsp,
1512 false,
1513 FILE_WRITE_ATTRIBUTES);
1514 if (!NT_STATUS_IS_OK(status)) {
1515 reply_nterror(req, status);
1516 goto out;
1519 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1520 false) != 0) {
1521 reply_nterror(req, map_nt_error_from_unix(errno));
1522 goto out;
1526 ft.mtime = time_t_to_full_timespec(mtime);
1528 status = smb_set_file_time(conn, smb_fname->fsp, smb_fname, &ft, true);
1529 if (!NT_STATUS_IS_OK(status)) {
1530 reply_nterror(req, status);
1531 goto out;
1534 reply_outbuf(req, 0, 0);
1536 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1537 mode));
1538 out:
1539 TALLOC_FREE(smb_fname);
1540 END_PROFILE(SMBsetatr);
1541 return;
1544 /****************************************************************************
1545 Reply to a dskattr.
1546 ****************************************************************************/
1548 void reply_dskattr(struct smb_request *req)
1550 connection_struct *conn = req->conn;
1551 uint64_t ret;
1552 uint64_t dfree,dsize,bsize;
1553 struct smb_filename smb_fname;
1554 START_PROFILE(SMBdskattr);
1556 ZERO_STRUCT(smb_fname);
1557 smb_fname.base_name = discard_const_p(char, ".");
1559 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1560 reply_nterror(req, map_nt_error_from_unix(errno));
1561 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1562 END_PROFILE(SMBdskattr);
1563 return;
1566 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1567 if (ret == (uint64_t)-1) {
1568 reply_nterror(req, map_nt_error_from_unix(errno));
1569 END_PROFILE(SMBdskattr);
1570 return;
1574 * Force max to fit in 16 bit fields.
1576 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1577 dfree /= 2;
1578 dsize /= 2;
1579 bsize *= 2;
1580 if (bsize > (WORDMAX*512)) {
1581 bsize = (WORDMAX*512);
1582 if (dsize > WORDMAX)
1583 dsize = WORDMAX;
1584 if (dfree > WORDMAX)
1585 dfree = WORDMAX;
1586 break;
1590 reply_outbuf(req, 5, 0);
1592 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1593 double total_space, free_space;
1594 /* we need to scale this to a number that DOS6 can handle. We
1595 use floating point so we can handle large drives on systems
1596 that don't have 64 bit integers
1598 we end up displaying a maximum of 2G to DOS systems
1600 total_space = dsize * (double)bsize;
1601 free_space = dfree * (double)bsize;
1603 dsize = (uint64_t)((total_space+63*512) / (64*512));
1604 dfree = (uint64_t)((free_space+63*512) / (64*512));
1606 if (dsize > 0xFFFF) dsize = 0xFFFF;
1607 if (dfree > 0xFFFF) dfree = 0xFFFF;
1609 SSVAL(req->outbuf,smb_vwv0,dsize);
1610 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1611 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1612 SSVAL(req->outbuf,smb_vwv3,dfree);
1613 } else {
1614 SSVAL(req->outbuf,smb_vwv0,dsize);
1615 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1616 SSVAL(req->outbuf,smb_vwv2,512);
1617 SSVAL(req->outbuf,smb_vwv3,dfree);
1620 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1622 END_PROFILE(SMBdskattr);
1623 return;
1627 * Utility function to split the filename from the directory.
1629 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1630 char **fname_dir_out,
1631 char **fname_mask_out)
1633 const char *p = NULL;
1634 char *fname_dir = NULL;
1635 char *fname_mask = NULL;
1637 p = strrchr_m(fname_in, '/');
1638 if (!p) {
1639 fname_dir = talloc_strdup(ctx, ".");
1640 fname_mask = talloc_strdup(ctx, fname_in);
1641 } else {
1642 fname_dir = talloc_strndup(ctx, fname_in,
1643 PTR_DIFF(p, fname_in));
1644 fname_mask = talloc_strdup(ctx, p+1);
1647 if (!fname_dir || !fname_mask) {
1648 TALLOC_FREE(fname_dir);
1649 TALLOC_FREE(fname_mask);
1650 return NT_STATUS_NO_MEMORY;
1653 *fname_dir_out = fname_dir;
1654 *fname_mask_out = fname_mask;
1655 return NT_STATUS_OK;
1658 /****************************************************************************
1659 Make a dir struct.
1660 ****************************************************************************/
1662 static bool make_dir_struct(TALLOC_CTX *ctx,
1663 char *buf,
1664 const char *mask,
1665 const char *fname,
1666 off_t size,
1667 uint32_t mode,
1668 time_t date,
1669 bool uc)
1671 char *p;
1672 char *mask2 = talloc_strdup(ctx, mask);
1674 if (!mask2) {
1675 return False;
1678 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1679 size = 0;
1682 memset(buf+1,' ',11);
1683 if ((p = strchr_m(mask2,'.')) != NULL) {
1684 *p = 0;
1685 push_ascii(buf+1,mask2,8, 0);
1686 push_ascii(buf+9,p+1,3, 0);
1687 *p = '.';
1688 } else {
1689 push_ascii(buf+1,mask2,11, 0);
1692 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1693 SCVAL(buf,21,mode);
1694 srv_put_dos_date(buf,22,date);
1695 SSVAL(buf,26,size & 0xFFFF);
1696 SSVAL(buf,28,(size >> 16)&0xFFFF);
1697 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1698 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1699 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1700 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1701 return True;
1704 /****************************************************************************
1705 Reply to a search.
1706 Can be called from SMBsearch, SMBffirst or SMBfunique.
1707 ****************************************************************************/
1709 void reply_search(struct smb_request *req)
1711 connection_struct *conn = req->conn;
1712 char *path = NULL;
1713 char *mask = NULL;
1714 char *directory = NULL;
1715 struct smb_filename *smb_fname = NULL;
1716 char *fname = NULL;
1717 off_t size;
1718 uint32_t mode;
1719 struct timespec date;
1720 uint32_t dirtype;
1721 unsigned int numentries = 0;
1722 unsigned int maxentries = 0;
1723 bool finished = False;
1724 const char *p;
1725 int status_len;
1726 char status[21];
1727 int dptr_num= -1;
1728 bool check_descend = False;
1729 bool expect_close = False;
1730 NTSTATUS nt_status;
1731 bool mask_contains_wcard = False;
1732 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1733 TALLOC_CTX *ctx = talloc_tos();
1734 bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1735 struct smbXsrv_connection *xconn = req->xconn;
1736 struct smbd_server_connection *sconn = req->sconn;
1737 files_struct *fsp = NULL;
1738 const struct loadparm_substitution *lp_sub =
1739 loadparm_s3_global_substitution();
1741 START_PROFILE(SMBsearch);
1743 if (req->wct < 2) {
1744 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1745 goto out;
1748 if (req->posix_pathnames) {
1749 reply_unknown_new(req, req->cmd);
1750 goto out;
1753 /* If we were called as SMBffirst then we must expect close. */
1754 if(req->cmd == SMBffirst) {
1755 expect_close = True;
1758 reply_outbuf(req, 1, 3);
1759 maxentries = SVAL(req->vwv+0, 0);
1760 dirtype = SVAL(req->vwv+1, 0);
1761 p = (const char *)req->buf + 1;
1762 p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
1763 &nt_status);
1764 if (!NT_STATUS_IS_OK(nt_status)) {
1765 reply_nterror(req, nt_status);
1766 goto out;
1769 if (smbreq_bufrem(req, p) < 3) {
1770 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1771 goto out;
1774 p++;
1775 status_len = SVAL(p, 0);
1776 p += 2;
1778 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1780 if (status_len == 0) {
1781 int ret;
1782 struct smb_filename *smb_dname = NULL;
1783 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1784 ucf_flags_from_smb_request(req);
1785 nt_status = filename_convert(ctx, conn,
1786 path,
1787 ucf_flags,
1789 &smb_fname);
1790 if (!NT_STATUS_IS_OK(nt_status)) {
1791 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1792 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1793 ERRSRV, ERRbadpath);
1794 goto out;
1796 reply_nterror(req, nt_status);
1797 goto out;
1800 directory = smb_fname->base_name;
1802 p = strrchr_m(directory,'/');
1803 if ((p != NULL) && (*directory != '/')) {
1804 mask = talloc_strdup(ctx, p + 1);
1805 directory = talloc_strndup(ctx, directory,
1806 PTR_DIFF(p, directory));
1807 } else {
1808 mask = talloc_strdup(ctx, directory);
1809 directory = talloc_strdup(ctx,".");
1812 if (!directory) {
1813 reply_nterror(req, NT_STATUS_NO_MEMORY);
1814 goto out;
1817 memset((char *)status,'\0',21);
1818 SCVAL(status,0,(dirtype & 0x1F));
1820 smb_dname = synthetic_smb_fname(talloc_tos(),
1821 directory,
1822 NULL,
1823 NULL,
1824 smb_fname->twrp,
1825 smb_fname->flags);
1826 if (smb_dname == NULL) {
1827 reply_nterror(req, NT_STATUS_NO_MEMORY);
1828 goto out;
1832 * As we've cut off the last component from
1833 * smb_fname we need to re-stat smb_dname
1834 * so FILE_OPEN disposition knows the directory
1835 * exists.
1837 ret = vfs_stat(conn, smb_dname);
1838 if (ret == -1) {
1839 nt_status = map_nt_error_from_unix(errno);
1840 reply_nterror(req, nt_status);
1841 goto out;
1844 nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
1845 if (!NT_STATUS_IS_OK(nt_status)) {
1846 reply_nterror(req, nt_status);
1847 goto out;
1851 * Open an fsp on this directory for the dptr.
1853 nt_status = SMB_VFS_CREATE_FILE(
1854 conn, /* conn */
1855 req, /* req */
1856 smb_dname, /* dname */
1857 FILE_LIST_DIRECTORY, /* access_mask */
1858 FILE_SHARE_READ|
1859 FILE_SHARE_WRITE, /* share_access */
1860 FILE_OPEN, /* create_disposition*/
1861 FILE_DIRECTORY_FILE, /* create_options */
1862 FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1863 NO_OPLOCK, /* oplock_request */
1864 NULL, /* lease */
1865 0, /* allocation_size */
1866 0, /* private_flags */
1867 NULL, /* sd */
1868 NULL, /* ea_list */
1869 &fsp, /* result */
1870 NULL, /* pinfo */
1871 NULL, /* in_context */
1872 NULL);/* out_context */
1874 if (!NT_STATUS_IS_OK(nt_status)) {
1875 DBG_ERR("failed to open directory %s\n",
1876 smb_fname_str_dbg(smb_dname));
1877 reply_nterror(req, nt_status);
1878 goto out;
1881 nt_status = dptr_create(conn,
1882 NULL, /* req */
1883 fsp, /* fsp */
1884 True,
1885 expect_close,
1886 req->smbpid,
1887 mask,
1888 dirtype,
1889 &fsp->dptr);
1891 TALLOC_FREE(smb_dname);
1893 if (!NT_STATUS_IS_OK(nt_status)) {
1895 * Use NULL here for the first parameter (req)
1896 * as this is not a client visible handle so
1897 * can'tbe part of an SMB1 chain.
1899 close_file(NULL, fsp, NORMAL_CLOSE);
1900 fsp = NULL;
1901 reply_nterror(req, nt_status);
1902 goto out;
1905 dptr_num = dptr_dnum(fsp->dptr);
1907 } else {
1908 int status_dirtype;
1909 const char *dirpath;
1911 if (smbreq_bufrem(req, p) < 21) {
1912 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1913 goto out;
1916 memcpy(status,p,21);
1917 status_dirtype = CVAL(status,0) & 0x1F;
1918 if (status_dirtype != (dirtype & 0x1F)) {
1919 dirtype = status_dirtype;
1922 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
1923 if (fsp == NULL) {
1924 goto SearchEmpty;
1926 dirpath = dptr_path(sconn, dptr_num);
1927 directory = talloc_strdup(ctx, dirpath);
1928 if (!directory) {
1929 reply_nterror(req, NT_STATUS_NO_MEMORY);
1930 goto out;
1933 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1934 if (!mask) {
1935 goto SearchEmpty;
1937 dirtype = dptr_attr(sconn, dptr_num);
1940 mask_contains_wcard = dptr_has_wild(fsp->dptr);
1942 DEBUG(4,("dptr_num is %d\n",dptr_num));
1944 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1945 char buf[DIR_STRUCT_SIZE];
1946 memcpy(buf,status,21);
1947 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1948 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1949 reply_nterror(req, NT_STATUS_NO_MEMORY);
1950 goto out;
1952 dptr_fill(sconn, buf+12,dptr_num);
1953 if (dptr_zero(buf+12) && (status_len==0)) {
1954 numentries = 1;
1955 } else {
1956 numentries = 0;
1958 if (message_push_blob(&req->outbuf,
1959 data_blob_const(buf, sizeof(buf)))
1960 == -1) {
1961 reply_nterror(req, NT_STATUS_NO_MEMORY);
1962 goto out;
1964 } else {
1965 unsigned int i;
1966 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1967 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1969 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1971 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1972 directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
1973 if (in_list(directory, lp_dont_descend(ctx, lp_sub, SNUM(conn)),True)) {
1974 check_descend = True;
1977 for (i=numentries;(i<maxentries) && !finished;i++) {
1978 finished = !get_dir_entry(ctx,
1979 fsp->dptr,
1980 mask,
1981 dirtype,
1982 &fname,
1983 &size,
1984 &mode,
1985 &date,
1986 check_descend,
1987 ask_sharemode);
1988 if (!finished) {
1989 char buf[DIR_STRUCT_SIZE];
1990 memcpy(buf,status,21);
1991 if (!make_dir_struct(ctx,
1992 buf,
1993 mask,
1994 fname,
1995 size,
1996 mode,
1997 convert_timespec_to_time_t(date),
1998 !allow_long_path_components)) {
1999 reply_nterror(req, NT_STATUS_NO_MEMORY);
2000 goto out;
2002 if (!dptr_fill(sconn, buf+12,dptr_num)) {
2003 break;
2005 if (message_push_blob(&req->outbuf,
2006 data_blob_const(buf, sizeof(buf)))
2007 == -1) {
2008 reply_nterror(req, NT_STATUS_NO_MEMORY);
2009 goto out;
2011 numentries++;
2016 SearchEmpty:
2018 /* If we were called as SMBffirst with smb_search_id == NULL
2019 and no entries were found then return error and close fsp->dptr
2020 (X/Open spec) */
2022 if (numentries == 0) {
2023 dptr_num = -1;
2024 if (fsp != NULL) {
2025 close_file(NULL, fsp, NORMAL_CLOSE);
2026 fsp = NULL;
2028 } else if(expect_close && status_len == 0) {
2029 /* Close the dptr - we know it's gone */
2030 dptr_num = -1;
2031 if (fsp != NULL) {
2032 close_file(NULL, fsp, NORMAL_CLOSE);
2033 fsp = NULL;
2037 /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
2038 if(dptr_num >= 0 && req->cmd == SMBfunique) {
2039 dptr_num = -1;
2040 /* fsp may have been closed above. */
2041 if (fsp != NULL) {
2042 close_file(NULL, fsp, NORMAL_CLOSE);
2043 fsp = NULL;
2047 if ((numentries == 0) && !mask_contains_wcard) {
2048 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
2049 goto out;
2052 SSVAL(req->outbuf,smb_vwv0,numentries);
2053 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2054 SCVAL(smb_buf(req->outbuf),0,5);
2055 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2057 /* The replies here are never long name. */
2058 SSVAL(req->outbuf, smb_flg2,
2059 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2060 if (!allow_long_path_components) {
2061 SSVAL(req->outbuf, smb_flg2,
2062 SVAL(req->outbuf, smb_flg2)
2063 & (~FLAGS2_LONG_PATH_COMPONENTS));
2066 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2067 SSVAL(req->outbuf, smb_flg2,
2068 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2070 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2071 smb_fn_name(req->cmd),
2072 mask,
2073 directory,
2074 dirtype,
2075 numentries,
2076 maxentries ));
2077 out:
2078 TALLOC_FREE(directory);
2079 TALLOC_FREE(mask);
2080 TALLOC_FREE(smb_fname);
2081 END_PROFILE(SMBsearch);
2082 return;
2085 /****************************************************************************
2086 Reply to a fclose (stop directory search).
2087 ****************************************************************************/
2089 void reply_fclose(struct smb_request *req)
2091 int status_len;
2092 char status[21];
2093 int dptr_num= -2;
2094 const char *p;
2095 char *path = NULL;
2096 NTSTATUS err;
2097 TALLOC_CTX *ctx = talloc_tos();
2098 struct smbd_server_connection *sconn = req->sconn;
2099 files_struct *fsp = NULL;
2101 START_PROFILE(SMBfclose);
2103 if (req->posix_pathnames) {
2104 reply_unknown_new(req, req->cmd);
2105 END_PROFILE(SMBfclose);
2106 return;
2109 p = (const char *)req->buf + 1;
2110 p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
2111 &err);
2112 if (!NT_STATUS_IS_OK(err)) {
2113 reply_nterror(req, err);
2114 END_PROFILE(SMBfclose);
2115 return;
2118 if (smbreq_bufrem(req, p) < 3) {
2119 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2120 END_PROFILE(SMBfclose);
2121 return;
2124 p++;
2125 status_len = SVAL(p,0);
2126 p += 2;
2128 if (status_len == 0) {
2129 reply_force_doserror(req, ERRSRV, ERRsrverror);
2130 END_PROFILE(SMBfclose);
2131 return;
2134 if (smbreq_bufrem(req, p) < 21) {
2135 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2136 END_PROFILE(SMBfclose);
2137 return;
2140 memcpy(status,p,21);
2142 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
2143 if(fsp != NULL) {
2144 /* Close the file - we know it's gone */
2145 close_file(NULL, fsp, NORMAL_CLOSE);
2146 fsp = NULL;
2147 dptr_num = -1;
2150 reply_outbuf(req, 1, 0);
2151 SSVAL(req->outbuf,smb_vwv0,0);
2153 DEBUG(3,("search close\n"));
2155 END_PROFILE(SMBfclose);
2156 return;
2159 /****************************************************************************
2160 Reply to an open.
2161 ****************************************************************************/
2163 void reply_open(struct smb_request *req)
2165 connection_struct *conn = req->conn;
2166 struct smb_filename *smb_fname = NULL;
2167 char *fname = NULL;
2168 uint32_t fattr=0;
2169 off_t size = 0;
2170 time_t mtime=0;
2171 int info;
2172 files_struct *fsp;
2173 int oplock_request;
2174 int deny_mode;
2175 uint32_t dos_attr;
2176 uint32_t access_mask;
2177 uint32_t share_mode;
2178 uint32_t create_disposition;
2179 uint32_t create_options = 0;
2180 uint32_t private_flags = 0;
2181 NTSTATUS status;
2182 uint32_t ucf_flags;
2183 TALLOC_CTX *ctx = talloc_tos();
2185 START_PROFILE(SMBopen);
2187 if (req->wct < 2) {
2188 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2189 goto out;
2192 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2193 deny_mode = SVAL(req->vwv+0, 0);
2194 dos_attr = SVAL(req->vwv+1, 0);
2196 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2197 STR_TERMINATE, &status);
2198 if (!NT_STATUS_IS_OK(status)) {
2199 reply_nterror(req, status);
2200 goto out;
2203 if (!map_open_params_to_ntcreate(fname, deny_mode,
2204 OPENX_FILE_EXISTS_OPEN, &access_mask,
2205 &share_mode, &create_disposition,
2206 &create_options, &private_flags)) {
2207 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2208 goto out;
2211 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2213 status = filename_convert(ctx,
2214 conn,
2215 fname,
2216 ucf_flags,
2218 &smb_fname);
2219 if (!NT_STATUS_IS_OK(status)) {
2220 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2221 reply_botherror(req,
2222 NT_STATUS_PATH_NOT_COVERED,
2223 ERRSRV, ERRbadpath);
2224 goto out;
2226 reply_nterror(req, status);
2227 goto out;
2230 status = SMB_VFS_CREATE_FILE(
2231 conn, /* conn */
2232 req, /* req */
2233 smb_fname, /* fname */
2234 access_mask, /* access_mask */
2235 share_mode, /* share_access */
2236 create_disposition, /* create_disposition*/
2237 create_options, /* create_options */
2238 dos_attr, /* file_attributes */
2239 oplock_request, /* oplock_request */
2240 NULL, /* lease */
2241 0, /* allocation_size */
2242 private_flags,
2243 NULL, /* sd */
2244 NULL, /* ea_list */
2245 &fsp, /* result */
2246 &info, /* pinfo */
2247 NULL, NULL); /* create context */
2249 if (!NT_STATUS_IS_OK(status)) {
2250 if (open_was_deferred(req->xconn, req->mid)) {
2251 /* We have re-scheduled this call. */
2252 goto out;
2255 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2256 reply_openerror(req, status);
2257 goto out;
2260 fsp = fcb_or_dos_open(
2261 req,
2262 smb_fname,
2263 access_mask,
2264 create_options,
2265 private_flags);
2266 if (fsp == NULL) {
2267 bool ok = defer_smb1_sharing_violation(req);
2268 if (ok) {
2269 goto out;
2271 reply_openerror(req, status);
2272 goto out;
2276 /* Ensure we're pointing at the correct stat struct. */
2277 TALLOC_FREE(smb_fname);
2278 smb_fname = fsp->fsp_name;
2280 size = smb_fname->st.st_ex_size;
2281 fattr = fdos_mode(fsp);
2283 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2285 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2286 DEBUG(3,("attempt to open a directory %s\n",
2287 fsp_str_dbg(fsp)));
2288 close_file(req, fsp, ERROR_CLOSE);
2289 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2290 ERRDOS, ERRnoaccess);
2291 goto out;
2294 reply_outbuf(req, 7, 0);
2295 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2296 SSVAL(req->outbuf,smb_vwv1,fattr);
2297 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2298 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2299 } else {
2300 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2302 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2303 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2305 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2306 SCVAL(req->outbuf,smb_flg,
2307 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2310 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2311 SCVAL(req->outbuf,smb_flg,
2312 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2314 out:
2315 END_PROFILE(SMBopen);
2316 return;
2319 /****************************************************************************
2320 Reply to an open and X.
2321 ****************************************************************************/
2323 void reply_open_and_X(struct smb_request *req)
2325 connection_struct *conn = req->conn;
2326 struct smb_filename *smb_fname = NULL;
2327 char *fname = NULL;
2328 uint16_t open_flags;
2329 int deny_mode;
2330 uint32_t smb_attr;
2331 /* Breakout the oplock request bits so we can set the
2332 reply bits separately. */
2333 int ex_oplock_request;
2334 int core_oplock_request;
2335 int oplock_request;
2336 #if 0
2337 int smb_sattr = SVAL(req->vwv+4, 0);
2338 uint32_t smb_time = make_unix_date3(req->vwv+6);
2339 #endif
2340 int smb_ofun;
2341 uint32_t fattr=0;
2342 int mtime=0;
2343 int smb_action = 0;
2344 files_struct *fsp;
2345 NTSTATUS status;
2346 uint64_t allocation_size;
2347 ssize_t retval = -1;
2348 uint32_t access_mask;
2349 uint32_t share_mode;
2350 uint32_t create_disposition;
2351 uint32_t create_options = 0;
2352 uint32_t private_flags = 0;
2353 uint32_t ucf_flags;
2354 TALLOC_CTX *ctx = talloc_tos();
2356 START_PROFILE(SMBopenX);
2358 if (req->wct < 15) {
2359 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2360 goto out;
2363 open_flags = SVAL(req->vwv+2, 0);
2364 deny_mode = SVAL(req->vwv+3, 0);
2365 smb_attr = SVAL(req->vwv+5, 0);
2366 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2367 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2368 oplock_request = ex_oplock_request | core_oplock_request;
2369 smb_ofun = SVAL(req->vwv+8, 0);
2370 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2372 /* If it's an IPC, pass off the pipe handler. */
2373 if (IS_IPC(conn)) {
2374 if (lp_nt_pipe_support()) {
2375 reply_open_pipe_and_X(conn, req);
2376 } else {
2377 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2379 goto out;
2382 /* XXXX we need to handle passed times, sattr and flags */
2383 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2384 STR_TERMINATE, &status);
2385 if (!NT_STATUS_IS_OK(status)) {
2386 reply_nterror(req, status);
2387 goto out;
2390 if (!map_open_params_to_ntcreate(fname, deny_mode,
2391 smb_ofun,
2392 &access_mask, &share_mode,
2393 &create_disposition,
2394 &create_options,
2395 &private_flags)) {
2396 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2397 goto out;
2400 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2402 status = filename_convert(ctx,
2403 conn,
2404 fname,
2405 ucf_flags,
2407 &smb_fname);
2408 if (!NT_STATUS_IS_OK(status)) {
2409 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2410 reply_botherror(req,
2411 NT_STATUS_PATH_NOT_COVERED,
2412 ERRSRV, ERRbadpath);
2413 goto out;
2415 reply_nterror(req, status);
2416 goto out;
2419 status = SMB_VFS_CREATE_FILE(
2420 conn, /* conn */
2421 req, /* req */
2422 smb_fname, /* fname */
2423 access_mask, /* access_mask */
2424 share_mode, /* share_access */
2425 create_disposition, /* create_disposition*/
2426 create_options, /* create_options */
2427 smb_attr, /* file_attributes */
2428 oplock_request, /* oplock_request */
2429 NULL, /* lease */
2430 0, /* allocation_size */
2431 private_flags,
2432 NULL, /* sd */
2433 NULL, /* ea_list */
2434 &fsp, /* result */
2435 &smb_action, /* pinfo */
2436 NULL, NULL); /* create context */
2438 if (!NT_STATUS_IS_OK(status)) {
2439 if (open_was_deferred(req->xconn, req->mid)) {
2440 /* We have re-scheduled this call. */
2441 goto out;
2444 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2445 reply_openerror(req, status);
2446 goto out;
2449 fsp = fcb_or_dos_open(
2450 req,
2451 smb_fname,
2452 access_mask,
2453 create_options,
2454 private_flags);
2455 if (fsp == NULL) {
2456 bool ok = defer_smb1_sharing_violation(req);
2457 if (ok) {
2458 goto out;
2460 reply_openerror(req, status);
2461 goto out;
2465 smb_action = FILE_WAS_OPENED;
2468 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2469 if the file is truncated or created. */
2470 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2471 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2472 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2473 close_file(req, fsp, ERROR_CLOSE);
2474 reply_nterror(req, NT_STATUS_DISK_FULL);
2475 goto out;
2477 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2478 if (retval < 0) {
2479 close_file(req, fsp, ERROR_CLOSE);
2480 reply_nterror(req, NT_STATUS_DISK_FULL);
2481 goto out;
2483 status = vfs_stat_fsp(fsp);
2484 if (!NT_STATUS_IS_OK(status)) {
2485 close_file(req, fsp, ERROR_CLOSE);
2486 reply_nterror(req, status);
2487 goto out;
2491 fattr = fdos_mode(fsp);
2492 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2493 close_file(req, fsp, ERROR_CLOSE);
2494 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2495 goto out;
2497 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2499 /* If the caller set the extended oplock request bit
2500 and we granted one (by whatever means) - set the
2501 correct bit for extended oplock reply.
2504 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2505 smb_action |= EXTENDED_OPLOCK_GRANTED;
2508 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2509 smb_action |= EXTENDED_OPLOCK_GRANTED;
2512 /* If the caller set the core oplock request bit
2513 and we granted one (by whatever means) - set the
2514 correct bit for core oplock reply.
2517 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2518 reply_outbuf(req, 19, 0);
2519 } else {
2520 reply_outbuf(req, 15, 0);
2523 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2524 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2526 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2527 SCVAL(req->outbuf, smb_flg,
2528 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2531 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2532 SCVAL(req->outbuf, smb_flg,
2533 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2536 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2537 SSVAL(req->outbuf,smb_vwv3,fattr);
2538 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2539 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2540 } else {
2541 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2543 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2544 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2545 SSVAL(req->outbuf,smb_vwv11,smb_action);
2547 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2548 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2551 out:
2552 TALLOC_FREE(smb_fname);
2553 END_PROFILE(SMBopenX);
2554 return;
2557 /****************************************************************************
2558 Reply to a SMBulogoffX.
2559 ****************************************************************************/
2561 static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2562 struct smbXsrv_session *session);
2563 static void reply_ulogoffX_done(struct tevent_req *req);
2565 void reply_ulogoffX(struct smb_request *smb1req)
2567 struct timeval now = timeval_current();
2568 struct smbXsrv_session *session = NULL;
2569 struct tevent_req *req;
2570 NTSTATUS status;
2573 * Don't setup the profile charge here, take
2574 * it in reply_ulogoffX_done(). Not strictly correct
2575 * but better than the other SMB1 async
2576 * code that double-charges at the moment.
2579 status = smb1srv_session_lookup(smb1req->xconn,
2580 smb1req->vuid,
2581 timeval_to_nttime(&now),
2582 &session);
2583 if (!NT_STATUS_IS_OK(status)) {
2584 /* Not going async, profile here. */
2585 START_PROFILE(SMBulogoffX);
2586 DBG_WARNING("ulogoff, vuser id %llu does not map to user.\n",
2587 (unsigned long long)smb1req->vuid);
2589 smb1req->vuid = UID_FIELD_INVALID;
2590 reply_force_doserror(smb1req, ERRSRV, ERRbaduid);
2591 END_PROFILE(SMBulogoffX);
2592 return;
2595 req = reply_ulogoffX_send(smb1req, session);
2596 if (req == NULL) {
2597 /* Not going async, profile here. */
2598 START_PROFILE(SMBulogoffX);
2599 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
2600 END_PROFILE(SMBulogoffX);
2601 return;
2604 /* We're async. This will complete later. */
2605 tevent_req_set_callback(req, reply_ulogoffX_done, smb1req);
2606 return;
2609 struct reply_ulogoffX_state {
2610 struct tevent_queue *wait_queue;
2611 struct smbXsrv_session *session;
2614 static void reply_ulogoffX_wait_done(struct tevent_req *subreq);
2616 /****************************************************************************
2617 Async SMB1 ulogoffX.
2618 Note, on failure here we deallocate and return NULL to allow the caller to
2619 SMB1 return an error of ERRnomem immediately.
2620 ****************************************************************************/
2622 static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
2623 struct smbXsrv_session *session)
2625 struct tevent_req *req;
2626 struct reply_ulogoffX_state *state;
2627 struct tevent_req *subreq;
2628 files_struct *fsp;
2629 struct smbd_server_connection *sconn = session->client->sconn;
2630 uint64_t vuid = session->global->session_wire_id;
2632 req = tevent_req_create(smb1req, &state,
2633 struct reply_ulogoffX_state);
2634 if (req == NULL) {
2635 return NULL;
2637 state->wait_queue = tevent_queue_create(state,
2638 "reply_ulogoffX_wait_queue");
2639 if (tevent_req_nomem(state->wait_queue, req)) {
2640 TALLOC_FREE(req);
2641 return NULL;
2643 state->session = session;
2646 * Make sure that no new request will be able to use this session.
2647 * This ensures that once all outstanding fsp->aio_requests
2648 * on this session are done, we are safe to close it.
2650 session->status = NT_STATUS_USER_SESSION_DELETED;
2652 for (fsp = sconn->files; fsp; fsp = fsp->next) {
2653 if (fsp->vuid != vuid) {
2654 continue;
2657 * Flag the file as close in progress.
2658 * This will prevent any more IO being
2659 * done on it.
2661 fsp->fsp_flags.closing = true;
2663 if (fsp->num_aio_requests > 0) {
2665 * Now wait until all aio requests on this fsp are
2666 * finished.
2668 * We don't set a callback, as we just want to block the
2669 * wait queue and the talloc_free() of fsp->aio_request
2670 * will remove the item from the wait queue.
2672 subreq = tevent_queue_wait_send(fsp->aio_requests,
2673 sconn->ev_ctx,
2674 state->wait_queue);
2675 if (tevent_req_nomem(subreq, req)) {
2676 TALLOC_FREE(req);
2677 return NULL;
2683 * Now we add our own waiter to the end of the queue,
2684 * this way we get notified when all pending requests are finished
2685 * and reply to the outstanding SMB1 request.
2687 subreq = tevent_queue_wait_send(state,
2688 sconn->ev_ctx,
2689 state->wait_queue);
2690 if (tevent_req_nomem(subreq, req)) {
2691 TALLOC_FREE(req);
2692 return NULL;
2696 * We're really going async - move the SMB1 request from
2697 * a talloc stackframe above us to the sconn talloc-context.
2698 * We need this to stick around until the wait_done
2699 * callback is invoked.
2701 smb1req = talloc_move(sconn, &smb1req);
2703 tevent_req_set_callback(subreq, reply_ulogoffX_wait_done, req);
2705 return req;
2708 static void reply_ulogoffX_wait_done(struct tevent_req *subreq)
2710 struct tevent_req *req = tevent_req_callback_data(
2711 subreq, struct tevent_req);
2713 tevent_queue_wait_recv(subreq);
2714 TALLOC_FREE(subreq);
2715 tevent_req_done(req);
2718 static NTSTATUS reply_ulogoffX_recv(struct tevent_req *req)
2720 return tevent_req_simple_recv_ntstatus(req);
2723 static void reply_ulogoffX_done(struct tevent_req *req)
2725 struct smb_request *smb1req = tevent_req_callback_data(
2726 req, struct smb_request);
2727 struct reply_ulogoffX_state *state = tevent_req_data(req,
2728 struct reply_ulogoffX_state);
2729 struct smbXsrv_session *session = state->session;
2730 NTSTATUS status;
2733 * Take the profile charge here. Not strictly
2734 * correct but better than the other SMB1 async
2735 * code that double-charges at the moment.
2737 START_PROFILE(SMBulogoffX);
2739 status = reply_ulogoffX_recv(req);
2740 TALLOC_FREE(req);
2741 if (!NT_STATUS_IS_OK(status)) {
2742 TALLOC_FREE(smb1req);
2743 END_PROFILE(SMBulogoffX);
2744 exit_server(__location__ ": reply_ulogoffX_recv failed");
2745 return;
2748 status = smbXsrv_session_logoff(session);
2749 if (!NT_STATUS_IS_OK(status)) {
2750 TALLOC_FREE(smb1req);
2751 END_PROFILE(SMBulogoffX);
2752 exit_server(__location__ ": smbXsrv_session_logoff failed");
2753 return;
2756 TALLOC_FREE(session);
2758 reply_outbuf(smb1req, 2, 0);
2759 SSVAL(smb1req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2760 SSVAL(smb1req->outbuf, smb_vwv1, 0); /* no andx offset */
2762 DBG_NOTICE("ulogoffX vuid=%llu\n",
2763 (unsigned long long)smb1req->vuid);
2765 smb1req->vuid = UID_FIELD_INVALID;
2767 * The following call is needed to push the
2768 * reply data back out the socket after async
2769 * return. Plus it frees smb1req.
2771 smb_request_done(smb1req);
2772 END_PROFILE(SMBulogoffX);
2775 /****************************************************************************
2776 Reply to a mknew or a create.
2777 ****************************************************************************/
2779 void reply_mknew(struct smb_request *req)
2781 connection_struct *conn = req->conn;
2782 struct smb_filename *smb_fname = NULL;
2783 char *fname = NULL;
2784 uint32_t fattr = 0;
2785 struct smb_file_time ft;
2786 files_struct *fsp;
2787 int oplock_request = 0;
2788 NTSTATUS status;
2789 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2790 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2791 uint32_t create_disposition;
2792 uint32_t create_options = 0;
2793 uint32_t ucf_flags;
2794 TALLOC_CTX *ctx = talloc_tos();
2796 START_PROFILE(SMBcreate);
2797 init_smb_file_time(&ft);
2799 if (req->wct < 3) {
2800 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2801 goto out;
2804 fattr = SVAL(req->vwv+0, 0);
2805 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2807 if (req->cmd == SMBmknew) {
2808 /* We should fail if file exists. */
2809 create_disposition = FILE_CREATE;
2810 } else {
2811 /* Create if file doesn't exist, truncate if it does. */
2812 create_disposition = FILE_OVERWRITE_IF;
2815 /* mtime. */
2816 ft.mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+1));
2818 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2819 STR_TERMINATE, &status);
2820 if (!NT_STATUS_IS_OK(status)) {
2821 reply_nterror(req, status);
2822 goto out;
2825 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2826 status = filename_convert(ctx,
2827 conn,
2828 fname,
2829 ucf_flags,
2831 &smb_fname);
2832 if (!NT_STATUS_IS_OK(status)) {
2833 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2834 reply_botherror(req,
2835 NT_STATUS_PATH_NOT_COVERED,
2836 ERRSRV, ERRbadpath);
2837 goto out;
2839 reply_nterror(req, status);
2840 goto out;
2843 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2844 DEBUG(0,("Attempt to create file (%s) with volid set - "
2845 "please report this\n",
2846 smb_fname_str_dbg(smb_fname)));
2849 status = SMB_VFS_CREATE_FILE(
2850 conn, /* conn */
2851 req, /* req */
2852 smb_fname, /* fname */
2853 access_mask, /* access_mask */
2854 share_mode, /* share_access */
2855 create_disposition, /* create_disposition*/
2856 create_options, /* create_options */
2857 fattr, /* file_attributes */
2858 oplock_request, /* oplock_request */
2859 NULL, /* lease */
2860 0, /* allocation_size */
2861 0, /* private_flags */
2862 NULL, /* sd */
2863 NULL, /* ea_list */
2864 &fsp, /* result */
2865 NULL, /* pinfo */
2866 NULL, NULL); /* create context */
2868 if (!NT_STATUS_IS_OK(status)) {
2869 if (open_was_deferred(req->xconn, req->mid)) {
2870 /* We have re-scheduled this call. */
2871 goto out;
2873 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2874 bool ok = defer_smb1_sharing_violation(req);
2875 if (ok) {
2876 goto out;
2879 reply_openerror(req, status);
2880 goto out;
2883 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2884 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2885 if (!NT_STATUS_IS_OK(status)) {
2886 END_PROFILE(SMBcreate);
2887 goto out;
2890 reply_outbuf(req, 1, 0);
2891 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2893 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2894 SCVAL(req->outbuf,smb_flg,
2895 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2898 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2899 SCVAL(req->outbuf,smb_flg,
2900 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2903 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2904 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2905 smb_fname_str_dbg(smb_fname), fsp_get_io_fd(fsp),
2906 (unsigned int)fattr));
2908 out:
2909 TALLOC_FREE(smb_fname);
2910 END_PROFILE(SMBcreate);
2911 return;
2914 /****************************************************************************
2915 Reply to a create temporary file.
2916 ****************************************************************************/
2918 void reply_ctemp(struct smb_request *req)
2920 connection_struct *conn = req->conn;
2921 struct smb_filename *smb_fname = NULL;
2922 char *wire_name = NULL;
2923 char *fname = NULL;
2924 uint32_t fattr;
2925 files_struct *fsp;
2926 int oplock_request;
2927 char *s;
2928 NTSTATUS status;
2929 int i;
2930 uint32_t ucf_flags;
2931 TALLOC_CTX *ctx = talloc_tos();
2933 START_PROFILE(SMBctemp);
2935 if (req->wct < 3) {
2936 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2937 goto out;
2940 fattr = SVAL(req->vwv+0, 0);
2941 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2943 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2944 STR_TERMINATE, &status);
2945 if (!NT_STATUS_IS_OK(status)) {
2946 reply_nterror(req, status);
2947 goto out;
2950 for (i = 0; i < 10; i++) {
2951 if (*wire_name) {
2952 fname = talloc_asprintf(ctx,
2953 "%s/TMP%s",
2954 wire_name,
2955 generate_random_str_list(ctx, 5, "0123456789"));
2956 } else {
2957 fname = talloc_asprintf(ctx,
2958 "TMP%s",
2959 generate_random_str_list(ctx, 5, "0123456789"));
2962 if (!fname) {
2963 reply_nterror(req, NT_STATUS_NO_MEMORY);
2964 goto out;
2967 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2968 status = filename_convert(ctx, conn,
2969 fname,
2970 ucf_flags,
2972 &smb_fname);
2973 if (!NT_STATUS_IS_OK(status)) {
2974 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2975 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2976 ERRSRV, ERRbadpath);
2977 goto out;
2979 reply_nterror(req, status);
2980 goto out;
2983 /* Create the file. */
2984 status = SMB_VFS_CREATE_FILE(
2985 conn, /* conn */
2986 req, /* req */
2987 smb_fname, /* fname */
2988 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2989 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2990 FILE_CREATE, /* create_disposition*/
2991 0, /* create_options */
2992 fattr, /* file_attributes */
2993 oplock_request, /* oplock_request */
2994 NULL, /* lease */
2995 0, /* allocation_size */
2996 0, /* private_flags */
2997 NULL, /* sd */
2998 NULL, /* ea_list */
2999 &fsp, /* result */
3000 NULL, /* pinfo */
3001 NULL, NULL); /* create context */
3003 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
3004 TALLOC_FREE(fname);
3005 TALLOC_FREE(smb_fname);
3006 continue;
3009 if (!NT_STATUS_IS_OK(status)) {
3010 if (open_was_deferred(req->xconn, req->mid)) {
3011 /* We have re-scheduled this call. */
3012 goto out;
3014 if (NT_STATUS_EQUAL(
3015 status, NT_STATUS_SHARING_VIOLATION)) {
3016 bool ok = defer_smb1_sharing_violation(req);
3017 if (ok) {
3018 goto out;
3021 reply_openerror(req, status);
3022 goto out;
3025 break;
3028 if (i == 10) {
3029 /* Collision after 10 times... */
3030 reply_nterror(req, status);
3031 goto out;
3034 reply_outbuf(req, 1, 0);
3035 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
3037 /* the returned filename is relative to the directory */
3038 s = strrchr_m(fsp->fsp_name->base_name, '/');
3039 if (!s) {
3040 s = fsp->fsp_name->base_name;
3041 } else {
3042 s++;
3045 #if 0
3046 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
3047 thing in the byte section. JRA */
3048 SSVALS(p, 0, -1); /* what is this? not in spec */
3049 #endif
3050 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
3051 == -1) {
3052 reply_nterror(req, NT_STATUS_NO_MEMORY);
3053 goto out;
3056 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3057 SCVAL(req->outbuf, smb_flg,
3058 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
3061 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3062 SCVAL(req->outbuf, smb_flg,
3063 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
3066 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
3067 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
3068 fsp_get_io_fd(fsp), (unsigned int)smb_fname->st.st_ex_mode));
3069 out:
3070 TALLOC_FREE(smb_fname);
3071 TALLOC_FREE(wire_name);
3072 END_PROFILE(SMBctemp);
3073 return;
3076 /*******************************************************************
3077 Check if a user is allowed to rename a file.
3078 ********************************************************************/
3080 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
3081 uint16_t dirtype)
3083 if (!CAN_WRITE(conn)) {
3084 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3087 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
3088 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
3089 /* Only bother to read the DOS attribute if we might deny the
3090 rename on the grounds of attribute mismatch. */
3091 uint32_t fmode = fdos_mode(fsp);
3092 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
3093 return NT_STATUS_NO_SUCH_FILE;
3097 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
3098 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
3099 return NT_STATUS_OK;
3102 /* If no pathnames are open below this
3103 directory, allow the rename. */
3105 if (lp_strict_rename(SNUM(conn))) {
3107 * Strict rename, check open file db.
3109 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
3110 return NT_STATUS_ACCESS_DENIED;
3112 } else if (file_find_subpath(fsp)) {
3114 * No strict rename, just look in local process.
3116 return NT_STATUS_ACCESS_DENIED;
3118 return NT_STATUS_OK;
3121 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
3122 return NT_STATUS_OK;
3125 return NT_STATUS_ACCESS_DENIED;
3128 /*******************************************************************
3129 * unlink a file with all relevant access checks
3130 *******************************************************************/
3132 static NTSTATUS do_unlink(connection_struct *conn,
3133 struct smb_request *req,
3134 struct smb_filename *smb_fname,
3135 uint32_t dirtype)
3137 uint32_t fattr;
3138 files_struct *fsp;
3139 uint32_t dirtype_orig = dirtype;
3140 NTSTATUS status;
3141 int ret;
3142 struct smb2_create_blobs *posx = NULL;
3144 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
3145 smb_fname_str_dbg(smb_fname),
3146 dirtype));
3148 if (!CAN_WRITE(conn)) {
3149 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3152 ret = vfs_stat(conn, smb_fname);
3153 if (ret != 0) {
3154 return map_nt_error_from_unix(errno);
3157 fattr = fdos_mode(smb_fname->fsp);
3159 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
3160 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
3163 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
3164 if (!dirtype) {
3165 return NT_STATUS_NO_SUCH_FILE;
3168 if (!dir_check_ftype(fattr, dirtype)) {
3169 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3170 return NT_STATUS_FILE_IS_A_DIRECTORY;
3172 return NT_STATUS_NO_SUCH_FILE;
3175 if (dirtype_orig & 0x8000) {
3176 /* These will never be set for POSIX. */
3177 return NT_STATUS_NO_SUCH_FILE;
3180 #if 0
3181 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
3182 return NT_STATUS_FILE_IS_A_DIRECTORY;
3185 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
3186 return NT_STATUS_NO_SUCH_FILE;
3189 if (dirtype & 0xFF00) {
3190 /* These will never be set for POSIX. */
3191 return NT_STATUS_NO_SUCH_FILE;
3194 dirtype &= 0xFF;
3195 if (!dirtype) {
3196 return NT_STATUS_NO_SUCH_FILE;
3199 /* Can't delete a directory. */
3200 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3201 return NT_STATUS_FILE_IS_A_DIRECTORY;
3203 #endif
3205 #if 0 /* JRATEST */
3206 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
3207 return NT_STATUS_OBJECT_NAME_INVALID;
3208 #endif /* JRATEST */
3210 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
3211 status = make_smb2_posix_create_ctx(
3212 talloc_tos(), &posx, 0777);
3213 if (!NT_STATUS_IS_OK(status)) {
3214 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3215 nt_errstr(status));
3216 return status;
3220 /* On open checks the open itself will check the share mode, so
3221 don't do it here as we'll get it wrong. */
3223 status = SMB_VFS_CREATE_FILE
3224 (conn, /* conn */
3225 req, /* req */
3226 smb_fname, /* fname */
3227 DELETE_ACCESS, /* access_mask */
3228 FILE_SHARE_NONE, /* share_access */
3229 FILE_OPEN, /* create_disposition*/
3230 FILE_NON_DIRECTORY_FILE, /* create_options */
3231 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
3232 0, /* oplock_request */
3233 NULL, /* lease */
3234 0, /* allocation_size */
3235 0, /* private_flags */
3236 NULL, /* sd */
3237 NULL, /* ea_list */
3238 &fsp, /* result */
3239 NULL, /* pinfo */
3240 posx, /* in_context_blobs */
3241 NULL); /* out_context_blobs */
3243 TALLOC_FREE(posx);
3245 if (!NT_STATUS_IS_OK(status)) {
3246 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
3247 nt_errstr(status)));
3248 return status;
3251 status = can_set_delete_on_close(fsp, fattr);
3252 if (!NT_STATUS_IS_OK(status)) {
3253 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
3254 "(%s)\n",
3255 smb_fname_str_dbg(smb_fname),
3256 nt_errstr(status)));
3257 close_file(req, fsp, NORMAL_CLOSE);
3258 return status;
3261 /* The set is across all open files on this dev/inode pair. */
3262 if (!set_delete_on_close(fsp, True,
3263 conn->session_info->security_token,
3264 conn->session_info->unix_token)) {
3265 close_file(req, fsp, NORMAL_CLOSE);
3266 return NT_STATUS_ACCESS_DENIED;
3269 return close_file(req, fsp, NORMAL_CLOSE);
3272 /****************************************************************************
3273 The guts of the unlink command, split out so it may be called by the NT SMB
3274 code.
3275 ****************************************************************************/
3277 NTSTATUS unlink_internals(connection_struct *conn,
3278 struct smb_request *req,
3279 uint32_t dirtype,
3280 struct smb_filename *smb_fname,
3281 bool has_wild)
3283 char *fname_dir = NULL;
3284 char *fname_mask = NULL;
3285 int count=0;
3286 NTSTATUS status = NT_STATUS_OK;
3287 struct smb_filename *smb_fname_dir = NULL;
3288 TALLOC_CTX *ctx = talloc_tos();
3289 int ret;
3291 /* Split up the directory from the filename/mask. */
3292 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3293 &fname_dir, &fname_mask);
3294 if (!NT_STATUS_IS_OK(status)) {
3295 goto out;
3299 * We should only check the mangled cache
3300 * here if unix_convert failed. This means
3301 * that the path in 'mask' doesn't exist
3302 * on the file system and so we need to look
3303 * for a possible mangle. This patch from
3304 * Tine Smukavec <valentin.smukavec@hermes.si>.
3307 if (!VALID_STAT(smb_fname->st) &&
3308 mangle_is_mangled(fname_mask, conn->params)) {
3309 char *new_mask = NULL;
3310 mangle_lookup_name_from_8_3(ctx, fname_mask,
3311 &new_mask, conn->params);
3312 if (new_mask) {
3313 TALLOC_FREE(fname_mask);
3314 fname_mask = new_mask;
3318 if (!has_wild) {
3321 * Only one file needs to be unlinked. Append the mask back
3322 * onto the directory.
3324 TALLOC_FREE(smb_fname->base_name);
3325 if (ISDOT(fname_dir)) {
3326 /* Ensure we use canonical names on open. */
3327 smb_fname->base_name = talloc_asprintf(smb_fname,
3328 "%s",
3329 fname_mask);
3330 } else {
3331 smb_fname->base_name = talloc_asprintf(smb_fname,
3332 "%s/%s",
3333 fname_dir,
3334 fname_mask);
3336 if (!smb_fname->base_name) {
3337 status = NT_STATUS_NO_MEMORY;
3338 goto out;
3340 if (dirtype == 0) {
3341 dirtype = FILE_ATTRIBUTE_NORMAL;
3344 status = check_name(conn, smb_fname);
3345 if (!NT_STATUS_IS_OK(status)) {
3346 goto out;
3349 status = do_unlink(conn, req, smb_fname, dirtype);
3350 if (!NT_STATUS_IS_OK(status)) {
3351 goto out;
3354 count++;
3355 } else {
3356 struct smb_Dir *dir_hnd = NULL;
3357 long offset = 0;
3358 const char *dname = NULL;
3359 char *talloced = NULL;
3361 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3362 status = NT_STATUS_OBJECT_NAME_INVALID;
3363 goto out;
3365 if (dirtype == 0) {
3366 dirtype = FILE_ATTRIBUTE_NORMAL;
3369 if (strequal(fname_mask,"????????.???")) {
3370 TALLOC_FREE(fname_mask);
3371 fname_mask = talloc_strdup(ctx, "*");
3372 if (!fname_mask) {
3373 status = NT_STATUS_NO_MEMORY;
3374 goto out;
3378 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3379 fname_dir,
3380 NULL,
3381 NULL,
3382 smb_fname->twrp,
3383 smb_fname->flags);
3384 if (smb_fname_dir == NULL) {
3385 status = NT_STATUS_NO_MEMORY;
3386 goto out;
3389 status = check_name(conn, smb_fname_dir);
3390 if (!NT_STATUS_IS_OK(status)) {
3391 goto out;
3394 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3395 dirtype);
3396 if (dir_hnd == NULL) {
3397 status = map_nt_error_from_unix(errno);
3398 goto out;
3401 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3402 the pattern matches against the long name, otherwise the short name
3403 We don't implement this yet XXXX
3406 status = NT_STATUS_NO_SUCH_FILE;
3408 while ((dname = ReadDirName(dir_hnd, &offset,
3409 &smb_fname->st, &talloced))) {
3410 TALLOC_CTX *frame = talloc_stackframe();
3411 char *p = NULL;
3412 struct smb_filename *f = NULL;
3414 /* Quick check for "." and ".." */
3415 if (ISDOT(dname) || ISDOTDOT(dname)) {
3416 TALLOC_FREE(frame);
3417 TALLOC_FREE(talloced);
3418 continue;
3421 if (IS_VETO_PATH(conn, dname)) {
3422 TALLOC_FREE(frame);
3423 TALLOC_FREE(talloced);
3424 continue;
3427 if(!mask_match(dname, fname_mask,
3428 conn->case_sensitive)) {
3429 TALLOC_FREE(frame);
3430 TALLOC_FREE(talloced);
3431 continue;
3434 if (ISDOT(fname_dir)) {
3435 /* Ensure we use canonical names on open. */
3436 p = talloc_asprintf(smb_fname, "%s", dname);
3437 } else {
3438 p = talloc_asprintf(smb_fname, "%s/%s",
3439 fname_dir, dname);
3441 if (p == NULL) {
3442 TALLOC_FREE(dir_hnd);
3443 status = NT_STATUS_NO_MEMORY;
3444 TALLOC_FREE(frame);
3445 TALLOC_FREE(talloced);
3446 goto out;
3448 f = synthetic_smb_fname(frame,
3450 NULL,
3451 &smb_fname->st,
3452 smb_fname->twrp,
3453 smb_fname->flags);
3454 if (f == NULL) {
3455 TALLOC_FREE(dir_hnd);
3456 status = NT_STATUS_NO_MEMORY;
3457 TALLOC_FREE(frame);
3458 TALLOC_FREE(talloced);
3459 goto out;
3462 ret = vfs_stat(conn, f);
3463 if (ret != 0) {
3464 status = map_nt_error_from_unix(errno);
3465 TALLOC_FREE(dir_hnd);
3466 TALLOC_FREE(frame);
3467 TALLOC_FREE(talloced);
3468 goto out;
3471 status = openat_pathref_fsp(conn->cwd_fsp, f);
3472 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
3473 (f->flags & SMB_FILENAME_POSIX_PATH) &&
3474 S_ISLNK(f->st.st_ex_mode))
3476 status = NT_STATUS_OK;
3478 if (!NT_STATUS_IS_OK(status)) {
3479 TALLOC_FREE(dir_hnd);
3480 TALLOC_FREE(frame);
3481 TALLOC_FREE(talloced);
3482 goto out;
3485 if (!is_visible_fsp(f->fsp)) {
3486 TALLOC_FREE(frame);
3487 TALLOC_FREE(talloced);
3488 continue;
3491 status = check_name(conn, f);
3492 if (!NT_STATUS_IS_OK(status)) {
3493 TALLOC_FREE(dir_hnd);
3494 TALLOC_FREE(frame);
3495 TALLOC_FREE(talloced);
3496 goto out;
3499 status = do_unlink(conn, req, f, dirtype);
3500 if (!NT_STATUS_IS_OK(status)) {
3501 TALLOC_FREE(dir_hnd);
3502 TALLOC_FREE(frame);
3503 TALLOC_FREE(talloced);
3504 goto out;
3507 count++;
3508 DBG_DEBUG("successful unlink [%s]\n",
3509 smb_fname_str_dbg(f));
3511 TALLOC_FREE(frame);
3512 TALLOC_FREE(talloced);
3514 TALLOC_FREE(dir_hnd);
3517 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3518 status = map_nt_error_from_unix(errno);
3521 out:
3522 TALLOC_FREE(smb_fname_dir);
3523 TALLOC_FREE(fname_dir);
3524 TALLOC_FREE(fname_mask);
3525 return status;
3528 /****************************************************************************
3529 Reply to a unlink
3530 ****************************************************************************/
3532 void reply_unlink(struct smb_request *req)
3534 connection_struct *conn = req->conn;
3535 char *name = NULL;
3536 struct smb_filename *smb_fname = NULL;
3537 uint32_t dirtype;
3538 NTSTATUS status;
3539 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
3540 ucf_flags_from_smb_request(req);
3541 TALLOC_CTX *ctx = talloc_tos();
3542 bool has_wild = false;
3544 START_PROFILE(SMBunlink);
3546 if (req->wct < 1) {
3547 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3548 goto out;
3551 dirtype = SVAL(req->vwv+0, 0);
3553 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
3554 STR_TERMINATE, &status);
3555 if (!NT_STATUS_IS_OK(status)) {
3556 reply_nterror(req, status);
3557 goto out;
3560 status = filename_convert(ctx, conn,
3561 name,
3562 ucf_flags,
3564 &smb_fname);
3565 if (!NT_STATUS_IS_OK(status)) {
3566 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3567 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3568 ERRSRV, ERRbadpath);
3569 goto out;
3571 reply_nterror(req, status);
3572 goto out;
3575 if (!req->posix_pathnames) {
3576 char *lcomp = get_original_lcomp(ctx,
3577 conn,
3578 name,
3579 ucf_flags);
3580 if (lcomp == NULL) {
3581 reply_nterror(req, NT_STATUS_NO_MEMORY);
3582 goto out;
3584 has_wild = ms_has_wild(lcomp);
3585 TALLOC_FREE(lcomp);
3588 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3590 status = unlink_internals(conn, req, dirtype, smb_fname, has_wild);
3591 if (!NT_STATUS_IS_OK(status)) {
3592 if (open_was_deferred(req->xconn, req->mid)) {
3593 /* We have re-scheduled this call. */
3594 goto out;
3596 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3597 bool ok = defer_smb1_sharing_violation(req);
3598 if (ok) {
3599 goto out;
3602 reply_nterror(req, status);
3603 goto out;
3606 reply_outbuf(req, 0, 0);
3607 out:
3608 TALLOC_FREE(smb_fname);
3609 END_PROFILE(SMBunlink);
3610 return;
3613 /****************************************************************************
3614 Fail for readbraw.
3615 ****************************************************************************/
3617 static void fail_readraw(void)
3619 const char *errstr = talloc_asprintf(talloc_tos(),
3620 "FAIL ! reply_readbraw: socket write fail (%s)",
3621 strerror(errno));
3622 if (!errstr) {
3623 errstr = "";
3625 exit_server_cleanly(errstr);
3628 /****************************************************************************
3629 Fake (read/write) sendfile. Returns -1 on read or write fail.
3630 ****************************************************************************/
3632 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3633 off_t startpos, size_t nread)
3635 size_t bufsize;
3636 size_t tosend = nread;
3637 char *buf;
3639 if (nread == 0) {
3640 return 0;
3643 bufsize = MIN(nread, 65536);
3645 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3646 return -1;
3649 while (tosend > 0) {
3650 ssize_t ret;
3651 size_t cur_read;
3653 cur_read = MIN(tosend, bufsize);
3654 ret = read_file(fsp,buf,startpos,cur_read);
3655 if (ret == -1) {
3656 SAFE_FREE(buf);
3657 return -1;
3660 /* If we had a short read, fill with zeros. */
3661 if (ret < cur_read) {
3662 memset(buf + ret, '\0', cur_read - ret);
3665 ret = write_data(xconn->transport.sock, buf, cur_read);
3666 if (ret != cur_read) {
3667 int saved_errno = errno;
3669 * Try and give an error message saying what
3670 * client failed.
3672 DEBUG(0, ("write_data failed for client %s. "
3673 "Error %s\n",
3674 smbXsrv_connection_dbg(xconn),
3675 strerror(saved_errno)));
3676 SAFE_FREE(buf);
3677 errno = saved_errno;
3678 return -1;
3680 tosend -= cur_read;
3681 startpos += cur_read;
3684 SAFE_FREE(buf);
3685 return (ssize_t)nread;
3688 /****************************************************************************
3689 Deal with the case of sendfile reading less bytes from the file than
3690 requested. Fill with zeros (all we can do). Returns 0 on success
3691 ****************************************************************************/
3693 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3694 files_struct *fsp,
3695 ssize_t nread,
3696 size_t headersize,
3697 size_t smb_maxcnt)
3699 #define SHORT_SEND_BUFSIZE 1024
3700 if (nread < headersize) {
3701 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3702 "header for file %s (%s). Terminating\n",
3703 fsp_str_dbg(fsp), strerror(errno)));
3704 return -1;
3707 nread -= headersize;
3709 if (nread < smb_maxcnt) {
3710 char buf[SHORT_SEND_BUFSIZE] = { 0 };
3712 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3713 "with zeros !\n", fsp_str_dbg(fsp)));
3715 while (nread < smb_maxcnt) {
3717 * We asked for the real file size and told sendfile
3718 * to not go beyond the end of the file. But it can
3719 * happen that in between our fstat call and the
3720 * sendfile call the file was truncated. This is very
3721 * bad because we have already announced the larger
3722 * number of bytes to the client.
3724 * The best we can do now is to send 0-bytes, just as
3725 * a read from a hole in a sparse file would do.
3727 * This should happen rarely enough that I don't care
3728 * about efficiency here :-)
3730 size_t to_write;
3731 ssize_t ret;
3733 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3734 ret = write_data(xconn->transport.sock, buf, to_write);
3735 if (ret != to_write) {
3736 int saved_errno = errno;
3738 * Try and give an error message saying what
3739 * client failed.
3741 DEBUG(0, ("write_data failed for client %s. "
3742 "Error %s\n",
3743 smbXsrv_connection_dbg(xconn),
3744 strerror(saved_errno)));
3745 errno = saved_errno;
3746 return -1;
3748 nread += to_write;
3752 return 0;
3755 /****************************************************************************
3756 Return a readbraw error (4 bytes of zero).
3757 ****************************************************************************/
3759 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3761 char header[4];
3763 SIVAL(header,0,0);
3765 smbd_lock_socket(xconn);
3766 if (write_data(xconn->transport.sock,header,4) != 4) {
3767 int saved_errno = errno;
3769 * Try and give an error message saying what
3770 * client failed.
3772 DEBUG(0, ("write_data failed for client %s. "
3773 "Error %s\n",
3774 smbXsrv_connection_dbg(xconn),
3775 strerror(saved_errno)));
3776 errno = saved_errno;
3778 fail_readraw();
3780 smbd_unlock_socket(xconn);
3783 /*******************************************************************
3784 Ensure we don't use sendfile if server smb signing is active.
3785 ********************************************************************/
3787 static bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state)
3789 bool sign_active = false;
3791 /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
3792 if (get_Protocol() < PROTOCOL_NT1) {
3793 return false;
3795 if (signing_state) {
3796 sign_active = smb_signing_is_active(signing_state);
3798 return (lp__use_sendfile(snum) &&
3799 (get_remote_arch() != RA_WIN95) &&
3800 !sign_active);
3802 /****************************************************************************
3803 Use sendfile in readbraw.
3804 ****************************************************************************/
3806 static void send_file_readbraw(connection_struct *conn,
3807 struct smb_request *req,
3808 files_struct *fsp,
3809 off_t startpos,
3810 size_t nread,
3811 ssize_t mincount)
3813 struct smbXsrv_connection *xconn = req->xconn;
3814 char *outbuf = NULL;
3815 ssize_t ret=0;
3818 * We can only use sendfile on a non-chained packet
3819 * but we can use on a non-oplocked file. tridge proved this
3820 * on a train in Germany :-). JRA.
3821 * reply_readbraw has already checked the length.
3824 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3825 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3826 ssize_t sendfile_read = -1;
3827 char header[4];
3828 DATA_BLOB header_blob;
3830 _smb_setlen(header,nread);
3831 header_blob = data_blob_const(header, 4);
3833 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3834 &header_blob, startpos,
3835 nread);
3836 if (sendfile_read == -1) {
3837 /* Returning ENOSYS means no data at all was sent.
3838 * Do this as a normal read. */
3839 if (errno == ENOSYS) {
3840 goto normal_readbraw;
3844 * Special hack for broken Linux with no working sendfile. If we
3845 * return EINTR we sent the header but not the rest of the data.
3846 * Fake this up by doing read/write calls.
3848 if (errno == EINTR) {
3849 /* Ensure we don't do this again. */
3850 set_use_sendfile(SNUM(conn), False);
3851 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3853 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3854 DEBUG(0,("send_file_readbraw: "
3855 "fake_sendfile failed for "
3856 "file %s (%s).\n",
3857 fsp_str_dbg(fsp),
3858 strerror(errno)));
3859 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3861 return;
3864 DEBUG(0,("send_file_readbraw: sendfile failed for "
3865 "file %s (%s). Terminating\n",
3866 fsp_str_dbg(fsp), strerror(errno)));
3867 exit_server_cleanly("send_file_readbraw sendfile failed");
3868 } else if (sendfile_read == 0) {
3870 * Some sendfile implementations return 0 to indicate
3871 * that there was a short read, but nothing was
3872 * actually written to the socket. In this case,
3873 * fallback to the normal read path so the header gets
3874 * the correct byte count.
3876 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3877 "bytes falling back to the normal read: "
3878 "%s\n", fsp_str_dbg(fsp)));
3879 goto normal_readbraw;
3882 /* Deal with possible short send. */
3883 if (sendfile_read != 4+nread) {
3884 ret = sendfile_short_send(xconn, fsp,
3885 sendfile_read, 4, nread);
3886 if (ret == -1) {
3887 fail_readraw();
3890 return;
3893 normal_readbraw:
3895 outbuf = talloc_array(NULL, char, nread+4);
3896 if (!outbuf) {
3897 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3898 (unsigned)(nread+4)));
3899 reply_readbraw_error(xconn);
3900 return;
3903 if (nread > 0) {
3904 ret = read_file(fsp,outbuf+4,startpos,nread);
3905 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3906 if (ret < mincount)
3907 ret = 0;
3908 #else
3909 if (ret < nread)
3910 ret = 0;
3911 #endif
3914 _smb_setlen(outbuf,ret);
3915 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3916 int saved_errno = errno;
3918 * Try and give an error message saying what
3919 * client failed.
3921 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3922 smbXsrv_connection_dbg(xconn),
3923 strerror(saved_errno)));
3924 errno = saved_errno;
3926 fail_readraw();
3929 TALLOC_FREE(outbuf);
3932 /****************************************************************************
3933 Reply to a readbraw (core+ protocol).
3934 ****************************************************************************/
3936 void reply_readbraw(struct smb_request *req)
3938 connection_struct *conn = req->conn;
3939 struct smbXsrv_connection *xconn = req->xconn;
3940 ssize_t maxcount,mincount;
3941 size_t nread = 0;
3942 off_t startpos;
3943 files_struct *fsp;
3944 struct lock_struct lock;
3945 off_t size = 0;
3946 NTSTATUS status;
3948 START_PROFILE(SMBreadbraw);
3950 if (srv_is_signing_active(xconn) || req->encrypted) {
3951 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3952 "raw reads/writes are disallowed.");
3955 if (req->wct < 8) {
3956 reply_readbraw_error(xconn);
3957 END_PROFILE(SMBreadbraw);
3958 return;
3961 if (xconn->smb1.echo_handler.trusted_fde) {
3962 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3963 "'async smb echo handler = yes'\n"));
3964 reply_readbraw_error(xconn);
3965 END_PROFILE(SMBreadbraw);
3966 return;
3970 * Special check if an oplock break has been issued
3971 * and the readraw request croses on the wire, we must
3972 * return a zero length response here.
3975 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3978 * We have to do a check_fsp by hand here, as
3979 * we must always return 4 zero bytes on error,
3980 * not a NTSTATUS.
3983 if (fsp == NULL ||
3984 conn == NULL ||
3985 conn != fsp->conn ||
3986 req->vuid != fsp->vuid ||
3987 fsp->fsp_flags.is_directory ||
3988 fsp_get_io_fd(fsp) == -1)
3991 * fsp could be NULL here so use the value from the packet. JRA.
3993 DEBUG(3,("reply_readbraw: fnum %d not valid "
3994 "- cache prime?\n",
3995 (int)SVAL(req->vwv+0, 0)));
3996 reply_readbraw_error(xconn);
3997 END_PROFILE(SMBreadbraw);
3998 return;
4001 /* Do a "by hand" version of CHECK_READ. */
4002 if (!(fsp->fsp_flags.can_read ||
4003 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
4004 (fsp->access_mask & FILE_EXECUTE)))) {
4005 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
4006 (int)SVAL(req->vwv+0, 0)));
4007 reply_readbraw_error(xconn);
4008 END_PROFILE(SMBreadbraw);
4009 return;
4012 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
4013 if(req->wct == 10) {
4015 * This is a large offset (64 bit) read.
4018 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
4020 if(startpos < 0) {
4021 DEBUG(0,("reply_readbraw: negative 64 bit "
4022 "readraw offset (%.0f) !\n",
4023 (double)startpos ));
4024 reply_readbraw_error(xconn);
4025 END_PROFILE(SMBreadbraw);
4026 return;
4030 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
4031 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
4033 /* ensure we don't overrun the packet size */
4034 maxcount = MIN(65535,maxcount);
4036 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4037 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
4038 &lock);
4040 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4041 reply_readbraw_error(xconn);
4042 END_PROFILE(SMBreadbraw);
4043 return;
4046 status = vfs_stat_fsp(fsp);
4047 if (NT_STATUS_IS_OK(status)) {
4048 size = fsp->fsp_name->st.st_ex_size;
4051 if (startpos >= size) {
4052 nread = 0;
4053 } else {
4054 nread = MIN(maxcount,(size - startpos));
4057 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
4058 if (nread < mincount)
4059 nread = 0;
4060 #endif
4062 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
4063 "min=%lu nread=%lu\n",
4064 fsp_fnum_dbg(fsp), (double)startpos,
4065 (unsigned long)maxcount,
4066 (unsigned long)mincount,
4067 (unsigned long)nread ) );
4069 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
4071 DEBUG(5,("reply_readbraw finished\n"));
4073 END_PROFILE(SMBreadbraw);
4074 return;
4077 #undef DBGC_CLASS
4078 #define DBGC_CLASS DBGC_LOCKING
4080 /****************************************************************************
4081 Reply to a lockread (core+ protocol).
4082 ****************************************************************************/
4084 static void reply_lockread_locked(struct tevent_req *subreq);
4086 void reply_lockread(struct smb_request *req)
4088 struct tevent_req *subreq = NULL;
4089 connection_struct *conn = req->conn;
4090 files_struct *fsp;
4091 struct smbd_lock_element *lck = NULL;
4093 START_PROFILE(SMBlockread);
4095 if (req->wct < 5) {
4096 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4097 END_PROFILE(SMBlockread);
4098 return;
4101 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4103 if (!check_fsp(conn, req, fsp)) {
4104 END_PROFILE(SMBlockread);
4105 return;
4108 if (!CHECK_READ(fsp,req)) {
4109 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4110 END_PROFILE(SMBlockread);
4111 return;
4114 lck = talloc(req, struct smbd_lock_element);
4115 if (lck == NULL) {
4116 reply_nterror(req, NT_STATUS_NO_MEMORY);
4117 END_PROFILE(SMBlockread);
4118 return;
4122 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
4123 * protocol request that predates the read/write lock concept.
4124 * Thus instead of asking for a read lock here we need to ask
4125 * for a write lock. JRA.
4126 * Note that the requested lock size is unaffected by max_send.
4129 *lck = (struct smbd_lock_element) {
4130 .req_guid = smbd_request_guid(req, 0),
4131 .smblctx = req->smbpid,
4132 .brltype = WRITE_LOCK,
4133 .count = SVAL(req->vwv+1, 0),
4134 .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
4137 subreq = smbd_smb1_do_locks_send(
4138 fsp,
4139 req->sconn->ev_ctx,
4140 &req,
4141 fsp,
4143 false, /* large_offset */
4144 WINDOWS_LOCK,
4146 lck);
4147 if (subreq == NULL) {
4148 reply_nterror(req, NT_STATUS_NO_MEMORY);
4149 END_PROFILE(SMBlockread);
4150 return;
4152 tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
4153 END_PROFILE(SMBlockread);
4156 static void reply_lockread_locked(struct tevent_req *subreq)
4158 struct smb_request *req = NULL;
4159 ssize_t nread = -1;
4160 char *data = NULL;
4161 NTSTATUS status;
4162 bool ok;
4163 off_t startpos;
4164 size_t numtoread, maxtoread;
4165 struct files_struct *fsp = NULL;
4166 char *p = NULL;
4168 START_PROFILE(SMBlockread);
4170 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
4171 SMB_ASSERT(ok);
4173 status = smbd_smb1_do_locks_recv(subreq);
4174 TALLOC_FREE(subreq);
4176 if (!NT_STATUS_IS_OK(status)) {
4177 reply_nterror(req, status);
4178 goto send;
4181 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4182 if (fsp == NULL) {
4183 reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
4184 goto send;
4187 numtoread = SVAL(req->vwv+1, 0);
4188 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4191 * However the requested READ size IS affected by max_send. Insanity.... JRA.
4193 maxtoread = req->xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4195 if (numtoread > maxtoread) {
4196 DBG_WARNING("requested read size (%zu) is greater than "
4197 "maximum allowed (%zu/%d). "
4198 "Returning short read of maximum allowed for "
4199 "compatibility with Windows 2000.\n",
4200 numtoread,
4201 maxtoread,
4202 req->xconn->smb1.sessions.max_send);
4203 numtoread = maxtoread;
4206 reply_outbuf(req, 5, numtoread + 3);
4208 data = smb_buf(req->outbuf) + 3;
4210 nread = read_file(fsp,data,startpos,numtoread);
4212 if (nread < 0) {
4213 reply_nterror(req, map_nt_error_from_unix(errno));
4214 goto send;
4217 srv_set_message((char *)req->outbuf, 5, nread+3, False);
4219 SSVAL(req->outbuf,smb_vwv0,nread);
4220 SSVAL(req->outbuf,smb_vwv5,nread+3);
4221 p = smb_buf(req->outbuf);
4222 SCVAL(p,0,0); /* pad byte. */
4223 SSVAL(p,1,nread);
4225 DEBUG(3,("lockread %s num=%d nread=%d\n",
4226 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4228 send:
4229 ok = srv_send_smb(req->xconn,
4230 (char *)req->outbuf,
4231 true,
4232 req->seqnum+1,
4233 IS_CONN_ENCRYPTED(req->conn),
4234 NULL);
4235 if (!ok) {
4236 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
4238 TALLOC_FREE(req);
4239 END_PROFILE(SMBlockread);
4240 return;
4243 #undef DBGC_CLASS
4244 #define DBGC_CLASS DBGC_ALL
4246 /****************************************************************************
4247 Reply to a read.
4248 ****************************************************************************/
4250 void reply_read(struct smb_request *req)
4252 connection_struct *conn = req->conn;
4253 size_t numtoread;
4254 size_t maxtoread;
4255 ssize_t nread = 0;
4256 char *data;
4257 off_t startpos;
4258 files_struct *fsp;
4259 struct lock_struct lock;
4260 struct smbXsrv_connection *xconn = req->xconn;
4262 START_PROFILE(SMBread);
4264 if (req->wct < 3) {
4265 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4266 END_PROFILE(SMBread);
4267 return;
4270 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4272 if (!check_fsp(conn, req, fsp)) {
4273 END_PROFILE(SMBread);
4274 return;
4277 if (!CHECK_READ(fsp,req)) {
4278 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4279 END_PROFILE(SMBread);
4280 return;
4283 numtoread = SVAL(req->vwv+1, 0);
4284 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4287 * The requested read size cannot be greater than max_send. JRA.
4289 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4291 if (numtoread > maxtoread) {
4292 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
4293 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
4294 (unsigned int)numtoread, (unsigned int)maxtoread,
4295 (unsigned int)xconn->smb1.sessions.max_send));
4296 numtoread = maxtoread;
4299 reply_outbuf(req, 5, numtoread+3);
4301 data = smb_buf(req->outbuf) + 3;
4303 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4304 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
4305 &lock);
4307 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4308 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4309 END_PROFILE(SMBread);
4310 return;
4313 if (numtoread > 0)
4314 nread = read_file(fsp,data,startpos,numtoread);
4316 if (nread < 0) {
4317 reply_nterror(req, map_nt_error_from_unix(errno));
4318 goto out;
4321 srv_set_message((char *)req->outbuf, 5, nread+3, False);
4323 SSVAL(req->outbuf,smb_vwv0,nread);
4324 SSVAL(req->outbuf,smb_vwv5,nread+3);
4325 SCVAL(smb_buf(req->outbuf),0,1);
4326 SSVAL(smb_buf(req->outbuf),1,nread);
4328 DEBUG(3, ("read %s num=%d nread=%d\n",
4329 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4331 out:
4332 END_PROFILE(SMBread);
4333 return;
4336 /****************************************************************************
4337 Setup readX header.
4338 ****************************************************************************/
4340 size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
4342 size_t outsize;
4344 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
4345 False);
4347 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
4349 SCVAL(outbuf,smb_vwv0,0xFF);
4350 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
4351 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
4352 SSVAL(outbuf,smb_vwv6,
4353 (smb_wct - 4) /* offset from smb header to wct */
4354 + 1 /* the wct field */
4355 + 12 * sizeof(uint16_t) /* vwv */
4356 + 2 /* the buflen field */
4357 + 1); /* padding byte */
4358 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
4359 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
4360 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
4361 _smb_setlen_large(outbuf,
4362 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
4363 return outsize;
4366 /****************************************************************************
4367 Reply to a read and X - possibly using sendfile.
4368 ****************************************************************************/
4370 static void send_file_readX(connection_struct *conn, struct smb_request *req,
4371 files_struct *fsp, off_t startpos,
4372 size_t smb_maxcnt)
4374 struct smbXsrv_connection *xconn = req->xconn;
4375 ssize_t nread = -1;
4376 struct lock_struct lock;
4377 int saved_errno = 0;
4378 NTSTATUS status;
4380 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4381 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
4382 &lock);
4384 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4385 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4386 return;
4390 * We can only use sendfile on a non-chained packet
4391 * but we can use on a non-oplocked file. tridge proved this
4392 * on a train in Germany :-). JRA.
4395 if (!req_is_in_chain(req) &&
4396 !req->encrypted &&
4397 (fsp->base_fsp == NULL) &&
4398 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
4399 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
4400 DATA_BLOB header;
4402 status = vfs_stat_fsp(fsp);
4403 if (!NT_STATUS_IS_OK(status)) {
4404 reply_nterror(req, status);
4405 goto out;
4408 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4409 (startpos > fsp->fsp_name->st.st_ex_size) ||
4410 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4412 * We already know that we would do a short read, so don't
4413 * try the sendfile() path.
4415 goto nosendfile_read;
4419 * Set up the packet header before send. We
4420 * assume here the sendfile will work (get the
4421 * correct amount of data).
4424 header = data_blob_const(headerbuf, sizeof(headerbuf));
4426 construct_reply_common_req(req, (char *)headerbuf);
4427 setup_readX_header((char *)headerbuf, smb_maxcnt);
4429 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4430 startpos, smb_maxcnt);
4431 if (nread == -1) {
4432 saved_errno = errno;
4434 /* Returning ENOSYS means no data at all was sent.
4435 Do this as a normal read. */
4436 if (errno == ENOSYS) {
4437 goto normal_read;
4441 * Special hack for broken Linux with no working sendfile. If we
4442 * return EINTR we sent the header but not the rest of the data.
4443 * Fake this up by doing read/write calls.
4446 if (errno == EINTR) {
4447 /* Ensure we don't do this again. */
4448 set_use_sendfile(SNUM(conn), False);
4449 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4450 nread = fake_sendfile(xconn, fsp, startpos,
4451 smb_maxcnt);
4452 if (nread == -1) {
4453 saved_errno = errno;
4454 DEBUG(0,("send_file_readX: "
4455 "fake_sendfile failed for "
4456 "file %s (%s) for client %s. "
4457 "Terminating\n",
4458 fsp_str_dbg(fsp),
4459 smbXsrv_connection_dbg(xconn),
4460 strerror(saved_errno)));
4461 errno = saved_errno;
4462 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4464 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4465 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4466 /* No outbuf here means successful sendfile. */
4467 goto out;
4470 DEBUG(0,("send_file_readX: sendfile failed for file "
4471 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4472 strerror(errno)));
4473 exit_server_cleanly("send_file_readX sendfile failed");
4474 } else if (nread == 0) {
4476 * Some sendfile implementations return 0 to indicate
4477 * that there was a short read, but nothing was
4478 * actually written to the socket. In this case,
4479 * fallback to the normal read path so the header gets
4480 * the correct byte count.
4482 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4483 "falling back to the normal read: %s\n",
4484 fsp_str_dbg(fsp)));
4485 goto normal_read;
4488 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4489 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4491 /* Deal with possible short send. */
4492 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4493 ssize_t ret;
4495 ret = sendfile_short_send(xconn, fsp, nread,
4496 sizeof(headerbuf), smb_maxcnt);
4497 if (ret == -1) {
4498 const char *r;
4499 r = "send_file_readX: sendfile_short_send failed";
4500 DEBUG(0,("%s for file %s (%s).\n",
4501 r, fsp_str_dbg(fsp), strerror(errno)));
4502 exit_server_cleanly(r);
4505 /* No outbuf here means successful sendfile. */
4506 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4507 SMB_PERFCOUNT_END(&req->pcd);
4508 goto out;
4511 normal_read:
4513 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4514 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4515 ssize_t ret;
4517 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4518 (startpos > fsp->fsp_name->st.st_ex_size) ||
4519 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4521 * We already know that we would do a short
4522 * read, so don't try the sendfile() path.
4524 goto nosendfile_read;
4527 construct_reply_common_req(req, (char *)headerbuf);
4528 setup_readX_header((char *)headerbuf, smb_maxcnt);
4530 /* Send out the header. */
4531 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4532 sizeof(headerbuf));
4533 if (ret != sizeof(headerbuf)) {
4534 saved_errno = errno;
4536 * Try and give an error message saying what
4537 * client failed.
4539 DEBUG(0,("send_file_readX: write_data failed for file "
4540 "%s (%s) for client %s. Terminating\n",
4541 fsp_str_dbg(fsp),
4542 smbXsrv_connection_dbg(xconn),
4543 strerror(saved_errno)));
4544 errno = saved_errno;
4545 exit_server_cleanly("send_file_readX sendfile failed");
4547 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4548 if (nread == -1) {
4549 saved_errno = errno;
4550 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4551 "%s (%s) for client %s. Terminating\n",
4552 fsp_str_dbg(fsp),
4553 smbXsrv_connection_dbg(xconn),
4554 strerror(saved_errno)));
4555 errno = saved_errno;
4556 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4558 goto out;
4561 nosendfile_read:
4563 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4564 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4565 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4567 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4568 startpos, smb_maxcnt);
4569 saved_errno = errno;
4571 if (nread < 0) {
4572 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4573 return;
4576 setup_readX_header((char *)req->outbuf, nread);
4578 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4579 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4580 return;
4582 out:
4583 TALLOC_FREE(req->outbuf);
4584 return;
4587 /****************************************************************************
4588 Work out how much space we have for a read return.
4589 ****************************************************************************/
4591 static size_t calc_max_read_pdu(const struct smb_request *req)
4593 struct smbXsrv_connection *xconn = req->xconn;
4595 if (xconn->protocol < PROTOCOL_NT1) {
4596 return xconn->smb1.sessions.max_send;
4599 if (!lp_large_readwrite()) {
4600 return xconn->smb1.sessions.max_send;
4603 if (req_is_in_chain(req)) {
4604 return xconn->smb1.sessions.max_send;
4607 if (req->encrypted) {
4609 * Don't take encrypted traffic up to the
4610 * limit. There are padding considerations
4611 * that make that tricky.
4613 return xconn->smb1.sessions.max_send;
4616 if (srv_is_signing_active(xconn)) {
4617 return 0x1FFFF;
4620 if (!lp_unix_extensions()) {
4621 return 0x1FFFF;
4625 * We can do ultra-large POSIX reads.
4627 return 0xFFFFFF;
4630 /****************************************************************************
4631 Calculate how big a read can be. Copes with all clients. It's always
4632 safe to return a short read - Windows does this.
4633 ****************************************************************************/
4635 static size_t calc_read_size(const struct smb_request *req,
4636 size_t upper_size,
4637 size_t lower_size)
4639 struct smbXsrv_connection *xconn = req->xconn;
4640 size_t max_pdu = calc_max_read_pdu(req);
4641 size_t total_size = 0;
4642 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4643 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4646 * Windows explicitly ignores upper size of 0xFFFF.
4647 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4648 * We must do the same as these will never fit even in
4649 * an extended size NetBIOS packet.
4651 if (upper_size == 0xFFFF) {
4652 upper_size = 0;
4655 if (xconn->protocol < PROTOCOL_NT1) {
4656 upper_size = 0;
4659 total_size = ((upper_size<<16) | lower_size);
4662 * LARGE_READX test shows it's always safe to return
4663 * a short read. Windows does so.
4665 return MIN(total_size, max_len);
4668 /****************************************************************************
4669 Reply to a read and X.
4670 ****************************************************************************/
4672 void reply_read_and_X(struct smb_request *req)
4674 connection_struct *conn = req->conn;
4675 files_struct *fsp;
4676 off_t startpos;
4677 size_t smb_maxcnt;
4678 size_t upper_size;
4679 bool big_readX = False;
4680 #if 0
4681 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4682 #endif
4684 START_PROFILE(SMBreadX);
4686 if ((req->wct != 10) && (req->wct != 12)) {
4687 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4688 return;
4691 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4692 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4693 smb_maxcnt = SVAL(req->vwv+5, 0);
4695 /* If it's an IPC, pass off the pipe handler. */
4696 if (IS_IPC(conn)) {
4697 reply_pipe_read_and_X(req);
4698 END_PROFILE(SMBreadX);
4699 return;
4702 if (!check_fsp(conn, req, fsp)) {
4703 END_PROFILE(SMBreadX);
4704 return;
4707 if (!CHECK_READ(fsp,req)) {
4708 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4709 END_PROFILE(SMBreadX);
4710 return;
4713 upper_size = SVAL(req->vwv+7, 0);
4714 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4715 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4717 * This is a heuristic to avoid keeping large
4718 * outgoing buffers around over long-lived aio
4719 * requests.
4721 big_readX = True;
4724 if (req->wct == 12) {
4726 * This is a large offset (64 bit) read.
4728 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4732 if (!big_readX) {
4733 NTSTATUS status = schedule_aio_read_and_X(conn,
4734 req,
4735 fsp,
4736 startpos,
4737 smb_maxcnt);
4738 if (NT_STATUS_IS_OK(status)) {
4739 /* Read scheduled - we're done. */
4740 goto out;
4742 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4743 /* Real error - report to client. */
4744 END_PROFILE(SMBreadX);
4745 reply_nterror(req, status);
4746 return;
4748 /* NT_STATUS_RETRY - fall back to sync read. */
4751 smbd_lock_socket(req->xconn);
4752 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4753 smbd_unlock_socket(req->xconn);
4755 out:
4756 END_PROFILE(SMBreadX);
4757 return;
4760 /****************************************************************************
4761 Error replies to writebraw must have smb_wct == 1. Fix this up.
4762 ****************************************************************************/
4764 void error_to_writebrawerr(struct smb_request *req)
4766 uint8_t *old_outbuf = req->outbuf;
4768 reply_outbuf(req, 1, 0);
4770 memcpy(req->outbuf, old_outbuf, smb_size);
4771 TALLOC_FREE(old_outbuf);
4774 /****************************************************************************
4775 Read 4 bytes of a smb packet and return the smb length of the packet.
4776 Store the result in the buffer. This version of the function will
4777 never return a session keepalive (length of zero).
4778 Timeout is in milliseconds.
4779 ****************************************************************************/
4781 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4782 size_t *len)
4784 uint8_t msgtype = NBSSkeepalive;
4786 while (msgtype == NBSSkeepalive) {
4787 NTSTATUS status;
4789 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4790 len);
4791 if (!NT_STATUS_IS_OK(status)) {
4792 char addr[INET6_ADDRSTRLEN];
4793 /* Try and give an error message
4794 * saying what client failed. */
4795 DEBUG(0, ("read_smb_length_return_keepalive failed for "
4796 "client %s read error = %s.\n",
4797 get_peer_addr(fd,addr,sizeof(addr)),
4798 nt_errstr(status)));
4799 return status;
4802 msgtype = CVAL(inbuf, 0);
4805 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4806 (unsigned long)len));
4808 return NT_STATUS_OK;
4811 /****************************************************************************
4812 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4813 ****************************************************************************/
4815 void reply_writebraw(struct smb_request *req)
4817 connection_struct *conn = req->conn;
4818 struct smbXsrv_connection *xconn = req->xconn;
4819 char *buf = NULL;
4820 ssize_t nwritten=0;
4821 ssize_t total_written=0;
4822 size_t numtowrite=0;
4823 size_t tcount;
4824 off_t startpos;
4825 const char *data=NULL;
4826 bool write_through;
4827 files_struct *fsp;
4828 struct lock_struct lock;
4829 NTSTATUS status;
4831 START_PROFILE(SMBwritebraw);
4834 * If we ever reply with an error, it must have the SMB command
4835 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4836 * we're finished.
4838 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4840 if (srv_is_signing_active(xconn)) {
4841 END_PROFILE(SMBwritebraw);
4842 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4843 "raw reads/writes are disallowed.");
4846 if (req->wct < 12) {
4847 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4848 error_to_writebrawerr(req);
4849 END_PROFILE(SMBwritebraw);
4850 return;
4853 if (xconn->smb1.echo_handler.trusted_fde) {
4854 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4855 "'async smb echo handler = yes'\n"));
4856 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4857 error_to_writebrawerr(req);
4858 END_PROFILE(SMBwritebraw);
4859 return;
4862 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4863 if (!check_fsp(conn, req, fsp)) {
4864 error_to_writebrawerr(req);
4865 END_PROFILE(SMBwritebraw);
4866 return;
4869 if (!CHECK_WRITE(fsp)) {
4870 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4871 error_to_writebrawerr(req);
4872 END_PROFILE(SMBwritebraw);
4873 return;
4876 tcount = IVAL(req->vwv+1, 0);
4877 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4878 write_through = BITSETW(req->vwv+7,0);
4880 /* We have to deal with slightly different formats depending
4881 on whether we are using the core+ or lanman1.0 protocol */
4883 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4884 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4885 data = smb_buf_const(req->inbuf);
4886 } else {
4887 numtowrite = SVAL(req->vwv+10, 0);
4888 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4891 /* Ensure we don't write bytes past the end of this packet. */
4893 * This already protects us against CVE-2017-12163.
4895 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4896 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4897 error_to_writebrawerr(req);
4898 END_PROFILE(SMBwritebraw);
4899 return;
4902 if (!fsp->print_file) {
4903 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4904 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4905 &lock);
4907 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4908 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4909 error_to_writebrawerr(req);
4910 END_PROFILE(SMBwritebraw);
4911 return;
4915 if (numtowrite>0) {
4916 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4919 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4920 "wrote=%d sync=%d\n",
4921 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4922 (int)nwritten, (int)write_through));
4924 if (nwritten < (ssize_t)numtowrite) {
4925 reply_nterror(req, NT_STATUS_DISK_FULL);
4926 error_to_writebrawerr(req);
4927 goto out;
4930 total_written = nwritten;
4932 /* Allocate a buffer of 64k + length. */
4933 buf = talloc_array(NULL, char, 65540);
4934 if (!buf) {
4935 reply_nterror(req, NT_STATUS_NO_MEMORY);
4936 error_to_writebrawerr(req);
4937 goto out;
4940 /* Return a SMBwritebraw message to the redirector to tell
4941 * it to send more bytes */
4943 memcpy(buf, req->inbuf, smb_size);
4944 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4945 SCVAL(buf,smb_com,SMBwritebraw);
4946 SSVALS(buf,smb_vwv0,0xFFFF);
4947 show_msg(buf);
4948 if (!srv_send_smb(req->xconn,
4949 buf,
4950 false, 0, /* no signing */
4951 IS_CONN_ENCRYPTED(conn),
4952 &req->pcd)) {
4953 exit_server_cleanly("reply_writebraw: srv_send_smb "
4954 "failed.");
4957 /* Now read the raw data into the buffer and write it */
4958 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4959 &numtowrite);
4960 if (!NT_STATUS_IS_OK(status)) {
4961 exit_server_cleanly("secondary writebraw failed");
4964 /* Set up outbuf to return the correct size */
4965 reply_outbuf(req, 1, 0);
4967 if (numtowrite != 0) {
4969 if (numtowrite > 0xFFFF) {
4970 DEBUG(0,("reply_writebraw: Oversize secondary write "
4971 "raw requested (%u). Terminating\n",
4972 (unsigned int)numtowrite ));
4973 exit_server_cleanly("secondary writebraw failed");
4976 if (tcount > nwritten+numtowrite) {
4977 DEBUG(3,("reply_writebraw: Client overestimated the "
4978 "write %d %d %d\n",
4979 (int)tcount,(int)nwritten,(int)numtowrite));
4982 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4983 numtowrite);
4985 if (!NT_STATUS_IS_OK(status)) {
4986 /* Try and give an error message
4987 * saying what client failed. */
4988 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4989 "raw read failed (%s) for client %s. "
4990 "Terminating\n", nt_errstr(status),
4991 smbXsrv_connection_dbg(xconn)));
4992 exit_server_cleanly("secondary writebraw failed");
4996 * We are not vulnerable to CVE-2017-12163
4997 * here as we are guaranteed to have numtowrite
4998 * bytes available - we just read from the client.
5000 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
5001 if (nwritten == -1) {
5002 TALLOC_FREE(buf);
5003 reply_nterror(req, map_nt_error_from_unix(errno));
5004 error_to_writebrawerr(req);
5005 goto out;
5008 if (nwritten < (ssize_t)numtowrite) {
5009 SCVAL(req->outbuf,smb_rcls,ERRHRD);
5010 SSVAL(req->outbuf,smb_err,ERRdiskfull);
5013 if (nwritten > 0) {
5014 total_written += nwritten;
5018 TALLOC_FREE(buf);
5019 SSVAL(req->outbuf,smb_vwv0,total_written);
5021 status = sync_file(conn, fsp, write_through);
5022 if (!NT_STATUS_IS_OK(status)) {
5023 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
5024 fsp_str_dbg(fsp), nt_errstr(status)));
5025 reply_nterror(req, status);
5026 error_to_writebrawerr(req);
5027 goto out;
5030 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
5031 "wrote=%d\n",
5032 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
5033 (int)total_written));
5035 /* We won't return a status if write through is not selected - this
5036 * follows what WfWg does */
5037 END_PROFILE(SMBwritebraw);
5039 if (!write_through && total_written==tcount) {
5041 #if RABBIT_PELLET_FIX
5043 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
5044 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
5045 * JRA.
5047 if (!send_keepalive(xconn->transport.sock)) {
5048 exit_server_cleanly("reply_writebraw: send of "
5049 "keepalive failed");
5051 #endif
5052 TALLOC_FREE(req->outbuf);
5054 return;
5056 out:
5057 END_PROFILE(SMBwritebraw);
5058 return;
5061 #undef DBGC_CLASS
5062 #define DBGC_CLASS DBGC_LOCKING
5064 /****************************************************************************
5065 Reply to a writeunlock (core+).
5066 ****************************************************************************/
5068 void reply_writeunlock(struct smb_request *req)
5070 connection_struct *conn = req->conn;
5071 ssize_t nwritten = -1;
5072 size_t numtowrite;
5073 size_t remaining;
5074 off_t startpos;
5075 const char *data;
5076 NTSTATUS status = NT_STATUS_OK;
5077 files_struct *fsp;
5078 struct lock_struct lock;
5079 int saved_errno = 0;
5081 START_PROFILE(SMBwriteunlock);
5083 if (req->wct < 5) {
5084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5085 END_PROFILE(SMBwriteunlock);
5086 return;
5089 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5091 if (!check_fsp(conn, req, fsp)) {
5092 END_PROFILE(SMBwriteunlock);
5093 return;
5096 if (!CHECK_WRITE(fsp)) {
5097 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5098 END_PROFILE(SMBwriteunlock);
5099 return;
5102 numtowrite = SVAL(req->vwv+1, 0);
5103 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5104 data = (const char *)req->buf + 3;
5107 * Ensure client isn't asking us to write more than
5108 * they sent. CVE-2017-12163.
5110 remaining = smbreq_bufrem(req, data);
5111 if (numtowrite > remaining) {
5112 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5113 END_PROFILE(SMBwriteunlock);
5114 return;
5117 if (!fsp->print_file && numtowrite > 0) {
5118 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5119 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5120 &lock);
5122 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5123 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5124 END_PROFILE(SMBwriteunlock);
5125 return;
5129 /* The special X/Open SMB protocol handling of
5130 zero length writes is *NOT* done for
5131 this call */
5132 if(numtowrite == 0) {
5133 nwritten = 0;
5134 } else {
5135 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5136 saved_errno = errno;
5139 status = sync_file(conn, fsp, False /* write through */);
5140 if (!NT_STATUS_IS_OK(status)) {
5141 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
5142 fsp_str_dbg(fsp), nt_errstr(status)));
5143 reply_nterror(req, status);
5144 goto out;
5147 if(nwritten < 0) {
5148 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5149 goto out;
5152 if((nwritten < numtowrite) && (numtowrite != 0)) {
5153 reply_nterror(req, NT_STATUS_DISK_FULL);
5154 goto out;
5157 if (numtowrite && !fsp->print_file) {
5158 struct smbd_lock_element l = {
5159 .req_guid = smbd_request_guid(req, 0),
5160 .smblctx = req->smbpid,
5161 .brltype = UNLOCK_LOCK,
5162 .offset = startpos,
5163 .count = numtowrite,
5165 status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
5166 if (NT_STATUS_V(status)) {
5167 reply_nterror(req, status);
5168 goto out;
5172 reply_outbuf(req, 1, 0);
5174 SSVAL(req->outbuf,smb_vwv0,nwritten);
5176 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
5177 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5179 out:
5180 END_PROFILE(SMBwriteunlock);
5181 return;
5184 #undef DBGC_CLASS
5185 #define DBGC_CLASS DBGC_ALL
5187 /****************************************************************************
5188 Reply to a write.
5189 ****************************************************************************/
5191 void reply_write(struct smb_request *req)
5193 connection_struct *conn = req->conn;
5194 size_t numtowrite;
5195 size_t remaining;
5196 ssize_t nwritten = -1;
5197 off_t startpos;
5198 const char *data;
5199 files_struct *fsp;
5200 struct lock_struct lock;
5201 NTSTATUS status;
5202 int saved_errno = 0;
5204 START_PROFILE(SMBwrite);
5206 if (req->wct < 5) {
5207 END_PROFILE(SMBwrite);
5208 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5209 return;
5212 /* If it's an IPC, pass off the pipe handler. */
5213 if (IS_IPC(conn)) {
5214 reply_pipe_write(req);
5215 END_PROFILE(SMBwrite);
5216 return;
5219 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5221 if (!check_fsp(conn, req, fsp)) {
5222 END_PROFILE(SMBwrite);
5223 return;
5226 if (!CHECK_WRITE(fsp)) {
5227 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5228 END_PROFILE(SMBwrite);
5229 return;
5232 numtowrite = SVAL(req->vwv+1, 0);
5233 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5234 data = (const char *)req->buf + 3;
5237 * Ensure client isn't asking us to write more than
5238 * they sent. CVE-2017-12163.
5240 remaining = smbreq_bufrem(req, data);
5241 if (numtowrite > remaining) {
5242 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5243 END_PROFILE(SMBwrite);
5244 return;
5247 if (!fsp->print_file) {
5248 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5249 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5250 &lock);
5252 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5253 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5254 END_PROFILE(SMBwrite);
5255 return;
5260 * X/Open SMB protocol says that if smb_vwv1 is
5261 * zero then the file size should be extended or
5262 * truncated to the size given in smb_vwv[2-3].
5265 if(numtowrite == 0) {
5267 * This is actually an allocate call, and set EOF. JRA.
5269 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
5270 if (nwritten < 0) {
5271 reply_nterror(req, NT_STATUS_DISK_FULL);
5272 goto out;
5274 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
5275 if (nwritten < 0) {
5276 reply_nterror(req, NT_STATUS_DISK_FULL);
5277 goto out;
5279 trigger_write_time_update_immediate(fsp);
5280 } else {
5281 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5284 status = sync_file(conn, fsp, False);
5285 if (!NT_STATUS_IS_OK(status)) {
5286 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
5287 fsp_str_dbg(fsp), nt_errstr(status)));
5288 reply_nterror(req, status);
5289 goto out;
5292 if(nwritten < 0) {
5293 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5294 goto out;
5297 if((nwritten == 0) && (numtowrite != 0)) {
5298 reply_nterror(req, NT_STATUS_DISK_FULL);
5299 goto out;
5302 reply_outbuf(req, 1, 0);
5304 SSVAL(req->outbuf,smb_vwv0,nwritten);
5306 if (nwritten < (ssize_t)numtowrite) {
5307 SCVAL(req->outbuf,smb_rcls,ERRHRD);
5308 SSVAL(req->outbuf,smb_err,ERRdiskfull);
5311 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5313 out:
5314 END_PROFILE(SMBwrite);
5315 return;
5318 /****************************************************************************
5319 Ensure a buffer is a valid writeX for recvfile purposes.
5320 ****************************************************************************/
5322 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
5323 (2*14) + /* word count (including bcc) */ \
5324 1 /* pad byte */)
5326 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
5327 const uint8_t *inbuf)
5329 size_t numtowrite;
5330 unsigned int doff = 0;
5331 size_t len = smb_len_large(inbuf);
5332 uint16_t fnum;
5333 struct smbXsrv_open *op = NULL;
5334 struct files_struct *fsp = NULL;
5335 NTSTATUS status;
5337 if (is_encrypted_packet(inbuf)) {
5338 /* Can't do this on encrypted
5339 * connections. */
5340 return false;
5343 if (CVAL(inbuf,smb_com) != SMBwriteX) {
5344 return false;
5347 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
5348 CVAL(inbuf,smb_wct) != 14) {
5349 DEBUG(10,("is_valid_writeX_buffer: chained or "
5350 "invalid word length.\n"));
5351 return false;
5354 fnum = SVAL(inbuf, smb_vwv2);
5355 status = smb1srv_open_lookup(xconn,
5356 fnum,
5357 0, /* now */
5358 &op);
5359 if (!NT_STATUS_IS_OK(status)) {
5360 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
5361 return false;
5363 fsp = op->compat;
5364 if (fsp == NULL) {
5365 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
5366 return false;
5368 if (fsp->conn == NULL) {
5369 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
5370 return false;
5373 if (IS_IPC(fsp->conn)) {
5374 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
5375 return false;
5377 if (IS_PRINT(fsp->conn)) {
5378 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
5379 return false;
5381 if (fsp->base_fsp != NULL) {
5382 DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
5383 return false;
5385 doff = SVAL(inbuf,smb_vwv11);
5387 numtowrite = SVAL(inbuf,smb_vwv10);
5389 if (len > doff && len - doff > 0xFFFF) {
5390 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
5393 if (numtowrite == 0) {
5394 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
5395 return false;
5398 /* Ensure the sizes match up. */
5399 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
5400 /* no pad byte...old smbclient :-( */
5401 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
5402 (unsigned int)doff,
5403 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
5404 return false;
5407 if (len - doff != numtowrite) {
5408 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
5409 "len = %u, doff = %u, numtowrite = %u\n",
5410 (unsigned int)len,
5411 (unsigned int)doff,
5412 (unsigned int)numtowrite ));
5413 return false;
5416 DEBUG(10,("is_valid_writeX_buffer: true "
5417 "len = %u, doff = %u, numtowrite = %u\n",
5418 (unsigned int)len,
5419 (unsigned int)doff,
5420 (unsigned int)numtowrite ));
5422 return true;
5425 /****************************************************************************
5426 Reply to a write and X.
5427 ****************************************************************************/
5429 void reply_write_and_X(struct smb_request *req)
5431 connection_struct *conn = req->conn;
5432 struct smbXsrv_connection *xconn = req->xconn;
5433 files_struct *fsp;
5434 struct lock_struct lock;
5435 off_t startpos;
5436 size_t numtowrite;
5437 bool write_through;
5438 ssize_t nwritten;
5439 unsigned int smb_doff;
5440 unsigned int smblen;
5441 const char *data;
5442 NTSTATUS status;
5443 int saved_errno = 0;
5445 START_PROFILE(SMBwriteX);
5447 if ((req->wct != 12) && (req->wct != 14)) {
5448 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5449 goto out;
5452 numtowrite = SVAL(req->vwv+10, 0);
5453 smb_doff = SVAL(req->vwv+11, 0);
5454 smblen = smb_len(req->inbuf);
5456 if (req->unread_bytes > 0xFFFF ||
5457 (smblen > smb_doff &&
5458 smblen - smb_doff > 0xFFFF)) {
5459 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5462 if (req->unread_bytes) {
5463 /* Can't do a recvfile write on IPC$ */
5464 if (IS_IPC(conn)) {
5465 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5466 goto out;
5468 if (numtowrite != req->unread_bytes) {
5469 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5470 goto out;
5472 } else {
5474 * This already protects us against CVE-2017-12163.
5476 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5477 smb_doff + numtowrite > smblen) {
5478 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5479 goto out;
5483 /* If it's an IPC, pass off the pipe handler. */
5484 if (IS_IPC(conn)) {
5485 if (req->unread_bytes) {
5486 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5487 goto out;
5489 reply_pipe_write_and_X(req);
5490 goto out;
5493 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5494 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5495 write_through = BITSETW(req->vwv+7,0);
5497 if (!check_fsp(conn, req, fsp)) {
5498 goto out;
5501 if (!CHECK_WRITE(fsp)) {
5502 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5503 goto out;
5506 data = smb_base(req->inbuf) + smb_doff;
5508 if(req->wct == 14) {
5510 * This is a large offset (64 bit) write.
5512 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5516 /* X/Open SMB protocol says that, unlike SMBwrite
5517 if the length is zero then NO truncation is
5518 done, just a write of zero. To truncate a file,
5519 use SMBwrite. */
5521 if(numtowrite == 0) {
5522 nwritten = 0;
5523 } else {
5524 if (req->unread_bytes == 0) {
5525 status = schedule_aio_write_and_X(conn,
5526 req,
5527 fsp,
5528 data,
5529 startpos,
5530 numtowrite);
5532 if (NT_STATUS_IS_OK(status)) {
5533 /* write scheduled - we're done. */
5534 goto out;
5536 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5537 /* Real error - report to client. */
5538 reply_nterror(req, status);
5539 goto out;
5541 /* NT_STATUS_RETRY - fall through to sync write. */
5544 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5545 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5546 &lock);
5548 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5549 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5550 goto out;
5553 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5554 saved_errno = errno;
5557 if(nwritten < 0) {
5558 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5559 goto out;
5562 if((nwritten == 0) && (numtowrite != 0)) {
5563 reply_nterror(req, NT_STATUS_DISK_FULL);
5564 goto out;
5567 reply_outbuf(req, 6, 0);
5568 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5569 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5570 SSVAL(req->outbuf,smb_vwv2,nwritten);
5571 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5573 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5574 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5576 status = sync_file(conn, fsp, write_through);
5577 if (!NT_STATUS_IS_OK(status)) {
5578 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5579 fsp_str_dbg(fsp), nt_errstr(status)));
5580 reply_nterror(req, status);
5581 goto out;
5584 END_PROFILE(SMBwriteX);
5585 return;
5587 out:
5588 if (req->unread_bytes) {
5589 /* writeX failed. drain socket. */
5590 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5591 req->unread_bytes) {
5592 smb_panic("failed to drain pending bytes");
5594 req->unread_bytes = 0;
5597 END_PROFILE(SMBwriteX);
5598 return;
5601 /****************************************************************************
5602 Reply to a lseek.
5603 ****************************************************************************/
5605 void reply_lseek(struct smb_request *req)
5607 connection_struct *conn = req->conn;
5608 off_t startpos;
5609 off_t res= -1;
5610 int mode,umode;
5611 files_struct *fsp;
5612 NTSTATUS status;
5614 START_PROFILE(SMBlseek);
5616 if (req->wct < 4) {
5617 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5618 END_PROFILE(SMBlseek);
5619 return;
5622 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5624 if (!check_fsp(conn, req, fsp)) {
5625 return;
5628 mode = SVAL(req->vwv+1, 0) & 3;
5629 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5630 startpos = (off_t)IVALS(req->vwv+2, 0);
5632 switch (mode) {
5633 case 0:
5634 umode = SEEK_SET;
5635 res = startpos;
5636 break;
5637 case 1:
5638 umode = SEEK_CUR;
5639 res = fh_get_pos(fsp->fh) + startpos;
5640 break;
5641 case 2:
5642 umode = SEEK_END;
5643 break;
5644 default:
5645 umode = SEEK_SET;
5646 res = startpos;
5647 break;
5650 if (umode == SEEK_END) {
5651 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5652 if(errno == EINVAL) {
5653 off_t current_pos = startpos;
5655 status = vfs_stat_fsp(fsp);
5656 if (!NT_STATUS_IS_OK(status)) {
5657 reply_nterror(req, status);
5658 END_PROFILE(SMBlseek);
5659 return;
5662 current_pos += fsp->fsp_name->st.st_ex_size;
5663 if(current_pos < 0)
5664 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5668 if(res == -1) {
5669 reply_nterror(req, map_nt_error_from_unix(errno));
5670 END_PROFILE(SMBlseek);
5671 return;
5675 fh_set_pos(fsp->fh, res);
5677 reply_outbuf(req, 2, 0);
5678 SIVAL(req->outbuf,smb_vwv0,res);
5680 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5681 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5683 END_PROFILE(SMBlseek);
5684 return;
5687 static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
5688 void *private_data)
5690 connection_struct *conn = talloc_get_type_abort(
5691 private_data, connection_struct);
5693 if (conn != fsp->conn) {
5694 return NULL;
5696 if (fsp_get_io_fd(fsp) == -1) {
5697 return NULL;
5699 sync_file(conn, fsp, True /* write through */);
5701 if (fsp->fsp_flags.modified) {
5702 trigger_write_time_update_immediate(fsp);
5705 return NULL;
5708 /****************************************************************************
5709 Reply to a flush.
5710 ****************************************************************************/
5712 void reply_flush(struct smb_request *req)
5714 connection_struct *conn = req->conn;
5715 uint16_t fnum;
5716 files_struct *fsp;
5718 START_PROFILE(SMBflush);
5720 if (req->wct < 1) {
5721 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5722 return;
5725 fnum = SVAL(req->vwv+0, 0);
5726 fsp = file_fsp(req, fnum);
5728 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5729 return;
5732 if (!fsp) {
5733 files_forall(req->sconn, file_sync_one_fn, conn);
5734 } else {
5735 NTSTATUS status = sync_file(conn, fsp, True);
5736 if (!NT_STATUS_IS_OK(status)) {
5737 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5738 fsp_str_dbg(fsp), nt_errstr(status)));
5739 reply_nterror(req, status);
5740 END_PROFILE(SMBflush);
5741 return;
5743 if (fsp->fsp_flags.modified) {
5744 trigger_write_time_update_immediate(fsp);
5748 reply_outbuf(req, 0, 0);
5750 DEBUG(3,("flush\n"));
5751 END_PROFILE(SMBflush);
5752 return;
5755 /****************************************************************************
5756 Reply to a exit.
5757 conn POINTER CAN BE NULL HERE !
5758 ****************************************************************************/
5760 static struct tevent_req *reply_exit_send(struct smb_request *smb1req);
5761 static void reply_exit_done(struct tevent_req *req);
5763 void reply_exit(struct smb_request *smb1req)
5765 struct tevent_req *req;
5768 * Don't setup the profile charge here, take
5769 * it in reply_exit_done(). Not strictly correct
5770 * but better than the other SMB1 async
5771 * code that double-charges at the moment.
5773 req = reply_exit_send(smb1req);
5774 if (req == NULL) {
5775 /* Not going async, profile here. */
5776 START_PROFILE(SMBexit);
5777 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
5778 END_PROFILE(SMBexit);
5779 return;
5782 /* We're async. This will complete later. */
5783 tevent_req_set_callback(req, reply_exit_done, smb1req);
5784 return;
5787 struct reply_exit_state {
5788 struct tevent_queue *wait_queue;
5791 static void reply_exit_wait_done(struct tevent_req *subreq);
5793 /****************************************************************************
5794 Async SMB1 exit.
5795 Note, on failure here we deallocate and return NULL to allow the caller to
5796 SMB1 return an error of ERRnomem immediately.
5797 ****************************************************************************/
5799 static struct tevent_req *reply_exit_send(struct smb_request *smb1req)
5801 struct tevent_req *req;
5802 struct reply_exit_state *state;
5803 struct tevent_req *subreq;
5804 files_struct *fsp;
5805 struct smbd_server_connection *sconn = smb1req->sconn;
5807 req = tevent_req_create(smb1req, &state,
5808 struct reply_exit_state);
5809 if (req == NULL) {
5810 return NULL;
5812 state->wait_queue = tevent_queue_create(state,
5813 "reply_exit_wait_queue");
5814 if (tevent_req_nomem(state->wait_queue, req)) {
5815 TALLOC_FREE(req);
5816 return NULL;
5819 for (fsp = sconn->files; fsp; fsp = fsp->next) {
5820 if (fsp->file_pid != smb1req->smbpid) {
5821 continue;
5823 if (fsp->vuid != smb1req->vuid) {
5824 continue;
5827 * Flag the file as close in progress.
5828 * This will prevent any more IO being
5829 * done on it.
5831 fsp->fsp_flags.closing = true;
5833 if (fsp->num_aio_requests > 0) {
5835 * Now wait until all aio requests on this fsp are
5836 * finished.
5838 * We don't set a callback, as we just want to block the
5839 * wait queue and the talloc_free() of fsp->aio_request
5840 * will remove the item from the wait queue.
5842 subreq = tevent_queue_wait_send(fsp->aio_requests,
5843 sconn->ev_ctx,
5844 state->wait_queue);
5845 if (tevent_req_nomem(subreq, req)) {
5846 TALLOC_FREE(req);
5847 return NULL;
5853 * Now we add our own waiter to the end of the queue,
5854 * this way we get notified when all pending requests are finished
5855 * and reply to the outstanding SMB1 request.
5857 subreq = tevent_queue_wait_send(state,
5858 sconn->ev_ctx,
5859 state->wait_queue);
5860 if (tevent_req_nomem(subreq, req)) {
5861 TALLOC_FREE(req);
5862 return NULL;
5866 * We're really going async - move the SMB1 request from
5867 * a talloc stackframe above us to the conn talloc-context.
5868 * We need this to stick around until the wait_done
5869 * callback is invoked.
5871 smb1req = talloc_move(sconn, &smb1req);
5873 tevent_req_set_callback(subreq, reply_exit_wait_done, req);
5875 return req;
5878 static void reply_exit_wait_done(struct tevent_req *subreq)
5880 struct tevent_req *req = tevent_req_callback_data(
5881 subreq, struct tevent_req);
5883 tevent_queue_wait_recv(subreq);
5884 TALLOC_FREE(subreq);
5885 tevent_req_done(req);
5888 static NTSTATUS reply_exit_recv(struct tevent_req *req)
5890 return tevent_req_simple_recv_ntstatus(req);
5893 static void reply_exit_done(struct tevent_req *req)
5895 struct smb_request *smb1req = tevent_req_callback_data(
5896 req, struct smb_request);
5897 struct smbd_server_connection *sconn = smb1req->sconn;
5898 struct smbXsrv_connection *xconn = smb1req->xconn;
5899 NTTIME now = timeval_to_nttime(&smb1req->request_time);
5900 struct smbXsrv_session *session = NULL;
5901 files_struct *fsp, *next;
5902 NTSTATUS status;
5905 * Take the profile charge here. Not strictly
5906 * correct but better than the other SMB1 async
5907 * code that double-charges at the moment.
5909 START_PROFILE(SMBexit);
5911 status = reply_exit_recv(req);
5912 TALLOC_FREE(req);
5913 if (!NT_STATUS_IS_OK(status)) {
5914 TALLOC_FREE(smb1req);
5915 END_PROFILE(SMBexit);
5916 exit_server(__location__ ": reply_exit_recv failed");
5917 return;
5921 * Ensure the session is still valid.
5923 status = smb1srv_session_lookup(xconn,
5924 smb1req->vuid,
5925 now,
5926 &session);
5927 if (!NT_STATUS_IS_OK(status)) {
5928 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5929 smb_request_done(smb1req);
5930 END_PROFILE(SMBexit);
5934 * Ensure the vuid is still valid - no one
5935 * called reply_ulogoffX() in the meantime.
5936 * reply_exit() doesn't have AS_USER set, so
5937 * use set_current_user_info() directly.
5938 * This is the same logic as in switch_message().
5940 if (session->global->auth_session_info != NULL) {
5941 set_current_user_info(
5942 session->global->auth_session_info->unix_info->sanitized_username,
5943 session->global->auth_session_info->unix_info->unix_name,
5944 session->global->auth_session_info->info->domain_name);
5947 /* No more aio - do the actual closes. */
5948 for (fsp = sconn->files; fsp; fsp = next) {
5949 bool ok;
5950 next = fsp->next;
5952 if (fsp->file_pid != smb1req->smbpid) {
5953 continue;
5955 if (fsp->vuid != smb1req->vuid) {
5956 continue;
5958 if (!fsp->fsp_flags.closing) {
5959 continue;
5963 * reply_exit() has the DO_CHDIR flag set.
5965 ok = chdir_current_service(fsp->conn);
5966 if (!ok) {
5967 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
5968 smb_request_done(smb1req);
5969 END_PROFILE(SMBexit);
5971 close_file(NULL, fsp, SHUTDOWN_CLOSE);
5974 reply_outbuf(smb1req, 0, 0);
5976 * The following call is needed to push the
5977 * reply data back out the socket after async
5978 * return. Plus it frees smb1req.
5980 smb_request_done(smb1req);
5981 DBG_INFO("reply_exit complete\n");
5982 END_PROFILE(SMBexit);
5983 return;
5986 static struct tevent_req *reply_close_send(struct smb_request *smb1req,
5987 files_struct *fsp);
5988 static void reply_close_done(struct tevent_req *req);
5990 void reply_close(struct smb_request *smb1req)
5992 connection_struct *conn = smb1req->conn;
5993 NTSTATUS status = NT_STATUS_OK;
5994 files_struct *fsp = NULL;
5995 START_PROFILE(SMBclose);
5997 if (smb1req->wct < 3) {
5998 reply_nterror(smb1req, NT_STATUS_INVALID_PARAMETER);
5999 END_PROFILE(SMBclose);
6000 return;
6003 fsp = file_fsp(smb1req, SVAL(smb1req->vwv+0, 0));
6006 * We can only use check_fsp if we know it's not a directory.
6009 if (!check_fsp_open(conn, smb1req, fsp)) {
6010 reply_nterror(smb1req, NT_STATUS_INVALID_HANDLE);
6011 END_PROFILE(SMBclose);
6012 return;
6015 DBG_NOTICE("Close %s fd=%d %s (numopen=%d)\n",
6016 fsp->fsp_flags.is_directory ?
6017 "directory" : "file",
6018 fsp_get_pathref_fd(fsp), fsp_fnum_dbg(fsp),
6019 conn->num_files_open);
6021 if (!fsp->fsp_flags.is_directory) {
6022 time_t t;
6025 * Take care of any time sent in the close.
6028 t = srv_make_unix_date3(smb1req->vwv+1);
6029 set_close_write_time(fsp, time_t_to_full_timespec(t));
6032 if (fsp->num_aio_requests != 0) {
6033 struct tevent_req *req;
6035 req = reply_close_send(smb1req, fsp);
6036 if (req == NULL) {
6037 status = NT_STATUS_NO_MEMORY;
6038 goto done;
6040 /* We're async. This will complete later. */
6041 tevent_req_set_callback(req, reply_close_done, smb1req);
6042 END_PROFILE(SMBclose);
6043 return;
6047 * close_file() returns the unix errno if an error was detected on
6048 * close - normally this is due to a disk full error. If not then it
6049 * was probably an I/O error.
6052 status = close_file(smb1req, fsp, NORMAL_CLOSE);
6053 done:
6054 if (!NT_STATUS_IS_OK(status)) {
6055 reply_nterror(smb1req, status);
6056 END_PROFILE(SMBclose);
6057 return;
6060 reply_outbuf(smb1req, 0, 0);
6061 END_PROFILE(SMBclose);
6062 return;
6065 struct reply_close_state {
6066 files_struct *fsp;
6067 struct tevent_queue *wait_queue;
6070 static void reply_close_wait_done(struct tevent_req *subreq);
6072 /****************************************************************************
6073 Async SMB1 close.
6074 Note, on failure here we deallocate and return NULL to allow the caller to
6075 SMB1 return an error of ERRnomem immediately.
6076 ****************************************************************************/
6078 static struct tevent_req *reply_close_send(struct smb_request *smb1req,
6079 files_struct *fsp)
6081 struct tevent_req *req;
6082 struct reply_close_state *state;
6083 struct tevent_req *subreq;
6084 struct smbd_server_connection *sconn = smb1req->sconn;
6086 req = tevent_req_create(smb1req, &state,
6087 struct reply_close_state);
6088 if (req == NULL) {
6089 return NULL;
6091 state->wait_queue = tevent_queue_create(state,
6092 "reply_close_wait_queue");
6093 if (tevent_req_nomem(state->wait_queue, req)) {
6094 TALLOC_FREE(req);
6095 return NULL;
6099 * Flag the file as close in progress.
6100 * This will prevent any more IO being
6101 * done on it.
6103 fsp->fsp_flags.closing = true;
6106 * Now wait until all aio requests on this fsp are
6107 * finished.
6109 * We don't set a callback, as we just want to block the
6110 * wait queue and the talloc_free() of fsp->aio_request
6111 * will remove the item from the wait queue.
6113 subreq = tevent_queue_wait_send(fsp->aio_requests,
6114 sconn->ev_ctx,
6115 state->wait_queue);
6116 if (tevent_req_nomem(subreq, req)) {
6117 TALLOC_FREE(req);
6118 return NULL;
6122 * Now we add our own waiter to the end of the queue,
6123 * this way we get notified when all pending requests are finished
6124 * and reply to the outstanding SMB1 request.
6126 subreq = tevent_queue_wait_send(state,
6127 sconn->ev_ctx,
6128 state->wait_queue);
6129 if (tevent_req_nomem(subreq, req)) {
6130 TALLOC_FREE(req);
6131 return NULL;
6135 * We're really going async - move the SMB1 request from
6136 * a talloc stackframe above us to the conn talloc-context.
6137 * We need this to stick around until the wait_done
6138 * callback is invoked.
6140 smb1req = talloc_move(sconn, &smb1req);
6142 tevent_req_set_callback(subreq, reply_close_wait_done, req);
6144 return req;
6147 static void reply_close_wait_done(struct tevent_req *subreq)
6149 struct tevent_req *req = tevent_req_callback_data(
6150 subreq, struct tevent_req);
6152 tevent_queue_wait_recv(subreq);
6153 TALLOC_FREE(subreq);
6154 tevent_req_done(req);
6157 static NTSTATUS reply_close_recv(struct tevent_req *req)
6159 return tevent_req_simple_recv_ntstatus(req);
6162 static void reply_close_done(struct tevent_req *req)
6164 struct smb_request *smb1req = tevent_req_callback_data(
6165 req, struct smb_request);
6166 struct reply_close_state *state = tevent_req_data(req,
6167 struct reply_close_state);
6168 NTSTATUS status;
6170 status = reply_close_recv(req);
6171 TALLOC_FREE(req);
6172 if (!NT_STATUS_IS_OK(status)) {
6173 TALLOC_FREE(smb1req);
6174 exit_server(__location__ ": reply_close_recv failed");
6175 return;
6178 status = close_file(smb1req, state->fsp, NORMAL_CLOSE);
6179 if (NT_STATUS_IS_OK(status)) {
6180 reply_outbuf(smb1req, 0, 0);
6181 } else {
6182 reply_nterror(smb1req, status);
6185 * The following call is needed to push the
6186 * reply data back out the socket after async
6187 * return. Plus it frees smb1req.
6189 smb_request_done(smb1req);
6192 /****************************************************************************
6193 Reply to a writeclose (Core+ protocol).
6194 ****************************************************************************/
6196 void reply_writeclose(struct smb_request *req)
6198 connection_struct *conn = req->conn;
6199 size_t numtowrite;
6200 size_t remaining;
6201 ssize_t nwritten = -1;
6202 NTSTATUS close_status = NT_STATUS_OK;
6203 off_t startpos;
6204 const char *data;
6205 struct timespec mtime;
6206 files_struct *fsp;
6207 struct lock_struct lock;
6209 START_PROFILE(SMBwriteclose);
6211 if (req->wct < 6) {
6212 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6213 END_PROFILE(SMBwriteclose);
6214 return;
6217 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6219 if (!check_fsp(conn, req, fsp)) {
6220 END_PROFILE(SMBwriteclose);
6221 return;
6223 if (!CHECK_WRITE(fsp)) {
6224 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6225 END_PROFILE(SMBwriteclose);
6226 return;
6229 numtowrite = SVAL(req->vwv+1, 0);
6230 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
6231 mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+4));
6232 data = (const char *)req->buf + 1;
6235 * Ensure client isn't asking us to write more than
6236 * they sent. CVE-2017-12163.
6238 remaining = smbreq_bufrem(req, data);
6239 if (numtowrite > remaining) {
6240 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6241 END_PROFILE(SMBwriteclose);
6242 return;
6245 if (fsp->print_file == NULL) {
6246 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
6247 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
6248 &lock);
6250 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
6251 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
6252 END_PROFILE(SMBwriteclose);
6253 return;
6257 nwritten = write_file(req,fsp,data,startpos,numtowrite);
6259 set_close_write_time(fsp, mtime);
6262 * More insanity. W2K only closes the file if writelen > 0.
6263 * JRA.
6266 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
6267 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
6268 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
6270 if (numtowrite) {
6271 DEBUG(3,("reply_writeclose: zero length write doesn't close "
6272 "file %s\n", fsp_str_dbg(fsp)));
6273 close_status = close_file(req, fsp, NORMAL_CLOSE);
6274 fsp = NULL;
6277 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
6278 reply_nterror(req, NT_STATUS_DISK_FULL);
6279 goto out;
6282 if(!NT_STATUS_IS_OK(close_status)) {
6283 reply_nterror(req, close_status);
6284 goto out;
6287 reply_outbuf(req, 1, 0);
6289 SSVAL(req->outbuf,smb_vwv0,nwritten);
6291 out:
6293 END_PROFILE(SMBwriteclose);
6294 return;
6297 #undef DBGC_CLASS
6298 #define DBGC_CLASS DBGC_LOCKING
6300 /****************************************************************************
6301 Reply to a lock.
6302 ****************************************************************************/
6304 static void reply_lock_done(struct tevent_req *subreq);
6306 void reply_lock(struct smb_request *req)
6308 struct tevent_req *subreq = NULL;
6309 connection_struct *conn = req->conn;
6310 files_struct *fsp;
6311 struct smbd_lock_element *lck = NULL;
6313 START_PROFILE(SMBlock);
6315 if (req->wct < 5) {
6316 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6317 END_PROFILE(SMBlock);
6318 return;
6321 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6323 if (!check_fsp(conn, req, fsp)) {
6324 END_PROFILE(SMBlock);
6325 return;
6328 lck = talloc(req, struct smbd_lock_element);
6329 if (lck == NULL) {
6330 reply_nterror(req, NT_STATUS_NO_MEMORY);
6331 END_PROFILE(SMBlock);
6332 return;
6335 *lck = (struct smbd_lock_element) {
6336 .req_guid = smbd_request_guid(req, 0),
6337 .smblctx = req->smbpid,
6338 .brltype = WRITE_LOCK,
6339 .count = IVAL(req->vwv+1, 0),
6340 .offset = IVAL(req->vwv+3, 0),
6343 DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
6344 fsp_get_io_fd(fsp),
6345 fsp_fnum_dbg(fsp),
6346 lck->offset,
6347 lck->count);
6349 subreq = smbd_smb1_do_locks_send(
6350 fsp,
6351 req->sconn->ev_ctx,
6352 &req,
6353 fsp,
6355 false, /* large_offset */
6356 WINDOWS_LOCK,
6358 lck);
6359 if (subreq == NULL) {
6360 reply_nterror(req, NT_STATUS_NO_MEMORY);
6361 END_PROFILE(SMBlock);
6362 return;
6364 tevent_req_set_callback(subreq, reply_lock_done, NULL);
6365 END_PROFILE(SMBlock);
6368 static void reply_lock_done(struct tevent_req *subreq)
6370 struct smb_request *req = NULL;
6371 NTSTATUS status;
6372 bool ok;
6374 START_PROFILE(SMBlock);
6376 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
6377 SMB_ASSERT(ok);
6379 status = smbd_smb1_do_locks_recv(subreq);
6380 TALLOC_FREE(subreq);
6382 if (NT_STATUS_IS_OK(status)) {
6383 reply_outbuf(req, 0, 0);
6384 } else {
6385 reply_nterror(req, status);
6388 ok = srv_send_smb(req->xconn,
6389 (char *)req->outbuf,
6390 true,
6391 req->seqnum+1,
6392 IS_CONN_ENCRYPTED(req->conn),
6393 NULL);
6394 if (!ok) {
6395 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
6397 TALLOC_FREE(req);
6398 END_PROFILE(SMBlock);
6401 /****************************************************************************
6402 Reply to a unlock.
6403 ****************************************************************************/
6405 void reply_unlock(struct smb_request *req)
6407 connection_struct *conn = req->conn;
6408 NTSTATUS status;
6409 files_struct *fsp;
6410 struct smbd_lock_element lck;
6412 START_PROFILE(SMBunlock);
6414 if (req->wct < 5) {
6415 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6416 END_PROFILE(SMBunlock);
6417 return;
6420 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6422 if (!check_fsp(conn, req, fsp)) {
6423 END_PROFILE(SMBunlock);
6424 return;
6427 lck = (struct smbd_lock_element) {
6428 .req_guid = smbd_request_guid(req, 0),
6429 .smblctx = req->smbpid,
6430 .brltype = UNLOCK_LOCK,
6431 .offset = IVAL(req->vwv+3, 0),
6432 .count = IVAL(req->vwv+1, 0),
6435 status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
6437 if (!NT_STATUS_IS_OK(status)) {
6438 reply_nterror(req, status);
6439 END_PROFILE(SMBunlock);
6440 return;
6443 DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
6444 fsp_get_io_fd(fsp),
6445 fsp_fnum_dbg(fsp),
6446 lck.offset,
6447 lck.count);
6449 reply_outbuf(req, 0, 0);
6451 END_PROFILE(SMBunlock);
6452 return;
6455 #undef DBGC_CLASS
6456 #define DBGC_CLASS DBGC_ALL
6458 /****************************************************************************
6459 Reply to a tdis.
6460 conn POINTER CAN BE NULL HERE !
6461 ****************************************************************************/
6463 static struct tevent_req *reply_tdis_send(struct smb_request *smb1req);
6464 static void reply_tdis_done(struct tevent_req *req);
6466 void reply_tdis(struct smb_request *smb1req)
6468 connection_struct *conn = smb1req->conn;
6469 struct tevent_req *req;
6472 * Don't setup the profile charge here, take
6473 * it in reply_tdis_done(). Not strictly correct
6474 * but better than the other SMB1 async
6475 * code that double-charges at the moment.
6478 if (conn == NULL) {
6479 /* Not going async, profile here. */
6480 START_PROFILE(SMBtdis);
6481 DBG_INFO("Invalid connection in tdis\n");
6482 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
6483 END_PROFILE(SMBtdis);
6484 return;
6487 req = reply_tdis_send(smb1req);
6488 if (req == NULL) {
6489 /* Not going async, profile here. */
6490 START_PROFILE(SMBtdis);
6491 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
6492 END_PROFILE(SMBtdis);
6493 return;
6495 /* We're async. This will complete later. */
6496 tevent_req_set_callback(req, reply_tdis_done, smb1req);
6497 return;
6500 struct reply_tdis_state {
6501 struct tevent_queue *wait_queue;
6504 static void reply_tdis_wait_done(struct tevent_req *subreq);
6506 /****************************************************************************
6507 Async SMB1 tdis.
6508 Note, on failure here we deallocate and return NULL to allow the caller to
6509 SMB1 return an error of ERRnomem immediately.
6510 ****************************************************************************/
6512 static struct tevent_req *reply_tdis_send(struct smb_request *smb1req)
6514 struct tevent_req *req;
6515 struct reply_tdis_state *state;
6516 struct tevent_req *subreq;
6517 connection_struct *conn = smb1req->conn;
6518 files_struct *fsp;
6520 req = tevent_req_create(smb1req, &state,
6521 struct reply_tdis_state);
6522 if (req == NULL) {
6523 return NULL;
6525 state->wait_queue = tevent_queue_create(state, "reply_tdis_wait_queue");
6526 if (tevent_req_nomem(state->wait_queue, req)) {
6527 TALLOC_FREE(req);
6528 return NULL;
6532 * Make sure that no new request will be able to use this tcon.
6533 * This ensures that once all outstanding fsp->aio_requests
6534 * on this tcon are done, we are safe to close it.
6536 conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
6538 for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
6539 if (fsp->conn != conn) {
6540 continue;
6543 * Flag the file as close in progress.
6544 * This will prevent any more IO being
6545 * done on it. Not strictly needed, but
6546 * doesn't hurt to flag it as closing.
6548 fsp->fsp_flags.closing = true;
6550 if (fsp->num_aio_requests > 0) {
6552 * Now wait until all aio requests on this fsp are
6553 * finished.
6555 * We don't set a callback, as we just want to block the
6556 * wait queue and the talloc_free() of fsp->aio_request
6557 * will remove the item from the wait queue.
6559 subreq = tevent_queue_wait_send(fsp->aio_requests,
6560 conn->sconn->ev_ctx,
6561 state->wait_queue);
6562 if (tevent_req_nomem(subreq, req)) {
6563 TALLOC_FREE(req);
6564 return NULL;
6570 * Now we add our own waiter to the end of the queue,
6571 * this way we get notified when all pending requests are finished
6572 * and reply to the outstanding SMB1 request.
6574 subreq = tevent_queue_wait_send(state,
6575 conn->sconn->ev_ctx,
6576 state->wait_queue);
6577 if (tevent_req_nomem(subreq, req)) {
6578 TALLOC_FREE(req);
6579 return NULL;
6583 * We're really going async - move the SMB1 request from
6584 * a talloc stackframe above us to the sconn talloc-context.
6585 * We need this to stick around until the wait_done
6586 * callback is invoked.
6588 smb1req = talloc_move(smb1req->sconn, &smb1req);
6590 tevent_req_set_callback(subreq, reply_tdis_wait_done, req);
6592 return req;
6595 static void reply_tdis_wait_done(struct tevent_req *subreq)
6597 struct tevent_req *req = tevent_req_callback_data(
6598 subreq, struct tevent_req);
6600 tevent_queue_wait_recv(subreq);
6601 TALLOC_FREE(subreq);
6602 tevent_req_done(req);
6605 static NTSTATUS reply_tdis_recv(struct tevent_req *req)
6607 return tevent_req_simple_recv_ntstatus(req);
6610 static void reply_tdis_done(struct tevent_req *req)
6612 struct smb_request *smb1req = tevent_req_callback_data(
6613 req, struct smb_request);
6614 NTSTATUS status;
6615 struct smbXsrv_tcon *tcon = smb1req->conn->tcon;
6616 bool ok;
6619 * Take the profile charge here. Not strictly
6620 * correct but better than the other SMB1 async
6621 * code that double-charges at the moment.
6623 START_PROFILE(SMBtdis);
6625 status = reply_tdis_recv(req);
6626 TALLOC_FREE(req);
6627 if (!NT_STATUS_IS_OK(status)) {
6628 TALLOC_FREE(smb1req);
6629 END_PROFILE(SMBtdis);
6630 exit_server(__location__ ": reply_tdis_recv failed");
6631 return;
6635 * As we've been awoken, we may have changed
6636 * directory in the meantime.
6637 * reply_tdis() has the DO_CHDIR flag set.
6639 ok = chdir_current_service(smb1req->conn);
6640 if (!ok) {
6641 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
6642 smb_request_done(smb1req);
6643 END_PROFILE(SMBtdis);
6646 status = smbXsrv_tcon_disconnect(tcon,
6647 smb1req->vuid);
6648 if (!NT_STATUS_IS_OK(status)) {
6649 TALLOC_FREE(smb1req);
6650 END_PROFILE(SMBtdis);
6651 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
6652 return;
6655 /* smbXsrv_tcon_disconnect frees smb1req->conn. */
6656 smb1req->conn = NULL;
6658 TALLOC_FREE(tcon);
6660 reply_outbuf(smb1req, 0, 0);
6662 * The following call is needed to push the
6663 * reply data back out the socket after async
6664 * return. Plus it frees smb1req.
6666 smb_request_done(smb1req);
6667 END_PROFILE(SMBtdis);
6670 /****************************************************************************
6671 Reply to a echo.
6672 conn POINTER CAN BE NULL HERE !
6673 ****************************************************************************/
6675 void reply_echo(struct smb_request *req)
6677 connection_struct *conn = req->conn;
6678 struct smb_perfcount_data local_pcd;
6679 struct smb_perfcount_data *cur_pcd;
6680 int smb_reverb;
6681 int seq_num;
6683 START_PROFILE(SMBecho);
6685 smb_init_perfcount_data(&local_pcd);
6687 if (req->wct < 1) {
6688 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6689 END_PROFILE(SMBecho);
6690 return;
6693 smb_reverb = SVAL(req->vwv+0, 0);
6695 reply_outbuf(req, 1, req->buflen);
6697 /* copy any incoming data back out */
6698 if (req->buflen > 0) {
6699 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
6702 if (smb_reverb > 100) {
6703 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
6704 smb_reverb = 100;
6707 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
6709 /* this makes sure we catch the request pcd */
6710 if (seq_num == smb_reverb) {
6711 cur_pcd = &req->pcd;
6712 } else {
6713 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
6714 cur_pcd = &local_pcd;
6717 SSVAL(req->outbuf,smb_vwv0,seq_num);
6719 show_msg((char *)req->outbuf);
6720 if (!srv_send_smb(req->xconn,
6721 (char *)req->outbuf,
6722 true, req->seqnum+1,
6723 IS_CONN_ENCRYPTED(conn)||req->encrypted,
6724 cur_pcd))
6725 exit_server_cleanly("reply_echo: srv_send_smb failed.");
6728 DEBUG(3,("echo %d times\n", smb_reverb));
6730 TALLOC_FREE(req->outbuf);
6732 END_PROFILE(SMBecho);
6733 return;
6736 /****************************************************************************
6737 Reply to a printopen.
6738 ****************************************************************************/
6740 void reply_printopen(struct smb_request *req)
6742 connection_struct *conn = req->conn;
6743 files_struct *fsp;
6744 NTSTATUS status;
6746 START_PROFILE(SMBsplopen);
6748 if (req->wct < 2) {
6749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6750 END_PROFILE(SMBsplopen);
6751 return;
6754 if (!CAN_PRINT(conn)) {
6755 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6756 END_PROFILE(SMBsplopen);
6757 return;
6760 status = file_new(req, conn, &fsp);
6761 if(!NT_STATUS_IS_OK(status)) {
6762 reply_nterror(req, status);
6763 END_PROFILE(SMBsplopen);
6764 return;
6767 /* Open for exclusive use, write only. */
6768 status = print_spool_open(fsp, NULL, req->vuid);
6770 if (!NT_STATUS_IS_OK(status)) {
6771 file_free(req, fsp);
6772 reply_nterror(req, status);
6773 END_PROFILE(SMBsplopen);
6774 return;
6777 reply_outbuf(req, 1, 0);
6778 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
6780 DEBUG(3,("openprint fd=%d %s\n",
6781 fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
6783 END_PROFILE(SMBsplopen);
6784 return;
6787 /****************************************************************************
6788 Reply to a printclose.
6789 ****************************************************************************/
6791 void reply_printclose(struct smb_request *req)
6793 connection_struct *conn = req->conn;
6794 files_struct *fsp;
6795 NTSTATUS status;
6797 START_PROFILE(SMBsplclose);
6799 if (req->wct < 1) {
6800 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6801 END_PROFILE(SMBsplclose);
6802 return;
6805 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6807 if (!check_fsp(conn, req, fsp)) {
6808 END_PROFILE(SMBsplclose);
6809 return;
6812 if (!CAN_PRINT(conn)) {
6813 reply_force_doserror(req, ERRSRV, ERRerror);
6814 END_PROFILE(SMBsplclose);
6815 return;
6818 DEBUG(3,("printclose fd=%d %s\n",
6819 fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
6821 status = close_file(req, fsp, NORMAL_CLOSE);
6823 if(!NT_STATUS_IS_OK(status)) {
6824 reply_nterror(req, status);
6825 END_PROFILE(SMBsplclose);
6826 return;
6829 reply_outbuf(req, 0, 0);
6831 END_PROFILE(SMBsplclose);
6832 return;
6835 /****************************************************************************
6836 Reply to a printqueue.
6837 ****************************************************************************/
6839 void reply_printqueue(struct smb_request *req)
6841 const struct loadparm_substitution *lp_sub =
6842 loadparm_s3_global_substitution();
6843 connection_struct *conn = req->conn;
6844 int max_count;
6845 int start_index;
6847 START_PROFILE(SMBsplretq);
6849 if (req->wct < 2) {
6850 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6851 END_PROFILE(SMBsplretq);
6852 return;
6855 max_count = SVAL(req->vwv+0, 0);
6856 start_index = SVAL(req->vwv+1, 0);
6858 /* we used to allow the client to get the cnum wrong, but that
6859 is really quite gross and only worked when there was only
6860 one printer - I think we should now only accept it if they
6861 get it right (tridge) */
6862 if (!CAN_PRINT(conn)) {
6863 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6864 END_PROFILE(SMBsplretq);
6865 return;
6868 reply_outbuf(req, 2, 3);
6869 SSVAL(req->outbuf,smb_vwv0,0);
6870 SSVAL(req->outbuf,smb_vwv1,0);
6871 SCVAL(smb_buf(req->outbuf),0,1);
6872 SSVAL(smb_buf(req->outbuf),1,0);
6874 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
6875 start_index, max_count));
6878 TALLOC_CTX *mem_ctx = talloc_tos();
6879 NTSTATUS status;
6880 WERROR werr;
6881 const char *sharename = lp_servicename(mem_ctx, lp_sub, SNUM(conn));
6882 struct rpc_pipe_client *cli = NULL;
6883 struct dcerpc_binding_handle *b = NULL;
6884 struct policy_handle handle;
6885 struct spoolss_DevmodeContainer devmode_ctr;
6886 union spoolss_JobInfo *info;
6887 uint32_t count;
6888 uint32_t num_to_get;
6889 uint32_t first;
6890 uint32_t i;
6892 ZERO_STRUCT(handle);
6894 status = rpc_pipe_open_interface(mem_ctx,
6895 &ndr_table_spoolss,
6896 conn->session_info,
6897 conn->sconn->remote_address,
6898 conn->sconn->local_address,
6899 conn->sconn->msg_ctx,
6900 &cli);
6901 if (!NT_STATUS_IS_OK(status)) {
6902 DEBUG(0, ("reply_printqueue: "
6903 "could not connect to spoolss: %s\n",
6904 nt_errstr(status)));
6905 reply_nterror(req, status);
6906 goto out;
6908 b = cli->binding_handle;
6910 ZERO_STRUCT(devmode_ctr);
6912 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
6913 sharename,
6914 NULL, devmode_ctr,
6915 SEC_FLAG_MAXIMUM_ALLOWED,
6916 &handle,
6917 &werr);
6918 if (!NT_STATUS_IS_OK(status)) {
6919 reply_nterror(req, status);
6920 goto out;
6922 if (!W_ERROR_IS_OK(werr)) {
6923 reply_nterror(req, werror_to_ntstatus(werr));
6924 goto out;
6927 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6928 &handle,
6929 0, /* firstjob */
6930 0xff, /* numjobs */
6931 2, /* level */
6932 0, /* offered */
6933 &count,
6934 &info);
6935 if (!W_ERROR_IS_OK(werr)) {
6936 reply_nterror(req, werror_to_ntstatus(werr));
6937 goto out;
6940 if (max_count > 0) {
6941 first = start_index;
6942 } else {
6943 first = start_index + max_count + 1;
6946 if (first >= count) {
6947 num_to_get = first;
6948 } else {
6949 num_to_get = first + MIN(ABS(max_count), count - first);
6952 for (i = first; i < num_to_get; i++) {
6953 char blob[28];
6954 char *p = blob;
6955 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6956 int qstatus;
6957 size_t len = 0;
6958 uint16_t qrapjobid = pjobid_to_rap(sharename,
6959 info[i].info2.job_id);
6961 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6962 qstatus = 2;
6963 } else {
6964 qstatus = 3;
6967 srv_put_dos_date2(p, 0, qtime);
6968 SCVAL(p, 4, qstatus);
6969 SSVAL(p, 5, qrapjobid);
6970 SIVAL(p, 7, info[i].info2.size);
6971 SCVAL(p, 11, 0);
6972 status = srvstr_push(blob, req->flags2, p+12,
6973 info[i].info2.notify_name, 16, STR_ASCII, &len);
6974 if (!NT_STATUS_IS_OK(status)) {
6975 reply_nterror(req, status);
6976 goto out;
6978 if (message_push_blob(
6979 &req->outbuf,
6980 data_blob_const(
6981 blob, sizeof(blob))) == -1) {
6982 reply_nterror(req, NT_STATUS_NO_MEMORY);
6983 goto out;
6987 if (count > 0) {
6988 SSVAL(req->outbuf,smb_vwv0,count);
6989 SSVAL(req->outbuf,smb_vwv1,
6990 (max_count>0?first+count:first-1));
6991 SCVAL(smb_buf(req->outbuf),0,1);
6992 SSVAL(smb_buf(req->outbuf),1,28*count);
6996 DEBUG(3, ("%u entries returned in queue\n",
6997 (unsigned)count));
6999 out:
7000 if (b && is_valid_policy_hnd(&handle)) {
7001 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
7006 END_PROFILE(SMBsplretq);
7007 return;
7010 /****************************************************************************
7011 Reply to a printwrite.
7012 ****************************************************************************/
7014 void reply_printwrite(struct smb_request *req)
7016 connection_struct *conn = req->conn;
7017 int numtowrite;
7018 const char *data;
7019 files_struct *fsp;
7021 START_PROFILE(SMBsplwr);
7023 if (req->wct < 1) {
7024 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7025 END_PROFILE(SMBsplwr);
7026 return;
7029 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7031 if (!check_fsp(conn, req, fsp)) {
7032 END_PROFILE(SMBsplwr);
7033 return;
7036 if (!fsp->print_file) {
7037 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7038 END_PROFILE(SMBsplwr);
7039 return;
7042 if (!CHECK_WRITE(fsp)) {
7043 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7044 END_PROFILE(SMBsplwr);
7045 return;
7048 numtowrite = SVAL(req->buf, 1);
7051 * This already protects us against CVE-2017-12163.
7053 if (req->buflen < numtowrite + 3) {
7054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7055 END_PROFILE(SMBsplwr);
7056 return;
7059 data = (const char *)req->buf + 3;
7061 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
7062 reply_nterror(req, map_nt_error_from_unix(errno));
7063 END_PROFILE(SMBsplwr);
7064 return;
7067 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
7069 reply_outbuf(req, 0, 0);
7071 END_PROFILE(SMBsplwr);
7072 return;
7075 /****************************************************************************
7076 Reply to a mkdir.
7077 ****************************************************************************/
7079 void reply_mkdir(struct smb_request *req)
7081 connection_struct *conn = req->conn;
7082 struct smb_filename *smb_dname = NULL;
7083 char *directory = NULL;
7084 NTSTATUS status;
7085 uint32_t ucf_flags;
7086 TALLOC_CTX *ctx = talloc_tos();
7088 START_PROFILE(SMBmkdir);
7090 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
7091 STR_TERMINATE, &status);
7092 if (!NT_STATUS_IS_OK(status)) {
7093 reply_nterror(req, status);
7094 goto out;
7097 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
7098 status = filename_convert(ctx, conn,
7099 directory,
7100 ucf_flags,
7102 &smb_dname);
7103 if (!NT_STATUS_IS_OK(status)) {
7104 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7105 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7106 ERRSRV, ERRbadpath);
7107 goto out;
7109 reply_nterror(req, status);
7110 goto out;
7113 status = create_directory(conn, req, smb_dname);
7115 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
7117 if (!NT_STATUS_IS_OK(status)) {
7119 if (!use_nt_status()
7120 && NT_STATUS_EQUAL(status,
7121 NT_STATUS_OBJECT_NAME_COLLISION)) {
7123 * Yes, in the DOS error code case we get a
7124 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
7125 * samba4 torture test.
7127 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
7130 reply_nterror(req, status);
7131 goto out;
7134 reply_outbuf(req, 0, 0);
7136 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
7137 out:
7138 TALLOC_FREE(smb_dname);
7139 END_PROFILE(SMBmkdir);
7140 return;
7143 /****************************************************************************
7144 Reply to a rmdir.
7145 ****************************************************************************/
7147 void reply_rmdir(struct smb_request *req)
7149 connection_struct *conn = req->conn;
7150 struct smb_filename *smb_dname = NULL;
7151 char *directory = NULL;
7152 NTSTATUS status;
7153 TALLOC_CTX *ctx = talloc_tos();
7154 files_struct *fsp = NULL;
7155 int info = 0;
7156 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
7158 START_PROFILE(SMBrmdir);
7160 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
7161 STR_TERMINATE, &status);
7162 if (!NT_STATUS_IS_OK(status)) {
7163 reply_nterror(req, status);
7164 goto out;
7167 status = filename_convert(ctx, conn,
7168 directory,
7169 ucf_flags,
7171 &smb_dname);
7172 if (!NT_STATUS_IS_OK(status)) {
7173 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7174 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7175 ERRSRV, ERRbadpath);
7176 goto out;
7178 reply_nterror(req, status);
7179 goto out;
7182 if (is_ntfs_stream_smb_fname(smb_dname)) {
7183 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
7184 goto out;
7187 status = SMB_VFS_CREATE_FILE(
7188 conn, /* conn */
7189 req, /* req */
7190 smb_dname, /* fname */
7191 DELETE_ACCESS, /* access_mask */
7192 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7193 FILE_SHARE_DELETE),
7194 FILE_OPEN, /* create_disposition*/
7195 FILE_DIRECTORY_FILE, /* create_options */
7196 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
7197 0, /* oplock_request */
7198 NULL, /* lease */
7199 0, /* allocation_size */
7200 0, /* private_flags */
7201 NULL, /* sd */
7202 NULL, /* ea_list */
7203 &fsp, /* result */
7204 &info, /* pinfo */
7205 NULL, NULL); /* create context */
7207 if (!NT_STATUS_IS_OK(status)) {
7208 if (open_was_deferred(req->xconn, req->mid)) {
7209 /* We have re-scheduled this call. */
7210 goto out;
7212 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
7213 bool ok = defer_smb1_sharing_violation(req);
7214 if (ok) {
7215 goto out;
7218 reply_nterror(req, status);
7219 goto out;
7222 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
7223 if (!NT_STATUS_IS_OK(status)) {
7224 close_file(req, fsp, ERROR_CLOSE);
7225 reply_nterror(req, status);
7226 goto out;
7229 if (!set_delete_on_close(fsp, true,
7230 conn->session_info->security_token,
7231 conn->session_info->unix_token)) {
7232 close_file(req, fsp, ERROR_CLOSE);
7233 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7234 goto out;
7237 status = close_file(req, fsp, NORMAL_CLOSE);
7238 if (!NT_STATUS_IS_OK(status)) {
7239 reply_nterror(req, status);
7240 } else {
7241 reply_outbuf(req, 0, 0);
7244 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
7245 out:
7246 TALLOC_FREE(smb_dname);
7247 END_PROFILE(SMBrmdir);
7248 return;
7251 /*******************************************************************
7252 Resolve wildcards in a filename rename.
7253 ********************************************************************/
7255 static bool resolve_wildcards(TALLOC_CTX *ctx,
7256 const char *name1,
7257 const char *name2,
7258 char **pp_newname)
7260 char *name2_copy = NULL;
7261 char *root1 = NULL;
7262 char *root2 = NULL;
7263 char *ext1 = NULL;
7264 char *ext2 = NULL;
7265 char *p,*p2, *pname1, *pname2;
7267 name2_copy = talloc_strdup(ctx, name2);
7268 if (!name2_copy) {
7269 return False;
7272 pname1 = strrchr_m(name1,'/');
7273 pname2 = strrchr_m(name2_copy,'/');
7275 if (!pname1 || !pname2) {
7276 return False;
7279 /* Truncate the copy of name2 at the last '/' */
7280 *pname2 = '\0';
7282 /* Now go past the '/' */
7283 pname1++;
7284 pname2++;
7286 root1 = talloc_strdup(ctx, pname1);
7287 root2 = talloc_strdup(ctx, pname2);
7289 if (!root1 || !root2) {
7290 return False;
7293 p = strrchr_m(root1,'.');
7294 if (p) {
7295 *p = 0;
7296 ext1 = talloc_strdup(ctx, p+1);
7297 } else {
7298 ext1 = talloc_strdup(ctx, "");
7300 p = strrchr_m(root2,'.');
7301 if (p) {
7302 *p = 0;
7303 ext2 = talloc_strdup(ctx, p+1);
7304 } else {
7305 ext2 = talloc_strdup(ctx, "");
7308 if (!ext1 || !ext2) {
7309 return False;
7312 p = root1;
7313 p2 = root2;
7314 while (*p2) {
7315 if (*p2 == '?') {
7316 /* Hmmm. Should this be mb-aware ? */
7317 *p2 = *p;
7318 p2++;
7319 } else if (*p2 == '*') {
7320 *p2 = '\0';
7321 root2 = talloc_asprintf(ctx, "%s%s",
7322 root2,
7324 if (!root2) {
7325 return False;
7327 break;
7328 } else {
7329 p2++;
7331 if (*p) {
7332 p++;
7336 p = ext1;
7337 p2 = ext2;
7338 while (*p2) {
7339 if (*p2 == '?') {
7340 /* Hmmm. Should this be mb-aware ? */
7341 *p2 = *p;
7342 p2++;
7343 } else if (*p2 == '*') {
7344 *p2 = '\0';
7345 ext2 = talloc_asprintf(ctx, "%s%s",
7346 ext2,
7348 if (!ext2) {
7349 return False;
7351 break;
7352 } else {
7353 p2++;
7355 if (*p) {
7356 p++;
7360 if (*ext2) {
7361 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
7362 name2_copy,
7363 root2,
7364 ext2);
7365 } else {
7366 *pp_newname = talloc_asprintf(ctx, "%s/%s",
7367 name2_copy,
7368 root2);
7371 if (!*pp_newname) {
7372 return False;
7375 return True;
7378 /****************************************************************************
7379 Ensure open files have their names updated. Updated to notify other smbd's
7380 asynchronously.
7381 ****************************************************************************/
7383 static void rename_open_files(connection_struct *conn,
7384 struct share_mode_lock *lck,
7385 struct file_id id,
7386 uint32_t orig_name_hash,
7387 const struct smb_filename *smb_fname_dst)
7389 files_struct *fsp;
7390 bool did_rename = False;
7391 NTSTATUS status;
7392 uint32_t new_name_hash = 0;
7394 for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
7395 fsp = file_find_di_next(fsp, false)) {
7396 struct file_id_buf idbuf;
7397 /* fsp_name is a relative path under the fsp. To change this for other
7398 sharepaths we need to manipulate relative paths. */
7399 /* TODO - create the absolute path and manipulate the newname
7400 relative to the sharepath. */
7401 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
7402 continue;
7404 if (fsp->name_hash != orig_name_hash) {
7405 continue;
7407 DBG_DEBUG("renaming file %s "
7408 "(file_id %s) from %s -> %s\n",
7409 fsp_fnum_dbg(fsp),
7410 file_id_str_buf(fsp->file_id, &idbuf),
7411 fsp_str_dbg(fsp),
7412 smb_fname_str_dbg(smb_fname_dst));
7414 status = fsp_set_smb_fname(fsp, smb_fname_dst);
7415 if (NT_STATUS_IS_OK(status)) {
7416 did_rename = True;
7417 new_name_hash = fsp->name_hash;
7421 if (!did_rename) {
7422 struct file_id_buf idbuf;
7423 DBG_DEBUG("no open files on file_id %s "
7424 "for %s\n",
7425 file_id_str_buf(id, &idbuf),
7426 smb_fname_str_dbg(smb_fname_dst));
7429 /* Send messages to all smbd's (not ourself) that the name has changed. */
7430 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
7431 orig_name_hash, new_name_hash,
7432 smb_fname_dst);
7436 /****************************************************************************
7437 We need to check if the source path is a parent directory of the destination
7438 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
7439 refuse the rename with a sharing violation. Under UNIX the above call can
7440 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
7441 probably need to check that the client is a Windows one before disallowing
7442 this as a UNIX client (one with UNIX extensions) can know the source is a
7443 symlink and make this decision intelligently. Found by an excellent bug
7444 report from <AndyLiebman@aol.com>.
7445 ****************************************************************************/
7447 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
7448 const struct smb_filename *smb_fname_dst)
7450 const char *psrc = smb_fname_src->base_name;
7451 const char *pdst = smb_fname_dst->base_name;
7452 size_t slen;
7454 if (psrc[0] == '.' && psrc[1] == '/') {
7455 psrc += 2;
7457 if (pdst[0] == '.' && pdst[1] == '/') {
7458 pdst += 2;
7460 if ((slen = strlen(psrc)) > strlen(pdst)) {
7461 return False;
7463 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
7467 * Do the notify calls from a rename
7470 static void notify_rename(connection_struct *conn, bool is_dir,
7471 const struct smb_filename *smb_fname_src,
7472 const struct smb_filename *smb_fname_dst)
7474 char *parent_dir_src = NULL;
7475 char *parent_dir_dst = NULL;
7476 uint32_t mask;
7478 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
7479 : FILE_NOTIFY_CHANGE_FILE_NAME;
7481 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
7482 &parent_dir_src, NULL) ||
7483 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
7484 &parent_dir_dst, NULL)) {
7485 goto out;
7488 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
7489 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
7490 smb_fname_src->base_name);
7491 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
7492 smb_fname_dst->base_name);
7494 else {
7495 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
7496 smb_fname_src->base_name);
7497 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
7498 smb_fname_dst->base_name);
7501 /* this is a strange one. w2k3 gives an additional event for
7502 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
7503 files, but not directories */
7504 if (!is_dir) {
7505 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
7506 FILE_NOTIFY_CHANGE_ATTRIBUTES
7507 |FILE_NOTIFY_CHANGE_CREATION,
7508 smb_fname_dst->base_name);
7510 out:
7511 TALLOC_FREE(parent_dir_src);
7512 TALLOC_FREE(parent_dir_dst);
7515 /****************************************************************************
7516 Returns an error if the parent directory for a filename is open in an
7517 incompatible way.
7518 ****************************************************************************/
7520 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
7521 const struct smb_filename *smb_fname_dst_in)
7523 struct smb_filename *smb_fname_parent = NULL;
7524 struct file_id id;
7525 files_struct *fsp = NULL;
7526 int ret;
7527 NTSTATUS status;
7529 status = SMB_VFS_PARENT_PATHNAME(conn,
7530 talloc_tos(),
7531 smb_fname_dst_in,
7532 &smb_fname_parent,
7533 NULL);
7534 if (!NT_STATUS_IS_OK(status)) {
7535 return status;
7538 ret = SMB_VFS_LSTAT(conn, smb_fname_parent);
7539 if (ret == -1) {
7540 return map_nt_error_from_unix(errno);
7544 * We're only checking on this smbd here, mostly good
7545 * enough.. and will pass tests.
7548 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
7549 for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
7550 fsp = file_find_di_next(fsp, true)) {
7551 if (fsp->access_mask & DELETE_ACCESS) {
7552 return NT_STATUS_SHARING_VIOLATION;
7555 return NT_STATUS_OK;
7558 /****************************************************************************
7559 Rename an open file - given an fsp.
7560 ****************************************************************************/
7562 NTSTATUS rename_internals_fsp(connection_struct *conn,
7563 files_struct *fsp,
7564 struct smb_filename *smb_fname_dst_in,
7565 const char *dst_original_lcomp,
7566 uint32_t attrs,
7567 bool replace_if_exists)
7569 TALLOC_CTX *ctx = talloc_tos();
7570 struct smb_filename *parent_dir_fname_dst = NULL;
7571 struct smb_filename *parent_dir_fname_dst_atname = NULL;
7572 struct smb_filename *smb_fname_dst = NULL;
7573 NTSTATUS status = NT_STATUS_OK;
7574 struct share_mode_lock *lck = NULL;
7575 uint32_t access_mask = SEC_DIR_ADD_FILE;
7576 bool dst_exists, old_is_stream, new_is_stream;
7577 int ret;
7579 status = check_name(conn, smb_fname_dst_in);
7580 if (!NT_STATUS_IS_OK(status)) {
7581 return status;
7584 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
7585 if (!NT_STATUS_IS_OK(status)) {
7586 return status;
7589 if (file_has_open_streams(fsp)) {
7590 return NT_STATUS_ACCESS_DENIED;
7593 /* Make a copy of the dst smb_fname structs */
7595 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
7596 if (smb_fname_dst == NULL) {
7597 status = NT_STATUS_NO_MEMORY;
7598 goto out;
7602 * Check for special case with case preserving and not
7603 * case sensitive. If the new last component differs from the original
7604 * last component only by case, then we should allow
7605 * the rename (user is trying to change the case of the
7606 * filename).
7608 if (!conn->case_sensitive && conn->case_preserve &&
7609 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7610 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
7611 char *fname_dst_parent = NULL;
7612 const char *fname_dst_lcomp = NULL;
7613 char *orig_lcomp_path = NULL;
7614 char *orig_lcomp_stream = NULL;
7615 bool ok = true;
7618 * Split off the last component of the processed
7619 * destination name. We will compare this to
7620 * the split components of dst_original_lcomp.
7622 if (!parent_dirname(ctx,
7623 smb_fname_dst->base_name,
7624 &fname_dst_parent,
7625 &fname_dst_lcomp)) {
7626 status = NT_STATUS_NO_MEMORY;
7627 goto out;
7631 * The dst_original_lcomp component contains
7632 * the last_component of the path + stream
7633 * name (if a stream exists).
7635 * Split off the stream name so we
7636 * can check them separately.
7639 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
7640 /* POSIX - no stream component. */
7641 orig_lcomp_path = talloc_strdup(ctx,
7642 dst_original_lcomp);
7643 if (orig_lcomp_path == NULL) {
7644 ok = false;
7646 } else {
7647 ok = split_stream_filename(ctx,
7648 dst_original_lcomp,
7649 &orig_lcomp_path,
7650 &orig_lcomp_stream);
7653 if (!ok) {
7654 TALLOC_FREE(fname_dst_parent);
7655 status = NT_STATUS_NO_MEMORY;
7656 goto out;
7659 /* If the base names only differ by case, use original. */
7660 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
7661 char *tmp;
7663 * Replace the modified last component with the
7664 * original.
7666 if (!ISDOT(fname_dst_parent)) {
7667 tmp = talloc_asprintf(smb_fname_dst,
7668 "%s/%s",
7669 fname_dst_parent,
7670 orig_lcomp_path);
7671 } else {
7672 tmp = talloc_strdup(smb_fname_dst,
7673 orig_lcomp_path);
7675 if (tmp == NULL) {
7676 status = NT_STATUS_NO_MEMORY;
7677 TALLOC_FREE(fname_dst_parent);
7678 TALLOC_FREE(orig_lcomp_path);
7679 TALLOC_FREE(orig_lcomp_stream);
7680 goto out;
7682 TALLOC_FREE(smb_fname_dst->base_name);
7683 smb_fname_dst->base_name = tmp;
7686 /* If the stream_names only differ by case, use original. */
7687 if(!strcsequal(smb_fname_dst->stream_name,
7688 orig_lcomp_stream)) {
7689 /* Use the original stream. */
7690 char *tmp = talloc_strdup(smb_fname_dst,
7691 orig_lcomp_stream);
7692 if (tmp == NULL) {
7693 status = NT_STATUS_NO_MEMORY;
7694 TALLOC_FREE(fname_dst_parent);
7695 TALLOC_FREE(orig_lcomp_path);
7696 TALLOC_FREE(orig_lcomp_stream);
7697 goto out;
7699 TALLOC_FREE(smb_fname_dst->stream_name);
7700 smb_fname_dst->stream_name = tmp;
7702 TALLOC_FREE(fname_dst_parent);
7703 TALLOC_FREE(orig_lcomp_path);
7704 TALLOC_FREE(orig_lcomp_stream);
7708 * If the src and dest names are identical - including case,
7709 * don't do the rename, just return success.
7712 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7713 strcsequal(fsp->fsp_name->stream_name,
7714 smb_fname_dst->stream_name)) {
7715 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
7716 "- returning success\n",
7717 smb_fname_str_dbg(smb_fname_dst)));
7718 status = NT_STATUS_OK;
7719 goto out;
7722 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
7723 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
7725 /* Return the correct error code if both names aren't streams. */
7726 if (!old_is_stream && new_is_stream) {
7727 status = NT_STATUS_OBJECT_NAME_INVALID;
7728 goto out;
7731 if (old_is_stream && !new_is_stream) {
7732 status = NT_STATUS_INVALID_PARAMETER;
7733 goto out;
7736 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
7738 if(!replace_if_exists && dst_exists) {
7739 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
7740 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7741 smb_fname_str_dbg(smb_fname_dst)));
7742 status = NT_STATUS_OBJECT_NAME_COLLISION;
7743 goto out;
7747 * Drop the pathref fsp on the destination otherwise we trip upon in in
7748 * the below check for open files check.
7750 if (smb_fname_dst_in->fsp != NULL) {
7751 fd_close(smb_fname_dst_in->fsp);
7752 file_free(NULL, smb_fname_dst_in->fsp);
7753 SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
7756 if (dst_exists) {
7757 struct file_id fileid = vfs_file_id_from_sbuf(conn,
7758 &smb_fname_dst->st);
7759 files_struct *dst_fsp = file_find_di_first(conn->sconn,
7760 fileid, true);
7761 /* The file can be open when renaming a stream */
7762 if (dst_fsp && !new_is_stream) {
7763 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
7764 status = NT_STATUS_ACCESS_DENIED;
7765 goto out;
7769 /* Ensure we have a valid stat struct for the source. */
7770 status = vfs_stat_fsp(fsp);
7771 if (!NT_STATUS_IS_OK(status)) {
7772 goto out;
7775 status = can_rename(conn, fsp, attrs);
7777 if (!NT_STATUS_IS_OK(status)) {
7778 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7779 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7780 smb_fname_str_dbg(smb_fname_dst)));
7781 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
7782 status = NT_STATUS_ACCESS_DENIED;
7783 goto out;
7786 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
7787 status = NT_STATUS_ACCESS_DENIED;
7788 goto out;
7791 /* Do we have rights to move into the destination ? */
7792 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
7793 /* We're moving a directory. */
7794 access_mask = SEC_DIR_ADD_SUBDIR;
7798 * Get a pathref on the parent directory, so
7799 * we can call check_parent_access_fsp().
7801 status = parent_pathref(ctx,
7802 conn->cwd_fsp,
7803 smb_fname_dst,
7804 &parent_dir_fname_dst,
7805 &parent_dir_fname_dst_atname);
7806 if (!NT_STATUS_IS_OK(status)) {
7807 goto out;
7810 status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
7811 access_mask);
7812 if (!NT_STATUS_IS_OK(status)) {
7813 DBG_INFO("check_parent_access_fsp on "
7814 "dst %s returned %s\n",
7815 smb_fname_str_dbg(smb_fname_dst),
7816 nt_errstr(status));
7817 goto out;
7820 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
7823 * We have the file open ourselves, so not being able to get the
7824 * corresponding share mode lock is a fatal error.
7827 SMB_ASSERT(lck != NULL);
7829 ret = SMB_VFS_RENAMEAT(conn,
7830 conn->cwd_fsp,
7831 fsp->fsp_name,
7832 conn->cwd_fsp,
7833 smb_fname_dst);
7834 if (ret == 0) {
7835 uint32_t create_options = fh_get_private_options(fsp->fh);
7837 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
7838 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7839 smb_fname_str_dbg(smb_fname_dst)));
7841 notify_rename(conn,
7842 fsp->fsp_flags.is_directory,
7843 fsp->fsp_name,
7844 smb_fname_dst);
7846 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
7847 smb_fname_dst);
7849 if (!fsp->fsp_flags.is_directory &&
7850 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
7851 (lp_map_archive(SNUM(conn)) ||
7852 lp_store_dos_attributes(SNUM(conn))))
7855 * We must set the archive bit on the newly renamed
7856 * file.
7858 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
7859 if (ret == 0) {
7860 uint32_t old_dosmode;
7861 old_dosmode = fdos_mode(fsp);
7863 * We can use fsp->fsp_name here as it has
7864 * already been changed to the new name.
7866 SMB_ASSERT(fsp->fsp_name->fsp == fsp);
7867 file_set_dosmode(conn,
7868 fsp->fsp_name,
7869 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
7870 NULL,
7871 true);
7876 * A rename acts as a new file create w.r.t. allowing an initial delete
7877 * on close, probably because in Windows there is a new handle to the
7878 * new file. If initial delete on close was requested but not
7879 * originally set, we need to set it here. This is probably not 100% correct,
7880 * but will work for the CIFSFS client which in non-posix mode
7881 * depends on these semantics. JRA.
7884 if (create_options & FILE_DELETE_ON_CLOSE) {
7885 status = can_set_delete_on_close(fsp, 0);
7887 if (NT_STATUS_IS_OK(status)) {
7888 /* Note that here we set the *initial* delete on close flag,
7889 * not the regular one. The magic gets handled in close. */
7890 fsp->fsp_flags.initial_delete_on_close = true;
7893 TALLOC_FREE(lck);
7894 status = NT_STATUS_OK;
7895 goto out;
7898 TALLOC_FREE(lck);
7900 if (errno == ENOTDIR || errno == EISDIR) {
7901 status = NT_STATUS_OBJECT_NAME_COLLISION;
7902 } else {
7903 status = map_nt_error_from_unix(errno);
7906 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7907 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7908 smb_fname_str_dbg(smb_fname_dst)));
7910 out:
7911 TALLOC_FREE(smb_fname_dst);
7913 return status;
7916 /****************************************************************************
7917 The guts of the rename command, split out so it may be called by the NT SMB
7918 code.
7919 ****************************************************************************/
7921 NTSTATUS rename_internals(TALLOC_CTX *ctx,
7922 connection_struct *conn,
7923 struct smb_request *req,
7924 struct smb_filename *smb_fname_src,
7925 const char *src_original_lcomp,
7926 struct smb_filename *smb_fname_dst,
7927 const char *dst_original_lcomp,
7928 uint32_t attrs,
7929 bool replace_if_exists,
7930 uint32_t access_mask)
7932 char *fname_src_dir = NULL;
7933 struct smb_filename *smb_fname_src_dir = NULL;
7934 char *fname_src_mask = NULL;
7935 int count=0;
7936 NTSTATUS status = NT_STATUS_OK;
7937 struct smb_Dir *dir_hnd = NULL;
7938 const char *dname = NULL;
7939 char *talloced = NULL;
7940 long offset = 0;
7941 int create_options = 0;
7942 struct smb2_create_blobs *posx = NULL;
7943 int rc;
7944 bool src_has_wild = false;
7945 bool dest_has_wild = false;
7948 * Split the old name into directory and last component
7949 * strings. Note that unix_convert may have stripped off a
7950 * leading ./ from both name and newname if the rename is
7951 * at the root of the share. We need to make sure either both
7952 * name and newname contain a / character or neither of them do
7953 * as this is checked in resolve_wildcards().
7956 /* Split up the directory from the filename/mask. */
7957 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7958 &fname_src_dir, &fname_src_mask);
7959 if (!NT_STATUS_IS_OK(status)) {
7960 status = NT_STATUS_NO_MEMORY;
7961 goto out;
7964 if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
7966 * Check the wildcard mask *before*
7967 * unmangling. As mangling is done
7968 * for names that can't be returned
7969 * to Windows the unmangled name may
7970 * contain Windows wildcard characters.
7972 if (src_original_lcomp != NULL) {
7973 src_has_wild = ms_has_wild(src_original_lcomp);
7975 dest_has_wild = ms_has_wild(dst_original_lcomp);
7979 * We should only check the mangled cache
7980 * here if unix_convert failed. This means
7981 * that the path in 'mask' doesn't exist
7982 * on the file system and so we need to look
7983 * for a possible mangle. This patch from
7984 * Tine Smukavec <valentin.smukavec@hermes.si>.
7987 if (!VALID_STAT(smb_fname_src->st) &&
7988 mangle_is_mangled(fname_src_mask, conn->params)) {
7989 char *new_mask = NULL;
7990 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
7991 conn->params);
7992 if (new_mask) {
7993 TALLOC_FREE(fname_src_mask);
7994 fname_src_mask = new_mask;
7998 if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
7999 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
8000 if (!NT_STATUS_IS_OK(status)) {
8001 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
8002 nt_errstr(status));
8003 goto out;
8007 if (!src_has_wild) {
8008 files_struct *fsp;
8011 * Only one file needs to be renamed. Append the mask back
8012 * onto the directory.
8014 TALLOC_FREE(smb_fname_src->base_name);
8015 if (ISDOT(fname_src_dir)) {
8016 /* Ensure we use canonical names on open. */
8017 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8018 "%s",
8019 fname_src_mask);
8020 } else {
8021 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8022 "%s/%s",
8023 fname_src_dir,
8024 fname_src_mask);
8026 if (!smb_fname_src->base_name) {
8027 status = NT_STATUS_NO_MEMORY;
8028 goto out;
8031 DEBUG(3, ("rename_internals: case_sensitive = %d, "
8032 "case_preserve = %d, short case preserve = %d, "
8033 "directory = %s, newname = %s, "
8034 "last_component_dest = %s\n",
8035 conn->case_sensitive, conn->case_preserve,
8036 conn->short_case_preserve,
8037 smb_fname_str_dbg(smb_fname_src),
8038 smb_fname_str_dbg(smb_fname_dst),
8039 dst_original_lcomp));
8041 /* The dest name still may have wildcards. */
8042 if (dest_has_wild) {
8043 char *fname_dst_mod = NULL;
8044 if (!resolve_wildcards(smb_fname_dst,
8045 smb_fname_src->base_name,
8046 smb_fname_dst->base_name,
8047 &fname_dst_mod)) {
8048 DEBUG(6, ("rename_internals: resolve_wildcards "
8049 "%s %s failed\n",
8050 smb_fname_src->base_name,
8051 smb_fname_dst->base_name));
8052 status = NT_STATUS_NO_MEMORY;
8053 goto out;
8055 TALLOC_FREE(smb_fname_dst->base_name);
8056 smb_fname_dst->base_name = fname_dst_mod;
8059 ZERO_STRUCT(smb_fname_src->st);
8061 rc = vfs_stat(conn, smb_fname_src);
8062 if (rc == -1) {
8063 status = map_nt_error_from_unix_common(errno);
8064 goto out;
8067 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8068 if (!NT_STATUS_IS_OK(status)) {
8069 if (!NT_STATUS_EQUAL(status,
8070 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
8071 goto out;
8074 * Possible symlink src.
8076 if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
8077 goto out;
8079 if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
8080 goto out;
8084 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
8085 create_options |= FILE_DIRECTORY_FILE;
8088 status = SMB_VFS_CREATE_FILE(
8089 conn, /* conn */
8090 req, /* req */
8091 smb_fname_src, /* fname */
8092 access_mask, /* access_mask */
8093 (FILE_SHARE_READ | /* share_access */
8094 FILE_SHARE_WRITE),
8095 FILE_OPEN, /* create_disposition*/
8096 create_options, /* create_options */
8097 0, /* file_attributes */
8098 0, /* oplock_request */
8099 NULL, /* lease */
8100 0, /* allocation_size */
8101 0, /* private_flags */
8102 NULL, /* sd */
8103 NULL, /* ea_list */
8104 &fsp, /* result */
8105 NULL, /* pinfo */
8106 posx, /* in_context_blobs */
8107 NULL); /* out_context_blobs */
8109 if (!NT_STATUS_IS_OK(status)) {
8110 DEBUG(3, ("Could not open rename source %s: %s\n",
8111 smb_fname_str_dbg(smb_fname_src),
8112 nt_errstr(status)));
8113 goto out;
8116 status = rename_internals_fsp(conn,
8117 fsp,
8118 smb_fname_dst,
8119 dst_original_lcomp,
8120 attrs,
8121 replace_if_exists);
8123 close_file(req, fsp, NORMAL_CLOSE);
8125 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
8126 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
8127 smb_fname_str_dbg(smb_fname_dst)));
8129 goto out;
8133 * Wildcards - process each file that matches.
8135 if (strequal(fname_src_mask, "????????.???")) {
8136 TALLOC_FREE(fname_src_mask);
8137 fname_src_mask = talloc_strdup(ctx, "*");
8138 if (!fname_src_mask) {
8139 status = NT_STATUS_NO_MEMORY;
8140 goto out;
8144 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
8145 fname_src_dir,
8146 NULL,
8147 NULL,
8148 smb_fname_src->twrp,
8149 smb_fname_src->flags);
8150 if (smb_fname_src_dir == NULL) {
8151 status = NT_STATUS_NO_MEMORY;
8152 goto out;
8155 status = check_name(conn, smb_fname_src_dir);
8156 if (!NT_STATUS_IS_OK(status)) {
8157 goto out;
8160 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
8161 attrs);
8162 if (dir_hnd == NULL) {
8163 status = map_nt_error_from_unix(errno);
8164 goto out;
8167 status = NT_STATUS_NO_SUCH_FILE;
8169 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
8170 * - gentest fix. JRA
8173 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
8174 &talloced))) {
8175 files_struct *fsp = NULL;
8176 char *destname = NULL;
8177 bool sysdir_entry = False;
8179 /* Quick check for "." and ".." */
8180 if (ISDOT(dname) || ISDOTDOT(dname)) {
8181 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
8182 sysdir_entry = True;
8183 } else {
8184 TALLOC_FREE(talloced);
8185 continue;
8189 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
8190 TALLOC_FREE(talloced);
8191 continue;
8194 if (sysdir_entry) {
8195 status = NT_STATUS_OBJECT_NAME_INVALID;
8196 break;
8199 TALLOC_FREE(smb_fname_src->base_name);
8200 if (ISDOT(fname_src_dir)) {
8201 /* Ensure we use canonical names on open. */
8202 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8203 "%s",
8204 dname);
8205 } else {
8206 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8207 "%s/%s",
8208 fname_src_dir,
8209 dname);
8211 if (!smb_fname_src->base_name) {
8212 status = NT_STATUS_NO_MEMORY;
8213 goto out;
8216 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
8217 smb_fname_dst->base_name,
8218 &destname)) {
8219 DEBUG(6, ("resolve_wildcards %s %s failed\n",
8220 smb_fname_src->base_name, destname));
8221 TALLOC_FREE(talloced);
8222 continue;
8224 if (!destname) {
8225 status = NT_STATUS_NO_MEMORY;
8226 goto out;
8229 TALLOC_FREE(smb_fname_dst->base_name);
8230 smb_fname_dst->base_name = destname;
8232 ZERO_STRUCT(smb_fname_src->st);
8233 vfs_stat(conn, smb_fname_src);
8235 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8236 if (!NT_STATUS_IS_OK(status)) {
8237 DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
8238 smb_fname_str_dbg(smb_fname_src),
8239 nt_errstr(status));
8240 break;
8243 if (!is_visible_fsp(smb_fname_src->fsp)) {
8244 TALLOC_FREE(talloced);
8245 continue;
8248 create_options = 0;
8250 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
8251 create_options |= FILE_DIRECTORY_FILE;
8254 status = SMB_VFS_CREATE_FILE(
8255 conn, /* conn */
8256 req, /* req */
8257 smb_fname_src, /* fname */
8258 access_mask, /* access_mask */
8259 (FILE_SHARE_READ | /* share_access */
8260 FILE_SHARE_WRITE),
8261 FILE_OPEN, /* create_disposition*/
8262 create_options, /* create_options */
8263 0, /* file_attributes */
8264 0, /* oplock_request */
8265 NULL, /* lease */
8266 0, /* allocation_size */
8267 0, /* private_flags */
8268 NULL, /* sd */
8269 NULL, /* ea_list */
8270 &fsp, /* result */
8271 NULL, /* pinfo */
8272 posx, /* in_context_blobs */
8273 NULL); /* out_context_blobs */
8275 if (!NT_STATUS_IS_OK(status)) {
8276 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
8277 "returned %s rename %s -> %s\n",
8278 nt_errstr(status),
8279 smb_fname_str_dbg(smb_fname_src),
8280 smb_fname_str_dbg(smb_fname_dst)));
8281 break;
8284 dst_original_lcomp = talloc_strdup(smb_fname_dst, dname);
8285 if (dst_original_lcomp == NULL) {
8286 status = NT_STATUS_NO_MEMORY;
8287 goto out;
8290 status = rename_internals_fsp(conn,
8291 fsp,
8292 smb_fname_dst,
8293 dst_original_lcomp,
8294 attrs,
8295 replace_if_exists);
8297 close_file(req, fsp, NORMAL_CLOSE);
8299 if (!NT_STATUS_IS_OK(status)) {
8300 DEBUG(3, ("rename_internals_fsp returned %s for "
8301 "rename %s -> %s\n", nt_errstr(status),
8302 smb_fname_str_dbg(smb_fname_src),
8303 smb_fname_str_dbg(smb_fname_dst)));
8304 break;
8307 count++;
8309 DEBUG(3,("rename_internals: doing rename on %s -> "
8310 "%s\n", smb_fname_str_dbg(smb_fname_src),
8311 smb_fname_str_dbg(smb_fname_src)));
8312 TALLOC_FREE(talloced);
8314 TALLOC_FREE(dir_hnd);
8316 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
8317 status = map_nt_error_from_unix(errno);
8320 out:
8321 TALLOC_FREE(posx);
8322 TALLOC_FREE(talloced);
8323 TALLOC_FREE(smb_fname_src_dir);
8324 TALLOC_FREE(fname_src_dir);
8325 TALLOC_FREE(fname_src_mask);
8326 return status;
8329 /****************************************************************************
8330 Reply to a mv.
8331 ****************************************************************************/
8333 void reply_mv(struct smb_request *req)
8335 connection_struct *conn = req->conn;
8336 char *name = NULL;
8337 char *newname = NULL;
8338 const char *p;
8339 uint32_t attrs;
8340 NTSTATUS status;
8341 TALLOC_CTX *ctx = talloc_tos();
8342 struct smb_filename *smb_fname_src = NULL;
8343 const char *src_original_lcomp = NULL;
8344 struct smb_filename *smb_fname_dst = NULL;
8345 const char *dst_original_lcomp = NULL;
8346 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
8347 (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
8348 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
8349 (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
8350 bool stream_rename = false;
8352 START_PROFILE(SMBmv);
8354 if (req->wct < 1) {
8355 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8356 goto out;
8359 attrs = SVAL(req->vwv+0, 0);
8361 p = (const char *)req->buf + 1;
8362 p += srvstr_get_path_req(ctx, req, &name, p, STR_TERMINATE,
8363 &status);
8364 if (!NT_STATUS_IS_OK(status)) {
8365 reply_nterror(req, status);
8366 goto out;
8368 p++;
8369 p += srvstr_get_path_req(ctx, req, &newname, p, STR_TERMINATE,
8370 &status);
8371 if (!NT_STATUS_IS_OK(status)) {
8372 reply_nterror(req, status);
8373 goto out;
8376 if (!req->posix_pathnames) {
8377 /* The newname must begin with a ':' if the
8378 name contains a ':'. */
8379 if (strchr_m(name, ':')) {
8380 if (newname[0] != ':') {
8381 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8382 goto out;
8384 stream_rename = true;
8388 status = filename_convert(ctx,
8389 conn,
8390 name,
8391 src_ucf_flags,
8393 &smb_fname_src);
8395 if (!NT_STATUS_IS_OK(status)) {
8396 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8397 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8398 ERRSRV, ERRbadpath);
8399 goto out;
8401 reply_nterror(req, status);
8402 goto out;
8405 /* Get the last component of the source for rename_internals(). */
8406 src_original_lcomp = get_original_lcomp(ctx,
8407 conn,
8408 name,
8409 dst_ucf_flags);
8410 if (src_original_lcomp == NULL) {
8411 reply_nterror(req, NT_STATUS_NO_MEMORY);
8412 goto out;
8415 status = filename_convert(ctx,
8416 conn,
8417 newname,
8418 dst_ucf_flags,
8420 &smb_fname_dst);
8422 if (!NT_STATUS_IS_OK(status)) {
8423 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8424 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8425 ERRSRV, ERRbadpath);
8426 goto out;
8428 reply_nterror(req, status);
8429 goto out;
8432 /* Get the last component of the destination for rename_internals(). */
8433 dst_original_lcomp = get_original_lcomp(ctx,
8434 conn,
8435 newname,
8436 dst_ucf_flags);
8437 if (dst_original_lcomp == NULL) {
8438 reply_nterror(req, NT_STATUS_NO_MEMORY);
8439 goto out;
8442 if (stream_rename) {
8443 /* smb_fname_dst->base_name must be the same as
8444 smb_fname_src->base_name. */
8445 TALLOC_FREE(smb_fname_dst->base_name);
8446 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
8447 smb_fname_src->base_name);
8448 if (!smb_fname_dst->base_name) {
8449 reply_nterror(req, NT_STATUS_NO_MEMORY);
8450 goto out;
8454 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
8455 smb_fname_str_dbg(smb_fname_dst)));
8457 status = rename_internals(ctx,
8458 conn,
8459 req,
8460 smb_fname_src,
8461 src_original_lcomp,
8462 smb_fname_dst,
8463 dst_original_lcomp,
8464 attrs,
8465 false,
8466 DELETE_ACCESS);
8467 if (!NT_STATUS_IS_OK(status)) {
8468 if (open_was_deferred(req->xconn, req->mid)) {
8469 /* We have re-scheduled this call. */
8470 goto out;
8472 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
8473 bool ok = defer_smb1_sharing_violation(req);
8474 if (ok) {
8475 goto out;
8478 reply_nterror(req, status);
8479 goto out;
8482 reply_outbuf(req, 0, 0);
8483 out:
8484 TALLOC_FREE(smb_fname_src);
8485 TALLOC_FREE(smb_fname_dst);
8486 END_PROFILE(SMBmv);
8487 return;
8490 /*******************************************************************
8491 Copy a file as part of a reply_copy.
8492 ******************************************************************/
8495 * TODO: check error codes on all callers
8498 NTSTATUS copy_file(TALLOC_CTX *ctx,
8499 connection_struct *conn,
8500 struct smb_filename *smb_fname_src,
8501 struct smb_filename *smb_fname_dst,
8502 int ofun,
8503 int count,
8504 bool target_is_directory)
8506 struct smb_filename *smb_fname_dst_tmp = NULL;
8507 off_t ret=-1;
8508 files_struct *fsp1,*fsp2;
8509 uint32_t dosattrs;
8510 uint32_t new_create_disposition;
8511 NTSTATUS status;
8514 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
8515 if (smb_fname_dst_tmp == NULL) {
8516 return NT_STATUS_NO_MEMORY;
8520 * If the target is a directory, extract the last component from the
8521 * src filename and append it to the dst filename
8523 if (target_is_directory) {
8524 const char *p;
8526 /* dest/target can't be a stream if it's a directory. */
8527 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
8529 p = strrchr_m(smb_fname_src->base_name,'/');
8530 if (p) {
8531 p++;
8532 } else {
8533 p = smb_fname_src->base_name;
8535 smb_fname_dst_tmp->base_name =
8536 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
8538 if (!smb_fname_dst_tmp->base_name) {
8539 status = NT_STATUS_NO_MEMORY;
8540 goto out;
8544 status = vfs_file_exist(conn, smb_fname_src);
8545 if (!NT_STATUS_IS_OK(status)) {
8546 goto out;
8549 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
8550 if (!NT_STATUS_IS_OK(status)) {
8551 goto out;
8554 if (!target_is_directory && count) {
8555 new_create_disposition = FILE_OPEN;
8556 } else {
8557 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
8558 0, ofun,
8559 NULL, NULL,
8560 &new_create_disposition,
8561 NULL,
8562 NULL)) {
8563 status = NT_STATUS_INVALID_PARAMETER;
8564 goto out;
8568 /* Open the src file for reading. */
8569 status = SMB_VFS_CREATE_FILE(
8570 conn, /* conn */
8571 NULL, /* req */
8572 smb_fname_src, /* fname */
8573 FILE_GENERIC_READ, /* access_mask */
8574 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
8575 FILE_OPEN, /* create_disposition*/
8576 0, /* create_options */
8577 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
8578 INTERNAL_OPEN_ONLY, /* oplock_request */
8579 NULL, /* lease */
8580 0, /* allocation_size */
8581 0, /* private_flags */
8582 NULL, /* sd */
8583 NULL, /* ea_list */
8584 &fsp1, /* result */
8585 NULL, /* psbuf */
8586 NULL, NULL); /* create context */
8588 if (!NT_STATUS_IS_OK(status)) {
8589 goto out;
8592 dosattrs = fdos_mode(fsp1);
8594 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
8595 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
8598 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
8599 if (!NT_STATUS_IS_OK(status) &&
8600 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
8602 goto out;
8605 /* Open the dst file for writing. */
8606 status = SMB_VFS_CREATE_FILE(
8607 conn, /* conn */
8608 NULL, /* req */
8609 smb_fname_dst, /* fname */
8610 FILE_GENERIC_WRITE, /* access_mask */
8611 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
8612 new_create_disposition, /* create_disposition*/
8613 0, /* create_options */
8614 dosattrs, /* file_attributes */
8615 INTERNAL_OPEN_ONLY, /* oplock_request */
8616 NULL, /* lease */
8617 0, /* allocation_size */
8618 0, /* private_flags */
8619 NULL, /* sd */
8620 NULL, /* ea_list */
8621 &fsp2, /* result */
8622 NULL, /* psbuf */
8623 NULL, NULL); /* create context */
8625 if (!NT_STATUS_IS_OK(status)) {
8626 close_file(NULL, fsp1, ERROR_CLOSE);
8627 goto out;
8630 if (ofun & OPENX_FILE_EXISTS_OPEN) {
8631 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
8632 if (ret == -1) {
8633 DEBUG(0, ("error - vfs lseek returned error %s\n",
8634 strerror(errno)));
8635 status = map_nt_error_from_unix(errno);
8636 close_file(NULL, fsp1, ERROR_CLOSE);
8637 close_file(NULL, fsp2, ERROR_CLOSE);
8638 goto out;
8642 /* Do the actual copy. */
8643 if (smb_fname_src->st.st_ex_size) {
8644 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
8645 } else {
8646 ret = 0;
8649 close_file(NULL, fsp1, NORMAL_CLOSE);
8651 /* Ensure the modtime is set correctly on the destination file. */
8652 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
8655 * As we are opening fsp1 read-only we only expect
8656 * an error on close on fsp2 if we are out of space.
8657 * Thus we don't look at the error return from the
8658 * close of fsp1.
8660 status = close_file(NULL, fsp2, NORMAL_CLOSE);
8662 if (!NT_STATUS_IS_OK(status)) {
8663 goto out;
8666 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
8667 status = NT_STATUS_DISK_FULL;
8668 goto out;
8671 status = NT_STATUS_OK;
8673 out:
8674 TALLOC_FREE(smb_fname_dst_tmp);
8675 return status;
8678 /****************************************************************************
8679 Reply to a file copy.
8680 ****************************************************************************/
8682 void reply_copy(struct smb_request *req)
8684 connection_struct *conn = req->conn;
8685 struct smb_filename *smb_fname_src = NULL;
8686 struct smb_filename *smb_fname_src_dir = NULL;
8687 struct smb_filename *smb_fname_dst = NULL;
8688 char *fname_src = NULL;
8689 char *fname_dst = NULL;
8690 char *fname_src_mask = NULL;
8691 char *fname_src_dir = NULL;
8692 const char *p;
8693 int count=0;
8694 int error = ERRnoaccess;
8695 int tid2;
8696 int ofun;
8697 int flags;
8698 bool target_is_directory=False;
8699 bool source_has_wild = False;
8700 bool dest_has_wild = False;
8701 NTSTATUS status;
8702 uint32_t ucf_flags_src = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
8703 ucf_flags_from_smb_request(req);
8704 uint32_t ucf_flags_dst = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
8705 ucf_flags_from_smb_request(req);
8706 TALLOC_CTX *ctx = talloc_tos();
8708 START_PROFILE(SMBcopy);
8710 if (req->wct < 3) {
8711 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8712 goto out;
8715 tid2 = SVAL(req->vwv+0, 0);
8716 ofun = SVAL(req->vwv+1, 0);
8717 flags = SVAL(req->vwv+2, 0);
8719 p = (const char *)req->buf;
8720 p += srvstr_get_path_req(ctx, req, &fname_src, p, STR_TERMINATE,
8721 &status);
8722 if (!NT_STATUS_IS_OK(status)) {
8723 reply_nterror(req, status);
8724 goto out;
8726 p += srvstr_get_path_req(ctx, req, &fname_dst, p, STR_TERMINATE,
8727 &status);
8728 if (!NT_STATUS_IS_OK(status)) {
8729 reply_nterror(req, status);
8730 goto out;
8733 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
8735 if (tid2 != conn->cnum) {
8736 /* can't currently handle inter share copies XXXX */
8737 DEBUG(3,("Rejecting inter-share copy\n"));
8738 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
8739 goto out;
8742 status = filename_convert(ctx, conn,
8743 fname_src,
8744 ucf_flags_src,
8746 &smb_fname_src);
8747 if (!NT_STATUS_IS_OK(status)) {
8748 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8749 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8750 ERRSRV, ERRbadpath);
8751 goto out;
8753 reply_nterror(req, status);
8754 goto out;
8757 status = filename_convert(ctx, conn,
8758 fname_dst,
8759 ucf_flags_dst,
8761 &smb_fname_dst);
8762 if (!NT_STATUS_IS_OK(status)) {
8763 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8764 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8765 ERRSRV, ERRbadpath);
8766 goto out;
8768 reply_nterror(req, status);
8769 goto out;
8772 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
8774 if ((flags&1) && target_is_directory) {
8775 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
8776 goto out;
8779 if ((flags&2) && !target_is_directory) {
8780 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
8781 goto out;
8784 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
8785 /* wants a tree copy! XXXX */
8786 DEBUG(3,("Rejecting tree copy\n"));
8787 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8788 goto out;
8791 /* Split up the directory from the filename/mask. */
8792 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
8793 &fname_src_dir, &fname_src_mask);
8794 if (!NT_STATUS_IS_OK(status)) {
8795 reply_nterror(req, NT_STATUS_NO_MEMORY);
8796 goto out;
8799 if (!req->posix_pathnames) {
8800 char *orig_src_lcomp = NULL;
8801 char *orig_dst_lcomp = NULL;
8803 * Check the wildcard mask *before*
8804 * unmangling. As mangling is done
8805 * for names that can't be returned
8806 * to Windows the unmangled name may
8807 * contain Windows wildcard characters.
8809 orig_src_lcomp = get_original_lcomp(ctx,
8810 conn,
8811 fname_src,
8812 ucf_flags_src);
8813 if (orig_src_lcomp == NULL) {
8814 reply_nterror(req, NT_STATUS_NO_MEMORY);
8815 goto out;
8817 orig_dst_lcomp = get_original_lcomp(ctx,
8818 conn,
8819 fname_dst,
8820 ucf_flags_dst);
8821 if (orig_dst_lcomp == NULL) {
8822 reply_nterror(req, NT_STATUS_NO_MEMORY);
8823 goto out;
8825 source_has_wild = ms_has_wild(orig_src_lcomp);
8826 dest_has_wild = ms_has_wild(orig_dst_lcomp);
8827 TALLOC_FREE(orig_src_lcomp);
8828 TALLOC_FREE(orig_dst_lcomp);
8832 * We should only check the mangled cache
8833 * here if unix_convert failed. This means
8834 * that the path in 'mask' doesn't exist
8835 * on the file system and so we need to look
8836 * for a possible mangle. This patch from
8837 * Tine Smukavec <valentin.smukavec@hermes.si>.
8839 if (!VALID_STAT(smb_fname_src->st) &&
8840 mangle_is_mangled(fname_src_mask, conn->params)) {
8841 char *new_mask = NULL;
8842 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
8843 &new_mask, conn->params);
8845 /* Use demangled name if one was successfully found. */
8846 if (new_mask) {
8847 TALLOC_FREE(fname_src_mask);
8848 fname_src_mask = new_mask;
8852 if (!source_has_wild) {
8855 * Only one file needs to be copied. Append the mask back onto
8856 * the directory.
8858 TALLOC_FREE(smb_fname_src->base_name);
8859 if (ISDOT(fname_src_dir)) {
8860 /* Ensure we use canonical names on open. */
8861 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8862 "%s",
8863 fname_src_mask);
8864 } else {
8865 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8866 "%s/%s",
8867 fname_src_dir,
8868 fname_src_mask);
8870 if (!smb_fname_src->base_name) {
8871 reply_nterror(req, NT_STATUS_NO_MEMORY);
8872 goto out;
8875 if (dest_has_wild) {
8876 char *fname_dst_mod = NULL;
8877 if (!resolve_wildcards(smb_fname_dst,
8878 smb_fname_src->base_name,
8879 smb_fname_dst->base_name,
8880 &fname_dst_mod)) {
8881 reply_nterror(req, NT_STATUS_NO_MEMORY);
8882 goto out;
8884 TALLOC_FREE(smb_fname_dst->base_name);
8885 smb_fname_dst->base_name = fname_dst_mod;
8888 status = check_name(conn, smb_fname_src);
8889 if (!NT_STATUS_IS_OK(status)) {
8890 reply_nterror(req, status);
8891 goto out;
8894 status = check_name(conn, smb_fname_dst);
8895 if (!NT_STATUS_IS_OK(status)) {
8896 reply_nterror(req, status);
8897 goto out;
8900 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
8901 ofun, count, target_is_directory);
8903 if(!NT_STATUS_IS_OK(status)) {
8904 reply_nterror(req, status);
8905 goto out;
8906 } else {
8907 count++;
8909 } else {
8910 struct smb_Dir *dir_hnd = NULL;
8911 const char *dname = NULL;
8912 char *talloced = NULL;
8913 long offset = 0;
8916 * There is a wildcard that requires us to actually read the
8917 * src dir and copy each file matching the mask to the dst.
8918 * Right now streams won't be copied, but this could
8919 * presumably be added with a nested loop for reach dir entry.
8921 SMB_ASSERT(!smb_fname_src->stream_name);
8922 SMB_ASSERT(!smb_fname_dst->stream_name);
8924 smb_fname_src->stream_name = NULL;
8925 smb_fname_dst->stream_name = NULL;
8927 if (strequal(fname_src_mask,"????????.???")) {
8928 TALLOC_FREE(fname_src_mask);
8929 fname_src_mask = talloc_strdup(ctx, "*");
8930 if (!fname_src_mask) {
8931 reply_nterror(req, NT_STATUS_NO_MEMORY);
8932 goto out;
8936 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
8937 fname_src_dir,
8938 NULL,
8939 NULL,
8940 smb_fname_src->twrp,
8941 smb_fname_src->flags);
8942 if (smb_fname_src_dir == NULL) {
8943 reply_nterror(req, NT_STATUS_NO_MEMORY);
8944 goto out;
8947 status = check_name(conn, smb_fname_src_dir);
8948 if (!NT_STATUS_IS_OK(status)) {
8949 reply_nterror(req, status);
8950 goto out;
8953 dir_hnd = OpenDir(ctx,
8954 conn,
8955 smb_fname_src_dir,
8956 fname_src_mask,
8958 if (dir_hnd == NULL) {
8959 status = map_nt_error_from_unix(errno);
8960 reply_nterror(req, status);
8961 goto out;
8964 error = ERRbadfile;
8966 /* Iterate over the src dir copying each entry to the dst. */
8967 while ((dname = ReadDirName(dir_hnd, &offset,
8968 &smb_fname_src->st, &talloced))) {
8969 char *destname = NULL;
8971 if (ISDOT(dname) || ISDOTDOT(dname)) {
8972 TALLOC_FREE(talloced);
8973 continue;
8976 if (IS_VETO_PATH(conn, dname)) {
8977 TALLOC_FREE(talloced);
8978 continue;
8981 if(!mask_match(dname, fname_src_mask,
8982 conn->case_sensitive)) {
8983 TALLOC_FREE(talloced);
8984 continue;
8987 error = ERRnoaccess;
8989 /* Get the src smb_fname struct setup. */
8990 TALLOC_FREE(smb_fname_src->base_name);
8991 if (ISDOT(fname_src_dir)) {
8992 /* Ensure we use canonical names on open. */
8993 smb_fname_src->base_name =
8994 talloc_asprintf(smb_fname_src, "%s",
8995 dname);
8996 } else {
8997 smb_fname_src->base_name =
8998 talloc_asprintf(smb_fname_src, "%s/%s",
8999 fname_src_dir, dname);
9002 if (!smb_fname_src->base_name) {
9003 TALLOC_FREE(dir_hnd);
9004 TALLOC_FREE(talloced);
9005 reply_nterror(req, NT_STATUS_NO_MEMORY);
9006 goto out;
9009 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
9010 smb_fname_dst->base_name,
9011 &destname)) {
9012 TALLOC_FREE(talloced);
9013 continue;
9015 if (!destname) {
9016 TALLOC_FREE(dir_hnd);
9017 TALLOC_FREE(talloced);
9018 reply_nterror(req, NT_STATUS_NO_MEMORY);
9019 goto out;
9022 TALLOC_FREE(smb_fname_dst->base_name);
9023 smb_fname_dst->base_name = destname;
9025 ZERO_STRUCT(smb_fname_src->st);
9026 vfs_stat(conn, smb_fname_src);
9028 status = openat_pathref_fsp(conn->cwd_fsp,
9029 smb_fname_src);
9030 if (!NT_STATUS_IS_OK(status)) {
9031 DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
9032 smb_fname_str_dbg(smb_fname_src),
9033 nt_errstr(status));
9034 break;
9037 if (!is_visible_fsp(smb_fname_src->fsp)) {
9038 TALLOC_FREE(talloced);
9039 continue;
9042 status = check_name(conn, smb_fname_src);
9043 if (!NT_STATUS_IS_OK(status)) {
9044 TALLOC_FREE(dir_hnd);
9045 TALLOC_FREE(talloced);
9046 reply_nterror(req, status);
9047 goto out;
9050 status = check_name(conn, smb_fname_dst);
9051 if (!NT_STATUS_IS_OK(status)) {
9052 TALLOC_FREE(dir_hnd);
9053 TALLOC_FREE(talloced);
9054 reply_nterror(req, status);
9055 goto out;
9058 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
9059 smb_fname_src->base_name,
9060 smb_fname_dst->base_name));
9062 status = copy_file(ctx, conn, smb_fname_src,
9063 smb_fname_dst, ofun, count,
9064 target_is_directory);
9065 if (NT_STATUS_IS_OK(status)) {
9066 count++;
9069 TALLOC_FREE(talloced);
9071 TALLOC_FREE(dir_hnd);
9074 if (count == 0) {
9075 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
9076 goto out;
9079 reply_outbuf(req, 1, 0);
9080 SSVAL(req->outbuf,smb_vwv0,count);
9081 out:
9082 TALLOC_FREE(smb_fname_src);
9083 TALLOC_FREE(smb_fname_src_dir);
9084 TALLOC_FREE(smb_fname_dst);
9085 TALLOC_FREE(fname_src);
9086 TALLOC_FREE(fname_dst);
9087 TALLOC_FREE(fname_src_mask);
9088 TALLOC_FREE(fname_src_dir);
9090 END_PROFILE(SMBcopy);
9091 return;
9094 #undef DBGC_CLASS
9095 #define DBGC_CLASS DBGC_LOCKING
9097 /****************************************************************************
9098 Get a lock pid, dealing with large count requests.
9099 ****************************************************************************/
9101 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
9102 bool large_file_format)
9104 if(!large_file_format)
9105 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
9106 else
9107 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
9110 /****************************************************************************
9111 Get a lock count, dealing with large count requests.
9112 ****************************************************************************/
9114 uint64_t get_lock_count(const uint8_t *data, int data_offset,
9115 bool large_file_format)
9117 uint64_t count = 0;
9119 if(!large_file_format) {
9120 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
9121 } else {
9123 * No BVAL, this is reversed!
9125 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
9126 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
9129 return count;
9132 /****************************************************************************
9133 Get a lock offset, dealing with large offset requests.
9134 ****************************************************************************/
9136 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
9137 bool large_file_format)
9139 uint64_t offset = 0;
9141 if(!large_file_format) {
9142 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
9143 } else {
9145 * No BVAL, this is reversed!
9147 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
9148 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
9151 return offset;
9154 struct smbd_do_unlocking_state {
9155 struct files_struct *fsp;
9156 uint16_t num_ulocks;
9157 struct smbd_lock_element *ulocks;
9158 enum brl_flavour lock_flav;
9159 NTSTATUS status;
9162 static void smbd_do_unlocking_fn(
9163 const uint8_t *buf,
9164 size_t buflen,
9165 bool *pmodified_dependent,
9166 void *private_data)
9168 struct smbd_do_unlocking_state *state = private_data;
9169 struct files_struct *fsp = state->fsp;
9170 enum brl_flavour lock_flav = state->lock_flav;
9171 uint16_t i;
9173 for (i = 0; i < state->num_ulocks; i++) {
9174 struct smbd_lock_element *e = &state->ulocks[i];
9176 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
9177 "pid %"PRIu64", file %s\n",
9178 e->offset,
9179 e->count,
9180 e->smblctx,
9181 fsp_str_dbg(fsp));
9183 if (e->brltype != UNLOCK_LOCK) {
9184 /* this can only happen with SMB2 */
9185 state->status = NT_STATUS_INVALID_PARAMETER;
9186 return;
9189 state->status = do_unlock(
9190 fsp, e->smblctx, e->count, e->offset, lock_flav);
9192 DBG_DEBUG("do_unlock returned %s\n",
9193 nt_errstr(state->status));
9195 if (!NT_STATUS_IS_OK(state->status)) {
9196 return;
9200 *pmodified_dependent = true;
9203 NTSTATUS smbd_do_unlocking(struct smb_request *req,
9204 files_struct *fsp,
9205 uint16_t num_ulocks,
9206 struct smbd_lock_element *ulocks,
9207 enum brl_flavour lock_flav)
9209 struct smbd_do_unlocking_state state = {
9210 .fsp = fsp,
9211 .num_ulocks = num_ulocks,
9212 .ulocks = ulocks,
9213 .lock_flav = lock_flav,
9215 NTSTATUS status;
9217 DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
9219 status = share_mode_do_locked(
9220 fsp->file_id, smbd_do_unlocking_fn, &state);
9222 if (!NT_STATUS_IS_OK(status)) {
9223 DBG_DEBUG("share_mode_do_locked failed: %s\n",
9224 nt_errstr(status));
9225 return status;
9227 if (!NT_STATUS_IS_OK(state.status)) {
9228 DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
9229 nt_errstr(status));
9230 return state.status;
9233 return NT_STATUS_OK;
9236 /****************************************************************************
9237 Reply to a lockingX request.
9238 ****************************************************************************/
9240 static void reply_lockingx_done(struct tevent_req *subreq);
9242 void reply_lockingX(struct smb_request *req)
9244 connection_struct *conn = req->conn;
9245 files_struct *fsp;
9246 unsigned char locktype;
9247 enum brl_type brltype;
9248 unsigned char oplocklevel;
9249 uint16_t num_ulocks;
9250 uint16_t num_locks;
9251 int32_t lock_timeout;
9252 uint16_t i;
9253 const uint8_t *data;
9254 bool large_file_format;
9255 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
9256 struct smbd_lock_element *locks = NULL;
9257 struct tevent_req *subreq = NULL;
9259 START_PROFILE(SMBlockingX);
9261 if (req->wct < 8) {
9262 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9263 END_PROFILE(SMBlockingX);
9264 return;
9267 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
9268 locktype = CVAL(req->vwv+3, 0);
9269 oplocklevel = CVAL(req->vwv+3, 1);
9270 num_ulocks = SVAL(req->vwv+6, 0);
9271 num_locks = SVAL(req->vwv+7, 0);
9272 lock_timeout = IVAL(req->vwv+4, 0);
9273 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
9275 if (!check_fsp(conn, req, fsp)) {
9276 END_PROFILE(SMBlockingX);
9277 return;
9280 data = req->buf;
9282 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
9283 /* we don't support these - and CANCEL_LOCK makes w2k
9284 and XP reboot so I don't really want to be
9285 compatible! (tridge) */
9286 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
9287 END_PROFILE(SMBlockingX);
9288 return;
9291 /* Check if this is an oplock break on a file
9292 we have granted an oplock on.
9294 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
9295 /* Client can insist on breaking to none. */
9296 bool break_to_none = (oplocklevel == 0);
9297 bool result;
9299 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
9300 "for %s\n", (unsigned int)oplocklevel,
9301 fsp_fnum_dbg(fsp)));
9304 * Make sure we have granted an exclusive or batch oplock on
9305 * this file.
9308 if (fsp->oplock_type == 0) {
9310 /* The Samba4 nbench simulator doesn't understand
9311 the difference between break to level2 and break
9312 to none from level2 - it sends oplock break
9313 replies in both cases. Don't keep logging an error
9314 message here - just ignore it. JRA. */
9316 DEBUG(5,("reply_lockingX: Error : oplock break from "
9317 "client for %s (oplock=%d) and no "
9318 "oplock granted on this file (%s).\n",
9319 fsp_fnum_dbg(fsp), fsp->oplock_type,
9320 fsp_str_dbg(fsp)));
9322 /* if this is a pure oplock break request then don't
9323 * send a reply */
9324 if (num_locks == 0 && num_ulocks == 0) {
9325 END_PROFILE(SMBlockingX);
9326 return;
9329 END_PROFILE(SMBlockingX);
9330 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
9331 return;
9334 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
9335 (break_to_none)) {
9336 result = remove_oplock(fsp);
9337 } else {
9338 result = downgrade_oplock(fsp);
9341 if (!result) {
9342 DEBUG(0, ("reply_lockingX: error in removing "
9343 "oplock on file %s\n", fsp_str_dbg(fsp)));
9344 /* Hmmm. Is this panic justified? */
9345 smb_panic("internal tdb error");
9348 /* if this is a pure oplock break request then don't send a
9349 * reply */
9350 if (num_locks == 0 && num_ulocks == 0) {
9351 /* Sanity check - ensure a pure oplock break is not a
9352 chained request. */
9353 if (CVAL(req->vwv+0, 0) != 0xff) {
9354 DEBUG(0,("reply_lockingX: Error : pure oplock "
9355 "break is a chained %d request !\n",
9356 (unsigned int)CVAL(req->vwv+0, 0)));
9358 END_PROFILE(SMBlockingX);
9359 return;
9363 if (req->buflen <
9364 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
9365 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9366 END_PROFILE(SMBlockingX);
9367 return;
9370 if (num_ulocks != 0) {
9371 struct smbd_lock_element *ulocks = NULL;
9372 bool ok;
9374 ulocks = talloc_array(
9375 req, struct smbd_lock_element, num_ulocks);
9376 if (ulocks == NULL) {
9377 reply_nterror(req, NT_STATUS_NO_MEMORY);
9378 END_PROFILE(SMBlockingX);
9379 return;
9383 * Data now points at the beginning of the list of
9384 * smb_unlkrng structs
9386 for (i = 0; i < num_ulocks; i++) {
9387 ulocks[i].req_guid = smbd_request_guid(req,
9388 UINT16_MAX - i),
9389 ulocks[i].smblctx = get_lock_pid(
9390 data, i, large_file_format);
9391 ulocks[i].count = get_lock_count(
9392 data, i, large_file_format);
9393 ulocks[i].offset = get_lock_offset(
9394 data, i, large_file_format);
9395 ulocks[i].brltype = UNLOCK_LOCK;
9399 * Unlock cancels pending locks
9402 ok = smbd_smb1_brl_finish_by_lock(
9403 fsp,
9404 large_file_format,
9405 WINDOWS_LOCK,
9406 ulocks[0],
9407 NT_STATUS_OK);
9408 if (ok) {
9409 reply_outbuf(req, 2, 0);
9410 SSVAL(req->outbuf, smb_vwv0, 0xff);
9411 SSVAL(req->outbuf, smb_vwv1, 0);
9412 END_PROFILE(SMBlockingX);
9413 return;
9416 status = smbd_do_unlocking(
9417 req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
9418 TALLOC_FREE(ulocks);
9419 if (!NT_STATUS_IS_OK(status)) {
9420 END_PROFILE(SMBlockingX);
9421 reply_nterror(req, status);
9422 return;
9426 /* Now do any requested locks */
9427 data += ((large_file_format ? 20 : 10)*num_ulocks);
9429 /* Data now points at the beginning of the list
9430 of smb_lkrng structs */
9432 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
9433 brltype = READ_LOCK;
9434 } else {
9435 brltype = WRITE_LOCK;
9438 locks = talloc_array(req, struct smbd_lock_element, num_locks);
9439 if (locks == NULL) {
9440 reply_nterror(req, NT_STATUS_NO_MEMORY);
9441 END_PROFILE(SMBlockingX);
9442 return;
9445 for (i = 0; i < num_locks; i++) {
9446 locks[i].req_guid = smbd_request_guid(req, i),
9447 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
9448 locks[i].count = get_lock_count(data, i, large_file_format);
9449 locks[i].offset = get_lock_offset(data, i, large_file_format);
9450 locks[i].brltype = brltype;
9453 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
9455 bool ok;
9457 if (num_locks == 0) {
9458 /* See smbtorture3 lock11 test */
9459 reply_outbuf(req, 2, 0);
9460 /* andx chain ends */
9461 SSVAL(req->outbuf, smb_vwv0, 0xff);
9462 SSVAL(req->outbuf, smb_vwv1, 0);
9463 END_PROFILE(SMBlockingX);
9464 return;
9467 ok = smbd_smb1_brl_finish_by_lock(
9468 fsp,
9469 large_file_format,
9470 WINDOWS_LOCK,
9471 locks[0], /* Windows only cancels the first lock */
9472 NT_STATUS_FILE_LOCK_CONFLICT);
9474 if (!ok) {
9475 reply_force_doserror(req, ERRDOS, ERRcancelviolation);
9476 END_PROFILE(SMBlockingX);
9477 return;
9480 reply_outbuf(req, 2, 0);
9481 SSVAL(req->outbuf, smb_vwv0, 0xff);
9482 SSVAL(req->outbuf, smb_vwv1, 0);
9483 END_PROFILE(SMBlockingX);
9484 return;
9487 subreq = smbd_smb1_do_locks_send(
9488 fsp,
9489 req->sconn->ev_ctx,
9490 &req,
9491 fsp,
9492 lock_timeout,
9493 large_file_format,
9494 WINDOWS_LOCK,
9495 num_locks,
9496 locks);
9497 if (subreq == NULL) {
9498 reply_nterror(req, NT_STATUS_NO_MEMORY);
9499 END_PROFILE(SMBlockingX);
9500 return;
9502 tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
9503 END_PROFILE(SMBlockingX);
9506 static void reply_lockingx_done(struct tevent_req *subreq)
9508 struct smb_request *req = NULL;
9509 NTSTATUS status;
9510 bool ok;
9512 START_PROFILE(SMBlockingX);
9514 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
9515 SMB_ASSERT(ok);
9517 status = smbd_smb1_do_locks_recv(subreq);
9518 TALLOC_FREE(subreq);
9520 DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
9522 if (NT_STATUS_IS_OK(status)) {
9523 reply_outbuf(req, 2, 0);
9524 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
9525 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
9526 } else {
9527 reply_nterror(req, status);
9530 ok = srv_send_smb(req->xconn,
9531 (char *)req->outbuf,
9532 true,
9533 req->seqnum+1,
9534 IS_CONN_ENCRYPTED(req->conn),
9535 NULL);
9536 if (!ok) {
9537 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
9539 TALLOC_FREE(req);
9540 END_PROFILE(SMBlockingX);
9543 #undef DBGC_CLASS
9544 #define DBGC_CLASS DBGC_ALL
9546 /****************************************************************************
9547 Reply to a SMBreadbmpx (read block multiplex) request.
9548 Always reply with an error, if someone has a platform really needs this,
9549 please contact vl@samba.org
9550 ****************************************************************************/
9552 void reply_readbmpx(struct smb_request *req)
9554 START_PROFILE(SMBreadBmpx);
9555 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9556 END_PROFILE(SMBreadBmpx);
9557 return;
9560 /****************************************************************************
9561 Reply to a SMBreadbs (read block multiplex secondary) request.
9562 Always reply with an error, if someone has a platform really needs this,
9563 please contact vl@samba.org
9564 ****************************************************************************/
9566 void reply_readbs(struct smb_request *req)
9568 START_PROFILE(SMBreadBs);
9569 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9570 END_PROFILE(SMBreadBs);
9571 return;
9574 /****************************************************************************
9575 Reply to a SMBsetattrE.
9576 ****************************************************************************/
9578 void reply_setattrE(struct smb_request *req)
9580 connection_struct *conn = req->conn;
9581 struct smb_file_time ft;
9582 files_struct *fsp;
9583 NTSTATUS status;
9585 START_PROFILE(SMBsetattrE);
9586 init_smb_file_time(&ft);
9588 if (req->wct < 7) {
9589 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9590 goto out;
9593 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
9595 if(!fsp || (fsp->conn != conn)) {
9596 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
9597 goto out;
9601 * Convert the DOS times into unix times.
9604 ft.atime = time_t_to_full_timespec(
9605 srv_make_unix_date2(req->vwv+3));
9606 ft.mtime = time_t_to_full_timespec(
9607 srv_make_unix_date2(req->vwv+5));
9608 ft.create_time = time_t_to_full_timespec(
9609 srv_make_unix_date2(req->vwv+1));
9611 reply_outbuf(req, 0, 0);
9614 * Patch from Ray Frush <frush@engr.colostate.edu>
9615 * Sometimes times are sent as zero - ignore them.
9618 /* Ensure we have a valid stat struct for the source. */
9619 status = vfs_stat_fsp(fsp);
9620 if (!NT_STATUS_IS_OK(status)) {
9621 reply_nterror(req, status);
9622 goto out;
9625 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
9626 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
9627 goto out;
9630 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
9631 if (!NT_STATUS_IS_OK(status)) {
9632 reply_nterror(req, status);
9633 goto out;
9636 if (fsp->fsp_flags.modified) {
9637 trigger_write_time_update_immediate(fsp);
9640 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
9641 " createtime=%u\n",
9642 fsp_fnum_dbg(fsp),
9643 (unsigned int)ft.atime.tv_sec,
9644 (unsigned int)ft.mtime.tv_sec,
9645 (unsigned int)ft.create_time.tv_sec
9647 out:
9648 END_PROFILE(SMBsetattrE);
9649 return;
9653 /* Back from the dead for OS/2..... JRA. */
9655 /****************************************************************************
9656 Reply to a SMBwritebmpx (write block multiplex primary) request.
9657 Always reply with an error, if someone has a platform really needs this,
9658 please contact vl@samba.org
9659 ****************************************************************************/
9661 void reply_writebmpx(struct smb_request *req)
9663 START_PROFILE(SMBwriteBmpx);
9664 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9665 END_PROFILE(SMBwriteBmpx);
9666 return;
9669 /****************************************************************************
9670 Reply to a SMBwritebs (write block multiplex secondary) request.
9671 Always reply with an error, if someone has a platform really needs this,
9672 please contact vl@samba.org
9673 ****************************************************************************/
9675 void reply_writebs(struct smb_request *req)
9677 START_PROFILE(SMBwriteBs);
9678 reply_force_doserror(req, ERRSRV, ERRuseSTD);
9679 END_PROFILE(SMBwriteBs);
9680 return;
9683 /****************************************************************************
9684 Reply to a SMBgetattrE.
9685 ****************************************************************************/
9687 void reply_getattrE(struct smb_request *req)
9689 connection_struct *conn = req->conn;
9690 int mode;
9691 files_struct *fsp;
9692 struct timespec create_ts;
9693 NTSTATUS status;
9695 START_PROFILE(SMBgetattrE);
9697 if (req->wct < 1) {
9698 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9699 END_PROFILE(SMBgetattrE);
9700 return;
9703 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
9705 if(!fsp || (fsp->conn != conn)) {
9706 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
9707 END_PROFILE(SMBgetattrE);
9708 return;
9711 /* Do an fstat on this file */
9712 status = vfs_stat_fsp(fsp);
9713 if (!NT_STATUS_IS_OK(status)) {
9714 reply_nterror(req, status);
9715 END_PROFILE(SMBgetattrE);
9716 return;
9719 mode = fdos_mode(fsp);
9722 * Convert the times into dos times. Set create
9723 * date to be last modify date as UNIX doesn't save
9724 * this.
9727 reply_outbuf(req, 11, 0);
9729 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
9730 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
9731 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
9732 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
9733 /* Should we check pending modtime here ? JRA */
9734 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
9735 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
9737 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
9738 SIVAL(req->outbuf, smb_vwv6, 0);
9739 SIVAL(req->outbuf, smb_vwv8, 0);
9740 } else {
9741 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
9742 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
9743 SIVAL(req->outbuf, smb_vwv8, allocation_size);
9745 SSVAL(req->outbuf,smb_vwv10, mode);
9747 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
9749 END_PROFILE(SMBgetattrE);
9750 return;