smbd: Return "blocker_pid" from do_lock()
[Samba.git] / source3 / smbd / reply.c
blobd02f14ead13f959ab0438f9de0e68a656d275422
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"
48 /****************************************************************************
49 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
50 path or anything including wildcards.
51 We're assuming here that '/' is not the second byte in any multibyte char
52 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
53 set.
54 ****************************************************************************/
56 /* Custom version for processing POSIX paths. */
57 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
59 static NTSTATUS check_path_syntax_internal(char *path,
60 bool posix_path,
61 bool *p_last_component_contains_wcard)
63 char *d = path;
64 const char *s = path;
65 NTSTATUS ret = NT_STATUS_OK;
66 bool start_of_name_component = True;
67 bool stream_started = false;
69 *p_last_component_contains_wcard = False;
71 while (*s) {
72 if (stream_started) {
73 switch (*s) {
74 case '/':
75 case '\\':
76 return NT_STATUS_OBJECT_NAME_INVALID;
77 case ':':
78 if (s[1] == '\0') {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 if (strchr_m(&s[1], ':')) {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 break;
88 if ((*s == ':') && !posix_path && !stream_started) {
89 if (*p_last_component_contains_wcard) {
90 return NT_STATUS_OBJECT_NAME_INVALID;
92 /* Stream names allow more characters than file names.
93 We're overloading posix_path here to allow a wider
94 range of characters. If stream_started is true this
95 is still a Windows path even if posix_path is true.
96 JRA.
98 stream_started = true;
99 start_of_name_component = false;
100 posix_path = true;
102 if (s[1] == '\0') {
103 return NT_STATUS_OBJECT_NAME_INVALID;
107 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
109 * Safe to assume is not the second part of a mb char
110 * as this is handled below.
112 /* Eat multiple '/' or '\\' */
113 while (IS_PATH_SEP(*s,posix_path)) {
114 s++;
116 if ((d != path) && (*s != '\0')) {
117 /* We only care about non-leading or trailing '/' or '\\' */
118 *d++ = '/';
121 start_of_name_component = True;
122 /* New component. */
123 *p_last_component_contains_wcard = False;
124 continue;
127 if (start_of_name_component) {
128 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
129 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
132 * No mb char starts with '.' so we're safe checking the directory separator here.
135 /* If we just added a '/' - delete it */
136 if ((d > path) && (*(d-1) == '/')) {
137 *(d-1) = '\0';
138 d--;
141 /* Are we at the start ? Can't go back further if so. */
142 if (d <= path) {
143 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
144 break;
146 /* Go back one level... */
147 /* We know this is safe as '/' cannot be part of a mb sequence. */
148 /* NOTE - if this assumption is invalid we are not in good shape... */
149 /* Decrement d first as d points to the *next* char to write into. */
150 for (d--; d > path; d--) {
151 if (*d == '/')
152 break;
154 s += 2; /* Else go past the .. */
155 /* We're still at the start of a name component, just the previous one. */
156 continue;
158 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
159 if (posix_path) {
160 /* Eat the '.' */
161 s++;
162 continue;
168 if (!(*s & 0x80)) {
169 if (!posix_path) {
170 if (*s <= 0x1f || *s == '|') {
171 return NT_STATUS_OBJECT_NAME_INVALID;
173 switch (*s) {
174 case '*':
175 case '?':
176 case '<':
177 case '>':
178 case '"':
179 *p_last_component_contains_wcard = True;
180 break;
181 default:
182 break;
185 *d++ = *s++;
186 } else {
187 size_t siz;
188 /* Get the size of the next MB character. */
189 next_codepoint(s,&siz);
190 switch(siz) {
191 case 5:
192 *d++ = *s++;
193 FALL_THROUGH;
194 case 4:
195 *d++ = *s++;
196 FALL_THROUGH;
197 case 3:
198 *d++ = *s++;
199 FALL_THROUGH;
200 case 2:
201 *d++ = *s++;
202 FALL_THROUGH;
203 case 1:
204 *d++ = *s++;
205 break;
206 default:
207 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
208 *d = '\0';
209 return NT_STATUS_INVALID_PARAMETER;
212 start_of_name_component = False;
215 *d = '\0';
217 return ret;
220 /****************************************************************************
221 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
222 No wildcards allowed.
223 ****************************************************************************/
225 NTSTATUS check_path_syntax(char *path)
227 bool ignore;
228 return check_path_syntax_internal(path, False, &ignore);
231 /****************************************************************************
232 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
233 Wildcards allowed - p_contains_wcard returns true if the last component contained
234 a wildcard.
235 ****************************************************************************/
237 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
239 return check_path_syntax_internal(path, False, p_contains_wcard);
242 /****************************************************************************
243 Check the path for a POSIX client.
244 We're assuming here that '/' is not the second byte in any multibyte char
245 set (a safe assumption).
246 ****************************************************************************/
248 NTSTATUS check_path_syntax_posix(char *path)
250 bool ignore;
251 return check_path_syntax_internal(path, True, &ignore);
254 /****************************************************************************
255 Pull a string and check the path allowing a wilcard - provide for error return.
256 Passes in posix flag.
257 ****************************************************************************/
259 static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
260 const char *base_ptr,
261 uint16_t smb_flags2,
262 char **pp_dest,
263 const char *src,
264 size_t src_len,
265 int flags,
266 bool posix_pathnames,
267 NTSTATUS *err,
268 bool *contains_wcard)
270 size_t ret;
272 *pp_dest = NULL;
274 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
275 src_len, flags);
277 if (!*pp_dest) {
278 *err = NT_STATUS_INVALID_PARAMETER;
279 return ret;
282 *contains_wcard = False;
284 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
286 * For a DFS path the function parse_dfs_path()
287 * will do the path processing, just make a copy.
289 *err = NT_STATUS_OK;
290 return ret;
293 if (posix_pathnames) {
294 *err = check_path_syntax_posix(*pp_dest);
295 } else {
296 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
299 return ret;
302 /****************************************************************************
303 Pull a string and check the path allowing a wilcard - provide for error return.
304 ****************************************************************************/
306 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
307 const char *base_ptr,
308 uint16_t smb_flags2,
309 char **pp_dest,
310 const char *src,
311 size_t src_len,
312 int flags,
313 NTSTATUS *err,
314 bool *contains_wcard)
316 return srvstr_get_path_wcard_internal(ctx,
317 base_ptr,
318 smb_flags2,
319 pp_dest,
320 src,
321 src_len,
322 flags,
323 false,
324 err,
325 contains_wcard);
328 /****************************************************************************
329 Pull a string and check the path allowing a wilcard - provide for error return.
330 posix_pathnames version.
331 ****************************************************************************/
333 size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
334 const char *base_ptr,
335 uint16_t smb_flags2,
336 char **pp_dest,
337 const char *src,
338 size_t src_len,
339 int flags,
340 NTSTATUS *err,
341 bool *contains_wcard)
343 return srvstr_get_path_wcard_internal(ctx,
344 base_ptr,
345 smb_flags2,
346 pp_dest,
347 src,
348 src_len,
349 flags,
350 true,
351 err,
352 contains_wcard);
355 /****************************************************************************
356 Pull a string and check the path - provide for error return.
357 ****************************************************************************/
359 size_t srvstr_get_path(TALLOC_CTX *ctx,
360 const char *base_ptr,
361 uint16_t smb_flags2,
362 char **pp_dest,
363 const char *src,
364 size_t src_len,
365 int flags,
366 NTSTATUS *err)
368 bool ignore;
369 return srvstr_get_path_wcard_internal(ctx,
370 base_ptr,
371 smb_flags2,
372 pp_dest,
373 src,
374 src_len,
375 flags,
376 false,
377 err,
378 &ignore);
381 /****************************************************************************
382 Pull a string and check the path - provide for error return.
383 posix_pathnames version.
384 ****************************************************************************/
386 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
387 const char *base_ptr,
388 uint16_t smb_flags2,
389 char **pp_dest,
390 const char *src,
391 size_t src_len,
392 int flags,
393 NTSTATUS *err)
395 bool ignore;
396 return srvstr_get_path_wcard_internal(ctx,
397 base_ptr,
398 smb_flags2,
399 pp_dest,
400 src,
401 src_len,
402 flags,
403 true,
404 err,
405 &ignore);
409 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
410 char **pp_dest, const char *src, int flags,
411 NTSTATUS *err, bool *contains_wcard)
413 ssize_t bufrem = smbreq_bufrem(req, src);
415 if (bufrem < 0) {
416 *err = NT_STATUS_INVALID_PARAMETER;
417 return 0;
420 if (req->posix_pathnames) {
421 return srvstr_get_path_wcard_internal(mem_ctx,
422 (const char *)req->inbuf,
423 req->flags2,
424 pp_dest,
425 src,
426 bufrem,
427 flags,
428 true,
429 err,
430 contains_wcard);
431 } else {
432 return srvstr_get_path_wcard_internal(mem_ctx,
433 (const char *)req->inbuf,
434 req->flags2,
435 pp_dest,
436 src,
437 bufrem,
438 flags,
439 false,
440 err,
441 contains_wcard);
445 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
446 char **pp_dest, const char *src, int flags,
447 NTSTATUS *err)
449 bool ignore;
450 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
451 flags, err, &ignore);
455 * pull a string from the smb_buf part of a packet. In this case the
456 * string can either be null terminated or it can be terminated by the
457 * end of the smbbuf area
459 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
460 char **dest, const uint8_t *src, int flags)
462 ssize_t bufrem = smbreq_bufrem(req, src);
464 if (bufrem < 0) {
465 return 0;
468 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
469 bufrem, flags);
472 /****************************************************************************
473 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
474 ****************************************************************************/
476 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
477 files_struct *fsp)
479 if ((fsp == NULL) || (conn == NULL)) {
480 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
481 return False;
483 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
484 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
485 return False;
487 return True;
490 /****************************************************************************
491 Check if we have a correct fsp pointing to a file.
492 ****************************************************************************/
494 bool check_fsp(connection_struct *conn, struct smb_request *req,
495 files_struct *fsp)
497 if (!check_fsp_open(conn, req, fsp)) {
498 return False;
500 if (fsp->is_directory) {
501 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
502 return False;
504 if (fsp->fh->fd == -1) {
505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
506 return False;
508 fsp->num_smb_operations++;
509 return True;
512 /****************************************************************************
513 Check if we have a correct fsp pointing to a quota fake file. Replacement for
514 the CHECK_NTQUOTA_HANDLE_OK macro.
515 ****************************************************************************/
517 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
518 files_struct *fsp)
520 if (!check_fsp_open(conn, req, fsp)) {
521 return false;
524 if (fsp->is_directory) {
525 return false;
528 if (fsp->fake_file_handle == NULL) {
529 return false;
532 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
533 return false;
536 if (fsp->fake_file_handle->private_data == NULL) {
537 return false;
540 return true;
543 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
544 const char *name, int name_type)
546 char *trim_name;
547 char *trim_name_type;
548 const char *retarget_parm;
549 char *retarget;
550 char *p;
551 int retarget_type = 0x20;
552 int retarget_port = NBT_SMB_PORT;
553 struct sockaddr_storage retarget_addr;
554 struct sockaddr_in *in_addr;
555 bool ret = false;
556 uint8_t outbuf[10];
558 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
559 return false;
562 trim_name = talloc_strdup(talloc_tos(), name);
563 if (trim_name == NULL) {
564 goto fail;
566 trim_char(trim_name, ' ', ' ');
568 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
569 name_type);
570 if (trim_name_type == NULL) {
571 goto fail;
574 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
575 trim_name_type, NULL);
576 if (retarget_parm == NULL) {
577 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
578 trim_name, NULL);
580 if (retarget_parm == NULL) {
581 goto fail;
584 retarget = talloc_strdup(trim_name, retarget_parm);
585 if (retarget == NULL) {
586 goto fail;
589 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
591 p = strchr(retarget, ':');
592 if (p != NULL) {
593 *p++ = '\0';
594 retarget_port = atoi(p);
597 p = strchr_m(retarget, '#');
598 if (p != NULL) {
599 *p++ = '\0';
600 if (sscanf(p, "%x", &retarget_type) != 1) {
601 goto fail;
605 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
606 if (!ret) {
607 DEBUG(10, ("could not resolve %s\n", retarget));
608 goto fail;
611 if (retarget_addr.ss_family != AF_INET) {
612 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
613 goto fail;
616 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
618 _smb_setlen(outbuf, 6);
619 SCVAL(outbuf, 0, 0x84);
620 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
621 *(uint16_t *)(outbuf+8) = htons(retarget_port);
623 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
624 NULL)) {
625 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
626 "failed.");
629 ret = true;
630 fail:
631 TALLOC_FREE(trim_name);
632 return ret;
635 static void reply_called_name_not_present(char *outbuf)
637 smb_setlen(outbuf, 1);
638 SCVAL(outbuf, 0, 0x83);
639 SCVAL(outbuf, 4, 0x82);
642 /****************************************************************************
643 Reply to a (netbios-level) special message.
644 ****************************************************************************/
646 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
648 struct smbd_server_connection *sconn = xconn->client->sconn;
649 int msg_type = CVAL(inbuf,0);
650 int msg_flags = CVAL(inbuf,1);
652 * We only really use 4 bytes of the outbuf, but for the smb_setlen
653 * calculation & friends (srv_send_smb uses that) we need the full smb
654 * header.
656 char outbuf[smb_size];
658 memset(outbuf, '\0', sizeof(outbuf));
660 smb_setlen(outbuf,0);
662 switch (msg_type) {
663 case NBSSrequest: /* session request */
665 /* inbuf_size is guarenteed to be at least 4. */
666 fstring name1,name2;
667 int name_type1, name_type2;
668 int name_len1, name_len2;
670 *name1 = *name2 = 0;
672 if (xconn->transport.nbt.got_session) {
673 exit_server_cleanly("multiple session request not permitted");
676 SCVAL(outbuf,0,NBSSpositive);
677 SCVAL(outbuf,3,0);
679 /* inbuf_size is guaranteed to be at least 4. */
680 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
681 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
682 DEBUG(0,("Invalid name length in session request\n"));
683 reply_called_name_not_present(outbuf);
684 break;
686 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
687 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
688 DEBUG(0,("Invalid name length in session request\n"));
689 reply_called_name_not_present(outbuf);
690 break;
693 name_type1 = name_extract((unsigned char *)inbuf,
694 inbuf_size,(unsigned int)4,name1);
695 name_type2 = name_extract((unsigned char *)inbuf,
696 inbuf_size,(unsigned int)(4 + name_len1),name2);
698 if (name_type1 == -1 || name_type2 == -1) {
699 DEBUG(0,("Invalid name type in session request\n"));
700 reply_called_name_not_present(outbuf);
701 break;
704 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
705 name1, name_type1, name2, name_type2));
707 if (netbios_session_retarget(xconn, name1, name_type1)) {
708 exit_server_cleanly("retargeted client");
712 * Windows NT/2k uses "*SMBSERVER" and XP uses
713 * "*SMBSERV" arrggg!!!
715 if (strequal(name1, "*SMBSERVER ")
716 || strequal(name1, "*SMBSERV ")) {
717 char *raddr;
719 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
720 talloc_tos());
721 if (raddr == NULL) {
722 exit_server_cleanly("could not allocate raddr");
725 fstrcpy(name1, raddr);
728 set_local_machine_name(name1, True);
729 set_remote_machine_name(name2, True);
731 if (is_ipaddress(sconn->remote_hostname)) {
732 char *p = discard_const_p(char, sconn->remote_hostname);
734 talloc_free(p);
736 sconn->remote_hostname = talloc_strdup(sconn,
737 get_remote_machine_name());
738 if (sconn->remote_hostname == NULL) {
739 exit_server_cleanly("could not copy remote name");
741 xconn->remote_hostname = sconn->remote_hostname;
744 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
745 get_local_machine_name(), get_remote_machine_name(),
746 name_type2));
748 if (name_type2 == 'R') {
749 /* We are being asked for a pathworks session ---
750 no thanks! */
751 reply_called_name_not_present(outbuf);
752 break;
755 reload_services(sconn, conn_snum_used, true);
756 reopen_logs();
758 xconn->transport.nbt.got_session = true;
759 break;
762 case 0x89: /* session keepalive request
763 (some old clients produce this?) */
764 SCVAL(outbuf,0,NBSSkeepalive);
765 SCVAL(outbuf,3,0);
766 break;
768 case NBSSpositive: /* positive session response */
769 case NBSSnegative: /* negative session response */
770 case NBSSretarget: /* retarget session response */
771 DEBUG(0,("Unexpected session response\n"));
772 break;
774 case NBSSkeepalive: /* session keepalive */
775 default:
776 return;
779 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
780 msg_type, msg_flags));
782 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
783 exit_server_cleanly("reply_special: srv_send_smb failed.");
786 if (CVAL(outbuf, 0) != 0x82) {
787 exit_server_cleanly("invalid netbios session");
789 return;
792 /****************************************************************************
793 Reply to a tcon.
794 conn POINTER CAN BE NULL HERE !
795 ****************************************************************************/
797 void reply_tcon(struct smb_request *req)
799 connection_struct *conn = req->conn;
800 const char *service;
801 char *service_buf = NULL;
802 char *password = NULL;
803 char *dev = NULL;
804 int pwlen=0;
805 NTSTATUS nt_status;
806 const uint8_t *p;
807 const char *p2;
808 TALLOC_CTX *ctx = talloc_tos();
809 struct smbXsrv_connection *xconn = req->xconn;
810 NTTIME now = timeval_to_nttime(&req->request_time);
812 START_PROFILE(SMBtcon);
814 if (req->buflen < 4) {
815 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
816 END_PROFILE(SMBtcon);
817 return;
820 p = req->buf + 1;
821 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
822 p += 1;
823 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
824 p += pwlen+1;
825 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
826 p += 1;
828 if (service_buf == NULL || password == NULL || dev == NULL) {
829 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
830 END_PROFILE(SMBtcon);
831 return;
833 p2 = strrchr_m(service_buf,'\\');
834 if (p2) {
835 service = p2+1;
836 } else {
837 service = service_buf;
840 conn = make_connection(req, now, service, dev,
841 req->vuid,&nt_status);
842 req->conn = conn;
844 if (!conn) {
845 reply_nterror(req, nt_status);
846 END_PROFILE(SMBtcon);
847 return;
850 reply_outbuf(req, 2, 0);
851 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
852 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
853 SSVAL(req->outbuf,smb_tid,conn->cnum);
855 DEBUG(3,("tcon service=%s cnum=%d\n",
856 service, conn->cnum));
858 END_PROFILE(SMBtcon);
859 return;
862 /****************************************************************************
863 Reply to a tcon and X.
864 conn POINTER CAN BE NULL HERE !
865 ****************************************************************************/
867 void reply_tcon_and_X(struct smb_request *req)
869 connection_struct *conn = req->conn;
870 const char *service = NULL;
871 TALLOC_CTX *ctx = talloc_tos();
872 /* what the client thinks the device is */
873 char *client_devicetype = NULL;
874 /* what the server tells the client the share represents */
875 const char *server_devicetype;
876 NTSTATUS nt_status;
877 int passlen;
878 char *path = NULL;
879 const uint8_t *p;
880 const char *q;
881 uint16_t tcon_flags;
882 struct smbXsrv_session *session = NULL;
883 NTTIME now = timeval_to_nttime(&req->request_time);
884 bool session_key_updated = false;
885 uint16_t optional_support = 0;
886 struct smbXsrv_connection *xconn = req->xconn;
888 START_PROFILE(SMBtconX);
890 if (req->wct < 4) {
891 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
892 END_PROFILE(SMBtconX);
893 return;
896 passlen = SVAL(req->vwv+3, 0);
897 tcon_flags = SVAL(req->vwv+2, 0);
899 /* we might have to close an old one */
900 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
901 struct smbXsrv_tcon *tcon;
902 NTSTATUS status;
904 tcon = conn->tcon;
905 req->conn = NULL;
906 conn = NULL;
909 * TODO: cancel all outstanding requests on the tcon
911 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
912 if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(0, ("reply_tcon_and_X: "
914 "smbXsrv_tcon_disconnect() failed: %s\n",
915 nt_errstr(status)));
917 * If we hit this case, there is something completely
918 * wrong, so we better disconnect the transport connection.
920 END_PROFILE(SMBtconX);
921 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
922 return;
925 TALLOC_FREE(tcon);
927 * This tree id is gone. Make sure we can't re-use it
928 * by accident.
930 req->tid = 0;
933 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
934 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
935 END_PROFILE(SMBtconX);
936 return;
939 if (xconn->smb1.negprot.encrypted_passwords) {
940 p = req->buf + passlen;
941 } else {
942 p = req->buf + passlen + 1;
945 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
947 if (path == NULL) {
948 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
949 END_PROFILE(SMBtconX);
950 return;
954 * the service name can be either: \\server\share
955 * or share directly like on the DELL PowerVault 705
957 if (*path=='\\') {
958 q = strchr_m(path+2,'\\');
959 if (!q) {
960 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
961 END_PROFILE(SMBtconX);
962 return;
964 service = q+1;
965 } else {
966 service = path;
969 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
970 &client_devicetype, p,
971 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
973 if (client_devicetype == NULL) {
974 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
975 END_PROFILE(SMBtconX);
976 return;
979 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
981 nt_status = smb1srv_session_lookup(xconn,
982 req->vuid, now, &session);
983 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
984 reply_force_doserror(req, ERRSRV, ERRbaduid);
985 END_PROFILE(SMBtconX);
986 return;
988 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
989 reply_nterror(req, nt_status);
990 END_PROFILE(SMBtconX);
991 return;
993 if (!NT_STATUS_IS_OK(nt_status)) {
994 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
995 END_PROFILE(SMBtconX);
996 return;
999 if (session->global->auth_session_info == NULL) {
1000 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1001 END_PROFILE(SMBtconX);
1002 return;
1006 * If there is no application key defined yet
1007 * we create one.
1009 * This means we setup the application key on the
1010 * first tcon that happens via the given session.
1012 * Once the application key is defined, it does not
1013 * change any more.
1015 if (session->global->application_key.length == 0 &&
1016 smb2_signing_key_valid(session->global->signing_key))
1018 struct smbXsrv_session *x = session;
1019 struct auth_session_info *session_info =
1020 session->global->auth_session_info;
1021 uint8_t session_key[16];
1023 ZERO_STRUCT(session_key);
1024 memcpy(session_key, x->global->signing_key->blob.data,
1025 MIN(x->global->signing_key->blob.length, sizeof(session_key)));
1028 * The application key is truncated/padded to 16 bytes
1030 x->global->application_key = data_blob_talloc(x->global,
1031 session_key,
1032 sizeof(session_key));
1033 ZERO_STRUCT(session_key);
1034 if (x->global->application_key.data == NULL) {
1035 reply_nterror(req, NT_STATUS_NO_MEMORY);
1036 END_PROFILE(SMBtconX);
1037 return;
1040 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1041 NTSTATUS status;
1043 status = smb_key_derivation(x->global->application_key.data,
1044 x->global->application_key.length,
1045 x->global->application_key.data);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 DBG_ERR("smb_key_derivation failed: %s\n",
1048 nt_errstr(status));
1049 return;
1051 optional_support |= SMB_EXTENDED_SIGNATURES;
1055 * Place the application key into the session_info
1057 data_blob_clear_free(&session_info->session_key);
1058 session_info->session_key = data_blob_dup_talloc(session_info,
1059 x->global->application_key);
1060 if (session_info->session_key.data == NULL) {
1061 data_blob_clear_free(&x->global->application_key);
1062 reply_nterror(req, NT_STATUS_NO_MEMORY);
1063 END_PROFILE(SMBtconX);
1064 return;
1066 session_key_updated = true;
1069 conn = make_connection(req, now, service, client_devicetype,
1070 req->vuid, &nt_status);
1071 req->conn =conn;
1073 if (!conn) {
1074 if (session_key_updated) {
1075 struct smbXsrv_session *x = session;
1076 struct auth_session_info *session_info =
1077 session->global->auth_session_info;
1078 data_blob_clear_free(&x->global->application_key);
1079 data_blob_clear_free(&session_info->session_key);
1081 reply_nterror(req, nt_status);
1082 END_PROFILE(SMBtconX);
1083 return;
1086 if ( IS_IPC(conn) )
1087 server_devicetype = "IPC";
1088 else if ( IS_PRINT(conn) )
1089 server_devicetype = "LPT1:";
1090 else
1091 server_devicetype = "A:";
1093 if (get_Protocol() < PROTOCOL_NT1) {
1094 reply_outbuf(req, 2, 0);
1095 if (message_push_string(&req->outbuf, server_devicetype,
1096 STR_TERMINATE|STR_ASCII) == -1) {
1097 reply_nterror(req, NT_STATUS_NO_MEMORY);
1098 END_PROFILE(SMBtconX);
1099 return;
1101 } else {
1102 /* NT sets the fstype of IPC$ to the null string */
1103 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1105 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1106 /* Return permissions. */
1107 uint32_t perm1 = 0;
1108 uint32_t perm2 = 0;
1110 reply_outbuf(req, 7, 0);
1112 if (IS_IPC(conn)) {
1113 perm1 = FILE_ALL_ACCESS;
1114 perm2 = FILE_ALL_ACCESS;
1115 } else {
1116 perm1 = conn->share_access;
1119 SIVAL(req->outbuf, smb_vwv3, perm1);
1120 SIVAL(req->outbuf, smb_vwv5, perm2);
1121 } else {
1122 reply_outbuf(req, 3, 0);
1125 if ((message_push_string(&req->outbuf, server_devicetype,
1126 STR_TERMINATE|STR_ASCII) == -1)
1127 || (message_push_string(&req->outbuf, fstype,
1128 STR_TERMINATE) == -1)) {
1129 reply_nterror(req, NT_STATUS_NO_MEMORY);
1130 END_PROFILE(SMBtconX);
1131 return;
1134 /* what does setting this bit do? It is set by NT4 and
1135 may affect the ability to autorun mounted cdroms */
1136 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1137 optional_support |=
1138 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1140 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1141 DEBUG(2,("Serving %s as a Dfs root\n",
1142 lp_servicename(ctx, SNUM(conn)) ));
1143 optional_support |= SMB_SHARE_IN_DFS;
1146 SSVAL(req->outbuf, smb_vwv2, optional_support);
1149 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1150 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1152 DEBUG(3,("tconX service=%s \n",
1153 service));
1155 /* set the incoming and outgoing tid to the just created one */
1156 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1157 SSVAL(req->outbuf,smb_tid,conn->cnum);
1159 END_PROFILE(SMBtconX);
1161 req->tid = conn->cnum;
1164 /****************************************************************************
1165 Reply to an unknown type.
1166 ****************************************************************************/
1168 void reply_unknown_new(struct smb_request *req, uint8_t type)
1170 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1171 smb_fn_name(type), type, type));
1172 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1173 return;
1176 /****************************************************************************
1177 Reply to an ioctl.
1178 conn POINTER CAN BE NULL HERE !
1179 ****************************************************************************/
1181 void reply_ioctl(struct smb_request *req)
1183 connection_struct *conn = req->conn;
1184 uint16_t device;
1185 uint16_t function;
1186 uint32_t ioctl_code;
1187 int replysize;
1188 char *p;
1190 START_PROFILE(SMBioctl);
1192 if (req->wct < 3) {
1193 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1194 END_PROFILE(SMBioctl);
1195 return;
1198 device = SVAL(req->vwv+1, 0);
1199 function = SVAL(req->vwv+2, 0);
1200 ioctl_code = (device << 16) + function;
1202 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1204 switch (ioctl_code) {
1205 case IOCTL_QUERY_JOB_INFO:
1206 replysize = 32;
1207 break;
1208 default:
1209 reply_force_doserror(req, ERRSRV, ERRnosupport);
1210 END_PROFILE(SMBioctl);
1211 return;
1214 reply_outbuf(req, 8, replysize+1);
1215 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1216 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1217 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1218 p = smb_buf(req->outbuf);
1219 memset(p, '\0', replysize+1); /* valgrind-safe. */
1220 p += 1; /* Allow for alignment */
1222 switch (ioctl_code) {
1223 case IOCTL_QUERY_JOB_INFO:
1225 NTSTATUS status;
1226 size_t len = 0;
1227 files_struct *fsp = file_fsp(
1228 req, SVAL(req->vwv+0, 0));
1229 if (!fsp) {
1230 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1231 END_PROFILE(SMBioctl);
1232 return;
1234 /* Job number */
1235 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1237 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1238 lp_netbios_name(), 15,
1239 STR_TERMINATE|STR_ASCII, &len);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 reply_nterror(req, status);
1242 END_PROFILE(SMBioctl);
1243 return;
1245 if (conn) {
1246 status = srvstr_push((char *)req->outbuf, req->flags2,
1247 p+18,
1248 lp_servicename(talloc_tos(),
1249 SNUM(conn)),
1250 13, STR_TERMINATE|STR_ASCII, &len);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 reply_nterror(req, status);
1253 END_PROFILE(SMBioctl);
1254 return;
1256 } else {
1257 memset(p+18, 0, 13);
1259 break;
1263 END_PROFILE(SMBioctl);
1264 return;
1267 /****************************************************************************
1268 Strange checkpath NTSTATUS mapping.
1269 ****************************************************************************/
1271 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1273 /* Strange DOS error code semantics only for checkpath... */
1274 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1275 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1276 /* We need to map to ERRbadpath */
1277 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1280 return status;
1283 /****************************************************************************
1284 Reply to a checkpath.
1285 ****************************************************************************/
1287 void reply_checkpath(struct smb_request *req)
1289 connection_struct *conn = req->conn;
1290 struct smb_filename *smb_fname = NULL;
1291 char *name = NULL;
1292 NTSTATUS status;
1293 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1294 TALLOC_CTX *ctx = talloc_tos();
1296 START_PROFILE(SMBcheckpath);
1298 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1299 STR_TERMINATE, &status);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 status = map_checkpath_error(req->flags2, status);
1303 reply_nterror(req, status);
1304 END_PROFILE(SMBcheckpath);
1305 return;
1308 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1310 status = filename_convert(ctx,
1311 conn,
1312 name,
1313 ucf_flags,
1314 NULL,
1315 NULL,
1316 &smb_fname);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1320 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1321 ERRSRV, ERRbadpath);
1322 END_PROFILE(SMBcheckpath);
1323 return;
1325 goto path_err;
1328 if (!VALID_STAT(smb_fname->st) &&
1329 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1330 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1331 smb_fname_str_dbg(smb_fname), strerror(errno)));
1332 status = map_nt_error_from_unix(errno);
1333 goto path_err;
1336 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1337 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1338 ERRDOS, ERRbadpath);
1339 goto out;
1342 reply_outbuf(req, 0, 0);
1344 path_err:
1345 /* We special case this - as when a Windows machine
1346 is parsing a path is steps through the components
1347 one at a time - if a component fails it expects
1348 ERRbadpath, not ERRbadfile.
1350 status = map_checkpath_error(req->flags2, status);
1351 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1353 * Windows returns different error codes if
1354 * the parent directory is valid but not the
1355 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1356 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1357 * if the path is invalid.
1359 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1360 ERRDOS, ERRbadpath);
1361 goto out;
1364 reply_nterror(req, status);
1366 out:
1367 TALLOC_FREE(smb_fname);
1368 END_PROFILE(SMBcheckpath);
1369 return;
1372 /****************************************************************************
1373 Reply to a getatr.
1374 ****************************************************************************/
1376 void reply_getatr(struct smb_request *req)
1378 connection_struct *conn = req->conn;
1379 struct smb_filename *smb_fname = NULL;
1380 char *fname = NULL;
1381 int mode=0;
1382 off_t size=0;
1383 time_t mtime=0;
1384 const char *p;
1385 NTSTATUS status;
1386 TALLOC_CTX *ctx = talloc_tos();
1387 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1389 START_PROFILE(SMBgetatr);
1391 p = (const char *)req->buf + 1;
1392 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 reply_nterror(req, status);
1395 goto out;
1398 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1399 under WfWg - weird! */
1400 if (*fname == '\0') {
1401 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1402 if (!CAN_WRITE(conn)) {
1403 mode |= FILE_ATTRIBUTE_READONLY;
1405 size = 0;
1406 mtime = 0;
1407 } else {
1408 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1409 status = filename_convert(ctx,
1410 conn,
1411 fname,
1412 ucf_flags,
1413 NULL,
1414 NULL,
1415 &smb_fname);
1416 if (!NT_STATUS_IS_OK(status)) {
1417 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1418 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1419 ERRSRV, ERRbadpath);
1420 goto out;
1422 reply_nterror(req, status);
1423 goto out;
1425 if (!VALID_STAT(smb_fname->st) &&
1426 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1427 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1428 smb_fname_str_dbg(smb_fname),
1429 strerror(errno)));
1430 reply_nterror(req, map_nt_error_from_unix(errno));
1431 goto out;
1434 mode = dos_mode(conn, smb_fname);
1435 size = smb_fname->st.st_ex_size;
1437 if (ask_sharemode) {
1438 struct timespec write_time_ts;
1439 struct file_id fileid;
1441 ZERO_STRUCT(write_time_ts);
1442 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1443 get_file_infos(fileid, 0, NULL, &write_time_ts);
1444 if (!null_timespec(write_time_ts)) {
1445 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1449 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1450 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1451 size = 0;
1455 reply_outbuf(req, 10, 0);
1457 SSVAL(req->outbuf,smb_vwv0,mode);
1458 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1459 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1460 } else {
1461 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1463 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1465 if (get_Protocol() >= PROTOCOL_NT1) {
1466 SSVAL(req->outbuf, smb_flg2,
1467 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1470 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1471 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1473 out:
1474 TALLOC_FREE(smb_fname);
1475 TALLOC_FREE(fname);
1476 END_PROFILE(SMBgetatr);
1477 return;
1480 /****************************************************************************
1481 Reply to a setatr.
1482 ****************************************************************************/
1484 void reply_setatr(struct smb_request *req)
1486 struct smb_file_time ft;
1487 connection_struct *conn = req->conn;
1488 struct smb_filename *smb_fname = NULL;
1489 char *fname = NULL;
1490 int mode;
1491 time_t mtime;
1492 const char *p;
1493 NTSTATUS status;
1494 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1495 TALLOC_CTX *ctx = talloc_tos();
1497 START_PROFILE(SMBsetatr);
1499 if (req->wct < 2) {
1500 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1501 goto out;
1504 p = (const char *)req->buf + 1;
1505 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1506 if (!NT_STATUS_IS_OK(status)) {
1507 reply_nterror(req, status);
1508 goto out;
1511 status = filename_convert(ctx,
1512 conn,
1513 fname,
1514 ucf_flags,
1515 NULL,
1516 NULL,
1517 &smb_fname);
1518 if (!NT_STATUS_IS_OK(status)) {
1519 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1520 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1521 ERRSRV, ERRbadpath);
1522 goto out;
1524 reply_nterror(req, status);
1525 goto out;
1528 if (ISDOT(smb_fname->base_name)) {
1530 * Not sure here is the right place to catch this
1531 * condition. Might be moved to somewhere else later -- vl
1533 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1534 goto out;
1537 mode = SVAL(req->vwv+0, 0);
1538 mtime = srv_make_unix_date3(req->vwv+1);
1540 if (mode != FILE_ATTRIBUTE_NORMAL) {
1541 if (VALID_STAT_OF_DIR(smb_fname->st))
1542 mode |= FILE_ATTRIBUTE_DIRECTORY;
1543 else
1544 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1546 status = smbd_check_access_rights(
1547 conn, smb_fname, false, FILE_WRITE_ATTRIBUTES);
1548 if (!NT_STATUS_IS_OK(status)) {
1549 reply_nterror(req, status);
1550 goto out;
1553 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1554 false) != 0) {
1555 reply_nterror(req, map_nt_error_from_unix(errno));
1556 goto out;
1560 ft = (struct smb_file_time) {
1561 .mtime = convert_time_t_to_timespec(mtime)
1564 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1565 if (!NT_STATUS_IS_OK(status)) {
1566 reply_nterror(req, status);
1567 goto out;
1570 reply_outbuf(req, 0, 0);
1572 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1573 mode));
1574 out:
1575 TALLOC_FREE(smb_fname);
1576 END_PROFILE(SMBsetatr);
1577 return;
1580 /****************************************************************************
1581 Reply to a dskattr.
1582 ****************************************************************************/
1584 void reply_dskattr(struct smb_request *req)
1586 connection_struct *conn = req->conn;
1587 uint64_t ret;
1588 uint64_t dfree,dsize,bsize;
1589 struct smb_filename smb_fname;
1590 START_PROFILE(SMBdskattr);
1592 ZERO_STRUCT(smb_fname);
1593 smb_fname.base_name = discard_const_p(char, ".");
1595 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1596 reply_nterror(req, map_nt_error_from_unix(errno));
1597 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1598 END_PROFILE(SMBdskattr);
1599 return;
1602 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1603 if (ret == (uint64_t)-1) {
1604 reply_nterror(req, map_nt_error_from_unix(errno));
1605 END_PROFILE(SMBdskattr);
1606 return;
1610 * Force max to fit in 16 bit fields.
1612 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1613 dfree /= 2;
1614 dsize /= 2;
1615 bsize *= 2;
1616 if (bsize > (WORDMAX*512)) {
1617 bsize = (WORDMAX*512);
1618 if (dsize > WORDMAX)
1619 dsize = WORDMAX;
1620 if (dfree > WORDMAX)
1621 dfree = WORDMAX;
1622 break;
1626 reply_outbuf(req, 5, 0);
1628 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1629 double total_space, free_space;
1630 /* we need to scale this to a number that DOS6 can handle. We
1631 use floating point so we can handle large drives on systems
1632 that don't have 64 bit integers
1634 we end up displaying a maximum of 2G to DOS systems
1636 total_space = dsize * (double)bsize;
1637 free_space = dfree * (double)bsize;
1639 dsize = (uint64_t)((total_space+63*512) / (64*512));
1640 dfree = (uint64_t)((free_space+63*512) / (64*512));
1642 if (dsize > 0xFFFF) dsize = 0xFFFF;
1643 if (dfree > 0xFFFF) dfree = 0xFFFF;
1645 SSVAL(req->outbuf,smb_vwv0,dsize);
1646 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1647 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1648 SSVAL(req->outbuf,smb_vwv3,dfree);
1649 } else {
1650 SSVAL(req->outbuf,smb_vwv0,dsize);
1651 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1652 SSVAL(req->outbuf,smb_vwv2,512);
1653 SSVAL(req->outbuf,smb_vwv3,dfree);
1656 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1658 END_PROFILE(SMBdskattr);
1659 return;
1663 * Utility function to split the filename from the directory.
1665 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1666 char **fname_dir_out,
1667 char **fname_mask_out)
1669 const char *p = NULL;
1670 char *fname_dir = NULL;
1671 char *fname_mask = NULL;
1673 p = strrchr_m(fname_in, '/');
1674 if (!p) {
1675 fname_dir = talloc_strdup(ctx, ".");
1676 fname_mask = talloc_strdup(ctx, fname_in);
1677 } else {
1678 fname_dir = talloc_strndup(ctx, fname_in,
1679 PTR_DIFF(p, fname_in));
1680 fname_mask = talloc_strdup(ctx, p+1);
1683 if (!fname_dir || !fname_mask) {
1684 TALLOC_FREE(fname_dir);
1685 TALLOC_FREE(fname_mask);
1686 return NT_STATUS_NO_MEMORY;
1689 *fname_dir_out = fname_dir;
1690 *fname_mask_out = fname_mask;
1691 return NT_STATUS_OK;
1694 /****************************************************************************
1695 Make a dir struct.
1696 ****************************************************************************/
1698 static bool make_dir_struct(TALLOC_CTX *ctx,
1699 char *buf,
1700 const char *mask,
1701 const char *fname,
1702 off_t size,
1703 uint32_t mode,
1704 time_t date,
1705 bool uc)
1707 char *p;
1708 char *mask2 = talloc_strdup(ctx, mask);
1710 if (!mask2) {
1711 return False;
1714 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1715 size = 0;
1718 memset(buf+1,' ',11);
1719 if ((p = strchr_m(mask2,'.')) != NULL) {
1720 *p = 0;
1721 push_ascii(buf+1,mask2,8, 0);
1722 push_ascii(buf+9,p+1,3, 0);
1723 *p = '.';
1724 } else {
1725 push_ascii(buf+1,mask2,11, 0);
1728 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1729 SCVAL(buf,21,mode);
1730 srv_put_dos_date(buf,22,date);
1731 SSVAL(buf,26,size & 0xFFFF);
1732 SSVAL(buf,28,(size >> 16)&0xFFFF);
1733 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1734 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1735 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1736 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1737 return True;
1740 /****************************************************************************
1741 Reply to a search.
1742 Can be called from SMBsearch, SMBffirst or SMBfunique.
1743 ****************************************************************************/
1745 void reply_search(struct smb_request *req)
1747 connection_struct *conn = req->conn;
1748 char *path = NULL;
1749 char *mask = NULL;
1750 char *directory = NULL;
1751 struct smb_filename *smb_fname = NULL;
1752 char *fname = NULL;
1753 off_t size;
1754 uint32_t mode;
1755 struct timespec date;
1756 uint32_t dirtype;
1757 unsigned int numentries = 0;
1758 unsigned int maxentries = 0;
1759 bool finished = False;
1760 const char *p;
1761 int status_len;
1762 char status[21];
1763 int dptr_num= -1;
1764 bool check_descend = False;
1765 bool expect_close = False;
1766 NTSTATUS nt_status;
1767 bool mask_contains_wcard = False;
1768 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1769 TALLOC_CTX *ctx = talloc_tos();
1770 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1771 struct dptr_struct *dirptr = NULL;
1772 struct smbXsrv_connection *xconn = req->xconn;
1773 struct smbd_server_connection *sconn = req->sconn;
1775 START_PROFILE(SMBsearch);
1777 if (req->wct < 2) {
1778 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1779 goto out;
1782 if (req->posix_pathnames) {
1783 reply_unknown_new(req, req->cmd);
1784 goto out;
1787 /* If we were called as SMBffirst then we must expect close. */
1788 if(req->cmd == SMBffirst) {
1789 expect_close = True;
1792 reply_outbuf(req, 1, 3);
1793 maxentries = SVAL(req->vwv+0, 0);
1794 dirtype = SVAL(req->vwv+1, 0);
1795 p = (const char *)req->buf + 1;
1796 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1797 &nt_status, &mask_contains_wcard);
1798 if (!NT_STATUS_IS_OK(nt_status)) {
1799 reply_nterror(req, nt_status);
1800 goto out;
1803 p++;
1804 status_len = SVAL(p, 0);
1805 p += 2;
1807 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1809 if (status_len == 0) {
1810 struct smb_filename *smb_dname = NULL;
1811 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1812 ucf_flags_from_smb_request(req);
1813 nt_status = filename_convert(ctx, conn,
1814 path,
1815 ucf_flags,
1816 NULL,
1817 &mask_contains_wcard,
1818 &smb_fname);
1819 if (!NT_STATUS_IS_OK(nt_status)) {
1820 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1821 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1822 ERRSRV, ERRbadpath);
1823 goto out;
1825 reply_nterror(req, nt_status);
1826 goto out;
1829 directory = smb_fname->base_name;
1831 p = strrchr_m(directory,'/');
1832 if ((p != NULL) && (*directory != '/')) {
1833 mask = talloc_strdup(ctx, p + 1);
1834 directory = talloc_strndup(ctx, directory,
1835 PTR_DIFF(p, directory));
1836 } else {
1837 mask = talloc_strdup(ctx, directory);
1838 directory = talloc_strdup(ctx,".");
1841 if (!directory) {
1842 reply_nterror(req, NT_STATUS_NO_MEMORY);
1843 goto out;
1846 memset((char *)status,'\0',21);
1847 SCVAL(status,0,(dirtype & 0x1F));
1849 smb_dname = synthetic_smb_fname(talloc_tos(),
1850 directory,
1851 NULL,
1852 NULL,
1853 smb_fname->flags);
1854 if (smb_dname == NULL) {
1855 reply_nterror(req, NT_STATUS_NO_MEMORY);
1856 goto out;
1859 nt_status = dptr_create(conn,
1860 NULL, /* req */
1861 NULL, /* fsp */
1862 smb_dname,
1863 True,
1864 expect_close,
1865 req->smbpid,
1866 mask,
1867 mask_contains_wcard,
1868 dirtype,
1869 &dirptr);
1871 TALLOC_FREE(smb_dname);
1873 if (!NT_STATUS_IS_OK(nt_status)) {
1874 reply_nterror(req, nt_status);
1875 goto out;
1877 dptr_num = dptr_dnum(dirptr);
1878 } else {
1879 int status_dirtype;
1880 const char *dirpath;
1882 memcpy(status,p,21);
1883 status_dirtype = CVAL(status,0) & 0x1F;
1884 if (status_dirtype != (dirtype & 0x1F)) {
1885 dirtype = status_dirtype;
1888 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1889 if (!dirptr) {
1890 goto SearchEmpty;
1892 dirpath = dptr_path(sconn, dptr_num);
1893 directory = talloc_strdup(ctx, dirpath);
1894 if (!directory) {
1895 reply_nterror(req, NT_STATUS_NO_MEMORY);
1896 goto out;
1899 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1900 if (!mask) {
1901 goto SearchEmpty;
1904 * For a 'continue' search we have no string. So
1905 * check from the initial saved string.
1907 if (!req->posix_pathnames) {
1908 mask_contains_wcard = ms_has_wild(mask);
1910 dirtype = dptr_attr(sconn, dptr_num);
1913 DEBUG(4,("dptr_num is %d\n",dptr_num));
1915 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1916 char buf[DIR_STRUCT_SIZE];
1917 memcpy(buf,status,21);
1918 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1919 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1920 reply_nterror(req, NT_STATUS_NO_MEMORY);
1921 goto out;
1923 dptr_fill(sconn, buf+12,dptr_num);
1924 if (dptr_zero(buf+12) && (status_len==0)) {
1925 numentries = 1;
1926 } else {
1927 numentries = 0;
1929 if (message_push_blob(&req->outbuf,
1930 data_blob_const(buf, sizeof(buf)))
1931 == -1) {
1932 reply_nterror(req, NT_STATUS_NO_MEMORY);
1933 goto out;
1935 } else {
1936 unsigned int i;
1937 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1938 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1940 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1942 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1943 directory,lp_dont_descend(ctx, SNUM(conn))));
1944 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1945 check_descend = True;
1948 for (i=numentries;(i<maxentries) && !finished;i++) {
1949 finished = !get_dir_entry(ctx,
1950 dirptr,
1951 mask,
1952 dirtype,
1953 &fname,
1954 &size,
1955 &mode,
1956 &date,
1957 check_descend,
1958 ask_sharemode);
1959 if (!finished) {
1960 char buf[DIR_STRUCT_SIZE];
1961 memcpy(buf,status,21);
1962 if (!make_dir_struct(ctx,
1963 buf,
1964 mask,
1965 fname,
1966 size,
1967 mode,
1968 convert_timespec_to_time_t(date),
1969 !allow_long_path_components)) {
1970 reply_nterror(req, NT_STATUS_NO_MEMORY);
1971 goto out;
1973 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1974 break;
1976 if (message_push_blob(&req->outbuf,
1977 data_blob_const(buf, sizeof(buf)))
1978 == -1) {
1979 reply_nterror(req, NT_STATUS_NO_MEMORY);
1980 goto out;
1982 numentries++;
1987 SearchEmpty:
1989 /* If we were called as SMBffirst with smb_search_id == NULL
1990 and no entries were found then return error and close dirptr
1991 (X/Open spec) */
1993 if (numentries == 0) {
1994 dptr_close(sconn, &dptr_num);
1995 } else if(expect_close && status_len == 0) {
1996 /* Close the dptr - we know it's gone */
1997 dptr_close(sconn, &dptr_num);
2000 /* If we were called as SMBfunique, then we can close the dirptr now ! */
2001 if(dptr_num >= 0 && req->cmd == SMBfunique) {
2002 dptr_close(sconn, &dptr_num);
2005 if ((numentries == 0) && !mask_contains_wcard) {
2006 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
2007 goto out;
2010 SSVAL(req->outbuf,smb_vwv0,numentries);
2011 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2012 SCVAL(smb_buf(req->outbuf),0,5);
2013 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2015 /* The replies here are never long name. */
2016 SSVAL(req->outbuf, smb_flg2,
2017 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2018 if (!allow_long_path_components) {
2019 SSVAL(req->outbuf, smb_flg2,
2020 SVAL(req->outbuf, smb_flg2)
2021 & (~FLAGS2_LONG_PATH_COMPONENTS));
2024 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2025 SSVAL(req->outbuf, smb_flg2,
2026 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2028 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2029 smb_fn_name(req->cmd),
2030 mask,
2031 directory,
2032 dirtype,
2033 numentries,
2034 maxentries ));
2035 out:
2036 TALLOC_FREE(directory);
2037 TALLOC_FREE(mask);
2038 TALLOC_FREE(smb_fname);
2039 END_PROFILE(SMBsearch);
2040 return;
2043 /****************************************************************************
2044 Reply to a fclose (stop directory search).
2045 ****************************************************************************/
2047 void reply_fclose(struct smb_request *req)
2049 int status_len;
2050 char status[21];
2051 int dptr_num= -2;
2052 const char *p;
2053 char *path = NULL;
2054 NTSTATUS err;
2055 bool path_contains_wcard = False;
2056 TALLOC_CTX *ctx = talloc_tos();
2057 struct smbd_server_connection *sconn = req->sconn;
2059 START_PROFILE(SMBfclose);
2061 if (req->posix_pathnames) {
2062 reply_unknown_new(req, req->cmd);
2063 END_PROFILE(SMBfclose);
2064 return;
2067 p = (const char *)req->buf + 1;
2068 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2069 &err, &path_contains_wcard);
2070 if (!NT_STATUS_IS_OK(err)) {
2071 reply_nterror(req, err);
2072 END_PROFILE(SMBfclose);
2073 return;
2075 p++;
2076 status_len = SVAL(p,0);
2077 p += 2;
2079 if (status_len == 0) {
2080 reply_force_doserror(req, ERRSRV, ERRsrverror);
2081 END_PROFILE(SMBfclose);
2082 return;
2085 memcpy(status,p,21);
2087 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2088 /* Close the dptr - we know it's gone */
2089 dptr_close(sconn, &dptr_num);
2092 reply_outbuf(req, 1, 0);
2093 SSVAL(req->outbuf,smb_vwv0,0);
2095 DEBUG(3,("search close\n"));
2097 END_PROFILE(SMBfclose);
2098 return;
2101 /****************************************************************************
2102 Reply to an open.
2103 ****************************************************************************/
2105 void reply_open(struct smb_request *req)
2107 connection_struct *conn = req->conn;
2108 struct smb_filename *smb_fname = NULL;
2109 char *fname = NULL;
2110 uint32_t fattr=0;
2111 off_t size = 0;
2112 time_t mtime=0;
2113 int info;
2114 files_struct *fsp;
2115 int oplock_request;
2116 int deny_mode;
2117 uint32_t dos_attr;
2118 uint32_t access_mask;
2119 uint32_t share_mode;
2120 uint32_t create_disposition;
2121 uint32_t create_options = 0;
2122 uint32_t private_flags = 0;
2123 NTSTATUS status;
2124 uint32_t ucf_flags;
2125 TALLOC_CTX *ctx = talloc_tos();
2127 START_PROFILE(SMBopen);
2129 if (req->wct < 2) {
2130 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2131 goto out;
2134 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2135 deny_mode = SVAL(req->vwv+0, 0);
2136 dos_attr = SVAL(req->vwv+1, 0);
2138 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2139 STR_TERMINATE, &status);
2140 if (!NT_STATUS_IS_OK(status)) {
2141 reply_nterror(req, status);
2142 goto out;
2145 if (!map_open_params_to_ntcreate(fname, deny_mode,
2146 OPENX_FILE_EXISTS_OPEN, &access_mask,
2147 &share_mode, &create_disposition,
2148 &create_options, &private_flags)) {
2149 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2150 goto out;
2153 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2155 status = filename_convert(ctx,
2156 conn,
2157 fname,
2158 ucf_flags,
2159 NULL,
2160 NULL,
2161 &smb_fname);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2164 reply_botherror(req,
2165 NT_STATUS_PATH_NOT_COVERED,
2166 ERRSRV, ERRbadpath);
2167 goto out;
2169 reply_nterror(req, status);
2170 goto out;
2173 status = SMB_VFS_CREATE_FILE(
2174 conn, /* conn */
2175 req, /* req */
2176 0, /* root_dir_fid */
2177 smb_fname, /* fname */
2178 access_mask, /* access_mask */
2179 share_mode, /* share_access */
2180 create_disposition, /* create_disposition*/
2181 create_options, /* create_options */
2182 dos_attr, /* file_attributes */
2183 oplock_request, /* oplock_request */
2184 NULL, /* lease */
2185 0, /* allocation_size */
2186 private_flags,
2187 NULL, /* sd */
2188 NULL, /* ea_list */
2189 &fsp, /* result */
2190 &info, /* pinfo */
2191 NULL, NULL); /* create context */
2193 if (!NT_STATUS_IS_OK(status)) {
2194 if (open_was_deferred(req->xconn, req->mid)) {
2195 /* We have re-scheduled this call. */
2196 goto out;
2198 reply_openerror(req, status);
2199 goto out;
2202 /* Ensure we're pointing at the correct stat struct. */
2203 TALLOC_FREE(smb_fname);
2204 smb_fname = fsp->fsp_name;
2206 size = smb_fname->st.st_ex_size;
2207 fattr = dos_mode(conn, smb_fname);
2209 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2211 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2212 DEBUG(3,("attempt to open a directory %s\n",
2213 fsp_str_dbg(fsp)));
2214 close_file(req, fsp, ERROR_CLOSE);
2215 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2216 ERRDOS, ERRnoaccess);
2217 goto out;
2220 reply_outbuf(req, 7, 0);
2221 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2222 SSVAL(req->outbuf,smb_vwv1,fattr);
2223 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2224 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2225 } else {
2226 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2228 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2229 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2231 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2232 SCVAL(req->outbuf,smb_flg,
2233 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2236 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2237 SCVAL(req->outbuf,smb_flg,
2238 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2240 out:
2241 END_PROFILE(SMBopen);
2242 return;
2245 /****************************************************************************
2246 Reply to an open and X.
2247 ****************************************************************************/
2249 void reply_open_and_X(struct smb_request *req)
2251 connection_struct *conn = req->conn;
2252 struct smb_filename *smb_fname = NULL;
2253 char *fname = NULL;
2254 uint16_t open_flags;
2255 int deny_mode;
2256 uint32_t smb_attr;
2257 /* Breakout the oplock request bits so we can set the
2258 reply bits separately. */
2259 int ex_oplock_request;
2260 int core_oplock_request;
2261 int oplock_request;
2262 #if 0
2263 int smb_sattr = SVAL(req->vwv+4, 0);
2264 uint32_t smb_time = make_unix_date3(req->vwv+6);
2265 #endif
2266 int smb_ofun;
2267 uint32_t fattr=0;
2268 int mtime=0;
2269 int smb_action = 0;
2270 files_struct *fsp;
2271 NTSTATUS status;
2272 uint64_t allocation_size;
2273 ssize_t retval = -1;
2274 uint32_t access_mask;
2275 uint32_t share_mode;
2276 uint32_t create_disposition;
2277 uint32_t create_options = 0;
2278 uint32_t private_flags = 0;
2279 uint32_t ucf_flags;
2280 TALLOC_CTX *ctx = talloc_tos();
2282 START_PROFILE(SMBopenX);
2284 if (req->wct < 15) {
2285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2286 goto out;
2289 open_flags = SVAL(req->vwv+2, 0);
2290 deny_mode = SVAL(req->vwv+3, 0);
2291 smb_attr = SVAL(req->vwv+5, 0);
2292 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2293 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2294 oplock_request = ex_oplock_request | core_oplock_request;
2295 smb_ofun = SVAL(req->vwv+8, 0);
2296 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2298 /* If it's an IPC, pass off the pipe handler. */
2299 if (IS_IPC(conn)) {
2300 if (lp_nt_pipe_support()) {
2301 reply_open_pipe_and_X(conn, req);
2302 } else {
2303 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2305 goto out;
2308 /* XXXX we need to handle passed times, sattr and flags */
2309 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2310 STR_TERMINATE, &status);
2311 if (!NT_STATUS_IS_OK(status)) {
2312 reply_nterror(req, status);
2313 goto out;
2316 if (!map_open_params_to_ntcreate(fname, deny_mode,
2317 smb_ofun,
2318 &access_mask, &share_mode,
2319 &create_disposition,
2320 &create_options,
2321 &private_flags)) {
2322 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2323 goto out;
2326 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2328 status = filename_convert(ctx,
2329 conn,
2330 fname,
2331 ucf_flags,
2332 NULL,
2333 NULL,
2334 &smb_fname);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2337 reply_botherror(req,
2338 NT_STATUS_PATH_NOT_COVERED,
2339 ERRSRV, ERRbadpath);
2340 goto out;
2342 reply_nterror(req, status);
2343 goto out;
2346 status = SMB_VFS_CREATE_FILE(
2347 conn, /* conn */
2348 req, /* req */
2349 0, /* root_dir_fid */
2350 smb_fname, /* fname */
2351 access_mask, /* access_mask */
2352 share_mode, /* share_access */
2353 create_disposition, /* create_disposition*/
2354 create_options, /* create_options */
2355 smb_attr, /* file_attributes */
2356 oplock_request, /* oplock_request */
2357 NULL, /* lease */
2358 0, /* allocation_size */
2359 private_flags,
2360 NULL, /* sd */
2361 NULL, /* ea_list */
2362 &fsp, /* result */
2363 &smb_action, /* pinfo */
2364 NULL, NULL); /* create context */
2366 if (!NT_STATUS_IS_OK(status)) {
2367 if (open_was_deferred(req->xconn, req->mid)) {
2368 /* We have re-scheduled this call. */
2369 goto out;
2371 reply_openerror(req, status);
2372 goto out;
2375 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2376 if the file is truncated or created. */
2377 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2378 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2379 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2380 close_file(req, fsp, ERROR_CLOSE);
2381 reply_nterror(req, NT_STATUS_DISK_FULL);
2382 goto out;
2384 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2385 if (retval < 0) {
2386 close_file(req, fsp, ERROR_CLOSE);
2387 reply_nterror(req, NT_STATUS_DISK_FULL);
2388 goto out;
2390 status = vfs_stat_fsp(fsp);
2391 if (!NT_STATUS_IS_OK(status)) {
2392 close_file(req, fsp, ERROR_CLOSE);
2393 reply_nterror(req, status);
2394 goto out;
2398 fattr = dos_mode(conn, fsp->fsp_name);
2399 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2400 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2401 close_file(req, fsp, ERROR_CLOSE);
2402 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2403 goto out;
2406 /* If the caller set the extended oplock request bit
2407 and we granted one (by whatever means) - set the
2408 correct bit for extended oplock reply.
2411 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2412 smb_action |= EXTENDED_OPLOCK_GRANTED;
2415 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2416 smb_action |= EXTENDED_OPLOCK_GRANTED;
2419 /* If the caller set the core oplock request bit
2420 and we granted one (by whatever means) - set the
2421 correct bit for core oplock reply.
2424 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2425 reply_outbuf(req, 19, 0);
2426 } else {
2427 reply_outbuf(req, 15, 0);
2430 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2431 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2433 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2434 SCVAL(req->outbuf, smb_flg,
2435 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2438 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2439 SCVAL(req->outbuf, smb_flg,
2440 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2443 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2444 SSVAL(req->outbuf,smb_vwv3,fattr);
2445 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2446 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2447 } else {
2448 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2450 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2451 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2452 SSVAL(req->outbuf,smb_vwv11,smb_action);
2454 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2455 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2458 out:
2459 TALLOC_FREE(smb_fname);
2460 END_PROFILE(SMBopenX);
2461 return;
2464 /****************************************************************************
2465 Reply to a SMBulogoffX.
2466 ****************************************************************************/
2468 void reply_ulogoffX(struct smb_request *req)
2470 struct smbd_server_connection *sconn = req->sconn;
2471 struct user_struct *vuser;
2472 struct smbXsrv_session *session = NULL;
2473 NTSTATUS status;
2475 START_PROFILE(SMBulogoffX);
2477 vuser = get_valid_user_struct(sconn, req->vuid);
2479 if(vuser == NULL) {
2480 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2481 (unsigned long long)req->vuid));
2483 req->vuid = UID_FIELD_INVALID;
2484 reply_force_doserror(req, ERRSRV, ERRbaduid);
2485 END_PROFILE(SMBulogoffX);
2486 return;
2489 session = vuser->session;
2490 vuser = NULL;
2493 * TODO: cancel all outstanding requests on the session
2495 status = smbXsrv_session_logoff(session);
2496 if (!NT_STATUS_IS_OK(status)) {
2497 DEBUG(0, ("reply_ulogoff: "
2498 "smbXsrv_session_logoff() failed: %s\n",
2499 nt_errstr(status)));
2501 * If we hit this case, there is something completely
2502 * wrong, so we better disconnect the transport connection.
2504 END_PROFILE(SMBulogoffX);
2505 exit_server(__location__ ": smbXsrv_session_logoff failed");
2506 return;
2509 TALLOC_FREE(session);
2511 reply_outbuf(req, 2, 0);
2512 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2513 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2515 DEBUG(3, ("ulogoffX vuid=%llu\n",
2516 (unsigned long long)req->vuid));
2518 END_PROFILE(SMBulogoffX);
2519 req->vuid = UID_FIELD_INVALID;
2522 /****************************************************************************
2523 Reply to a mknew or a create.
2524 ****************************************************************************/
2526 void reply_mknew(struct smb_request *req)
2528 connection_struct *conn = req->conn;
2529 struct smb_filename *smb_fname = NULL;
2530 char *fname = NULL;
2531 uint32_t fattr = 0;
2532 struct smb_file_time ft;
2533 files_struct *fsp;
2534 int oplock_request = 0;
2535 NTSTATUS status;
2536 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2537 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2538 uint32_t create_disposition;
2539 uint32_t create_options = 0;
2540 uint32_t ucf_flags;
2541 TALLOC_CTX *ctx = talloc_tos();
2543 START_PROFILE(SMBcreate);
2544 ZERO_STRUCT(ft);
2546 if (req->wct < 3) {
2547 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2548 goto out;
2551 fattr = SVAL(req->vwv+0, 0);
2552 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2554 if (req->cmd == SMBmknew) {
2555 /* We should fail if file exists. */
2556 create_disposition = FILE_CREATE;
2557 } else {
2558 /* Create if file doesn't exist, truncate if it does. */
2559 create_disposition = FILE_OVERWRITE_IF;
2562 /* mtime. */
2563 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2565 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2566 STR_TERMINATE, &status);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 reply_nterror(req, status);
2569 goto out;
2572 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2573 status = filename_convert(ctx,
2574 conn,
2575 fname,
2576 ucf_flags,
2577 NULL,
2578 NULL,
2579 &smb_fname);
2580 if (!NT_STATUS_IS_OK(status)) {
2581 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2582 reply_botherror(req,
2583 NT_STATUS_PATH_NOT_COVERED,
2584 ERRSRV, ERRbadpath);
2585 goto out;
2587 reply_nterror(req, status);
2588 goto out;
2591 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2592 DEBUG(0,("Attempt to create file (%s) with volid set - "
2593 "please report this\n",
2594 smb_fname_str_dbg(smb_fname)));
2597 status = SMB_VFS_CREATE_FILE(
2598 conn, /* conn */
2599 req, /* req */
2600 0, /* root_dir_fid */
2601 smb_fname, /* fname */
2602 access_mask, /* access_mask */
2603 share_mode, /* share_access */
2604 create_disposition, /* create_disposition*/
2605 create_options, /* create_options */
2606 fattr, /* file_attributes */
2607 oplock_request, /* oplock_request */
2608 NULL, /* lease */
2609 0, /* allocation_size */
2610 0, /* private_flags */
2611 NULL, /* sd */
2612 NULL, /* ea_list */
2613 &fsp, /* result */
2614 NULL, /* pinfo */
2615 NULL, NULL); /* create context */
2617 if (!NT_STATUS_IS_OK(status)) {
2618 if (open_was_deferred(req->xconn, req->mid)) {
2619 /* We have re-scheduled this call. */
2620 goto out;
2622 reply_openerror(req, status);
2623 goto out;
2626 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2627 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2628 if (!NT_STATUS_IS_OK(status)) {
2629 END_PROFILE(SMBcreate);
2630 goto out;
2633 reply_outbuf(req, 1, 0);
2634 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2636 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2637 SCVAL(req->outbuf,smb_flg,
2638 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2641 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2642 SCVAL(req->outbuf,smb_flg,
2643 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2646 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2647 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2648 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2649 (unsigned int)fattr));
2651 out:
2652 TALLOC_FREE(smb_fname);
2653 END_PROFILE(SMBcreate);
2654 return;
2657 /****************************************************************************
2658 Reply to a create temporary file.
2659 ****************************************************************************/
2661 void reply_ctemp(struct smb_request *req)
2663 connection_struct *conn = req->conn;
2664 struct smb_filename *smb_fname = NULL;
2665 char *wire_name = NULL;
2666 char *fname = NULL;
2667 uint32_t fattr;
2668 files_struct *fsp;
2669 int oplock_request;
2670 char *s;
2671 NTSTATUS status;
2672 int i;
2673 uint32_t ucf_flags;
2674 TALLOC_CTX *ctx = talloc_tos();
2676 START_PROFILE(SMBctemp);
2678 if (req->wct < 3) {
2679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2680 goto out;
2683 fattr = SVAL(req->vwv+0, 0);
2684 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2686 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2687 STR_TERMINATE, &status);
2688 if (!NT_STATUS_IS_OK(status)) {
2689 reply_nterror(req, status);
2690 goto out;
2693 for (i = 0; i < 10; i++) {
2694 if (*wire_name) {
2695 fname = talloc_asprintf(ctx,
2696 "%s/TMP%s",
2697 wire_name,
2698 generate_random_str_list(ctx, 5, "0123456789"));
2699 } else {
2700 fname = talloc_asprintf(ctx,
2701 "TMP%s",
2702 generate_random_str_list(ctx, 5, "0123456789"));
2705 if (!fname) {
2706 reply_nterror(req, NT_STATUS_NO_MEMORY);
2707 goto out;
2710 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2711 status = filename_convert(ctx, conn,
2712 fname,
2713 ucf_flags,
2714 NULL,
2715 NULL,
2716 &smb_fname);
2717 if (!NT_STATUS_IS_OK(status)) {
2718 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2719 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2720 ERRSRV, ERRbadpath);
2721 goto out;
2723 reply_nterror(req, status);
2724 goto out;
2727 /* Create the file. */
2728 status = SMB_VFS_CREATE_FILE(
2729 conn, /* conn */
2730 req, /* req */
2731 0, /* root_dir_fid */
2732 smb_fname, /* fname */
2733 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2734 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2735 FILE_CREATE, /* create_disposition*/
2736 0, /* create_options */
2737 fattr, /* file_attributes */
2738 oplock_request, /* oplock_request */
2739 NULL, /* lease */
2740 0, /* allocation_size */
2741 0, /* private_flags */
2742 NULL, /* sd */
2743 NULL, /* ea_list */
2744 &fsp, /* result */
2745 NULL, /* pinfo */
2746 NULL, NULL); /* create context */
2748 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2749 TALLOC_FREE(fname);
2750 TALLOC_FREE(smb_fname);
2751 continue;
2754 if (!NT_STATUS_IS_OK(status)) {
2755 if (open_was_deferred(req->xconn, req->mid)) {
2756 /* We have re-scheduled this call. */
2757 goto out;
2759 reply_openerror(req, status);
2760 goto out;
2763 break;
2766 if (i == 10) {
2767 /* Collision after 10 times... */
2768 reply_nterror(req, status);
2769 goto out;
2772 reply_outbuf(req, 1, 0);
2773 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2775 /* the returned filename is relative to the directory */
2776 s = strrchr_m(fsp->fsp_name->base_name, '/');
2777 if (!s) {
2778 s = fsp->fsp_name->base_name;
2779 } else {
2780 s++;
2783 #if 0
2784 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2785 thing in the byte section. JRA */
2786 SSVALS(p, 0, -1); /* what is this? not in spec */
2787 #endif
2788 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2789 == -1) {
2790 reply_nterror(req, NT_STATUS_NO_MEMORY);
2791 goto out;
2794 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2795 SCVAL(req->outbuf, smb_flg,
2796 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2799 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2800 SCVAL(req->outbuf, smb_flg,
2801 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2804 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2805 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2806 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2807 out:
2808 TALLOC_FREE(smb_fname);
2809 TALLOC_FREE(wire_name);
2810 END_PROFILE(SMBctemp);
2811 return;
2814 /*******************************************************************
2815 Check if a user is allowed to rename a file.
2816 ********************************************************************/
2818 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2819 uint16_t dirtype)
2821 if (!CAN_WRITE(conn)) {
2822 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2825 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2826 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2827 /* Only bother to read the DOS attribute if we might deny the
2828 rename on the grounds of attribute mismatch. */
2829 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2830 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2831 return NT_STATUS_NO_SUCH_FILE;
2835 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2836 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2837 return NT_STATUS_OK;
2840 /* If no pathnames are open below this
2841 directory, allow the rename. */
2843 if (lp_strict_rename(SNUM(conn))) {
2845 * Strict rename, check open file db.
2847 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2848 return NT_STATUS_ACCESS_DENIED;
2850 } else if (file_find_subpath(fsp)) {
2852 * No strict rename, just look in local process.
2854 return NT_STATUS_ACCESS_DENIED;
2856 return NT_STATUS_OK;
2859 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2860 return NT_STATUS_OK;
2863 return NT_STATUS_ACCESS_DENIED;
2866 /*******************************************************************
2867 * unlink a file with all relevant access checks
2868 *******************************************************************/
2870 static NTSTATUS do_unlink(connection_struct *conn,
2871 struct smb_request *req,
2872 struct smb_filename *smb_fname,
2873 uint32_t dirtype)
2875 uint32_t fattr;
2876 files_struct *fsp;
2877 uint32_t dirtype_orig = dirtype;
2878 NTSTATUS status;
2879 int ret;
2880 bool posix_paths = (req != NULL && req->posix_pathnames);
2882 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2883 smb_fname_str_dbg(smb_fname),
2884 dirtype));
2886 if (!CAN_WRITE(conn)) {
2887 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2890 if (posix_paths) {
2891 ret = SMB_VFS_LSTAT(conn, smb_fname);
2892 } else {
2893 ret = SMB_VFS_STAT(conn, smb_fname);
2895 if (ret != 0) {
2896 return map_nt_error_from_unix(errno);
2899 fattr = dos_mode(conn, smb_fname);
2901 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2902 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2905 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2906 if (!dirtype) {
2907 return NT_STATUS_NO_SUCH_FILE;
2910 if (!dir_check_ftype(fattr, dirtype)) {
2911 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2912 return NT_STATUS_FILE_IS_A_DIRECTORY;
2914 return NT_STATUS_NO_SUCH_FILE;
2917 if (dirtype_orig & 0x8000) {
2918 /* These will never be set for POSIX. */
2919 return NT_STATUS_NO_SUCH_FILE;
2922 #if 0
2923 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2924 return NT_STATUS_FILE_IS_A_DIRECTORY;
2927 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2928 return NT_STATUS_NO_SUCH_FILE;
2931 if (dirtype & 0xFF00) {
2932 /* These will never be set for POSIX. */
2933 return NT_STATUS_NO_SUCH_FILE;
2936 dirtype &= 0xFF;
2937 if (!dirtype) {
2938 return NT_STATUS_NO_SUCH_FILE;
2941 /* Can't delete a directory. */
2942 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2943 return NT_STATUS_FILE_IS_A_DIRECTORY;
2945 #endif
2947 #if 0 /* JRATEST */
2948 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2949 return NT_STATUS_OBJECT_NAME_INVALID;
2950 #endif /* JRATEST */
2952 /* On open checks the open itself will check the share mode, so
2953 don't do it here as we'll get it wrong. */
2955 status = SMB_VFS_CREATE_FILE
2956 (conn, /* conn */
2957 req, /* req */
2958 0, /* root_dir_fid */
2959 smb_fname, /* fname */
2960 DELETE_ACCESS, /* access_mask */
2961 FILE_SHARE_NONE, /* share_access */
2962 FILE_OPEN, /* create_disposition*/
2963 FILE_NON_DIRECTORY_FILE, /* create_options */
2964 /* file_attributes */
2965 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2966 FILE_ATTRIBUTE_NORMAL,
2967 0, /* oplock_request */
2968 NULL, /* lease */
2969 0, /* allocation_size */
2970 0, /* private_flags */
2971 NULL, /* sd */
2972 NULL, /* ea_list */
2973 &fsp, /* result */
2974 NULL, /* pinfo */
2975 NULL, NULL); /* create context */
2977 if (!NT_STATUS_IS_OK(status)) {
2978 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2979 nt_errstr(status)));
2980 return status;
2983 status = can_set_delete_on_close(fsp, fattr);
2984 if (!NT_STATUS_IS_OK(status)) {
2985 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2986 "(%s)\n",
2987 smb_fname_str_dbg(smb_fname),
2988 nt_errstr(status)));
2989 close_file(req, fsp, NORMAL_CLOSE);
2990 return status;
2993 /* The set is across all open files on this dev/inode pair. */
2994 if (!set_delete_on_close(fsp, True,
2995 conn->session_info->security_token,
2996 conn->session_info->unix_token)) {
2997 close_file(req, fsp, NORMAL_CLOSE);
2998 return NT_STATUS_ACCESS_DENIED;
3001 return close_file(req, fsp, NORMAL_CLOSE);
3004 /****************************************************************************
3005 The guts of the unlink command, split out so it may be called by the NT SMB
3006 code.
3007 ****************************************************************************/
3009 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
3010 uint32_t dirtype, struct smb_filename *smb_fname,
3011 bool has_wild)
3013 char *fname_dir = NULL;
3014 char *fname_mask = NULL;
3015 int count=0;
3016 NTSTATUS status = NT_STATUS_OK;
3017 struct smb_filename *smb_fname_dir = NULL;
3018 TALLOC_CTX *ctx = talloc_tos();
3020 /* Split up the directory from the filename/mask. */
3021 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3022 &fname_dir, &fname_mask);
3023 if (!NT_STATUS_IS_OK(status)) {
3024 goto out;
3028 * We should only check the mangled cache
3029 * here if unix_convert failed. This means
3030 * that the path in 'mask' doesn't exist
3031 * on the file system and so we need to look
3032 * for a possible mangle. This patch from
3033 * Tine Smukavec <valentin.smukavec@hermes.si>.
3036 if (!VALID_STAT(smb_fname->st) &&
3037 mangle_is_mangled(fname_mask, conn->params)) {
3038 char *new_mask = NULL;
3039 mangle_lookup_name_from_8_3(ctx, fname_mask,
3040 &new_mask, conn->params);
3041 if (new_mask) {
3042 TALLOC_FREE(fname_mask);
3043 fname_mask = new_mask;
3047 if (!has_wild) {
3050 * Only one file needs to be unlinked. Append the mask back
3051 * onto the directory.
3053 TALLOC_FREE(smb_fname->base_name);
3054 if (ISDOT(fname_dir)) {
3055 /* Ensure we use canonical names on open. */
3056 smb_fname->base_name = talloc_asprintf(smb_fname,
3057 "%s",
3058 fname_mask);
3059 } else {
3060 smb_fname->base_name = talloc_asprintf(smb_fname,
3061 "%s/%s",
3062 fname_dir,
3063 fname_mask);
3065 if (!smb_fname->base_name) {
3066 status = NT_STATUS_NO_MEMORY;
3067 goto out;
3069 if (dirtype == 0) {
3070 dirtype = FILE_ATTRIBUTE_NORMAL;
3073 status = check_name(conn, smb_fname);
3074 if (!NT_STATUS_IS_OK(status)) {
3075 goto out;
3078 status = do_unlink(conn, req, smb_fname, dirtype);
3079 if (!NT_STATUS_IS_OK(status)) {
3080 goto out;
3083 count++;
3084 } else {
3085 struct smb_Dir *dir_hnd = NULL;
3086 long offset = 0;
3087 const char *dname = NULL;
3088 char *talloced = NULL;
3090 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3091 status = NT_STATUS_OBJECT_NAME_INVALID;
3092 goto out;
3094 if (dirtype == 0) {
3095 dirtype = FILE_ATTRIBUTE_NORMAL;
3098 if (strequal(fname_mask,"????????.???")) {
3099 TALLOC_FREE(fname_mask);
3100 fname_mask = talloc_strdup(ctx, "*");
3101 if (!fname_mask) {
3102 status = NT_STATUS_NO_MEMORY;
3103 goto out;
3107 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3108 fname_dir,
3109 NULL,
3110 NULL,
3111 smb_fname->flags);
3112 if (smb_fname_dir == NULL) {
3113 status = NT_STATUS_NO_MEMORY;
3114 goto out;
3117 status = check_name(conn, smb_fname_dir);
3118 if (!NT_STATUS_IS_OK(status)) {
3119 goto out;
3122 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3123 dirtype);
3124 if (dir_hnd == NULL) {
3125 status = map_nt_error_from_unix(errno);
3126 goto out;
3129 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3130 the pattern matches against the long name, otherwise the short name
3131 We don't implement this yet XXXX
3134 status = NT_STATUS_NO_SUCH_FILE;
3136 while ((dname = ReadDirName(dir_hnd, &offset,
3137 &smb_fname->st, &talloced))) {
3138 TALLOC_CTX *frame = talloc_stackframe();
3140 if (!is_visible_file(conn, fname_dir, dname,
3141 &smb_fname->st, true)) {
3142 TALLOC_FREE(frame);
3143 TALLOC_FREE(talloced);
3144 continue;
3147 /* Quick check for "." and ".." */
3148 if (ISDOT(dname) || ISDOTDOT(dname)) {
3149 TALLOC_FREE(frame);
3150 TALLOC_FREE(talloced);
3151 continue;
3154 if(!mask_match(dname, fname_mask,
3155 conn->case_sensitive)) {
3156 TALLOC_FREE(frame);
3157 TALLOC_FREE(talloced);
3158 continue;
3161 TALLOC_FREE(smb_fname->base_name);
3162 if (ISDOT(fname_dir)) {
3163 /* Ensure we use canonical names on open. */
3164 smb_fname->base_name =
3165 talloc_asprintf(smb_fname, "%s",
3166 dname);
3167 } else {
3168 smb_fname->base_name =
3169 talloc_asprintf(smb_fname, "%s/%s",
3170 fname_dir, dname);
3173 if (!smb_fname->base_name) {
3174 TALLOC_FREE(dir_hnd);
3175 status = NT_STATUS_NO_MEMORY;
3176 TALLOC_FREE(frame);
3177 TALLOC_FREE(talloced);
3178 goto out;
3181 status = check_name(conn, smb_fname);
3182 if (!NT_STATUS_IS_OK(status)) {
3183 TALLOC_FREE(dir_hnd);
3184 TALLOC_FREE(frame);
3185 TALLOC_FREE(talloced);
3186 goto out;
3189 status = do_unlink(conn, req, smb_fname, dirtype);
3190 if (!NT_STATUS_IS_OK(status)) {
3191 TALLOC_FREE(dir_hnd);
3192 TALLOC_FREE(frame);
3193 TALLOC_FREE(talloced);
3194 goto out;
3197 count++;
3198 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3199 smb_fname->base_name));
3201 TALLOC_FREE(frame);
3202 TALLOC_FREE(talloced);
3204 TALLOC_FREE(dir_hnd);
3207 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3208 status = map_nt_error_from_unix(errno);
3211 out:
3212 TALLOC_FREE(smb_fname_dir);
3213 TALLOC_FREE(fname_dir);
3214 TALLOC_FREE(fname_mask);
3215 return status;
3218 /****************************************************************************
3219 Reply to a unlink
3220 ****************************************************************************/
3222 void reply_unlink(struct smb_request *req)
3224 connection_struct *conn = req->conn;
3225 char *name = NULL;
3226 struct smb_filename *smb_fname = NULL;
3227 uint32_t dirtype;
3228 NTSTATUS status;
3229 bool path_contains_wcard = False;
3230 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3231 ucf_flags_from_smb_request(req);
3232 TALLOC_CTX *ctx = talloc_tos();
3234 START_PROFILE(SMBunlink);
3236 if (req->wct < 1) {
3237 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3238 goto out;
3241 dirtype = SVAL(req->vwv+0, 0);
3243 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3244 STR_TERMINATE, &status,
3245 &path_contains_wcard);
3246 if (!NT_STATUS_IS_OK(status)) {
3247 reply_nterror(req, status);
3248 goto out;
3251 status = filename_convert(ctx, conn,
3252 name,
3253 ucf_flags,
3254 NULL,
3255 &path_contains_wcard,
3256 &smb_fname);
3257 if (!NT_STATUS_IS_OK(status)) {
3258 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3259 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3260 ERRSRV, ERRbadpath);
3261 goto out;
3263 reply_nterror(req, status);
3264 goto out;
3267 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3269 status = unlink_internals(conn, req, dirtype, smb_fname,
3270 path_contains_wcard);
3271 if (!NT_STATUS_IS_OK(status)) {
3272 if (open_was_deferred(req->xconn, req->mid)) {
3273 /* We have re-scheduled this call. */
3274 goto out;
3276 reply_nterror(req, status);
3277 goto out;
3280 reply_outbuf(req, 0, 0);
3281 out:
3282 TALLOC_FREE(smb_fname);
3283 END_PROFILE(SMBunlink);
3284 return;
3287 /****************************************************************************
3288 Fail for readbraw.
3289 ****************************************************************************/
3291 static void fail_readraw(void)
3293 const char *errstr = talloc_asprintf(talloc_tos(),
3294 "FAIL ! reply_readbraw: socket write fail (%s)",
3295 strerror(errno));
3296 if (!errstr) {
3297 errstr = "";
3299 exit_server_cleanly(errstr);
3302 /****************************************************************************
3303 Fake (read/write) sendfile. Returns -1 on read or write fail.
3304 ****************************************************************************/
3306 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3307 off_t startpos, size_t nread)
3309 size_t bufsize;
3310 size_t tosend = nread;
3311 char *buf;
3313 if (nread == 0) {
3314 return 0;
3317 bufsize = MIN(nread, 65536);
3319 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3320 return -1;
3323 while (tosend > 0) {
3324 ssize_t ret;
3325 size_t cur_read;
3327 cur_read = MIN(tosend, bufsize);
3328 ret = read_file(fsp,buf,startpos,cur_read);
3329 if (ret == -1) {
3330 SAFE_FREE(buf);
3331 return -1;
3334 /* If we had a short read, fill with zeros. */
3335 if (ret < cur_read) {
3336 memset(buf + ret, '\0', cur_read - ret);
3339 ret = write_data(xconn->transport.sock, buf, cur_read);
3340 if (ret != cur_read) {
3341 int saved_errno = errno;
3343 * Try and give an error message saying what
3344 * client failed.
3346 DEBUG(0, ("write_data failed for client %s. "
3347 "Error %s\n",
3348 smbXsrv_connection_dbg(xconn),
3349 strerror(saved_errno)));
3350 SAFE_FREE(buf);
3351 errno = saved_errno;
3352 return -1;
3354 tosend -= cur_read;
3355 startpos += cur_read;
3358 SAFE_FREE(buf);
3359 return (ssize_t)nread;
3362 /****************************************************************************
3363 Deal with the case of sendfile reading less bytes from the file than
3364 requested. Fill with zeros (all we can do). Returns 0 on success
3365 ****************************************************************************/
3367 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3368 files_struct *fsp,
3369 ssize_t nread,
3370 size_t headersize,
3371 size_t smb_maxcnt)
3373 #define SHORT_SEND_BUFSIZE 1024
3374 if (nread < headersize) {
3375 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3376 "header for file %s (%s). Terminating\n",
3377 fsp_str_dbg(fsp), strerror(errno)));
3378 return -1;
3381 nread -= headersize;
3383 if (nread < smb_maxcnt) {
3384 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3385 if (!buf) {
3386 DEBUG(0,("sendfile_short_send: malloc failed "
3387 "for file %s (%s). Terminating\n",
3388 fsp_str_dbg(fsp), strerror(errno)));
3389 return -1;
3392 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3393 "with zeros !\n", fsp_str_dbg(fsp)));
3395 while (nread < smb_maxcnt) {
3397 * We asked for the real file size and told sendfile
3398 * to not go beyond the end of the file. But it can
3399 * happen that in between our fstat call and the
3400 * sendfile call the file was truncated. This is very
3401 * bad because we have already announced the larger
3402 * number of bytes to the client.
3404 * The best we can do now is to send 0-bytes, just as
3405 * a read from a hole in a sparse file would do.
3407 * This should happen rarely enough that I don't care
3408 * about efficiency here :-)
3410 size_t to_write;
3411 ssize_t ret;
3413 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3414 ret = write_data(xconn->transport.sock, buf, to_write);
3415 if (ret != to_write) {
3416 int saved_errno = errno;
3418 * Try and give an error message saying what
3419 * client failed.
3421 DEBUG(0, ("write_data failed for client %s. "
3422 "Error %s\n",
3423 smbXsrv_connection_dbg(xconn),
3424 strerror(saved_errno)));
3425 errno = saved_errno;
3426 return -1;
3428 nread += to_write;
3430 SAFE_FREE(buf);
3433 return 0;
3436 /****************************************************************************
3437 Return a readbraw error (4 bytes of zero).
3438 ****************************************************************************/
3440 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3442 char header[4];
3444 SIVAL(header,0,0);
3446 smbd_lock_socket(xconn);
3447 if (write_data(xconn->transport.sock,header,4) != 4) {
3448 int saved_errno = errno;
3450 * Try and give an error message saying what
3451 * client failed.
3453 DEBUG(0, ("write_data failed for client %s. "
3454 "Error %s\n",
3455 smbXsrv_connection_dbg(xconn),
3456 strerror(saved_errno)));
3457 errno = saved_errno;
3459 fail_readraw();
3461 smbd_unlock_socket(xconn);
3464 /****************************************************************************
3465 Use sendfile in readbraw.
3466 ****************************************************************************/
3468 static void send_file_readbraw(connection_struct *conn,
3469 struct smb_request *req,
3470 files_struct *fsp,
3471 off_t startpos,
3472 size_t nread,
3473 ssize_t mincount)
3475 struct smbXsrv_connection *xconn = req->xconn;
3476 char *outbuf = NULL;
3477 ssize_t ret=0;
3480 * We can only use sendfile on a non-chained packet
3481 * but we can use on a non-oplocked file. tridge proved this
3482 * on a train in Germany :-). JRA.
3483 * reply_readbraw has already checked the length.
3486 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3487 (fsp->wcp == NULL) &&
3488 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3489 ssize_t sendfile_read = -1;
3490 char header[4];
3491 DATA_BLOB header_blob;
3493 _smb_setlen(header,nread);
3494 header_blob = data_blob_const(header, 4);
3496 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3497 &header_blob, startpos,
3498 nread);
3499 if (sendfile_read == -1) {
3500 /* Returning ENOSYS means no data at all was sent.
3501 * Do this as a normal read. */
3502 if (errno == ENOSYS) {
3503 goto normal_readbraw;
3507 * Special hack for broken Linux with no working sendfile. If we
3508 * return EINTR we sent the header but not the rest of the data.
3509 * Fake this up by doing read/write calls.
3511 if (errno == EINTR) {
3512 /* Ensure we don't do this again. */
3513 set_use_sendfile(SNUM(conn), False);
3514 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3516 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3517 DEBUG(0,("send_file_readbraw: "
3518 "fake_sendfile failed for "
3519 "file %s (%s).\n",
3520 fsp_str_dbg(fsp),
3521 strerror(errno)));
3522 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3524 return;
3527 DEBUG(0,("send_file_readbraw: sendfile failed for "
3528 "file %s (%s). Terminating\n",
3529 fsp_str_dbg(fsp), strerror(errno)));
3530 exit_server_cleanly("send_file_readbraw sendfile failed");
3531 } else if (sendfile_read == 0) {
3533 * Some sendfile implementations return 0 to indicate
3534 * that there was a short read, but nothing was
3535 * actually written to the socket. In this case,
3536 * fallback to the normal read path so the header gets
3537 * the correct byte count.
3539 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3540 "bytes falling back to the normal read: "
3541 "%s\n", fsp_str_dbg(fsp)));
3542 goto normal_readbraw;
3545 /* Deal with possible short send. */
3546 if (sendfile_read != 4+nread) {
3547 ret = sendfile_short_send(xconn, fsp,
3548 sendfile_read, 4, nread);
3549 if (ret == -1) {
3550 fail_readraw();
3553 return;
3556 normal_readbraw:
3558 outbuf = talloc_array(NULL, char, nread+4);
3559 if (!outbuf) {
3560 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3561 (unsigned)(nread+4)));
3562 reply_readbraw_error(xconn);
3563 return;
3566 if (nread > 0) {
3567 ret = read_file(fsp,outbuf+4,startpos,nread);
3568 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3569 if (ret < mincount)
3570 ret = 0;
3571 #else
3572 if (ret < nread)
3573 ret = 0;
3574 #endif
3577 _smb_setlen(outbuf,ret);
3578 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3579 int saved_errno = errno;
3581 * Try and give an error message saying what
3582 * client failed.
3584 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3585 smbXsrv_connection_dbg(xconn),
3586 strerror(saved_errno)));
3587 errno = saved_errno;
3589 fail_readraw();
3592 TALLOC_FREE(outbuf);
3595 /****************************************************************************
3596 Reply to a readbraw (core+ protocol).
3597 ****************************************************************************/
3599 void reply_readbraw(struct smb_request *req)
3601 connection_struct *conn = req->conn;
3602 struct smbXsrv_connection *xconn = req->xconn;
3603 ssize_t maxcount,mincount;
3604 size_t nread = 0;
3605 off_t startpos;
3606 files_struct *fsp;
3607 struct lock_struct lock;
3608 off_t size = 0;
3610 START_PROFILE(SMBreadbraw);
3612 if (srv_is_signing_active(xconn) || req->encrypted) {
3613 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3614 "raw reads/writes are disallowed.");
3617 if (req->wct < 8) {
3618 reply_readbraw_error(xconn);
3619 END_PROFILE(SMBreadbraw);
3620 return;
3623 if (xconn->smb1.echo_handler.trusted_fde) {
3624 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3625 "'async smb echo handler = yes'\n"));
3626 reply_readbraw_error(xconn);
3627 END_PROFILE(SMBreadbraw);
3628 return;
3632 * Special check if an oplock break has been issued
3633 * and the readraw request croses on the wire, we must
3634 * return a zero length response here.
3637 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3640 * We have to do a check_fsp by hand here, as
3641 * we must always return 4 zero bytes on error,
3642 * not a NTSTATUS.
3645 if (!fsp || !conn || conn != fsp->conn ||
3646 req->vuid != fsp->vuid ||
3647 fsp->is_directory || fsp->fh->fd == -1) {
3649 * fsp could be NULL here so use the value from the packet. JRA.
3651 DEBUG(3,("reply_readbraw: fnum %d not valid "
3652 "- cache prime?\n",
3653 (int)SVAL(req->vwv+0, 0)));
3654 reply_readbraw_error(xconn);
3655 END_PROFILE(SMBreadbraw);
3656 return;
3659 /* Do a "by hand" version of CHECK_READ. */
3660 if (!(fsp->can_read ||
3661 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3662 (fsp->access_mask & FILE_EXECUTE)))) {
3663 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3664 (int)SVAL(req->vwv+0, 0)));
3665 reply_readbraw_error(xconn);
3666 END_PROFILE(SMBreadbraw);
3667 return;
3670 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3672 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3673 if(req->wct == 10) {
3675 * This is a large offset (64 bit) read.
3678 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3680 if(startpos < 0) {
3681 DEBUG(0,("reply_readbraw: negative 64 bit "
3682 "readraw offset (%.0f) !\n",
3683 (double)startpos ));
3684 reply_readbraw_error(xconn);
3685 END_PROFILE(SMBreadbraw);
3686 return;
3690 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3691 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3693 /* ensure we don't overrun the packet size */
3694 maxcount = MIN(65535,maxcount);
3696 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3697 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3698 &lock);
3700 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3701 reply_readbraw_error(xconn);
3702 END_PROFILE(SMBreadbraw);
3703 return;
3706 if (fsp_stat(fsp) == 0) {
3707 size = fsp->fsp_name->st.st_ex_size;
3710 if (startpos >= size) {
3711 nread = 0;
3712 } else {
3713 nread = MIN(maxcount,(size - startpos));
3716 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3717 if (nread < mincount)
3718 nread = 0;
3719 #endif
3721 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3722 "min=%lu nread=%lu\n",
3723 fsp_fnum_dbg(fsp), (double)startpos,
3724 (unsigned long)maxcount,
3725 (unsigned long)mincount,
3726 (unsigned long)nread ) );
3728 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3730 DEBUG(5,("reply_readbraw finished\n"));
3732 END_PROFILE(SMBreadbraw);
3733 return;
3736 #undef DBGC_CLASS
3737 #define DBGC_CLASS DBGC_LOCKING
3739 /****************************************************************************
3740 Reply to a lockread (core+ protocol).
3741 ****************************************************************************/
3743 void reply_lockread(struct smb_request *req)
3745 connection_struct *conn = req->conn;
3746 ssize_t nread = -1;
3747 char *data;
3748 off_t startpos;
3749 size_t numtoread;
3750 size_t maxtoread;
3751 NTSTATUS status;
3752 files_struct *fsp;
3753 struct byte_range_lock *br_lck = NULL;
3754 char *p = NULL;
3755 struct smbXsrv_connection *xconn = req->xconn;
3757 START_PROFILE(SMBlockread);
3759 if (req->wct < 5) {
3760 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3761 END_PROFILE(SMBlockread);
3762 return;
3765 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3767 if (!check_fsp(conn, req, fsp)) {
3768 END_PROFILE(SMBlockread);
3769 return;
3772 if (!CHECK_READ(fsp,req)) {
3773 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3774 END_PROFILE(SMBlockread);
3775 return;
3778 numtoread = SVAL(req->vwv+1, 0);
3779 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3782 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3783 * protocol request that predates the read/write lock concept.
3784 * Thus instead of asking for a read lock here we need to ask
3785 * for a write lock. JRA.
3786 * Note that the requested lock size is unaffected by max_send.
3789 br_lck = do_lock(req->sconn->msg_ctx,
3790 fsp,
3791 (uint64_t)req->smbpid,
3792 (uint64_t)numtoread,
3793 (uint64_t)startpos,
3794 WRITE_LOCK,
3795 WINDOWS_LOCK,
3796 False, /* Non-blocking lock. */
3797 &status,
3798 NULL,
3799 NULL);
3800 TALLOC_FREE(br_lck);
3802 if (NT_STATUS_V(status)) {
3803 reply_nterror(req, status);
3804 END_PROFILE(SMBlockread);
3805 return;
3809 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3811 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3813 if (numtoread > maxtoread) {
3814 DBG_WARNING("requested read size (%zu) is greater than "
3815 "maximum allowed (%zu/%d). "
3816 "Returning short read of maximum allowed for "
3817 "compatibility with Windows 2000.\n",
3818 numtoread,
3819 maxtoread,
3820 xconn->smb1.sessions.max_send);
3821 numtoread = maxtoread;
3824 reply_outbuf(req, 5, numtoread + 3);
3826 data = smb_buf(req->outbuf) + 3;
3828 nread = read_file(fsp,data,startpos,numtoread);
3830 if (nread < 0) {
3831 reply_nterror(req, map_nt_error_from_unix(errno));
3832 END_PROFILE(SMBlockread);
3833 return;
3836 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3838 SSVAL(req->outbuf,smb_vwv0,nread);
3839 SSVAL(req->outbuf,smb_vwv5,nread+3);
3840 p = smb_buf(req->outbuf);
3841 SCVAL(p,0,0); /* pad byte. */
3842 SSVAL(p,1,nread);
3844 DEBUG(3,("lockread %s num=%d nread=%d\n",
3845 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3847 END_PROFILE(SMBlockread);
3848 return;
3851 #undef DBGC_CLASS
3852 #define DBGC_CLASS DBGC_ALL
3854 /****************************************************************************
3855 Reply to a read.
3856 ****************************************************************************/
3858 void reply_read(struct smb_request *req)
3860 connection_struct *conn = req->conn;
3861 size_t numtoread;
3862 size_t maxtoread;
3863 ssize_t nread = 0;
3864 char *data;
3865 off_t startpos;
3866 files_struct *fsp;
3867 struct lock_struct lock;
3868 struct smbXsrv_connection *xconn = req->xconn;
3870 START_PROFILE(SMBread);
3872 if (req->wct < 3) {
3873 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3874 END_PROFILE(SMBread);
3875 return;
3878 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3880 if (!check_fsp(conn, req, fsp)) {
3881 END_PROFILE(SMBread);
3882 return;
3885 if (!CHECK_READ(fsp,req)) {
3886 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3887 END_PROFILE(SMBread);
3888 return;
3891 numtoread = SVAL(req->vwv+1, 0);
3892 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3895 * The requested read size cannot be greater than max_send. JRA.
3897 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3899 if (numtoread > maxtoread) {
3900 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3901 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3902 (unsigned int)numtoread, (unsigned int)maxtoread,
3903 (unsigned int)xconn->smb1.sessions.max_send));
3904 numtoread = maxtoread;
3907 reply_outbuf(req, 5, numtoread+3);
3909 data = smb_buf(req->outbuf) + 3;
3911 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3912 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3913 &lock);
3915 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3916 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3917 END_PROFILE(SMBread);
3918 return;
3921 if (numtoread > 0)
3922 nread = read_file(fsp,data,startpos,numtoread);
3924 if (nread < 0) {
3925 reply_nterror(req, map_nt_error_from_unix(errno));
3926 goto out;
3929 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3931 SSVAL(req->outbuf,smb_vwv0,nread);
3932 SSVAL(req->outbuf,smb_vwv5,nread+3);
3933 SCVAL(smb_buf(req->outbuf),0,1);
3934 SSVAL(smb_buf(req->outbuf),1,nread);
3936 DEBUG(3, ("read %s num=%d nread=%d\n",
3937 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3939 out:
3940 END_PROFILE(SMBread);
3941 return;
3944 /****************************************************************************
3945 Setup readX header.
3946 ****************************************************************************/
3948 size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
3950 size_t outsize;
3952 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3953 False);
3955 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3957 SCVAL(outbuf,smb_vwv0,0xFF);
3958 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3959 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3960 SSVAL(outbuf,smb_vwv6,
3961 (smb_wct - 4) /* offset from smb header to wct */
3962 + 1 /* the wct field */
3963 + 12 * sizeof(uint16_t) /* vwv */
3964 + 2 /* the buflen field */
3965 + 1); /* padding byte */
3966 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3967 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3968 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3969 _smb_setlen_large(outbuf,
3970 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3971 return outsize;
3974 /****************************************************************************
3975 Reply to a read and X - possibly using sendfile.
3976 ****************************************************************************/
3978 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3979 files_struct *fsp, off_t startpos,
3980 size_t smb_maxcnt)
3982 struct smbXsrv_connection *xconn = req->xconn;
3983 ssize_t nread = -1;
3984 struct lock_struct lock;
3985 int saved_errno = 0;
3987 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3988 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3989 &lock);
3991 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3992 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3993 return;
3997 * We can only use sendfile on a non-chained packet
3998 * but we can use on a non-oplocked file. tridge proved this
3999 * on a train in Germany :-). JRA.
4002 if (!req_is_in_chain(req) &&
4003 !req->encrypted &&
4004 (fsp->base_fsp == NULL) &&
4005 (fsp->wcp == NULL) &&
4006 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
4007 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
4008 DATA_BLOB header;
4010 if(fsp_stat(fsp) == -1) {
4011 reply_nterror(req, map_nt_error_from_unix(errno));
4012 goto out;
4015 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4016 (startpos > fsp->fsp_name->st.st_ex_size) ||
4017 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4019 * We already know that we would do a short read, so don't
4020 * try the sendfile() path.
4022 goto nosendfile_read;
4026 * Set up the packet header before send. We
4027 * assume here the sendfile will work (get the
4028 * correct amount of data).
4031 header = data_blob_const(headerbuf, sizeof(headerbuf));
4033 construct_reply_common_req(req, (char *)headerbuf);
4034 setup_readX_header((char *)headerbuf, smb_maxcnt);
4036 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4037 startpos, smb_maxcnt);
4038 if (nread == -1) {
4039 saved_errno = errno;
4041 /* Returning ENOSYS means no data at all was sent.
4042 Do this as a normal read. */
4043 if (errno == ENOSYS) {
4044 goto normal_read;
4048 * Special hack for broken Linux with no working sendfile. If we
4049 * return EINTR we sent the header but not the rest of the data.
4050 * Fake this up by doing read/write calls.
4053 if (errno == EINTR) {
4054 /* Ensure we don't do this again. */
4055 set_use_sendfile(SNUM(conn), False);
4056 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4057 nread = fake_sendfile(xconn, fsp, startpos,
4058 smb_maxcnt);
4059 if (nread == -1) {
4060 saved_errno = errno;
4061 DEBUG(0,("send_file_readX: "
4062 "fake_sendfile failed for "
4063 "file %s (%s) for client %s. "
4064 "Terminating\n",
4065 fsp_str_dbg(fsp),
4066 smbXsrv_connection_dbg(xconn),
4067 strerror(saved_errno)));
4068 errno = saved_errno;
4069 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4071 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4072 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4073 /* No outbuf here means successful sendfile. */
4074 goto out;
4077 DEBUG(0,("send_file_readX: sendfile failed for file "
4078 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4079 strerror(errno)));
4080 exit_server_cleanly("send_file_readX sendfile failed");
4081 } else if (nread == 0) {
4083 * Some sendfile implementations return 0 to indicate
4084 * that there was a short read, but nothing was
4085 * actually written to the socket. In this case,
4086 * fallback to the normal read path so the header gets
4087 * the correct byte count.
4089 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4090 "falling back to the normal read: %s\n",
4091 fsp_str_dbg(fsp)));
4092 goto normal_read;
4095 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4096 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4098 /* Deal with possible short send. */
4099 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4100 ssize_t ret;
4102 ret = sendfile_short_send(xconn, fsp, nread,
4103 sizeof(headerbuf), smb_maxcnt);
4104 if (ret == -1) {
4105 const char *r;
4106 r = "send_file_readX: sendfile_short_send failed";
4107 DEBUG(0,("%s for file %s (%s).\n",
4108 r, fsp_str_dbg(fsp), strerror(errno)));
4109 exit_server_cleanly(r);
4112 /* No outbuf here means successful sendfile. */
4113 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4114 SMB_PERFCOUNT_END(&req->pcd);
4115 goto out;
4118 normal_read:
4120 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4121 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4122 ssize_t ret;
4124 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4125 (startpos > fsp->fsp_name->st.st_ex_size) ||
4126 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4128 * We already know that we would do a short
4129 * read, so don't try the sendfile() path.
4131 goto nosendfile_read;
4134 construct_reply_common_req(req, (char *)headerbuf);
4135 setup_readX_header((char *)headerbuf, smb_maxcnt);
4137 /* Send out the header. */
4138 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4139 sizeof(headerbuf));
4140 if (ret != sizeof(headerbuf)) {
4141 saved_errno = errno;
4143 * Try and give an error message saying what
4144 * client failed.
4146 DEBUG(0,("send_file_readX: write_data failed for file "
4147 "%s (%s) for client %s. Terminating\n",
4148 fsp_str_dbg(fsp),
4149 smbXsrv_connection_dbg(xconn),
4150 strerror(saved_errno)));
4151 errno = saved_errno;
4152 exit_server_cleanly("send_file_readX sendfile failed");
4154 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4155 if (nread == -1) {
4156 saved_errno = errno;
4157 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4158 "%s (%s) for client %s. Terminating\n",
4159 fsp_str_dbg(fsp),
4160 smbXsrv_connection_dbg(xconn),
4161 strerror(saved_errno)));
4162 errno = saved_errno;
4163 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4165 goto out;
4168 nosendfile_read:
4170 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4171 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4172 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4174 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4175 startpos, smb_maxcnt);
4176 saved_errno = errno;
4178 if (nread < 0) {
4179 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4180 return;
4183 setup_readX_header((char *)req->outbuf, nread);
4185 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4186 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4187 return;
4189 out:
4190 TALLOC_FREE(req->outbuf);
4191 return;
4194 /****************************************************************************
4195 Work out how much space we have for a read return.
4196 ****************************************************************************/
4198 static size_t calc_max_read_pdu(const struct smb_request *req)
4200 struct smbXsrv_connection *xconn = req->xconn;
4202 if (xconn->protocol < PROTOCOL_NT1) {
4203 return xconn->smb1.sessions.max_send;
4206 if (!lp_large_readwrite()) {
4207 return xconn->smb1.sessions.max_send;
4210 if (req_is_in_chain(req)) {
4211 return xconn->smb1.sessions.max_send;
4214 if (req->encrypted) {
4216 * Don't take encrypted traffic up to the
4217 * limit. There are padding considerations
4218 * that make that tricky.
4220 return xconn->smb1.sessions.max_send;
4223 if (srv_is_signing_active(xconn)) {
4224 return 0x1FFFF;
4227 if (!lp_unix_extensions()) {
4228 return 0x1FFFF;
4232 * We can do ultra-large POSIX reads.
4234 return 0xFFFFFF;
4237 /****************************************************************************
4238 Calculate how big a read can be. Copes with all clients. It's always
4239 safe to return a short read - Windows does this.
4240 ****************************************************************************/
4242 static size_t calc_read_size(const struct smb_request *req,
4243 size_t upper_size,
4244 size_t lower_size)
4246 struct smbXsrv_connection *xconn = req->xconn;
4247 size_t max_pdu = calc_max_read_pdu(req);
4248 size_t total_size = 0;
4249 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4250 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4253 * Windows explicitly ignores upper size of 0xFFFF.
4254 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4255 * We must do the same as these will never fit even in
4256 * an extended size NetBIOS packet.
4258 if (upper_size == 0xFFFF) {
4259 upper_size = 0;
4262 if (xconn->protocol < PROTOCOL_NT1) {
4263 upper_size = 0;
4266 total_size = ((upper_size<<16) | lower_size);
4269 * LARGE_READX test shows it's always safe to return
4270 * a short read. Windows does so.
4272 return MIN(total_size, max_len);
4275 /****************************************************************************
4276 Reply to a read and X.
4277 ****************************************************************************/
4279 void reply_read_and_X(struct smb_request *req)
4281 connection_struct *conn = req->conn;
4282 files_struct *fsp;
4283 off_t startpos;
4284 size_t smb_maxcnt;
4285 size_t upper_size;
4286 bool big_readX = False;
4287 #if 0
4288 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4289 #endif
4291 START_PROFILE(SMBreadX);
4293 if ((req->wct != 10) && (req->wct != 12)) {
4294 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4295 return;
4298 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4299 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4300 smb_maxcnt = SVAL(req->vwv+5, 0);
4302 /* If it's an IPC, pass off the pipe handler. */
4303 if (IS_IPC(conn)) {
4304 reply_pipe_read_and_X(req);
4305 END_PROFILE(SMBreadX);
4306 return;
4309 if (!check_fsp(conn, req, fsp)) {
4310 END_PROFILE(SMBreadX);
4311 return;
4314 if (!CHECK_READ(fsp,req)) {
4315 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4316 END_PROFILE(SMBreadX);
4317 return;
4320 upper_size = SVAL(req->vwv+7, 0);
4321 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4322 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4324 * This is a heuristic to avoid keeping large
4325 * outgoing buffers around over long-lived aio
4326 * requests.
4328 big_readX = True;
4331 if (req->wct == 12) {
4333 * This is a large offset (64 bit) read.
4335 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4339 if (!big_readX) {
4340 NTSTATUS status = schedule_aio_read_and_X(conn,
4341 req,
4342 fsp,
4343 startpos,
4344 smb_maxcnt);
4345 if (NT_STATUS_IS_OK(status)) {
4346 /* Read scheduled - we're done. */
4347 goto out;
4349 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4350 /* Real error - report to client. */
4351 END_PROFILE(SMBreadX);
4352 reply_nterror(req, status);
4353 return;
4355 /* NT_STATUS_RETRY - fall back to sync read. */
4358 smbd_lock_socket(req->xconn);
4359 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4360 smbd_unlock_socket(req->xconn);
4362 out:
4363 END_PROFILE(SMBreadX);
4364 return;
4367 /****************************************************************************
4368 Error replies to writebraw must have smb_wct == 1. Fix this up.
4369 ****************************************************************************/
4371 void error_to_writebrawerr(struct smb_request *req)
4373 uint8_t *old_outbuf = req->outbuf;
4375 reply_outbuf(req, 1, 0);
4377 memcpy(req->outbuf, old_outbuf, smb_size);
4378 TALLOC_FREE(old_outbuf);
4381 /****************************************************************************
4382 Read 4 bytes of a smb packet and return the smb length of the packet.
4383 Store the result in the buffer. This version of the function will
4384 never return a session keepalive (length of zero).
4385 Timeout is in milliseconds.
4386 ****************************************************************************/
4388 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4389 size_t *len)
4391 uint8_t msgtype = NBSSkeepalive;
4393 while (msgtype == NBSSkeepalive) {
4394 NTSTATUS status;
4396 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4397 len);
4398 if (!NT_STATUS_IS_OK(status)) {
4399 char addr[INET6_ADDRSTRLEN];
4400 /* Try and give an error message
4401 * saying what client failed. */
4402 DEBUG(0, ("read_smb_length_return_keepalive failed for "
4403 "client %s read error = %s.\n",
4404 get_peer_addr(fd,addr,sizeof(addr)),
4405 nt_errstr(status)));
4406 return status;
4409 msgtype = CVAL(inbuf, 0);
4412 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4413 (unsigned long)len));
4415 return NT_STATUS_OK;
4418 /****************************************************************************
4419 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4420 ****************************************************************************/
4422 void reply_writebraw(struct smb_request *req)
4424 connection_struct *conn = req->conn;
4425 struct smbXsrv_connection *xconn = req->xconn;
4426 char *buf = NULL;
4427 ssize_t nwritten=0;
4428 ssize_t total_written=0;
4429 size_t numtowrite=0;
4430 size_t tcount;
4431 off_t startpos;
4432 const char *data=NULL;
4433 bool write_through;
4434 files_struct *fsp;
4435 struct lock_struct lock;
4436 NTSTATUS status;
4438 START_PROFILE(SMBwritebraw);
4441 * If we ever reply with an error, it must have the SMB command
4442 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4443 * we're finished.
4445 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4447 if (srv_is_signing_active(xconn)) {
4448 END_PROFILE(SMBwritebraw);
4449 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4450 "raw reads/writes are disallowed.");
4453 if (req->wct < 12) {
4454 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4455 error_to_writebrawerr(req);
4456 END_PROFILE(SMBwritebraw);
4457 return;
4460 if (xconn->smb1.echo_handler.trusted_fde) {
4461 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4462 "'async smb echo handler = yes'\n"));
4463 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4464 error_to_writebrawerr(req);
4465 END_PROFILE(SMBwritebraw);
4466 return;
4469 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4470 if (!check_fsp(conn, req, fsp)) {
4471 error_to_writebrawerr(req);
4472 END_PROFILE(SMBwritebraw);
4473 return;
4476 if (!CHECK_WRITE(fsp)) {
4477 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4478 error_to_writebrawerr(req);
4479 END_PROFILE(SMBwritebraw);
4480 return;
4483 tcount = IVAL(req->vwv+1, 0);
4484 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4485 write_through = BITSETW(req->vwv+7,0);
4487 /* We have to deal with slightly different formats depending
4488 on whether we are using the core+ or lanman1.0 protocol */
4490 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4491 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4492 data = smb_buf_const(req->inbuf);
4493 } else {
4494 numtowrite = SVAL(req->vwv+10, 0);
4495 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4498 /* Ensure we don't write bytes past the end of this packet. */
4500 * This already protects us against CVE-2017-12163.
4502 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4503 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4504 error_to_writebrawerr(req);
4505 END_PROFILE(SMBwritebraw);
4506 return;
4509 if (!fsp->print_file) {
4510 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4511 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4512 &lock);
4514 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4515 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4516 error_to_writebrawerr(req);
4517 END_PROFILE(SMBwritebraw);
4518 return;
4522 if (numtowrite>0) {
4523 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4526 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4527 "wrote=%d sync=%d\n",
4528 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4529 (int)nwritten, (int)write_through));
4531 if (nwritten < (ssize_t)numtowrite) {
4532 reply_nterror(req, NT_STATUS_DISK_FULL);
4533 error_to_writebrawerr(req);
4534 goto out;
4537 total_written = nwritten;
4539 /* Allocate a buffer of 64k + length. */
4540 buf = talloc_array(NULL, char, 65540);
4541 if (!buf) {
4542 reply_nterror(req, NT_STATUS_NO_MEMORY);
4543 error_to_writebrawerr(req);
4544 goto out;
4547 /* Return a SMBwritebraw message to the redirector to tell
4548 * it to send more bytes */
4550 memcpy(buf, req->inbuf, smb_size);
4551 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4552 SCVAL(buf,smb_com,SMBwritebraw);
4553 SSVALS(buf,smb_vwv0,0xFFFF);
4554 show_msg(buf);
4555 if (!srv_send_smb(req->xconn,
4556 buf,
4557 false, 0, /* no signing */
4558 IS_CONN_ENCRYPTED(conn),
4559 &req->pcd)) {
4560 exit_server_cleanly("reply_writebraw: srv_send_smb "
4561 "failed.");
4564 /* Now read the raw data into the buffer and write it */
4565 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4566 &numtowrite);
4567 if (!NT_STATUS_IS_OK(status)) {
4568 exit_server_cleanly("secondary writebraw failed");
4571 /* Set up outbuf to return the correct size */
4572 reply_outbuf(req, 1, 0);
4574 if (numtowrite != 0) {
4576 if (numtowrite > 0xFFFF) {
4577 DEBUG(0,("reply_writebraw: Oversize secondary write "
4578 "raw requested (%u). Terminating\n",
4579 (unsigned int)numtowrite ));
4580 exit_server_cleanly("secondary writebraw failed");
4583 if (tcount > nwritten+numtowrite) {
4584 DEBUG(3,("reply_writebraw: Client overestimated the "
4585 "write %d %d %d\n",
4586 (int)tcount,(int)nwritten,(int)numtowrite));
4589 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4590 numtowrite);
4592 if (!NT_STATUS_IS_OK(status)) {
4593 /* Try and give an error message
4594 * saying what client failed. */
4595 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4596 "raw read failed (%s) for client %s. "
4597 "Terminating\n", nt_errstr(status),
4598 smbXsrv_connection_dbg(xconn)));
4599 exit_server_cleanly("secondary writebraw failed");
4603 * We are not vulnerable to CVE-2017-12163
4604 * here as we are guaranteed to have numtowrite
4605 * bytes available - we just read from the client.
4607 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4608 if (nwritten == -1) {
4609 TALLOC_FREE(buf);
4610 reply_nterror(req, map_nt_error_from_unix(errno));
4611 error_to_writebrawerr(req);
4612 goto out;
4615 if (nwritten < (ssize_t)numtowrite) {
4616 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4617 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4620 if (nwritten > 0) {
4621 total_written += nwritten;
4625 TALLOC_FREE(buf);
4626 SSVAL(req->outbuf,smb_vwv0,total_written);
4628 status = sync_file(conn, fsp, write_through);
4629 if (!NT_STATUS_IS_OK(status)) {
4630 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4631 fsp_str_dbg(fsp), nt_errstr(status)));
4632 reply_nterror(req, status);
4633 error_to_writebrawerr(req);
4634 goto out;
4637 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4638 "wrote=%d\n",
4639 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4640 (int)total_written));
4642 /* We won't return a status if write through is not selected - this
4643 * follows what WfWg does */
4644 END_PROFILE(SMBwritebraw);
4646 if (!write_through && total_written==tcount) {
4648 #if RABBIT_PELLET_FIX
4650 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4651 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4652 * JRA.
4654 if (!send_keepalive(xconn->transport.sock)) {
4655 exit_server_cleanly("reply_writebraw: send of "
4656 "keepalive failed");
4658 #endif
4659 TALLOC_FREE(req->outbuf);
4661 return;
4663 out:
4664 END_PROFILE(SMBwritebraw);
4665 return;
4668 #undef DBGC_CLASS
4669 #define DBGC_CLASS DBGC_LOCKING
4671 /****************************************************************************
4672 Reply to a writeunlock (core+).
4673 ****************************************************************************/
4675 void reply_writeunlock(struct smb_request *req)
4677 connection_struct *conn = req->conn;
4678 ssize_t nwritten = -1;
4679 size_t numtowrite;
4680 size_t remaining;
4681 off_t startpos;
4682 const char *data;
4683 NTSTATUS status = NT_STATUS_OK;
4684 files_struct *fsp;
4685 struct lock_struct lock;
4686 int saved_errno = 0;
4688 START_PROFILE(SMBwriteunlock);
4690 if (req->wct < 5) {
4691 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4692 END_PROFILE(SMBwriteunlock);
4693 return;
4696 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4698 if (!check_fsp(conn, req, fsp)) {
4699 END_PROFILE(SMBwriteunlock);
4700 return;
4703 if (!CHECK_WRITE(fsp)) {
4704 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4705 END_PROFILE(SMBwriteunlock);
4706 return;
4709 numtowrite = SVAL(req->vwv+1, 0);
4710 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4711 data = (const char *)req->buf + 3;
4714 * Ensure client isn't asking us to write more than
4715 * they sent. CVE-2017-12163.
4717 remaining = smbreq_bufrem(req, data);
4718 if (numtowrite > remaining) {
4719 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4720 END_PROFILE(SMBwriteunlock);
4721 return;
4724 if (!fsp->print_file && numtowrite > 0) {
4725 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4726 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4727 &lock);
4729 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4730 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4731 END_PROFILE(SMBwriteunlock);
4732 return;
4736 /* The special X/Open SMB protocol handling of
4737 zero length writes is *NOT* done for
4738 this call */
4739 if(numtowrite == 0) {
4740 nwritten = 0;
4741 } else {
4742 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4743 saved_errno = errno;
4746 status = sync_file(conn, fsp, False /* write through */);
4747 if (!NT_STATUS_IS_OK(status)) {
4748 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4749 fsp_str_dbg(fsp), nt_errstr(status)));
4750 reply_nterror(req, status);
4751 goto out;
4754 if(nwritten < 0) {
4755 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4756 goto out;
4759 if((nwritten < numtowrite) && (numtowrite != 0)) {
4760 reply_nterror(req, NT_STATUS_DISK_FULL);
4761 goto out;
4764 if (numtowrite && !fsp->print_file) {
4765 struct smbd_lock_element l = {
4766 .smblctx = req->smbpid,
4767 .brltype = UNLOCK_LOCK,
4768 .offset = startpos,
4769 .count = numtowrite,
4771 status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
4772 if (NT_STATUS_V(status)) {
4773 reply_nterror(req, status);
4774 goto out;
4778 reply_outbuf(req, 1, 0);
4780 SSVAL(req->outbuf,smb_vwv0,nwritten);
4782 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4783 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4785 out:
4786 END_PROFILE(SMBwriteunlock);
4787 return;
4790 #undef DBGC_CLASS
4791 #define DBGC_CLASS DBGC_ALL
4793 /****************************************************************************
4794 Reply to a write.
4795 ****************************************************************************/
4797 void reply_write(struct smb_request *req)
4799 connection_struct *conn = req->conn;
4800 size_t numtowrite;
4801 size_t remaining;
4802 ssize_t nwritten = -1;
4803 off_t startpos;
4804 const char *data;
4805 files_struct *fsp;
4806 struct lock_struct lock;
4807 NTSTATUS status;
4808 int saved_errno = 0;
4810 START_PROFILE(SMBwrite);
4812 if (req->wct < 5) {
4813 END_PROFILE(SMBwrite);
4814 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4815 return;
4818 /* If it's an IPC, pass off the pipe handler. */
4819 if (IS_IPC(conn)) {
4820 reply_pipe_write(req);
4821 END_PROFILE(SMBwrite);
4822 return;
4825 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4827 if (!check_fsp(conn, req, fsp)) {
4828 END_PROFILE(SMBwrite);
4829 return;
4832 if (!CHECK_WRITE(fsp)) {
4833 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4834 END_PROFILE(SMBwrite);
4835 return;
4838 numtowrite = SVAL(req->vwv+1, 0);
4839 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4840 data = (const char *)req->buf + 3;
4843 * Ensure client isn't asking us to write more than
4844 * they sent. CVE-2017-12163.
4846 remaining = smbreq_bufrem(req, data);
4847 if (numtowrite > remaining) {
4848 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4849 END_PROFILE(SMBwrite);
4850 return;
4853 if (!fsp->print_file) {
4854 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4855 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4856 &lock);
4858 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4859 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4860 END_PROFILE(SMBwrite);
4861 return;
4866 * X/Open SMB protocol says that if smb_vwv1 is
4867 * zero then the file size should be extended or
4868 * truncated to the size given in smb_vwv[2-3].
4871 if(numtowrite == 0) {
4873 * This is actually an allocate call, and set EOF. JRA.
4875 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4876 if (nwritten < 0) {
4877 reply_nterror(req, NT_STATUS_DISK_FULL);
4878 goto out;
4880 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4881 if (nwritten < 0) {
4882 reply_nterror(req, NT_STATUS_DISK_FULL);
4883 goto out;
4885 trigger_write_time_update_immediate(fsp);
4886 } else {
4887 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4890 status = sync_file(conn, fsp, False);
4891 if (!NT_STATUS_IS_OK(status)) {
4892 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4893 fsp_str_dbg(fsp), nt_errstr(status)));
4894 reply_nterror(req, status);
4895 goto out;
4898 if(nwritten < 0) {
4899 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4900 goto out;
4903 if((nwritten == 0) && (numtowrite != 0)) {
4904 reply_nterror(req, NT_STATUS_DISK_FULL);
4905 goto out;
4908 reply_outbuf(req, 1, 0);
4910 SSVAL(req->outbuf,smb_vwv0,nwritten);
4912 if (nwritten < (ssize_t)numtowrite) {
4913 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4914 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4917 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4919 out:
4920 END_PROFILE(SMBwrite);
4921 return;
4924 /****************************************************************************
4925 Ensure a buffer is a valid writeX for recvfile purposes.
4926 ****************************************************************************/
4928 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4929 (2*14) + /* word count (including bcc) */ \
4930 1 /* pad byte */)
4932 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4933 const uint8_t *inbuf)
4935 size_t numtowrite;
4936 unsigned int doff = 0;
4937 size_t len = smb_len_large(inbuf);
4938 uint16_t fnum;
4939 struct smbXsrv_open *op = NULL;
4940 struct files_struct *fsp = NULL;
4941 NTSTATUS status;
4943 if (is_encrypted_packet(inbuf)) {
4944 /* Can't do this on encrypted
4945 * connections. */
4946 return false;
4949 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4950 return false;
4953 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4954 CVAL(inbuf,smb_wct) != 14) {
4955 DEBUG(10,("is_valid_writeX_buffer: chained or "
4956 "invalid word length.\n"));
4957 return false;
4960 fnum = SVAL(inbuf, smb_vwv2);
4961 status = smb1srv_open_lookup(xconn,
4962 fnum,
4963 0, /* now */
4964 &op);
4965 if (!NT_STATUS_IS_OK(status)) {
4966 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4967 return false;
4969 fsp = op->compat;
4970 if (fsp == NULL) {
4971 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4972 return false;
4974 if (fsp->conn == NULL) {
4975 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4976 return false;
4979 if (IS_IPC(fsp->conn)) {
4980 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4981 return false;
4983 if (IS_PRINT(fsp->conn)) {
4984 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4985 return false;
4987 if (fsp->base_fsp != NULL) {
4988 DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
4989 return false;
4991 doff = SVAL(inbuf,smb_vwv11);
4993 numtowrite = SVAL(inbuf,smb_vwv10);
4995 if (len > doff && len - doff > 0xFFFF) {
4996 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4999 if (numtowrite == 0) {
5000 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
5001 return false;
5004 /* Ensure the sizes match up. */
5005 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
5006 /* no pad byte...old smbclient :-( */
5007 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
5008 (unsigned int)doff,
5009 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
5010 return false;
5013 if (len - doff != numtowrite) {
5014 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
5015 "len = %u, doff = %u, numtowrite = %u\n",
5016 (unsigned int)len,
5017 (unsigned int)doff,
5018 (unsigned int)numtowrite ));
5019 return false;
5022 DEBUG(10,("is_valid_writeX_buffer: true "
5023 "len = %u, doff = %u, numtowrite = %u\n",
5024 (unsigned int)len,
5025 (unsigned int)doff,
5026 (unsigned int)numtowrite ));
5028 return true;
5031 /****************************************************************************
5032 Reply to a write and X.
5033 ****************************************************************************/
5035 void reply_write_and_X(struct smb_request *req)
5037 connection_struct *conn = req->conn;
5038 struct smbXsrv_connection *xconn = req->xconn;
5039 files_struct *fsp;
5040 struct lock_struct lock;
5041 off_t startpos;
5042 size_t numtowrite;
5043 bool write_through;
5044 ssize_t nwritten;
5045 unsigned int smb_doff;
5046 unsigned int smblen;
5047 const char *data;
5048 NTSTATUS status;
5049 int saved_errno = 0;
5051 START_PROFILE(SMBwriteX);
5053 if ((req->wct != 12) && (req->wct != 14)) {
5054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5055 goto out;
5058 numtowrite = SVAL(req->vwv+10, 0);
5059 smb_doff = SVAL(req->vwv+11, 0);
5060 smblen = smb_len(req->inbuf);
5062 if (req->unread_bytes > 0xFFFF ||
5063 (smblen > smb_doff &&
5064 smblen - smb_doff > 0xFFFF)) {
5065 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5068 if (req->unread_bytes) {
5069 /* Can't do a recvfile write on IPC$ */
5070 if (IS_IPC(conn)) {
5071 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5072 goto out;
5074 if (numtowrite != req->unread_bytes) {
5075 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5076 goto out;
5078 } else {
5080 * This already protects us against CVE-2017-12163.
5082 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5083 smb_doff + numtowrite > smblen) {
5084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5085 goto out;
5089 /* If it's an IPC, pass off the pipe handler. */
5090 if (IS_IPC(conn)) {
5091 if (req->unread_bytes) {
5092 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5093 goto out;
5095 reply_pipe_write_and_X(req);
5096 goto out;
5099 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5100 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5101 write_through = BITSETW(req->vwv+7,0);
5103 if (!check_fsp(conn, req, fsp)) {
5104 goto out;
5107 if (!CHECK_WRITE(fsp)) {
5108 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5109 goto out;
5112 data = smb_base(req->inbuf) + smb_doff;
5114 if(req->wct == 14) {
5116 * This is a large offset (64 bit) write.
5118 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5122 /* X/Open SMB protocol says that, unlike SMBwrite
5123 if the length is zero then NO truncation is
5124 done, just a write of zero. To truncate a file,
5125 use SMBwrite. */
5127 if(numtowrite == 0) {
5128 nwritten = 0;
5129 } else {
5130 if (req->unread_bytes == 0) {
5131 status = schedule_aio_write_and_X(conn,
5132 req,
5133 fsp,
5134 data,
5135 startpos,
5136 numtowrite);
5138 if (NT_STATUS_IS_OK(status)) {
5139 /* write scheduled - we're done. */
5140 goto out;
5142 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5143 /* Real error - report to client. */
5144 reply_nterror(req, status);
5145 goto out;
5147 /* NT_STATUS_RETRY - fall through to sync write. */
5150 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5151 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5152 &lock);
5154 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5155 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5156 goto out;
5159 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5160 saved_errno = errno;
5163 if(nwritten < 0) {
5164 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5165 goto out;
5168 if((nwritten == 0) && (numtowrite != 0)) {
5169 reply_nterror(req, NT_STATUS_DISK_FULL);
5170 goto out;
5173 reply_outbuf(req, 6, 0);
5174 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5175 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5176 SSVAL(req->outbuf,smb_vwv2,nwritten);
5177 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5179 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5180 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5182 status = sync_file(conn, fsp, write_through);
5183 if (!NT_STATUS_IS_OK(status)) {
5184 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5185 fsp_str_dbg(fsp), nt_errstr(status)));
5186 reply_nterror(req, status);
5187 goto out;
5190 END_PROFILE(SMBwriteX);
5191 return;
5193 out:
5194 if (req->unread_bytes) {
5195 /* writeX failed. drain socket. */
5196 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5197 req->unread_bytes) {
5198 smb_panic("failed to drain pending bytes");
5200 req->unread_bytes = 0;
5203 END_PROFILE(SMBwriteX);
5204 return;
5207 /****************************************************************************
5208 Reply to a lseek.
5209 ****************************************************************************/
5211 void reply_lseek(struct smb_request *req)
5213 connection_struct *conn = req->conn;
5214 off_t startpos;
5215 off_t res= -1;
5216 int mode,umode;
5217 files_struct *fsp;
5219 START_PROFILE(SMBlseek);
5221 if (req->wct < 4) {
5222 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5223 END_PROFILE(SMBlseek);
5224 return;
5227 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5229 if (!check_fsp(conn, req, fsp)) {
5230 return;
5233 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5235 mode = SVAL(req->vwv+1, 0) & 3;
5236 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5237 startpos = (off_t)IVALS(req->vwv+2, 0);
5239 switch (mode) {
5240 case 0:
5241 umode = SEEK_SET;
5242 res = startpos;
5243 break;
5244 case 1:
5245 umode = SEEK_CUR;
5246 res = fsp->fh->pos + startpos;
5247 break;
5248 case 2:
5249 umode = SEEK_END;
5250 break;
5251 default:
5252 umode = SEEK_SET;
5253 res = startpos;
5254 break;
5257 if (umode == SEEK_END) {
5258 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5259 if(errno == EINVAL) {
5260 off_t current_pos = startpos;
5262 if(fsp_stat(fsp) == -1) {
5263 reply_nterror(req,
5264 map_nt_error_from_unix(errno));
5265 END_PROFILE(SMBlseek);
5266 return;
5269 current_pos += fsp->fsp_name->st.st_ex_size;
5270 if(current_pos < 0)
5271 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5275 if(res == -1) {
5276 reply_nterror(req, map_nt_error_from_unix(errno));
5277 END_PROFILE(SMBlseek);
5278 return;
5282 fsp->fh->pos = res;
5284 reply_outbuf(req, 2, 0);
5285 SIVAL(req->outbuf,smb_vwv0,res);
5287 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5288 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5290 END_PROFILE(SMBlseek);
5291 return;
5294 static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
5295 void *private_data)
5297 connection_struct *conn = talloc_get_type_abort(
5298 private_data, connection_struct);
5300 if (conn != fsp->conn) {
5301 return NULL;
5303 if (fsp->fh->fd == -1) {
5304 return NULL;
5306 sync_file(conn, fsp, True /* write through */);
5308 return NULL;
5311 /****************************************************************************
5312 Reply to a flush.
5313 ****************************************************************************/
5315 void reply_flush(struct smb_request *req)
5317 connection_struct *conn = req->conn;
5318 uint16_t fnum;
5319 files_struct *fsp;
5321 START_PROFILE(SMBflush);
5323 if (req->wct < 1) {
5324 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5325 return;
5328 fnum = SVAL(req->vwv+0, 0);
5329 fsp = file_fsp(req, fnum);
5331 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5332 return;
5335 if (!fsp) {
5336 files_forall(req->sconn, file_sync_one_fn, conn);
5337 } else {
5338 NTSTATUS status = sync_file(conn, fsp, True);
5339 if (!NT_STATUS_IS_OK(status)) {
5340 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5341 fsp_str_dbg(fsp), nt_errstr(status)));
5342 reply_nterror(req, status);
5343 END_PROFILE(SMBflush);
5344 return;
5348 reply_outbuf(req, 0, 0);
5350 DEBUG(3,("flush\n"));
5351 END_PROFILE(SMBflush);
5352 return;
5355 /****************************************************************************
5356 Reply to a exit.
5357 conn POINTER CAN BE NULL HERE !
5358 ****************************************************************************/
5360 void reply_exit(struct smb_request *req)
5362 START_PROFILE(SMBexit);
5364 file_close_pid(req->sconn, req->smbpid, req->vuid);
5366 reply_outbuf(req, 0, 0);
5368 DEBUG(3,("exit\n"));
5370 END_PROFILE(SMBexit);
5371 return;
5374 struct reply_close_state {
5375 files_struct *fsp;
5376 struct smb_request *smbreq;
5379 static void do_smb1_close(struct tevent_req *req);
5381 void reply_close(struct smb_request *req)
5383 connection_struct *conn = req->conn;
5384 NTSTATUS status = NT_STATUS_OK;
5385 files_struct *fsp = NULL;
5386 START_PROFILE(SMBclose);
5388 if (req->wct < 3) {
5389 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5390 END_PROFILE(SMBclose);
5391 return;
5394 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5397 * We can only use check_fsp if we know it's not a directory.
5400 if (!check_fsp_open(conn, req, fsp)) {
5401 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5402 END_PROFILE(SMBclose);
5403 return;
5406 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5407 fsp->is_directory ? "directory" : "file",
5408 fsp->fh->fd, fsp_fnum_dbg(fsp),
5409 conn->num_files_open));
5411 if (!fsp->is_directory) {
5412 time_t t;
5415 * Take care of any time sent in the close.
5418 t = srv_make_unix_date3(req->vwv+1);
5419 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5422 if (fsp->num_aio_requests != 0) {
5424 struct reply_close_state *state;
5426 DEBUG(10, ("closing with aio %u requests pending\n",
5427 fsp->num_aio_requests));
5430 * We depend on the aio_extra destructor to take care of this
5431 * close request once fsp->num_aio_request drops to 0.
5434 fsp->deferred_close = tevent_wait_send(
5435 fsp, fsp->conn->sconn->ev_ctx);
5436 if (fsp->deferred_close == NULL) {
5437 status = NT_STATUS_NO_MEMORY;
5438 goto done;
5441 state = talloc(fsp, struct reply_close_state);
5442 if (state == NULL) {
5443 TALLOC_FREE(fsp->deferred_close);
5444 status = NT_STATUS_NO_MEMORY;
5445 goto done;
5447 state->fsp = fsp;
5448 state->smbreq = talloc_move(fsp, &req);
5449 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5450 state);
5451 END_PROFILE(SMBclose);
5452 return;
5456 * close_file() returns the unix errno if an error was detected on
5457 * close - normally this is due to a disk full error. If not then it
5458 * was probably an I/O error.
5461 status = close_file(req, fsp, NORMAL_CLOSE);
5462 done:
5463 if (!NT_STATUS_IS_OK(status)) {
5464 reply_nterror(req, status);
5465 END_PROFILE(SMBclose);
5466 return;
5469 reply_outbuf(req, 0, 0);
5470 END_PROFILE(SMBclose);
5471 return;
5474 static void do_smb1_close(struct tevent_req *req)
5476 struct reply_close_state *state = tevent_req_callback_data(
5477 req, struct reply_close_state);
5478 struct smb_request *smbreq;
5479 NTSTATUS status;
5480 int ret;
5482 ret = tevent_wait_recv(req);
5483 TALLOC_FREE(req);
5484 if (ret != 0) {
5485 DEBUG(10, ("tevent_wait_recv returned %s\n",
5486 strerror(ret)));
5488 * Continue anyway, this should never happen
5493 * fsp->smb2_close_request right now is a talloc grandchild of
5494 * fsp. When we close_file(fsp), it would go with it. No chance to
5495 * reply...
5497 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5499 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5500 if (NT_STATUS_IS_OK(status)) {
5501 reply_outbuf(smbreq, 0, 0);
5502 } else {
5503 reply_nterror(smbreq, status);
5505 if (!srv_send_smb(smbreq->xconn,
5506 (char *)smbreq->outbuf,
5507 true,
5508 smbreq->seqnum+1,
5509 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5510 NULL)) {
5511 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5512 "failed.");
5514 TALLOC_FREE(smbreq);
5517 /****************************************************************************
5518 Reply to a writeclose (Core+ protocol).
5519 ****************************************************************************/
5521 void reply_writeclose(struct smb_request *req)
5523 connection_struct *conn = req->conn;
5524 size_t numtowrite;
5525 size_t remaining;
5526 ssize_t nwritten = -1;
5527 NTSTATUS close_status = NT_STATUS_OK;
5528 off_t startpos;
5529 const char *data;
5530 struct timespec mtime;
5531 files_struct *fsp;
5532 struct lock_struct lock;
5534 START_PROFILE(SMBwriteclose);
5536 if (req->wct < 6) {
5537 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5538 END_PROFILE(SMBwriteclose);
5539 return;
5542 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5544 if (!check_fsp(conn, req, fsp)) {
5545 END_PROFILE(SMBwriteclose);
5546 return;
5548 if (!CHECK_WRITE(fsp)) {
5549 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5550 END_PROFILE(SMBwriteclose);
5551 return;
5554 numtowrite = SVAL(req->vwv+1, 0);
5555 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5556 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5557 data = (const char *)req->buf + 1;
5560 * Ensure client isn't asking us to write more than
5561 * they sent. CVE-2017-12163.
5563 remaining = smbreq_bufrem(req, data);
5564 if (numtowrite > remaining) {
5565 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5566 END_PROFILE(SMBwriteclose);
5567 return;
5570 if (fsp->print_file == NULL) {
5571 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5572 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5573 &lock);
5575 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5576 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5577 END_PROFILE(SMBwriteclose);
5578 return;
5582 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5584 set_close_write_time(fsp, mtime);
5587 * More insanity. W2K only closes the file if writelen > 0.
5588 * JRA.
5591 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5592 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5593 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5595 if (numtowrite) {
5596 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5597 "file %s\n", fsp_str_dbg(fsp)));
5598 close_status = close_file(req, fsp, NORMAL_CLOSE);
5599 fsp = NULL;
5602 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5603 reply_nterror(req, NT_STATUS_DISK_FULL);
5604 goto out;
5607 if(!NT_STATUS_IS_OK(close_status)) {
5608 reply_nterror(req, close_status);
5609 goto out;
5612 reply_outbuf(req, 1, 0);
5614 SSVAL(req->outbuf,smb_vwv0,nwritten);
5616 out:
5618 END_PROFILE(SMBwriteclose);
5619 return;
5622 #undef DBGC_CLASS
5623 #define DBGC_CLASS DBGC_LOCKING
5625 /****************************************************************************
5626 Reply to a lock.
5627 ****************************************************************************/
5629 void reply_lock(struct smb_request *req)
5631 connection_struct *conn = req->conn;
5632 uint64_t count,offset;
5633 NTSTATUS status;
5634 files_struct *fsp;
5635 struct byte_range_lock *br_lck = NULL;
5637 START_PROFILE(SMBlock);
5639 if (req->wct < 5) {
5640 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5641 END_PROFILE(SMBlock);
5642 return;
5645 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5647 if (!check_fsp(conn, req, fsp)) {
5648 END_PROFILE(SMBlock);
5649 return;
5652 count = (uint64_t)IVAL(req->vwv+1, 0);
5653 offset = (uint64_t)IVAL(req->vwv+3, 0);
5655 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5656 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5658 br_lck = do_lock(req->sconn->msg_ctx,
5659 fsp,
5660 (uint64_t)req->smbpid,
5661 count,
5662 offset,
5663 WRITE_LOCK,
5664 WINDOWS_LOCK,
5665 False, /* Non-blocking lock. */
5666 &status,
5667 NULL,
5668 NULL);
5670 TALLOC_FREE(br_lck);
5672 if (NT_STATUS_V(status)) {
5673 reply_nterror(req, status);
5674 END_PROFILE(SMBlock);
5675 return;
5678 reply_outbuf(req, 0, 0);
5680 END_PROFILE(SMBlock);
5681 return;
5684 /****************************************************************************
5685 Reply to a unlock.
5686 ****************************************************************************/
5688 void reply_unlock(struct smb_request *req)
5690 connection_struct *conn = req->conn;
5691 NTSTATUS status;
5692 files_struct *fsp;
5693 struct smbd_lock_element lck;
5695 START_PROFILE(SMBunlock);
5697 if (req->wct < 5) {
5698 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5699 END_PROFILE(SMBunlock);
5700 return;
5703 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5705 if (!check_fsp(conn, req, fsp)) {
5706 END_PROFILE(SMBunlock);
5707 return;
5710 lck = (struct smbd_lock_element) {
5711 .smblctx = req->smbpid,
5712 .brltype = UNLOCK_LOCK,
5713 .offset = IVAL(req->vwv+3, 0),
5714 .count = IVAL(req->vwv+1, 0),
5717 status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
5719 if (!NT_STATUS_IS_OK(status)) {
5720 reply_nterror(req, status);
5721 END_PROFILE(SMBunlock);
5722 return;
5725 DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
5726 fsp->fh->fd,
5727 fsp_fnum_dbg(fsp),
5728 lck.offset,
5729 lck.count);
5731 reply_outbuf(req, 0, 0);
5733 END_PROFILE(SMBunlock);
5734 return;
5737 #undef DBGC_CLASS
5738 #define DBGC_CLASS DBGC_ALL
5740 /****************************************************************************
5741 Reply to a tdis.
5742 conn POINTER CAN BE NULL HERE !
5743 ****************************************************************************/
5745 void reply_tdis(struct smb_request *req)
5747 NTSTATUS status;
5748 connection_struct *conn = req->conn;
5749 struct smbXsrv_tcon *tcon;
5751 START_PROFILE(SMBtdis);
5753 if (!conn) {
5754 DEBUG(4,("Invalid connection in tdis\n"));
5755 reply_force_doserror(req, ERRSRV, ERRinvnid);
5756 END_PROFILE(SMBtdis);
5757 return;
5760 tcon = conn->tcon;
5761 req->conn = NULL;
5764 * TODO: cancel all outstanding requests on the tcon
5766 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5767 if (!NT_STATUS_IS_OK(status)) {
5768 DEBUG(0, ("reply_tdis: "
5769 "smbXsrv_tcon_disconnect() failed: %s\n",
5770 nt_errstr(status)));
5772 * If we hit this case, there is something completely
5773 * wrong, so we better disconnect the transport connection.
5775 END_PROFILE(SMBtdis);
5776 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5777 return;
5780 TALLOC_FREE(tcon);
5782 reply_outbuf(req, 0, 0);
5783 END_PROFILE(SMBtdis);
5784 return;
5787 /****************************************************************************
5788 Reply to a echo.
5789 conn POINTER CAN BE NULL HERE !
5790 ****************************************************************************/
5792 void reply_echo(struct smb_request *req)
5794 connection_struct *conn = req->conn;
5795 struct smb_perfcount_data local_pcd;
5796 struct smb_perfcount_data *cur_pcd;
5797 int smb_reverb;
5798 int seq_num;
5800 START_PROFILE(SMBecho);
5802 smb_init_perfcount_data(&local_pcd);
5804 if (req->wct < 1) {
5805 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5806 END_PROFILE(SMBecho);
5807 return;
5810 smb_reverb = SVAL(req->vwv+0, 0);
5812 reply_outbuf(req, 1, req->buflen);
5814 /* copy any incoming data back out */
5815 if (req->buflen > 0) {
5816 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5819 if (smb_reverb > 100) {
5820 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5821 smb_reverb = 100;
5824 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5826 /* this makes sure we catch the request pcd */
5827 if (seq_num == smb_reverb) {
5828 cur_pcd = &req->pcd;
5829 } else {
5830 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5831 cur_pcd = &local_pcd;
5834 SSVAL(req->outbuf,smb_vwv0,seq_num);
5836 show_msg((char *)req->outbuf);
5837 if (!srv_send_smb(req->xconn,
5838 (char *)req->outbuf,
5839 true, req->seqnum+1,
5840 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5841 cur_pcd))
5842 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5845 DEBUG(3,("echo %d times\n", smb_reverb));
5847 TALLOC_FREE(req->outbuf);
5849 END_PROFILE(SMBecho);
5850 return;
5853 /****************************************************************************
5854 Reply to a printopen.
5855 ****************************************************************************/
5857 void reply_printopen(struct smb_request *req)
5859 connection_struct *conn = req->conn;
5860 files_struct *fsp;
5861 NTSTATUS status;
5863 START_PROFILE(SMBsplopen);
5865 if (req->wct < 2) {
5866 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5867 END_PROFILE(SMBsplopen);
5868 return;
5871 if (!CAN_PRINT(conn)) {
5872 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5873 END_PROFILE(SMBsplopen);
5874 return;
5877 status = file_new(req, conn, &fsp);
5878 if(!NT_STATUS_IS_OK(status)) {
5879 reply_nterror(req, status);
5880 END_PROFILE(SMBsplopen);
5881 return;
5884 /* Open for exclusive use, write only. */
5885 status = print_spool_open(fsp, NULL, req->vuid);
5887 if (!NT_STATUS_IS_OK(status)) {
5888 file_free(req, fsp);
5889 reply_nterror(req, status);
5890 END_PROFILE(SMBsplopen);
5891 return;
5894 reply_outbuf(req, 1, 0);
5895 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5897 DEBUG(3,("openprint fd=%d %s\n",
5898 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5900 END_PROFILE(SMBsplopen);
5901 return;
5904 /****************************************************************************
5905 Reply to a printclose.
5906 ****************************************************************************/
5908 void reply_printclose(struct smb_request *req)
5910 connection_struct *conn = req->conn;
5911 files_struct *fsp;
5912 NTSTATUS status;
5914 START_PROFILE(SMBsplclose);
5916 if (req->wct < 1) {
5917 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5918 END_PROFILE(SMBsplclose);
5919 return;
5922 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5924 if (!check_fsp(conn, req, fsp)) {
5925 END_PROFILE(SMBsplclose);
5926 return;
5929 if (!CAN_PRINT(conn)) {
5930 reply_force_doserror(req, ERRSRV, ERRerror);
5931 END_PROFILE(SMBsplclose);
5932 return;
5935 DEBUG(3,("printclose fd=%d %s\n",
5936 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5938 status = close_file(req, fsp, NORMAL_CLOSE);
5940 if(!NT_STATUS_IS_OK(status)) {
5941 reply_nterror(req, status);
5942 END_PROFILE(SMBsplclose);
5943 return;
5946 reply_outbuf(req, 0, 0);
5948 END_PROFILE(SMBsplclose);
5949 return;
5952 /****************************************************************************
5953 Reply to a printqueue.
5954 ****************************************************************************/
5956 void reply_printqueue(struct smb_request *req)
5958 connection_struct *conn = req->conn;
5959 int max_count;
5960 int start_index;
5962 START_PROFILE(SMBsplretq);
5964 if (req->wct < 2) {
5965 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5966 END_PROFILE(SMBsplretq);
5967 return;
5970 max_count = SVAL(req->vwv+0, 0);
5971 start_index = SVAL(req->vwv+1, 0);
5973 /* we used to allow the client to get the cnum wrong, but that
5974 is really quite gross and only worked when there was only
5975 one printer - I think we should now only accept it if they
5976 get it right (tridge) */
5977 if (!CAN_PRINT(conn)) {
5978 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5979 END_PROFILE(SMBsplretq);
5980 return;
5983 reply_outbuf(req, 2, 3);
5984 SSVAL(req->outbuf,smb_vwv0,0);
5985 SSVAL(req->outbuf,smb_vwv1,0);
5986 SCVAL(smb_buf(req->outbuf),0,1);
5987 SSVAL(smb_buf(req->outbuf),1,0);
5989 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5990 start_index, max_count));
5993 TALLOC_CTX *mem_ctx = talloc_tos();
5994 NTSTATUS status;
5995 WERROR werr;
5996 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5997 struct rpc_pipe_client *cli = NULL;
5998 struct dcerpc_binding_handle *b = NULL;
5999 struct policy_handle handle;
6000 struct spoolss_DevmodeContainer devmode_ctr;
6001 union spoolss_JobInfo *info;
6002 uint32_t count;
6003 uint32_t num_to_get;
6004 uint32_t first;
6005 uint32_t i;
6007 ZERO_STRUCT(handle);
6009 status = rpc_pipe_open_interface(mem_ctx,
6010 &ndr_table_spoolss,
6011 conn->session_info,
6012 conn->sconn->remote_address,
6013 conn->sconn->local_address,
6014 conn->sconn->msg_ctx,
6015 &cli);
6016 if (!NT_STATUS_IS_OK(status)) {
6017 DEBUG(0, ("reply_printqueue: "
6018 "could not connect to spoolss: %s\n",
6019 nt_errstr(status)));
6020 reply_nterror(req, status);
6021 goto out;
6023 b = cli->binding_handle;
6025 ZERO_STRUCT(devmode_ctr);
6027 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
6028 sharename,
6029 NULL, devmode_ctr,
6030 SEC_FLAG_MAXIMUM_ALLOWED,
6031 &handle,
6032 &werr);
6033 if (!NT_STATUS_IS_OK(status)) {
6034 reply_nterror(req, status);
6035 goto out;
6037 if (!W_ERROR_IS_OK(werr)) {
6038 reply_nterror(req, werror_to_ntstatus(werr));
6039 goto out;
6042 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6043 &handle,
6044 0, /* firstjob */
6045 0xff, /* numjobs */
6046 2, /* level */
6047 0, /* offered */
6048 &count,
6049 &info);
6050 if (!W_ERROR_IS_OK(werr)) {
6051 reply_nterror(req, werror_to_ntstatus(werr));
6052 goto out;
6055 if (max_count > 0) {
6056 first = start_index;
6057 } else {
6058 first = start_index + max_count + 1;
6061 if (first >= count) {
6062 num_to_get = first;
6063 } else {
6064 num_to_get = first + MIN(ABS(max_count), count - first);
6067 for (i = first; i < num_to_get; i++) {
6068 char blob[28];
6069 char *p = blob;
6070 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6071 int qstatus;
6072 size_t len = 0;
6073 uint16_t qrapjobid = pjobid_to_rap(sharename,
6074 info[i].info2.job_id);
6076 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6077 qstatus = 2;
6078 } else {
6079 qstatus = 3;
6082 srv_put_dos_date2(p, 0, qtime);
6083 SCVAL(p, 4, qstatus);
6084 SSVAL(p, 5, qrapjobid);
6085 SIVAL(p, 7, info[i].info2.size);
6086 SCVAL(p, 11, 0);
6087 status = srvstr_push(blob, req->flags2, p+12,
6088 info[i].info2.notify_name, 16, STR_ASCII, &len);
6089 if (!NT_STATUS_IS_OK(status)) {
6090 reply_nterror(req, status);
6091 goto out;
6093 if (message_push_blob(
6094 &req->outbuf,
6095 data_blob_const(
6096 blob, sizeof(blob))) == -1) {
6097 reply_nterror(req, NT_STATUS_NO_MEMORY);
6098 goto out;
6102 if (count > 0) {
6103 SSVAL(req->outbuf,smb_vwv0,count);
6104 SSVAL(req->outbuf,smb_vwv1,
6105 (max_count>0?first+count:first-1));
6106 SCVAL(smb_buf(req->outbuf),0,1);
6107 SSVAL(smb_buf(req->outbuf),1,28*count);
6111 DEBUG(3, ("%u entries returned in queue\n",
6112 (unsigned)count));
6114 out:
6115 if (b && is_valid_policy_hnd(&handle)) {
6116 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6121 END_PROFILE(SMBsplretq);
6122 return;
6125 /****************************************************************************
6126 Reply to a printwrite.
6127 ****************************************************************************/
6129 void reply_printwrite(struct smb_request *req)
6131 connection_struct *conn = req->conn;
6132 int numtowrite;
6133 const char *data;
6134 files_struct *fsp;
6136 START_PROFILE(SMBsplwr);
6138 if (req->wct < 1) {
6139 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6140 END_PROFILE(SMBsplwr);
6141 return;
6144 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6146 if (!check_fsp(conn, req, fsp)) {
6147 END_PROFILE(SMBsplwr);
6148 return;
6151 if (!fsp->print_file) {
6152 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6153 END_PROFILE(SMBsplwr);
6154 return;
6157 if (!CHECK_WRITE(fsp)) {
6158 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6159 END_PROFILE(SMBsplwr);
6160 return;
6163 numtowrite = SVAL(req->buf, 1);
6166 * This already protects us against CVE-2017-12163.
6168 if (req->buflen < numtowrite + 3) {
6169 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6170 END_PROFILE(SMBsplwr);
6171 return;
6174 data = (const char *)req->buf + 3;
6176 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6177 reply_nterror(req, map_nt_error_from_unix(errno));
6178 END_PROFILE(SMBsplwr);
6179 return;
6182 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6184 END_PROFILE(SMBsplwr);
6185 return;
6188 /****************************************************************************
6189 Reply to a mkdir.
6190 ****************************************************************************/
6192 void reply_mkdir(struct smb_request *req)
6194 connection_struct *conn = req->conn;
6195 struct smb_filename *smb_dname = NULL;
6196 char *directory = NULL;
6197 NTSTATUS status;
6198 uint32_t ucf_flags;
6199 TALLOC_CTX *ctx = talloc_tos();
6201 START_PROFILE(SMBmkdir);
6203 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6204 STR_TERMINATE, &status);
6205 if (!NT_STATUS_IS_OK(status)) {
6206 reply_nterror(req, status);
6207 goto out;
6210 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6211 status = filename_convert(ctx, conn,
6212 directory,
6213 ucf_flags,
6214 NULL,
6215 NULL,
6216 &smb_dname);
6217 if (!NT_STATUS_IS_OK(status)) {
6218 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6219 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6220 ERRSRV, ERRbadpath);
6221 goto out;
6223 reply_nterror(req, status);
6224 goto out;
6227 status = create_directory(conn, req, smb_dname);
6229 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6231 if (!NT_STATUS_IS_OK(status)) {
6233 if (!use_nt_status()
6234 && NT_STATUS_EQUAL(status,
6235 NT_STATUS_OBJECT_NAME_COLLISION)) {
6237 * Yes, in the DOS error code case we get a
6238 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6239 * samba4 torture test.
6241 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6244 reply_nterror(req, status);
6245 goto out;
6248 reply_outbuf(req, 0, 0);
6250 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6251 out:
6252 TALLOC_FREE(smb_dname);
6253 END_PROFILE(SMBmkdir);
6254 return;
6257 /****************************************************************************
6258 Reply to a rmdir.
6259 ****************************************************************************/
6261 void reply_rmdir(struct smb_request *req)
6263 connection_struct *conn = req->conn;
6264 struct smb_filename *smb_dname = NULL;
6265 char *directory = NULL;
6266 NTSTATUS status;
6267 TALLOC_CTX *ctx = talloc_tos();
6268 files_struct *fsp = NULL;
6269 int info = 0;
6270 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6271 struct smbd_server_connection *sconn = req->sconn;
6273 START_PROFILE(SMBrmdir);
6275 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6276 STR_TERMINATE, &status);
6277 if (!NT_STATUS_IS_OK(status)) {
6278 reply_nterror(req, status);
6279 goto out;
6282 status = filename_convert(ctx, conn,
6283 directory,
6284 ucf_flags,
6285 NULL,
6286 NULL,
6287 &smb_dname);
6288 if (!NT_STATUS_IS_OK(status)) {
6289 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6290 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6291 ERRSRV, ERRbadpath);
6292 goto out;
6294 reply_nterror(req, status);
6295 goto out;
6298 if (is_ntfs_stream_smb_fname(smb_dname)) {
6299 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6300 goto out;
6303 status = SMB_VFS_CREATE_FILE(
6304 conn, /* conn */
6305 req, /* req */
6306 0, /* root_dir_fid */
6307 smb_dname, /* fname */
6308 DELETE_ACCESS, /* access_mask */
6309 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6310 FILE_SHARE_DELETE),
6311 FILE_OPEN, /* create_disposition*/
6312 FILE_DIRECTORY_FILE, /* create_options */
6313 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6314 0, /* oplock_request */
6315 NULL, /* lease */
6316 0, /* allocation_size */
6317 0, /* private_flags */
6318 NULL, /* sd */
6319 NULL, /* ea_list */
6320 &fsp, /* result */
6321 &info, /* pinfo */
6322 NULL, NULL); /* create context */
6324 if (!NT_STATUS_IS_OK(status)) {
6325 if (open_was_deferred(req->xconn, req->mid)) {
6326 /* We have re-scheduled this call. */
6327 goto out;
6329 reply_nterror(req, status);
6330 goto out;
6333 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6334 if (!NT_STATUS_IS_OK(status)) {
6335 close_file(req, fsp, ERROR_CLOSE);
6336 reply_nterror(req, status);
6337 goto out;
6340 if (!set_delete_on_close(fsp, true,
6341 conn->session_info->security_token,
6342 conn->session_info->unix_token)) {
6343 close_file(req, fsp, ERROR_CLOSE);
6344 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6345 goto out;
6348 status = close_file(req, fsp, NORMAL_CLOSE);
6349 if (!NT_STATUS_IS_OK(status)) {
6350 reply_nterror(req, status);
6351 } else {
6352 reply_outbuf(req, 0, 0);
6355 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6357 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6358 out:
6359 TALLOC_FREE(smb_dname);
6360 END_PROFILE(SMBrmdir);
6361 return;
6364 /*******************************************************************
6365 Resolve wildcards in a filename rename.
6366 ********************************************************************/
6368 static bool resolve_wildcards(TALLOC_CTX *ctx,
6369 const char *name1,
6370 const char *name2,
6371 char **pp_newname)
6373 char *name2_copy = NULL;
6374 char *root1 = NULL;
6375 char *root2 = NULL;
6376 char *ext1 = NULL;
6377 char *ext2 = NULL;
6378 char *p,*p2, *pname1, *pname2;
6380 name2_copy = talloc_strdup(ctx, name2);
6381 if (!name2_copy) {
6382 return False;
6385 pname1 = strrchr_m(name1,'/');
6386 pname2 = strrchr_m(name2_copy,'/');
6388 if (!pname1 || !pname2) {
6389 return False;
6392 /* Truncate the copy of name2 at the last '/' */
6393 *pname2 = '\0';
6395 /* Now go past the '/' */
6396 pname1++;
6397 pname2++;
6399 root1 = talloc_strdup(ctx, pname1);
6400 root2 = talloc_strdup(ctx, pname2);
6402 if (!root1 || !root2) {
6403 return False;
6406 p = strrchr_m(root1,'.');
6407 if (p) {
6408 *p = 0;
6409 ext1 = talloc_strdup(ctx, p+1);
6410 } else {
6411 ext1 = talloc_strdup(ctx, "");
6413 p = strrchr_m(root2,'.');
6414 if (p) {
6415 *p = 0;
6416 ext2 = talloc_strdup(ctx, p+1);
6417 } else {
6418 ext2 = talloc_strdup(ctx, "");
6421 if (!ext1 || !ext2) {
6422 return False;
6425 p = root1;
6426 p2 = root2;
6427 while (*p2) {
6428 if (*p2 == '?') {
6429 /* Hmmm. Should this be mb-aware ? */
6430 *p2 = *p;
6431 p2++;
6432 } else if (*p2 == '*') {
6433 *p2 = '\0';
6434 root2 = talloc_asprintf(ctx, "%s%s",
6435 root2,
6437 if (!root2) {
6438 return False;
6440 break;
6441 } else {
6442 p2++;
6444 if (*p) {
6445 p++;
6449 p = ext1;
6450 p2 = ext2;
6451 while (*p2) {
6452 if (*p2 == '?') {
6453 /* Hmmm. Should this be mb-aware ? */
6454 *p2 = *p;
6455 p2++;
6456 } else if (*p2 == '*') {
6457 *p2 = '\0';
6458 ext2 = talloc_asprintf(ctx, "%s%s",
6459 ext2,
6461 if (!ext2) {
6462 return False;
6464 break;
6465 } else {
6466 p2++;
6468 if (*p) {
6469 p++;
6473 if (*ext2) {
6474 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6475 name2_copy,
6476 root2,
6477 ext2);
6478 } else {
6479 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6480 name2_copy,
6481 root2);
6484 if (!*pp_newname) {
6485 return False;
6488 return True;
6491 /****************************************************************************
6492 Ensure open files have their names updated. Updated to notify other smbd's
6493 asynchronously.
6494 ****************************************************************************/
6496 static void rename_open_files(connection_struct *conn,
6497 struct share_mode_lock *lck,
6498 struct file_id id,
6499 uint32_t orig_name_hash,
6500 const struct smb_filename *smb_fname_dst)
6502 files_struct *fsp;
6503 bool did_rename = False;
6504 NTSTATUS status;
6505 uint32_t new_name_hash = 0;
6507 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6508 fsp = file_find_di_next(fsp)) {
6509 /* fsp_name is a relative path under the fsp. To change this for other
6510 sharepaths we need to manipulate relative paths. */
6511 /* TODO - create the absolute path and manipulate the newname
6512 relative to the sharepath. */
6513 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6514 continue;
6516 if (fsp->name_hash != orig_name_hash) {
6517 continue;
6519 DEBUG(10, ("rename_open_files: renaming file %s "
6520 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6521 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6522 smb_fname_str_dbg(smb_fname_dst)));
6524 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6525 if (NT_STATUS_IS_OK(status)) {
6526 did_rename = True;
6527 new_name_hash = fsp->name_hash;
6531 if (!did_rename) {
6532 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6533 "for %s\n", file_id_string_tos(&id),
6534 smb_fname_str_dbg(smb_fname_dst)));
6537 /* Send messages to all smbd's (not ourself) that the name has changed. */
6538 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6539 orig_name_hash, new_name_hash,
6540 smb_fname_dst);
6544 /****************************************************************************
6545 We need to check if the source path is a parent directory of the destination
6546 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6547 refuse the rename with a sharing violation. Under UNIX the above call can
6548 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6549 probably need to check that the client is a Windows one before disallowing
6550 this as a UNIX client (one with UNIX extensions) can know the source is a
6551 symlink and make this decision intelligently. Found by an excellent bug
6552 report from <AndyLiebman@aol.com>.
6553 ****************************************************************************/
6555 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6556 const struct smb_filename *smb_fname_dst)
6558 const char *psrc = smb_fname_src->base_name;
6559 const char *pdst = smb_fname_dst->base_name;
6560 size_t slen;
6562 if (psrc[0] == '.' && psrc[1] == '/') {
6563 psrc += 2;
6565 if (pdst[0] == '.' && pdst[1] == '/') {
6566 pdst += 2;
6568 if ((slen = strlen(psrc)) > strlen(pdst)) {
6569 return False;
6571 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6575 * Do the notify calls from a rename
6578 static void notify_rename(connection_struct *conn, bool is_dir,
6579 const struct smb_filename *smb_fname_src,
6580 const struct smb_filename *smb_fname_dst)
6582 char *parent_dir_src = NULL;
6583 char *parent_dir_dst = NULL;
6584 uint32_t mask;
6586 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6587 : FILE_NOTIFY_CHANGE_FILE_NAME;
6589 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6590 &parent_dir_src, NULL) ||
6591 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6592 &parent_dir_dst, NULL)) {
6593 goto out;
6596 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6597 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6598 smb_fname_src->base_name);
6599 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6600 smb_fname_dst->base_name);
6602 else {
6603 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6604 smb_fname_src->base_name);
6605 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6606 smb_fname_dst->base_name);
6609 /* this is a strange one. w2k3 gives an additional event for
6610 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6611 files, but not directories */
6612 if (!is_dir) {
6613 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6614 FILE_NOTIFY_CHANGE_ATTRIBUTES
6615 |FILE_NOTIFY_CHANGE_CREATION,
6616 smb_fname_dst->base_name);
6618 out:
6619 TALLOC_FREE(parent_dir_src);
6620 TALLOC_FREE(parent_dir_dst);
6623 /****************************************************************************
6624 Returns an error if the parent directory for a filename is open in an
6625 incompatible way.
6626 ****************************************************************************/
6628 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6629 const struct smb_filename *smb_fname_dst_in)
6631 char *parent_dir = NULL;
6632 struct smb_filename smb_fname_parent;
6633 struct file_id id;
6634 files_struct *fsp = NULL;
6635 int ret;
6637 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6638 &parent_dir, NULL)) {
6639 return NT_STATUS_NO_MEMORY;
6641 ZERO_STRUCT(smb_fname_parent);
6642 smb_fname_parent.base_name = parent_dir;
6644 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6645 if (ret == -1) {
6646 return map_nt_error_from_unix(errno);
6650 * We're only checking on this smbd here, mostly good
6651 * enough.. and will pass tests.
6654 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6655 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6656 fsp = file_find_di_next(fsp)) {
6657 if (fsp->access_mask & DELETE_ACCESS) {
6658 return NT_STATUS_SHARING_VIOLATION;
6661 return NT_STATUS_OK;
6664 /****************************************************************************
6665 Rename an open file - given an fsp.
6666 ****************************************************************************/
6668 NTSTATUS rename_internals_fsp(connection_struct *conn,
6669 files_struct *fsp,
6670 const struct smb_filename *smb_fname_dst_in,
6671 uint32_t attrs,
6672 bool replace_if_exists)
6674 TALLOC_CTX *ctx = talloc_tos();
6675 struct smb_filename *smb_fname_dst = NULL;
6676 NTSTATUS status = NT_STATUS_OK;
6677 struct share_mode_lock *lck = NULL;
6678 uint32_t access_mask = SEC_DIR_ADD_FILE;
6679 bool dst_exists, old_is_stream, new_is_stream;
6681 status = check_name(conn, smb_fname_dst_in);
6682 if (!NT_STATUS_IS_OK(status)) {
6683 return status;
6686 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6687 if (!NT_STATUS_IS_OK(status)) {
6688 return status;
6691 if (file_has_open_streams(fsp)) {
6692 return NT_STATUS_ACCESS_DENIED;
6695 /* Make a copy of the dst smb_fname structs */
6697 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6698 if (smb_fname_dst == NULL) {
6699 status = NT_STATUS_NO_MEMORY;
6700 goto out;
6704 * Check for special case with case preserving and not
6705 * case sensitive. If the new last component differs from the original
6706 * last component only by case, then we should allow
6707 * the rename (user is trying to change the case of the
6708 * filename).
6710 if (!conn->case_sensitive && conn->case_preserve &&
6711 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6712 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6713 char *fname_dst_parent = NULL;
6714 const char *fname_dst_lcomp = NULL;
6715 char *orig_lcomp_path = NULL;
6716 char *orig_lcomp_stream = NULL;
6717 bool ok = true;
6720 * Split off the last component of the processed
6721 * destination name. We will compare this to
6722 * the split components of smb_fname_dst->original_lcomp.
6724 if (!parent_dirname(ctx,
6725 smb_fname_dst->base_name,
6726 &fname_dst_parent,
6727 &fname_dst_lcomp)) {
6728 status = NT_STATUS_NO_MEMORY;
6729 goto out;
6733 * The original_lcomp component contains
6734 * the last_component of the path + stream
6735 * name (if a stream exists).
6737 * Split off the stream name so we
6738 * can check them separately.
6741 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6742 /* POSIX - no stream component. */
6743 orig_lcomp_path = talloc_strdup(ctx,
6744 smb_fname_dst->original_lcomp);
6745 if (orig_lcomp_path == NULL) {
6746 ok = false;
6748 } else {
6749 ok = split_stream_filename(ctx,
6750 smb_fname_dst->original_lcomp,
6751 &orig_lcomp_path,
6752 &orig_lcomp_stream);
6755 if (!ok) {
6756 TALLOC_FREE(fname_dst_parent);
6757 status = NT_STATUS_NO_MEMORY;
6758 goto out;
6761 /* If the base names only differ by case, use original. */
6762 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6763 char *tmp;
6765 * Replace the modified last component with the
6766 * original.
6768 if (!ISDOT(fname_dst_parent)) {
6769 tmp = talloc_asprintf(smb_fname_dst,
6770 "%s/%s",
6771 fname_dst_parent,
6772 orig_lcomp_path);
6773 } else {
6774 tmp = talloc_strdup(smb_fname_dst,
6775 orig_lcomp_path);
6777 if (tmp == NULL) {
6778 status = NT_STATUS_NO_MEMORY;
6779 TALLOC_FREE(fname_dst_parent);
6780 TALLOC_FREE(orig_lcomp_path);
6781 TALLOC_FREE(orig_lcomp_stream);
6782 goto out;
6784 TALLOC_FREE(smb_fname_dst->base_name);
6785 smb_fname_dst->base_name = tmp;
6788 /* If the stream_names only differ by case, use original. */
6789 if(!strcsequal(smb_fname_dst->stream_name,
6790 orig_lcomp_stream)) {
6791 /* Use the original stream. */
6792 char *tmp = talloc_strdup(smb_fname_dst,
6793 orig_lcomp_stream);
6794 if (tmp == NULL) {
6795 status = NT_STATUS_NO_MEMORY;
6796 TALLOC_FREE(fname_dst_parent);
6797 TALLOC_FREE(orig_lcomp_path);
6798 TALLOC_FREE(orig_lcomp_stream);
6799 goto out;
6801 TALLOC_FREE(smb_fname_dst->stream_name);
6802 smb_fname_dst->stream_name = tmp;
6804 TALLOC_FREE(fname_dst_parent);
6805 TALLOC_FREE(orig_lcomp_path);
6806 TALLOC_FREE(orig_lcomp_stream);
6810 * If the src and dest names are identical - including case,
6811 * don't do the rename, just return success.
6814 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6815 strcsequal(fsp->fsp_name->stream_name,
6816 smb_fname_dst->stream_name)) {
6817 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6818 "- returning success\n",
6819 smb_fname_str_dbg(smb_fname_dst)));
6820 status = NT_STATUS_OK;
6821 goto out;
6824 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6825 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6827 /* Return the correct error code if both names aren't streams. */
6828 if (!old_is_stream && new_is_stream) {
6829 status = NT_STATUS_OBJECT_NAME_INVALID;
6830 goto out;
6833 if (old_is_stream && !new_is_stream) {
6834 status = NT_STATUS_INVALID_PARAMETER;
6835 goto out;
6838 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6840 if(!replace_if_exists && dst_exists) {
6841 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6842 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6843 smb_fname_str_dbg(smb_fname_dst)));
6844 status = NT_STATUS_OBJECT_NAME_COLLISION;
6845 goto out;
6848 if (dst_exists) {
6849 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6850 &smb_fname_dst->st);
6851 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6852 fileid);
6853 /* The file can be open when renaming a stream */
6854 if (dst_fsp && !new_is_stream) {
6855 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6856 status = NT_STATUS_ACCESS_DENIED;
6857 goto out;
6861 /* Ensure we have a valid stat struct for the source. */
6862 status = vfs_stat_fsp(fsp);
6863 if (!NT_STATUS_IS_OK(status)) {
6864 goto out;
6867 status = can_rename(conn, fsp, attrs);
6869 if (!NT_STATUS_IS_OK(status)) {
6870 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6871 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6872 smb_fname_str_dbg(smb_fname_dst)));
6873 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6874 status = NT_STATUS_ACCESS_DENIED;
6875 goto out;
6878 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6879 status = NT_STATUS_ACCESS_DENIED;
6880 goto out;
6883 /* Do we have rights to move into the destination ? */
6884 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
6885 /* We're moving a directory. */
6886 access_mask = SEC_DIR_ADD_SUBDIR;
6888 status = check_parent_access(conn,
6889 smb_fname_dst,
6890 access_mask);
6891 if (!NT_STATUS_IS_OK(status)) {
6892 DBG_INFO("check_parent_access on "
6893 "dst %s returned %s\n",
6894 smb_fname_str_dbg(smb_fname_dst),
6895 nt_errstr(status));
6896 goto out;
6899 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6902 * We have the file open ourselves, so not being able to get the
6903 * corresponding share mode lock is a fatal error.
6906 SMB_ASSERT(lck != NULL);
6908 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6909 uint32_t create_options = fsp->fh->private_options;
6911 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6912 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6913 smb_fname_str_dbg(smb_fname_dst)));
6915 if (!fsp->is_directory &&
6916 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6917 (lp_map_archive(SNUM(conn)) ||
6918 lp_store_dos_attributes(SNUM(conn)))) {
6919 /* We must set the archive bit on the newly
6920 renamed file. */
6921 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6922 uint32_t old_dosmode = dos_mode(conn,
6923 smb_fname_dst);
6924 file_set_dosmode(conn,
6925 smb_fname_dst,
6926 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6927 NULL,
6928 true);
6932 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6933 smb_fname_dst);
6935 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6936 smb_fname_dst);
6939 * A rename acts as a new file create w.r.t. allowing an initial delete
6940 * on close, probably because in Windows there is a new handle to the
6941 * new file. If initial delete on close was requested but not
6942 * originally set, we need to set it here. This is probably not 100% correct,
6943 * but will work for the CIFSFS client which in non-posix mode
6944 * depends on these semantics. JRA.
6947 if (create_options & FILE_DELETE_ON_CLOSE) {
6948 status = can_set_delete_on_close(fsp, 0);
6950 if (NT_STATUS_IS_OK(status)) {
6951 /* Note that here we set the *initial* delete on close flag,
6952 * not the regular one. The magic gets handled in close. */
6953 fsp->initial_delete_on_close = True;
6956 TALLOC_FREE(lck);
6957 status = NT_STATUS_OK;
6958 goto out;
6961 TALLOC_FREE(lck);
6963 if (errno == ENOTDIR || errno == EISDIR) {
6964 status = NT_STATUS_OBJECT_NAME_COLLISION;
6965 } else {
6966 status = map_nt_error_from_unix(errno);
6969 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6970 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6971 smb_fname_str_dbg(smb_fname_dst)));
6973 out:
6974 TALLOC_FREE(smb_fname_dst);
6976 return status;
6979 /****************************************************************************
6980 The guts of the rename command, split out so it may be called by the NT SMB
6981 code.
6982 ****************************************************************************/
6984 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6985 connection_struct *conn,
6986 struct smb_request *req,
6987 struct smb_filename *smb_fname_src,
6988 struct smb_filename *smb_fname_dst,
6989 uint32_t attrs,
6990 bool replace_if_exists,
6991 bool src_has_wild,
6992 bool dest_has_wild,
6993 uint32_t access_mask)
6995 char *fname_src_dir = NULL;
6996 struct smb_filename *smb_fname_src_dir = NULL;
6997 char *fname_src_mask = NULL;
6998 int count=0;
6999 NTSTATUS status = NT_STATUS_OK;
7000 struct smb_Dir *dir_hnd = NULL;
7001 const char *dname = NULL;
7002 char *talloced = NULL;
7003 long offset = 0;
7004 int create_options = 0;
7005 bool posix_pathnames = (req != NULL && req->posix_pathnames);
7006 int rc;
7009 * Split the old name into directory and last component
7010 * strings. Note that unix_convert may have stripped off a
7011 * leading ./ from both name and newname if the rename is
7012 * at the root of the share. We need to make sure either both
7013 * name and newname contain a / character or neither of them do
7014 * as this is checked in resolve_wildcards().
7017 /* Split up the directory from the filename/mask. */
7018 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7019 &fname_src_dir, &fname_src_mask);
7020 if (!NT_STATUS_IS_OK(status)) {
7021 status = NT_STATUS_NO_MEMORY;
7022 goto out;
7026 * We should only check the mangled cache
7027 * here if unix_convert failed. This means
7028 * that the path in 'mask' doesn't exist
7029 * on the file system and so we need to look
7030 * for a possible mangle. This patch from
7031 * Tine Smukavec <valentin.smukavec@hermes.si>.
7034 if (!VALID_STAT(smb_fname_src->st) &&
7035 mangle_is_mangled(fname_src_mask, conn->params)) {
7036 char *new_mask = NULL;
7037 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
7038 conn->params);
7039 if (new_mask) {
7040 TALLOC_FREE(fname_src_mask);
7041 fname_src_mask = new_mask;
7045 if (!src_has_wild) {
7046 files_struct *fsp;
7049 * Only one file needs to be renamed. Append the mask back
7050 * onto the directory.
7052 TALLOC_FREE(smb_fname_src->base_name);
7053 if (ISDOT(fname_src_dir)) {
7054 /* Ensure we use canonical names on open. */
7055 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7056 "%s",
7057 fname_src_mask);
7058 } else {
7059 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7060 "%s/%s",
7061 fname_src_dir,
7062 fname_src_mask);
7064 if (!smb_fname_src->base_name) {
7065 status = NT_STATUS_NO_MEMORY;
7066 goto out;
7069 DEBUG(3, ("rename_internals: case_sensitive = %d, "
7070 "case_preserve = %d, short case preserve = %d, "
7071 "directory = %s, newname = %s, "
7072 "last_component_dest = %s\n",
7073 conn->case_sensitive, conn->case_preserve,
7074 conn->short_case_preserve,
7075 smb_fname_str_dbg(smb_fname_src),
7076 smb_fname_str_dbg(smb_fname_dst),
7077 smb_fname_dst->original_lcomp));
7079 /* The dest name still may have wildcards. */
7080 if (dest_has_wild) {
7081 char *fname_dst_mod = NULL;
7082 if (!resolve_wildcards(smb_fname_dst,
7083 smb_fname_src->base_name,
7084 smb_fname_dst->base_name,
7085 &fname_dst_mod)) {
7086 DEBUG(6, ("rename_internals: resolve_wildcards "
7087 "%s %s failed\n",
7088 smb_fname_src->base_name,
7089 smb_fname_dst->base_name));
7090 status = NT_STATUS_NO_MEMORY;
7091 goto out;
7093 TALLOC_FREE(smb_fname_dst->base_name);
7094 smb_fname_dst->base_name = fname_dst_mod;
7097 ZERO_STRUCT(smb_fname_src->st);
7098 if (posix_pathnames) {
7099 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7100 } else {
7101 rc = SMB_VFS_STAT(conn, smb_fname_src);
7103 if (rc == -1) {
7104 status = map_nt_error_from_unix_common(errno);
7105 goto out;
7108 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7109 create_options |= FILE_DIRECTORY_FILE;
7112 status = SMB_VFS_CREATE_FILE(
7113 conn, /* conn */
7114 req, /* req */
7115 0, /* root_dir_fid */
7116 smb_fname_src, /* fname */
7117 access_mask, /* access_mask */
7118 (FILE_SHARE_READ | /* share_access */
7119 FILE_SHARE_WRITE),
7120 FILE_OPEN, /* create_disposition*/
7121 create_options, /* create_options */
7122 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7123 0, /* oplock_request */
7124 NULL, /* lease */
7125 0, /* allocation_size */
7126 0, /* private_flags */
7127 NULL, /* sd */
7128 NULL, /* ea_list */
7129 &fsp, /* result */
7130 NULL, /* pinfo */
7131 NULL, NULL); /* create context */
7133 if (!NT_STATUS_IS_OK(status)) {
7134 DEBUG(3, ("Could not open rename source %s: %s\n",
7135 smb_fname_str_dbg(smb_fname_src),
7136 nt_errstr(status)));
7137 goto out;
7140 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7141 attrs, replace_if_exists);
7143 close_file(req, fsp, NORMAL_CLOSE);
7145 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7146 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7147 smb_fname_str_dbg(smb_fname_dst)));
7149 goto out;
7153 * Wildcards - process each file that matches.
7155 if (strequal(fname_src_mask, "????????.???")) {
7156 TALLOC_FREE(fname_src_mask);
7157 fname_src_mask = talloc_strdup(ctx, "*");
7158 if (!fname_src_mask) {
7159 status = NT_STATUS_NO_MEMORY;
7160 goto out;
7164 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7165 fname_src_dir,
7166 NULL,
7167 NULL,
7168 smb_fname_src->flags);
7169 if (smb_fname_src_dir == NULL) {
7170 status = NT_STATUS_NO_MEMORY;
7171 goto out;
7174 status = check_name(conn, smb_fname_src_dir);
7175 if (!NT_STATUS_IS_OK(status)) {
7176 goto out;
7179 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7180 attrs);
7181 if (dir_hnd == NULL) {
7182 status = map_nt_error_from_unix(errno);
7183 goto out;
7186 status = NT_STATUS_NO_SUCH_FILE;
7188 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7189 * - gentest fix. JRA
7192 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7193 &talloced))) {
7194 files_struct *fsp = NULL;
7195 char *destname = NULL;
7196 bool sysdir_entry = False;
7198 /* Quick check for "." and ".." */
7199 if (ISDOT(dname) || ISDOTDOT(dname)) {
7200 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7201 sysdir_entry = True;
7202 } else {
7203 TALLOC_FREE(talloced);
7204 continue;
7208 if (!is_visible_file(conn, fname_src_dir, dname,
7209 &smb_fname_src->st, false)) {
7210 TALLOC_FREE(talloced);
7211 continue;
7214 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7215 TALLOC_FREE(talloced);
7216 continue;
7219 if (sysdir_entry) {
7220 status = NT_STATUS_OBJECT_NAME_INVALID;
7221 break;
7224 TALLOC_FREE(smb_fname_src->base_name);
7225 if (ISDOT(fname_src_dir)) {
7226 /* Ensure we use canonical names on open. */
7227 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7228 "%s",
7229 dname);
7230 } else {
7231 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7232 "%s/%s",
7233 fname_src_dir,
7234 dname);
7236 if (!smb_fname_src->base_name) {
7237 status = NT_STATUS_NO_MEMORY;
7238 goto out;
7241 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7242 smb_fname_dst->base_name,
7243 &destname)) {
7244 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7245 smb_fname_src->base_name, destname));
7246 TALLOC_FREE(talloced);
7247 continue;
7249 if (!destname) {
7250 status = NT_STATUS_NO_MEMORY;
7251 goto out;
7254 TALLOC_FREE(smb_fname_dst->base_name);
7255 smb_fname_dst->base_name = destname;
7257 ZERO_STRUCT(smb_fname_src->st);
7258 if (posix_pathnames) {
7259 SMB_VFS_LSTAT(conn, smb_fname_src);
7260 } else {
7261 SMB_VFS_STAT(conn, smb_fname_src);
7264 create_options = 0;
7266 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7267 create_options |= FILE_DIRECTORY_FILE;
7270 status = SMB_VFS_CREATE_FILE(
7271 conn, /* conn */
7272 req, /* req */
7273 0, /* root_dir_fid */
7274 smb_fname_src, /* fname */
7275 access_mask, /* access_mask */
7276 (FILE_SHARE_READ | /* share_access */
7277 FILE_SHARE_WRITE),
7278 FILE_OPEN, /* create_disposition*/
7279 create_options, /* create_options */
7280 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7281 0, /* oplock_request */
7282 NULL, /* lease */
7283 0, /* allocation_size */
7284 0, /* private_flags */
7285 NULL, /* sd */
7286 NULL, /* ea_list */
7287 &fsp, /* result */
7288 NULL, /* pinfo */
7289 NULL, NULL); /* create context */
7291 if (!NT_STATUS_IS_OK(status)) {
7292 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7293 "returned %s rename %s -> %s\n",
7294 nt_errstr(status),
7295 smb_fname_str_dbg(smb_fname_src),
7296 smb_fname_str_dbg(smb_fname_dst)));
7297 break;
7300 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7301 dname);
7302 if (!smb_fname_dst->original_lcomp) {
7303 status = NT_STATUS_NO_MEMORY;
7304 goto out;
7307 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7308 attrs, replace_if_exists);
7310 close_file(req, fsp, NORMAL_CLOSE);
7312 if (!NT_STATUS_IS_OK(status)) {
7313 DEBUG(3, ("rename_internals_fsp returned %s for "
7314 "rename %s -> %s\n", nt_errstr(status),
7315 smb_fname_str_dbg(smb_fname_src),
7316 smb_fname_str_dbg(smb_fname_dst)));
7317 break;
7320 count++;
7322 DEBUG(3,("rename_internals: doing rename on %s -> "
7323 "%s\n", smb_fname_str_dbg(smb_fname_src),
7324 smb_fname_str_dbg(smb_fname_src)));
7325 TALLOC_FREE(talloced);
7327 TALLOC_FREE(dir_hnd);
7329 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7330 status = map_nt_error_from_unix(errno);
7333 out:
7334 TALLOC_FREE(talloced);
7335 TALLOC_FREE(smb_fname_src_dir);
7336 TALLOC_FREE(fname_src_dir);
7337 TALLOC_FREE(fname_src_mask);
7338 return status;
7341 /****************************************************************************
7342 Reply to a mv.
7343 ****************************************************************************/
7345 void reply_mv(struct smb_request *req)
7347 connection_struct *conn = req->conn;
7348 char *name = NULL;
7349 char *newname = NULL;
7350 const char *p;
7351 uint32_t attrs;
7352 NTSTATUS status;
7353 bool src_has_wcard = False;
7354 bool dest_has_wcard = False;
7355 TALLOC_CTX *ctx = talloc_tos();
7356 struct smb_filename *smb_fname_src = NULL;
7357 struct smb_filename *smb_fname_dst = NULL;
7358 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
7359 (req->posix_pathnames ?
7360 UCF_UNIX_NAME_LOOKUP :
7361 UCF_COND_ALLOW_WCARD_LCOMP);
7362 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
7363 UCF_SAVE_LCOMP |
7364 (req->posix_pathnames ?
7366 UCF_COND_ALLOW_WCARD_LCOMP);
7367 bool stream_rename = false;
7369 START_PROFILE(SMBmv);
7371 if (req->wct < 1) {
7372 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7373 goto out;
7376 attrs = SVAL(req->vwv+0, 0);
7378 p = (const char *)req->buf + 1;
7379 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7380 &status, &src_has_wcard);
7381 if (!NT_STATUS_IS_OK(status)) {
7382 reply_nterror(req, status);
7383 goto out;
7385 p++;
7386 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7387 &status, &dest_has_wcard);
7388 if (!NT_STATUS_IS_OK(status)) {
7389 reply_nterror(req, status);
7390 goto out;
7393 if (!req->posix_pathnames) {
7394 /* The newname must begin with a ':' if the
7395 name contains a ':'. */
7396 if (strchr_m(name, ':')) {
7397 if (newname[0] != ':') {
7398 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7399 goto out;
7401 stream_rename = true;
7405 status = filename_convert(ctx,
7406 conn,
7407 name,
7408 src_ucf_flags,
7409 NULL,
7410 &src_has_wcard,
7411 &smb_fname_src);
7413 if (!NT_STATUS_IS_OK(status)) {
7414 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7415 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7416 ERRSRV, ERRbadpath);
7417 goto out;
7419 reply_nterror(req, status);
7420 goto out;
7423 status = filename_convert(ctx,
7424 conn,
7425 newname,
7426 dst_ucf_flags,
7427 NULL,
7428 &dest_has_wcard,
7429 &smb_fname_dst);
7431 if (!NT_STATUS_IS_OK(status)) {
7432 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7433 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7434 ERRSRV, ERRbadpath);
7435 goto out;
7437 reply_nterror(req, status);
7438 goto out;
7441 if (stream_rename) {
7442 /* smb_fname_dst->base_name must be the same as
7443 smb_fname_src->base_name. */
7444 TALLOC_FREE(smb_fname_dst->base_name);
7445 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7446 smb_fname_src->base_name);
7447 if (!smb_fname_dst->base_name) {
7448 reply_nterror(req, NT_STATUS_NO_MEMORY);
7449 goto out;
7453 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7454 smb_fname_str_dbg(smb_fname_dst)));
7456 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7457 attrs, False, src_has_wcard, dest_has_wcard,
7458 DELETE_ACCESS);
7459 if (!NT_STATUS_IS_OK(status)) {
7460 if (open_was_deferred(req->xconn, req->mid)) {
7461 /* We have re-scheduled this call. */
7462 goto out;
7464 reply_nterror(req, status);
7465 goto out;
7468 reply_outbuf(req, 0, 0);
7469 out:
7470 TALLOC_FREE(smb_fname_src);
7471 TALLOC_FREE(smb_fname_dst);
7472 END_PROFILE(SMBmv);
7473 return;
7476 /*******************************************************************
7477 Copy a file as part of a reply_copy.
7478 ******************************************************************/
7481 * TODO: check error codes on all callers
7484 NTSTATUS copy_file(TALLOC_CTX *ctx,
7485 connection_struct *conn,
7486 struct smb_filename *smb_fname_src,
7487 struct smb_filename *smb_fname_dst,
7488 int ofun,
7489 int count,
7490 bool target_is_directory)
7492 struct smb_filename *smb_fname_dst_tmp = NULL;
7493 off_t ret=-1;
7494 files_struct *fsp1,*fsp2;
7495 uint32_t dosattrs;
7496 uint32_t new_create_disposition;
7497 NTSTATUS status;
7500 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7501 if (smb_fname_dst_tmp == NULL) {
7502 return NT_STATUS_NO_MEMORY;
7506 * If the target is a directory, extract the last component from the
7507 * src filename and append it to the dst filename
7509 if (target_is_directory) {
7510 const char *p;
7512 /* dest/target can't be a stream if it's a directory. */
7513 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7515 p = strrchr_m(smb_fname_src->base_name,'/');
7516 if (p) {
7517 p++;
7518 } else {
7519 p = smb_fname_src->base_name;
7521 smb_fname_dst_tmp->base_name =
7522 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7524 if (!smb_fname_dst_tmp->base_name) {
7525 status = NT_STATUS_NO_MEMORY;
7526 goto out;
7530 status = vfs_file_exist(conn, smb_fname_src);
7531 if (!NT_STATUS_IS_OK(status)) {
7532 goto out;
7535 if (!target_is_directory && count) {
7536 new_create_disposition = FILE_OPEN;
7537 } else {
7538 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7539 0, ofun,
7540 NULL, NULL,
7541 &new_create_disposition,
7542 NULL,
7543 NULL)) {
7544 status = NT_STATUS_INVALID_PARAMETER;
7545 goto out;
7549 /* Open the src file for reading. */
7550 status = SMB_VFS_CREATE_FILE(
7551 conn, /* conn */
7552 NULL, /* req */
7553 0, /* root_dir_fid */
7554 smb_fname_src, /* fname */
7555 FILE_GENERIC_READ, /* access_mask */
7556 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7557 FILE_OPEN, /* create_disposition*/
7558 0, /* create_options */
7559 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7560 INTERNAL_OPEN_ONLY, /* oplock_request */
7561 NULL, /* lease */
7562 0, /* allocation_size */
7563 0, /* private_flags */
7564 NULL, /* sd */
7565 NULL, /* ea_list */
7566 &fsp1, /* result */
7567 NULL, /* psbuf */
7568 NULL, NULL); /* create context */
7570 if (!NT_STATUS_IS_OK(status)) {
7571 goto out;
7574 dosattrs = dos_mode(conn, smb_fname_src);
7576 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7577 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7580 /* Open the dst file for writing. */
7581 status = SMB_VFS_CREATE_FILE(
7582 conn, /* conn */
7583 NULL, /* req */
7584 0, /* root_dir_fid */
7585 smb_fname_dst, /* fname */
7586 FILE_GENERIC_WRITE, /* access_mask */
7587 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7588 new_create_disposition, /* create_disposition*/
7589 0, /* create_options */
7590 dosattrs, /* file_attributes */
7591 INTERNAL_OPEN_ONLY, /* oplock_request */
7592 NULL, /* lease */
7593 0, /* allocation_size */
7594 0, /* private_flags */
7595 NULL, /* sd */
7596 NULL, /* ea_list */
7597 &fsp2, /* result */
7598 NULL, /* psbuf */
7599 NULL, NULL); /* create context */
7601 if (!NT_STATUS_IS_OK(status)) {
7602 close_file(NULL, fsp1, ERROR_CLOSE);
7603 goto out;
7606 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7607 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7608 if (ret == -1) {
7609 DEBUG(0, ("error - vfs lseek returned error %s\n",
7610 strerror(errno)));
7611 status = map_nt_error_from_unix(errno);
7612 close_file(NULL, fsp1, ERROR_CLOSE);
7613 close_file(NULL, fsp2, ERROR_CLOSE);
7614 goto out;
7618 /* Do the actual copy. */
7619 if (smb_fname_src->st.st_ex_size) {
7620 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7621 } else {
7622 ret = 0;
7625 close_file(NULL, fsp1, NORMAL_CLOSE);
7627 /* Ensure the modtime is set correctly on the destination file. */
7628 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7631 * As we are opening fsp1 read-only we only expect
7632 * an error on close on fsp2 if we are out of space.
7633 * Thus we don't look at the error return from the
7634 * close of fsp1.
7636 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7638 if (!NT_STATUS_IS_OK(status)) {
7639 goto out;
7642 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7643 status = NT_STATUS_DISK_FULL;
7644 goto out;
7647 status = NT_STATUS_OK;
7649 out:
7650 TALLOC_FREE(smb_fname_dst_tmp);
7651 return status;
7654 /****************************************************************************
7655 Reply to a file copy.
7656 ****************************************************************************/
7658 void reply_copy(struct smb_request *req)
7660 connection_struct *conn = req->conn;
7661 struct smb_filename *smb_fname_src = NULL;
7662 struct smb_filename *smb_fname_src_dir = NULL;
7663 struct smb_filename *smb_fname_dst = NULL;
7664 char *fname_src = NULL;
7665 char *fname_dst = NULL;
7666 char *fname_src_mask = NULL;
7667 char *fname_src_dir = NULL;
7668 const char *p;
7669 int count=0;
7670 int error = ERRnoaccess;
7671 int tid2;
7672 int ofun;
7673 int flags;
7674 bool target_is_directory=False;
7675 bool source_has_wild = False;
7676 bool dest_has_wild = False;
7677 NTSTATUS status;
7678 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7679 ucf_flags_from_smb_request(req);
7680 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7681 ucf_flags_from_smb_request(req);
7682 TALLOC_CTX *ctx = talloc_tos();
7684 START_PROFILE(SMBcopy);
7686 if (req->wct < 3) {
7687 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7688 goto out;
7691 tid2 = SVAL(req->vwv+0, 0);
7692 ofun = SVAL(req->vwv+1, 0);
7693 flags = SVAL(req->vwv+2, 0);
7695 p = (const char *)req->buf;
7696 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7697 &status, &source_has_wild);
7698 if (!NT_STATUS_IS_OK(status)) {
7699 reply_nterror(req, status);
7700 goto out;
7702 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7703 &status, &dest_has_wild);
7704 if (!NT_STATUS_IS_OK(status)) {
7705 reply_nterror(req, status);
7706 goto out;
7709 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7711 if (tid2 != conn->cnum) {
7712 /* can't currently handle inter share copies XXXX */
7713 DEBUG(3,("Rejecting inter-share copy\n"));
7714 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7715 goto out;
7718 status = filename_convert(ctx, conn,
7719 fname_src,
7720 ucf_flags_src,
7721 NULL,
7722 &source_has_wild,
7723 &smb_fname_src);
7724 if (!NT_STATUS_IS_OK(status)) {
7725 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7726 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7727 ERRSRV, ERRbadpath);
7728 goto out;
7730 reply_nterror(req, status);
7731 goto out;
7734 status = filename_convert(ctx, conn,
7735 fname_dst,
7736 ucf_flags_dst,
7737 NULL,
7738 &dest_has_wild,
7739 &smb_fname_dst);
7740 if (!NT_STATUS_IS_OK(status)) {
7741 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7742 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7743 ERRSRV, ERRbadpath);
7744 goto out;
7746 reply_nterror(req, status);
7747 goto out;
7750 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7752 if ((flags&1) && target_is_directory) {
7753 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7754 goto out;
7757 if ((flags&2) && !target_is_directory) {
7758 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7759 goto out;
7762 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7763 /* wants a tree copy! XXXX */
7764 DEBUG(3,("Rejecting tree copy\n"));
7765 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7766 goto out;
7769 /* Split up the directory from the filename/mask. */
7770 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7771 &fname_src_dir, &fname_src_mask);
7772 if (!NT_STATUS_IS_OK(status)) {
7773 reply_nterror(req, NT_STATUS_NO_MEMORY);
7774 goto out;
7778 * We should only check the mangled cache
7779 * here if unix_convert failed. This means
7780 * that the path in 'mask' doesn't exist
7781 * on the file system and so we need to look
7782 * for a possible mangle. This patch from
7783 * Tine Smukavec <valentin.smukavec@hermes.si>.
7785 if (!VALID_STAT(smb_fname_src->st) &&
7786 mangle_is_mangled(fname_src_mask, conn->params)) {
7787 char *new_mask = NULL;
7788 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7789 &new_mask, conn->params);
7791 /* Use demangled name if one was successfully found. */
7792 if (new_mask) {
7793 TALLOC_FREE(fname_src_mask);
7794 fname_src_mask = new_mask;
7798 if (!source_has_wild) {
7801 * Only one file needs to be copied. Append the mask back onto
7802 * the directory.
7804 TALLOC_FREE(smb_fname_src->base_name);
7805 if (ISDOT(fname_src_dir)) {
7806 /* Ensure we use canonical names on open. */
7807 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7808 "%s",
7809 fname_src_mask);
7810 } else {
7811 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7812 "%s/%s",
7813 fname_src_dir,
7814 fname_src_mask);
7816 if (!smb_fname_src->base_name) {
7817 reply_nterror(req, NT_STATUS_NO_MEMORY);
7818 goto out;
7821 if (dest_has_wild) {
7822 char *fname_dst_mod = NULL;
7823 if (!resolve_wildcards(smb_fname_dst,
7824 smb_fname_src->base_name,
7825 smb_fname_dst->base_name,
7826 &fname_dst_mod)) {
7827 reply_nterror(req, NT_STATUS_NO_MEMORY);
7828 goto out;
7830 TALLOC_FREE(smb_fname_dst->base_name);
7831 smb_fname_dst->base_name = fname_dst_mod;
7834 status = check_name(conn, smb_fname_src);
7835 if (!NT_STATUS_IS_OK(status)) {
7836 reply_nterror(req, status);
7837 goto out;
7840 status = check_name(conn, smb_fname_dst);
7841 if (!NT_STATUS_IS_OK(status)) {
7842 reply_nterror(req, status);
7843 goto out;
7846 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7847 ofun, count, target_is_directory);
7849 if(!NT_STATUS_IS_OK(status)) {
7850 reply_nterror(req, status);
7851 goto out;
7852 } else {
7853 count++;
7855 } else {
7856 struct smb_Dir *dir_hnd = NULL;
7857 const char *dname = NULL;
7858 char *talloced = NULL;
7859 long offset = 0;
7862 * There is a wildcard that requires us to actually read the
7863 * src dir and copy each file matching the mask to the dst.
7864 * Right now streams won't be copied, but this could
7865 * presumably be added with a nested loop for reach dir entry.
7867 SMB_ASSERT(!smb_fname_src->stream_name);
7868 SMB_ASSERT(!smb_fname_dst->stream_name);
7870 smb_fname_src->stream_name = NULL;
7871 smb_fname_dst->stream_name = NULL;
7873 if (strequal(fname_src_mask,"????????.???")) {
7874 TALLOC_FREE(fname_src_mask);
7875 fname_src_mask = talloc_strdup(ctx, "*");
7876 if (!fname_src_mask) {
7877 reply_nterror(req, NT_STATUS_NO_MEMORY);
7878 goto out;
7882 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7883 fname_src_dir,
7884 NULL,
7885 NULL,
7886 smb_fname_src->flags);
7887 if (smb_fname_src_dir == NULL) {
7888 reply_nterror(req, NT_STATUS_NO_MEMORY);
7889 goto out;
7892 status = check_name(conn, smb_fname_src_dir);
7893 if (!NT_STATUS_IS_OK(status)) {
7894 reply_nterror(req, status);
7895 goto out;
7898 dir_hnd = OpenDir(ctx,
7899 conn,
7900 smb_fname_src_dir,
7901 fname_src_mask,
7903 if (dir_hnd == NULL) {
7904 status = map_nt_error_from_unix(errno);
7905 reply_nterror(req, status);
7906 goto out;
7909 error = ERRbadfile;
7911 /* Iterate over the src dir copying each entry to the dst. */
7912 while ((dname = ReadDirName(dir_hnd, &offset,
7913 &smb_fname_src->st, &talloced))) {
7914 char *destname = NULL;
7916 if (ISDOT(dname) || ISDOTDOT(dname)) {
7917 TALLOC_FREE(talloced);
7918 continue;
7921 if (!is_visible_file(conn, fname_src_dir, dname,
7922 &smb_fname_src->st, false)) {
7923 TALLOC_FREE(talloced);
7924 continue;
7927 if(!mask_match(dname, fname_src_mask,
7928 conn->case_sensitive)) {
7929 TALLOC_FREE(talloced);
7930 continue;
7933 error = ERRnoaccess;
7935 /* Get the src smb_fname struct setup. */
7936 TALLOC_FREE(smb_fname_src->base_name);
7937 if (ISDOT(fname_src_dir)) {
7938 /* Ensure we use canonical names on open. */
7939 smb_fname_src->base_name =
7940 talloc_asprintf(smb_fname_src, "%s",
7941 dname);
7942 } else {
7943 smb_fname_src->base_name =
7944 talloc_asprintf(smb_fname_src, "%s/%s",
7945 fname_src_dir, dname);
7948 if (!smb_fname_src->base_name) {
7949 TALLOC_FREE(dir_hnd);
7950 TALLOC_FREE(talloced);
7951 reply_nterror(req, NT_STATUS_NO_MEMORY);
7952 goto out;
7955 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7956 smb_fname_dst->base_name,
7957 &destname)) {
7958 TALLOC_FREE(talloced);
7959 continue;
7961 if (!destname) {
7962 TALLOC_FREE(dir_hnd);
7963 TALLOC_FREE(talloced);
7964 reply_nterror(req, NT_STATUS_NO_MEMORY);
7965 goto out;
7968 TALLOC_FREE(smb_fname_dst->base_name);
7969 smb_fname_dst->base_name = destname;
7971 status = check_name(conn, smb_fname_src);
7972 if (!NT_STATUS_IS_OK(status)) {
7973 TALLOC_FREE(dir_hnd);
7974 TALLOC_FREE(talloced);
7975 reply_nterror(req, status);
7976 goto out;
7979 status = check_name(conn, smb_fname_dst);
7980 if (!NT_STATUS_IS_OK(status)) {
7981 TALLOC_FREE(dir_hnd);
7982 TALLOC_FREE(talloced);
7983 reply_nterror(req, status);
7984 goto out;
7987 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7988 smb_fname_src->base_name,
7989 smb_fname_dst->base_name));
7991 status = copy_file(ctx, conn, smb_fname_src,
7992 smb_fname_dst, ofun, count,
7993 target_is_directory);
7994 if (NT_STATUS_IS_OK(status)) {
7995 count++;
7998 TALLOC_FREE(talloced);
8000 TALLOC_FREE(dir_hnd);
8003 if (count == 0) {
8004 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
8005 goto out;
8008 reply_outbuf(req, 1, 0);
8009 SSVAL(req->outbuf,smb_vwv0,count);
8010 out:
8011 TALLOC_FREE(smb_fname_src);
8012 TALLOC_FREE(smb_fname_src_dir);
8013 TALLOC_FREE(smb_fname_dst);
8014 TALLOC_FREE(fname_src);
8015 TALLOC_FREE(fname_dst);
8016 TALLOC_FREE(fname_src_mask);
8017 TALLOC_FREE(fname_src_dir);
8019 END_PROFILE(SMBcopy);
8020 return;
8023 #undef DBGC_CLASS
8024 #define DBGC_CLASS DBGC_LOCKING
8026 /****************************************************************************
8027 Get a lock pid, dealing with large count requests.
8028 ****************************************************************************/
8030 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
8031 bool large_file_format)
8033 if(!large_file_format)
8034 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
8035 else
8036 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
8039 /****************************************************************************
8040 Get a lock count, dealing with large count requests.
8041 ****************************************************************************/
8043 uint64_t get_lock_count(const uint8_t *data, int data_offset,
8044 bool large_file_format)
8046 uint64_t count = 0;
8048 if(!large_file_format) {
8049 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
8050 } else {
8052 * No BVAL, this is reversed!
8054 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
8055 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
8058 return count;
8061 /****************************************************************************
8062 Get a lock offset, dealing with large offset requests.
8063 ****************************************************************************/
8065 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
8066 bool large_file_format)
8068 uint64_t offset = 0;
8070 if(!large_file_format) {
8071 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
8072 } else {
8074 * No BVAL, this is reversed!
8076 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
8077 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
8080 return offset;
8083 NTSTATUS smbd_do_locking(struct smb_request *req,
8084 files_struct *fsp,
8085 int32_t timeout,
8086 uint16_t num_locks,
8087 struct smbd_lock_element *locks,
8088 bool *async)
8090 connection_struct *conn = req->conn;
8091 int i;
8092 NTSTATUS status = NT_STATUS_OK;
8094 *async = false;
8096 /* Setup the timeout in seconds. */
8098 if (!lp_blocking_locks(SNUM(conn))) {
8099 timeout = 0;
8102 for(i = 0; i < (int)num_locks; i++) {
8103 struct smbd_lock_element *e = &locks[i];
8105 DBG_DEBUG("lock start=%"PRIu64", len=%"PRIu64" for smblctx "
8106 "%"PRIu64", file %s timeout = %"PRIi32"\n",
8107 e->offset,
8108 e->count,
8109 e->smblctx,
8110 fsp_str_dbg(fsp),
8111 timeout);
8114 bool blocking_lock = (timeout != 0);
8115 bool defer_lock = false;
8116 struct byte_range_lock *br_lck;
8117 struct server_id blocker_pid;
8118 uint64_t block_smblctx;
8120 br_lck = do_lock(req->sconn->msg_ctx,
8121 fsp,
8122 e->smblctx,
8123 e->count,
8124 e->offset,
8125 e->brltype,
8126 WINDOWS_LOCK,
8127 blocking_lock,
8128 &status,
8129 &blocker_pid,
8130 &block_smblctx);
8132 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8133 /* Windows internal resolution for blocking locks seems
8134 to be about 200ms... Don't wait for less than that. JRA. */
8135 if (timeout != -1) {
8136 timeout = MAX(timeout, lp_lock_spin_time());
8138 defer_lock = true;
8141 /* If a lock sent with timeout of zero would fail, and
8142 * this lock has been requested multiple times,
8143 * according to brl_lock_failed() we convert this
8144 * request to a blocking lock with a timeout of between
8145 * 150 - 300 milliseconds.
8147 * If lp_lock_spin_time() has been set to 0, we skip
8148 * this blocking retry and fail immediately.
8150 * Replacement for do_lock_spin(). JRA. */
8152 if (!req->sconn->using_smb2 &&
8153 br_lck && lp_blocking_locks(SNUM(conn)) &&
8154 lp_lock_spin_time() && !blocking_lock &&
8155 NT_STATUS_EQUAL((status),
8156 NT_STATUS_FILE_LOCK_CONFLICT))
8158 defer_lock = true;
8159 timeout = lp_lock_spin_time();
8162 if (br_lck && defer_lock) {
8164 * A blocking lock was requested. Package up
8165 * this smb into a queued request and push it
8166 * onto the blocking lock queue.
8168 if(push_blocking_lock_request(br_lck,
8169 req,
8170 fsp,
8171 timeout,
8173 e->smblctx,
8174 e->brltype,
8175 WINDOWS_LOCK,
8176 e->offset,
8177 e->count,
8178 block_smblctx)) {
8179 TALLOC_FREE(br_lck);
8180 *async = true;
8181 return NT_STATUS_OK;
8185 TALLOC_FREE(br_lck);
8188 if (!NT_STATUS_IS_OK(status)) {
8189 break;
8193 /* If any of the above locks failed, then we must unlock
8194 all of the previous locks (X/Open spec). */
8196 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8199 * Ensure we don't do a remove on the lock that just failed,
8200 * as under POSIX rules, if we have a lock already there, we
8201 * will delete it (and we shouldn't) .....
8203 for(i--; i >= 0; i--) {
8204 struct smbd_lock_element *e = &locks[i];
8206 do_unlock(req->sconn->msg_ctx,
8207 fsp,
8208 e->smblctx,
8209 e->count,
8210 e->offset,
8211 WINDOWS_LOCK);
8213 return status;
8216 DBG_NOTICE("%s num_locks=%"PRIu16"\n",
8217 fsp_fnum_dbg(fsp),
8218 num_locks);
8220 return NT_STATUS_OK;
8223 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8224 files_struct *fsp,
8225 uint16_t num_ulocks,
8226 struct smbd_lock_element *ulocks,
8227 enum brl_flavour lock_flav)
8229 uint16_t i;
8231 for(i = 0; i < num_ulocks; i++) {
8232 struct smbd_lock_element *e = &ulocks[i];
8233 NTSTATUS status;
8235 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
8236 "pid %"PRIu64", file %s\n",
8237 e->offset,
8238 e->count,
8239 e->smblctx,
8240 fsp_str_dbg(fsp));
8242 if (e->brltype != UNLOCK_LOCK) {
8243 /* this can only happen with SMB2 */
8244 return NT_STATUS_INVALID_PARAMETER;
8247 status = do_unlock(req->sconn->msg_ctx,
8248 fsp,
8249 e->smblctx,
8250 e->count,
8251 e->offset,
8252 lock_flav);
8254 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8255 nt_errstr(status)));
8257 if (!NT_STATUS_IS_OK(status)) {
8258 return status;
8262 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8263 num_ulocks));
8265 return NT_STATUS_OK;
8268 /****************************************************************************
8269 Reply to a lockingX request.
8270 ****************************************************************************/
8272 void reply_lockingX(struct smb_request *req)
8274 connection_struct *conn = req->conn;
8275 files_struct *fsp;
8276 unsigned char locktype;
8277 enum brl_type brltype;
8278 unsigned char oplocklevel;
8279 uint16_t num_ulocks;
8280 uint16_t num_locks;
8281 int32_t lock_timeout;
8282 uint16_t i;
8283 const uint8_t *data;
8284 bool large_file_format;
8285 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8286 struct smbd_lock_element *ulocks = NULL;
8287 struct smbd_lock_element *locks = NULL;
8288 bool async = false;
8290 START_PROFILE(SMBlockingX);
8292 if (req->wct < 8) {
8293 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8294 END_PROFILE(SMBlockingX);
8295 return;
8298 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8299 locktype = CVAL(req->vwv+3, 0);
8300 oplocklevel = CVAL(req->vwv+3, 1);
8301 num_ulocks = SVAL(req->vwv+6, 0);
8302 num_locks = SVAL(req->vwv+7, 0);
8303 lock_timeout = IVAL(req->vwv+4, 0);
8304 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8306 if (!check_fsp(conn, req, fsp)) {
8307 END_PROFILE(SMBlockingX);
8308 return;
8311 data = req->buf;
8313 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8314 /* we don't support these - and CANCEL_LOCK makes w2k
8315 and XP reboot so I don't really want to be
8316 compatible! (tridge) */
8317 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8318 END_PROFILE(SMBlockingX);
8319 return;
8322 /* Check if this is an oplock break on a file
8323 we have granted an oplock on.
8325 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8326 /* Client can insist on breaking to none. */
8327 bool break_to_none = (oplocklevel == 0);
8328 bool result;
8330 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8331 "for %s\n", (unsigned int)oplocklevel,
8332 fsp_fnum_dbg(fsp)));
8335 * Make sure we have granted an exclusive or batch oplock on
8336 * this file.
8339 if (fsp->oplock_type == 0) {
8341 /* The Samba4 nbench simulator doesn't understand
8342 the difference between break to level2 and break
8343 to none from level2 - it sends oplock break
8344 replies in both cases. Don't keep logging an error
8345 message here - just ignore it. JRA. */
8347 DEBUG(5,("reply_lockingX: Error : oplock break from "
8348 "client for %s (oplock=%d) and no "
8349 "oplock granted on this file (%s).\n",
8350 fsp_fnum_dbg(fsp), fsp->oplock_type,
8351 fsp_str_dbg(fsp)));
8353 /* if this is a pure oplock break request then don't
8354 * send a reply */
8355 if (num_locks == 0 && num_ulocks == 0) {
8356 END_PROFILE(SMBlockingX);
8357 return;
8360 END_PROFILE(SMBlockingX);
8361 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8362 return;
8365 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8366 (break_to_none)) {
8367 result = remove_oplock(fsp);
8368 } else {
8369 result = downgrade_oplock(fsp);
8372 if (!result) {
8373 DEBUG(0, ("reply_lockingX: error in removing "
8374 "oplock on file %s\n", fsp_str_dbg(fsp)));
8375 /* Hmmm. Is this panic justified? */
8376 smb_panic("internal tdb error");
8379 /* if this is a pure oplock break request then don't send a
8380 * reply */
8381 if (num_locks == 0 && num_ulocks == 0) {
8382 /* Sanity check - ensure a pure oplock break is not a
8383 chained request. */
8384 if (CVAL(req->vwv+0, 0) != 0xff) {
8385 DEBUG(0,("reply_lockingX: Error : pure oplock "
8386 "break is a chained %d request !\n",
8387 (unsigned int)CVAL(req->vwv+0, 0)));
8389 END_PROFILE(SMBlockingX);
8390 return;
8394 if (req->buflen <
8395 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8396 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8397 END_PROFILE(SMBlockingX);
8398 return;
8401 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8402 if (ulocks == NULL) {
8403 reply_nterror(req, NT_STATUS_NO_MEMORY);
8404 END_PROFILE(SMBlockingX);
8405 return;
8408 /* Data now points at the beginning of the list
8409 of smb_unlkrng structs */
8410 for (i = 0; i < num_ulocks; i++) {
8411 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8412 ulocks[i].count = get_lock_count(data, i, large_file_format);
8413 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8414 ulocks[i].brltype = UNLOCK_LOCK;
8417 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
8418 TALLOC_FREE(ulocks);
8419 if (!NT_STATUS_IS_OK(status)) {
8420 END_PROFILE(SMBlockingX);
8421 reply_nterror(req, status);
8422 return;
8425 /* Now do any requested locks */
8426 data += ((large_file_format ? 20 : 10)*num_ulocks);
8428 /* Data now points at the beginning of the list
8429 of smb_lkrng structs */
8431 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8432 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8433 brltype = PENDING_READ_LOCK;
8434 } else {
8435 brltype = READ_LOCK;
8437 } else {
8438 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8439 brltype = PENDING_WRITE_LOCK;
8440 } else {
8441 brltype = WRITE_LOCK;
8445 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8446 if (locks == NULL) {
8447 reply_nterror(req, NT_STATUS_NO_MEMORY);
8448 END_PROFILE(SMBlockingX);
8449 return;
8452 for (i = 0; i < num_locks; i++) {
8453 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8454 locks[i].count = get_lock_count(data, i, large_file_format);
8455 locks[i].offset = get_lock_offset(data, i, large_file_format);
8456 locks[i].brltype = brltype;
8459 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8460 struct smbd_lock_element *e = NULL;
8462 if (num_locks == 0) {
8463 /* See smbtorture3 lock11 test */
8464 goto done;
8467 e = &locks[0];
8470 * MS-CIFS (2.2.4.32.1) states that a cancel is
8471 * honored if and only if the lock vector contains one
8472 * entry. When given multiple cancel requests in a
8473 * single PDU we expect the server to return an
8474 * error. Windows servers seem to accept the request
8475 * but only cancel the first lock.
8477 * JRA - Do what Windows does (tm) :-).
8480 if (lp_blocking_locks(SNUM(conn))) {
8481 struct blocking_lock_record *blr = NULL;
8483 /* Schedule a message to ourselves to
8484 remove the blocking lock record and
8485 return the right error. */
8487 blr = blocking_lock_cancel_smb1(
8488 fsp,
8489 e->smblctx,
8490 e->offset,
8491 e->count,
8492 WINDOWS_LOCK,
8493 locktype,
8494 NT_STATUS_FILE_LOCK_CONFLICT);
8495 if (blr == NULL) {
8496 reply_force_doserror(
8497 req, ERRDOS, ERRcancelviolation);
8498 END_PROFILE(SMBlockingX);
8499 return;
8503 /* Remove a matching pending lock. */
8504 status = do_lock_cancel(fsp,
8505 e->smblctx,
8506 e->count,
8507 e->offset,
8508 WINDOWS_LOCK);
8509 END_PROFILE(SMBlockingX);
8510 reply_nterror(req, status);
8511 return;
8514 status = smbd_do_locking(
8515 req, fsp, lock_timeout, num_locks, locks, &async);
8516 TALLOC_FREE(locks);
8517 if (!NT_STATUS_IS_OK(status)) {
8518 END_PROFILE(SMBlockingX);
8519 reply_nterror(req, status);
8520 return;
8522 if (async) {
8523 END_PROFILE(SMBlockingX);
8524 return;
8527 done:
8528 reply_outbuf(req, 2, 0);
8529 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8530 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8532 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8533 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8535 END_PROFILE(SMBlockingX);
8538 #undef DBGC_CLASS
8539 #define DBGC_CLASS DBGC_ALL
8541 /****************************************************************************
8542 Reply to a SMBreadbmpx (read block multiplex) request.
8543 Always reply with an error, if someone has a platform really needs this,
8544 please contact vl@samba.org
8545 ****************************************************************************/
8547 void reply_readbmpx(struct smb_request *req)
8549 START_PROFILE(SMBreadBmpx);
8550 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8551 END_PROFILE(SMBreadBmpx);
8552 return;
8555 /****************************************************************************
8556 Reply to a SMBreadbs (read block multiplex secondary) request.
8557 Always reply with an error, if someone has a platform really needs this,
8558 please contact vl@samba.org
8559 ****************************************************************************/
8561 void reply_readbs(struct smb_request *req)
8563 START_PROFILE(SMBreadBs);
8564 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8565 END_PROFILE(SMBreadBs);
8566 return;
8569 /****************************************************************************
8570 Reply to a SMBsetattrE.
8571 ****************************************************************************/
8573 void reply_setattrE(struct smb_request *req)
8575 connection_struct *conn = req->conn;
8576 struct smb_file_time ft;
8577 files_struct *fsp;
8578 NTSTATUS status;
8580 START_PROFILE(SMBsetattrE);
8581 ZERO_STRUCT(ft);
8583 if (req->wct < 7) {
8584 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8585 goto out;
8588 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8590 if(!fsp || (fsp->conn != conn)) {
8591 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8592 goto out;
8596 * Convert the DOS times into unix times.
8599 ft.atime = convert_time_t_to_timespec(
8600 srv_make_unix_date2(req->vwv+3));
8601 ft.mtime = convert_time_t_to_timespec(
8602 srv_make_unix_date2(req->vwv+5));
8603 ft.create_time = convert_time_t_to_timespec(
8604 srv_make_unix_date2(req->vwv+1));
8606 reply_outbuf(req, 0, 0);
8609 * Patch from Ray Frush <frush@engr.colostate.edu>
8610 * Sometimes times are sent as zero - ignore them.
8613 /* Ensure we have a valid stat struct for the source. */
8614 status = vfs_stat_fsp(fsp);
8615 if (!NT_STATUS_IS_OK(status)) {
8616 reply_nterror(req, status);
8617 goto out;
8620 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8621 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8622 goto out;
8625 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8626 if (!NT_STATUS_IS_OK(status)) {
8627 reply_nterror(req, status);
8628 goto out;
8631 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8632 " createtime=%u\n",
8633 fsp_fnum_dbg(fsp),
8634 (unsigned int)ft.atime.tv_sec,
8635 (unsigned int)ft.mtime.tv_sec,
8636 (unsigned int)ft.create_time.tv_sec
8638 out:
8639 END_PROFILE(SMBsetattrE);
8640 return;
8644 /* Back from the dead for OS/2..... JRA. */
8646 /****************************************************************************
8647 Reply to a SMBwritebmpx (write block multiplex primary) request.
8648 Always reply with an error, if someone has a platform really needs this,
8649 please contact vl@samba.org
8650 ****************************************************************************/
8652 void reply_writebmpx(struct smb_request *req)
8654 START_PROFILE(SMBwriteBmpx);
8655 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8656 END_PROFILE(SMBwriteBmpx);
8657 return;
8660 /****************************************************************************
8661 Reply to a SMBwritebs (write block multiplex secondary) request.
8662 Always reply with an error, if someone has a platform really needs this,
8663 please contact vl@samba.org
8664 ****************************************************************************/
8666 void reply_writebs(struct smb_request *req)
8668 START_PROFILE(SMBwriteBs);
8669 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8670 END_PROFILE(SMBwriteBs);
8671 return;
8674 /****************************************************************************
8675 Reply to a SMBgetattrE.
8676 ****************************************************************************/
8678 void reply_getattrE(struct smb_request *req)
8680 connection_struct *conn = req->conn;
8681 int mode;
8682 files_struct *fsp;
8683 struct timespec create_ts;
8685 START_PROFILE(SMBgetattrE);
8687 if (req->wct < 1) {
8688 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8689 END_PROFILE(SMBgetattrE);
8690 return;
8693 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8695 if(!fsp || (fsp->conn != conn)) {
8696 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8697 END_PROFILE(SMBgetattrE);
8698 return;
8701 /* Do an fstat on this file */
8702 if(fsp_stat(fsp)) {
8703 reply_nterror(req, map_nt_error_from_unix(errno));
8704 END_PROFILE(SMBgetattrE);
8705 return;
8708 mode = dos_mode(conn, fsp->fsp_name);
8711 * Convert the times into dos times. Set create
8712 * date to be last modify date as UNIX doesn't save
8713 * this.
8716 reply_outbuf(req, 11, 0);
8718 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8719 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8720 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8721 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8722 /* Should we check pending modtime here ? JRA */
8723 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8724 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8726 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8727 SIVAL(req->outbuf, smb_vwv6, 0);
8728 SIVAL(req->outbuf, smb_vwv8, 0);
8729 } else {
8730 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8731 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8732 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8734 SSVAL(req->outbuf,smb_vwv10, mode);
8736 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8738 END_PROFILE(SMBgetattrE);
8739 return;