s3: replace fsp_stat() with vfs_stat_fsp()
[Samba.git] / source3 / smbd / reply.c
blobdcd46dd574c0bfb109311c708736c51766045093
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 "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "fake_file.h"
34 #include "rpc_client/rpc_client.h"
35 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
46 #include "lib/util/sys_rw_data.h"
47 #include "librpc/gen_ndr/open_files.h"
48 #include "smb1_utils.h"
50 /****************************************************************************
51 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
52 path or anything including wildcards.
53 We're assuming here that '/' is not the second byte in any multibyte char
54 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
55 set.
56 ****************************************************************************/
58 /* Custom version for processing POSIX paths. */
59 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
61 static NTSTATUS check_path_syntax_internal(char *path,
62 bool posix_path,
63 bool *p_last_component_contains_wcard)
65 char *d = path;
66 const char *s = path;
67 NTSTATUS ret = NT_STATUS_OK;
68 bool start_of_name_component = True;
69 bool stream_started = false;
71 *p_last_component_contains_wcard = False;
73 while (*s) {
74 if (stream_started) {
75 switch (*s) {
76 case '/':
77 case '\\':
78 return NT_STATUS_OBJECT_NAME_INVALID;
79 case ':':
80 if (s[1] == '\0') {
81 return NT_STATUS_OBJECT_NAME_INVALID;
83 if (strchr_m(&s[1], ':')) {
84 return NT_STATUS_OBJECT_NAME_INVALID;
86 break;
90 if ((*s == ':') && !posix_path && !stream_started) {
91 if (*p_last_component_contains_wcard) {
92 return NT_STATUS_OBJECT_NAME_INVALID;
94 /* Stream names allow more characters than file names.
95 We're overloading posix_path here to allow a wider
96 range of characters. If stream_started is true this
97 is still a Windows path even if posix_path is true.
98 JRA.
100 stream_started = true;
101 start_of_name_component = false;
102 posix_path = true;
104 if (s[1] == '\0') {
105 return NT_STATUS_OBJECT_NAME_INVALID;
109 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
111 * Safe to assume is not the second part of a mb char
112 * as this is handled below.
114 /* Eat multiple '/' or '\\' */
115 while (IS_PATH_SEP(*s,posix_path)) {
116 s++;
118 if ((d != path) && (*s != '\0')) {
119 /* We only care about non-leading or trailing '/' or '\\' */
120 *d++ = '/';
123 start_of_name_component = True;
124 /* New component. */
125 *p_last_component_contains_wcard = False;
126 continue;
129 if (start_of_name_component) {
130 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
131 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
134 * No mb char starts with '.' so we're safe checking the directory separator here.
137 /* If we just added a '/' - delete it */
138 if ((d > path) && (*(d-1) == '/')) {
139 *(d-1) = '\0';
140 d--;
143 /* Are we at the start ? Can't go back further if so. */
144 if (d <= path) {
145 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
146 break;
148 /* Go back one level... */
149 /* We know this is safe as '/' cannot be part of a mb sequence. */
150 /* NOTE - if this assumption is invalid we are not in good shape... */
151 /* Decrement d first as d points to the *next* char to write into. */
152 for (d--; d > path; d--) {
153 if (*d == '/')
154 break;
156 s += 2; /* Else go past the .. */
157 /* We're still at the start of a name component, just the previous one. */
158 continue;
160 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
161 if (posix_path) {
162 /* Eat the '.' */
163 s++;
164 continue;
170 if (!(*s & 0x80)) {
171 if (!posix_path) {
172 if (*s <= 0x1f || *s == '|') {
173 return NT_STATUS_OBJECT_NAME_INVALID;
175 switch (*s) {
176 case '*':
177 case '?':
178 case '<':
179 case '>':
180 case '"':
181 *p_last_component_contains_wcard = True;
182 break;
183 default:
184 break;
187 *d++ = *s++;
188 } else {
189 size_t siz;
190 /* Get the size of the next MB character. */
191 next_codepoint(s,&siz);
192 switch(siz) {
193 case 5:
194 *d++ = *s++;
195 FALL_THROUGH;
196 case 4:
197 *d++ = *s++;
198 FALL_THROUGH;
199 case 3:
200 *d++ = *s++;
201 FALL_THROUGH;
202 case 2:
203 *d++ = *s++;
204 FALL_THROUGH;
205 case 1:
206 *d++ = *s++;
207 break;
208 default:
209 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
210 *d = '\0';
211 return NT_STATUS_INVALID_PARAMETER;
214 start_of_name_component = False;
217 *d = '\0';
219 return ret;
222 /****************************************************************************
223 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
224 No wildcards allowed.
225 ****************************************************************************/
227 NTSTATUS check_path_syntax(char *path)
229 bool ignore;
230 return check_path_syntax_internal(path, False, &ignore);
233 /****************************************************************************
234 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
235 Wildcards allowed - p_contains_wcard returns true if the last component contained
236 a wildcard.
237 ****************************************************************************/
239 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
241 return check_path_syntax_internal(path, False, p_contains_wcard);
244 /****************************************************************************
245 Check the path for a POSIX client.
246 We're assuming here that '/' is not the second byte in any multibyte char
247 set (a safe assumption).
248 ****************************************************************************/
250 NTSTATUS check_path_syntax_posix(char *path)
252 bool ignore;
253 return check_path_syntax_internal(path, True, &ignore);
256 /****************************************************************************
257 Pull a string and check the path allowing a wilcard - provide for error return.
258 Passes in posix flag.
259 ****************************************************************************/
261 static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
262 const char *base_ptr,
263 uint16_t smb_flags2,
264 char **pp_dest,
265 const char *src,
266 size_t src_len,
267 int flags,
268 bool posix_pathnames,
269 NTSTATUS *err,
270 bool *contains_wcard)
272 size_t ret;
274 *pp_dest = NULL;
276 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
277 src_len, flags);
279 if (!*pp_dest) {
280 *err = NT_STATUS_INVALID_PARAMETER;
281 return ret;
284 *contains_wcard = False;
286 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
288 * For a DFS path the function parse_dfs_path()
289 * will do the path processing, just make a copy.
291 *err = NT_STATUS_OK;
292 return ret;
295 if (posix_pathnames) {
296 *err = check_path_syntax_posix(*pp_dest);
297 } else {
298 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
301 return ret;
304 /****************************************************************************
305 Pull a string and check the path allowing a wilcard - provide for error return.
306 ****************************************************************************/
308 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
309 const char *base_ptr,
310 uint16_t smb_flags2,
311 char **pp_dest,
312 const char *src,
313 size_t src_len,
314 int flags,
315 NTSTATUS *err,
316 bool *contains_wcard)
318 return srvstr_get_path_wcard_internal(ctx,
319 base_ptr,
320 smb_flags2,
321 pp_dest,
322 src,
323 src_len,
324 flags,
325 false,
326 err,
327 contains_wcard);
330 /****************************************************************************
331 Pull a string and check the path allowing a wilcard - provide for error return.
332 posix_pathnames version.
333 ****************************************************************************/
335 size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
336 const char *base_ptr,
337 uint16_t smb_flags2,
338 char **pp_dest,
339 const char *src,
340 size_t src_len,
341 int flags,
342 NTSTATUS *err,
343 bool *contains_wcard)
345 return srvstr_get_path_wcard_internal(ctx,
346 base_ptr,
347 smb_flags2,
348 pp_dest,
349 src,
350 src_len,
351 flags,
352 true,
353 err,
354 contains_wcard);
357 /****************************************************************************
358 Pull a string and check the path - provide for error return.
359 ****************************************************************************/
361 size_t srvstr_get_path(TALLOC_CTX *ctx,
362 const char *base_ptr,
363 uint16_t smb_flags2,
364 char **pp_dest,
365 const char *src,
366 size_t src_len,
367 int flags,
368 NTSTATUS *err)
370 bool ignore;
371 return srvstr_get_path_wcard_internal(ctx,
372 base_ptr,
373 smb_flags2,
374 pp_dest,
375 src,
376 src_len,
377 flags,
378 false,
379 err,
380 &ignore);
383 /****************************************************************************
384 Pull a string and check the path - provide for error return.
385 posix_pathnames version.
386 ****************************************************************************/
388 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
389 const char *base_ptr,
390 uint16_t smb_flags2,
391 char **pp_dest,
392 const char *src,
393 size_t src_len,
394 int flags,
395 NTSTATUS *err)
397 bool ignore;
398 return srvstr_get_path_wcard_internal(ctx,
399 base_ptr,
400 smb_flags2,
401 pp_dest,
402 src,
403 src_len,
404 flags,
405 true,
406 err,
407 &ignore);
411 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
412 char **pp_dest, const char *src, int flags,
413 NTSTATUS *err, bool *contains_wcard)
415 ssize_t bufrem = smbreq_bufrem(req, src);
417 if (bufrem < 0) {
418 *err = NT_STATUS_INVALID_PARAMETER;
419 return 0;
422 if (req->posix_pathnames) {
423 return srvstr_get_path_wcard_internal(mem_ctx,
424 (const char *)req->inbuf,
425 req->flags2,
426 pp_dest,
427 src,
428 bufrem,
429 flags,
430 true,
431 err,
432 contains_wcard);
433 } else {
434 return srvstr_get_path_wcard_internal(mem_ctx,
435 (const char *)req->inbuf,
436 req->flags2,
437 pp_dest,
438 src,
439 bufrem,
440 flags,
441 false,
442 err,
443 contains_wcard);
447 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
448 char **pp_dest, const char *src, int flags,
449 NTSTATUS *err)
451 bool ignore;
452 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
453 flags, err, &ignore);
457 * pull a string from the smb_buf part of a packet. In this case the
458 * string can either be null terminated or it can be terminated by the
459 * end of the smbbuf area
461 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
462 char **dest, const uint8_t *src, int flags)
464 ssize_t bufrem = smbreq_bufrem(req, src);
466 if (bufrem < 0) {
467 return 0;
470 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
471 bufrem, flags);
474 /****************************************************************************
475 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
476 ****************************************************************************/
478 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
479 files_struct *fsp)
481 if ((fsp == NULL) || (conn == NULL)) {
482 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
483 return False;
485 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
486 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
487 return False;
489 return True;
492 /****************************************************************************
493 Check if we have a correct fsp pointing to a file.
494 ****************************************************************************/
496 bool check_fsp(connection_struct *conn, struct smb_request *req,
497 files_struct *fsp)
499 if (!check_fsp_open(conn, req, fsp)) {
500 return False;
502 if (fsp->is_directory) {
503 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
504 return False;
506 if (fsp->fh->fd == -1) {
507 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
508 return False;
510 fsp->num_smb_operations++;
511 return True;
514 /****************************************************************************
515 Check if we have a correct fsp pointing to a quota fake file. Replacement for
516 the CHECK_NTQUOTA_HANDLE_OK macro.
517 ****************************************************************************/
519 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
520 files_struct *fsp)
522 if (!check_fsp_open(conn, req, fsp)) {
523 return false;
526 if (fsp->is_directory) {
527 return false;
530 if (fsp->fake_file_handle == NULL) {
531 return false;
534 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
535 return false;
538 if (fsp->fake_file_handle->private_data == NULL) {
539 return false;
542 return true;
545 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
546 const char *name, int name_type)
548 char *trim_name;
549 char *trim_name_type;
550 const char *retarget_parm;
551 char *retarget;
552 char *p;
553 int retarget_type = 0x20;
554 int retarget_port = NBT_SMB_PORT;
555 struct sockaddr_storage retarget_addr;
556 struct sockaddr_in *in_addr;
557 bool ret = false;
558 uint8_t outbuf[10];
560 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
561 return false;
564 trim_name = talloc_strdup(talloc_tos(), name);
565 if (trim_name == NULL) {
566 goto fail;
568 trim_char(trim_name, ' ', ' ');
570 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
571 name_type);
572 if (trim_name_type == NULL) {
573 goto fail;
576 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
577 trim_name_type, NULL);
578 if (retarget_parm == NULL) {
579 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
580 trim_name, NULL);
582 if (retarget_parm == NULL) {
583 goto fail;
586 retarget = talloc_strdup(trim_name, retarget_parm);
587 if (retarget == NULL) {
588 goto fail;
591 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
593 p = strchr(retarget, ':');
594 if (p != NULL) {
595 *p++ = '\0';
596 retarget_port = atoi(p);
599 p = strchr_m(retarget, '#');
600 if (p != NULL) {
601 *p++ = '\0';
602 if (sscanf(p, "%x", &retarget_type) != 1) {
603 goto fail;
607 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
608 if (!ret) {
609 DEBUG(10, ("could not resolve %s\n", retarget));
610 goto fail;
613 if (retarget_addr.ss_family != AF_INET) {
614 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
615 goto fail;
618 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
620 _smb_setlen(outbuf, 6);
621 SCVAL(outbuf, 0, 0x84);
622 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
623 *(uint16_t *)(outbuf+8) = htons(retarget_port);
625 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
626 NULL)) {
627 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
628 "failed.");
631 ret = true;
632 fail:
633 TALLOC_FREE(trim_name);
634 return ret;
637 static void reply_called_name_not_present(char *outbuf)
639 smb_setlen(outbuf, 1);
640 SCVAL(outbuf, 0, 0x83);
641 SCVAL(outbuf, 4, 0x82);
644 /****************************************************************************
645 Reply to a (netbios-level) special message.
646 ****************************************************************************/
648 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
650 struct smbd_server_connection *sconn = xconn->client->sconn;
651 int msg_type = CVAL(inbuf,0);
652 int msg_flags = CVAL(inbuf,1);
654 * We only really use 4 bytes of the outbuf, but for the smb_setlen
655 * calculation & friends (srv_send_smb uses that) we need the full smb
656 * header.
658 char outbuf[smb_size];
660 memset(outbuf, '\0', sizeof(outbuf));
662 smb_setlen(outbuf,0);
664 switch (msg_type) {
665 case NBSSrequest: /* session request */
667 /* inbuf_size is guarenteed to be at least 4. */
668 fstring name1,name2;
669 int name_type1, name_type2;
670 int name_len1, name_len2;
672 *name1 = *name2 = 0;
674 if (xconn->transport.nbt.got_session) {
675 exit_server_cleanly("multiple session request not permitted");
678 SCVAL(outbuf,0,NBSSpositive);
679 SCVAL(outbuf,3,0);
681 /* inbuf_size is guaranteed to be at least 4. */
682 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
683 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
684 DEBUG(0,("Invalid name length in session request\n"));
685 reply_called_name_not_present(outbuf);
686 break;
688 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
689 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
690 DEBUG(0,("Invalid name length in session request\n"));
691 reply_called_name_not_present(outbuf);
692 break;
695 name_type1 = name_extract((unsigned char *)inbuf,
696 inbuf_size,(unsigned int)4,name1);
697 name_type2 = name_extract((unsigned char *)inbuf,
698 inbuf_size,(unsigned int)(4 + name_len1),name2);
700 if (name_type1 == -1 || name_type2 == -1) {
701 DEBUG(0,("Invalid name type in session request\n"));
702 reply_called_name_not_present(outbuf);
703 break;
706 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
707 name1, name_type1, name2, name_type2));
709 if (netbios_session_retarget(xconn, name1, name_type1)) {
710 exit_server_cleanly("retargeted client");
714 * Windows NT/2k uses "*SMBSERVER" and XP uses
715 * "*SMBSERV" arrggg!!!
717 if (strequal(name1, "*SMBSERVER ")
718 || strequal(name1, "*SMBSERV ")) {
719 char *raddr;
721 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
722 talloc_tos());
723 if (raddr == NULL) {
724 exit_server_cleanly("could not allocate raddr");
727 fstrcpy(name1, raddr);
730 set_local_machine_name(name1, True);
731 set_remote_machine_name(name2, True);
733 if (is_ipaddress(sconn->remote_hostname)) {
734 char *p = discard_const_p(char, sconn->remote_hostname);
736 talloc_free(p);
738 sconn->remote_hostname = talloc_strdup(sconn,
739 get_remote_machine_name());
740 if (sconn->remote_hostname == NULL) {
741 exit_server_cleanly("could not copy remote name");
743 xconn->remote_hostname = sconn->remote_hostname;
746 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
747 get_local_machine_name(), get_remote_machine_name(),
748 name_type2));
750 if (name_type2 == 'R') {
751 /* We are being asked for a pathworks session ---
752 no thanks! */
753 reply_called_name_not_present(outbuf);
754 break;
757 reload_services(sconn, conn_snum_used, true);
758 reopen_logs();
760 xconn->transport.nbt.got_session = true;
761 break;
764 case 0x89: /* session keepalive request
765 (some old clients produce this?) */
766 SCVAL(outbuf,0,NBSSkeepalive);
767 SCVAL(outbuf,3,0);
768 break;
770 case NBSSpositive: /* positive session response */
771 case NBSSnegative: /* negative session response */
772 case NBSSretarget: /* retarget session response */
773 DEBUG(0,("Unexpected session response\n"));
774 break;
776 case NBSSkeepalive: /* session keepalive */
777 default:
778 return;
781 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
782 msg_type, msg_flags));
784 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
785 exit_server_cleanly("reply_special: srv_send_smb failed.");
788 if (CVAL(outbuf, 0) != 0x82) {
789 exit_server_cleanly("invalid netbios session");
791 return;
794 /****************************************************************************
795 Reply to a tcon.
796 conn POINTER CAN BE NULL HERE !
797 ****************************************************************************/
799 void reply_tcon(struct smb_request *req)
801 connection_struct *conn = req->conn;
802 const char *service;
803 char *service_buf = NULL;
804 char *password = NULL;
805 char *dev = NULL;
806 int pwlen=0;
807 NTSTATUS nt_status;
808 const uint8_t *p;
809 const char *p2;
810 TALLOC_CTX *ctx = talloc_tos();
811 struct smbXsrv_connection *xconn = req->xconn;
812 NTTIME now = timeval_to_nttime(&req->request_time);
814 START_PROFILE(SMBtcon);
816 if (req->buflen < 4) {
817 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
818 END_PROFILE(SMBtcon);
819 return;
822 p = req->buf + 1;
823 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
824 p += 1;
825 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
826 p += pwlen+1;
827 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
828 p += 1;
830 if (service_buf == NULL || password == NULL || dev == NULL) {
831 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
832 END_PROFILE(SMBtcon);
833 return;
835 p2 = strrchr_m(service_buf,'\\');
836 if (p2) {
837 service = p2+1;
838 } else {
839 service = service_buf;
842 conn = make_connection(req, now, service, dev,
843 req->vuid,&nt_status);
844 req->conn = conn;
846 if (!conn) {
847 reply_nterror(req, nt_status);
848 END_PROFILE(SMBtcon);
849 return;
852 reply_outbuf(req, 2, 0);
853 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
854 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
855 SSVAL(req->outbuf,smb_tid,conn->cnum);
857 DEBUG(3,("tcon service=%s cnum=%d\n",
858 service, conn->cnum));
860 END_PROFILE(SMBtcon);
861 return;
864 /****************************************************************************
865 Reply to a tcon and X.
866 conn POINTER CAN BE NULL HERE !
867 ****************************************************************************/
869 void reply_tcon_and_X(struct smb_request *req)
871 connection_struct *conn = req->conn;
872 const char *service = NULL;
873 TALLOC_CTX *ctx = talloc_tos();
874 /* what the client thinks the device is */
875 char *client_devicetype = NULL;
876 /* what the server tells the client the share represents */
877 const char *server_devicetype;
878 NTSTATUS nt_status;
879 int passlen;
880 char *path = NULL;
881 const uint8_t *p;
882 const char *q;
883 uint16_t tcon_flags;
884 struct smbXsrv_session *session = NULL;
885 NTTIME now = timeval_to_nttime(&req->request_time);
886 bool session_key_updated = false;
887 uint16_t optional_support = 0;
888 struct smbXsrv_connection *xconn = req->xconn;
890 START_PROFILE(SMBtconX);
892 if (req->wct < 4) {
893 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
894 END_PROFILE(SMBtconX);
895 return;
898 passlen = SVAL(req->vwv+3, 0);
899 tcon_flags = SVAL(req->vwv+2, 0);
901 /* we might have to close an old one */
902 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
903 struct smbXsrv_tcon *tcon;
904 NTSTATUS status;
906 tcon = conn->tcon;
907 req->conn = NULL;
908 conn = NULL;
911 * TODO: cancel all outstanding requests on the tcon
913 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
914 if (!NT_STATUS_IS_OK(status)) {
915 DEBUG(0, ("reply_tcon_and_X: "
916 "smbXsrv_tcon_disconnect() failed: %s\n",
917 nt_errstr(status)));
919 * If we hit this case, there is something completely
920 * wrong, so we better disconnect the transport connection.
922 END_PROFILE(SMBtconX);
923 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
924 return;
927 TALLOC_FREE(tcon);
929 * This tree id is gone. Make sure we can't re-use it
930 * by accident.
932 req->tid = 0;
935 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
936 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
937 END_PROFILE(SMBtconX);
938 return;
941 if (xconn->smb1.negprot.encrypted_passwords) {
942 p = req->buf + passlen;
943 } else {
944 p = req->buf + passlen + 1;
947 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
949 if (path == NULL) {
950 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
951 END_PROFILE(SMBtconX);
952 return;
956 * the service name can be either: \\server\share
957 * or share directly like on the DELL PowerVault 705
959 if (*path=='\\') {
960 q = strchr_m(path+2,'\\');
961 if (!q) {
962 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
963 END_PROFILE(SMBtconX);
964 return;
966 service = q+1;
967 } else {
968 service = path;
971 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
972 &client_devicetype, p,
973 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
975 if (client_devicetype == NULL) {
976 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
977 END_PROFILE(SMBtconX);
978 return;
981 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
983 nt_status = smb1srv_session_lookup(xconn,
984 req->vuid, now, &session);
985 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
986 reply_force_doserror(req, ERRSRV, ERRbaduid);
987 END_PROFILE(SMBtconX);
988 return;
990 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
991 reply_nterror(req, nt_status);
992 END_PROFILE(SMBtconX);
993 return;
995 if (!NT_STATUS_IS_OK(nt_status)) {
996 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
997 END_PROFILE(SMBtconX);
998 return;
1001 if (session->global->auth_session_info == NULL) {
1002 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1003 END_PROFILE(SMBtconX);
1004 return;
1008 * If there is no application key defined yet
1009 * we create one.
1011 * This means we setup the application key on the
1012 * first tcon that happens via the given session.
1014 * Once the application key is defined, it does not
1015 * change any more.
1017 if (session->global->application_key.length == 0 &&
1018 smb2_signing_key_valid(session->global->signing_key))
1020 struct smbXsrv_session *x = session;
1021 struct auth_session_info *session_info =
1022 session->global->auth_session_info;
1023 uint8_t session_key[16];
1025 ZERO_STRUCT(session_key);
1026 memcpy(session_key, x->global->signing_key->blob.data,
1027 MIN(x->global->signing_key->blob.length, sizeof(session_key)));
1030 * The application key is truncated/padded to 16 bytes
1032 x->global->application_key = data_blob_talloc(x->global,
1033 session_key,
1034 sizeof(session_key));
1035 ZERO_STRUCT(session_key);
1036 if (x->global->application_key.data == NULL) {
1037 reply_nterror(req, NT_STATUS_NO_MEMORY);
1038 END_PROFILE(SMBtconX);
1039 return;
1042 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1043 NTSTATUS status;
1045 status = smb_key_derivation(x->global->application_key.data,
1046 x->global->application_key.length,
1047 x->global->application_key.data);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 DBG_ERR("smb_key_derivation failed: %s\n",
1050 nt_errstr(status));
1051 return;
1053 optional_support |= SMB_EXTENDED_SIGNATURES;
1057 * Place the application key into the session_info
1059 data_blob_clear_free(&session_info->session_key);
1060 session_info->session_key = data_blob_dup_talloc(session_info,
1061 x->global->application_key);
1062 if (session_info->session_key.data == NULL) {
1063 data_blob_clear_free(&x->global->application_key);
1064 reply_nterror(req, NT_STATUS_NO_MEMORY);
1065 END_PROFILE(SMBtconX);
1066 return;
1068 session_key_updated = true;
1071 conn = make_connection(req, now, service, client_devicetype,
1072 req->vuid, &nt_status);
1073 req->conn =conn;
1075 if (!conn) {
1076 if (session_key_updated) {
1077 struct smbXsrv_session *x = session;
1078 struct auth_session_info *session_info =
1079 session->global->auth_session_info;
1080 data_blob_clear_free(&x->global->application_key);
1081 data_blob_clear_free(&session_info->session_key);
1083 reply_nterror(req, nt_status);
1084 END_PROFILE(SMBtconX);
1085 return;
1088 if ( IS_IPC(conn) )
1089 server_devicetype = "IPC";
1090 else if ( IS_PRINT(conn) )
1091 server_devicetype = "LPT1:";
1092 else
1093 server_devicetype = "A:";
1095 if (get_Protocol() < PROTOCOL_NT1) {
1096 reply_outbuf(req, 2, 0);
1097 if (message_push_string(&req->outbuf, server_devicetype,
1098 STR_TERMINATE|STR_ASCII) == -1) {
1099 reply_nterror(req, NT_STATUS_NO_MEMORY);
1100 END_PROFILE(SMBtconX);
1101 return;
1103 } else {
1104 /* NT sets the fstype of IPC$ to the null string */
1105 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1107 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1108 /* Return permissions. */
1109 uint32_t perm1 = 0;
1110 uint32_t perm2 = 0;
1112 reply_outbuf(req, 7, 0);
1114 if (IS_IPC(conn)) {
1115 perm1 = FILE_ALL_ACCESS;
1116 perm2 = FILE_ALL_ACCESS;
1117 } else {
1118 perm1 = conn->share_access;
1121 SIVAL(req->outbuf, smb_vwv3, perm1);
1122 SIVAL(req->outbuf, smb_vwv5, perm2);
1123 } else {
1124 reply_outbuf(req, 3, 0);
1127 if ((message_push_string(&req->outbuf, server_devicetype,
1128 STR_TERMINATE|STR_ASCII) == -1)
1129 || (message_push_string(&req->outbuf, fstype,
1130 STR_TERMINATE) == -1)) {
1131 reply_nterror(req, NT_STATUS_NO_MEMORY);
1132 END_PROFILE(SMBtconX);
1133 return;
1136 /* what does setting this bit do? It is set by NT4 and
1137 may affect the ability to autorun mounted cdroms */
1138 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1139 optional_support |=
1140 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1142 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1143 DEBUG(2,("Serving %s as a Dfs root\n",
1144 lp_servicename(ctx, SNUM(conn)) ));
1145 optional_support |= SMB_SHARE_IN_DFS;
1148 SSVAL(req->outbuf, smb_vwv2, optional_support);
1151 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1152 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1154 DEBUG(3,("tconX service=%s \n",
1155 service));
1157 /* set the incoming and outgoing tid to the just created one */
1158 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1159 SSVAL(req->outbuf,smb_tid,conn->cnum);
1161 END_PROFILE(SMBtconX);
1163 req->tid = conn->cnum;
1166 /****************************************************************************
1167 Reply to an unknown type.
1168 ****************************************************************************/
1170 void reply_unknown_new(struct smb_request *req, uint8_t type)
1172 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1173 smb_fn_name(type), type, type));
1174 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1175 return;
1178 /****************************************************************************
1179 Reply to an ioctl.
1180 conn POINTER CAN BE NULL HERE !
1181 ****************************************************************************/
1183 void reply_ioctl(struct smb_request *req)
1185 connection_struct *conn = req->conn;
1186 uint16_t device;
1187 uint16_t function;
1188 uint32_t ioctl_code;
1189 int replysize;
1190 char *p;
1192 START_PROFILE(SMBioctl);
1194 if (req->wct < 3) {
1195 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1196 END_PROFILE(SMBioctl);
1197 return;
1200 device = SVAL(req->vwv+1, 0);
1201 function = SVAL(req->vwv+2, 0);
1202 ioctl_code = (device << 16) + function;
1204 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1206 switch (ioctl_code) {
1207 case IOCTL_QUERY_JOB_INFO:
1208 replysize = 32;
1209 break;
1210 default:
1211 reply_force_doserror(req, ERRSRV, ERRnosupport);
1212 END_PROFILE(SMBioctl);
1213 return;
1216 reply_outbuf(req, 8, replysize+1);
1217 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1218 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1219 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1220 p = smb_buf(req->outbuf);
1221 memset(p, '\0', replysize+1); /* valgrind-safe. */
1222 p += 1; /* Allow for alignment */
1224 switch (ioctl_code) {
1225 case IOCTL_QUERY_JOB_INFO:
1227 NTSTATUS status;
1228 size_t len = 0;
1229 files_struct *fsp = file_fsp(
1230 req, SVAL(req->vwv+0, 0));
1231 if (!fsp) {
1232 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1233 END_PROFILE(SMBioctl);
1234 return;
1236 /* Job number */
1237 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1239 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1240 lp_netbios_name(), 15,
1241 STR_TERMINATE|STR_ASCII, &len);
1242 if (!NT_STATUS_IS_OK(status)) {
1243 reply_nterror(req, status);
1244 END_PROFILE(SMBioctl);
1245 return;
1247 if (conn) {
1248 status = srvstr_push((char *)req->outbuf, req->flags2,
1249 p+18,
1250 lp_servicename(talloc_tos(),
1251 SNUM(conn)),
1252 13, STR_TERMINATE|STR_ASCII, &len);
1253 if (!NT_STATUS_IS_OK(status)) {
1254 reply_nterror(req, status);
1255 END_PROFILE(SMBioctl);
1256 return;
1258 } else {
1259 memset(p+18, 0, 13);
1261 break;
1265 END_PROFILE(SMBioctl);
1266 return;
1269 /****************************************************************************
1270 Strange checkpath NTSTATUS mapping.
1271 ****************************************************************************/
1273 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1275 /* Strange DOS error code semantics only for checkpath... */
1276 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1277 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1278 /* We need to map to ERRbadpath */
1279 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1282 return status;
1285 /****************************************************************************
1286 Reply to a checkpath.
1287 ****************************************************************************/
1289 void reply_checkpath(struct smb_request *req)
1291 connection_struct *conn = req->conn;
1292 struct smb_filename *smb_fname = NULL;
1293 char *name = NULL;
1294 NTSTATUS status;
1295 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1296 TALLOC_CTX *ctx = talloc_tos();
1298 START_PROFILE(SMBcheckpath);
1300 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1301 STR_TERMINATE, &status);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 status = map_checkpath_error(req->flags2, status);
1305 reply_nterror(req, status);
1306 END_PROFILE(SMBcheckpath);
1307 return;
1310 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1312 status = filename_convert(ctx,
1313 conn,
1314 name,
1315 ucf_flags,
1316 NULL,
1317 NULL,
1318 &smb_fname);
1320 if (!NT_STATUS_IS_OK(status)) {
1321 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1322 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1323 ERRSRV, ERRbadpath);
1324 END_PROFILE(SMBcheckpath);
1325 return;
1327 goto path_err;
1330 if (!VALID_STAT(smb_fname->st) &&
1331 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1332 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1333 smb_fname_str_dbg(smb_fname), strerror(errno)));
1334 status = map_nt_error_from_unix(errno);
1335 goto path_err;
1338 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1339 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1340 ERRDOS, ERRbadpath);
1341 goto out;
1344 reply_outbuf(req, 0, 0);
1346 path_err:
1347 /* We special case this - as when a Windows machine
1348 is parsing a path is steps through the components
1349 one at a time - if a component fails it expects
1350 ERRbadpath, not ERRbadfile.
1352 status = map_checkpath_error(req->flags2, status);
1353 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1355 * Windows returns different error codes if
1356 * the parent directory is valid but not the
1357 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1358 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1359 * if the path is invalid.
1361 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1362 ERRDOS, ERRbadpath);
1363 goto out;
1366 reply_nterror(req, status);
1368 out:
1369 TALLOC_FREE(smb_fname);
1370 END_PROFILE(SMBcheckpath);
1371 return;
1374 /****************************************************************************
1375 Reply to a getatr.
1376 ****************************************************************************/
1378 void reply_getatr(struct smb_request *req)
1380 connection_struct *conn = req->conn;
1381 struct smb_filename *smb_fname = NULL;
1382 char *fname = NULL;
1383 int mode=0;
1384 off_t size=0;
1385 time_t mtime=0;
1386 const char *p;
1387 NTSTATUS status;
1388 TALLOC_CTX *ctx = talloc_tos();
1389 bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1391 START_PROFILE(SMBgetatr);
1393 p = (const char *)req->buf + 1;
1394 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1395 if (!NT_STATUS_IS_OK(status)) {
1396 reply_nterror(req, status);
1397 goto out;
1400 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1401 under WfWg - weird! */
1402 if (*fname == '\0') {
1403 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1404 if (!CAN_WRITE(conn)) {
1405 mode |= FILE_ATTRIBUTE_READONLY;
1407 size = 0;
1408 mtime = 0;
1409 } else {
1410 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1411 status = filename_convert(ctx,
1412 conn,
1413 fname,
1414 ucf_flags,
1415 NULL,
1416 NULL,
1417 &smb_fname);
1418 if (!NT_STATUS_IS_OK(status)) {
1419 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1420 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1421 ERRSRV, ERRbadpath);
1422 goto out;
1424 reply_nterror(req, status);
1425 goto out;
1427 if (!VALID_STAT(smb_fname->st) &&
1428 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1429 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1430 smb_fname_str_dbg(smb_fname),
1431 strerror(errno)));
1432 reply_nterror(req, map_nt_error_from_unix(errno));
1433 goto out;
1436 mode = dos_mode(conn, smb_fname);
1437 size = smb_fname->st.st_ex_size;
1439 if (ask_sharemode) {
1440 struct timespec write_time_ts;
1441 struct file_id fileid;
1443 ZERO_STRUCT(write_time_ts);
1444 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1445 get_file_infos(fileid, 0, NULL, &write_time_ts);
1446 if (!null_timespec(write_time_ts)) {
1447 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1451 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1452 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1453 size = 0;
1457 reply_outbuf(req, 10, 0);
1459 SSVAL(req->outbuf,smb_vwv0,mode);
1460 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1461 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1462 } else {
1463 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1465 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1467 if (get_Protocol() >= PROTOCOL_NT1) {
1468 SSVAL(req->outbuf, smb_flg2,
1469 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1472 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1473 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1475 out:
1476 TALLOC_FREE(smb_fname);
1477 TALLOC_FREE(fname);
1478 END_PROFILE(SMBgetatr);
1479 return;
1482 /****************************************************************************
1483 Reply to a setatr.
1484 ****************************************************************************/
1486 void reply_setatr(struct smb_request *req)
1488 struct smb_file_time ft;
1489 connection_struct *conn = req->conn;
1490 struct smb_filename *smb_fname = NULL;
1491 char *fname = NULL;
1492 int mode;
1493 time_t mtime;
1494 const char *p;
1495 NTSTATUS status;
1496 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1497 TALLOC_CTX *ctx = talloc_tos();
1499 START_PROFILE(SMBsetatr);
1501 if (req->wct < 2) {
1502 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1503 goto out;
1506 p = (const char *)req->buf + 1;
1507 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1508 if (!NT_STATUS_IS_OK(status)) {
1509 reply_nterror(req, status);
1510 goto out;
1513 status = filename_convert(ctx,
1514 conn,
1515 fname,
1516 ucf_flags,
1517 NULL,
1518 NULL,
1519 &smb_fname);
1520 if (!NT_STATUS_IS_OK(status)) {
1521 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1522 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1523 ERRSRV, ERRbadpath);
1524 goto out;
1526 reply_nterror(req, status);
1527 goto out;
1530 if (ISDOT(smb_fname->base_name)) {
1532 * Not sure here is the right place to catch this
1533 * condition. Might be moved to somewhere else later -- vl
1535 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1536 goto out;
1539 mode = SVAL(req->vwv+0, 0);
1540 mtime = srv_make_unix_date3(req->vwv+1);
1542 if (mode != FILE_ATTRIBUTE_NORMAL) {
1543 if (VALID_STAT_OF_DIR(smb_fname->st))
1544 mode |= FILE_ATTRIBUTE_DIRECTORY;
1545 else
1546 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1548 status = smbd_check_access_rights(
1549 conn, smb_fname, false, FILE_WRITE_ATTRIBUTES);
1550 if (!NT_STATUS_IS_OK(status)) {
1551 reply_nterror(req, status);
1552 goto out;
1555 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1556 false) != 0) {
1557 reply_nterror(req, map_nt_error_from_unix(errno));
1558 goto out;
1562 ft = (struct smb_file_time) {
1563 .mtime = convert_time_t_to_timespec(mtime)
1566 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1567 if (!NT_STATUS_IS_OK(status)) {
1568 reply_nterror(req, status);
1569 goto out;
1572 reply_outbuf(req, 0, 0);
1574 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1575 mode));
1576 out:
1577 TALLOC_FREE(smb_fname);
1578 END_PROFILE(SMBsetatr);
1579 return;
1582 /****************************************************************************
1583 Reply to a dskattr.
1584 ****************************************************************************/
1586 void reply_dskattr(struct smb_request *req)
1588 connection_struct *conn = req->conn;
1589 uint64_t ret;
1590 uint64_t dfree,dsize,bsize;
1591 struct smb_filename smb_fname;
1592 START_PROFILE(SMBdskattr);
1594 ZERO_STRUCT(smb_fname);
1595 smb_fname.base_name = discard_const_p(char, ".");
1597 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1598 reply_nterror(req, map_nt_error_from_unix(errno));
1599 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1600 END_PROFILE(SMBdskattr);
1601 return;
1604 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1605 if (ret == (uint64_t)-1) {
1606 reply_nterror(req, map_nt_error_from_unix(errno));
1607 END_PROFILE(SMBdskattr);
1608 return;
1612 * Force max to fit in 16 bit fields.
1614 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1615 dfree /= 2;
1616 dsize /= 2;
1617 bsize *= 2;
1618 if (bsize > (WORDMAX*512)) {
1619 bsize = (WORDMAX*512);
1620 if (dsize > WORDMAX)
1621 dsize = WORDMAX;
1622 if (dfree > WORDMAX)
1623 dfree = WORDMAX;
1624 break;
1628 reply_outbuf(req, 5, 0);
1630 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1631 double total_space, free_space;
1632 /* we need to scale this to a number that DOS6 can handle. We
1633 use floating point so we can handle large drives on systems
1634 that don't have 64 bit integers
1636 we end up displaying a maximum of 2G to DOS systems
1638 total_space = dsize * (double)bsize;
1639 free_space = dfree * (double)bsize;
1641 dsize = (uint64_t)((total_space+63*512) / (64*512));
1642 dfree = (uint64_t)((free_space+63*512) / (64*512));
1644 if (dsize > 0xFFFF) dsize = 0xFFFF;
1645 if (dfree > 0xFFFF) dfree = 0xFFFF;
1647 SSVAL(req->outbuf,smb_vwv0,dsize);
1648 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1649 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1650 SSVAL(req->outbuf,smb_vwv3,dfree);
1651 } else {
1652 SSVAL(req->outbuf,smb_vwv0,dsize);
1653 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1654 SSVAL(req->outbuf,smb_vwv2,512);
1655 SSVAL(req->outbuf,smb_vwv3,dfree);
1658 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1660 END_PROFILE(SMBdskattr);
1661 return;
1665 * Utility function to split the filename from the directory.
1667 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1668 char **fname_dir_out,
1669 char **fname_mask_out)
1671 const char *p = NULL;
1672 char *fname_dir = NULL;
1673 char *fname_mask = NULL;
1675 p = strrchr_m(fname_in, '/');
1676 if (!p) {
1677 fname_dir = talloc_strdup(ctx, ".");
1678 fname_mask = talloc_strdup(ctx, fname_in);
1679 } else {
1680 fname_dir = talloc_strndup(ctx, fname_in,
1681 PTR_DIFF(p, fname_in));
1682 fname_mask = talloc_strdup(ctx, p+1);
1685 if (!fname_dir || !fname_mask) {
1686 TALLOC_FREE(fname_dir);
1687 TALLOC_FREE(fname_mask);
1688 return NT_STATUS_NO_MEMORY;
1691 *fname_dir_out = fname_dir;
1692 *fname_mask_out = fname_mask;
1693 return NT_STATUS_OK;
1696 /****************************************************************************
1697 Make a dir struct.
1698 ****************************************************************************/
1700 static bool make_dir_struct(TALLOC_CTX *ctx,
1701 char *buf,
1702 const char *mask,
1703 const char *fname,
1704 off_t size,
1705 uint32_t mode,
1706 time_t date,
1707 bool uc)
1709 char *p;
1710 char *mask2 = talloc_strdup(ctx, mask);
1712 if (!mask2) {
1713 return False;
1716 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1717 size = 0;
1720 memset(buf+1,' ',11);
1721 if ((p = strchr_m(mask2,'.')) != NULL) {
1722 *p = 0;
1723 push_ascii(buf+1,mask2,8, 0);
1724 push_ascii(buf+9,p+1,3, 0);
1725 *p = '.';
1726 } else {
1727 push_ascii(buf+1,mask2,11, 0);
1730 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1731 SCVAL(buf,21,mode);
1732 srv_put_dos_date(buf,22,date);
1733 SSVAL(buf,26,size & 0xFFFF);
1734 SSVAL(buf,28,(size >> 16)&0xFFFF);
1735 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1736 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1737 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1738 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1739 return True;
1742 /****************************************************************************
1743 Reply to a search.
1744 Can be called from SMBsearch, SMBffirst or SMBfunique.
1745 ****************************************************************************/
1747 void reply_search(struct smb_request *req)
1749 connection_struct *conn = req->conn;
1750 char *path = NULL;
1751 char *mask = NULL;
1752 char *directory = NULL;
1753 struct smb_filename *smb_fname = NULL;
1754 char *fname = NULL;
1755 off_t size;
1756 uint32_t mode;
1757 struct timespec date;
1758 uint32_t dirtype;
1759 unsigned int numentries = 0;
1760 unsigned int maxentries = 0;
1761 bool finished = False;
1762 const char *p;
1763 int status_len;
1764 char status[21];
1765 int dptr_num= -1;
1766 bool check_descend = False;
1767 bool expect_close = False;
1768 NTSTATUS nt_status;
1769 bool mask_contains_wcard = False;
1770 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1771 TALLOC_CTX *ctx = talloc_tos();
1772 bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
1773 struct smbXsrv_connection *xconn = req->xconn;
1774 struct smbd_server_connection *sconn = req->sconn;
1775 files_struct *fsp = NULL;
1777 START_PROFILE(SMBsearch);
1779 if (req->wct < 2) {
1780 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1781 goto out;
1784 if (req->posix_pathnames) {
1785 reply_unknown_new(req, req->cmd);
1786 goto out;
1789 /* If we were called as SMBffirst then we must expect close. */
1790 if(req->cmd == SMBffirst) {
1791 expect_close = True;
1794 reply_outbuf(req, 1, 3);
1795 maxentries = SVAL(req->vwv+0, 0);
1796 dirtype = SVAL(req->vwv+1, 0);
1797 p = (const char *)req->buf + 1;
1798 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1799 &nt_status, &mask_contains_wcard);
1800 if (!NT_STATUS_IS_OK(nt_status)) {
1801 reply_nterror(req, nt_status);
1802 goto out;
1805 if (smbreq_bufrem(req, p) < 3) {
1806 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1807 goto out;
1810 p++;
1811 status_len = SVAL(p, 0);
1812 p += 2;
1814 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1816 if (status_len == 0) {
1817 int ret;
1818 struct smb_filename *smb_dname = NULL;
1819 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1820 ucf_flags_from_smb_request(req);
1821 nt_status = filename_convert(ctx, conn,
1822 path,
1823 ucf_flags,
1824 NULL,
1825 &mask_contains_wcard,
1826 &smb_fname);
1827 if (!NT_STATUS_IS_OK(nt_status)) {
1828 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1829 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1830 ERRSRV, ERRbadpath);
1831 goto out;
1833 reply_nterror(req, nt_status);
1834 goto out;
1837 directory = smb_fname->base_name;
1839 p = strrchr_m(directory,'/');
1840 if ((p != NULL) && (*directory != '/')) {
1841 mask = talloc_strdup(ctx, p + 1);
1842 directory = talloc_strndup(ctx, directory,
1843 PTR_DIFF(p, directory));
1844 } else {
1845 mask = talloc_strdup(ctx, directory);
1846 directory = talloc_strdup(ctx,".");
1849 if (!directory) {
1850 reply_nterror(req, NT_STATUS_NO_MEMORY);
1851 goto out;
1854 memset((char *)status,'\0',21);
1855 SCVAL(status,0,(dirtype & 0x1F));
1857 smb_dname = synthetic_smb_fname(talloc_tos(),
1858 directory,
1859 NULL,
1860 NULL,
1861 smb_fname->flags);
1862 if (smb_dname == NULL) {
1863 reply_nterror(req, NT_STATUS_NO_MEMORY);
1864 goto out;
1868 * As we've cut off the last component from
1869 * smb_fname we need to re-stat smb_dname
1870 * so FILE_OPEN disposition knows the directory
1871 * exists.
1873 if (req->posix_pathnames) {
1874 ret = SMB_VFS_LSTAT(conn, smb_dname);
1875 } else {
1876 ret = SMB_VFS_STAT(conn, smb_dname);
1878 if (ret == -1) {
1879 nt_status = map_nt_error_from_unix(errno);
1880 reply_nterror(req, nt_status);
1881 goto out;
1885 * Open an fsp on this directory for the dptr.
1887 nt_status = SMB_VFS_CREATE_FILE(
1888 conn, /* conn */
1889 req, /* req */
1890 0, /* root_dir_fid */
1891 smb_dname, /* dname */
1892 FILE_LIST_DIRECTORY, /* access_mask */
1893 FILE_SHARE_READ|
1894 FILE_SHARE_WRITE, /* share_access */
1895 FILE_OPEN, /* create_disposition*/
1896 FILE_DIRECTORY_FILE, /* create_options */
1897 FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1898 NO_OPLOCK, /* oplock_request */
1899 NULL, /* lease */
1900 0, /* allocation_size */
1901 0, /* private_flags */
1902 NULL, /* sd */
1903 NULL, /* ea_list */
1904 &fsp, /* result */
1905 NULL, /* pinfo */
1906 NULL, /* in_context */
1907 NULL);/* out_context */
1909 if (!NT_STATUS_IS_OK(nt_status)) {
1910 DBG_ERR("failed to open directory %s\n",
1911 smb_fname_str_dbg(smb_dname));
1912 reply_nterror(req, nt_status);
1913 goto out;
1916 nt_status = dptr_create(conn,
1917 NULL, /* req */
1918 fsp, /* fsp */
1919 True,
1920 expect_close,
1921 req->smbpid,
1922 mask,
1923 mask_contains_wcard,
1924 dirtype,
1925 &fsp->dptr);
1927 TALLOC_FREE(smb_dname);
1929 if (!NT_STATUS_IS_OK(nt_status)) {
1931 * Use NULL here for the first parameter (req)
1932 * as this is not a client visible handle so
1933 * can'tbe part of an SMB1 chain.
1935 close_file(NULL, fsp, NORMAL_CLOSE);
1936 fsp = NULL;
1937 reply_nterror(req, nt_status);
1938 goto out;
1941 dptr_num = dptr_dnum(fsp->dptr);
1943 } else {
1944 int status_dirtype;
1945 const char *dirpath;
1947 if (smbreq_bufrem(req, p) < 21) {
1948 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1949 goto out;
1952 memcpy(status,p,21);
1953 status_dirtype = CVAL(status,0) & 0x1F;
1954 if (status_dirtype != (dirtype & 0x1F)) {
1955 dirtype = status_dirtype;
1958 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
1959 if (fsp == NULL) {
1960 goto SearchEmpty;
1962 dirpath = dptr_path(sconn, dptr_num);
1963 directory = talloc_strdup(ctx, dirpath);
1964 if (!directory) {
1965 reply_nterror(req, NT_STATUS_NO_MEMORY);
1966 goto out;
1969 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1970 if (!mask) {
1971 goto SearchEmpty;
1974 * For a 'continue' search we have no string. So
1975 * check from the initial saved string.
1977 if (!req->posix_pathnames) {
1978 mask_contains_wcard = ms_has_wild(mask);
1980 dirtype = dptr_attr(sconn, dptr_num);
1983 DEBUG(4,("dptr_num is %d\n",dptr_num));
1985 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1986 char buf[DIR_STRUCT_SIZE];
1987 memcpy(buf,status,21);
1988 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1989 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1990 reply_nterror(req, NT_STATUS_NO_MEMORY);
1991 goto out;
1993 dptr_fill(sconn, buf+12,dptr_num);
1994 if (dptr_zero(buf+12) && (status_len==0)) {
1995 numentries = 1;
1996 } else {
1997 numentries = 0;
1999 if (message_push_blob(&req->outbuf,
2000 data_blob_const(buf, sizeof(buf)))
2001 == -1) {
2002 reply_nterror(req, NT_STATUS_NO_MEMORY);
2003 goto out;
2005 } else {
2006 unsigned int i;
2007 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
2008 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
2010 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
2012 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2013 directory,lp_dont_descend(ctx, SNUM(conn))));
2014 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
2015 check_descend = True;
2018 for (i=numentries;(i<maxentries) && !finished;i++) {
2019 finished = !get_dir_entry(ctx,
2020 fsp->dptr,
2021 mask,
2022 dirtype,
2023 &fname,
2024 &size,
2025 &mode,
2026 &date,
2027 check_descend,
2028 ask_sharemode);
2029 if (!finished) {
2030 char buf[DIR_STRUCT_SIZE];
2031 memcpy(buf,status,21);
2032 if (!make_dir_struct(ctx,
2033 buf,
2034 mask,
2035 fname,
2036 size,
2037 mode,
2038 convert_timespec_to_time_t(date),
2039 !allow_long_path_components)) {
2040 reply_nterror(req, NT_STATUS_NO_MEMORY);
2041 goto out;
2043 if (!dptr_fill(sconn, buf+12,dptr_num)) {
2044 break;
2046 if (message_push_blob(&req->outbuf,
2047 data_blob_const(buf, sizeof(buf)))
2048 == -1) {
2049 reply_nterror(req, NT_STATUS_NO_MEMORY);
2050 goto out;
2052 numentries++;
2057 SearchEmpty:
2059 /* If we were called as SMBffirst with smb_search_id == NULL
2060 and no entries were found then return error and close fsp->dptr
2061 (X/Open spec) */
2063 if (numentries == 0) {
2064 dptr_num = -1;
2065 if (fsp != NULL) {
2066 close_file(NULL, fsp, NORMAL_CLOSE);
2067 fsp = NULL;
2069 } else if(expect_close && status_len == 0) {
2070 /* Close the dptr - we know it's gone */
2071 dptr_num = -1;
2072 if (fsp != NULL) {
2073 close_file(NULL, fsp, NORMAL_CLOSE);
2074 fsp = NULL;
2078 /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
2079 if(dptr_num >= 0 && req->cmd == SMBfunique) {
2080 dptr_num = -1;
2081 /* fsp may have been closed above. */
2082 if (fsp != NULL) {
2083 close_file(NULL, fsp, NORMAL_CLOSE);
2084 fsp = NULL;
2088 if ((numentries == 0) && !mask_contains_wcard) {
2089 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
2090 goto out;
2093 SSVAL(req->outbuf,smb_vwv0,numentries);
2094 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2095 SCVAL(smb_buf(req->outbuf),0,5);
2096 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2098 /* The replies here are never long name. */
2099 SSVAL(req->outbuf, smb_flg2,
2100 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2101 if (!allow_long_path_components) {
2102 SSVAL(req->outbuf, smb_flg2,
2103 SVAL(req->outbuf, smb_flg2)
2104 & (~FLAGS2_LONG_PATH_COMPONENTS));
2107 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2108 SSVAL(req->outbuf, smb_flg2,
2109 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2111 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2112 smb_fn_name(req->cmd),
2113 mask,
2114 directory,
2115 dirtype,
2116 numentries,
2117 maxentries ));
2118 out:
2119 TALLOC_FREE(directory);
2120 TALLOC_FREE(mask);
2121 TALLOC_FREE(smb_fname);
2122 END_PROFILE(SMBsearch);
2123 return;
2126 /****************************************************************************
2127 Reply to a fclose (stop directory search).
2128 ****************************************************************************/
2130 void reply_fclose(struct smb_request *req)
2132 int status_len;
2133 char status[21];
2134 int dptr_num= -2;
2135 const char *p;
2136 char *path = NULL;
2137 NTSTATUS err;
2138 bool path_contains_wcard = False;
2139 TALLOC_CTX *ctx = talloc_tos();
2140 struct smbd_server_connection *sconn = req->sconn;
2141 files_struct *fsp = NULL;
2143 START_PROFILE(SMBfclose);
2145 if (req->posix_pathnames) {
2146 reply_unknown_new(req, req->cmd);
2147 END_PROFILE(SMBfclose);
2148 return;
2151 p = (const char *)req->buf + 1;
2152 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2153 &err, &path_contains_wcard);
2154 if (!NT_STATUS_IS_OK(err)) {
2155 reply_nterror(req, err);
2156 END_PROFILE(SMBfclose);
2157 return;
2160 if (smbreq_bufrem(req, p) < 3) {
2161 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2162 END_PROFILE(SMBfclose);
2163 return;
2166 p++;
2167 status_len = SVAL(p,0);
2168 p += 2;
2170 if (status_len == 0) {
2171 reply_force_doserror(req, ERRSRV, ERRsrverror);
2172 END_PROFILE(SMBfclose);
2173 return;
2176 if (smbreq_bufrem(req, p) < 21) {
2177 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2178 END_PROFILE(SMBfclose);
2179 return;
2182 memcpy(status,p,21);
2184 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
2185 if(fsp != NULL) {
2186 /* Close the file - we know it's gone */
2187 close_file(NULL, fsp, NORMAL_CLOSE);
2188 fsp = NULL;
2189 dptr_num = -1;
2192 reply_outbuf(req, 1, 0);
2193 SSVAL(req->outbuf,smb_vwv0,0);
2195 DEBUG(3,("search close\n"));
2197 END_PROFILE(SMBfclose);
2198 return;
2201 /****************************************************************************
2202 Reply to an open.
2203 ****************************************************************************/
2205 void reply_open(struct smb_request *req)
2207 connection_struct *conn = req->conn;
2208 struct smb_filename *smb_fname = NULL;
2209 char *fname = NULL;
2210 uint32_t fattr=0;
2211 off_t size = 0;
2212 time_t mtime=0;
2213 int info;
2214 files_struct *fsp;
2215 int oplock_request;
2216 int deny_mode;
2217 uint32_t dos_attr;
2218 uint32_t access_mask;
2219 uint32_t share_mode;
2220 uint32_t create_disposition;
2221 uint32_t create_options = 0;
2222 uint32_t private_flags = 0;
2223 NTSTATUS status;
2224 uint32_t ucf_flags;
2225 TALLOC_CTX *ctx = talloc_tos();
2227 START_PROFILE(SMBopen);
2229 if (req->wct < 2) {
2230 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2231 goto out;
2234 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2235 deny_mode = SVAL(req->vwv+0, 0);
2236 dos_attr = SVAL(req->vwv+1, 0);
2238 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2239 STR_TERMINATE, &status);
2240 if (!NT_STATUS_IS_OK(status)) {
2241 reply_nterror(req, status);
2242 goto out;
2245 if (!map_open_params_to_ntcreate(fname, deny_mode,
2246 OPENX_FILE_EXISTS_OPEN, &access_mask,
2247 &share_mode, &create_disposition,
2248 &create_options, &private_flags)) {
2249 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2250 goto out;
2253 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2255 status = filename_convert(ctx,
2256 conn,
2257 fname,
2258 ucf_flags,
2259 NULL,
2260 NULL,
2261 &smb_fname);
2262 if (!NT_STATUS_IS_OK(status)) {
2263 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2264 reply_botherror(req,
2265 NT_STATUS_PATH_NOT_COVERED,
2266 ERRSRV, ERRbadpath);
2267 goto out;
2269 reply_nterror(req, status);
2270 goto out;
2273 status = SMB_VFS_CREATE_FILE(
2274 conn, /* conn */
2275 req, /* req */
2276 0, /* root_dir_fid */
2277 smb_fname, /* fname */
2278 access_mask, /* access_mask */
2279 share_mode, /* share_access */
2280 create_disposition, /* create_disposition*/
2281 create_options, /* create_options */
2282 dos_attr, /* file_attributes */
2283 oplock_request, /* oplock_request */
2284 NULL, /* lease */
2285 0, /* allocation_size */
2286 private_flags,
2287 NULL, /* sd */
2288 NULL, /* ea_list */
2289 &fsp, /* result */
2290 &info, /* pinfo */
2291 NULL, NULL); /* create context */
2293 if (!NT_STATUS_IS_OK(status)) {
2294 if (open_was_deferred(req->xconn, req->mid)) {
2295 /* We have re-scheduled this call. */
2296 goto out;
2299 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2300 reply_openerror(req, status);
2301 goto out;
2304 fsp = fcb_or_dos_open(
2305 req,
2306 smb_fname,
2307 access_mask,
2308 create_options,
2309 private_flags);
2310 if (fsp == NULL) {
2311 bool ok = defer_smb1_sharing_violation(req);
2312 if (ok) {
2313 goto out;
2315 reply_openerror(req, status);
2316 goto out;
2320 /* Ensure we're pointing at the correct stat struct. */
2321 TALLOC_FREE(smb_fname);
2322 smb_fname = fsp->fsp_name;
2324 size = smb_fname->st.st_ex_size;
2325 fattr = dos_mode(conn, smb_fname);
2327 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2329 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2330 DEBUG(3,("attempt to open a directory %s\n",
2331 fsp_str_dbg(fsp)));
2332 close_file(req, fsp, ERROR_CLOSE);
2333 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2334 ERRDOS, ERRnoaccess);
2335 goto out;
2338 reply_outbuf(req, 7, 0);
2339 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2340 SSVAL(req->outbuf,smb_vwv1,fattr);
2341 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2342 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2343 } else {
2344 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2346 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2347 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2349 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2350 SCVAL(req->outbuf,smb_flg,
2351 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2354 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2355 SCVAL(req->outbuf,smb_flg,
2356 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2358 out:
2359 END_PROFILE(SMBopen);
2360 return;
2363 /****************************************************************************
2364 Reply to an open and X.
2365 ****************************************************************************/
2367 void reply_open_and_X(struct smb_request *req)
2369 connection_struct *conn = req->conn;
2370 struct smb_filename *smb_fname = NULL;
2371 char *fname = NULL;
2372 uint16_t open_flags;
2373 int deny_mode;
2374 uint32_t smb_attr;
2375 /* Breakout the oplock request bits so we can set the
2376 reply bits separately. */
2377 int ex_oplock_request;
2378 int core_oplock_request;
2379 int oplock_request;
2380 #if 0
2381 int smb_sattr = SVAL(req->vwv+4, 0);
2382 uint32_t smb_time = make_unix_date3(req->vwv+6);
2383 #endif
2384 int smb_ofun;
2385 uint32_t fattr=0;
2386 int mtime=0;
2387 int smb_action = 0;
2388 files_struct *fsp;
2389 NTSTATUS status;
2390 uint64_t allocation_size;
2391 ssize_t retval = -1;
2392 uint32_t access_mask;
2393 uint32_t share_mode;
2394 uint32_t create_disposition;
2395 uint32_t create_options = 0;
2396 uint32_t private_flags = 0;
2397 uint32_t ucf_flags;
2398 TALLOC_CTX *ctx = talloc_tos();
2400 START_PROFILE(SMBopenX);
2402 if (req->wct < 15) {
2403 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2404 goto out;
2407 open_flags = SVAL(req->vwv+2, 0);
2408 deny_mode = SVAL(req->vwv+3, 0);
2409 smb_attr = SVAL(req->vwv+5, 0);
2410 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2411 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2412 oplock_request = ex_oplock_request | core_oplock_request;
2413 smb_ofun = SVAL(req->vwv+8, 0);
2414 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2416 /* If it's an IPC, pass off the pipe handler. */
2417 if (IS_IPC(conn)) {
2418 if (lp_nt_pipe_support()) {
2419 reply_open_pipe_and_X(conn, req);
2420 } else {
2421 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2423 goto out;
2426 /* XXXX we need to handle passed times, sattr and flags */
2427 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2428 STR_TERMINATE, &status);
2429 if (!NT_STATUS_IS_OK(status)) {
2430 reply_nterror(req, status);
2431 goto out;
2434 if (!map_open_params_to_ntcreate(fname, deny_mode,
2435 smb_ofun,
2436 &access_mask, &share_mode,
2437 &create_disposition,
2438 &create_options,
2439 &private_flags)) {
2440 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2441 goto out;
2444 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2446 status = filename_convert(ctx,
2447 conn,
2448 fname,
2449 ucf_flags,
2450 NULL,
2451 NULL,
2452 &smb_fname);
2453 if (!NT_STATUS_IS_OK(status)) {
2454 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2455 reply_botherror(req,
2456 NT_STATUS_PATH_NOT_COVERED,
2457 ERRSRV, ERRbadpath);
2458 goto out;
2460 reply_nterror(req, status);
2461 goto out;
2464 status = SMB_VFS_CREATE_FILE(
2465 conn, /* conn */
2466 req, /* req */
2467 0, /* root_dir_fid */
2468 smb_fname, /* fname */
2469 access_mask, /* access_mask */
2470 share_mode, /* share_access */
2471 create_disposition, /* create_disposition*/
2472 create_options, /* create_options */
2473 smb_attr, /* file_attributes */
2474 oplock_request, /* oplock_request */
2475 NULL, /* lease */
2476 0, /* allocation_size */
2477 private_flags,
2478 NULL, /* sd */
2479 NULL, /* ea_list */
2480 &fsp, /* result */
2481 &smb_action, /* pinfo */
2482 NULL, NULL); /* create context */
2484 if (!NT_STATUS_IS_OK(status)) {
2485 if (open_was_deferred(req->xconn, req->mid)) {
2486 /* We have re-scheduled this call. */
2487 goto out;
2490 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2491 reply_openerror(req, status);
2492 goto out;
2495 fsp = fcb_or_dos_open(
2496 req,
2497 smb_fname,
2498 access_mask,
2499 create_options,
2500 private_flags);
2501 if (fsp == NULL) {
2502 bool ok = defer_smb1_sharing_violation(req);
2503 if (ok) {
2504 goto out;
2506 reply_openerror(req, status);
2507 goto out;
2511 smb_action = FILE_WAS_OPENED;
2514 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2515 if the file is truncated or created. */
2516 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2517 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2518 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2519 close_file(req, fsp, ERROR_CLOSE);
2520 reply_nterror(req, NT_STATUS_DISK_FULL);
2521 goto out;
2523 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2524 if (retval < 0) {
2525 close_file(req, fsp, ERROR_CLOSE);
2526 reply_nterror(req, NT_STATUS_DISK_FULL);
2527 goto out;
2529 status = vfs_stat_fsp(fsp);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 close_file(req, fsp, ERROR_CLOSE);
2532 reply_nterror(req, status);
2533 goto out;
2537 fattr = dos_mode(conn, fsp->fsp_name);
2538 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2539 close_file(req, fsp, ERROR_CLOSE);
2540 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2541 goto out;
2543 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2545 /* If the caller set the extended oplock request bit
2546 and we granted one (by whatever means) - set the
2547 correct bit for extended oplock reply.
2550 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2551 smb_action |= EXTENDED_OPLOCK_GRANTED;
2554 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2555 smb_action |= EXTENDED_OPLOCK_GRANTED;
2558 /* If the caller set the core oplock request bit
2559 and we granted one (by whatever means) - set the
2560 correct bit for core oplock reply.
2563 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2564 reply_outbuf(req, 19, 0);
2565 } else {
2566 reply_outbuf(req, 15, 0);
2569 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2570 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2572 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2573 SCVAL(req->outbuf, smb_flg,
2574 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2577 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2578 SCVAL(req->outbuf, smb_flg,
2579 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2582 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2583 SSVAL(req->outbuf,smb_vwv3,fattr);
2584 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2585 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2586 } else {
2587 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2589 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2590 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2591 SSVAL(req->outbuf,smb_vwv11,smb_action);
2593 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2594 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2597 out:
2598 TALLOC_FREE(smb_fname);
2599 END_PROFILE(SMBopenX);
2600 return;
2603 /****************************************************************************
2604 Reply to a SMBulogoffX.
2605 ****************************************************************************/
2607 void reply_ulogoffX(struct smb_request *req)
2609 struct smbd_server_connection *sconn = req->sconn;
2610 struct user_struct *vuser;
2611 struct smbXsrv_session *session = NULL;
2612 NTSTATUS status;
2614 START_PROFILE(SMBulogoffX);
2616 vuser = get_valid_user_struct(sconn, req->vuid);
2618 if(vuser == NULL) {
2619 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2620 (unsigned long long)req->vuid));
2622 req->vuid = UID_FIELD_INVALID;
2623 reply_force_doserror(req, ERRSRV, ERRbaduid);
2624 END_PROFILE(SMBulogoffX);
2625 return;
2628 session = vuser->session;
2629 vuser = NULL;
2632 * TODO: cancel all outstanding requests on the session
2634 status = smbXsrv_session_logoff(session);
2635 if (!NT_STATUS_IS_OK(status)) {
2636 DEBUG(0, ("reply_ulogoff: "
2637 "smbXsrv_session_logoff() failed: %s\n",
2638 nt_errstr(status)));
2640 * If we hit this case, there is something completely
2641 * wrong, so we better disconnect the transport connection.
2643 END_PROFILE(SMBulogoffX);
2644 exit_server(__location__ ": smbXsrv_session_logoff failed");
2645 return;
2648 TALLOC_FREE(session);
2650 reply_outbuf(req, 2, 0);
2651 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2652 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2654 DEBUG(3, ("ulogoffX vuid=%llu\n",
2655 (unsigned long long)req->vuid));
2657 END_PROFILE(SMBulogoffX);
2658 req->vuid = UID_FIELD_INVALID;
2661 /****************************************************************************
2662 Reply to a mknew or a create.
2663 ****************************************************************************/
2665 void reply_mknew(struct smb_request *req)
2667 connection_struct *conn = req->conn;
2668 struct smb_filename *smb_fname = NULL;
2669 char *fname = NULL;
2670 uint32_t fattr = 0;
2671 struct smb_file_time ft;
2672 files_struct *fsp;
2673 int oplock_request = 0;
2674 NTSTATUS status;
2675 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2676 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2677 uint32_t create_disposition;
2678 uint32_t create_options = 0;
2679 uint32_t ucf_flags;
2680 TALLOC_CTX *ctx = talloc_tos();
2682 START_PROFILE(SMBcreate);
2683 ZERO_STRUCT(ft);
2685 if (req->wct < 3) {
2686 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2687 goto out;
2690 fattr = SVAL(req->vwv+0, 0);
2691 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2693 if (req->cmd == SMBmknew) {
2694 /* We should fail if file exists. */
2695 create_disposition = FILE_CREATE;
2696 } else {
2697 /* Create if file doesn't exist, truncate if it does. */
2698 create_disposition = FILE_OVERWRITE_IF;
2701 /* mtime. */
2702 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2704 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2705 STR_TERMINATE, &status);
2706 if (!NT_STATUS_IS_OK(status)) {
2707 reply_nterror(req, status);
2708 goto out;
2711 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2712 status = filename_convert(ctx,
2713 conn,
2714 fname,
2715 ucf_flags,
2716 NULL,
2717 NULL,
2718 &smb_fname);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2721 reply_botherror(req,
2722 NT_STATUS_PATH_NOT_COVERED,
2723 ERRSRV, ERRbadpath);
2724 goto out;
2726 reply_nterror(req, status);
2727 goto out;
2730 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2731 DEBUG(0,("Attempt to create file (%s) with volid set - "
2732 "please report this\n",
2733 smb_fname_str_dbg(smb_fname)));
2736 status = SMB_VFS_CREATE_FILE(
2737 conn, /* conn */
2738 req, /* req */
2739 0, /* root_dir_fid */
2740 smb_fname, /* fname */
2741 access_mask, /* access_mask */
2742 share_mode, /* share_access */
2743 create_disposition, /* create_disposition*/
2744 create_options, /* create_options */
2745 fattr, /* file_attributes */
2746 oplock_request, /* oplock_request */
2747 NULL, /* lease */
2748 0, /* allocation_size */
2749 0, /* private_flags */
2750 NULL, /* sd */
2751 NULL, /* ea_list */
2752 &fsp, /* result */
2753 NULL, /* pinfo */
2754 NULL, NULL); /* create context */
2756 if (!NT_STATUS_IS_OK(status)) {
2757 if (open_was_deferred(req->xconn, req->mid)) {
2758 /* We have re-scheduled this call. */
2759 goto out;
2761 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2762 bool ok = defer_smb1_sharing_violation(req);
2763 if (ok) {
2764 goto out;
2767 reply_openerror(req, status);
2768 goto out;
2771 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2772 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2773 if (!NT_STATUS_IS_OK(status)) {
2774 END_PROFILE(SMBcreate);
2775 goto out;
2778 reply_outbuf(req, 1, 0);
2779 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2781 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2782 SCVAL(req->outbuf,smb_flg,
2783 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2786 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2787 SCVAL(req->outbuf,smb_flg,
2788 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2791 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2792 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2793 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2794 (unsigned int)fattr));
2796 out:
2797 TALLOC_FREE(smb_fname);
2798 END_PROFILE(SMBcreate);
2799 return;
2802 /****************************************************************************
2803 Reply to a create temporary file.
2804 ****************************************************************************/
2806 void reply_ctemp(struct smb_request *req)
2808 connection_struct *conn = req->conn;
2809 struct smb_filename *smb_fname = NULL;
2810 char *wire_name = NULL;
2811 char *fname = NULL;
2812 uint32_t fattr;
2813 files_struct *fsp;
2814 int oplock_request;
2815 char *s;
2816 NTSTATUS status;
2817 int i;
2818 uint32_t ucf_flags;
2819 TALLOC_CTX *ctx = talloc_tos();
2821 START_PROFILE(SMBctemp);
2823 if (req->wct < 3) {
2824 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2825 goto out;
2828 fattr = SVAL(req->vwv+0, 0);
2829 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2831 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2832 STR_TERMINATE, &status);
2833 if (!NT_STATUS_IS_OK(status)) {
2834 reply_nterror(req, status);
2835 goto out;
2838 for (i = 0; i < 10; i++) {
2839 if (*wire_name) {
2840 fname = talloc_asprintf(ctx,
2841 "%s/TMP%s",
2842 wire_name,
2843 generate_random_str_list(ctx, 5, "0123456789"));
2844 } else {
2845 fname = talloc_asprintf(ctx,
2846 "TMP%s",
2847 generate_random_str_list(ctx, 5, "0123456789"));
2850 if (!fname) {
2851 reply_nterror(req, NT_STATUS_NO_MEMORY);
2852 goto out;
2855 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2856 status = filename_convert(ctx, conn,
2857 fname,
2858 ucf_flags,
2859 NULL,
2860 NULL,
2861 &smb_fname);
2862 if (!NT_STATUS_IS_OK(status)) {
2863 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2864 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2865 ERRSRV, ERRbadpath);
2866 goto out;
2868 reply_nterror(req, status);
2869 goto out;
2872 /* Create the file. */
2873 status = SMB_VFS_CREATE_FILE(
2874 conn, /* conn */
2875 req, /* req */
2876 0, /* root_dir_fid */
2877 smb_fname, /* fname */
2878 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2879 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2880 FILE_CREATE, /* create_disposition*/
2881 0, /* create_options */
2882 fattr, /* file_attributes */
2883 oplock_request, /* oplock_request */
2884 NULL, /* lease */
2885 0, /* allocation_size */
2886 0, /* private_flags */
2887 NULL, /* sd */
2888 NULL, /* ea_list */
2889 &fsp, /* result */
2890 NULL, /* pinfo */
2891 NULL, NULL); /* create context */
2893 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2894 TALLOC_FREE(fname);
2895 TALLOC_FREE(smb_fname);
2896 continue;
2899 if (!NT_STATUS_IS_OK(status)) {
2900 if (open_was_deferred(req->xconn, req->mid)) {
2901 /* We have re-scheduled this call. */
2902 goto out;
2904 if (NT_STATUS_EQUAL(
2905 status, NT_STATUS_SHARING_VIOLATION)) {
2906 bool ok = defer_smb1_sharing_violation(req);
2907 if (ok) {
2908 goto out;
2911 reply_openerror(req, status);
2912 goto out;
2915 break;
2918 if (i == 10) {
2919 /* Collision after 10 times... */
2920 reply_nterror(req, status);
2921 goto out;
2924 reply_outbuf(req, 1, 0);
2925 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2927 /* the returned filename is relative to the directory */
2928 s = strrchr_m(fsp->fsp_name->base_name, '/');
2929 if (!s) {
2930 s = fsp->fsp_name->base_name;
2931 } else {
2932 s++;
2935 #if 0
2936 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2937 thing in the byte section. JRA */
2938 SSVALS(p, 0, -1); /* what is this? not in spec */
2939 #endif
2940 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2941 == -1) {
2942 reply_nterror(req, NT_STATUS_NO_MEMORY);
2943 goto out;
2946 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2947 SCVAL(req->outbuf, smb_flg,
2948 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2951 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2952 SCVAL(req->outbuf, smb_flg,
2953 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2956 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2957 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2958 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2959 out:
2960 TALLOC_FREE(smb_fname);
2961 TALLOC_FREE(wire_name);
2962 END_PROFILE(SMBctemp);
2963 return;
2966 /*******************************************************************
2967 Check if a user is allowed to rename a file.
2968 ********************************************************************/
2970 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2971 uint16_t dirtype)
2973 if (!CAN_WRITE(conn)) {
2974 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2977 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2978 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2979 /* Only bother to read the DOS attribute if we might deny the
2980 rename on the grounds of attribute mismatch. */
2981 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2982 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2983 return NT_STATUS_NO_SUCH_FILE;
2987 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2988 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2989 return NT_STATUS_OK;
2992 /* If no pathnames are open below this
2993 directory, allow the rename. */
2995 if (lp_strict_rename(SNUM(conn))) {
2997 * Strict rename, check open file db.
2999 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
3000 return NT_STATUS_ACCESS_DENIED;
3002 } else if (file_find_subpath(fsp)) {
3004 * No strict rename, just look in local process.
3006 return NT_STATUS_ACCESS_DENIED;
3008 return NT_STATUS_OK;
3011 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
3012 return NT_STATUS_OK;
3015 return NT_STATUS_ACCESS_DENIED;
3018 /*******************************************************************
3019 * unlink a file with all relevant access checks
3020 *******************************************************************/
3022 static NTSTATUS do_unlink(connection_struct *conn,
3023 struct smb_request *req,
3024 struct smb_filename *smb_fname,
3025 uint32_t dirtype)
3027 uint32_t fattr;
3028 files_struct *fsp;
3029 uint32_t dirtype_orig = dirtype;
3030 NTSTATUS status;
3031 int ret;
3032 bool posix_paths = (req != NULL && req->posix_pathnames);
3034 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
3035 smb_fname_str_dbg(smb_fname),
3036 dirtype));
3038 if (!CAN_WRITE(conn)) {
3039 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3042 if (posix_paths) {
3043 ret = SMB_VFS_LSTAT(conn, smb_fname);
3044 } else {
3045 ret = SMB_VFS_STAT(conn, smb_fname);
3047 if (ret != 0) {
3048 return map_nt_error_from_unix(errno);
3051 fattr = dos_mode(conn, smb_fname);
3053 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
3054 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
3057 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
3058 if (!dirtype) {
3059 return NT_STATUS_NO_SUCH_FILE;
3062 if (!dir_check_ftype(fattr, dirtype)) {
3063 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3064 return NT_STATUS_FILE_IS_A_DIRECTORY;
3066 return NT_STATUS_NO_SUCH_FILE;
3069 if (dirtype_orig & 0x8000) {
3070 /* These will never be set for POSIX. */
3071 return NT_STATUS_NO_SUCH_FILE;
3074 #if 0
3075 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
3076 return NT_STATUS_FILE_IS_A_DIRECTORY;
3079 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
3080 return NT_STATUS_NO_SUCH_FILE;
3083 if (dirtype & 0xFF00) {
3084 /* These will never be set for POSIX. */
3085 return NT_STATUS_NO_SUCH_FILE;
3088 dirtype &= 0xFF;
3089 if (!dirtype) {
3090 return NT_STATUS_NO_SUCH_FILE;
3093 /* Can't delete a directory. */
3094 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
3095 return NT_STATUS_FILE_IS_A_DIRECTORY;
3097 #endif
3099 #if 0 /* JRATEST */
3100 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
3101 return NT_STATUS_OBJECT_NAME_INVALID;
3102 #endif /* JRATEST */
3104 /* On open checks the open itself will check the share mode, so
3105 don't do it here as we'll get it wrong. */
3107 status = SMB_VFS_CREATE_FILE
3108 (conn, /* conn */
3109 req, /* req */
3110 0, /* root_dir_fid */
3111 smb_fname, /* fname */
3112 DELETE_ACCESS, /* access_mask */
3113 FILE_SHARE_NONE, /* share_access */
3114 FILE_OPEN, /* create_disposition*/
3115 FILE_NON_DIRECTORY_FILE, /* create_options */
3116 /* file_attributes */
3117 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
3118 FILE_ATTRIBUTE_NORMAL,
3119 0, /* oplock_request */
3120 NULL, /* lease */
3121 0, /* allocation_size */
3122 0, /* private_flags */
3123 NULL, /* sd */
3124 NULL, /* ea_list */
3125 &fsp, /* result */
3126 NULL, /* pinfo */
3127 NULL, NULL); /* create context */
3129 if (!NT_STATUS_IS_OK(status)) {
3130 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
3131 nt_errstr(status)));
3132 return status;
3135 status = can_set_delete_on_close(fsp, fattr);
3136 if (!NT_STATUS_IS_OK(status)) {
3137 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
3138 "(%s)\n",
3139 smb_fname_str_dbg(smb_fname),
3140 nt_errstr(status)));
3141 close_file(req, fsp, NORMAL_CLOSE);
3142 return status;
3145 /* The set is across all open files on this dev/inode pair. */
3146 if (!set_delete_on_close(fsp, True,
3147 conn->session_info->security_token,
3148 conn->session_info->unix_token)) {
3149 close_file(req, fsp, NORMAL_CLOSE);
3150 return NT_STATUS_ACCESS_DENIED;
3153 return close_file(req, fsp, NORMAL_CLOSE);
3156 /****************************************************************************
3157 The guts of the unlink command, split out so it may be called by the NT SMB
3158 code.
3159 ****************************************************************************/
3161 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
3162 uint32_t dirtype, struct smb_filename *smb_fname,
3163 bool has_wild)
3165 char *fname_dir = NULL;
3166 char *fname_mask = NULL;
3167 int count=0;
3168 NTSTATUS status = NT_STATUS_OK;
3169 struct smb_filename *smb_fname_dir = NULL;
3170 TALLOC_CTX *ctx = talloc_tos();
3172 /* Split up the directory from the filename/mask. */
3173 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3174 &fname_dir, &fname_mask);
3175 if (!NT_STATUS_IS_OK(status)) {
3176 goto out;
3180 * We should only check the mangled cache
3181 * here if unix_convert failed. This means
3182 * that the path in 'mask' doesn't exist
3183 * on the file system and so we need to look
3184 * for a possible mangle. This patch from
3185 * Tine Smukavec <valentin.smukavec@hermes.si>.
3188 if (!VALID_STAT(smb_fname->st) &&
3189 mangle_is_mangled(fname_mask, conn->params)) {
3190 char *new_mask = NULL;
3191 mangle_lookup_name_from_8_3(ctx, fname_mask,
3192 &new_mask, conn->params);
3193 if (new_mask) {
3194 TALLOC_FREE(fname_mask);
3195 fname_mask = new_mask;
3199 if (!has_wild) {
3202 * Only one file needs to be unlinked. Append the mask back
3203 * onto the directory.
3205 TALLOC_FREE(smb_fname->base_name);
3206 if (ISDOT(fname_dir)) {
3207 /* Ensure we use canonical names on open. */
3208 smb_fname->base_name = talloc_asprintf(smb_fname,
3209 "%s",
3210 fname_mask);
3211 } else {
3212 smb_fname->base_name = talloc_asprintf(smb_fname,
3213 "%s/%s",
3214 fname_dir,
3215 fname_mask);
3217 if (!smb_fname->base_name) {
3218 status = NT_STATUS_NO_MEMORY;
3219 goto out;
3221 if (dirtype == 0) {
3222 dirtype = FILE_ATTRIBUTE_NORMAL;
3225 status = check_name(conn, smb_fname);
3226 if (!NT_STATUS_IS_OK(status)) {
3227 goto out;
3230 status = do_unlink(conn, req, smb_fname, dirtype);
3231 if (!NT_STATUS_IS_OK(status)) {
3232 goto out;
3235 count++;
3236 } else {
3237 struct smb_Dir *dir_hnd = NULL;
3238 long offset = 0;
3239 const char *dname = NULL;
3240 char *talloced = NULL;
3242 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3243 status = NT_STATUS_OBJECT_NAME_INVALID;
3244 goto out;
3246 if (dirtype == 0) {
3247 dirtype = FILE_ATTRIBUTE_NORMAL;
3250 if (strequal(fname_mask,"????????.???")) {
3251 TALLOC_FREE(fname_mask);
3252 fname_mask = talloc_strdup(ctx, "*");
3253 if (!fname_mask) {
3254 status = NT_STATUS_NO_MEMORY;
3255 goto out;
3259 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3260 fname_dir,
3261 NULL,
3262 NULL,
3263 smb_fname->flags);
3264 if (smb_fname_dir == NULL) {
3265 status = NT_STATUS_NO_MEMORY;
3266 goto out;
3269 status = check_name(conn, smb_fname_dir);
3270 if (!NT_STATUS_IS_OK(status)) {
3271 goto out;
3274 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3275 dirtype);
3276 if (dir_hnd == NULL) {
3277 status = map_nt_error_from_unix(errno);
3278 goto out;
3281 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3282 the pattern matches against the long name, otherwise the short name
3283 We don't implement this yet XXXX
3286 status = NT_STATUS_NO_SUCH_FILE;
3288 while ((dname = ReadDirName(dir_hnd, &offset,
3289 &smb_fname->st, &talloced))) {
3290 TALLOC_CTX *frame = talloc_stackframe();
3292 if (!is_visible_file(conn, fname_dir, dname,
3293 &smb_fname->st, true)) {
3294 TALLOC_FREE(frame);
3295 TALLOC_FREE(talloced);
3296 continue;
3299 /* Quick check for "." and ".." */
3300 if (ISDOT(dname) || ISDOTDOT(dname)) {
3301 TALLOC_FREE(frame);
3302 TALLOC_FREE(talloced);
3303 continue;
3306 if(!mask_match(dname, fname_mask,
3307 conn->case_sensitive)) {
3308 TALLOC_FREE(frame);
3309 TALLOC_FREE(talloced);
3310 continue;
3313 TALLOC_FREE(smb_fname->base_name);
3314 if (ISDOT(fname_dir)) {
3315 /* Ensure we use canonical names on open. */
3316 smb_fname->base_name =
3317 talloc_asprintf(smb_fname, "%s",
3318 dname);
3319 } else {
3320 smb_fname->base_name =
3321 talloc_asprintf(smb_fname, "%s/%s",
3322 fname_dir, dname);
3325 if (!smb_fname->base_name) {
3326 TALLOC_FREE(dir_hnd);
3327 status = NT_STATUS_NO_MEMORY;
3328 TALLOC_FREE(frame);
3329 TALLOC_FREE(talloced);
3330 goto out;
3333 status = check_name(conn, smb_fname);
3334 if (!NT_STATUS_IS_OK(status)) {
3335 TALLOC_FREE(dir_hnd);
3336 TALLOC_FREE(frame);
3337 TALLOC_FREE(talloced);
3338 goto out;
3341 status = do_unlink(conn, req, smb_fname, dirtype);
3342 if (!NT_STATUS_IS_OK(status)) {
3343 TALLOC_FREE(dir_hnd);
3344 TALLOC_FREE(frame);
3345 TALLOC_FREE(talloced);
3346 goto out;
3349 count++;
3350 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3351 smb_fname->base_name));
3353 TALLOC_FREE(frame);
3354 TALLOC_FREE(talloced);
3356 TALLOC_FREE(dir_hnd);
3359 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3360 status = map_nt_error_from_unix(errno);
3363 out:
3364 TALLOC_FREE(smb_fname_dir);
3365 TALLOC_FREE(fname_dir);
3366 TALLOC_FREE(fname_mask);
3367 return status;
3370 /****************************************************************************
3371 Reply to a unlink
3372 ****************************************************************************/
3374 void reply_unlink(struct smb_request *req)
3376 connection_struct *conn = req->conn;
3377 char *name = NULL;
3378 struct smb_filename *smb_fname = NULL;
3379 uint32_t dirtype;
3380 NTSTATUS status;
3381 bool path_contains_wcard = False;
3382 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3383 ucf_flags_from_smb_request(req);
3384 TALLOC_CTX *ctx = talloc_tos();
3386 START_PROFILE(SMBunlink);
3388 if (req->wct < 1) {
3389 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3390 goto out;
3393 dirtype = SVAL(req->vwv+0, 0);
3395 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3396 STR_TERMINATE, &status,
3397 &path_contains_wcard);
3398 if (!NT_STATUS_IS_OK(status)) {
3399 reply_nterror(req, status);
3400 goto out;
3403 status = filename_convert(ctx, conn,
3404 name,
3405 ucf_flags,
3406 NULL,
3407 &path_contains_wcard,
3408 &smb_fname);
3409 if (!NT_STATUS_IS_OK(status)) {
3410 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3411 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3412 ERRSRV, ERRbadpath);
3413 goto out;
3415 reply_nterror(req, status);
3416 goto out;
3419 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3421 status = unlink_internals(conn, req, dirtype, smb_fname,
3422 path_contains_wcard);
3423 if (!NT_STATUS_IS_OK(status)) {
3424 if (open_was_deferred(req->xconn, req->mid)) {
3425 /* We have re-scheduled this call. */
3426 goto out;
3428 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3429 bool ok = defer_smb1_sharing_violation(req);
3430 if (ok) {
3431 goto out;
3434 reply_nterror(req, status);
3435 goto out;
3438 reply_outbuf(req, 0, 0);
3439 out:
3440 TALLOC_FREE(smb_fname);
3441 END_PROFILE(SMBunlink);
3442 return;
3445 /****************************************************************************
3446 Fail for readbraw.
3447 ****************************************************************************/
3449 static void fail_readraw(void)
3451 const char *errstr = talloc_asprintf(talloc_tos(),
3452 "FAIL ! reply_readbraw: socket write fail (%s)",
3453 strerror(errno));
3454 if (!errstr) {
3455 errstr = "";
3457 exit_server_cleanly(errstr);
3460 /****************************************************************************
3461 Fake (read/write) sendfile. Returns -1 on read or write fail.
3462 ****************************************************************************/
3464 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3465 off_t startpos, size_t nread)
3467 size_t bufsize;
3468 size_t tosend = nread;
3469 char *buf;
3471 if (nread == 0) {
3472 return 0;
3475 bufsize = MIN(nread, 65536);
3477 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3478 return -1;
3481 while (tosend > 0) {
3482 ssize_t ret;
3483 size_t cur_read;
3485 cur_read = MIN(tosend, bufsize);
3486 ret = read_file(fsp,buf,startpos,cur_read);
3487 if (ret == -1) {
3488 SAFE_FREE(buf);
3489 return -1;
3492 /* If we had a short read, fill with zeros. */
3493 if (ret < cur_read) {
3494 memset(buf + ret, '\0', cur_read - ret);
3497 ret = write_data(xconn->transport.sock, buf, cur_read);
3498 if (ret != cur_read) {
3499 int saved_errno = errno;
3501 * Try and give an error message saying what
3502 * client failed.
3504 DEBUG(0, ("write_data failed for client %s. "
3505 "Error %s\n",
3506 smbXsrv_connection_dbg(xconn),
3507 strerror(saved_errno)));
3508 SAFE_FREE(buf);
3509 errno = saved_errno;
3510 return -1;
3512 tosend -= cur_read;
3513 startpos += cur_read;
3516 SAFE_FREE(buf);
3517 return (ssize_t)nread;
3520 /****************************************************************************
3521 Deal with the case of sendfile reading less bytes from the file than
3522 requested. Fill with zeros (all we can do). Returns 0 on success
3523 ****************************************************************************/
3525 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3526 files_struct *fsp,
3527 ssize_t nread,
3528 size_t headersize,
3529 size_t smb_maxcnt)
3531 #define SHORT_SEND_BUFSIZE 1024
3532 if (nread < headersize) {
3533 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3534 "header for file %s (%s). Terminating\n",
3535 fsp_str_dbg(fsp), strerror(errno)));
3536 return -1;
3539 nread -= headersize;
3541 if (nread < smb_maxcnt) {
3542 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3543 if (!buf) {
3544 DEBUG(0,("sendfile_short_send: malloc failed "
3545 "for file %s (%s). Terminating\n",
3546 fsp_str_dbg(fsp), strerror(errno)));
3547 return -1;
3550 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3551 "with zeros !\n", fsp_str_dbg(fsp)));
3553 while (nread < smb_maxcnt) {
3555 * We asked for the real file size and told sendfile
3556 * to not go beyond the end of the file. But it can
3557 * happen that in between our fstat call and the
3558 * sendfile call the file was truncated. This is very
3559 * bad because we have already announced the larger
3560 * number of bytes to the client.
3562 * The best we can do now is to send 0-bytes, just as
3563 * a read from a hole in a sparse file would do.
3565 * This should happen rarely enough that I don't care
3566 * about efficiency here :-)
3568 size_t to_write;
3569 ssize_t ret;
3571 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3572 ret = write_data(xconn->transport.sock, buf, to_write);
3573 if (ret != to_write) {
3574 int saved_errno = errno;
3576 * Try and give an error message saying what
3577 * client failed.
3579 DEBUG(0, ("write_data failed for client %s. "
3580 "Error %s\n",
3581 smbXsrv_connection_dbg(xconn),
3582 strerror(saved_errno)));
3583 errno = saved_errno;
3584 return -1;
3586 nread += to_write;
3588 SAFE_FREE(buf);
3591 return 0;
3594 /****************************************************************************
3595 Return a readbraw error (4 bytes of zero).
3596 ****************************************************************************/
3598 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3600 char header[4];
3602 SIVAL(header,0,0);
3604 smbd_lock_socket(xconn);
3605 if (write_data(xconn->transport.sock,header,4) != 4) {
3606 int saved_errno = errno;
3608 * Try and give an error message saying what
3609 * client failed.
3611 DEBUG(0, ("write_data failed for client %s. "
3612 "Error %s\n",
3613 smbXsrv_connection_dbg(xconn),
3614 strerror(saved_errno)));
3615 errno = saved_errno;
3617 fail_readraw();
3619 smbd_unlock_socket(xconn);
3622 /****************************************************************************
3623 Use sendfile in readbraw.
3624 ****************************************************************************/
3626 static void send_file_readbraw(connection_struct *conn,
3627 struct smb_request *req,
3628 files_struct *fsp,
3629 off_t startpos,
3630 size_t nread,
3631 ssize_t mincount)
3633 struct smbXsrv_connection *xconn = req->xconn;
3634 char *outbuf = NULL;
3635 ssize_t ret=0;
3638 * We can only use sendfile on a non-chained packet
3639 * but we can use on a non-oplocked file. tridge proved this
3640 * on a train in Germany :-). JRA.
3641 * reply_readbraw has already checked the length.
3644 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3645 (fsp->wcp == NULL) &&
3646 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3647 ssize_t sendfile_read = -1;
3648 char header[4];
3649 DATA_BLOB header_blob;
3651 _smb_setlen(header,nread);
3652 header_blob = data_blob_const(header, 4);
3654 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3655 &header_blob, startpos,
3656 nread);
3657 if (sendfile_read == -1) {
3658 /* Returning ENOSYS means no data at all was sent.
3659 * Do this as a normal read. */
3660 if (errno == ENOSYS) {
3661 goto normal_readbraw;
3665 * Special hack for broken Linux with no working sendfile. If we
3666 * return EINTR we sent the header but not the rest of the data.
3667 * Fake this up by doing read/write calls.
3669 if (errno == EINTR) {
3670 /* Ensure we don't do this again. */
3671 set_use_sendfile(SNUM(conn), False);
3672 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3674 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3675 DEBUG(0,("send_file_readbraw: "
3676 "fake_sendfile failed for "
3677 "file %s (%s).\n",
3678 fsp_str_dbg(fsp),
3679 strerror(errno)));
3680 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3682 return;
3685 DEBUG(0,("send_file_readbraw: sendfile failed for "
3686 "file %s (%s). Terminating\n",
3687 fsp_str_dbg(fsp), strerror(errno)));
3688 exit_server_cleanly("send_file_readbraw sendfile failed");
3689 } else if (sendfile_read == 0) {
3691 * Some sendfile implementations return 0 to indicate
3692 * that there was a short read, but nothing was
3693 * actually written to the socket. In this case,
3694 * fallback to the normal read path so the header gets
3695 * the correct byte count.
3697 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3698 "bytes falling back to the normal read: "
3699 "%s\n", fsp_str_dbg(fsp)));
3700 goto normal_readbraw;
3703 /* Deal with possible short send. */
3704 if (sendfile_read != 4+nread) {
3705 ret = sendfile_short_send(xconn, fsp,
3706 sendfile_read, 4, nread);
3707 if (ret == -1) {
3708 fail_readraw();
3711 return;
3714 normal_readbraw:
3716 outbuf = talloc_array(NULL, char, nread+4);
3717 if (!outbuf) {
3718 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3719 (unsigned)(nread+4)));
3720 reply_readbraw_error(xconn);
3721 return;
3724 if (nread > 0) {
3725 ret = read_file(fsp,outbuf+4,startpos,nread);
3726 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3727 if (ret < mincount)
3728 ret = 0;
3729 #else
3730 if (ret < nread)
3731 ret = 0;
3732 #endif
3735 _smb_setlen(outbuf,ret);
3736 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3737 int saved_errno = errno;
3739 * Try and give an error message saying what
3740 * client failed.
3742 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3743 smbXsrv_connection_dbg(xconn),
3744 strerror(saved_errno)));
3745 errno = saved_errno;
3747 fail_readraw();
3750 TALLOC_FREE(outbuf);
3753 /****************************************************************************
3754 Reply to a readbraw (core+ protocol).
3755 ****************************************************************************/
3757 void reply_readbraw(struct smb_request *req)
3759 connection_struct *conn = req->conn;
3760 struct smbXsrv_connection *xconn = req->xconn;
3761 ssize_t maxcount,mincount;
3762 size_t nread = 0;
3763 off_t startpos;
3764 files_struct *fsp;
3765 struct lock_struct lock;
3766 off_t size = 0;
3767 NTSTATUS status;
3769 START_PROFILE(SMBreadbraw);
3771 if (srv_is_signing_active(xconn) || req->encrypted) {
3772 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3773 "raw reads/writes are disallowed.");
3776 if (req->wct < 8) {
3777 reply_readbraw_error(xconn);
3778 END_PROFILE(SMBreadbraw);
3779 return;
3782 if (xconn->smb1.echo_handler.trusted_fde) {
3783 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3784 "'async smb echo handler = yes'\n"));
3785 reply_readbraw_error(xconn);
3786 END_PROFILE(SMBreadbraw);
3787 return;
3791 * Special check if an oplock break has been issued
3792 * and the readraw request croses on the wire, we must
3793 * return a zero length response here.
3796 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3799 * We have to do a check_fsp by hand here, as
3800 * we must always return 4 zero bytes on error,
3801 * not a NTSTATUS.
3804 if (!fsp || !conn || conn != fsp->conn ||
3805 req->vuid != fsp->vuid ||
3806 fsp->is_directory || fsp->fh->fd == -1) {
3808 * fsp could be NULL here so use the value from the packet. JRA.
3810 DEBUG(3,("reply_readbraw: fnum %d not valid "
3811 "- cache prime?\n",
3812 (int)SVAL(req->vwv+0, 0)));
3813 reply_readbraw_error(xconn);
3814 END_PROFILE(SMBreadbraw);
3815 return;
3818 /* Do a "by hand" version of CHECK_READ. */
3819 if (!(fsp->can_read ||
3820 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3821 (fsp->access_mask & FILE_EXECUTE)))) {
3822 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3823 (int)SVAL(req->vwv+0, 0)));
3824 reply_readbraw_error(xconn);
3825 END_PROFILE(SMBreadbraw);
3826 return;
3829 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3831 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3832 if(req->wct == 10) {
3834 * This is a large offset (64 bit) read.
3837 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3839 if(startpos < 0) {
3840 DEBUG(0,("reply_readbraw: negative 64 bit "
3841 "readraw offset (%.0f) !\n",
3842 (double)startpos ));
3843 reply_readbraw_error(xconn);
3844 END_PROFILE(SMBreadbraw);
3845 return;
3849 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3850 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3852 /* ensure we don't overrun the packet size */
3853 maxcount = MIN(65535,maxcount);
3855 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3856 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3857 &lock);
3859 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3860 reply_readbraw_error(xconn);
3861 END_PROFILE(SMBreadbraw);
3862 return;
3865 status = vfs_stat_fsp(fsp);
3866 if (NT_STATUS_IS_OK(status)) {
3867 size = fsp->fsp_name->st.st_ex_size;
3870 if (startpos >= size) {
3871 nread = 0;
3872 } else {
3873 nread = MIN(maxcount,(size - startpos));
3876 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3877 if (nread < mincount)
3878 nread = 0;
3879 #endif
3881 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3882 "min=%lu nread=%lu\n",
3883 fsp_fnum_dbg(fsp), (double)startpos,
3884 (unsigned long)maxcount,
3885 (unsigned long)mincount,
3886 (unsigned long)nread ) );
3888 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3890 DEBUG(5,("reply_readbraw finished\n"));
3892 END_PROFILE(SMBreadbraw);
3893 return;
3896 #undef DBGC_CLASS
3897 #define DBGC_CLASS DBGC_LOCKING
3899 /****************************************************************************
3900 Reply to a lockread (core+ protocol).
3901 ****************************************************************************/
3903 static void reply_lockread_locked(struct tevent_req *subreq);
3905 void reply_lockread(struct smb_request *req)
3907 struct tevent_req *subreq = NULL;
3908 connection_struct *conn = req->conn;
3909 files_struct *fsp;
3910 struct smbd_lock_element *lck = NULL;
3912 START_PROFILE(SMBlockread);
3914 if (req->wct < 5) {
3915 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3916 END_PROFILE(SMBlockread);
3917 return;
3920 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3922 if (!check_fsp(conn, req, fsp)) {
3923 END_PROFILE(SMBlockread);
3924 return;
3927 if (!CHECK_READ(fsp,req)) {
3928 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3929 END_PROFILE(SMBlockread);
3930 return;
3933 lck = talloc(req, struct smbd_lock_element);
3934 if (lck == NULL) {
3935 reply_nterror(req, NT_STATUS_NO_MEMORY);
3936 END_PROFILE(SMBlockread);
3937 return;
3941 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3942 * protocol request that predates the read/write lock concept.
3943 * Thus instead of asking for a read lock here we need to ask
3944 * for a write lock. JRA.
3945 * Note that the requested lock size is unaffected by max_send.
3948 *lck = (struct smbd_lock_element) {
3949 .req_guid = smbd_request_guid(req, 0),
3950 .smblctx = req->smbpid,
3951 .brltype = WRITE_LOCK,
3952 .count = SVAL(req->vwv+1, 0),
3953 .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
3956 subreq = smbd_smb1_do_locks_send(
3957 fsp,
3958 req->sconn->ev_ctx,
3959 &req,
3960 fsp,
3962 false, /* large_offset */
3963 WINDOWS_LOCK,
3965 lck);
3966 if (subreq == NULL) {
3967 reply_nterror(req, NT_STATUS_NO_MEMORY);
3968 END_PROFILE(SMBlockread);
3969 return;
3971 tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
3972 END_PROFILE(SMBlockread);
3975 static void reply_lockread_locked(struct tevent_req *subreq)
3977 struct smb_request *req = NULL;
3978 ssize_t nread = -1;
3979 char *data = NULL;
3980 NTSTATUS status;
3981 bool ok;
3982 off_t startpos;
3983 size_t numtoread, maxtoread;
3984 struct files_struct *fsp = NULL;
3985 char *p = NULL;
3987 START_PROFILE(SMBlockread);
3989 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
3990 SMB_ASSERT(ok);
3992 status = smbd_smb1_do_locks_recv(subreq);
3993 TALLOC_FREE(subreq);
3995 if (!NT_STATUS_IS_OK(status)) {
3996 reply_nterror(req, status);
3997 goto send;
4000 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4001 if (fsp == NULL) {
4002 reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
4003 goto send;
4006 numtoread = SVAL(req->vwv+1, 0);
4007 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4010 * However the requested READ size IS affected by max_send. Insanity.... JRA.
4012 maxtoread = req->xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4014 if (numtoread > maxtoread) {
4015 DBG_WARNING("requested read size (%zu) is greater than "
4016 "maximum allowed (%zu/%d). "
4017 "Returning short read of maximum allowed for "
4018 "compatibility with Windows 2000.\n",
4019 numtoread,
4020 maxtoread,
4021 req->xconn->smb1.sessions.max_send);
4022 numtoread = maxtoread;
4025 reply_outbuf(req, 5, numtoread + 3);
4027 data = smb_buf(req->outbuf) + 3;
4029 nread = read_file(fsp,data,startpos,numtoread);
4031 if (nread < 0) {
4032 reply_nterror(req, map_nt_error_from_unix(errno));
4033 goto send;
4036 srv_set_message((char *)req->outbuf, 5, nread+3, False);
4038 SSVAL(req->outbuf,smb_vwv0,nread);
4039 SSVAL(req->outbuf,smb_vwv5,nread+3);
4040 p = smb_buf(req->outbuf);
4041 SCVAL(p,0,0); /* pad byte. */
4042 SSVAL(p,1,nread);
4044 DEBUG(3,("lockread %s num=%d nread=%d\n",
4045 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4047 send:
4048 ok = srv_send_smb(req->xconn,
4049 (char *)req->outbuf,
4050 true,
4051 req->seqnum+1,
4052 IS_CONN_ENCRYPTED(req->conn),
4053 NULL);
4054 if (!ok) {
4055 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
4057 TALLOC_FREE(req);
4058 END_PROFILE(SMBlockread);
4059 return;
4062 #undef DBGC_CLASS
4063 #define DBGC_CLASS DBGC_ALL
4065 /****************************************************************************
4066 Reply to a read.
4067 ****************************************************************************/
4069 void reply_read(struct smb_request *req)
4071 connection_struct *conn = req->conn;
4072 size_t numtoread;
4073 size_t maxtoread;
4074 ssize_t nread = 0;
4075 char *data;
4076 off_t startpos;
4077 files_struct *fsp;
4078 struct lock_struct lock;
4079 struct smbXsrv_connection *xconn = req->xconn;
4081 START_PROFILE(SMBread);
4083 if (req->wct < 3) {
4084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4085 END_PROFILE(SMBread);
4086 return;
4089 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4091 if (!check_fsp(conn, req, fsp)) {
4092 END_PROFILE(SMBread);
4093 return;
4096 if (!CHECK_READ(fsp,req)) {
4097 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4098 END_PROFILE(SMBread);
4099 return;
4102 numtoread = SVAL(req->vwv+1, 0);
4103 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4106 * The requested read size cannot be greater than max_send. JRA.
4108 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
4110 if (numtoread > maxtoread) {
4111 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
4112 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
4113 (unsigned int)numtoread, (unsigned int)maxtoread,
4114 (unsigned int)xconn->smb1.sessions.max_send));
4115 numtoread = maxtoread;
4118 reply_outbuf(req, 5, numtoread+3);
4120 data = smb_buf(req->outbuf) + 3;
4122 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4123 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
4124 &lock);
4126 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4127 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4128 END_PROFILE(SMBread);
4129 return;
4132 if (numtoread > 0)
4133 nread = read_file(fsp,data,startpos,numtoread);
4135 if (nread < 0) {
4136 reply_nterror(req, map_nt_error_from_unix(errno));
4137 goto out;
4140 srv_set_message((char *)req->outbuf, 5, nread+3, False);
4142 SSVAL(req->outbuf,smb_vwv0,nread);
4143 SSVAL(req->outbuf,smb_vwv5,nread+3);
4144 SCVAL(smb_buf(req->outbuf),0,1);
4145 SSVAL(smb_buf(req->outbuf),1,nread);
4147 DEBUG(3, ("read %s num=%d nread=%d\n",
4148 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
4150 out:
4151 END_PROFILE(SMBread);
4152 return;
4155 /****************************************************************************
4156 Setup readX header.
4157 ****************************************************************************/
4159 size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
4161 size_t outsize;
4163 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
4164 False);
4166 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
4168 SCVAL(outbuf,smb_vwv0,0xFF);
4169 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
4170 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
4171 SSVAL(outbuf,smb_vwv6,
4172 (smb_wct - 4) /* offset from smb header to wct */
4173 + 1 /* the wct field */
4174 + 12 * sizeof(uint16_t) /* vwv */
4175 + 2 /* the buflen field */
4176 + 1); /* padding byte */
4177 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
4178 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
4179 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
4180 _smb_setlen_large(outbuf,
4181 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
4182 return outsize;
4185 /****************************************************************************
4186 Reply to a read and X - possibly using sendfile.
4187 ****************************************************************************/
4189 static void send_file_readX(connection_struct *conn, struct smb_request *req,
4190 files_struct *fsp, off_t startpos,
4191 size_t smb_maxcnt)
4193 struct smbXsrv_connection *xconn = req->xconn;
4194 ssize_t nread = -1;
4195 struct lock_struct lock;
4196 int saved_errno = 0;
4197 NTSTATUS status;
4199 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4200 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
4201 &lock);
4203 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4204 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4205 return;
4209 * We can only use sendfile on a non-chained packet
4210 * but we can use on a non-oplocked file. tridge proved this
4211 * on a train in Germany :-). JRA.
4214 if (!req_is_in_chain(req) &&
4215 !req->encrypted &&
4216 (fsp->base_fsp == NULL) &&
4217 (fsp->wcp == NULL) &&
4218 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
4219 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
4220 DATA_BLOB header;
4222 status = vfs_stat_fsp(fsp);
4223 if (!NT_STATUS_IS_OK(status)) {
4224 reply_nterror(req, status);
4225 goto out;
4228 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4229 (startpos > fsp->fsp_name->st.st_ex_size) ||
4230 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4232 * We already know that we would do a short read, so don't
4233 * try the sendfile() path.
4235 goto nosendfile_read;
4239 * Set up the packet header before send. We
4240 * assume here the sendfile will work (get the
4241 * correct amount of data).
4244 header = data_blob_const(headerbuf, sizeof(headerbuf));
4246 construct_reply_common_req(req, (char *)headerbuf);
4247 setup_readX_header((char *)headerbuf, smb_maxcnt);
4249 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4250 startpos, smb_maxcnt);
4251 if (nread == -1) {
4252 saved_errno = errno;
4254 /* Returning ENOSYS means no data at all was sent.
4255 Do this as a normal read. */
4256 if (errno == ENOSYS) {
4257 goto normal_read;
4261 * Special hack for broken Linux with no working sendfile. If we
4262 * return EINTR we sent the header but not the rest of the data.
4263 * Fake this up by doing read/write calls.
4266 if (errno == EINTR) {
4267 /* Ensure we don't do this again. */
4268 set_use_sendfile(SNUM(conn), False);
4269 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4270 nread = fake_sendfile(xconn, fsp, startpos,
4271 smb_maxcnt);
4272 if (nread == -1) {
4273 saved_errno = errno;
4274 DEBUG(0,("send_file_readX: "
4275 "fake_sendfile failed for "
4276 "file %s (%s) for client %s. "
4277 "Terminating\n",
4278 fsp_str_dbg(fsp),
4279 smbXsrv_connection_dbg(xconn),
4280 strerror(saved_errno)));
4281 errno = saved_errno;
4282 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4284 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4285 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4286 /* No outbuf here means successful sendfile. */
4287 goto out;
4290 DEBUG(0,("send_file_readX: sendfile failed for file "
4291 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4292 strerror(errno)));
4293 exit_server_cleanly("send_file_readX sendfile failed");
4294 } else if (nread == 0) {
4296 * Some sendfile implementations return 0 to indicate
4297 * that there was a short read, but nothing was
4298 * actually written to the socket. In this case,
4299 * fallback to the normal read path so the header gets
4300 * the correct byte count.
4302 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4303 "falling back to the normal read: %s\n",
4304 fsp_str_dbg(fsp)));
4305 goto normal_read;
4308 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4309 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4311 /* Deal with possible short send. */
4312 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4313 ssize_t ret;
4315 ret = sendfile_short_send(xconn, fsp, nread,
4316 sizeof(headerbuf), smb_maxcnt);
4317 if (ret == -1) {
4318 const char *r;
4319 r = "send_file_readX: sendfile_short_send failed";
4320 DEBUG(0,("%s for file %s (%s).\n",
4321 r, fsp_str_dbg(fsp), strerror(errno)));
4322 exit_server_cleanly(r);
4325 /* No outbuf here means successful sendfile. */
4326 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4327 SMB_PERFCOUNT_END(&req->pcd);
4328 goto out;
4331 normal_read:
4333 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4334 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4335 ssize_t ret;
4337 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4338 (startpos > fsp->fsp_name->st.st_ex_size) ||
4339 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4341 * We already know that we would do a short
4342 * read, so don't try the sendfile() path.
4344 goto nosendfile_read;
4347 construct_reply_common_req(req, (char *)headerbuf);
4348 setup_readX_header((char *)headerbuf, smb_maxcnt);
4350 /* Send out the header. */
4351 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4352 sizeof(headerbuf));
4353 if (ret != sizeof(headerbuf)) {
4354 saved_errno = errno;
4356 * Try and give an error message saying what
4357 * client failed.
4359 DEBUG(0,("send_file_readX: write_data failed for file "
4360 "%s (%s) for client %s. Terminating\n",
4361 fsp_str_dbg(fsp),
4362 smbXsrv_connection_dbg(xconn),
4363 strerror(saved_errno)));
4364 errno = saved_errno;
4365 exit_server_cleanly("send_file_readX sendfile failed");
4367 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4368 if (nread == -1) {
4369 saved_errno = errno;
4370 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4371 "%s (%s) for client %s. Terminating\n",
4372 fsp_str_dbg(fsp),
4373 smbXsrv_connection_dbg(xconn),
4374 strerror(saved_errno)));
4375 errno = saved_errno;
4376 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4378 goto out;
4381 nosendfile_read:
4383 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4384 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4385 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4387 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4388 startpos, smb_maxcnt);
4389 saved_errno = errno;
4391 if (nread < 0) {
4392 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4393 return;
4396 setup_readX_header((char *)req->outbuf, nread);
4398 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4399 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4400 return;
4402 out:
4403 TALLOC_FREE(req->outbuf);
4404 return;
4407 /****************************************************************************
4408 Work out how much space we have for a read return.
4409 ****************************************************************************/
4411 static size_t calc_max_read_pdu(const struct smb_request *req)
4413 struct smbXsrv_connection *xconn = req->xconn;
4415 if (xconn->protocol < PROTOCOL_NT1) {
4416 return xconn->smb1.sessions.max_send;
4419 if (!lp_large_readwrite()) {
4420 return xconn->smb1.sessions.max_send;
4423 if (req_is_in_chain(req)) {
4424 return xconn->smb1.sessions.max_send;
4427 if (req->encrypted) {
4429 * Don't take encrypted traffic up to the
4430 * limit. There are padding considerations
4431 * that make that tricky.
4433 return xconn->smb1.sessions.max_send;
4436 if (srv_is_signing_active(xconn)) {
4437 return 0x1FFFF;
4440 if (!lp_unix_extensions()) {
4441 return 0x1FFFF;
4445 * We can do ultra-large POSIX reads.
4447 return 0xFFFFFF;
4450 /****************************************************************************
4451 Calculate how big a read can be. Copes with all clients. It's always
4452 safe to return a short read - Windows does this.
4453 ****************************************************************************/
4455 static size_t calc_read_size(const struct smb_request *req,
4456 size_t upper_size,
4457 size_t lower_size)
4459 struct smbXsrv_connection *xconn = req->xconn;
4460 size_t max_pdu = calc_max_read_pdu(req);
4461 size_t total_size = 0;
4462 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4463 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4466 * Windows explicitly ignores upper size of 0xFFFF.
4467 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4468 * We must do the same as these will never fit even in
4469 * an extended size NetBIOS packet.
4471 if (upper_size == 0xFFFF) {
4472 upper_size = 0;
4475 if (xconn->protocol < PROTOCOL_NT1) {
4476 upper_size = 0;
4479 total_size = ((upper_size<<16) | lower_size);
4482 * LARGE_READX test shows it's always safe to return
4483 * a short read. Windows does so.
4485 return MIN(total_size, max_len);
4488 /****************************************************************************
4489 Reply to a read and X.
4490 ****************************************************************************/
4492 void reply_read_and_X(struct smb_request *req)
4494 connection_struct *conn = req->conn;
4495 files_struct *fsp;
4496 off_t startpos;
4497 size_t smb_maxcnt;
4498 size_t upper_size;
4499 bool big_readX = False;
4500 #if 0
4501 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4502 #endif
4504 START_PROFILE(SMBreadX);
4506 if ((req->wct != 10) && (req->wct != 12)) {
4507 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4508 return;
4511 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4512 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4513 smb_maxcnt = SVAL(req->vwv+5, 0);
4515 /* If it's an IPC, pass off the pipe handler. */
4516 if (IS_IPC(conn)) {
4517 reply_pipe_read_and_X(req);
4518 END_PROFILE(SMBreadX);
4519 return;
4522 if (!check_fsp(conn, req, fsp)) {
4523 END_PROFILE(SMBreadX);
4524 return;
4527 if (!CHECK_READ(fsp,req)) {
4528 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4529 END_PROFILE(SMBreadX);
4530 return;
4533 upper_size = SVAL(req->vwv+7, 0);
4534 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4535 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4537 * This is a heuristic to avoid keeping large
4538 * outgoing buffers around over long-lived aio
4539 * requests.
4541 big_readX = True;
4544 if (req->wct == 12) {
4546 * This is a large offset (64 bit) read.
4548 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4552 if (!big_readX) {
4553 NTSTATUS status = schedule_aio_read_and_X(conn,
4554 req,
4555 fsp,
4556 startpos,
4557 smb_maxcnt);
4558 if (NT_STATUS_IS_OK(status)) {
4559 /* Read scheduled - we're done. */
4560 goto out;
4562 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4563 /* Real error - report to client. */
4564 END_PROFILE(SMBreadX);
4565 reply_nterror(req, status);
4566 return;
4568 /* NT_STATUS_RETRY - fall back to sync read. */
4571 smbd_lock_socket(req->xconn);
4572 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4573 smbd_unlock_socket(req->xconn);
4575 out:
4576 END_PROFILE(SMBreadX);
4577 return;
4580 /****************************************************************************
4581 Error replies to writebraw must have smb_wct == 1. Fix this up.
4582 ****************************************************************************/
4584 void error_to_writebrawerr(struct smb_request *req)
4586 uint8_t *old_outbuf = req->outbuf;
4588 reply_outbuf(req, 1, 0);
4590 memcpy(req->outbuf, old_outbuf, smb_size);
4591 TALLOC_FREE(old_outbuf);
4594 /****************************************************************************
4595 Read 4 bytes of a smb packet and return the smb length of the packet.
4596 Store the result in the buffer. This version of the function will
4597 never return a session keepalive (length of zero).
4598 Timeout is in milliseconds.
4599 ****************************************************************************/
4601 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4602 size_t *len)
4604 uint8_t msgtype = NBSSkeepalive;
4606 while (msgtype == NBSSkeepalive) {
4607 NTSTATUS status;
4609 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4610 len);
4611 if (!NT_STATUS_IS_OK(status)) {
4612 char addr[INET6_ADDRSTRLEN];
4613 /* Try and give an error message
4614 * saying what client failed. */
4615 DEBUG(0, ("read_smb_length_return_keepalive failed for "
4616 "client %s read error = %s.\n",
4617 get_peer_addr(fd,addr,sizeof(addr)),
4618 nt_errstr(status)));
4619 return status;
4622 msgtype = CVAL(inbuf, 0);
4625 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4626 (unsigned long)len));
4628 return NT_STATUS_OK;
4631 /****************************************************************************
4632 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4633 ****************************************************************************/
4635 void reply_writebraw(struct smb_request *req)
4637 connection_struct *conn = req->conn;
4638 struct smbXsrv_connection *xconn = req->xconn;
4639 char *buf = NULL;
4640 ssize_t nwritten=0;
4641 ssize_t total_written=0;
4642 size_t numtowrite=0;
4643 size_t tcount;
4644 off_t startpos;
4645 const char *data=NULL;
4646 bool write_through;
4647 files_struct *fsp;
4648 struct lock_struct lock;
4649 NTSTATUS status;
4651 START_PROFILE(SMBwritebraw);
4654 * If we ever reply with an error, it must have the SMB command
4655 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4656 * we're finished.
4658 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4660 if (srv_is_signing_active(xconn)) {
4661 END_PROFILE(SMBwritebraw);
4662 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4663 "raw reads/writes are disallowed.");
4666 if (req->wct < 12) {
4667 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4668 error_to_writebrawerr(req);
4669 END_PROFILE(SMBwritebraw);
4670 return;
4673 if (xconn->smb1.echo_handler.trusted_fde) {
4674 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4675 "'async smb echo handler = yes'\n"));
4676 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4677 error_to_writebrawerr(req);
4678 END_PROFILE(SMBwritebraw);
4679 return;
4682 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4683 if (!check_fsp(conn, req, fsp)) {
4684 error_to_writebrawerr(req);
4685 END_PROFILE(SMBwritebraw);
4686 return;
4689 if (!CHECK_WRITE(fsp)) {
4690 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4691 error_to_writebrawerr(req);
4692 END_PROFILE(SMBwritebraw);
4693 return;
4696 tcount = IVAL(req->vwv+1, 0);
4697 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4698 write_through = BITSETW(req->vwv+7,0);
4700 /* We have to deal with slightly different formats depending
4701 on whether we are using the core+ or lanman1.0 protocol */
4703 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4704 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4705 data = smb_buf_const(req->inbuf);
4706 } else {
4707 numtowrite = SVAL(req->vwv+10, 0);
4708 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4711 /* Ensure we don't write bytes past the end of this packet. */
4713 * This already protects us against CVE-2017-12163.
4715 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4716 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4717 error_to_writebrawerr(req);
4718 END_PROFILE(SMBwritebraw);
4719 return;
4722 if (!fsp->print_file) {
4723 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4724 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4725 &lock);
4727 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4728 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4729 error_to_writebrawerr(req);
4730 END_PROFILE(SMBwritebraw);
4731 return;
4735 if (numtowrite>0) {
4736 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4739 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4740 "wrote=%d sync=%d\n",
4741 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4742 (int)nwritten, (int)write_through));
4744 if (nwritten < (ssize_t)numtowrite) {
4745 reply_nterror(req, NT_STATUS_DISK_FULL);
4746 error_to_writebrawerr(req);
4747 goto out;
4750 total_written = nwritten;
4752 /* Allocate a buffer of 64k + length. */
4753 buf = talloc_array(NULL, char, 65540);
4754 if (!buf) {
4755 reply_nterror(req, NT_STATUS_NO_MEMORY);
4756 error_to_writebrawerr(req);
4757 goto out;
4760 /* Return a SMBwritebraw message to the redirector to tell
4761 * it to send more bytes */
4763 memcpy(buf, req->inbuf, smb_size);
4764 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4765 SCVAL(buf,smb_com,SMBwritebraw);
4766 SSVALS(buf,smb_vwv0,0xFFFF);
4767 show_msg(buf);
4768 if (!srv_send_smb(req->xconn,
4769 buf,
4770 false, 0, /* no signing */
4771 IS_CONN_ENCRYPTED(conn),
4772 &req->pcd)) {
4773 exit_server_cleanly("reply_writebraw: srv_send_smb "
4774 "failed.");
4777 /* Now read the raw data into the buffer and write it */
4778 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4779 &numtowrite);
4780 if (!NT_STATUS_IS_OK(status)) {
4781 exit_server_cleanly("secondary writebraw failed");
4784 /* Set up outbuf to return the correct size */
4785 reply_outbuf(req, 1, 0);
4787 if (numtowrite != 0) {
4789 if (numtowrite > 0xFFFF) {
4790 DEBUG(0,("reply_writebraw: Oversize secondary write "
4791 "raw requested (%u). Terminating\n",
4792 (unsigned int)numtowrite ));
4793 exit_server_cleanly("secondary writebraw failed");
4796 if (tcount > nwritten+numtowrite) {
4797 DEBUG(3,("reply_writebraw: Client overestimated the "
4798 "write %d %d %d\n",
4799 (int)tcount,(int)nwritten,(int)numtowrite));
4802 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4803 numtowrite);
4805 if (!NT_STATUS_IS_OK(status)) {
4806 /* Try and give an error message
4807 * saying what client failed. */
4808 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4809 "raw read failed (%s) for client %s. "
4810 "Terminating\n", nt_errstr(status),
4811 smbXsrv_connection_dbg(xconn)));
4812 exit_server_cleanly("secondary writebraw failed");
4816 * We are not vulnerable to CVE-2017-12163
4817 * here as we are guaranteed to have numtowrite
4818 * bytes available - we just read from the client.
4820 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4821 if (nwritten == -1) {
4822 TALLOC_FREE(buf);
4823 reply_nterror(req, map_nt_error_from_unix(errno));
4824 error_to_writebrawerr(req);
4825 goto out;
4828 if (nwritten < (ssize_t)numtowrite) {
4829 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4830 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4833 if (nwritten > 0) {
4834 total_written += nwritten;
4838 TALLOC_FREE(buf);
4839 SSVAL(req->outbuf,smb_vwv0,total_written);
4841 status = sync_file(conn, fsp, write_through);
4842 if (!NT_STATUS_IS_OK(status)) {
4843 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4844 fsp_str_dbg(fsp), nt_errstr(status)));
4845 reply_nterror(req, status);
4846 error_to_writebrawerr(req);
4847 goto out;
4850 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4851 "wrote=%d\n",
4852 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4853 (int)total_written));
4855 /* We won't return a status if write through is not selected - this
4856 * follows what WfWg does */
4857 END_PROFILE(SMBwritebraw);
4859 if (!write_through && total_written==tcount) {
4861 #if RABBIT_PELLET_FIX
4863 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4864 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4865 * JRA.
4867 if (!send_keepalive(xconn->transport.sock)) {
4868 exit_server_cleanly("reply_writebraw: send of "
4869 "keepalive failed");
4871 #endif
4872 TALLOC_FREE(req->outbuf);
4874 return;
4876 out:
4877 END_PROFILE(SMBwritebraw);
4878 return;
4881 #undef DBGC_CLASS
4882 #define DBGC_CLASS DBGC_LOCKING
4884 /****************************************************************************
4885 Reply to a writeunlock (core+).
4886 ****************************************************************************/
4888 void reply_writeunlock(struct smb_request *req)
4890 connection_struct *conn = req->conn;
4891 ssize_t nwritten = -1;
4892 size_t numtowrite;
4893 size_t remaining;
4894 off_t startpos;
4895 const char *data;
4896 NTSTATUS status = NT_STATUS_OK;
4897 files_struct *fsp;
4898 struct lock_struct lock;
4899 int saved_errno = 0;
4901 START_PROFILE(SMBwriteunlock);
4903 if (req->wct < 5) {
4904 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4905 END_PROFILE(SMBwriteunlock);
4906 return;
4909 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4911 if (!check_fsp(conn, req, fsp)) {
4912 END_PROFILE(SMBwriteunlock);
4913 return;
4916 if (!CHECK_WRITE(fsp)) {
4917 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4918 END_PROFILE(SMBwriteunlock);
4919 return;
4922 numtowrite = SVAL(req->vwv+1, 0);
4923 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4924 data = (const char *)req->buf + 3;
4927 * Ensure client isn't asking us to write more than
4928 * they sent. CVE-2017-12163.
4930 remaining = smbreq_bufrem(req, data);
4931 if (numtowrite > remaining) {
4932 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4933 END_PROFILE(SMBwriteunlock);
4934 return;
4937 if (!fsp->print_file && numtowrite > 0) {
4938 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4939 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4940 &lock);
4942 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4943 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4944 END_PROFILE(SMBwriteunlock);
4945 return;
4949 /* The special X/Open SMB protocol handling of
4950 zero length writes is *NOT* done for
4951 this call */
4952 if(numtowrite == 0) {
4953 nwritten = 0;
4954 } else {
4955 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4956 saved_errno = errno;
4959 status = sync_file(conn, fsp, False /* write through */);
4960 if (!NT_STATUS_IS_OK(status)) {
4961 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4962 fsp_str_dbg(fsp), nt_errstr(status)));
4963 reply_nterror(req, status);
4964 goto out;
4967 if(nwritten < 0) {
4968 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4969 goto out;
4972 if((nwritten < numtowrite) && (numtowrite != 0)) {
4973 reply_nterror(req, NT_STATUS_DISK_FULL);
4974 goto out;
4977 if (numtowrite && !fsp->print_file) {
4978 struct smbd_lock_element l = {
4979 .req_guid = smbd_request_guid(req, 0),
4980 .smblctx = req->smbpid,
4981 .brltype = UNLOCK_LOCK,
4982 .offset = startpos,
4983 .count = numtowrite,
4985 status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
4986 if (NT_STATUS_V(status)) {
4987 reply_nterror(req, status);
4988 goto out;
4992 reply_outbuf(req, 1, 0);
4994 SSVAL(req->outbuf,smb_vwv0,nwritten);
4996 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4997 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4999 out:
5000 END_PROFILE(SMBwriteunlock);
5001 return;
5004 #undef DBGC_CLASS
5005 #define DBGC_CLASS DBGC_ALL
5007 /****************************************************************************
5008 Reply to a write.
5009 ****************************************************************************/
5011 void reply_write(struct smb_request *req)
5013 connection_struct *conn = req->conn;
5014 size_t numtowrite;
5015 size_t remaining;
5016 ssize_t nwritten = -1;
5017 off_t startpos;
5018 const char *data;
5019 files_struct *fsp;
5020 struct lock_struct lock;
5021 NTSTATUS status;
5022 int saved_errno = 0;
5024 START_PROFILE(SMBwrite);
5026 if (req->wct < 5) {
5027 END_PROFILE(SMBwrite);
5028 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5029 return;
5032 /* If it's an IPC, pass off the pipe handler. */
5033 if (IS_IPC(conn)) {
5034 reply_pipe_write(req);
5035 END_PROFILE(SMBwrite);
5036 return;
5039 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5041 if (!check_fsp(conn, req, fsp)) {
5042 END_PROFILE(SMBwrite);
5043 return;
5046 if (!CHECK_WRITE(fsp)) {
5047 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5048 END_PROFILE(SMBwrite);
5049 return;
5052 numtowrite = SVAL(req->vwv+1, 0);
5053 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5054 data = (const char *)req->buf + 3;
5057 * Ensure client isn't asking us to write more than
5058 * they sent. CVE-2017-12163.
5060 remaining = smbreq_bufrem(req, data);
5061 if (numtowrite > remaining) {
5062 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5063 END_PROFILE(SMBwrite);
5064 return;
5067 if (!fsp->print_file) {
5068 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5069 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5070 &lock);
5072 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5073 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5074 END_PROFILE(SMBwrite);
5075 return;
5080 * X/Open SMB protocol says that if smb_vwv1 is
5081 * zero then the file size should be extended or
5082 * truncated to the size given in smb_vwv[2-3].
5085 if(numtowrite == 0) {
5087 * This is actually an allocate call, and set EOF. JRA.
5089 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
5090 if (nwritten < 0) {
5091 reply_nterror(req, NT_STATUS_DISK_FULL);
5092 goto out;
5094 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
5095 if (nwritten < 0) {
5096 reply_nterror(req, NT_STATUS_DISK_FULL);
5097 goto out;
5099 trigger_write_time_update_immediate(fsp);
5100 } else {
5101 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5104 status = sync_file(conn, fsp, False);
5105 if (!NT_STATUS_IS_OK(status)) {
5106 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
5107 fsp_str_dbg(fsp), nt_errstr(status)));
5108 reply_nterror(req, status);
5109 goto out;
5112 if(nwritten < 0) {
5113 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5114 goto out;
5117 if((nwritten == 0) && (numtowrite != 0)) {
5118 reply_nterror(req, NT_STATUS_DISK_FULL);
5119 goto out;
5122 reply_outbuf(req, 1, 0);
5124 SSVAL(req->outbuf,smb_vwv0,nwritten);
5126 if (nwritten < (ssize_t)numtowrite) {
5127 SCVAL(req->outbuf,smb_rcls,ERRHRD);
5128 SSVAL(req->outbuf,smb_err,ERRdiskfull);
5131 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5133 out:
5134 END_PROFILE(SMBwrite);
5135 return;
5138 /****************************************************************************
5139 Ensure a buffer is a valid writeX for recvfile purposes.
5140 ****************************************************************************/
5142 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
5143 (2*14) + /* word count (including bcc) */ \
5144 1 /* pad byte */)
5146 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
5147 const uint8_t *inbuf)
5149 size_t numtowrite;
5150 unsigned int doff = 0;
5151 size_t len = smb_len_large(inbuf);
5152 uint16_t fnum;
5153 struct smbXsrv_open *op = NULL;
5154 struct files_struct *fsp = NULL;
5155 NTSTATUS status;
5157 if (is_encrypted_packet(inbuf)) {
5158 /* Can't do this on encrypted
5159 * connections. */
5160 return false;
5163 if (CVAL(inbuf,smb_com) != SMBwriteX) {
5164 return false;
5167 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
5168 CVAL(inbuf,smb_wct) != 14) {
5169 DEBUG(10,("is_valid_writeX_buffer: chained or "
5170 "invalid word length.\n"));
5171 return false;
5174 fnum = SVAL(inbuf, smb_vwv2);
5175 status = smb1srv_open_lookup(xconn,
5176 fnum,
5177 0, /* now */
5178 &op);
5179 if (!NT_STATUS_IS_OK(status)) {
5180 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
5181 return false;
5183 fsp = op->compat;
5184 if (fsp == NULL) {
5185 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
5186 return false;
5188 if (fsp->conn == NULL) {
5189 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
5190 return false;
5193 if (IS_IPC(fsp->conn)) {
5194 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
5195 return false;
5197 if (IS_PRINT(fsp->conn)) {
5198 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
5199 return false;
5201 if (fsp->base_fsp != NULL) {
5202 DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
5203 return false;
5205 doff = SVAL(inbuf,smb_vwv11);
5207 numtowrite = SVAL(inbuf,smb_vwv10);
5209 if (len > doff && len - doff > 0xFFFF) {
5210 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
5213 if (numtowrite == 0) {
5214 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
5215 return false;
5218 /* Ensure the sizes match up. */
5219 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
5220 /* no pad byte...old smbclient :-( */
5221 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
5222 (unsigned int)doff,
5223 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
5224 return false;
5227 if (len - doff != numtowrite) {
5228 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
5229 "len = %u, doff = %u, numtowrite = %u\n",
5230 (unsigned int)len,
5231 (unsigned int)doff,
5232 (unsigned int)numtowrite ));
5233 return false;
5236 DEBUG(10,("is_valid_writeX_buffer: true "
5237 "len = %u, doff = %u, numtowrite = %u\n",
5238 (unsigned int)len,
5239 (unsigned int)doff,
5240 (unsigned int)numtowrite ));
5242 return true;
5245 /****************************************************************************
5246 Reply to a write and X.
5247 ****************************************************************************/
5249 void reply_write_and_X(struct smb_request *req)
5251 connection_struct *conn = req->conn;
5252 struct smbXsrv_connection *xconn = req->xconn;
5253 files_struct *fsp;
5254 struct lock_struct lock;
5255 off_t startpos;
5256 size_t numtowrite;
5257 bool write_through;
5258 ssize_t nwritten;
5259 unsigned int smb_doff;
5260 unsigned int smblen;
5261 const char *data;
5262 NTSTATUS status;
5263 int saved_errno = 0;
5265 START_PROFILE(SMBwriteX);
5267 if ((req->wct != 12) && (req->wct != 14)) {
5268 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5269 goto out;
5272 numtowrite = SVAL(req->vwv+10, 0);
5273 smb_doff = SVAL(req->vwv+11, 0);
5274 smblen = smb_len(req->inbuf);
5276 if (req->unread_bytes > 0xFFFF ||
5277 (smblen > smb_doff &&
5278 smblen - smb_doff > 0xFFFF)) {
5279 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5282 if (req->unread_bytes) {
5283 /* Can't do a recvfile write on IPC$ */
5284 if (IS_IPC(conn)) {
5285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5286 goto out;
5288 if (numtowrite != req->unread_bytes) {
5289 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5290 goto out;
5292 } else {
5294 * This already protects us against CVE-2017-12163.
5296 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5297 smb_doff + numtowrite > smblen) {
5298 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5299 goto out;
5303 /* If it's an IPC, pass off the pipe handler. */
5304 if (IS_IPC(conn)) {
5305 if (req->unread_bytes) {
5306 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5307 goto out;
5309 reply_pipe_write_and_X(req);
5310 goto out;
5313 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5314 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5315 write_through = BITSETW(req->vwv+7,0);
5317 if (!check_fsp(conn, req, fsp)) {
5318 goto out;
5321 if (!CHECK_WRITE(fsp)) {
5322 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5323 goto out;
5326 data = smb_base(req->inbuf) + smb_doff;
5328 if(req->wct == 14) {
5330 * This is a large offset (64 bit) write.
5332 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5336 /* X/Open SMB protocol says that, unlike SMBwrite
5337 if the length is zero then NO truncation is
5338 done, just a write of zero. To truncate a file,
5339 use SMBwrite. */
5341 if(numtowrite == 0) {
5342 nwritten = 0;
5343 } else {
5344 if (req->unread_bytes == 0) {
5345 status = schedule_aio_write_and_X(conn,
5346 req,
5347 fsp,
5348 data,
5349 startpos,
5350 numtowrite);
5352 if (NT_STATUS_IS_OK(status)) {
5353 /* write scheduled - we're done. */
5354 goto out;
5356 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5357 /* Real error - report to client. */
5358 reply_nterror(req, status);
5359 goto out;
5361 /* NT_STATUS_RETRY - fall through to sync write. */
5364 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5365 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5366 &lock);
5368 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5369 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5370 goto out;
5373 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5374 saved_errno = errno;
5377 if(nwritten < 0) {
5378 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5379 goto out;
5382 if((nwritten == 0) && (numtowrite != 0)) {
5383 reply_nterror(req, NT_STATUS_DISK_FULL);
5384 goto out;
5387 reply_outbuf(req, 6, 0);
5388 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5389 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5390 SSVAL(req->outbuf,smb_vwv2,nwritten);
5391 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5393 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5394 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5396 status = sync_file(conn, fsp, write_through);
5397 if (!NT_STATUS_IS_OK(status)) {
5398 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5399 fsp_str_dbg(fsp), nt_errstr(status)));
5400 reply_nterror(req, status);
5401 goto out;
5404 END_PROFILE(SMBwriteX);
5405 return;
5407 out:
5408 if (req->unread_bytes) {
5409 /* writeX failed. drain socket. */
5410 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5411 req->unread_bytes) {
5412 smb_panic("failed to drain pending bytes");
5414 req->unread_bytes = 0;
5417 END_PROFILE(SMBwriteX);
5418 return;
5421 /****************************************************************************
5422 Reply to a lseek.
5423 ****************************************************************************/
5425 void reply_lseek(struct smb_request *req)
5427 connection_struct *conn = req->conn;
5428 off_t startpos;
5429 off_t res= -1;
5430 int mode,umode;
5431 files_struct *fsp;
5432 NTSTATUS status;
5434 START_PROFILE(SMBlseek);
5436 if (req->wct < 4) {
5437 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5438 END_PROFILE(SMBlseek);
5439 return;
5442 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5444 if (!check_fsp(conn, req, fsp)) {
5445 return;
5448 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5450 mode = SVAL(req->vwv+1, 0) & 3;
5451 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5452 startpos = (off_t)IVALS(req->vwv+2, 0);
5454 switch (mode) {
5455 case 0:
5456 umode = SEEK_SET;
5457 res = startpos;
5458 break;
5459 case 1:
5460 umode = SEEK_CUR;
5461 res = fsp->fh->pos + startpos;
5462 break;
5463 case 2:
5464 umode = SEEK_END;
5465 break;
5466 default:
5467 umode = SEEK_SET;
5468 res = startpos;
5469 break;
5472 if (umode == SEEK_END) {
5473 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5474 if(errno == EINVAL) {
5475 off_t current_pos = startpos;
5477 status = vfs_stat_fsp(fsp);
5478 if (!NT_STATUS_IS_OK(status)) {
5479 reply_nterror(req, status);
5480 END_PROFILE(SMBlseek);
5481 return;
5484 current_pos += fsp->fsp_name->st.st_ex_size;
5485 if(current_pos < 0)
5486 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5490 if(res == -1) {
5491 reply_nterror(req, map_nt_error_from_unix(errno));
5492 END_PROFILE(SMBlseek);
5493 return;
5497 fsp->fh->pos = res;
5499 reply_outbuf(req, 2, 0);
5500 SIVAL(req->outbuf,smb_vwv0,res);
5502 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5503 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5505 END_PROFILE(SMBlseek);
5506 return;
5509 static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
5510 void *private_data)
5512 connection_struct *conn = talloc_get_type_abort(
5513 private_data, connection_struct);
5515 if (conn != fsp->conn) {
5516 return NULL;
5518 if (fsp->fh->fd == -1) {
5519 return NULL;
5521 sync_file(conn, fsp, True /* write through */);
5523 return NULL;
5526 /****************************************************************************
5527 Reply to a flush.
5528 ****************************************************************************/
5530 void reply_flush(struct smb_request *req)
5532 connection_struct *conn = req->conn;
5533 uint16_t fnum;
5534 files_struct *fsp;
5536 START_PROFILE(SMBflush);
5538 if (req->wct < 1) {
5539 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5540 return;
5543 fnum = SVAL(req->vwv+0, 0);
5544 fsp = file_fsp(req, fnum);
5546 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5547 return;
5550 if (!fsp) {
5551 files_forall(req->sconn, file_sync_one_fn, conn);
5552 } else {
5553 NTSTATUS status = sync_file(conn, fsp, True);
5554 if (!NT_STATUS_IS_OK(status)) {
5555 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5556 fsp_str_dbg(fsp), nt_errstr(status)));
5557 reply_nterror(req, status);
5558 END_PROFILE(SMBflush);
5559 return;
5563 reply_outbuf(req, 0, 0);
5565 DEBUG(3,("flush\n"));
5566 END_PROFILE(SMBflush);
5567 return;
5570 /****************************************************************************
5571 Reply to a exit.
5572 conn POINTER CAN BE NULL HERE !
5573 ****************************************************************************/
5575 void reply_exit(struct smb_request *req)
5577 START_PROFILE(SMBexit);
5579 file_close_pid(req->sconn, req->smbpid, req->vuid);
5581 reply_outbuf(req, 0, 0);
5583 DEBUG(3,("exit\n"));
5585 END_PROFILE(SMBexit);
5586 return;
5589 struct reply_close_state {
5590 files_struct *fsp;
5591 struct smb_request *smbreq;
5594 static void do_smb1_close(struct tevent_req *req);
5596 void reply_close(struct smb_request *req)
5598 connection_struct *conn = req->conn;
5599 NTSTATUS status = NT_STATUS_OK;
5600 files_struct *fsp = NULL;
5601 START_PROFILE(SMBclose);
5603 if (req->wct < 3) {
5604 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5605 END_PROFILE(SMBclose);
5606 return;
5609 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5612 * We can only use check_fsp if we know it's not a directory.
5615 if (!check_fsp_open(conn, req, fsp)) {
5616 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5617 END_PROFILE(SMBclose);
5618 return;
5621 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5622 fsp->is_directory ? "directory" : "file",
5623 fsp->fh->fd, fsp_fnum_dbg(fsp),
5624 conn->num_files_open));
5626 if (!fsp->is_directory) {
5627 time_t t;
5630 * Take care of any time sent in the close.
5633 t = srv_make_unix_date3(req->vwv+1);
5634 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5637 if (fsp->num_aio_requests != 0) {
5639 struct reply_close_state *state;
5641 DEBUG(10, ("closing with aio %u requests pending\n",
5642 fsp->num_aio_requests));
5645 * We depend on the aio_extra destructor to take care of this
5646 * close request once fsp->num_aio_request drops to 0.
5649 fsp->deferred_close = tevent_wait_send(
5650 fsp, fsp->conn->sconn->ev_ctx);
5651 if (fsp->deferred_close == NULL) {
5652 status = NT_STATUS_NO_MEMORY;
5653 goto done;
5656 state = talloc(fsp, struct reply_close_state);
5657 if (state == NULL) {
5658 TALLOC_FREE(fsp->deferred_close);
5659 status = NT_STATUS_NO_MEMORY;
5660 goto done;
5662 state->fsp = fsp;
5663 state->smbreq = talloc_move(fsp, &req);
5664 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5665 state);
5666 END_PROFILE(SMBclose);
5667 return;
5671 * close_file() returns the unix errno if an error was detected on
5672 * close - normally this is due to a disk full error. If not then it
5673 * was probably an I/O error.
5676 status = close_file(req, fsp, NORMAL_CLOSE);
5677 done:
5678 if (!NT_STATUS_IS_OK(status)) {
5679 reply_nterror(req, status);
5680 END_PROFILE(SMBclose);
5681 return;
5684 reply_outbuf(req, 0, 0);
5685 END_PROFILE(SMBclose);
5686 return;
5689 static void do_smb1_close(struct tevent_req *req)
5691 struct reply_close_state *state = tevent_req_callback_data(
5692 req, struct reply_close_state);
5693 struct smb_request *smbreq;
5694 NTSTATUS status;
5695 int ret;
5697 ret = tevent_wait_recv(req);
5698 TALLOC_FREE(req);
5699 if (ret != 0) {
5700 DEBUG(10, ("tevent_wait_recv returned %s\n",
5701 strerror(ret)));
5703 * Continue anyway, this should never happen
5708 * fsp->smb2_close_request right now is a talloc grandchild of
5709 * fsp. When we close_file(fsp), it would go with it. No chance to
5710 * reply...
5712 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5714 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5715 if (NT_STATUS_IS_OK(status)) {
5716 reply_outbuf(smbreq, 0, 0);
5717 } else {
5718 reply_nterror(smbreq, status);
5720 if (!srv_send_smb(smbreq->xconn,
5721 (char *)smbreq->outbuf,
5722 true,
5723 smbreq->seqnum+1,
5724 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5725 NULL)) {
5726 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5727 "failed.");
5729 TALLOC_FREE(smbreq);
5732 /****************************************************************************
5733 Reply to a writeclose (Core+ protocol).
5734 ****************************************************************************/
5736 void reply_writeclose(struct smb_request *req)
5738 connection_struct *conn = req->conn;
5739 size_t numtowrite;
5740 size_t remaining;
5741 ssize_t nwritten = -1;
5742 NTSTATUS close_status = NT_STATUS_OK;
5743 off_t startpos;
5744 const char *data;
5745 struct timespec mtime;
5746 files_struct *fsp;
5747 struct lock_struct lock;
5749 START_PROFILE(SMBwriteclose);
5751 if (req->wct < 6) {
5752 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5753 END_PROFILE(SMBwriteclose);
5754 return;
5757 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5759 if (!check_fsp(conn, req, fsp)) {
5760 END_PROFILE(SMBwriteclose);
5761 return;
5763 if (!CHECK_WRITE(fsp)) {
5764 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5765 END_PROFILE(SMBwriteclose);
5766 return;
5769 numtowrite = SVAL(req->vwv+1, 0);
5770 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5771 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5772 data = (const char *)req->buf + 1;
5775 * Ensure client isn't asking us to write more than
5776 * they sent. CVE-2017-12163.
5778 remaining = smbreq_bufrem(req, data);
5779 if (numtowrite > remaining) {
5780 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5781 END_PROFILE(SMBwriteclose);
5782 return;
5785 if (fsp->print_file == NULL) {
5786 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5787 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5788 &lock);
5790 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5791 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5792 END_PROFILE(SMBwriteclose);
5793 return;
5797 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5799 set_close_write_time(fsp, mtime);
5802 * More insanity. W2K only closes the file if writelen > 0.
5803 * JRA.
5806 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5807 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5808 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5810 if (numtowrite) {
5811 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5812 "file %s\n", fsp_str_dbg(fsp)));
5813 close_status = close_file(req, fsp, NORMAL_CLOSE);
5814 fsp = NULL;
5817 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5818 reply_nterror(req, NT_STATUS_DISK_FULL);
5819 goto out;
5822 if(!NT_STATUS_IS_OK(close_status)) {
5823 reply_nterror(req, close_status);
5824 goto out;
5827 reply_outbuf(req, 1, 0);
5829 SSVAL(req->outbuf,smb_vwv0,nwritten);
5831 out:
5833 END_PROFILE(SMBwriteclose);
5834 return;
5837 #undef DBGC_CLASS
5838 #define DBGC_CLASS DBGC_LOCKING
5840 /****************************************************************************
5841 Reply to a lock.
5842 ****************************************************************************/
5844 static void reply_lock_done(struct tevent_req *subreq);
5846 void reply_lock(struct smb_request *req)
5848 struct tevent_req *subreq = NULL;
5849 connection_struct *conn = req->conn;
5850 files_struct *fsp;
5851 struct smbd_lock_element *lck = NULL;
5853 START_PROFILE(SMBlock);
5855 if (req->wct < 5) {
5856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5857 END_PROFILE(SMBlock);
5858 return;
5861 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5863 if (!check_fsp(conn, req, fsp)) {
5864 END_PROFILE(SMBlock);
5865 return;
5868 lck = talloc(req, struct smbd_lock_element);
5869 if (lck == NULL) {
5870 reply_nterror(req, NT_STATUS_NO_MEMORY);
5871 END_PROFILE(SMBlock);
5872 return;
5875 *lck = (struct smbd_lock_element) {
5876 .req_guid = smbd_request_guid(req, 0),
5877 .smblctx = req->smbpid,
5878 .brltype = WRITE_LOCK,
5879 .count = IVAL(req->vwv+1, 0),
5880 .offset = IVAL(req->vwv+3, 0),
5883 DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
5884 fsp->fh->fd,
5885 fsp_fnum_dbg(fsp),
5886 lck->offset,
5887 lck->count);
5889 subreq = smbd_smb1_do_locks_send(
5890 fsp,
5891 req->sconn->ev_ctx,
5892 &req,
5893 fsp,
5895 false, /* large_offset */
5896 WINDOWS_LOCK,
5898 lck);
5899 if (subreq == NULL) {
5900 reply_nterror(req, NT_STATUS_NO_MEMORY);
5901 END_PROFILE(SMBlock);
5902 return;
5904 tevent_req_set_callback(subreq, reply_lock_done, NULL);
5905 END_PROFILE(SMBlock);
5908 static void reply_lock_done(struct tevent_req *subreq)
5910 struct smb_request *req = NULL;
5911 NTSTATUS status;
5912 bool ok;
5914 START_PROFILE(SMBlock);
5916 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
5917 SMB_ASSERT(ok);
5919 status = smbd_smb1_do_locks_recv(subreq);
5920 TALLOC_FREE(subreq);
5922 if (NT_STATUS_IS_OK(status)) {
5923 reply_outbuf(req, 0, 0);
5924 } else {
5925 reply_nterror(req, status);
5928 ok = srv_send_smb(req->xconn,
5929 (char *)req->outbuf,
5930 true,
5931 req->seqnum+1,
5932 IS_CONN_ENCRYPTED(req->conn),
5933 NULL);
5934 if (!ok) {
5935 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
5937 TALLOC_FREE(req);
5938 END_PROFILE(SMBlock);
5941 /****************************************************************************
5942 Reply to a unlock.
5943 ****************************************************************************/
5945 void reply_unlock(struct smb_request *req)
5947 connection_struct *conn = req->conn;
5948 NTSTATUS status;
5949 files_struct *fsp;
5950 struct smbd_lock_element lck;
5952 START_PROFILE(SMBunlock);
5954 if (req->wct < 5) {
5955 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5956 END_PROFILE(SMBunlock);
5957 return;
5960 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5962 if (!check_fsp(conn, req, fsp)) {
5963 END_PROFILE(SMBunlock);
5964 return;
5967 lck = (struct smbd_lock_element) {
5968 .req_guid = smbd_request_guid(req, 0),
5969 .smblctx = req->smbpid,
5970 .brltype = UNLOCK_LOCK,
5971 .offset = IVAL(req->vwv+3, 0),
5972 .count = IVAL(req->vwv+1, 0),
5975 status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
5977 if (!NT_STATUS_IS_OK(status)) {
5978 reply_nterror(req, status);
5979 END_PROFILE(SMBunlock);
5980 return;
5983 DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
5984 fsp->fh->fd,
5985 fsp_fnum_dbg(fsp),
5986 lck.offset,
5987 lck.count);
5989 reply_outbuf(req, 0, 0);
5991 END_PROFILE(SMBunlock);
5992 return;
5995 #undef DBGC_CLASS
5996 #define DBGC_CLASS DBGC_ALL
5998 /****************************************************************************
5999 Reply to a tdis.
6000 conn POINTER CAN BE NULL HERE !
6001 ****************************************************************************/
6003 void reply_tdis(struct smb_request *req)
6005 NTSTATUS status;
6006 connection_struct *conn = req->conn;
6007 struct smbXsrv_tcon *tcon;
6009 START_PROFILE(SMBtdis);
6011 if (!conn) {
6012 DEBUG(4,("Invalid connection in tdis\n"));
6013 reply_force_doserror(req, ERRSRV, ERRinvnid);
6014 END_PROFILE(SMBtdis);
6015 return;
6018 tcon = conn->tcon;
6019 req->conn = NULL;
6022 * TODO: cancel all outstanding requests on the tcon
6024 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
6025 if (!NT_STATUS_IS_OK(status)) {
6026 DEBUG(0, ("reply_tdis: "
6027 "smbXsrv_tcon_disconnect() failed: %s\n",
6028 nt_errstr(status)));
6030 * If we hit this case, there is something completely
6031 * wrong, so we better disconnect the transport connection.
6033 END_PROFILE(SMBtdis);
6034 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
6035 return;
6038 TALLOC_FREE(tcon);
6040 reply_outbuf(req, 0, 0);
6041 END_PROFILE(SMBtdis);
6042 return;
6045 /****************************************************************************
6046 Reply to a echo.
6047 conn POINTER CAN BE NULL HERE !
6048 ****************************************************************************/
6050 void reply_echo(struct smb_request *req)
6052 connection_struct *conn = req->conn;
6053 struct smb_perfcount_data local_pcd;
6054 struct smb_perfcount_data *cur_pcd;
6055 int smb_reverb;
6056 int seq_num;
6058 START_PROFILE(SMBecho);
6060 smb_init_perfcount_data(&local_pcd);
6062 if (req->wct < 1) {
6063 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6064 END_PROFILE(SMBecho);
6065 return;
6068 smb_reverb = SVAL(req->vwv+0, 0);
6070 reply_outbuf(req, 1, req->buflen);
6072 /* copy any incoming data back out */
6073 if (req->buflen > 0) {
6074 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
6077 if (smb_reverb > 100) {
6078 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
6079 smb_reverb = 100;
6082 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
6084 /* this makes sure we catch the request pcd */
6085 if (seq_num == smb_reverb) {
6086 cur_pcd = &req->pcd;
6087 } else {
6088 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
6089 cur_pcd = &local_pcd;
6092 SSVAL(req->outbuf,smb_vwv0,seq_num);
6094 show_msg((char *)req->outbuf);
6095 if (!srv_send_smb(req->xconn,
6096 (char *)req->outbuf,
6097 true, req->seqnum+1,
6098 IS_CONN_ENCRYPTED(conn)||req->encrypted,
6099 cur_pcd))
6100 exit_server_cleanly("reply_echo: srv_send_smb failed.");
6103 DEBUG(3,("echo %d times\n", smb_reverb));
6105 TALLOC_FREE(req->outbuf);
6107 END_PROFILE(SMBecho);
6108 return;
6111 /****************************************************************************
6112 Reply to a printopen.
6113 ****************************************************************************/
6115 void reply_printopen(struct smb_request *req)
6117 connection_struct *conn = req->conn;
6118 files_struct *fsp;
6119 NTSTATUS status;
6121 START_PROFILE(SMBsplopen);
6123 if (req->wct < 2) {
6124 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6125 END_PROFILE(SMBsplopen);
6126 return;
6129 if (!CAN_PRINT(conn)) {
6130 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6131 END_PROFILE(SMBsplopen);
6132 return;
6135 status = file_new(req, conn, &fsp);
6136 if(!NT_STATUS_IS_OK(status)) {
6137 reply_nterror(req, status);
6138 END_PROFILE(SMBsplopen);
6139 return;
6142 /* Open for exclusive use, write only. */
6143 status = print_spool_open(fsp, NULL, req->vuid);
6145 if (!NT_STATUS_IS_OK(status)) {
6146 file_free(req, fsp);
6147 reply_nterror(req, status);
6148 END_PROFILE(SMBsplopen);
6149 return;
6152 reply_outbuf(req, 1, 0);
6153 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
6155 DEBUG(3,("openprint fd=%d %s\n",
6156 fsp->fh->fd, fsp_fnum_dbg(fsp)));
6158 END_PROFILE(SMBsplopen);
6159 return;
6162 /****************************************************************************
6163 Reply to a printclose.
6164 ****************************************************************************/
6166 void reply_printclose(struct smb_request *req)
6168 connection_struct *conn = req->conn;
6169 files_struct *fsp;
6170 NTSTATUS status;
6172 START_PROFILE(SMBsplclose);
6174 if (req->wct < 1) {
6175 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6176 END_PROFILE(SMBsplclose);
6177 return;
6180 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6182 if (!check_fsp(conn, req, fsp)) {
6183 END_PROFILE(SMBsplclose);
6184 return;
6187 if (!CAN_PRINT(conn)) {
6188 reply_force_doserror(req, ERRSRV, ERRerror);
6189 END_PROFILE(SMBsplclose);
6190 return;
6193 DEBUG(3,("printclose fd=%d %s\n",
6194 fsp->fh->fd, fsp_fnum_dbg(fsp)));
6196 status = close_file(req, fsp, NORMAL_CLOSE);
6198 if(!NT_STATUS_IS_OK(status)) {
6199 reply_nterror(req, status);
6200 END_PROFILE(SMBsplclose);
6201 return;
6204 reply_outbuf(req, 0, 0);
6206 END_PROFILE(SMBsplclose);
6207 return;
6210 /****************************************************************************
6211 Reply to a printqueue.
6212 ****************************************************************************/
6214 void reply_printqueue(struct smb_request *req)
6216 connection_struct *conn = req->conn;
6217 int max_count;
6218 int start_index;
6220 START_PROFILE(SMBsplretq);
6222 if (req->wct < 2) {
6223 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6224 END_PROFILE(SMBsplretq);
6225 return;
6228 max_count = SVAL(req->vwv+0, 0);
6229 start_index = SVAL(req->vwv+1, 0);
6231 /* we used to allow the client to get the cnum wrong, but that
6232 is really quite gross and only worked when there was only
6233 one printer - I think we should now only accept it if they
6234 get it right (tridge) */
6235 if (!CAN_PRINT(conn)) {
6236 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6237 END_PROFILE(SMBsplretq);
6238 return;
6241 reply_outbuf(req, 2, 3);
6242 SSVAL(req->outbuf,smb_vwv0,0);
6243 SSVAL(req->outbuf,smb_vwv1,0);
6244 SCVAL(smb_buf(req->outbuf),0,1);
6245 SSVAL(smb_buf(req->outbuf),1,0);
6247 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
6248 start_index, max_count));
6251 TALLOC_CTX *mem_ctx = talloc_tos();
6252 NTSTATUS status;
6253 WERROR werr;
6254 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
6255 struct rpc_pipe_client *cli = NULL;
6256 struct dcerpc_binding_handle *b = NULL;
6257 struct policy_handle handle;
6258 struct spoolss_DevmodeContainer devmode_ctr;
6259 union spoolss_JobInfo *info;
6260 uint32_t count;
6261 uint32_t num_to_get;
6262 uint32_t first;
6263 uint32_t i;
6265 ZERO_STRUCT(handle);
6267 status = rpc_pipe_open_interface(mem_ctx,
6268 &ndr_table_spoolss,
6269 conn->session_info,
6270 conn->sconn->remote_address,
6271 conn->sconn->local_address,
6272 conn->sconn->msg_ctx,
6273 &cli);
6274 if (!NT_STATUS_IS_OK(status)) {
6275 DEBUG(0, ("reply_printqueue: "
6276 "could not connect to spoolss: %s\n",
6277 nt_errstr(status)));
6278 reply_nterror(req, status);
6279 goto out;
6281 b = cli->binding_handle;
6283 ZERO_STRUCT(devmode_ctr);
6285 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
6286 sharename,
6287 NULL, devmode_ctr,
6288 SEC_FLAG_MAXIMUM_ALLOWED,
6289 &handle,
6290 &werr);
6291 if (!NT_STATUS_IS_OK(status)) {
6292 reply_nterror(req, status);
6293 goto out;
6295 if (!W_ERROR_IS_OK(werr)) {
6296 reply_nterror(req, werror_to_ntstatus(werr));
6297 goto out;
6300 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6301 &handle,
6302 0, /* firstjob */
6303 0xff, /* numjobs */
6304 2, /* level */
6305 0, /* offered */
6306 &count,
6307 &info);
6308 if (!W_ERROR_IS_OK(werr)) {
6309 reply_nterror(req, werror_to_ntstatus(werr));
6310 goto out;
6313 if (max_count > 0) {
6314 first = start_index;
6315 } else {
6316 first = start_index + max_count + 1;
6319 if (first >= count) {
6320 num_to_get = first;
6321 } else {
6322 num_to_get = first + MIN(ABS(max_count), count - first);
6325 for (i = first; i < num_to_get; i++) {
6326 char blob[28];
6327 char *p = blob;
6328 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6329 int qstatus;
6330 size_t len = 0;
6331 uint16_t qrapjobid = pjobid_to_rap(sharename,
6332 info[i].info2.job_id);
6334 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6335 qstatus = 2;
6336 } else {
6337 qstatus = 3;
6340 srv_put_dos_date2(p, 0, qtime);
6341 SCVAL(p, 4, qstatus);
6342 SSVAL(p, 5, qrapjobid);
6343 SIVAL(p, 7, info[i].info2.size);
6344 SCVAL(p, 11, 0);
6345 status = srvstr_push(blob, req->flags2, p+12,
6346 info[i].info2.notify_name, 16, STR_ASCII, &len);
6347 if (!NT_STATUS_IS_OK(status)) {
6348 reply_nterror(req, status);
6349 goto out;
6351 if (message_push_blob(
6352 &req->outbuf,
6353 data_blob_const(
6354 blob, sizeof(blob))) == -1) {
6355 reply_nterror(req, NT_STATUS_NO_MEMORY);
6356 goto out;
6360 if (count > 0) {
6361 SSVAL(req->outbuf,smb_vwv0,count);
6362 SSVAL(req->outbuf,smb_vwv1,
6363 (max_count>0?first+count:first-1));
6364 SCVAL(smb_buf(req->outbuf),0,1);
6365 SSVAL(smb_buf(req->outbuf),1,28*count);
6369 DEBUG(3, ("%u entries returned in queue\n",
6370 (unsigned)count));
6372 out:
6373 if (b && is_valid_policy_hnd(&handle)) {
6374 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6379 END_PROFILE(SMBsplretq);
6380 return;
6383 /****************************************************************************
6384 Reply to a printwrite.
6385 ****************************************************************************/
6387 void reply_printwrite(struct smb_request *req)
6389 connection_struct *conn = req->conn;
6390 int numtowrite;
6391 const char *data;
6392 files_struct *fsp;
6394 START_PROFILE(SMBsplwr);
6396 if (req->wct < 1) {
6397 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6398 END_PROFILE(SMBsplwr);
6399 return;
6402 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6404 if (!check_fsp(conn, req, fsp)) {
6405 END_PROFILE(SMBsplwr);
6406 return;
6409 if (!fsp->print_file) {
6410 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6411 END_PROFILE(SMBsplwr);
6412 return;
6415 if (!CHECK_WRITE(fsp)) {
6416 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6417 END_PROFILE(SMBsplwr);
6418 return;
6421 numtowrite = SVAL(req->buf, 1);
6424 * This already protects us against CVE-2017-12163.
6426 if (req->buflen < numtowrite + 3) {
6427 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6428 END_PROFILE(SMBsplwr);
6429 return;
6432 data = (const char *)req->buf + 3;
6434 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6435 reply_nterror(req, map_nt_error_from_unix(errno));
6436 END_PROFILE(SMBsplwr);
6437 return;
6440 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6442 END_PROFILE(SMBsplwr);
6443 return;
6446 /****************************************************************************
6447 Reply to a mkdir.
6448 ****************************************************************************/
6450 void reply_mkdir(struct smb_request *req)
6452 connection_struct *conn = req->conn;
6453 struct smb_filename *smb_dname = NULL;
6454 char *directory = NULL;
6455 NTSTATUS status;
6456 uint32_t ucf_flags;
6457 TALLOC_CTX *ctx = talloc_tos();
6459 START_PROFILE(SMBmkdir);
6461 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6462 STR_TERMINATE, &status);
6463 if (!NT_STATUS_IS_OK(status)) {
6464 reply_nterror(req, status);
6465 goto out;
6468 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6469 status = filename_convert(ctx, conn,
6470 directory,
6471 ucf_flags,
6472 NULL,
6473 NULL,
6474 &smb_dname);
6475 if (!NT_STATUS_IS_OK(status)) {
6476 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6477 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6478 ERRSRV, ERRbadpath);
6479 goto out;
6481 reply_nterror(req, status);
6482 goto out;
6485 status = create_directory(conn, req, smb_dname);
6487 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6489 if (!NT_STATUS_IS_OK(status)) {
6491 if (!use_nt_status()
6492 && NT_STATUS_EQUAL(status,
6493 NT_STATUS_OBJECT_NAME_COLLISION)) {
6495 * Yes, in the DOS error code case we get a
6496 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6497 * samba4 torture test.
6499 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6502 reply_nterror(req, status);
6503 goto out;
6506 reply_outbuf(req, 0, 0);
6508 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6509 out:
6510 TALLOC_FREE(smb_dname);
6511 END_PROFILE(SMBmkdir);
6512 return;
6515 /****************************************************************************
6516 Reply to a rmdir.
6517 ****************************************************************************/
6519 void reply_rmdir(struct smb_request *req)
6521 connection_struct *conn = req->conn;
6522 struct smb_filename *smb_dname = NULL;
6523 char *directory = NULL;
6524 NTSTATUS status;
6525 TALLOC_CTX *ctx = talloc_tos();
6526 files_struct *fsp = NULL;
6527 int info = 0;
6528 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6530 START_PROFILE(SMBrmdir);
6532 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6533 STR_TERMINATE, &status);
6534 if (!NT_STATUS_IS_OK(status)) {
6535 reply_nterror(req, status);
6536 goto out;
6539 status = filename_convert(ctx, conn,
6540 directory,
6541 ucf_flags,
6542 NULL,
6543 NULL,
6544 &smb_dname);
6545 if (!NT_STATUS_IS_OK(status)) {
6546 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6547 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6548 ERRSRV, ERRbadpath);
6549 goto out;
6551 reply_nterror(req, status);
6552 goto out;
6555 if (is_ntfs_stream_smb_fname(smb_dname)) {
6556 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6557 goto out;
6560 status = SMB_VFS_CREATE_FILE(
6561 conn, /* conn */
6562 req, /* req */
6563 0, /* root_dir_fid */
6564 smb_dname, /* fname */
6565 DELETE_ACCESS, /* access_mask */
6566 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6567 FILE_SHARE_DELETE),
6568 FILE_OPEN, /* create_disposition*/
6569 FILE_DIRECTORY_FILE, /* create_options */
6570 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6571 0, /* oplock_request */
6572 NULL, /* lease */
6573 0, /* allocation_size */
6574 0, /* private_flags */
6575 NULL, /* sd */
6576 NULL, /* ea_list */
6577 &fsp, /* result */
6578 &info, /* pinfo */
6579 NULL, NULL); /* create context */
6581 if (!NT_STATUS_IS_OK(status)) {
6582 if (open_was_deferred(req->xconn, req->mid)) {
6583 /* We have re-scheduled this call. */
6584 goto out;
6586 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
6587 bool ok = defer_smb1_sharing_violation(req);
6588 if (ok) {
6589 goto out;
6592 reply_nterror(req, status);
6593 goto out;
6596 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6597 if (!NT_STATUS_IS_OK(status)) {
6598 close_file(req, fsp, ERROR_CLOSE);
6599 reply_nterror(req, status);
6600 goto out;
6603 if (!set_delete_on_close(fsp, true,
6604 conn->session_info->security_token,
6605 conn->session_info->unix_token)) {
6606 close_file(req, fsp, ERROR_CLOSE);
6607 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6608 goto out;
6611 status = close_file(req, fsp, NORMAL_CLOSE);
6612 if (!NT_STATUS_IS_OK(status)) {
6613 reply_nterror(req, status);
6614 } else {
6615 reply_outbuf(req, 0, 0);
6618 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6619 out:
6620 TALLOC_FREE(smb_dname);
6621 END_PROFILE(SMBrmdir);
6622 return;
6625 /*******************************************************************
6626 Resolve wildcards in a filename rename.
6627 ********************************************************************/
6629 static bool resolve_wildcards(TALLOC_CTX *ctx,
6630 const char *name1,
6631 const char *name2,
6632 char **pp_newname)
6634 char *name2_copy = NULL;
6635 char *root1 = NULL;
6636 char *root2 = NULL;
6637 char *ext1 = NULL;
6638 char *ext2 = NULL;
6639 char *p,*p2, *pname1, *pname2;
6641 name2_copy = talloc_strdup(ctx, name2);
6642 if (!name2_copy) {
6643 return False;
6646 pname1 = strrchr_m(name1,'/');
6647 pname2 = strrchr_m(name2_copy,'/');
6649 if (!pname1 || !pname2) {
6650 return False;
6653 /* Truncate the copy of name2 at the last '/' */
6654 *pname2 = '\0';
6656 /* Now go past the '/' */
6657 pname1++;
6658 pname2++;
6660 root1 = talloc_strdup(ctx, pname1);
6661 root2 = talloc_strdup(ctx, pname2);
6663 if (!root1 || !root2) {
6664 return False;
6667 p = strrchr_m(root1,'.');
6668 if (p) {
6669 *p = 0;
6670 ext1 = talloc_strdup(ctx, p+1);
6671 } else {
6672 ext1 = talloc_strdup(ctx, "");
6674 p = strrchr_m(root2,'.');
6675 if (p) {
6676 *p = 0;
6677 ext2 = talloc_strdup(ctx, p+1);
6678 } else {
6679 ext2 = talloc_strdup(ctx, "");
6682 if (!ext1 || !ext2) {
6683 return False;
6686 p = root1;
6687 p2 = root2;
6688 while (*p2) {
6689 if (*p2 == '?') {
6690 /* Hmmm. Should this be mb-aware ? */
6691 *p2 = *p;
6692 p2++;
6693 } else if (*p2 == '*') {
6694 *p2 = '\0';
6695 root2 = talloc_asprintf(ctx, "%s%s",
6696 root2,
6698 if (!root2) {
6699 return False;
6701 break;
6702 } else {
6703 p2++;
6705 if (*p) {
6706 p++;
6710 p = ext1;
6711 p2 = ext2;
6712 while (*p2) {
6713 if (*p2 == '?') {
6714 /* Hmmm. Should this be mb-aware ? */
6715 *p2 = *p;
6716 p2++;
6717 } else if (*p2 == '*') {
6718 *p2 = '\0';
6719 ext2 = talloc_asprintf(ctx, "%s%s",
6720 ext2,
6722 if (!ext2) {
6723 return False;
6725 break;
6726 } else {
6727 p2++;
6729 if (*p) {
6730 p++;
6734 if (*ext2) {
6735 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6736 name2_copy,
6737 root2,
6738 ext2);
6739 } else {
6740 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6741 name2_copy,
6742 root2);
6745 if (!*pp_newname) {
6746 return False;
6749 return True;
6752 /****************************************************************************
6753 Ensure open files have their names updated. Updated to notify other smbd's
6754 asynchronously.
6755 ****************************************************************************/
6757 static void rename_open_files(connection_struct *conn,
6758 struct share_mode_lock *lck,
6759 struct file_id id,
6760 uint32_t orig_name_hash,
6761 const struct smb_filename *smb_fname_dst)
6763 files_struct *fsp;
6764 bool did_rename = False;
6765 NTSTATUS status;
6766 uint32_t new_name_hash = 0;
6768 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6769 fsp = file_find_di_next(fsp)) {
6770 /* fsp_name is a relative path under the fsp. To change this for other
6771 sharepaths we need to manipulate relative paths. */
6772 /* TODO - create the absolute path and manipulate the newname
6773 relative to the sharepath. */
6774 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6775 continue;
6777 if (fsp->name_hash != orig_name_hash) {
6778 continue;
6780 DEBUG(10, ("rename_open_files: renaming file %s "
6781 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6782 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6783 smb_fname_str_dbg(smb_fname_dst)));
6785 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6786 if (NT_STATUS_IS_OK(status)) {
6787 did_rename = True;
6788 new_name_hash = fsp->name_hash;
6792 if (!did_rename) {
6793 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6794 "for %s\n", file_id_string_tos(&id),
6795 smb_fname_str_dbg(smb_fname_dst)));
6798 /* Send messages to all smbd's (not ourself) that the name has changed. */
6799 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6800 orig_name_hash, new_name_hash,
6801 smb_fname_dst);
6805 /****************************************************************************
6806 We need to check if the source path is a parent directory of the destination
6807 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6808 refuse the rename with a sharing violation. Under UNIX the above call can
6809 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6810 probably need to check that the client is a Windows one before disallowing
6811 this as a UNIX client (one with UNIX extensions) can know the source is a
6812 symlink and make this decision intelligently. Found by an excellent bug
6813 report from <AndyLiebman@aol.com>.
6814 ****************************************************************************/
6816 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6817 const struct smb_filename *smb_fname_dst)
6819 const char *psrc = smb_fname_src->base_name;
6820 const char *pdst = smb_fname_dst->base_name;
6821 size_t slen;
6823 if (psrc[0] == '.' && psrc[1] == '/') {
6824 psrc += 2;
6826 if (pdst[0] == '.' && pdst[1] == '/') {
6827 pdst += 2;
6829 if ((slen = strlen(psrc)) > strlen(pdst)) {
6830 return False;
6832 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6836 * Do the notify calls from a rename
6839 static void notify_rename(connection_struct *conn, bool is_dir,
6840 const struct smb_filename *smb_fname_src,
6841 const struct smb_filename *smb_fname_dst)
6843 char *parent_dir_src = NULL;
6844 char *parent_dir_dst = NULL;
6845 uint32_t mask;
6847 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6848 : FILE_NOTIFY_CHANGE_FILE_NAME;
6850 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6851 &parent_dir_src, NULL) ||
6852 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6853 &parent_dir_dst, NULL)) {
6854 goto out;
6857 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6858 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6859 smb_fname_src->base_name);
6860 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6861 smb_fname_dst->base_name);
6863 else {
6864 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6865 smb_fname_src->base_name);
6866 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6867 smb_fname_dst->base_name);
6870 /* this is a strange one. w2k3 gives an additional event for
6871 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6872 files, but not directories */
6873 if (!is_dir) {
6874 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6875 FILE_NOTIFY_CHANGE_ATTRIBUTES
6876 |FILE_NOTIFY_CHANGE_CREATION,
6877 smb_fname_dst->base_name);
6879 out:
6880 TALLOC_FREE(parent_dir_src);
6881 TALLOC_FREE(parent_dir_dst);
6884 /****************************************************************************
6885 Returns an error if the parent directory for a filename is open in an
6886 incompatible way.
6887 ****************************************************************************/
6889 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6890 const struct smb_filename *smb_fname_dst_in)
6892 char *parent_dir = NULL;
6893 struct smb_filename smb_fname_parent;
6894 struct file_id id;
6895 files_struct *fsp = NULL;
6896 int ret;
6898 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6899 &parent_dir, NULL)) {
6900 return NT_STATUS_NO_MEMORY;
6902 ZERO_STRUCT(smb_fname_parent);
6903 smb_fname_parent.base_name = parent_dir;
6905 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6906 if (ret == -1) {
6907 return map_nt_error_from_unix(errno);
6911 * We're only checking on this smbd here, mostly good
6912 * enough.. and will pass tests.
6915 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6916 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6917 fsp = file_find_di_next(fsp)) {
6918 if (fsp->access_mask & DELETE_ACCESS) {
6919 return NT_STATUS_SHARING_VIOLATION;
6922 return NT_STATUS_OK;
6925 /****************************************************************************
6926 Rename an open file - given an fsp.
6927 ****************************************************************************/
6929 NTSTATUS rename_internals_fsp(connection_struct *conn,
6930 files_struct *fsp,
6931 const struct smb_filename *smb_fname_dst_in,
6932 uint32_t attrs,
6933 bool replace_if_exists)
6935 TALLOC_CTX *ctx = talloc_tos();
6936 struct smb_filename *smb_fname_dst = NULL;
6937 NTSTATUS status = NT_STATUS_OK;
6938 struct share_mode_lock *lck = NULL;
6939 uint32_t access_mask = SEC_DIR_ADD_FILE;
6940 bool dst_exists, old_is_stream, new_is_stream;
6941 int ret;
6943 status = check_name(conn, smb_fname_dst_in);
6944 if (!NT_STATUS_IS_OK(status)) {
6945 return status;
6948 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6949 if (!NT_STATUS_IS_OK(status)) {
6950 return status;
6953 if (file_has_open_streams(fsp)) {
6954 return NT_STATUS_ACCESS_DENIED;
6957 /* Make a copy of the dst smb_fname structs */
6959 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6960 if (smb_fname_dst == NULL) {
6961 status = NT_STATUS_NO_MEMORY;
6962 goto out;
6966 * Check for special case with case preserving and not
6967 * case sensitive. If the new last component differs from the original
6968 * last component only by case, then we should allow
6969 * the rename (user is trying to change the case of the
6970 * filename).
6972 if (!conn->case_sensitive && conn->case_preserve &&
6973 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6974 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6975 char *fname_dst_parent = NULL;
6976 const char *fname_dst_lcomp = NULL;
6977 char *orig_lcomp_path = NULL;
6978 char *orig_lcomp_stream = NULL;
6979 bool ok = true;
6982 * Split off the last component of the processed
6983 * destination name. We will compare this to
6984 * the split components of smb_fname_dst->original_lcomp.
6986 if (!parent_dirname(ctx,
6987 smb_fname_dst->base_name,
6988 &fname_dst_parent,
6989 &fname_dst_lcomp)) {
6990 status = NT_STATUS_NO_MEMORY;
6991 goto out;
6995 * The original_lcomp component contains
6996 * the last_component of the path + stream
6997 * name (if a stream exists).
6999 * Split off the stream name so we
7000 * can check them separately.
7003 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
7004 /* POSIX - no stream component. */
7005 orig_lcomp_path = talloc_strdup(ctx,
7006 smb_fname_dst->original_lcomp);
7007 if (orig_lcomp_path == NULL) {
7008 ok = false;
7010 } else {
7011 ok = split_stream_filename(ctx,
7012 smb_fname_dst->original_lcomp,
7013 &orig_lcomp_path,
7014 &orig_lcomp_stream);
7017 if (!ok) {
7018 TALLOC_FREE(fname_dst_parent);
7019 status = NT_STATUS_NO_MEMORY;
7020 goto out;
7023 /* If the base names only differ by case, use original. */
7024 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
7025 char *tmp;
7027 * Replace the modified last component with the
7028 * original.
7030 if (!ISDOT(fname_dst_parent)) {
7031 tmp = talloc_asprintf(smb_fname_dst,
7032 "%s/%s",
7033 fname_dst_parent,
7034 orig_lcomp_path);
7035 } else {
7036 tmp = talloc_strdup(smb_fname_dst,
7037 orig_lcomp_path);
7039 if (tmp == NULL) {
7040 status = NT_STATUS_NO_MEMORY;
7041 TALLOC_FREE(fname_dst_parent);
7042 TALLOC_FREE(orig_lcomp_path);
7043 TALLOC_FREE(orig_lcomp_stream);
7044 goto out;
7046 TALLOC_FREE(smb_fname_dst->base_name);
7047 smb_fname_dst->base_name = tmp;
7050 /* If the stream_names only differ by case, use original. */
7051 if(!strcsequal(smb_fname_dst->stream_name,
7052 orig_lcomp_stream)) {
7053 /* Use the original stream. */
7054 char *tmp = talloc_strdup(smb_fname_dst,
7055 orig_lcomp_stream);
7056 if (tmp == NULL) {
7057 status = NT_STATUS_NO_MEMORY;
7058 TALLOC_FREE(fname_dst_parent);
7059 TALLOC_FREE(orig_lcomp_path);
7060 TALLOC_FREE(orig_lcomp_stream);
7061 goto out;
7063 TALLOC_FREE(smb_fname_dst->stream_name);
7064 smb_fname_dst->stream_name = tmp;
7066 TALLOC_FREE(fname_dst_parent);
7067 TALLOC_FREE(orig_lcomp_path);
7068 TALLOC_FREE(orig_lcomp_stream);
7072 * If the src and dest names are identical - including case,
7073 * don't do the rename, just return success.
7076 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
7077 strcsequal(fsp->fsp_name->stream_name,
7078 smb_fname_dst->stream_name)) {
7079 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
7080 "- returning success\n",
7081 smb_fname_str_dbg(smb_fname_dst)));
7082 status = NT_STATUS_OK;
7083 goto out;
7086 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
7087 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
7089 /* Return the correct error code if both names aren't streams. */
7090 if (!old_is_stream && new_is_stream) {
7091 status = NT_STATUS_OBJECT_NAME_INVALID;
7092 goto out;
7095 if (old_is_stream && !new_is_stream) {
7096 status = NT_STATUS_INVALID_PARAMETER;
7097 goto out;
7100 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
7102 if(!replace_if_exists && dst_exists) {
7103 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
7104 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7105 smb_fname_str_dbg(smb_fname_dst)));
7106 status = NT_STATUS_OBJECT_NAME_COLLISION;
7107 goto out;
7110 if (dst_exists) {
7111 struct file_id fileid = vfs_file_id_from_sbuf(conn,
7112 &smb_fname_dst->st);
7113 files_struct *dst_fsp = file_find_di_first(conn->sconn,
7114 fileid);
7115 /* The file can be open when renaming a stream */
7116 if (dst_fsp && !new_is_stream) {
7117 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
7118 status = NT_STATUS_ACCESS_DENIED;
7119 goto out;
7123 /* Ensure we have a valid stat struct for the source. */
7124 status = vfs_stat_fsp(fsp);
7125 if (!NT_STATUS_IS_OK(status)) {
7126 goto out;
7129 status = can_rename(conn, fsp, attrs);
7131 if (!NT_STATUS_IS_OK(status)) {
7132 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7133 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7134 smb_fname_str_dbg(smb_fname_dst)));
7135 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
7136 status = NT_STATUS_ACCESS_DENIED;
7137 goto out;
7140 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
7141 status = NT_STATUS_ACCESS_DENIED;
7142 goto out;
7145 /* Do we have rights to move into the destination ? */
7146 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
7147 /* We're moving a directory. */
7148 access_mask = SEC_DIR_ADD_SUBDIR;
7150 status = check_parent_access(conn,
7151 smb_fname_dst,
7152 access_mask);
7153 if (!NT_STATUS_IS_OK(status)) {
7154 DBG_INFO("check_parent_access on "
7155 "dst %s returned %s\n",
7156 smb_fname_str_dbg(smb_fname_dst),
7157 nt_errstr(status));
7158 goto out;
7161 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
7164 * We have the file open ourselves, so not being able to get the
7165 * corresponding share mode lock is a fatal error.
7168 SMB_ASSERT(lck != NULL);
7170 ret = SMB_VFS_RENAMEAT(conn,
7171 conn->cwd_fsp,
7172 fsp->fsp_name,
7173 conn->cwd_fsp,
7174 smb_fname_dst);
7175 if (ret == 0) {
7176 uint32_t create_options = fsp->fh->private_options;
7178 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
7179 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
7180 smb_fname_str_dbg(smb_fname_dst)));
7182 if (!fsp->is_directory &&
7183 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
7184 (lp_map_archive(SNUM(conn)) ||
7185 lp_store_dos_attributes(SNUM(conn)))) {
7186 /* We must set the archive bit on the newly
7187 renamed file. */
7188 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
7189 uint32_t old_dosmode = dos_mode(conn,
7190 smb_fname_dst);
7191 file_set_dosmode(conn,
7192 smb_fname_dst,
7193 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
7194 NULL,
7195 true);
7199 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
7200 smb_fname_dst);
7202 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
7203 smb_fname_dst);
7206 * A rename acts as a new file create w.r.t. allowing an initial delete
7207 * on close, probably because in Windows there is a new handle to the
7208 * new file. If initial delete on close was requested but not
7209 * originally set, we need to set it here. This is probably not 100% correct,
7210 * but will work for the CIFSFS client which in non-posix mode
7211 * depends on these semantics. JRA.
7214 if (create_options & FILE_DELETE_ON_CLOSE) {
7215 status = can_set_delete_on_close(fsp, 0);
7217 if (NT_STATUS_IS_OK(status)) {
7218 /* Note that here we set the *initial* delete on close flag,
7219 * not the regular one. The magic gets handled in close. */
7220 fsp->initial_delete_on_close = True;
7223 TALLOC_FREE(lck);
7224 status = NT_STATUS_OK;
7225 goto out;
7228 TALLOC_FREE(lck);
7230 if (errno == ENOTDIR || errno == EISDIR) {
7231 status = NT_STATUS_OBJECT_NAME_COLLISION;
7232 } else {
7233 status = map_nt_error_from_unix(errno);
7236 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
7237 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
7238 smb_fname_str_dbg(smb_fname_dst)));
7240 out:
7241 TALLOC_FREE(smb_fname_dst);
7243 return status;
7246 /****************************************************************************
7247 The guts of the rename command, split out so it may be called by the NT SMB
7248 code.
7249 ****************************************************************************/
7251 NTSTATUS rename_internals(TALLOC_CTX *ctx,
7252 connection_struct *conn,
7253 struct smb_request *req,
7254 struct smb_filename *smb_fname_src,
7255 struct smb_filename *smb_fname_dst,
7256 uint32_t attrs,
7257 bool replace_if_exists,
7258 bool src_has_wild,
7259 bool dest_has_wild,
7260 uint32_t access_mask)
7262 char *fname_src_dir = NULL;
7263 struct smb_filename *smb_fname_src_dir = NULL;
7264 char *fname_src_mask = NULL;
7265 int count=0;
7266 NTSTATUS status = NT_STATUS_OK;
7267 struct smb_Dir *dir_hnd = NULL;
7268 const char *dname = NULL;
7269 char *talloced = NULL;
7270 long offset = 0;
7271 int create_options = 0;
7272 bool posix_pathnames = (req != NULL && req->posix_pathnames);
7273 int rc;
7276 * Split the old name into directory and last component
7277 * strings. Note that unix_convert may have stripped off a
7278 * leading ./ from both name and newname if the rename is
7279 * at the root of the share. We need to make sure either both
7280 * name and newname contain a / character or neither of them do
7281 * as this is checked in resolve_wildcards().
7284 /* Split up the directory from the filename/mask. */
7285 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7286 &fname_src_dir, &fname_src_mask);
7287 if (!NT_STATUS_IS_OK(status)) {
7288 status = NT_STATUS_NO_MEMORY;
7289 goto out;
7293 * We should only check the mangled cache
7294 * here if unix_convert failed. This means
7295 * that the path in 'mask' doesn't exist
7296 * on the file system and so we need to look
7297 * for a possible mangle. This patch from
7298 * Tine Smukavec <valentin.smukavec@hermes.si>.
7301 if (!VALID_STAT(smb_fname_src->st) &&
7302 mangle_is_mangled(fname_src_mask, conn->params)) {
7303 char *new_mask = NULL;
7304 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
7305 conn->params);
7306 if (new_mask) {
7307 TALLOC_FREE(fname_src_mask);
7308 fname_src_mask = new_mask;
7312 if (!src_has_wild) {
7313 files_struct *fsp;
7316 * Only one file needs to be renamed. Append the mask back
7317 * onto the directory.
7319 TALLOC_FREE(smb_fname_src->base_name);
7320 if (ISDOT(fname_src_dir)) {
7321 /* Ensure we use canonical names on open. */
7322 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7323 "%s",
7324 fname_src_mask);
7325 } else {
7326 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7327 "%s/%s",
7328 fname_src_dir,
7329 fname_src_mask);
7331 if (!smb_fname_src->base_name) {
7332 status = NT_STATUS_NO_MEMORY;
7333 goto out;
7336 DEBUG(3, ("rename_internals: case_sensitive = %d, "
7337 "case_preserve = %d, short case preserve = %d, "
7338 "directory = %s, newname = %s, "
7339 "last_component_dest = %s\n",
7340 conn->case_sensitive, conn->case_preserve,
7341 conn->short_case_preserve,
7342 smb_fname_str_dbg(smb_fname_src),
7343 smb_fname_str_dbg(smb_fname_dst),
7344 smb_fname_dst->original_lcomp));
7346 /* The dest name still may have wildcards. */
7347 if (dest_has_wild) {
7348 char *fname_dst_mod = NULL;
7349 if (!resolve_wildcards(smb_fname_dst,
7350 smb_fname_src->base_name,
7351 smb_fname_dst->base_name,
7352 &fname_dst_mod)) {
7353 DEBUG(6, ("rename_internals: resolve_wildcards "
7354 "%s %s failed\n",
7355 smb_fname_src->base_name,
7356 smb_fname_dst->base_name));
7357 status = NT_STATUS_NO_MEMORY;
7358 goto out;
7360 TALLOC_FREE(smb_fname_dst->base_name);
7361 smb_fname_dst->base_name = fname_dst_mod;
7364 ZERO_STRUCT(smb_fname_src->st);
7365 if (posix_pathnames) {
7366 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7367 } else {
7368 rc = SMB_VFS_STAT(conn, smb_fname_src);
7370 if (rc == -1) {
7371 status = map_nt_error_from_unix_common(errno);
7372 goto out;
7375 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7376 create_options |= FILE_DIRECTORY_FILE;
7379 status = SMB_VFS_CREATE_FILE(
7380 conn, /* conn */
7381 req, /* req */
7382 0, /* root_dir_fid */
7383 smb_fname_src, /* fname */
7384 access_mask, /* access_mask */
7385 (FILE_SHARE_READ | /* share_access */
7386 FILE_SHARE_WRITE),
7387 FILE_OPEN, /* create_disposition*/
7388 create_options, /* create_options */
7389 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7390 0, /* oplock_request */
7391 NULL, /* lease */
7392 0, /* allocation_size */
7393 0, /* private_flags */
7394 NULL, /* sd */
7395 NULL, /* ea_list */
7396 &fsp, /* result */
7397 NULL, /* pinfo */
7398 NULL, NULL); /* create context */
7400 if (!NT_STATUS_IS_OK(status)) {
7401 DEBUG(3, ("Could not open rename source %s: %s\n",
7402 smb_fname_str_dbg(smb_fname_src),
7403 nt_errstr(status)));
7404 goto out;
7407 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7408 attrs, replace_if_exists);
7410 close_file(req, fsp, NORMAL_CLOSE);
7412 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7413 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7414 smb_fname_str_dbg(smb_fname_dst)));
7416 goto out;
7420 * Wildcards - process each file that matches.
7422 if (strequal(fname_src_mask, "????????.???")) {
7423 TALLOC_FREE(fname_src_mask);
7424 fname_src_mask = talloc_strdup(ctx, "*");
7425 if (!fname_src_mask) {
7426 status = NT_STATUS_NO_MEMORY;
7427 goto out;
7431 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7432 fname_src_dir,
7433 NULL,
7434 NULL,
7435 smb_fname_src->flags);
7436 if (smb_fname_src_dir == NULL) {
7437 status = NT_STATUS_NO_MEMORY;
7438 goto out;
7441 status = check_name(conn, smb_fname_src_dir);
7442 if (!NT_STATUS_IS_OK(status)) {
7443 goto out;
7446 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7447 attrs);
7448 if (dir_hnd == NULL) {
7449 status = map_nt_error_from_unix(errno);
7450 goto out;
7453 status = NT_STATUS_NO_SUCH_FILE;
7455 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7456 * - gentest fix. JRA
7459 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7460 &talloced))) {
7461 files_struct *fsp = NULL;
7462 char *destname = NULL;
7463 bool sysdir_entry = False;
7465 /* Quick check for "." and ".." */
7466 if (ISDOT(dname) || ISDOTDOT(dname)) {
7467 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7468 sysdir_entry = True;
7469 } else {
7470 TALLOC_FREE(talloced);
7471 continue;
7475 if (!is_visible_file(conn, fname_src_dir, dname,
7476 &smb_fname_src->st, false)) {
7477 TALLOC_FREE(talloced);
7478 continue;
7481 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7482 TALLOC_FREE(talloced);
7483 continue;
7486 if (sysdir_entry) {
7487 status = NT_STATUS_OBJECT_NAME_INVALID;
7488 break;
7491 TALLOC_FREE(smb_fname_src->base_name);
7492 if (ISDOT(fname_src_dir)) {
7493 /* Ensure we use canonical names on open. */
7494 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7495 "%s",
7496 dname);
7497 } else {
7498 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7499 "%s/%s",
7500 fname_src_dir,
7501 dname);
7503 if (!smb_fname_src->base_name) {
7504 status = NT_STATUS_NO_MEMORY;
7505 goto out;
7508 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7509 smb_fname_dst->base_name,
7510 &destname)) {
7511 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7512 smb_fname_src->base_name, destname));
7513 TALLOC_FREE(talloced);
7514 continue;
7516 if (!destname) {
7517 status = NT_STATUS_NO_MEMORY;
7518 goto out;
7521 TALLOC_FREE(smb_fname_dst->base_name);
7522 smb_fname_dst->base_name = destname;
7524 ZERO_STRUCT(smb_fname_src->st);
7525 if (posix_pathnames) {
7526 SMB_VFS_LSTAT(conn, smb_fname_src);
7527 } else {
7528 SMB_VFS_STAT(conn, smb_fname_src);
7531 create_options = 0;
7533 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7534 create_options |= FILE_DIRECTORY_FILE;
7537 status = SMB_VFS_CREATE_FILE(
7538 conn, /* conn */
7539 req, /* req */
7540 0, /* root_dir_fid */
7541 smb_fname_src, /* fname */
7542 access_mask, /* access_mask */
7543 (FILE_SHARE_READ | /* share_access */
7544 FILE_SHARE_WRITE),
7545 FILE_OPEN, /* create_disposition*/
7546 create_options, /* create_options */
7547 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7548 0, /* oplock_request */
7549 NULL, /* lease */
7550 0, /* allocation_size */
7551 0, /* private_flags */
7552 NULL, /* sd */
7553 NULL, /* ea_list */
7554 &fsp, /* result */
7555 NULL, /* pinfo */
7556 NULL, NULL); /* create context */
7558 if (!NT_STATUS_IS_OK(status)) {
7559 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7560 "returned %s rename %s -> %s\n",
7561 nt_errstr(status),
7562 smb_fname_str_dbg(smb_fname_src),
7563 smb_fname_str_dbg(smb_fname_dst)));
7564 break;
7567 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7568 dname);
7569 if (!smb_fname_dst->original_lcomp) {
7570 status = NT_STATUS_NO_MEMORY;
7571 goto out;
7574 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7575 attrs, replace_if_exists);
7577 close_file(req, fsp, NORMAL_CLOSE);
7579 if (!NT_STATUS_IS_OK(status)) {
7580 DEBUG(3, ("rename_internals_fsp returned %s for "
7581 "rename %s -> %s\n", nt_errstr(status),
7582 smb_fname_str_dbg(smb_fname_src),
7583 smb_fname_str_dbg(smb_fname_dst)));
7584 break;
7587 count++;
7589 DEBUG(3,("rename_internals: doing rename on %s -> "
7590 "%s\n", smb_fname_str_dbg(smb_fname_src),
7591 smb_fname_str_dbg(smb_fname_src)));
7592 TALLOC_FREE(talloced);
7594 TALLOC_FREE(dir_hnd);
7596 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7597 status = map_nt_error_from_unix(errno);
7600 out:
7601 TALLOC_FREE(talloced);
7602 TALLOC_FREE(smb_fname_src_dir);
7603 TALLOC_FREE(fname_src_dir);
7604 TALLOC_FREE(fname_src_mask);
7605 return status;
7608 /****************************************************************************
7609 Reply to a mv.
7610 ****************************************************************************/
7612 void reply_mv(struct smb_request *req)
7614 connection_struct *conn = req->conn;
7615 char *name = NULL;
7616 char *newname = NULL;
7617 const char *p;
7618 uint32_t attrs;
7619 NTSTATUS status;
7620 bool src_has_wcard = False;
7621 bool dest_has_wcard = False;
7622 TALLOC_CTX *ctx = talloc_tos();
7623 struct smb_filename *smb_fname_src = NULL;
7624 struct smb_filename *smb_fname_dst = NULL;
7625 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
7626 (req->posix_pathnames ?
7627 UCF_UNIX_NAME_LOOKUP :
7628 UCF_COND_ALLOW_WCARD_LCOMP);
7629 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
7630 UCF_SAVE_LCOMP |
7631 (req->posix_pathnames ?
7633 UCF_COND_ALLOW_WCARD_LCOMP);
7634 bool stream_rename = false;
7636 START_PROFILE(SMBmv);
7638 if (req->wct < 1) {
7639 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7640 goto out;
7643 attrs = SVAL(req->vwv+0, 0);
7645 p = (const char *)req->buf + 1;
7646 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7647 &status, &src_has_wcard);
7648 if (!NT_STATUS_IS_OK(status)) {
7649 reply_nterror(req, status);
7650 goto out;
7652 p++;
7653 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7654 &status, &dest_has_wcard);
7655 if (!NT_STATUS_IS_OK(status)) {
7656 reply_nterror(req, status);
7657 goto out;
7660 if (!req->posix_pathnames) {
7661 /* The newname must begin with a ':' if the
7662 name contains a ':'. */
7663 if (strchr_m(name, ':')) {
7664 if (newname[0] != ':') {
7665 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7666 goto out;
7668 stream_rename = true;
7672 status = filename_convert(ctx,
7673 conn,
7674 name,
7675 src_ucf_flags,
7676 NULL,
7677 &src_has_wcard,
7678 &smb_fname_src);
7680 if (!NT_STATUS_IS_OK(status)) {
7681 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7682 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7683 ERRSRV, ERRbadpath);
7684 goto out;
7686 reply_nterror(req, status);
7687 goto out;
7690 status = filename_convert(ctx,
7691 conn,
7692 newname,
7693 dst_ucf_flags,
7694 NULL,
7695 &dest_has_wcard,
7696 &smb_fname_dst);
7698 if (!NT_STATUS_IS_OK(status)) {
7699 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7700 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7701 ERRSRV, ERRbadpath);
7702 goto out;
7704 reply_nterror(req, status);
7705 goto out;
7708 if (stream_rename) {
7709 /* smb_fname_dst->base_name must be the same as
7710 smb_fname_src->base_name. */
7711 TALLOC_FREE(smb_fname_dst->base_name);
7712 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7713 smb_fname_src->base_name);
7714 if (!smb_fname_dst->base_name) {
7715 reply_nterror(req, NT_STATUS_NO_MEMORY);
7716 goto out;
7720 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7721 smb_fname_str_dbg(smb_fname_dst)));
7723 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7724 attrs, False, src_has_wcard, dest_has_wcard,
7725 DELETE_ACCESS);
7726 if (!NT_STATUS_IS_OK(status)) {
7727 if (open_was_deferred(req->xconn, req->mid)) {
7728 /* We have re-scheduled this call. */
7729 goto out;
7731 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
7732 bool ok = defer_smb1_sharing_violation(req);
7733 if (ok) {
7734 goto out;
7737 reply_nterror(req, status);
7738 goto out;
7741 reply_outbuf(req, 0, 0);
7742 out:
7743 TALLOC_FREE(smb_fname_src);
7744 TALLOC_FREE(smb_fname_dst);
7745 END_PROFILE(SMBmv);
7746 return;
7749 /*******************************************************************
7750 Copy a file as part of a reply_copy.
7751 ******************************************************************/
7754 * TODO: check error codes on all callers
7757 NTSTATUS copy_file(TALLOC_CTX *ctx,
7758 connection_struct *conn,
7759 struct smb_filename *smb_fname_src,
7760 struct smb_filename *smb_fname_dst,
7761 int ofun,
7762 int count,
7763 bool target_is_directory)
7765 struct smb_filename *smb_fname_dst_tmp = NULL;
7766 off_t ret=-1;
7767 files_struct *fsp1,*fsp2;
7768 uint32_t dosattrs;
7769 uint32_t new_create_disposition;
7770 NTSTATUS status;
7773 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7774 if (smb_fname_dst_tmp == NULL) {
7775 return NT_STATUS_NO_MEMORY;
7779 * If the target is a directory, extract the last component from the
7780 * src filename and append it to the dst filename
7782 if (target_is_directory) {
7783 const char *p;
7785 /* dest/target can't be a stream if it's a directory. */
7786 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7788 p = strrchr_m(smb_fname_src->base_name,'/');
7789 if (p) {
7790 p++;
7791 } else {
7792 p = smb_fname_src->base_name;
7794 smb_fname_dst_tmp->base_name =
7795 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7797 if (!smb_fname_dst_tmp->base_name) {
7798 status = NT_STATUS_NO_MEMORY;
7799 goto out;
7803 status = vfs_file_exist(conn, smb_fname_src);
7804 if (!NT_STATUS_IS_OK(status)) {
7805 goto out;
7808 if (!target_is_directory && count) {
7809 new_create_disposition = FILE_OPEN;
7810 } else {
7811 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7812 0, ofun,
7813 NULL, NULL,
7814 &new_create_disposition,
7815 NULL,
7816 NULL)) {
7817 status = NT_STATUS_INVALID_PARAMETER;
7818 goto out;
7822 /* Open the src file for reading. */
7823 status = SMB_VFS_CREATE_FILE(
7824 conn, /* conn */
7825 NULL, /* req */
7826 0, /* root_dir_fid */
7827 smb_fname_src, /* fname */
7828 FILE_GENERIC_READ, /* access_mask */
7829 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7830 FILE_OPEN, /* create_disposition*/
7831 0, /* create_options */
7832 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7833 INTERNAL_OPEN_ONLY, /* oplock_request */
7834 NULL, /* lease */
7835 0, /* allocation_size */
7836 0, /* private_flags */
7837 NULL, /* sd */
7838 NULL, /* ea_list */
7839 &fsp1, /* result */
7840 NULL, /* psbuf */
7841 NULL, NULL); /* create context */
7843 if (!NT_STATUS_IS_OK(status)) {
7844 goto out;
7847 dosattrs = dos_mode(conn, smb_fname_src);
7849 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7850 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7853 /* Open the dst file for writing. */
7854 status = SMB_VFS_CREATE_FILE(
7855 conn, /* conn */
7856 NULL, /* req */
7857 0, /* root_dir_fid */
7858 smb_fname_dst, /* fname */
7859 FILE_GENERIC_WRITE, /* access_mask */
7860 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7861 new_create_disposition, /* create_disposition*/
7862 0, /* create_options */
7863 dosattrs, /* file_attributes */
7864 INTERNAL_OPEN_ONLY, /* oplock_request */
7865 NULL, /* lease */
7866 0, /* allocation_size */
7867 0, /* private_flags */
7868 NULL, /* sd */
7869 NULL, /* ea_list */
7870 &fsp2, /* result */
7871 NULL, /* psbuf */
7872 NULL, NULL); /* create context */
7874 if (!NT_STATUS_IS_OK(status)) {
7875 close_file(NULL, fsp1, ERROR_CLOSE);
7876 goto out;
7879 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7880 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7881 if (ret == -1) {
7882 DEBUG(0, ("error - vfs lseek returned error %s\n",
7883 strerror(errno)));
7884 status = map_nt_error_from_unix(errno);
7885 close_file(NULL, fsp1, ERROR_CLOSE);
7886 close_file(NULL, fsp2, ERROR_CLOSE);
7887 goto out;
7891 /* Do the actual copy. */
7892 if (smb_fname_src->st.st_ex_size) {
7893 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7894 } else {
7895 ret = 0;
7898 close_file(NULL, fsp1, NORMAL_CLOSE);
7900 /* Ensure the modtime is set correctly on the destination file. */
7901 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7904 * As we are opening fsp1 read-only we only expect
7905 * an error on close on fsp2 if we are out of space.
7906 * Thus we don't look at the error return from the
7907 * close of fsp1.
7909 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7911 if (!NT_STATUS_IS_OK(status)) {
7912 goto out;
7915 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7916 status = NT_STATUS_DISK_FULL;
7917 goto out;
7920 status = NT_STATUS_OK;
7922 out:
7923 TALLOC_FREE(smb_fname_dst_tmp);
7924 return status;
7927 /****************************************************************************
7928 Reply to a file copy.
7929 ****************************************************************************/
7931 void reply_copy(struct smb_request *req)
7933 connection_struct *conn = req->conn;
7934 struct smb_filename *smb_fname_src = NULL;
7935 struct smb_filename *smb_fname_src_dir = NULL;
7936 struct smb_filename *smb_fname_dst = NULL;
7937 char *fname_src = NULL;
7938 char *fname_dst = NULL;
7939 char *fname_src_mask = NULL;
7940 char *fname_src_dir = NULL;
7941 const char *p;
7942 int count=0;
7943 int error = ERRnoaccess;
7944 int tid2;
7945 int ofun;
7946 int flags;
7947 bool target_is_directory=False;
7948 bool source_has_wild = False;
7949 bool dest_has_wild = False;
7950 NTSTATUS status;
7951 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7952 ucf_flags_from_smb_request(req);
7953 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7954 ucf_flags_from_smb_request(req);
7955 TALLOC_CTX *ctx = talloc_tos();
7957 START_PROFILE(SMBcopy);
7959 if (req->wct < 3) {
7960 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7961 goto out;
7964 tid2 = SVAL(req->vwv+0, 0);
7965 ofun = SVAL(req->vwv+1, 0);
7966 flags = SVAL(req->vwv+2, 0);
7968 p = (const char *)req->buf;
7969 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7970 &status, &source_has_wild);
7971 if (!NT_STATUS_IS_OK(status)) {
7972 reply_nterror(req, status);
7973 goto out;
7975 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7976 &status, &dest_has_wild);
7977 if (!NT_STATUS_IS_OK(status)) {
7978 reply_nterror(req, status);
7979 goto out;
7982 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7984 if (tid2 != conn->cnum) {
7985 /* can't currently handle inter share copies XXXX */
7986 DEBUG(3,("Rejecting inter-share copy\n"));
7987 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7988 goto out;
7991 status = filename_convert(ctx, conn,
7992 fname_src,
7993 ucf_flags_src,
7994 NULL,
7995 &source_has_wild,
7996 &smb_fname_src);
7997 if (!NT_STATUS_IS_OK(status)) {
7998 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7999 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8000 ERRSRV, ERRbadpath);
8001 goto out;
8003 reply_nterror(req, status);
8004 goto out;
8007 status = filename_convert(ctx, conn,
8008 fname_dst,
8009 ucf_flags_dst,
8010 NULL,
8011 &dest_has_wild,
8012 &smb_fname_dst);
8013 if (!NT_STATUS_IS_OK(status)) {
8014 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8015 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8016 ERRSRV, ERRbadpath);
8017 goto out;
8019 reply_nterror(req, status);
8020 goto out;
8023 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
8025 if ((flags&1) && target_is_directory) {
8026 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
8027 goto out;
8030 if ((flags&2) && !target_is_directory) {
8031 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
8032 goto out;
8035 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
8036 /* wants a tree copy! XXXX */
8037 DEBUG(3,("Rejecting tree copy\n"));
8038 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8039 goto out;
8042 /* Split up the directory from the filename/mask. */
8043 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
8044 &fname_src_dir, &fname_src_mask);
8045 if (!NT_STATUS_IS_OK(status)) {
8046 reply_nterror(req, NT_STATUS_NO_MEMORY);
8047 goto out;
8051 * We should only check the mangled cache
8052 * here if unix_convert failed. This means
8053 * that the path in 'mask' doesn't exist
8054 * on the file system and so we need to look
8055 * for a possible mangle. This patch from
8056 * Tine Smukavec <valentin.smukavec@hermes.si>.
8058 if (!VALID_STAT(smb_fname_src->st) &&
8059 mangle_is_mangled(fname_src_mask, conn->params)) {
8060 char *new_mask = NULL;
8061 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
8062 &new_mask, conn->params);
8064 /* Use demangled name if one was successfully found. */
8065 if (new_mask) {
8066 TALLOC_FREE(fname_src_mask);
8067 fname_src_mask = new_mask;
8071 if (!source_has_wild) {
8074 * Only one file needs to be copied. Append the mask back onto
8075 * the directory.
8077 TALLOC_FREE(smb_fname_src->base_name);
8078 if (ISDOT(fname_src_dir)) {
8079 /* Ensure we use canonical names on open. */
8080 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8081 "%s",
8082 fname_src_mask);
8083 } else {
8084 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
8085 "%s/%s",
8086 fname_src_dir,
8087 fname_src_mask);
8089 if (!smb_fname_src->base_name) {
8090 reply_nterror(req, NT_STATUS_NO_MEMORY);
8091 goto out;
8094 if (dest_has_wild) {
8095 char *fname_dst_mod = NULL;
8096 if (!resolve_wildcards(smb_fname_dst,
8097 smb_fname_src->base_name,
8098 smb_fname_dst->base_name,
8099 &fname_dst_mod)) {
8100 reply_nterror(req, NT_STATUS_NO_MEMORY);
8101 goto out;
8103 TALLOC_FREE(smb_fname_dst->base_name);
8104 smb_fname_dst->base_name = fname_dst_mod;
8107 status = check_name(conn, smb_fname_src);
8108 if (!NT_STATUS_IS_OK(status)) {
8109 reply_nterror(req, status);
8110 goto out;
8113 status = check_name(conn, smb_fname_dst);
8114 if (!NT_STATUS_IS_OK(status)) {
8115 reply_nterror(req, status);
8116 goto out;
8119 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
8120 ofun, count, target_is_directory);
8122 if(!NT_STATUS_IS_OK(status)) {
8123 reply_nterror(req, status);
8124 goto out;
8125 } else {
8126 count++;
8128 } else {
8129 struct smb_Dir *dir_hnd = NULL;
8130 const char *dname = NULL;
8131 char *talloced = NULL;
8132 long offset = 0;
8135 * There is a wildcard that requires us to actually read the
8136 * src dir and copy each file matching the mask to the dst.
8137 * Right now streams won't be copied, but this could
8138 * presumably be added with a nested loop for reach dir entry.
8140 SMB_ASSERT(!smb_fname_src->stream_name);
8141 SMB_ASSERT(!smb_fname_dst->stream_name);
8143 smb_fname_src->stream_name = NULL;
8144 smb_fname_dst->stream_name = NULL;
8146 if (strequal(fname_src_mask,"????????.???")) {
8147 TALLOC_FREE(fname_src_mask);
8148 fname_src_mask = talloc_strdup(ctx, "*");
8149 if (!fname_src_mask) {
8150 reply_nterror(req, NT_STATUS_NO_MEMORY);
8151 goto out;
8155 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
8156 fname_src_dir,
8157 NULL,
8158 NULL,
8159 smb_fname_src->flags);
8160 if (smb_fname_src_dir == NULL) {
8161 reply_nterror(req, NT_STATUS_NO_MEMORY);
8162 goto out;
8165 status = check_name(conn, smb_fname_src_dir);
8166 if (!NT_STATUS_IS_OK(status)) {
8167 reply_nterror(req, status);
8168 goto out;
8171 dir_hnd = OpenDir(ctx,
8172 conn,
8173 smb_fname_src_dir,
8174 fname_src_mask,
8176 if (dir_hnd == NULL) {
8177 status = map_nt_error_from_unix(errno);
8178 reply_nterror(req, status);
8179 goto out;
8182 error = ERRbadfile;
8184 /* Iterate over the src dir copying each entry to the dst. */
8185 while ((dname = ReadDirName(dir_hnd, &offset,
8186 &smb_fname_src->st, &talloced))) {
8187 char *destname = NULL;
8189 if (ISDOT(dname) || ISDOTDOT(dname)) {
8190 TALLOC_FREE(talloced);
8191 continue;
8194 if (!is_visible_file(conn, fname_src_dir, dname,
8195 &smb_fname_src->st, false)) {
8196 TALLOC_FREE(talloced);
8197 continue;
8200 if(!mask_match(dname, fname_src_mask,
8201 conn->case_sensitive)) {
8202 TALLOC_FREE(talloced);
8203 continue;
8206 error = ERRnoaccess;
8208 /* Get the src smb_fname struct setup. */
8209 TALLOC_FREE(smb_fname_src->base_name);
8210 if (ISDOT(fname_src_dir)) {
8211 /* Ensure we use canonical names on open. */
8212 smb_fname_src->base_name =
8213 talloc_asprintf(smb_fname_src, "%s",
8214 dname);
8215 } else {
8216 smb_fname_src->base_name =
8217 talloc_asprintf(smb_fname_src, "%s/%s",
8218 fname_src_dir, dname);
8221 if (!smb_fname_src->base_name) {
8222 TALLOC_FREE(dir_hnd);
8223 TALLOC_FREE(talloced);
8224 reply_nterror(req, NT_STATUS_NO_MEMORY);
8225 goto out;
8228 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
8229 smb_fname_dst->base_name,
8230 &destname)) {
8231 TALLOC_FREE(talloced);
8232 continue;
8234 if (!destname) {
8235 TALLOC_FREE(dir_hnd);
8236 TALLOC_FREE(talloced);
8237 reply_nterror(req, NT_STATUS_NO_MEMORY);
8238 goto out;
8241 TALLOC_FREE(smb_fname_dst->base_name);
8242 smb_fname_dst->base_name = destname;
8244 status = check_name(conn, smb_fname_src);
8245 if (!NT_STATUS_IS_OK(status)) {
8246 TALLOC_FREE(dir_hnd);
8247 TALLOC_FREE(talloced);
8248 reply_nterror(req, status);
8249 goto out;
8252 status = check_name(conn, smb_fname_dst);
8253 if (!NT_STATUS_IS_OK(status)) {
8254 TALLOC_FREE(dir_hnd);
8255 TALLOC_FREE(talloced);
8256 reply_nterror(req, status);
8257 goto out;
8260 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
8261 smb_fname_src->base_name,
8262 smb_fname_dst->base_name));
8264 status = copy_file(ctx, conn, smb_fname_src,
8265 smb_fname_dst, ofun, count,
8266 target_is_directory);
8267 if (NT_STATUS_IS_OK(status)) {
8268 count++;
8271 TALLOC_FREE(talloced);
8273 TALLOC_FREE(dir_hnd);
8276 if (count == 0) {
8277 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
8278 goto out;
8281 reply_outbuf(req, 1, 0);
8282 SSVAL(req->outbuf,smb_vwv0,count);
8283 out:
8284 TALLOC_FREE(smb_fname_src);
8285 TALLOC_FREE(smb_fname_src_dir);
8286 TALLOC_FREE(smb_fname_dst);
8287 TALLOC_FREE(fname_src);
8288 TALLOC_FREE(fname_dst);
8289 TALLOC_FREE(fname_src_mask);
8290 TALLOC_FREE(fname_src_dir);
8292 END_PROFILE(SMBcopy);
8293 return;
8296 #undef DBGC_CLASS
8297 #define DBGC_CLASS DBGC_LOCKING
8299 /****************************************************************************
8300 Get a lock pid, dealing with large count requests.
8301 ****************************************************************************/
8303 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
8304 bool large_file_format)
8306 if(!large_file_format)
8307 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
8308 else
8309 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
8312 /****************************************************************************
8313 Get a lock count, dealing with large count requests.
8314 ****************************************************************************/
8316 uint64_t get_lock_count(const uint8_t *data, int data_offset,
8317 bool large_file_format)
8319 uint64_t count = 0;
8321 if(!large_file_format) {
8322 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
8323 } else {
8325 * No BVAL, this is reversed!
8327 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
8328 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
8331 return count;
8334 /****************************************************************************
8335 Get a lock offset, dealing with large offset requests.
8336 ****************************************************************************/
8338 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
8339 bool large_file_format)
8341 uint64_t offset = 0;
8343 if(!large_file_format) {
8344 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
8345 } else {
8347 * No BVAL, this is reversed!
8349 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
8350 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
8353 return offset;
8356 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8357 files_struct *fsp,
8358 uint16_t num_ulocks,
8359 struct smbd_lock_element *ulocks,
8360 enum brl_flavour lock_flav)
8362 struct share_mode_lock *lck;
8363 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8364 uint16_t i;
8366 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
8368 for(i = 0; i < num_ulocks; i++) {
8369 struct smbd_lock_element *e = &ulocks[i];
8371 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
8372 "pid %"PRIu64", file %s\n",
8373 e->offset,
8374 e->count,
8375 e->smblctx,
8376 fsp_str_dbg(fsp));
8378 if (e->brltype != UNLOCK_LOCK) {
8379 /* this can only happen with SMB2 */
8380 status = NT_STATUS_INVALID_PARAMETER;
8381 goto done;
8384 status = do_unlock(
8385 fsp,
8386 e->smblctx,
8387 e->count,
8388 e->offset,
8389 lock_flav);
8391 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8392 nt_errstr(status)));
8394 if (!NT_STATUS_IS_OK(status)) {
8395 goto done;
8399 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8400 num_ulocks));
8402 done:
8403 if (NT_STATUS_IS_OK(status) && (lck != NULL)) {
8404 lck->data->modified = true;
8407 TALLOC_FREE(lck);
8408 return status;
8411 /****************************************************************************
8412 Reply to a lockingX request.
8413 ****************************************************************************/
8415 static void reply_lockingx_done(struct tevent_req *subreq);
8417 void reply_lockingX(struct smb_request *req)
8419 connection_struct *conn = req->conn;
8420 files_struct *fsp;
8421 unsigned char locktype;
8422 enum brl_type brltype;
8423 unsigned char oplocklevel;
8424 uint16_t num_ulocks;
8425 uint16_t num_locks;
8426 int32_t lock_timeout;
8427 uint16_t i;
8428 const uint8_t *data;
8429 bool large_file_format;
8430 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8431 struct smbd_lock_element *locks = NULL;
8432 struct tevent_req *subreq = NULL;
8434 START_PROFILE(SMBlockingX);
8436 if (req->wct < 8) {
8437 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8438 END_PROFILE(SMBlockingX);
8439 return;
8442 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8443 locktype = CVAL(req->vwv+3, 0);
8444 oplocklevel = CVAL(req->vwv+3, 1);
8445 num_ulocks = SVAL(req->vwv+6, 0);
8446 num_locks = SVAL(req->vwv+7, 0);
8447 lock_timeout = IVAL(req->vwv+4, 0);
8448 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8450 if (!check_fsp(conn, req, fsp)) {
8451 END_PROFILE(SMBlockingX);
8452 return;
8455 data = req->buf;
8457 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8458 /* we don't support these - and CANCEL_LOCK makes w2k
8459 and XP reboot so I don't really want to be
8460 compatible! (tridge) */
8461 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8462 END_PROFILE(SMBlockingX);
8463 return;
8466 /* Check if this is an oplock break on a file
8467 we have granted an oplock on.
8469 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8470 /* Client can insist on breaking to none. */
8471 bool break_to_none = (oplocklevel == 0);
8472 bool result;
8474 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8475 "for %s\n", (unsigned int)oplocklevel,
8476 fsp_fnum_dbg(fsp)));
8479 * Make sure we have granted an exclusive or batch oplock on
8480 * this file.
8483 if (fsp->oplock_type == 0) {
8485 /* The Samba4 nbench simulator doesn't understand
8486 the difference between break to level2 and break
8487 to none from level2 - it sends oplock break
8488 replies in both cases. Don't keep logging an error
8489 message here - just ignore it. JRA. */
8491 DEBUG(5,("reply_lockingX: Error : oplock break from "
8492 "client for %s (oplock=%d) and no "
8493 "oplock granted on this file (%s).\n",
8494 fsp_fnum_dbg(fsp), fsp->oplock_type,
8495 fsp_str_dbg(fsp)));
8497 /* if this is a pure oplock break request then don't
8498 * send a reply */
8499 if (num_locks == 0 && num_ulocks == 0) {
8500 END_PROFILE(SMBlockingX);
8501 return;
8504 END_PROFILE(SMBlockingX);
8505 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8506 return;
8509 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8510 (break_to_none)) {
8511 result = remove_oplock(fsp);
8512 } else {
8513 result = downgrade_oplock(fsp);
8516 if (!result) {
8517 DEBUG(0, ("reply_lockingX: error in removing "
8518 "oplock on file %s\n", fsp_str_dbg(fsp)));
8519 /* Hmmm. Is this panic justified? */
8520 smb_panic("internal tdb error");
8523 /* if this is a pure oplock break request then don't send a
8524 * reply */
8525 if (num_locks == 0 && num_ulocks == 0) {
8526 /* Sanity check - ensure a pure oplock break is not a
8527 chained request. */
8528 if (CVAL(req->vwv+0, 0) != 0xff) {
8529 DEBUG(0,("reply_lockingX: Error : pure oplock "
8530 "break is a chained %d request !\n",
8531 (unsigned int)CVAL(req->vwv+0, 0)));
8533 END_PROFILE(SMBlockingX);
8534 return;
8538 if (req->buflen <
8539 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8540 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8541 END_PROFILE(SMBlockingX);
8542 return;
8545 if (num_ulocks != 0) {
8546 struct smbd_lock_element *ulocks = NULL;
8547 bool ok;
8549 ulocks = talloc_array(
8550 req, struct smbd_lock_element, num_ulocks);
8551 if (ulocks == NULL) {
8552 reply_nterror(req, NT_STATUS_NO_MEMORY);
8553 END_PROFILE(SMBlockingX);
8554 return;
8558 * Data now points at the beginning of the list of
8559 * smb_unlkrng structs
8561 for (i = 0; i < num_ulocks; i++) {
8562 ulocks[i].req_guid = smbd_request_guid(req,
8563 UINT16_MAX - i),
8564 ulocks[i].smblctx = get_lock_pid(
8565 data, i, large_file_format);
8566 ulocks[i].count = get_lock_count(
8567 data, i, large_file_format);
8568 ulocks[i].offset = get_lock_offset(
8569 data, i, large_file_format);
8570 ulocks[i].brltype = UNLOCK_LOCK;
8574 * Unlock cancels pending locks
8577 ok = smbd_smb1_brl_finish_by_lock(
8578 fsp,
8579 large_file_format,
8580 WINDOWS_LOCK,
8581 ulocks[0],
8582 NT_STATUS_OK);
8583 if (ok) {
8584 reply_outbuf(req, 2, 0);
8585 SSVAL(req->outbuf, smb_vwv0, 0xff);
8586 SSVAL(req->outbuf, smb_vwv1, 0);
8587 END_PROFILE(SMBlockingX);
8588 return;
8591 status = smbd_do_unlocking(
8592 req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
8593 TALLOC_FREE(ulocks);
8594 if (!NT_STATUS_IS_OK(status)) {
8595 END_PROFILE(SMBlockingX);
8596 reply_nterror(req, status);
8597 return;
8601 /* Now do any requested locks */
8602 data += ((large_file_format ? 20 : 10)*num_ulocks);
8604 /* Data now points at the beginning of the list
8605 of smb_lkrng structs */
8607 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8608 brltype = READ_LOCK;
8609 } else {
8610 brltype = WRITE_LOCK;
8613 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8614 if (locks == NULL) {
8615 reply_nterror(req, NT_STATUS_NO_MEMORY);
8616 END_PROFILE(SMBlockingX);
8617 return;
8620 for (i = 0; i < num_locks; i++) {
8621 locks[i].req_guid = smbd_request_guid(req, i),
8622 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8623 locks[i].count = get_lock_count(data, i, large_file_format);
8624 locks[i].offset = get_lock_offset(data, i, large_file_format);
8625 locks[i].brltype = brltype;
8628 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8630 bool ok;
8632 if (num_locks == 0) {
8633 /* See smbtorture3 lock11 test */
8634 reply_outbuf(req, 2, 0);
8635 /* andx chain ends */
8636 SSVAL(req->outbuf, smb_vwv0, 0xff);
8637 SSVAL(req->outbuf, smb_vwv1, 0);
8638 END_PROFILE(SMBlockingX);
8639 return;
8642 ok = smbd_smb1_brl_finish_by_lock(
8643 fsp,
8644 large_file_format,
8645 WINDOWS_LOCK,
8646 locks[0], /* Windows only cancels the first lock */
8647 NT_STATUS_FILE_LOCK_CONFLICT);
8649 if (!ok) {
8650 reply_force_doserror(req, ERRDOS, ERRcancelviolation);
8651 END_PROFILE(SMBlockingX);
8652 return;
8655 reply_outbuf(req, 2, 0);
8656 SSVAL(req->outbuf, smb_vwv0, 0xff);
8657 SSVAL(req->outbuf, smb_vwv1, 0);
8658 END_PROFILE(SMBlockingX);
8659 return;
8662 subreq = smbd_smb1_do_locks_send(
8663 fsp,
8664 req->sconn->ev_ctx,
8665 &req,
8666 fsp,
8667 lock_timeout,
8668 large_file_format,
8669 WINDOWS_LOCK,
8670 num_locks,
8671 locks);
8672 if (subreq == NULL) {
8673 reply_nterror(req, NT_STATUS_NO_MEMORY);
8674 END_PROFILE(SMBlockingX);
8675 return;
8677 tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
8678 END_PROFILE(SMBlockingX);
8681 static void reply_lockingx_done(struct tevent_req *subreq)
8683 struct smb_request *req = NULL;
8684 NTSTATUS status;
8685 bool ok;
8687 START_PROFILE(SMBlockingX);
8689 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
8690 SMB_ASSERT(ok);
8692 status = smbd_smb1_do_locks_recv(subreq);
8693 TALLOC_FREE(subreq);
8695 DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
8697 if (NT_STATUS_IS_OK(status)) {
8698 reply_outbuf(req, 2, 0);
8699 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8700 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8701 } else {
8702 reply_nterror(req, status);
8705 ok = srv_send_smb(req->xconn,
8706 (char *)req->outbuf,
8707 true,
8708 req->seqnum+1,
8709 IS_CONN_ENCRYPTED(req->conn),
8710 NULL);
8711 if (!ok) {
8712 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
8714 TALLOC_FREE(req);
8715 END_PROFILE(SMBlockingX);
8718 #undef DBGC_CLASS
8719 #define DBGC_CLASS DBGC_ALL
8721 /****************************************************************************
8722 Reply to a SMBreadbmpx (read block multiplex) request.
8723 Always reply with an error, if someone has a platform really needs this,
8724 please contact vl@samba.org
8725 ****************************************************************************/
8727 void reply_readbmpx(struct smb_request *req)
8729 START_PROFILE(SMBreadBmpx);
8730 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8731 END_PROFILE(SMBreadBmpx);
8732 return;
8735 /****************************************************************************
8736 Reply to a SMBreadbs (read block multiplex secondary) request.
8737 Always reply with an error, if someone has a platform really needs this,
8738 please contact vl@samba.org
8739 ****************************************************************************/
8741 void reply_readbs(struct smb_request *req)
8743 START_PROFILE(SMBreadBs);
8744 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8745 END_PROFILE(SMBreadBs);
8746 return;
8749 /****************************************************************************
8750 Reply to a SMBsetattrE.
8751 ****************************************************************************/
8753 void reply_setattrE(struct smb_request *req)
8755 connection_struct *conn = req->conn;
8756 struct smb_file_time ft;
8757 files_struct *fsp;
8758 NTSTATUS status;
8760 START_PROFILE(SMBsetattrE);
8761 ZERO_STRUCT(ft);
8763 if (req->wct < 7) {
8764 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8765 goto out;
8768 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8770 if(!fsp || (fsp->conn != conn)) {
8771 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8772 goto out;
8776 * Convert the DOS times into unix times.
8779 ft.atime = convert_time_t_to_timespec(
8780 srv_make_unix_date2(req->vwv+3));
8781 ft.mtime = convert_time_t_to_timespec(
8782 srv_make_unix_date2(req->vwv+5));
8783 ft.create_time = convert_time_t_to_timespec(
8784 srv_make_unix_date2(req->vwv+1));
8786 reply_outbuf(req, 0, 0);
8789 * Patch from Ray Frush <frush@engr.colostate.edu>
8790 * Sometimes times are sent as zero - ignore them.
8793 /* Ensure we have a valid stat struct for the source. */
8794 status = vfs_stat_fsp(fsp);
8795 if (!NT_STATUS_IS_OK(status)) {
8796 reply_nterror(req, status);
8797 goto out;
8800 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8801 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8802 goto out;
8805 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8806 if (!NT_STATUS_IS_OK(status)) {
8807 reply_nterror(req, status);
8808 goto out;
8811 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8812 " createtime=%u\n",
8813 fsp_fnum_dbg(fsp),
8814 (unsigned int)ft.atime.tv_sec,
8815 (unsigned int)ft.mtime.tv_sec,
8816 (unsigned int)ft.create_time.tv_sec
8818 out:
8819 END_PROFILE(SMBsetattrE);
8820 return;
8824 /* Back from the dead for OS/2..... JRA. */
8826 /****************************************************************************
8827 Reply to a SMBwritebmpx (write block multiplex primary) request.
8828 Always reply with an error, if someone has a platform really needs this,
8829 please contact vl@samba.org
8830 ****************************************************************************/
8832 void reply_writebmpx(struct smb_request *req)
8834 START_PROFILE(SMBwriteBmpx);
8835 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8836 END_PROFILE(SMBwriteBmpx);
8837 return;
8840 /****************************************************************************
8841 Reply to a SMBwritebs (write block multiplex secondary) request.
8842 Always reply with an error, if someone has a platform really needs this,
8843 please contact vl@samba.org
8844 ****************************************************************************/
8846 void reply_writebs(struct smb_request *req)
8848 START_PROFILE(SMBwriteBs);
8849 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8850 END_PROFILE(SMBwriteBs);
8851 return;
8854 /****************************************************************************
8855 Reply to a SMBgetattrE.
8856 ****************************************************************************/
8858 void reply_getattrE(struct smb_request *req)
8860 connection_struct *conn = req->conn;
8861 int mode;
8862 files_struct *fsp;
8863 struct timespec create_ts;
8864 NTSTATUS status;
8866 START_PROFILE(SMBgetattrE);
8868 if (req->wct < 1) {
8869 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8870 END_PROFILE(SMBgetattrE);
8871 return;
8874 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8876 if(!fsp || (fsp->conn != conn)) {
8877 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8878 END_PROFILE(SMBgetattrE);
8879 return;
8882 /* Do an fstat on this file */
8883 status = vfs_stat_fsp(fsp);
8884 if (!NT_STATUS_IS_OK(status)) {
8885 reply_nterror(req, status);
8886 END_PROFILE(SMBgetattrE);
8887 return;
8890 mode = dos_mode(conn, fsp->fsp_name);
8893 * Convert the times into dos times. Set create
8894 * date to be last modify date as UNIX doesn't save
8895 * this.
8898 reply_outbuf(req, 11, 0);
8900 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8901 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8902 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8903 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8904 /* Should we check pending modtime here ? JRA */
8905 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8906 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8908 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8909 SIVAL(req->outbuf, smb_vwv6, 0);
8910 SIVAL(req->outbuf, smb_vwv8, 0);
8911 } else {
8912 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8913 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8914 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8916 SSVAL(req->outbuf,smb_vwv10, mode);
8918 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8920 END_PROFILE(SMBgetattrE);
8921 return;