s3:smbd: don't allow renaming basefile if streams are open
[Samba.git] / source3 / smbd / reply.c
blob5295ff76bfad240f5b738f7e54533053a2116a1c
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 "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.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 session->global->signing_key.length > 0)
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.data,
1025 MIN(x->global->signing_key.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 smb_key_derivation(x->global->application_key.data,
1042 x->global->application_key.length,
1043 x->global->application_key.data);
1044 optional_support |= SMB_EXTENDED_SIGNATURES;
1048 * Place the application key into the session_info
1050 data_blob_clear_free(&session_info->session_key);
1051 session_info->session_key = data_blob_dup_talloc(session_info,
1052 x->global->application_key);
1053 if (session_info->session_key.data == NULL) {
1054 data_blob_clear_free(&x->global->application_key);
1055 reply_nterror(req, NT_STATUS_NO_MEMORY);
1056 END_PROFILE(SMBtconX);
1057 return;
1059 session_key_updated = true;
1062 conn = make_connection(req, now, service, client_devicetype,
1063 req->vuid, &nt_status);
1064 req->conn =conn;
1066 if (!conn) {
1067 if (session_key_updated) {
1068 struct smbXsrv_session *x = session;
1069 struct auth_session_info *session_info =
1070 session->global->auth_session_info;
1071 data_blob_clear_free(&x->global->application_key);
1072 data_blob_clear_free(&session_info->session_key);
1074 reply_nterror(req, nt_status);
1075 END_PROFILE(SMBtconX);
1076 return;
1079 if ( IS_IPC(conn) )
1080 server_devicetype = "IPC";
1081 else if ( IS_PRINT(conn) )
1082 server_devicetype = "LPT1:";
1083 else
1084 server_devicetype = "A:";
1086 if (get_Protocol() < PROTOCOL_NT1) {
1087 reply_outbuf(req, 2, 0);
1088 if (message_push_string(&req->outbuf, server_devicetype,
1089 STR_TERMINATE|STR_ASCII) == -1) {
1090 reply_nterror(req, NT_STATUS_NO_MEMORY);
1091 END_PROFILE(SMBtconX);
1092 return;
1094 } else {
1095 /* NT sets the fstype of IPC$ to the null string */
1096 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1098 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1099 /* Return permissions. */
1100 uint32_t perm1 = 0;
1101 uint32_t perm2 = 0;
1103 reply_outbuf(req, 7, 0);
1105 if (IS_IPC(conn)) {
1106 perm1 = FILE_ALL_ACCESS;
1107 perm2 = FILE_ALL_ACCESS;
1108 } else {
1109 perm1 = conn->share_access;
1112 SIVAL(req->outbuf, smb_vwv3, perm1);
1113 SIVAL(req->outbuf, smb_vwv5, perm2);
1114 } else {
1115 reply_outbuf(req, 3, 0);
1118 if ((message_push_string(&req->outbuf, server_devicetype,
1119 STR_TERMINATE|STR_ASCII) == -1)
1120 || (message_push_string(&req->outbuf, fstype,
1121 STR_TERMINATE) == -1)) {
1122 reply_nterror(req, NT_STATUS_NO_MEMORY);
1123 END_PROFILE(SMBtconX);
1124 return;
1127 /* what does setting this bit do? It is set by NT4 and
1128 may affect the ability to autorun mounted cdroms */
1129 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1130 optional_support |=
1131 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1133 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1134 DEBUG(2,("Serving %s as a Dfs root\n",
1135 lp_servicename(ctx, SNUM(conn)) ));
1136 optional_support |= SMB_SHARE_IN_DFS;
1139 SSVAL(req->outbuf, smb_vwv2, optional_support);
1142 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1143 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1145 DEBUG(3,("tconX service=%s \n",
1146 service));
1148 /* set the incoming and outgoing tid to the just created one */
1149 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1150 SSVAL(req->outbuf,smb_tid,conn->cnum);
1152 END_PROFILE(SMBtconX);
1154 req->tid = conn->cnum;
1157 /****************************************************************************
1158 Reply to an unknown type.
1159 ****************************************************************************/
1161 void reply_unknown_new(struct smb_request *req, uint8_t type)
1163 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1164 smb_fn_name(type), type, type));
1165 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1166 return;
1169 /****************************************************************************
1170 Reply to an ioctl.
1171 conn POINTER CAN BE NULL HERE !
1172 ****************************************************************************/
1174 void reply_ioctl(struct smb_request *req)
1176 connection_struct *conn = req->conn;
1177 uint16_t device;
1178 uint16_t function;
1179 uint32_t ioctl_code;
1180 int replysize;
1181 char *p;
1183 START_PROFILE(SMBioctl);
1185 if (req->wct < 3) {
1186 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1187 END_PROFILE(SMBioctl);
1188 return;
1191 device = SVAL(req->vwv+1, 0);
1192 function = SVAL(req->vwv+2, 0);
1193 ioctl_code = (device << 16) + function;
1195 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1197 switch (ioctl_code) {
1198 case IOCTL_QUERY_JOB_INFO:
1199 replysize = 32;
1200 break;
1201 default:
1202 reply_force_doserror(req, ERRSRV, ERRnosupport);
1203 END_PROFILE(SMBioctl);
1204 return;
1207 reply_outbuf(req, 8, replysize+1);
1208 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1209 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1210 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1211 p = smb_buf(req->outbuf);
1212 memset(p, '\0', replysize+1); /* valgrind-safe. */
1213 p += 1; /* Allow for alignment */
1215 switch (ioctl_code) {
1216 case IOCTL_QUERY_JOB_INFO:
1218 NTSTATUS status;
1219 size_t len = 0;
1220 files_struct *fsp = file_fsp(
1221 req, SVAL(req->vwv+0, 0));
1222 if (!fsp) {
1223 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1224 END_PROFILE(SMBioctl);
1225 return;
1227 /* Job number */
1228 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1230 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1231 lp_netbios_name(), 15,
1232 STR_TERMINATE|STR_ASCII, &len);
1233 if (!NT_STATUS_IS_OK(status)) {
1234 reply_nterror(req, status);
1235 END_PROFILE(SMBioctl);
1236 return;
1238 if (conn) {
1239 status = srvstr_push((char *)req->outbuf, req->flags2,
1240 p+18,
1241 lp_servicename(talloc_tos(),
1242 SNUM(conn)),
1243 13, STR_TERMINATE|STR_ASCII, &len);
1244 if (!NT_STATUS_IS_OK(status)) {
1245 reply_nterror(req, status);
1246 END_PROFILE(SMBioctl);
1247 return;
1249 } else {
1250 memset(p+18, 0, 13);
1252 break;
1256 END_PROFILE(SMBioctl);
1257 return;
1260 /****************************************************************************
1261 Strange checkpath NTSTATUS mapping.
1262 ****************************************************************************/
1264 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1266 /* Strange DOS error code semantics only for checkpath... */
1267 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1268 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1269 /* We need to map to ERRbadpath */
1270 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1273 return status;
1276 /****************************************************************************
1277 Reply to a checkpath.
1278 ****************************************************************************/
1280 void reply_checkpath(struct smb_request *req)
1282 connection_struct *conn = req->conn;
1283 struct smb_filename *smb_fname = NULL;
1284 char *name = NULL;
1285 NTSTATUS status;
1286 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1287 TALLOC_CTX *ctx = talloc_tos();
1289 START_PROFILE(SMBcheckpath);
1291 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1292 STR_TERMINATE, &status);
1294 if (!NT_STATUS_IS_OK(status)) {
1295 status = map_checkpath_error(req->flags2, status);
1296 reply_nterror(req, status);
1297 END_PROFILE(SMBcheckpath);
1298 return;
1301 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1303 status = filename_convert(ctx,
1304 conn,
1305 name,
1306 ucf_flags,
1307 NULL,
1308 &smb_fname);
1310 if (!NT_STATUS_IS_OK(status)) {
1311 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1312 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1313 ERRSRV, ERRbadpath);
1314 END_PROFILE(SMBcheckpath);
1315 return;
1317 goto path_err;
1320 if (!VALID_STAT(smb_fname->st) &&
1321 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1322 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1323 smb_fname_str_dbg(smb_fname), strerror(errno)));
1324 status = map_nt_error_from_unix(errno);
1325 goto path_err;
1328 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1329 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1330 ERRDOS, ERRbadpath);
1331 goto out;
1334 reply_outbuf(req, 0, 0);
1336 path_err:
1337 /* We special case this - as when a Windows machine
1338 is parsing a path is steps through the components
1339 one at a time - if a component fails it expects
1340 ERRbadpath, not ERRbadfile.
1342 status = map_checkpath_error(req->flags2, status);
1343 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1345 * Windows returns different error codes if
1346 * the parent directory is valid but not the
1347 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1348 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1349 * if the path is invalid.
1351 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1352 ERRDOS, ERRbadpath);
1353 goto out;
1356 reply_nterror(req, status);
1358 out:
1359 TALLOC_FREE(smb_fname);
1360 END_PROFILE(SMBcheckpath);
1361 return;
1364 /****************************************************************************
1365 Reply to a getatr.
1366 ****************************************************************************/
1368 void reply_getatr(struct smb_request *req)
1370 connection_struct *conn = req->conn;
1371 struct smb_filename *smb_fname = NULL;
1372 char *fname = NULL;
1373 int mode=0;
1374 off_t size=0;
1375 time_t mtime=0;
1376 const char *p;
1377 NTSTATUS status;
1378 TALLOC_CTX *ctx = talloc_tos();
1379 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1381 START_PROFILE(SMBgetatr);
1383 p = (const char *)req->buf + 1;
1384 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1385 if (!NT_STATUS_IS_OK(status)) {
1386 reply_nterror(req, status);
1387 goto out;
1390 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1391 under WfWg - weird! */
1392 if (*fname == '\0') {
1393 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1394 if (!CAN_WRITE(conn)) {
1395 mode |= FILE_ATTRIBUTE_READONLY;
1397 size = 0;
1398 mtime = 0;
1399 } else {
1400 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1401 status = filename_convert(ctx,
1402 conn,
1403 fname,
1404 ucf_flags,
1405 NULL,
1406 &smb_fname);
1407 if (!NT_STATUS_IS_OK(status)) {
1408 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1409 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1410 ERRSRV, ERRbadpath);
1411 goto out;
1413 reply_nterror(req, status);
1414 goto out;
1416 if (!VALID_STAT(smb_fname->st) &&
1417 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1418 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1419 smb_fname_str_dbg(smb_fname),
1420 strerror(errno)));
1421 reply_nterror(req, map_nt_error_from_unix(errno));
1422 goto out;
1425 mode = dos_mode(conn, smb_fname);
1426 size = smb_fname->st.st_ex_size;
1428 if (ask_sharemode) {
1429 struct timespec write_time_ts;
1430 struct file_id fileid;
1432 ZERO_STRUCT(write_time_ts);
1433 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1434 get_file_infos(fileid, 0, NULL, &write_time_ts);
1435 if (!null_timespec(write_time_ts)) {
1436 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1440 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1441 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1442 size = 0;
1446 reply_outbuf(req, 10, 0);
1448 SSVAL(req->outbuf,smb_vwv0,mode);
1449 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1450 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1451 } else {
1452 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1454 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1456 if (get_Protocol() >= PROTOCOL_NT1) {
1457 SSVAL(req->outbuf, smb_flg2,
1458 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1461 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1462 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1464 out:
1465 TALLOC_FREE(smb_fname);
1466 TALLOC_FREE(fname);
1467 END_PROFILE(SMBgetatr);
1468 return;
1471 /****************************************************************************
1472 Reply to a setatr.
1473 ****************************************************************************/
1475 void reply_setatr(struct smb_request *req)
1477 struct smb_file_time ft;
1478 connection_struct *conn = req->conn;
1479 struct smb_filename *smb_fname = NULL;
1480 char *fname = NULL;
1481 int mode;
1482 time_t mtime;
1483 const char *p;
1484 NTSTATUS status;
1485 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1486 TALLOC_CTX *ctx = talloc_tos();
1488 START_PROFILE(SMBsetatr);
1490 ZERO_STRUCT(ft);
1492 if (req->wct < 2) {
1493 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1494 goto out;
1497 p = (const char *)req->buf + 1;
1498 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1499 if (!NT_STATUS_IS_OK(status)) {
1500 reply_nterror(req, status);
1501 goto out;
1504 status = filename_convert(ctx,
1505 conn,
1506 fname,
1507 ucf_flags,
1508 NULL,
1509 &smb_fname);
1510 if (!NT_STATUS_IS_OK(status)) {
1511 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1512 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1513 ERRSRV, ERRbadpath);
1514 goto out;
1516 reply_nterror(req, status);
1517 goto out;
1520 if (smb_fname->base_name[0] == '.' &&
1521 smb_fname->base_name[1] == '\0') {
1523 * Not sure here is the right place to catch this
1524 * condition. Might be moved to somewhere else later -- vl
1526 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1527 goto out;
1530 mode = SVAL(req->vwv+0, 0);
1531 mtime = srv_make_unix_date3(req->vwv+1);
1533 if (mode != FILE_ATTRIBUTE_NORMAL) {
1534 if (VALID_STAT_OF_DIR(smb_fname->st))
1535 mode |= FILE_ATTRIBUTE_DIRECTORY;
1536 else
1537 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1539 status = check_access(conn, NULL, smb_fname,
1540 FILE_WRITE_ATTRIBUTES);
1541 if (!NT_STATUS_IS_OK(status)) {
1542 reply_nterror(req, status);
1543 goto out;
1546 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1547 false) != 0) {
1548 reply_nterror(req, map_nt_error_from_unix(errno));
1549 goto out;
1553 ft.mtime = convert_time_t_to_timespec(mtime);
1554 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1555 if (!NT_STATUS_IS_OK(status)) {
1556 reply_nterror(req, status);
1557 goto out;
1560 reply_outbuf(req, 0, 0);
1562 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1563 mode));
1564 out:
1565 TALLOC_FREE(smb_fname);
1566 END_PROFILE(SMBsetatr);
1567 return;
1570 /****************************************************************************
1571 Reply to a dskattr.
1572 ****************************************************************************/
1574 void reply_dskattr(struct smb_request *req)
1576 connection_struct *conn = req->conn;
1577 uint64_t ret;
1578 uint64_t dfree,dsize,bsize;
1579 struct smb_filename smb_fname;
1580 START_PROFILE(SMBdskattr);
1582 ZERO_STRUCT(smb_fname);
1583 smb_fname.base_name = discard_const_p(char, ".");
1585 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1586 reply_nterror(req, map_nt_error_from_unix(errno));
1587 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1588 END_PROFILE(SMBdskattr);
1589 return;
1592 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1593 if (ret == (uint64_t)-1) {
1594 reply_nterror(req, map_nt_error_from_unix(errno));
1595 END_PROFILE(SMBdskattr);
1596 return;
1600 * Force max to fit in 16 bit fields.
1602 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1603 dfree /= 2;
1604 dsize /= 2;
1605 bsize *= 2;
1606 if (bsize > (WORDMAX*512)) {
1607 bsize = (WORDMAX*512);
1608 if (dsize > WORDMAX)
1609 dsize = WORDMAX;
1610 if (dfree > WORDMAX)
1611 dfree = WORDMAX;
1612 break;
1616 reply_outbuf(req, 5, 0);
1618 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1619 double total_space, free_space;
1620 /* we need to scale this to a number that DOS6 can handle. We
1621 use floating point so we can handle large drives on systems
1622 that don't have 64 bit integers
1624 we end up displaying a maximum of 2G to DOS systems
1626 total_space = dsize * (double)bsize;
1627 free_space = dfree * (double)bsize;
1629 dsize = (uint64_t)((total_space+63*512) / (64*512));
1630 dfree = (uint64_t)((free_space+63*512) / (64*512));
1632 if (dsize > 0xFFFF) dsize = 0xFFFF;
1633 if (dfree > 0xFFFF) dfree = 0xFFFF;
1635 SSVAL(req->outbuf,smb_vwv0,dsize);
1636 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1637 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1638 SSVAL(req->outbuf,smb_vwv3,dfree);
1639 } else {
1640 SSVAL(req->outbuf,smb_vwv0,dsize);
1641 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1642 SSVAL(req->outbuf,smb_vwv2,512);
1643 SSVAL(req->outbuf,smb_vwv3,dfree);
1646 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1648 END_PROFILE(SMBdskattr);
1649 return;
1653 * Utility function to split the filename from the directory.
1655 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1656 char **fname_dir_out,
1657 char **fname_mask_out)
1659 const char *p = NULL;
1660 char *fname_dir = NULL;
1661 char *fname_mask = NULL;
1663 p = strrchr_m(fname_in, '/');
1664 if (!p) {
1665 fname_dir = talloc_strdup(ctx, ".");
1666 fname_mask = talloc_strdup(ctx, fname_in);
1667 } else {
1668 fname_dir = talloc_strndup(ctx, fname_in,
1669 PTR_DIFF(p, fname_in));
1670 fname_mask = talloc_strdup(ctx, p+1);
1673 if (!fname_dir || !fname_mask) {
1674 TALLOC_FREE(fname_dir);
1675 TALLOC_FREE(fname_mask);
1676 return NT_STATUS_NO_MEMORY;
1679 *fname_dir_out = fname_dir;
1680 *fname_mask_out = fname_mask;
1681 return NT_STATUS_OK;
1684 /****************************************************************************
1685 Make a dir struct.
1686 ****************************************************************************/
1688 static bool make_dir_struct(TALLOC_CTX *ctx,
1689 char *buf,
1690 const char *mask,
1691 const char *fname,
1692 off_t size,
1693 uint32_t mode,
1694 time_t date,
1695 bool uc)
1697 char *p;
1698 char *mask2 = talloc_strdup(ctx, mask);
1700 if (!mask2) {
1701 return False;
1704 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1705 size = 0;
1708 memset(buf+1,' ',11);
1709 if ((p = strchr_m(mask2,'.')) != NULL) {
1710 *p = 0;
1711 push_ascii(buf+1,mask2,8, 0);
1712 push_ascii(buf+9,p+1,3, 0);
1713 *p = '.';
1714 } else {
1715 push_ascii(buf+1,mask2,11, 0);
1718 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1719 SCVAL(buf,21,mode);
1720 srv_put_dos_date(buf,22,date);
1721 SSVAL(buf,26,size & 0xFFFF);
1722 SSVAL(buf,28,(size >> 16)&0xFFFF);
1723 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1724 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1725 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1726 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1727 return True;
1730 /****************************************************************************
1731 Reply to a search.
1732 Can be called from SMBsearch, SMBffirst or SMBfunique.
1733 ****************************************************************************/
1735 void reply_search(struct smb_request *req)
1737 connection_struct *conn = req->conn;
1738 char *path = NULL;
1739 char *mask = NULL;
1740 char *directory = NULL;
1741 struct smb_filename *smb_fname = NULL;
1742 char *fname = NULL;
1743 off_t size;
1744 uint32_t mode;
1745 struct timespec date;
1746 uint32_t dirtype;
1747 unsigned int numentries = 0;
1748 unsigned int maxentries = 0;
1749 bool finished = False;
1750 const char *p;
1751 int status_len;
1752 char status[21];
1753 int dptr_num= -1;
1754 bool check_descend = False;
1755 bool expect_close = False;
1756 NTSTATUS nt_status;
1757 bool mask_contains_wcard = False;
1758 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1759 TALLOC_CTX *ctx = talloc_tos();
1760 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1761 struct dptr_struct *dirptr = NULL;
1762 struct smbXsrv_connection *xconn = req->xconn;
1763 struct smbd_server_connection *sconn = req->sconn;
1765 START_PROFILE(SMBsearch);
1767 if (req->wct < 2) {
1768 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1769 goto out;
1772 if (req->posix_pathnames) {
1773 reply_unknown_new(req, req->cmd);
1774 goto out;
1777 /* If we were called as SMBffirst then we must expect close. */
1778 if(req->cmd == SMBffirst) {
1779 expect_close = True;
1782 reply_outbuf(req, 1, 3);
1783 maxentries = SVAL(req->vwv+0, 0);
1784 dirtype = SVAL(req->vwv+1, 0);
1785 p = (const char *)req->buf + 1;
1786 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1787 &nt_status, &mask_contains_wcard);
1788 if (!NT_STATUS_IS_OK(nt_status)) {
1789 reply_nterror(req, nt_status);
1790 goto out;
1793 p++;
1794 status_len = SVAL(p, 0);
1795 p += 2;
1797 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1799 if (status_len == 0) {
1800 struct smb_filename *smb_dname = NULL;
1801 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1802 ucf_flags_from_smb_request(req);
1803 nt_status = filename_convert(ctx, conn,
1804 path,
1805 ucf_flags,
1806 &mask_contains_wcard,
1807 &smb_fname);
1808 if (!NT_STATUS_IS_OK(nt_status)) {
1809 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1810 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1811 ERRSRV, ERRbadpath);
1812 goto out;
1814 reply_nterror(req, nt_status);
1815 goto out;
1818 directory = smb_fname->base_name;
1820 p = strrchr_m(directory,'/');
1821 if ((p != NULL) && (*directory != '/')) {
1822 mask = talloc_strdup(ctx, p + 1);
1823 directory = talloc_strndup(ctx, directory,
1824 PTR_DIFF(p, directory));
1825 } else {
1826 mask = talloc_strdup(ctx, directory);
1827 directory = talloc_strdup(ctx,".");
1830 if (!directory) {
1831 reply_nterror(req, NT_STATUS_NO_MEMORY);
1832 goto out;
1835 memset((char *)status,'\0',21);
1836 SCVAL(status,0,(dirtype & 0x1F));
1838 smb_dname = synthetic_smb_fname(talloc_tos(),
1839 directory,
1840 NULL,
1841 NULL,
1842 smb_fname->flags);
1843 if (smb_dname == NULL) {
1844 reply_nterror(req, NT_STATUS_NO_MEMORY);
1845 goto out;
1848 nt_status = dptr_create(conn,
1849 NULL, /* req */
1850 NULL, /* fsp */
1851 smb_dname,
1852 True,
1853 expect_close,
1854 req->smbpid,
1855 mask,
1856 mask_contains_wcard,
1857 dirtype,
1858 &dirptr);
1860 TALLOC_FREE(smb_dname);
1862 if (!NT_STATUS_IS_OK(nt_status)) {
1863 reply_nterror(req, nt_status);
1864 goto out;
1866 dptr_num = dptr_dnum(dirptr);
1867 } else {
1868 int status_dirtype;
1869 const char *dirpath;
1871 memcpy(status,p,21);
1872 status_dirtype = CVAL(status,0) & 0x1F;
1873 if (status_dirtype != (dirtype & 0x1F)) {
1874 dirtype = status_dirtype;
1877 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1878 if (!dirptr) {
1879 goto SearchEmpty;
1881 dirpath = dptr_path(sconn, dptr_num);
1882 directory = talloc_strdup(ctx, dirpath);
1883 if (!directory) {
1884 reply_nterror(req, NT_STATUS_NO_MEMORY);
1885 goto out;
1888 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1889 if (!mask) {
1890 goto SearchEmpty;
1893 * For a 'continue' search we have no string. So
1894 * check from the initial saved string.
1896 if (!req->posix_pathnames) {
1897 mask_contains_wcard = ms_has_wild(mask);
1899 dirtype = dptr_attr(sconn, dptr_num);
1902 DEBUG(4,("dptr_num is %d\n",dptr_num));
1904 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1905 dptr_init_search_op(dirptr);
1907 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1908 char buf[DIR_STRUCT_SIZE];
1909 memcpy(buf,status,21);
1910 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1911 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1912 reply_nterror(req, NT_STATUS_NO_MEMORY);
1913 goto out;
1915 dptr_fill(sconn, buf+12,dptr_num);
1916 if (dptr_zero(buf+12) && (status_len==0)) {
1917 numentries = 1;
1918 } else {
1919 numentries = 0;
1921 if (message_push_blob(&req->outbuf,
1922 data_blob_const(buf, sizeof(buf)))
1923 == -1) {
1924 reply_nterror(req, NT_STATUS_NO_MEMORY);
1925 goto out;
1927 } else {
1928 unsigned int i;
1929 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1930 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1932 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1934 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1935 directory,lp_dont_descend(ctx, SNUM(conn))));
1936 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1937 check_descend = True;
1940 for (i=numentries;(i<maxentries) && !finished;i++) {
1941 finished = !get_dir_entry(ctx,
1942 dirptr,
1943 mask,
1944 dirtype,
1945 &fname,
1946 &size,
1947 &mode,
1948 &date,
1949 check_descend,
1950 ask_sharemode);
1951 if (!finished) {
1952 char buf[DIR_STRUCT_SIZE];
1953 memcpy(buf,status,21);
1954 if (!make_dir_struct(ctx,
1955 buf,
1956 mask,
1957 fname,
1958 size,
1959 mode,
1960 convert_timespec_to_time_t(date),
1961 !allow_long_path_components)) {
1962 reply_nterror(req, NT_STATUS_NO_MEMORY);
1963 goto out;
1965 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1966 break;
1968 if (message_push_blob(&req->outbuf,
1969 data_blob_const(buf, sizeof(buf)))
1970 == -1) {
1971 reply_nterror(req, NT_STATUS_NO_MEMORY);
1972 goto out;
1974 numentries++;
1979 SearchEmpty:
1981 /* If we were called as SMBffirst with smb_search_id == NULL
1982 and no entries were found then return error and close dirptr
1983 (X/Open spec) */
1985 if (numentries == 0) {
1986 dptr_close(sconn, &dptr_num);
1987 } else if(expect_close && status_len == 0) {
1988 /* Close the dptr - we know it's gone */
1989 dptr_close(sconn, &dptr_num);
1992 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1993 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1994 dptr_close(sconn, &dptr_num);
1997 if ((numentries == 0) && !mask_contains_wcard) {
1998 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1999 goto out;
2002 SSVAL(req->outbuf,smb_vwv0,numentries);
2003 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2004 SCVAL(smb_buf(req->outbuf),0,5);
2005 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2007 /* The replies here are never long name. */
2008 SSVAL(req->outbuf, smb_flg2,
2009 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2010 if (!allow_long_path_components) {
2011 SSVAL(req->outbuf, smb_flg2,
2012 SVAL(req->outbuf, smb_flg2)
2013 & (~FLAGS2_LONG_PATH_COMPONENTS));
2016 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2017 SSVAL(req->outbuf, smb_flg2,
2018 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2020 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2021 smb_fn_name(req->cmd),
2022 mask,
2023 directory,
2024 dirtype,
2025 numentries,
2026 maxentries ));
2027 out:
2028 TALLOC_FREE(directory);
2029 TALLOC_FREE(mask);
2030 TALLOC_FREE(smb_fname);
2031 END_PROFILE(SMBsearch);
2032 return;
2035 /****************************************************************************
2036 Reply to a fclose (stop directory search).
2037 ****************************************************************************/
2039 void reply_fclose(struct smb_request *req)
2041 int status_len;
2042 char status[21];
2043 int dptr_num= -2;
2044 const char *p;
2045 char *path = NULL;
2046 NTSTATUS err;
2047 bool path_contains_wcard = False;
2048 TALLOC_CTX *ctx = talloc_tos();
2049 struct smbd_server_connection *sconn = req->sconn;
2051 START_PROFILE(SMBfclose);
2053 if (req->posix_pathnames) {
2054 reply_unknown_new(req, req->cmd);
2055 END_PROFILE(SMBfclose);
2056 return;
2059 p = (const char *)req->buf + 1;
2060 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2061 &err, &path_contains_wcard);
2062 if (!NT_STATUS_IS_OK(err)) {
2063 reply_nterror(req, err);
2064 END_PROFILE(SMBfclose);
2065 return;
2067 p++;
2068 status_len = SVAL(p,0);
2069 p += 2;
2071 if (status_len == 0) {
2072 reply_force_doserror(req, ERRSRV, ERRsrverror);
2073 END_PROFILE(SMBfclose);
2074 return;
2077 memcpy(status,p,21);
2079 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2080 /* Close the dptr - we know it's gone */
2081 dptr_close(sconn, &dptr_num);
2084 reply_outbuf(req, 1, 0);
2085 SSVAL(req->outbuf,smb_vwv0,0);
2087 DEBUG(3,("search close\n"));
2089 END_PROFILE(SMBfclose);
2090 return;
2093 /****************************************************************************
2094 Reply to an open.
2095 ****************************************************************************/
2097 void reply_open(struct smb_request *req)
2099 connection_struct *conn = req->conn;
2100 struct smb_filename *smb_fname = NULL;
2101 char *fname = NULL;
2102 uint32_t fattr=0;
2103 off_t size = 0;
2104 time_t mtime=0;
2105 int info;
2106 files_struct *fsp;
2107 int oplock_request;
2108 int deny_mode;
2109 uint32_t dos_attr;
2110 uint32_t access_mask;
2111 uint32_t share_mode;
2112 uint32_t create_disposition;
2113 uint32_t create_options = 0;
2114 uint32_t private_flags = 0;
2115 NTSTATUS status;
2116 uint32_t ucf_flags;
2117 TALLOC_CTX *ctx = talloc_tos();
2119 START_PROFILE(SMBopen);
2121 if (req->wct < 2) {
2122 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2123 goto out;
2126 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2127 deny_mode = SVAL(req->vwv+0, 0);
2128 dos_attr = SVAL(req->vwv+1, 0);
2130 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2131 STR_TERMINATE, &status);
2132 if (!NT_STATUS_IS_OK(status)) {
2133 reply_nterror(req, status);
2134 goto out;
2137 if (!map_open_params_to_ntcreate(fname, deny_mode,
2138 OPENX_FILE_EXISTS_OPEN, &access_mask,
2139 &share_mode, &create_disposition,
2140 &create_options, &private_flags)) {
2141 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2142 goto out;
2145 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2147 status = filename_convert(ctx,
2148 conn,
2149 fname,
2150 ucf_flags,
2151 NULL,
2152 &smb_fname);
2153 if (!NT_STATUS_IS_OK(status)) {
2154 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2155 reply_botherror(req,
2156 NT_STATUS_PATH_NOT_COVERED,
2157 ERRSRV, ERRbadpath);
2158 goto out;
2160 reply_nterror(req, status);
2161 goto out;
2164 status = SMB_VFS_CREATE_FILE(
2165 conn, /* conn */
2166 req, /* req */
2167 0, /* root_dir_fid */
2168 smb_fname, /* fname */
2169 access_mask, /* access_mask */
2170 share_mode, /* share_access */
2171 create_disposition, /* create_disposition*/
2172 create_options, /* create_options */
2173 dos_attr, /* file_attributes */
2174 oplock_request, /* oplock_request */
2175 NULL, /* lease */
2176 0, /* allocation_size */
2177 private_flags,
2178 NULL, /* sd */
2179 NULL, /* ea_list */
2180 &fsp, /* result */
2181 &info, /* pinfo */
2182 NULL, NULL); /* create context */
2184 if (!NT_STATUS_IS_OK(status)) {
2185 if (open_was_deferred(req->xconn, req->mid)) {
2186 /* We have re-scheduled this call. */
2187 goto out;
2189 reply_openerror(req, status);
2190 goto out;
2193 /* Ensure we're pointing at the correct stat struct. */
2194 TALLOC_FREE(smb_fname);
2195 smb_fname = fsp->fsp_name;
2197 size = smb_fname->st.st_ex_size;
2198 fattr = dos_mode(conn, smb_fname);
2200 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2202 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2203 DEBUG(3,("attempt to open a directory %s\n",
2204 fsp_str_dbg(fsp)));
2205 close_file(req, fsp, ERROR_CLOSE);
2206 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2207 ERRDOS, ERRnoaccess);
2208 goto out;
2211 reply_outbuf(req, 7, 0);
2212 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2213 SSVAL(req->outbuf,smb_vwv1,fattr);
2214 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2215 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2216 } else {
2217 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2219 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2220 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2222 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2223 SCVAL(req->outbuf,smb_flg,
2224 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2227 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2228 SCVAL(req->outbuf,smb_flg,
2229 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2231 out:
2232 END_PROFILE(SMBopen);
2233 return;
2236 /****************************************************************************
2237 Reply to an open and X.
2238 ****************************************************************************/
2240 void reply_open_and_X(struct smb_request *req)
2242 connection_struct *conn = req->conn;
2243 struct smb_filename *smb_fname = NULL;
2244 char *fname = NULL;
2245 uint16_t open_flags;
2246 int deny_mode;
2247 uint32_t smb_attr;
2248 /* Breakout the oplock request bits so we can set the
2249 reply bits separately. */
2250 int ex_oplock_request;
2251 int core_oplock_request;
2252 int oplock_request;
2253 #if 0
2254 int smb_sattr = SVAL(req->vwv+4, 0);
2255 uint32_t smb_time = make_unix_date3(req->vwv+6);
2256 #endif
2257 int smb_ofun;
2258 uint32_t fattr=0;
2259 int mtime=0;
2260 int smb_action = 0;
2261 files_struct *fsp;
2262 NTSTATUS status;
2263 uint64_t allocation_size;
2264 ssize_t retval = -1;
2265 uint32_t access_mask;
2266 uint32_t share_mode;
2267 uint32_t create_disposition;
2268 uint32_t create_options = 0;
2269 uint32_t private_flags = 0;
2270 uint32_t ucf_flags;
2271 TALLOC_CTX *ctx = talloc_tos();
2273 START_PROFILE(SMBopenX);
2275 if (req->wct < 15) {
2276 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2277 goto out;
2280 open_flags = SVAL(req->vwv+2, 0);
2281 deny_mode = SVAL(req->vwv+3, 0);
2282 smb_attr = SVAL(req->vwv+5, 0);
2283 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2284 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2285 oplock_request = ex_oplock_request | core_oplock_request;
2286 smb_ofun = SVAL(req->vwv+8, 0);
2287 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2289 /* If it's an IPC, pass off the pipe handler. */
2290 if (IS_IPC(conn)) {
2291 if (lp_nt_pipe_support()) {
2292 reply_open_pipe_and_X(conn, req);
2293 } else {
2294 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2296 goto out;
2299 /* XXXX we need to handle passed times, sattr and flags */
2300 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2301 STR_TERMINATE, &status);
2302 if (!NT_STATUS_IS_OK(status)) {
2303 reply_nterror(req, status);
2304 goto out;
2307 if (!map_open_params_to_ntcreate(fname, deny_mode,
2308 smb_ofun,
2309 &access_mask, &share_mode,
2310 &create_disposition,
2311 &create_options,
2312 &private_flags)) {
2313 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2314 goto out;
2317 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2319 status = filename_convert(ctx,
2320 conn,
2321 fname,
2322 ucf_flags,
2323 NULL,
2324 &smb_fname);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2327 reply_botherror(req,
2328 NT_STATUS_PATH_NOT_COVERED,
2329 ERRSRV, ERRbadpath);
2330 goto out;
2332 reply_nterror(req, status);
2333 goto out;
2336 status = SMB_VFS_CREATE_FILE(
2337 conn, /* conn */
2338 req, /* req */
2339 0, /* root_dir_fid */
2340 smb_fname, /* fname */
2341 access_mask, /* access_mask */
2342 share_mode, /* share_access */
2343 create_disposition, /* create_disposition*/
2344 create_options, /* create_options */
2345 smb_attr, /* file_attributes */
2346 oplock_request, /* oplock_request */
2347 NULL, /* lease */
2348 0, /* allocation_size */
2349 private_flags,
2350 NULL, /* sd */
2351 NULL, /* ea_list */
2352 &fsp, /* result */
2353 &smb_action, /* pinfo */
2354 NULL, NULL); /* create context */
2356 if (!NT_STATUS_IS_OK(status)) {
2357 if (open_was_deferred(req->xconn, req->mid)) {
2358 /* We have re-scheduled this call. */
2359 goto out;
2361 reply_openerror(req, status);
2362 goto out;
2365 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2366 if the file is truncated or created. */
2367 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2368 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2369 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2370 close_file(req, fsp, ERROR_CLOSE);
2371 reply_nterror(req, NT_STATUS_DISK_FULL);
2372 goto out;
2374 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2375 if (retval < 0) {
2376 close_file(req, fsp, ERROR_CLOSE);
2377 reply_nterror(req, NT_STATUS_DISK_FULL);
2378 goto out;
2380 status = vfs_stat_fsp(fsp);
2381 if (!NT_STATUS_IS_OK(status)) {
2382 close_file(req, fsp, ERROR_CLOSE);
2383 reply_nterror(req, status);
2384 goto out;
2388 fattr = dos_mode(conn, fsp->fsp_name);
2389 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2390 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2391 close_file(req, fsp, ERROR_CLOSE);
2392 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2393 goto out;
2396 /* If the caller set the extended oplock request bit
2397 and we granted one (by whatever means) - set the
2398 correct bit for extended oplock reply.
2401 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2402 smb_action |= EXTENDED_OPLOCK_GRANTED;
2405 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2406 smb_action |= EXTENDED_OPLOCK_GRANTED;
2409 /* If the caller set the core oplock request bit
2410 and we granted one (by whatever means) - set the
2411 correct bit for core oplock reply.
2414 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2415 reply_outbuf(req, 19, 0);
2416 } else {
2417 reply_outbuf(req, 15, 0);
2420 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2421 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2423 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2424 SCVAL(req->outbuf, smb_flg,
2425 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2428 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2429 SCVAL(req->outbuf, smb_flg,
2430 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2433 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2434 SSVAL(req->outbuf,smb_vwv3,fattr);
2435 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2436 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2437 } else {
2438 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2440 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2441 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2442 SSVAL(req->outbuf,smb_vwv11,smb_action);
2444 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2445 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2448 out:
2449 TALLOC_FREE(smb_fname);
2450 END_PROFILE(SMBopenX);
2451 return;
2454 /****************************************************************************
2455 Reply to a SMBulogoffX.
2456 ****************************************************************************/
2458 void reply_ulogoffX(struct smb_request *req)
2460 struct smbd_server_connection *sconn = req->sconn;
2461 struct user_struct *vuser;
2462 struct smbXsrv_session *session = NULL;
2463 NTSTATUS status;
2465 START_PROFILE(SMBulogoffX);
2467 vuser = get_valid_user_struct(sconn, req->vuid);
2469 if(vuser == NULL) {
2470 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2471 (unsigned long long)req->vuid));
2473 req->vuid = UID_FIELD_INVALID;
2474 reply_force_doserror(req, ERRSRV, ERRbaduid);
2475 END_PROFILE(SMBulogoffX);
2476 return;
2479 session = vuser->session;
2480 vuser = NULL;
2483 * TODO: cancel all outstanding requests on the session
2485 status = smbXsrv_session_logoff(session);
2486 if (!NT_STATUS_IS_OK(status)) {
2487 DEBUG(0, ("reply_ulogoff: "
2488 "smbXsrv_session_logoff() failed: %s\n",
2489 nt_errstr(status)));
2491 * If we hit this case, there is something completely
2492 * wrong, so we better disconnect the transport connection.
2494 END_PROFILE(SMBulogoffX);
2495 exit_server(__location__ ": smbXsrv_session_logoff failed");
2496 return;
2499 TALLOC_FREE(session);
2501 reply_outbuf(req, 2, 0);
2502 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2503 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2505 DEBUG(3, ("ulogoffX vuid=%llu\n",
2506 (unsigned long long)req->vuid));
2508 END_PROFILE(SMBulogoffX);
2509 req->vuid = UID_FIELD_INVALID;
2512 /****************************************************************************
2513 Reply to a mknew or a create.
2514 ****************************************************************************/
2516 void reply_mknew(struct smb_request *req)
2518 connection_struct *conn = req->conn;
2519 struct smb_filename *smb_fname = NULL;
2520 char *fname = NULL;
2521 uint32_t fattr = 0;
2522 struct smb_file_time ft;
2523 files_struct *fsp;
2524 int oplock_request = 0;
2525 NTSTATUS status;
2526 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2527 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2528 uint32_t create_disposition;
2529 uint32_t create_options = 0;
2530 uint32_t ucf_flags;
2531 TALLOC_CTX *ctx = talloc_tos();
2533 START_PROFILE(SMBcreate);
2534 ZERO_STRUCT(ft);
2536 if (req->wct < 3) {
2537 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2538 goto out;
2541 fattr = SVAL(req->vwv+0, 0);
2542 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2544 if (req->cmd == SMBmknew) {
2545 /* We should fail if file exists. */
2546 create_disposition = FILE_CREATE;
2547 } else {
2548 /* Create if file doesn't exist, truncate if it does. */
2549 create_disposition = FILE_OVERWRITE_IF;
2552 /* mtime. */
2553 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2555 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2556 STR_TERMINATE, &status);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 reply_nterror(req, status);
2559 goto out;
2562 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2563 status = filename_convert(ctx,
2564 conn,
2565 fname,
2566 ucf_flags,
2567 NULL,
2568 &smb_fname);
2569 if (!NT_STATUS_IS_OK(status)) {
2570 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2571 reply_botherror(req,
2572 NT_STATUS_PATH_NOT_COVERED,
2573 ERRSRV, ERRbadpath);
2574 goto out;
2576 reply_nterror(req, status);
2577 goto out;
2580 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2581 DEBUG(0,("Attempt to create file (%s) with volid set - "
2582 "please report this\n",
2583 smb_fname_str_dbg(smb_fname)));
2586 status = SMB_VFS_CREATE_FILE(
2587 conn, /* conn */
2588 req, /* req */
2589 0, /* root_dir_fid */
2590 smb_fname, /* fname */
2591 access_mask, /* access_mask */
2592 share_mode, /* share_access */
2593 create_disposition, /* create_disposition*/
2594 create_options, /* create_options */
2595 fattr, /* file_attributes */
2596 oplock_request, /* oplock_request */
2597 NULL, /* lease */
2598 0, /* allocation_size */
2599 0, /* private_flags */
2600 NULL, /* sd */
2601 NULL, /* ea_list */
2602 &fsp, /* result */
2603 NULL, /* pinfo */
2604 NULL, NULL); /* create context */
2606 if (!NT_STATUS_IS_OK(status)) {
2607 if (open_was_deferred(req->xconn, req->mid)) {
2608 /* We have re-scheduled this call. */
2609 goto out;
2611 reply_openerror(req, status);
2612 goto out;
2615 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2616 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 END_PROFILE(SMBcreate);
2619 goto out;
2622 reply_outbuf(req, 1, 0);
2623 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2625 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2626 SCVAL(req->outbuf,smb_flg,
2627 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2630 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2631 SCVAL(req->outbuf,smb_flg,
2632 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2635 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2636 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2637 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2638 (unsigned int)fattr));
2640 out:
2641 TALLOC_FREE(smb_fname);
2642 END_PROFILE(SMBcreate);
2643 return;
2646 /****************************************************************************
2647 Reply to a create temporary file.
2648 ****************************************************************************/
2650 void reply_ctemp(struct smb_request *req)
2652 connection_struct *conn = req->conn;
2653 struct smb_filename *smb_fname = NULL;
2654 char *wire_name = NULL;
2655 char *fname = NULL;
2656 uint32_t fattr;
2657 files_struct *fsp;
2658 int oplock_request;
2659 char *s;
2660 NTSTATUS status;
2661 int i;
2662 uint32_t ucf_flags;
2663 TALLOC_CTX *ctx = talloc_tos();
2665 START_PROFILE(SMBctemp);
2667 if (req->wct < 3) {
2668 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2669 goto out;
2672 fattr = SVAL(req->vwv+0, 0);
2673 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2675 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2676 STR_TERMINATE, &status);
2677 if (!NT_STATUS_IS_OK(status)) {
2678 reply_nterror(req, status);
2679 goto out;
2682 for (i = 0; i < 10; i++) {
2683 if (*wire_name) {
2684 fname = talloc_asprintf(ctx,
2685 "%s/TMP%s",
2686 wire_name,
2687 generate_random_str_list(ctx, 5, "0123456789"));
2688 } else {
2689 fname = talloc_asprintf(ctx,
2690 "TMP%s",
2691 generate_random_str_list(ctx, 5, "0123456789"));
2694 if (!fname) {
2695 reply_nterror(req, NT_STATUS_NO_MEMORY);
2696 goto out;
2699 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2700 status = filename_convert(ctx, conn,
2701 fname,
2702 ucf_flags,
2703 NULL,
2704 &smb_fname);
2705 if (!NT_STATUS_IS_OK(status)) {
2706 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2707 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2708 ERRSRV, ERRbadpath);
2709 goto out;
2711 reply_nterror(req, status);
2712 goto out;
2715 /* Create the file. */
2716 status = SMB_VFS_CREATE_FILE(
2717 conn, /* conn */
2718 req, /* req */
2719 0, /* root_dir_fid */
2720 smb_fname, /* fname */
2721 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2722 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2723 FILE_CREATE, /* create_disposition*/
2724 0, /* create_options */
2725 fattr, /* file_attributes */
2726 oplock_request, /* oplock_request */
2727 NULL, /* lease */
2728 0, /* allocation_size */
2729 0, /* private_flags */
2730 NULL, /* sd */
2731 NULL, /* ea_list */
2732 &fsp, /* result */
2733 NULL, /* pinfo */
2734 NULL, NULL); /* create context */
2736 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2737 TALLOC_FREE(fname);
2738 TALLOC_FREE(smb_fname);
2739 continue;
2742 if (!NT_STATUS_IS_OK(status)) {
2743 if (open_was_deferred(req->xconn, req->mid)) {
2744 /* We have re-scheduled this call. */
2745 goto out;
2747 reply_openerror(req, status);
2748 goto out;
2751 break;
2754 if (i == 10) {
2755 /* Collision after 10 times... */
2756 reply_nterror(req, status);
2757 goto out;
2760 reply_outbuf(req, 1, 0);
2761 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2763 /* the returned filename is relative to the directory */
2764 s = strrchr_m(fsp->fsp_name->base_name, '/');
2765 if (!s) {
2766 s = fsp->fsp_name->base_name;
2767 } else {
2768 s++;
2771 #if 0
2772 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2773 thing in the byte section. JRA */
2774 SSVALS(p, 0, -1); /* what is this? not in spec */
2775 #endif
2776 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2777 == -1) {
2778 reply_nterror(req, NT_STATUS_NO_MEMORY);
2779 goto out;
2782 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2783 SCVAL(req->outbuf, smb_flg,
2784 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2787 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2788 SCVAL(req->outbuf, smb_flg,
2789 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2792 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2793 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2794 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2795 out:
2796 TALLOC_FREE(smb_fname);
2797 TALLOC_FREE(wire_name);
2798 END_PROFILE(SMBctemp);
2799 return;
2802 /*******************************************************************
2803 Check if a user is allowed to rename a file.
2804 ********************************************************************/
2806 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2807 uint16_t dirtype)
2809 if (!CAN_WRITE(conn)) {
2810 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2813 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2814 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2815 /* Only bother to read the DOS attribute if we might deny the
2816 rename on the grounds of attribute mismatch. */
2817 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2818 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2819 return NT_STATUS_NO_SUCH_FILE;
2823 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2824 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2825 return NT_STATUS_OK;
2828 /* If no pathnames are open below this
2829 directory, allow the rename. */
2831 if (lp_strict_rename(SNUM(conn))) {
2833 * Strict rename, check open file db.
2835 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2836 return NT_STATUS_ACCESS_DENIED;
2838 } else if (file_find_subpath(fsp)) {
2840 * No strict rename, just look in local process.
2842 return NT_STATUS_ACCESS_DENIED;
2844 return NT_STATUS_OK;
2847 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2848 return NT_STATUS_OK;
2851 return NT_STATUS_ACCESS_DENIED;
2854 /*******************************************************************
2855 * unlink a file with all relevant access checks
2856 *******************************************************************/
2858 static NTSTATUS do_unlink(connection_struct *conn,
2859 struct smb_request *req,
2860 struct smb_filename *smb_fname,
2861 uint32_t dirtype)
2863 uint32_t fattr;
2864 files_struct *fsp;
2865 uint32_t dirtype_orig = dirtype;
2866 NTSTATUS status;
2867 int ret;
2868 bool posix_paths = (req != NULL && req->posix_pathnames);
2870 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2871 smb_fname_str_dbg(smb_fname),
2872 dirtype));
2874 if (!CAN_WRITE(conn)) {
2875 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2878 if (posix_paths) {
2879 ret = SMB_VFS_LSTAT(conn, smb_fname);
2880 } else {
2881 ret = SMB_VFS_STAT(conn, smb_fname);
2883 if (ret != 0) {
2884 return map_nt_error_from_unix(errno);
2887 fattr = dos_mode(conn, smb_fname);
2889 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2890 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2893 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2894 if (!dirtype) {
2895 return NT_STATUS_NO_SUCH_FILE;
2898 if (!dir_check_ftype(fattr, dirtype)) {
2899 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2900 return NT_STATUS_FILE_IS_A_DIRECTORY;
2902 return NT_STATUS_NO_SUCH_FILE;
2905 if (dirtype_orig & 0x8000) {
2906 /* These will never be set for POSIX. */
2907 return NT_STATUS_NO_SUCH_FILE;
2910 #if 0
2911 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2912 return NT_STATUS_FILE_IS_A_DIRECTORY;
2915 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2916 return NT_STATUS_NO_SUCH_FILE;
2919 if (dirtype & 0xFF00) {
2920 /* These will never be set for POSIX. */
2921 return NT_STATUS_NO_SUCH_FILE;
2924 dirtype &= 0xFF;
2925 if (!dirtype) {
2926 return NT_STATUS_NO_SUCH_FILE;
2929 /* Can't delete a directory. */
2930 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2931 return NT_STATUS_FILE_IS_A_DIRECTORY;
2933 #endif
2935 #if 0 /* JRATEST */
2936 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2937 return NT_STATUS_OBJECT_NAME_INVALID;
2938 #endif /* JRATEST */
2940 /* On open checks the open itself will check the share mode, so
2941 don't do it here as we'll get it wrong. */
2943 status = SMB_VFS_CREATE_FILE
2944 (conn, /* conn */
2945 req, /* req */
2946 0, /* root_dir_fid */
2947 smb_fname, /* fname */
2948 DELETE_ACCESS, /* access_mask */
2949 FILE_SHARE_NONE, /* share_access */
2950 FILE_OPEN, /* create_disposition*/
2951 FILE_NON_DIRECTORY_FILE, /* create_options */
2952 /* file_attributes */
2953 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2954 FILE_ATTRIBUTE_NORMAL,
2955 0, /* oplock_request */
2956 NULL, /* lease */
2957 0, /* allocation_size */
2958 0, /* private_flags */
2959 NULL, /* sd */
2960 NULL, /* ea_list */
2961 &fsp, /* result */
2962 NULL, /* pinfo */
2963 NULL, NULL); /* create context */
2965 if (!NT_STATUS_IS_OK(status)) {
2966 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2967 nt_errstr(status)));
2968 return status;
2971 status = can_set_delete_on_close(fsp, fattr);
2972 if (!NT_STATUS_IS_OK(status)) {
2973 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2974 "(%s)\n",
2975 smb_fname_str_dbg(smb_fname),
2976 nt_errstr(status)));
2977 close_file(req, fsp, NORMAL_CLOSE);
2978 return status;
2981 /* The set is across all open files on this dev/inode pair. */
2982 if (!set_delete_on_close(fsp, True,
2983 conn->session_info->security_token,
2984 conn->session_info->unix_token)) {
2985 close_file(req, fsp, NORMAL_CLOSE);
2986 return NT_STATUS_ACCESS_DENIED;
2989 return close_file(req, fsp, NORMAL_CLOSE);
2992 /****************************************************************************
2993 The guts of the unlink command, split out so it may be called by the NT SMB
2994 code.
2995 ****************************************************************************/
2997 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2998 uint32_t dirtype, struct smb_filename *smb_fname,
2999 bool has_wild)
3001 char *fname_dir = NULL;
3002 char *fname_mask = NULL;
3003 int count=0;
3004 NTSTATUS status = NT_STATUS_OK;
3005 struct smb_filename *smb_fname_dir = NULL;
3006 TALLOC_CTX *ctx = talloc_tos();
3008 /* Split up the directory from the filename/mask. */
3009 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3010 &fname_dir, &fname_mask);
3011 if (!NT_STATUS_IS_OK(status)) {
3012 goto out;
3016 * We should only check the mangled cache
3017 * here if unix_convert failed. This means
3018 * that the path in 'mask' doesn't exist
3019 * on the file system and so we need to look
3020 * for a possible mangle. This patch from
3021 * Tine Smukavec <valentin.smukavec@hermes.si>.
3024 if (!VALID_STAT(smb_fname->st) &&
3025 mangle_is_mangled(fname_mask, conn->params)) {
3026 char *new_mask = NULL;
3027 mangle_lookup_name_from_8_3(ctx, fname_mask,
3028 &new_mask, conn->params);
3029 if (new_mask) {
3030 TALLOC_FREE(fname_mask);
3031 fname_mask = new_mask;
3035 if (!has_wild) {
3038 * Only one file needs to be unlinked. Append the mask back
3039 * onto the directory.
3041 TALLOC_FREE(smb_fname->base_name);
3042 if (ISDOT(fname_dir)) {
3043 /* Ensure we use canonical names on open. */
3044 smb_fname->base_name = talloc_asprintf(smb_fname,
3045 "%s",
3046 fname_mask);
3047 } else {
3048 smb_fname->base_name = talloc_asprintf(smb_fname,
3049 "%s/%s",
3050 fname_dir,
3051 fname_mask);
3053 if (!smb_fname->base_name) {
3054 status = NT_STATUS_NO_MEMORY;
3055 goto out;
3057 if (dirtype == 0) {
3058 dirtype = FILE_ATTRIBUTE_NORMAL;
3061 status = check_name(conn, smb_fname);
3062 if (!NT_STATUS_IS_OK(status)) {
3063 goto out;
3066 status = do_unlink(conn, req, smb_fname, dirtype);
3067 if (!NT_STATUS_IS_OK(status)) {
3068 goto out;
3071 count++;
3072 } else {
3073 struct smb_Dir *dir_hnd = NULL;
3074 long offset = 0;
3075 const char *dname = NULL;
3076 char *talloced = NULL;
3078 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3079 status = NT_STATUS_OBJECT_NAME_INVALID;
3080 goto out;
3082 if (dirtype == 0) {
3083 dirtype = FILE_ATTRIBUTE_NORMAL;
3086 if (strequal(fname_mask,"????????.???")) {
3087 TALLOC_FREE(fname_mask);
3088 fname_mask = talloc_strdup(ctx, "*");
3089 if (!fname_mask) {
3090 status = NT_STATUS_NO_MEMORY;
3091 goto out;
3095 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3096 fname_dir,
3097 NULL,
3098 NULL,
3099 smb_fname->flags);
3100 if (smb_fname_dir == NULL) {
3101 status = NT_STATUS_NO_MEMORY;
3102 goto out;
3105 status = check_name(conn, smb_fname_dir);
3106 if (!NT_STATUS_IS_OK(status)) {
3107 goto out;
3110 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3111 dirtype);
3112 if (dir_hnd == NULL) {
3113 status = map_nt_error_from_unix(errno);
3114 goto out;
3117 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3118 the pattern matches against the long name, otherwise the short name
3119 We don't implement this yet XXXX
3122 status = NT_STATUS_NO_SUCH_FILE;
3124 while ((dname = ReadDirName(dir_hnd, &offset,
3125 &smb_fname->st, &talloced))) {
3126 TALLOC_CTX *frame = talloc_stackframe();
3128 if (!is_visible_file(conn, fname_dir, dname,
3129 &smb_fname->st, true)) {
3130 TALLOC_FREE(frame);
3131 TALLOC_FREE(talloced);
3132 continue;
3135 /* Quick check for "." and ".." */
3136 if (ISDOT(dname) || ISDOTDOT(dname)) {
3137 TALLOC_FREE(frame);
3138 TALLOC_FREE(talloced);
3139 continue;
3142 if(!mask_match(dname, fname_mask,
3143 conn->case_sensitive)) {
3144 TALLOC_FREE(frame);
3145 TALLOC_FREE(talloced);
3146 continue;
3149 TALLOC_FREE(smb_fname->base_name);
3150 if (ISDOT(fname_dir)) {
3151 /* Ensure we use canonical names on open. */
3152 smb_fname->base_name =
3153 talloc_asprintf(smb_fname, "%s",
3154 dname);
3155 } else {
3156 smb_fname->base_name =
3157 talloc_asprintf(smb_fname, "%s/%s",
3158 fname_dir, dname);
3161 if (!smb_fname->base_name) {
3162 TALLOC_FREE(dir_hnd);
3163 status = NT_STATUS_NO_MEMORY;
3164 TALLOC_FREE(frame);
3165 TALLOC_FREE(talloced);
3166 goto out;
3169 status = check_name(conn, smb_fname);
3170 if (!NT_STATUS_IS_OK(status)) {
3171 TALLOC_FREE(dir_hnd);
3172 TALLOC_FREE(frame);
3173 TALLOC_FREE(talloced);
3174 goto out;
3177 status = do_unlink(conn, req, smb_fname, dirtype);
3178 if (!NT_STATUS_IS_OK(status)) {
3179 TALLOC_FREE(dir_hnd);
3180 TALLOC_FREE(frame);
3181 TALLOC_FREE(talloced);
3182 goto out;
3185 count++;
3186 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3187 smb_fname->base_name));
3189 TALLOC_FREE(frame);
3190 TALLOC_FREE(talloced);
3192 TALLOC_FREE(dir_hnd);
3195 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3196 status = map_nt_error_from_unix(errno);
3199 out:
3200 TALLOC_FREE(smb_fname_dir);
3201 TALLOC_FREE(fname_dir);
3202 TALLOC_FREE(fname_mask);
3203 return status;
3206 /****************************************************************************
3207 Reply to a unlink
3208 ****************************************************************************/
3210 void reply_unlink(struct smb_request *req)
3212 connection_struct *conn = req->conn;
3213 char *name = NULL;
3214 struct smb_filename *smb_fname = NULL;
3215 uint32_t dirtype;
3216 NTSTATUS status;
3217 bool path_contains_wcard = False;
3218 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3219 ucf_flags_from_smb_request(req);
3220 TALLOC_CTX *ctx = talloc_tos();
3222 START_PROFILE(SMBunlink);
3224 if (req->wct < 1) {
3225 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3226 goto out;
3229 dirtype = SVAL(req->vwv+0, 0);
3231 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3232 STR_TERMINATE, &status,
3233 &path_contains_wcard);
3234 if (!NT_STATUS_IS_OK(status)) {
3235 reply_nterror(req, status);
3236 goto out;
3239 status = filename_convert(ctx, conn,
3240 name,
3241 ucf_flags,
3242 &path_contains_wcard,
3243 &smb_fname);
3244 if (!NT_STATUS_IS_OK(status)) {
3245 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3246 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3247 ERRSRV, ERRbadpath);
3248 goto out;
3250 reply_nterror(req, status);
3251 goto out;
3254 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3256 status = unlink_internals(conn, req, dirtype, smb_fname,
3257 path_contains_wcard);
3258 if (!NT_STATUS_IS_OK(status)) {
3259 if (open_was_deferred(req->xconn, req->mid)) {
3260 /* We have re-scheduled this call. */
3261 goto out;
3263 reply_nterror(req, status);
3264 goto out;
3267 reply_outbuf(req, 0, 0);
3268 out:
3269 TALLOC_FREE(smb_fname);
3270 END_PROFILE(SMBunlink);
3271 return;
3274 /****************************************************************************
3275 Fail for readbraw.
3276 ****************************************************************************/
3278 static void fail_readraw(void)
3280 const char *errstr = talloc_asprintf(talloc_tos(),
3281 "FAIL ! reply_readbraw: socket write fail (%s)",
3282 strerror(errno));
3283 if (!errstr) {
3284 errstr = "";
3286 exit_server_cleanly(errstr);
3289 /****************************************************************************
3290 Fake (read/write) sendfile. Returns -1 on read or write fail.
3291 ****************************************************************************/
3293 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3294 off_t startpos, size_t nread)
3296 size_t bufsize;
3297 size_t tosend = nread;
3298 char *buf;
3300 if (nread == 0) {
3301 return 0;
3304 bufsize = MIN(nread, 65536);
3306 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3307 return -1;
3310 while (tosend > 0) {
3311 ssize_t ret;
3312 size_t cur_read;
3314 cur_read = MIN(tosend, bufsize);
3315 ret = read_file(fsp,buf,startpos,cur_read);
3316 if (ret == -1) {
3317 SAFE_FREE(buf);
3318 return -1;
3321 /* If we had a short read, fill with zeros. */
3322 if (ret < cur_read) {
3323 memset(buf + ret, '\0', cur_read - ret);
3326 ret = write_data(xconn->transport.sock, buf, cur_read);
3327 if (ret != cur_read) {
3328 int saved_errno = errno;
3330 * Try and give an error message saying what
3331 * client failed.
3333 DEBUG(0, ("write_data failed for client %s. "
3334 "Error %s\n",
3335 smbXsrv_connection_dbg(xconn),
3336 strerror(saved_errno)));
3337 SAFE_FREE(buf);
3338 errno = saved_errno;
3339 return -1;
3341 tosend -= cur_read;
3342 startpos += cur_read;
3345 SAFE_FREE(buf);
3346 return (ssize_t)nread;
3349 /****************************************************************************
3350 Deal with the case of sendfile reading less bytes from the file than
3351 requested. Fill with zeros (all we can do). Returns 0 on success
3352 ****************************************************************************/
3354 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3355 files_struct *fsp,
3356 ssize_t nread,
3357 size_t headersize,
3358 size_t smb_maxcnt)
3360 #define SHORT_SEND_BUFSIZE 1024
3361 if (nread < headersize) {
3362 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3363 "header for file %s (%s). Terminating\n",
3364 fsp_str_dbg(fsp), strerror(errno)));
3365 return -1;
3368 nread -= headersize;
3370 if (nread < smb_maxcnt) {
3371 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3372 if (!buf) {
3373 DEBUG(0,("sendfile_short_send: malloc failed "
3374 "for file %s (%s). Terminating\n",
3375 fsp_str_dbg(fsp), strerror(errno)));
3376 return -1;
3379 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3380 "with zeros !\n", fsp_str_dbg(fsp)));
3382 while (nread < smb_maxcnt) {
3384 * We asked for the real file size and told sendfile
3385 * to not go beyond the end of the file. But it can
3386 * happen that in between our fstat call and the
3387 * sendfile call the file was truncated. This is very
3388 * bad because we have already announced the larger
3389 * number of bytes to the client.
3391 * The best we can do now is to send 0-bytes, just as
3392 * a read from a hole in a sparse file would do.
3394 * This should happen rarely enough that I don't care
3395 * about efficiency here :-)
3397 size_t to_write;
3398 ssize_t ret;
3400 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3401 ret = write_data(xconn->transport.sock, buf, to_write);
3402 if (ret != to_write) {
3403 int saved_errno = errno;
3405 * Try and give an error message saying what
3406 * client failed.
3408 DEBUG(0, ("write_data failed for client %s. "
3409 "Error %s\n",
3410 smbXsrv_connection_dbg(xconn),
3411 strerror(saved_errno)));
3412 errno = saved_errno;
3413 return -1;
3415 nread += to_write;
3417 SAFE_FREE(buf);
3420 return 0;
3423 /****************************************************************************
3424 Return a readbraw error (4 bytes of zero).
3425 ****************************************************************************/
3427 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3429 char header[4];
3431 SIVAL(header,0,0);
3433 smbd_lock_socket(xconn);
3434 if (write_data(xconn->transport.sock,header,4) != 4) {
3435 int saved_errno = errno;
3437 * Try and give an error message saying what
3438 * client failed.
3440 DEBUG(0, ("write_data failed for client %s. "
3441 "Error %s\n",
3442 smbXsrv_connection_dbg(xconn),
3443 strerror(saved_errno)));
3444 errno = saved_errno;
3446 fail_readraw();
3448 smbd_unlock_socket(xconn);
3451 /****************************************************************************
3452 Use sendfile in readbraw.
3453 ****************************************************************************/
3455 static void send_file_readbraw(connection_struct *conn,
3456 struct smb_request *req,
3457 files_struct *fsp,
3458 off_t startpos,
3459 size_t nread,
3460 ssize_t mincount)
3462 struct smbXsrv_connection *xconn = req->xconn;
3463 char *outbuf = NULL;
3464 ssize_t ret=0;
3467 * We can only use sendfile on a non-chained packet
3468 * but we can use on a non-oplocked file. tridge proved this
3469 * on a train in Germany :-). JRA.
3470 * reply_readbraw has already checked the length.
3473 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3474 (fsp->wcp == NULL) &&
3475 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3476 ssize_t sendfile_read = -1;
3477 char header[4];
3478 DATA_BLOB header_blob;
3480 _smb_setlen(header,nread);
3481 header_blob = data_blob_const(header, 4);
3483 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3484 &header_blob, startpos,
3485 nread);
3486 if (sendfile_read == -1) {
3487 /* Returning ENOSYS means no data at all was sent.
3488 * Do this as a normal read. */
3489 if (errno == ENOSYS) {
3490 goto normal_readbraw;
3494 * Special hack for broken Linux with no working sendfile. If we
3495 * return EINTR we sent the header but not the rest of the data.
3496 * Fake this up by doing read/write calls.
3498 if (errno == EINTR) {
3499 /* Ensure we don't do this again. */
3500 set_use_sendfile(SNUM(conn), False);
3501 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3503 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3504 DEBUG(0,("send_file_readbraw: "
3505 "fake_sendfile failed for "
3506 "file %s (%s).\n",
3507 fsp_str_dbg(fsp),
3508 strerror(errno)));
3509 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3511 return;
3514 DEBUG(0,("send_file_readbraw: sendfile failed for "
3515 "file %s (%s). Terminating\n",
3516 fsp_str_dbg(fsp), strerror(errno)));
3517 exit_server_cleanly("send_file_readbraw sendfile failed");
3518 } else if (sendfile_read == 0) {
3520 * Some sendfile implementations return 0 to indicate
3521 * that there was a short read, but nothing was
3522 * actually written to the socket. In this case,
3523 * fallback to the normal read path so the header gets
3524 * the correct byte count.
3526 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3527 "bytes falling back to the normal read: "
3528 "%s\n", fsp_str_dbg(fsp)));
3529 goto normal_readbraw;
3532 /* Deal with possible short send. */
3533 if (sendfile_read != 4+nread) {
3534 ret = sendfile_short_send(xconn, fsp,
3535 sendfile_read, 4, nread);
3536 if (ret == -1) {
3537 fail_readraw();
3540 return;
3543 normal_readbraw:
3545 outbuf = talloc_array(NULL, char, nread+4);
3546 if (!outbuf) {
3547 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3548 (unsigned)(nread+4)));
3549 reply_readbraw_error(xconn);
3550 return;
3553 if (nread > 0) {
3554 ret = read_file(fsp,outbuf+4,startpos,nread);
3555 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3556 if (ret < mincount)
3557 ret = 0;
3558 #else
3559 if (ret < nread)
3560 ret = 0;
3561 #endif
3564 _smb_setlen(outbuf,ret);
3565 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3566 int saved_errno = errno;
3568 * Try and give an error message saying what
3569 * client failed.
3571 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3572 smbXsrv_connection_dbg(xconn),
3573 strerror(saved_errno)));
3574 errno = saved_errno;
3576 fail_readraw();
3579 TALLOC_FREE(outbuf);
3582 /****************************************************************************
3583 Reply to a readbraw (core+ protocol).
3584 ****************************************************************************/
3586 void reply_readbraw(struct smb_request *req)
3588 connection_struct *conn = req->conn;
3589 struct smbXsrv_connection *xconn = req->xconn;
3590 ssize_t maxcount,mincount;
3591 size_t nread = 0;
3592 off_t startpos;
3593 files_struct *fsp;
3594 struct lock_struct lock;
3595 off_t size = 0;
3597 START_PROFILE(SMBreadbraw);
3599 if (srv_is_signing_active(xconn) || req->encrypted) {
3600 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3601 "raw reads/writes are disallowed.");
3604 if (req->wct < 8) {
3605 reply_readbraw_error(xconn);
3606 END_PROFILE(SMBreadbraw);
3607 return;
3610 if (xconn->smb1.echo_handler.trusted_fde) {
3611 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3612 "'async smb echo handler = yes'\n"));
3613 reply_readbraw_error(xconn);
3614 END_PROFILE(SMBreadbraw);
3615 return;
3619 * Special check if an oplock break has been issued
3620 * and the readraw request croses on the wire, we must
3621 * return a zero length response here.
3624 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3627 * We have to do a check_fsp by hand here, as
3628 * we must always return 4 zero bytes on error,
3629 * not a NTSTATUS.
3632 if (!fsp || !conn || conn != fsp->conn ||
3633 req->vuid != fsp->vuid ||
3634 fsp->is_directory || fsp->fh->fd == -1) {
3636 * fsp could be NULL here so use the value from the packet. JRA.
3638 DEBUG(3,("reply_readbraw: fnum %d not valid "
3639 "- cache prime?\n",
3640 (int)SVAL(req->vwv+0, 0)));
3641 reply_readbraw_error(xconn);
3642 END_PROFILE(SMBreadbraw);
3643 return;
3646 /* Do a "by hand" version of CHECK_READ. */
3647 if (!(fsp->can_read ||
3648 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3649 (fsp->access_mask & FILE_EXECUTE)))) {
3650 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3651 (int)SVAL(req->vwv+0, 0)));
3652 reply_readbraw_error(xconn);
3653 END_PROFILE(SMBreadbraw);
3654 return;
3657 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3659 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3660 if(req->wct == 10) {
3662 * This is a large offset (64 bit) read.
3665 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3667 if(startpos < 0) {
3668 DEBUG(0,("reply_readbraw: negative 64 bit "
3669 "readraw offset (%.0f) !\n",
3670 (double)startpos ));
3671 reply_readbraw_error(xconn);
3672 END_PROFILE(SMBreadbraw);
3673 return;
3677 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3678 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3680 /* ensure we don't overrun the packet size */
3681 maxcount = MIN(65535,maxcount);
3683 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3684 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3685 &lock);
3687 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3688 reply_readbraw_error(xconn);
3689 END_PROFILE(SMBreadbraw);
3690 return;
3693 if (fsp_stat(fsp) == 0) {
3694 size = fsp->fsp_name->st.st_ex_size;
3697 if (startpos >= size) {
3698 nread = 0;
3699 } else {
3700 nread = MIN(maxcount,(size - startpos));
3703 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3704 if (nread < mincount)
3705 nread = 0;
3706 #endif
3708 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3709 "min=%lu nread=%lu\n",
3710 fsp_fnum_dbg(fsp), (double)startpos,
3711 (unsigned long)maxcount,
3712 (unsigned long)mincount,
3713 (unsigned long)nread ) );
3715 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3717 DEBUG(5,("reply_readbraw finished\n"));
3719 END_PROFILE(SMBreadbraw);
3720 return;
3723 #undef DBGC_CLASS
3724 #define DBGC_CLASS DBGC_LOCKING
3726 /****************************************************************************
3727 Reply to a lockread (core+ protocol).
3728 ****************************************************************************/
3730 void reply_lockread(struct smb_request *req)
3732 connection_struct *conn = req->conn;
3733 ssize_t nread = -1;
3734 char *data;
3735 off_t startpos;
3736 size_t numtoread;
3737 size_t maxtoread;
3738 NTSTATUS status;
3739 files_struct *fsp;
3740 struct byte_range_lock *br_lck = NULL;
3741 char *p = NULL;
3742 struct smbXsrv_connection *xconn = req->xconn;
3744 START_PROFILE(SMBlockread);
3746 if (req->wct < 5) {
3747 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3748 END_PROFILE(SMBlockread);
3749 return;
3752 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3754 if (!check_fsp(conn, req, fsp)) {
3755 END_PROFILE(SMBlockread);
3756 return;
3759 if (!CHECK_READ(fsp,req)) {
3760 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3761 END_PROFILE(SMBlockread);
3762 return;
3765 numtoread = SVAL(req->vwv+1, 0);
3766 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3769 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3770 * protocol request that predates the read/write lock concept.
3771 * Thus instead of asking for a read lock here we need to ask
3772 * for a write lock. JRA.
3773 * Note that the requested lock size is unaffected by max_send.
3776 br_lck = do_lock(req->sconn->msg_ctx,
3777 fsp,
3778 (uint64_t)req->smbpid,
3779 (uint64_t)numtoread,
3780 (uint64_t)startpos,
3781 WRITE_LOCK,
3782 WINDOWS_LOCK,
3783 False, /* Non-blocking lock. */
3784 &status,
3785 NULL);
3786 TALLOC_FREE(br_lck);
3788 if (NT_STATUS_V(status)) {
3789 reply_nterror(req, status);
3790 END_PROFILE(SMBlockread);
3791 return;
3795 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3797 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3799 if (numtoread > maxtoread) {
3800 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3801 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3802 (unsigned int)numtoread, (unsigned int)maxtoread,
3803 (unsigned int)xconn->smb1.sessions.max_send));
3804 numtoread = maxtoread;
3807 reply_outbuf(req, 5, numtoread + 3);
3809 data = smb_buf(req->outbuf) + 3;
3811 nread = read_file(fsp,data,startpos,numtoread);
3813 if (nread < 0) {
3814 reply_nterror(req, map_nt_error_from_unix(errno));
3815 END_PROFILE(SMBlockread);
3816 return;
3819 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3821 SSVAL(req->outbuf,smb_vwv0,nread);
3822 SSVAL(req->outbuf,smb_vwv5,nread+3);
3823 p = smb_buf(req->outbuf);
3824 SCVAL(p,0,0); /* pad byte. */
3825 SSVAL(p,1,nread);
3827 DEBUG(3,("lockread %s num=%d nread=%d\n",
3828 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3830 END_PROFILE(SMBlockread);
3831 return;
3834 #undef DBGC_CLASS
3835 #define DBGC_CLASS DBGC_ALL
3837 /****************************************************************************
3838 Reply to a read.
3839 ****************************************************************************/
3841 void reply_read(struct smb_request *req)
3843 connection_struct *conn = req->conn;
3844 size_t numtoread;
3845 size_t maxtoread;
3846 ssize_t nread = 0;
3847 char *data;
3848 off_t startpos;
3849 files_struct *fsp;
3850 struct lock_struct lock;
3851 struct smbXsrv_connection *xconn = req->xconn;
3853 START_PROFILE(SMBread);
3855 if (req->wct < 3) {
3856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3857 END_PROFILE(SMBread);
3858 return;
3861 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3863 if (!check_fsp(conn, req, fsp)) {
3864 END_PROFILE(SMBread);
3865 return;
3868 if (!CHECK_READ(fsp,req)) {
3869 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3870 END_PROFILE(SMBread);
3871 return;
3874 numtoread = SVAL(req->vwv+1, 0);
3875 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3878 * The requested read size cannot be greater than max_send. JRA.
3880 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3882 if (numtoread > maxtoread) {
3883 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3884 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3885 (unsigned int)numtoread, (unsigned int)maxtoread,
3886 (unsigned int)xconn->smb1.sessions.max_send));
3887 numtoread = maxtoread;
3890 reply_outbuf(req, 5, numtoread+3);
3892 data = smb_buf(req->outbuf) + 3;
3894 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3895 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3896 &lock);
3898 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3899 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3900 END_PROFILE(SMBread);
3901 return;
3904 if (numtoread > 0)
3905 nread = read_file(fsp,data,startpos,numtoread);
3907 if (nread < 0) {
3908 reply_nterror(req, map_nt_error_from_unix(errno));
3909 goto out;
3912 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3914 SSVAL(req->outbuf,smb_vwv0,nread);
3915 SSVAL(req->outbuf,smb_vwv5,nread+3);
3916 SCVAL(smb_buf(req->outbuf),0,1);
3917 SSVAL(smb_buf(req->outbuf),1,nread);
3919 DEBUG(3, ("read %s num=%d nread=%d\n",
3920 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3922 out:
3923 END_PROFILE(SMBread);
3924 return;
3927 /****************************************************************************
3928 Setup readX header.
3929 ****************************************************************************/
3931 int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3933 int outsize;
3935 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3936 False);
3938 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3940 SCVAL(outbuf,smb_vwv0,0xFF);
3941 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3942 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3943 SSVAL(outbuf,smb_vwv6,
3944 (smb_wct - 4) /* offset from smb header to wct */
3945 + 1 /* the wct field */
3946 + 12 * sizeof(uint16_t) /* vwv */
3947 + 2 /* the buflen field */
3948 + 1); /* padding byte */
3949 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3950 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3951 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3952 _smb_setlen_large(outbuf,
3953 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3954 return outsize;
3957 /****************************************************************************
3958 Reply to a read and X - possibly using sendfile.
3959 ****************************************************************************/
3961 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3962 files_struct *fsp, off_t startpos,
3963 size_t smb_maxcnt)
3965 struct smbXsrv_connection *xconn = req->xconn;
3966 ssize_t nread = -1;
3967 struct lock_struct lock;
3968 int saved_errno = 0;
3970 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3971 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3972 &lock);
3974 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3975 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3976 return;
3980 * We can only use sendfile on a non-chained packet
3981 * but we can use on a non-oplocked file. tridge proved this
3982 * on a train in Germany :-). JRA.
3985 if (!req_is_in_chain(req) &&
3986 !req->encrypted &&
3987 (fsp->base_fsp == NULL) &&
3988 (fsp->wcp == NULL) &&
3989 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3990 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3991 DATA_BLOB header;
3993 if(fsp_stat(fsp) == -1) {
3994 reply_nterror(req, map_nt_error_from_unix(errno));
3995 goto out;
3998 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3999 (startpos > fsp->fsp_name->st.st_ex_size) ||
4000 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4002 * We already know that we would do a short read, so don't
4003 * try the sendfile() path.
4005 goto nosendfile_read;
4009 * Set up the packet header before send. We
4010 * assume here the sendfile will work (get the
4011 * correct amount of data).
4014 header = data_blob_const(headerbuf, sizeof(headerbuf));
4016 construct_reply_common_req(req, (char *)headerbuf);
4017 setup_readX_header((char *)headerbuf, smb_maxcnt);
4019 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4020 startpos, smb_maxcnt);
4021 if (nread == -1) {
4022 saved_errno = errno;
4024 /* Returning ENOSYS means no data at all was sent.
4025 Do this as a normal read. */
4026 if (errno == ENOSYS) {
4027 goto normal_read;
4031 * Special hack for broken Linux with no working sendfile. If we
4032 * return EINTR we sent the header but not the rest of the data.
4033 * Fake this up by doing read/write calls.
4036 if (errno == EINTR) {
4037 /* Ensure we don't do this again. */
4038 set_use_sendfile(SNUM(conn), False);
4039 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4040 nread = fake_sendfile(xconn, fsp, startpos,
4041 smb_maxcnt);
4042 if (nread == -1) {
4043 saved_errno = errno;
4044 DEBUG(0,("send_file_readX: "
4045 "fake_sendfile failed for "
4046 "file %s (%s) for client %s. "
4047 "Terminating\n",
4048 fsp_str_dbg(fsp),
4049 smbXsrv_connection_dbg(xconn),
4050 strerror(saved_errno)));
4051 errno = saved_errno;
4052 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4054 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4055 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4056 /* No outbuf here means successful sendfile. */
4057 goto out;
4060 DEBUG(0,("send_file_readX: sendfile failed for file "
4061 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4062 strerror(errno)));
4063 exit_server_cleanly("send_file_readX sendfile failed");
4064 } else if (nread == 0) {
4066 * Some sendfile implementations return 0 to indicate
4067 * that there was a short read, but nothing was
4068 * actually written to the socket. In this case,
4069 * fallback to the normal read path so the header gets
4070 * the correct byte count.
4072 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4073 "falling back to the normal read: %s\n",
4074 fsp_str_dbg(fsp)));
4075 goto normal_read;
4078 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4079 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4081 /* Deal with possible short send. */
4082 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4083 ssize_t ret;
4085 ret = sendfile_short_send(xconn, fsp, nread,
4086 sizeof(headerbuf), smb_maxcnt);
4087 if (ret == -1) {
4088 const char *r;
4089 r = "send_file_readX: sendfile_short_send failed";
4090 DEBUG(0,("%s for file %s (%s).\n",
4091 r, fsp_str_dbg(fsp), strerror(errno)));
4092 exit_server_cleanly(r);
4095 /* No outbuf here means successful sendfile. */
4096 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4097 SMB_PERFCOUNT_END(&req->pcd);
4098 goto out;
4101 normal_read:
4103 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4104 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4105 ssize_t ret;
4107 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4108 (startpos > fsp->fsp_name->st.st_ex_size) ||
4109 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4111 * We already know that we would do a short
4112 * read, so don't try the sendfile() path.
4114 goto nosendfile_read;
4117 construct_reply_common_req(req, (char *)headerbuf);
4118 setup_readX_header((char *)headerbuf, smb_maxcnt);
4120 /* Send out the header. */
4121 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4122 sizeof(headerbuf));
4123 if (ret != sizeof(headerbuf)) {
4124 saved_errno = errno;
4126 * Try and give an error message saying what
4127 * client failed.
4129 DEBUG(0,("send_file_readX: write_data failed for file "
4130 "%s (%s) for client %s. Terminating\n",
4131 fsp_str_dbg(fsp),
4132 smbXsrv_connection_dbg(xconn),
4133 strerror(saved_errno)));
4134 errno = saved_errno;
4135 exit_server_cleanly("send_file_readX sendfile failed");
4137 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4138 if (nread == -1) {
4139 saved_errno = errno;
4140 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4141 "%s (%s) for client %s. Terminating\n",
4142 fsp_str_dbg(fsp),
4143 smbXsrv_connection_dbg(xconn),
4144 strerror(saved_errno)));
4145 errno = saved_errno;
4146 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4148 goto out;
4151 nosendfile_read:
4153 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4154 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4155 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4157 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4158 startpos, smb_maxcnt);
4159 saved_errno = errno;
4161 if (nread < 0) {
4162 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4163 return;
4166 setup_readX_header((char *)req->outbuf, nread);
4168 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4169 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4170 return;
4172 out:
4173 TALLOC_FREE(req->outbuf);
4174 return;
4177 /****************************************************************************
4178 Work out how much space we have for a read return.
4179 ****************************************************************************/
4181 static size_t calc_max_read_pdu(const struct smb_request *req)
4183 struct smbXsrv_connection *xconn = req->xconn;
4185 if (xconn->protocol < PROTOCOL_NT1) {
4186 return xconn->smb1.sessions.max_send;
4189 if (!lp_large_readwrite()) {
4190 return xconn->smb1.sessions.max_send;
4193 if (req_is_in_chain(req)) {
4194 return xconn->smb1.sessions.max_send;
4197 if (req->encrypted) {
4199 * Don't take encrypted traffic up to the
4200 * limit. There are padding considerations
4201 * that make that tricky.
4203 return xconn->smb1.sessions.max_send;
4206 if (srv_is_signing_active(xconn)) {
4207 return 0x1FFFF;
4210 if (!lp_unix_extensions()) {
4211 return 0x1FFFF;
4215 * We can do ultra-large POSIX reads.
4217 return 0xFFFFFF;
4220 /****************************************************************************
4221 Calculate how big a read can be. Copes with all clients. It's always
4222 safe to return a short read - Windows does this.
4223 ****************************************************************************/
4225 static size_t calc_read_size(const struct smb_request *req,
4226 size_t upper_size,
4227 size_t lower_size)
4229 struct smbXsrv_connection *xconn = req->xconn;
4230 size_t max_pdu = calc_max_read_pdu(req);
4231 size_t total_size = 0;
4232 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4233 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4236 * Windows explicitly ignores upper size of 0xFFFF.
4237 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4238 * We must do the same as these will never fit even in
4239 * an extended size NetBIOS packet.
4241 if (upper_size == 0xFFFF) {
4242 upper_size = 0;
4245 if (xconn->protocol < PROTOCOL_NT1) {
4246 upper_size = 0;
4249 total_size = ((upper_size<<16) | lower_size);
4252 * LARGE_READX test shows it's always safe to return
4253 * a short read. Windows does so.
4255 return MIN(total_size, max_len);
4258 /****************************************************************************
4259 Reply to a read and X.
4260 ****************************************************************************/
4262 void reply_read_and_X(struct smb_request *req)
4264 connection_struct *conn = req->conn;
4265 files_struct *fsp;
4266 off_t startpos;
4267 size_t smb_maxcnt;
4268 size_t upper_size;
4269 bool big_readX = False;
4270 #if 0
4271 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4272 #endif
4274 START_PROFILE(SMBreadX);
4276 if ((req->wct != 10) && (req->wct != 12)) {
4277 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4278 return;
4281 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4282 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4283 smb_maxcnt = SVAL(req->vwv+5, 0);
4285 /* If it's an IPC, pass off the pipe handler. */
4286 if (IS_IPC(conn)) {
4287 reply_pipe_read_and_X(req);
4288 END_PROFILE(SMBreadX);
4289 return;
4292 if (!check_fsp(conn, req, fsp)) {
4293 END_PROFILE(SMBreadX);
4294 return;
4297 if (!CHECK_READ(fsp,req)) {
4298 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4299 END_PROFILE(SMBreadX);
4300 return;
4303 upper_size = SVAL(req->vwv+7, 0);
4304 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4305 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4307 * This is a heuristic to avoid keeping large
4308 * outgoing buffers around over long-lived aio
4309 * requests.
4311 big_readX = True;
4314 if (req->wct == 12) {
4316 * This is a large offset (64 bit) read.
4318 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4322 if (!big_readX) {
4323 NTSTATUS status = schedule_aio_read_and_X(conn,
4324 req,
4325 fsp,
4326 startpos,
4327 smb_maxcnt);
4328 if (NT_STATUS_IS_OK(status)) {
4329 /* Read scheduled - we're done. */
4330 goto out;
4332 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4333 /* Real error - report to client. */
4334 END_PROFILE(SMBreadX);
4335 reply_nterror(req, status);
4336 return;
4338 /* NT_STATUS_RETRY - fall back to sync read. */
4341 smbd_lock_socket(req->xconn);
4342 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4343 smbd_unlock_socket(req->xconn);
4345 out:
4346 END_PROFILE(SMBreadX);
4347 return;
4350 /****************************************************************************
4351 Error replies to writebraw must have smb_wct == 1. Fix this up.
4352 ****************************************************************************/
4354 void error_to_writebrawerr(struct smb_request *req)
4356 uint8_t *old_outbuf = req->outbuf;
4358 reply_outbuf(req, 1, 0);
4360 memcpy(req->outbuf, old_outbuf, smb_size);
4361 TALLOC_FREE(old_outbuf);
4364 /****************************************************************************
4365 Read 4 bytes of a smb packet and return the smb length of the packet.
4366 Store the result in the buffer. This version of the function will
4367 never return a session keepalive (length of zero).
4368 Timeout is in milliseconds.
4369 ****************************************************************************/
4371 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4372 size_t *len)
4374 uint8_t msgtype = NBSSkeepalive;
4376 while (msgtype == NBSSkeepalive) {
4377 NTSTATUS status;
4379 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4380 len);
4381 if (!NT_STATUS_IS_OK(status)) {
4382 char addr[INET6_ADDRSTRLEN];
4383 /* Try and give an error message
4384 * saying what client failed. */
4385 DEBUG(0, ("read_fd_with_timeout failed for "
4386 "client %s read error = %s.\n",
4387 get_peer_addr(fd,addr,sizeof(addr)),
4388 nt_errstr(status)));
4389 return status;
4392 msgtype = CVAL(inbuf, 0);
4395 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4396 (unsigned long)len));
4398 return NT_STATUS_OK;
4401 /****************************************************************************
4402 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4403 ****************************************************************************/
4405 void reply_writebraw(struct smb_request *req)
4407 connection_struct *conn = req->conn;
4408 struct smbXsrv_connection *xconn = req->xconn;
4409 char *buf = NULL;
4410 ssize_t nwritten=0;
4411 ssize_t total_written=0;
4412 size_t numtowrite=0;
4413 size_t tcount;
4414 off_t startpos;
4415 const char *data=NULL;
4416 bool write_through;
4417 files_struct *fsp;
4418 struct lock_struct lock;
4419 NTSTATUS status;
4421 START_PROFILE(SMBwritebraw);
4424 * If we ever reply with an error, it must have the SMB command
4425 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4426 * we're finished.
4428 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4430 if (srv_is_signing_active(xconn)) {
4431 END_PROFILE(SMBwritebraw);
4432 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4433 "raw reads/writes are disallowed.");
4436 if (req->wct < 12) {
4437 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4438 error_to_writebrawerr(req);
4439 END_PROFILE(SMBwritebraw);
4440 return;
4443 if (xconn->smb1.echo_handler.trusted_fde) {
4444 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4445 "'async smb echo handler = yes'\n"));
4446 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4447 error_to_writebrawerr(req);
4448 END_PROFILE(SMBwritebraw);
4449 return;
4452 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4453 if (!check_fsp(conn, req, fsp)) {
4454 error_to_writebrawerr(req);
4455 END_PROFILE(SMBwritebraw);
4456 return;
4459 if (!CHECK_WRITE(fsp)) {
4460 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4461 error_to_writebrawerr(req);
4462 END_PROFILE(SMBwritebraw);
4463 return;
4466 tcount = IVAL(req->vwv+1, 0);
4467 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4468 write_through = BITSETW(req->vwv+7,0);
4470 /* We have to deal with slightly different formats depending
4471 on whether we are using the core+ or lanman1.0 protocol */
4473 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4474 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4475 data = smb_buf_const(req->inbuf);
4476 } else {
4477 numtowrite = SVAL(req->vwv+10, 0);
4478 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4481 /* Ensure we don't write bytes past the end of this packet. */
4483 * This already protects us against CVE-2017-12163.
4485 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4486 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4487 error_to_writebrawerr(req);
4488 END_PROFILE(SMBwritebraw);
4489 return;
4492 if (!fsp->print_file) {
4493 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4494 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4495 &lock);
4497 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4498 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4499 error_to_writebrawerr(req);
4500 END_PROFILE(SMBwritebraw);
4501 return;
4505 if (numtowrite>0) {
4506 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4509 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4510 "wrote=%d sync=%d\n",
4511 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4512 (int)nwritten, (int)write_through));
4514 if (nwritten < (ssize_t)numtowrite) {
4515 reply_nterror(req, NT_STATUS_DISK_FULL);
4516 error_to_writebrawerr(req);
4517 goto out;
4520 total_written = nwritten;
4522 /* Allocate a buffer of 64k + length. */
4523 buf = talloc_array(NULL, char, 65540);
4524 if (!buf) {
4525 reply_nterror(req, NT_STATUS_NO_MEMORY);
4526 error_to_writebrawerr(req);
4527 goto out;
4530 /* Return a SMBwritebraw message to the redirector to tell
4531 * it to send more bytes */
4533 memcpy(buf, req->inbuf, smb_size);
4534 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4535 SCVAL(buf,smb_com,SMBwritebraw);
4536 SSVALS(buf,smb_vwv0,0xFFFF);
4537 show_msg(buf);
4538 if (!srv_send_smb(req->xconn,
4539 buf,
4540 false, 0, /* no signing */
4541 IS_CONN_ENCRYPTED(conn),
4542 &req->pcd)) {
4543 exit_server_cleanly("reply_writebraw: srv_send_smb "
4544 "failed.");
4547 /* Now read the raw data into the buffer and write it */
4548 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4549 &numtowrite);
4550 if (!NT_STATUS_IS_OK(status)) {
4551 exit_server_cleanly("secondary writebraw failed");
4554 /* Set up outbuf to return the correct size */
4555 reply_outbuf(req, 1, 0);
4557 if (numtowrite != 0) {
4559 if (numtowrite > 0xFFFF) {
4560 DEBUG(0,("reply_writebraw: Oversize secondary write "
4561 "raw requested (%u). Terminating\n",
4562 (unsigned int)numtowrite ));
4563 exit_server_cleanly("secondary writebraw failed");
4566 if (tcount > nwritten+numtowrite) {
4567 DEBUG(3,("reply_writebraw: Client overestimated the "
4568 "write %d %d %d\n",
4569 (int)tcount,(int)nwritten,(int)numtowrite));
4572 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4573 numtowrite);
4575 if (!NT_STATUS_IS_OK(status)) {
4576 /* Try and give an error message
4577 * saying what client failed. */
4578 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4579 "raw read failed (%s) for client %s. "
4580 "Terminating\n", nt_errstr(status),
4581 smbXsrv_connection_dbg(xconn)));
4582 exit_server_cleanly("secondary writebraw failed");
4586 * We are not vulnerable to CVE-2017-12163
4587 * here as we are guarenteed to have numtowrite
4588 * bytes available - we just read from the client.
4590 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4591 if (nwritten == -1) {
4592 TALLOC_FREE(buf);
4593 reply_nterror(req, map_nt_error_from_unix(errno));
4594 error_to_writebrawerr(req);
4595 goto out;
4598 if (nwritten < (ssize_t)numtowrite) {
4599 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4600 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4603 if (nwritten > 0) {
4604 total_written += nwritten;
4608 TALLOC_FREE(buf);
4609 SSVAL(req->outbuf,smb_vwv0,total_written);
4611 status = sync_file(conn, fsp, write_through);
4612 if (!NT_STATUS_IS_OK(status)) {
4613 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4614 fsp_str_dbg(fsp), nt_errstr(status)));
4615 reply_nterror(req, status);
4616 error_to_writebrawerr(req);
4617 goto out;
4620 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4621 "wrote=%d\n",
4622 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4623 (int)total_written));
4625 /* We won't return a status if write through is not selected - this
4626 * follows what WfWg does */
4627 END_PROFILE(SMBwritebraw);
4629 if (!write_through && total_written==tcount) {
4631 #if RABBIT_PELLET_FIX
4633 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4634 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4635 * JRA.
4637 if (!send_keepalive(xconn->transport.sock)) {
4638 exit_server_cleanly("reply_writebraw: send of "
4639 "keepalive failed");
4641 #endif
4642 TALLOC_FREE(req->outbuf);
4644 return;
4646 out:
4647 END_PROFILE(SMBwritebraw);
4648 return;
4651 #undef DBGC_CLASS
4652 #define DBGC_CLASS DBGC_LOCKING
4654 /****************************************************************************
4655 Reply to a writeunlock (core+).
4656 ****************************************************************************/
4658 void reply_writeunlock(struct smb_request *req)
4660 connection_struct *conn = req->conn;
4661 ssize_t nwritten = -1;
4662 size_t numtowrite;
4663 size_t remaining;
4664 off_t startpos;
4665 const char *data;
4666 NTSTATUS status = NT_STATUS_OK;
4667 files_struct *fsp;
4668 struct lock_struct lock;
4669 int saved_errno = 0;
4671 START_PROFILE(SMBwriteunlock);
4673 if (req->wct < 5) {
4674 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4675 END_PROFILE(SMBwriteunlock);
4676 return;
4679 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4681 if (!check_fsp(conn, req, fsp)) {
4682 END_PROFILE(SMBwriteunlock);
4683 return;
4686 if (!CHECK_WRITE(fsp)) {
4687 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4688 END_PROFILE(SMBwriteunlock);
4689 return;
4692 numtowrite = SVAL(req->vwv+1, 0);
4693 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4694 data = (const char *)req->buf + 3;
4697 * Ensure client isn't asking us to write more than
4698 * they sent. CVE-2017-12163.
4700 remaining = smbreq_bufrem(req, data);
4701 if (numtowrite > remaining) {
4702 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4703 END_PROFILE(SMBwriteunlock);
4704 return;
4707 if (!fsp->print_file && numtowrite > 0) {
4708 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4709 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4710 &lock);
4712 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4713 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4714 END_PROFILE(SMBwriteunlock);
4715 return;
4719 /* The special X/Open SMB protocol handling of
4720 zero length writes is *NOT* done for
4721 this call */
4722 if(numtowrite == 0) {
4723 nwritten = 0;
4724 } else {
4725 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4726 saved_errno = errno;
4729 status = sync_file(conn, fsp, False /* write through */);
4730 if (!NT_STATUS_IS_OK(status)) {
4731 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4732 fsp_str_dbg(fsp), nt_errstr(status)));
4733 reply_nterror(req, status);
4734 goto out;
4737 if(nwritten < 0) {
4738 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4739 goto out;
4742 if((nwritten < numtowrite) && (numtowrite != 0)) {
4743 reply_nterror(req, NT_STATUS_DISK_FULL);
4744 goto out;
4747 if (numtowrite && !fsp->print_file) {
4748 status = do_unlock(req->sconn->msg_ctx,
4749 fsp,
4750 (uint64_t)req->smbpid,
4751 (uint64_t)numtowrite,
4752 (uint64_t)startpos,
4753 WINDOWS_LOCK);
4755 if (NT_STATUS_V(status)) {
4756 reply_nterror(req, status);
4757 goto out;
4761 reply_outbuf(req, 1, 0);
4763 SSVAL(req->outbuf,smb_vwv0,nwritten);
4765 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4766 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4768 out:
4769 END_PROFILE(SMBwriteunlock);
4770 return;
4773 #undef DBGC_CLASS
4774 #define DBGC_CLASS DBGC_ALL
4776 /****************************************************************************
4777 Reply to a write.
4778 ****************************************************************************/
4780 void reply_write(struct smb_request *req)
4782 connection_struct *conn = req->conn;
4783 size_t numtowrite;
4784 size_t remaining;
4785 ssize_t nwritten = -1;
4786 off_t startpos;
4787 const char *data;
4788 files_struct *fsp;
4789 struct lock_struct lock;
4790 NTSTATUS status;
4791 int saved_errno = 0;
4793 START_PROFILE(SMBwrite);
4795 if (req->wct < 5) {
4796 END_PROFILE(SMBwrite);
4797 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4798 return;
4801 /* If it's an IPC, pass off the pipe handler. */
4802 if (IS_IPC(conn)) {
4803 reply_pipe_write(req);
4804 END_PROFILE(SMBwrite);
4805 return;
4808 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4810 if (!check_fsp(conn, req, fsp)) {
4811 END_PROFILE(SMBwrite);
4812 return;
4815 if (!CHECK_WRITE(fsp)) {
4816 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4817 END_PROFILE(SMBwrite);
4818 return;
4821 numtowrite = SVAL(req->vwv+1, 0);
4822 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4823 data = (const char *)req->buf + 3;
4826 * Ensure client isn't asking us to write more than
4827 * they sent. CVE-2017-12163.
4829 remaining = smbreq_bufrem(req, data);
4830 if (numtowrite > remaining) {
4831 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4832 END_PROFILE(SMBwrite);
4833 return;
4836 if (!fsp->print_file) {
4837 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4838 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4839 &lock);
4841 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4842 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4843 END_PROFILE(SMBwrite);
4844 return;
4849 * X/Open SMB protocol says that if smb_vwv1 is
4850 * zero then the file size should be extended or
4851 * truncated to the size given in smb_vwv[2-3].
4854 if(numtowrite == 0) {
4856 * This is actually an allocate call, and set EOF. JRA.
4858 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4859 if (nwritten < 0) {
4860 reply_nterror(req, NT_STATUS_DISK_FULL);
4861 goto out;
4863 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4864 if (nwritten < 0) {
4865 reply_nterror(req, NT_STATUS_DISK_FULL);
4866 goto out;
4868 trigger_write_time_update_immediate(fsp);
4869 } else {
4870 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4873 status = sync_file(conn, fsp, False);
4874 if (!NT_STATUS_IS_OK(status)) {
4875 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4876 fsp_str_dbg(fsp), nt_errstr(status)));
4877 reply_nterror(req, status);
4878 goto out;
4881 if(nwritten < 0) {
4882 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4883 goto out;
4886 if((nwritten == 0) && (numtowrite != 0)) {
4887 reply_nterror(req, NT_STATUS_DISK_FULL);
4888 goto out;
4891 reply_outbuf(req, 1, 0);
4893 SSVAL(req->outbuf,smb_vwv0,nwritten);
4895 if (nwritten < (ssize_t)numtowrite) {
4896 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4897 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4900 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4902 out:
4903 END_PROFILE(SMBwrite);
4904 return;
4907 /****************************************************************************
4908 Ensure a buffer is a valid writeX for recvfile purposes.
4909 ****************************************************************************/
4911 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4912 (2*14) + /* word count (including bcc) */ \
4913 1 /* pad byte */)
4915 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4916 const uint8_t *inbuf)
4918 size_t numtowrite;
4919 unsigned int doff = 0;
4920 size_t len = smb_len_large(inbuf);
4921 uint16_t fnum;
4922 struct smbXsrv_open *op = NULL;
4923 struct files_struct *fsp = NULL;
4924 NTSTATUS status;
4926 if (is_encrypted_packet(inbuf)) {
4927 /* Can't do this on encrypted
4928 * connections. */
4929 return false;
4932 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4933 return false;
4936 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4937 CVAL(inbuf,smb_wct) != 14) {
4938 DEBUG(10,("is_valid_writeX_buffer: chained or "
4939 "invalid word length.\n"));
4940 return false;
4943 fnum = SVAL(inbuf, smb_vwv2);
4944 status = smb1srv_open_lookup(xconn,
4945 fnum,
4946 0, /* now */
4947 &op);
4948 if (!NT_STATUS_IS_OK(status)) {
4949 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4950 return false;
4952 fsp = op->compat;
4953 if (fsp == NULL) {
4954 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4955 return false;
4957 if (fsp->conn == NULL) {
4958 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4959 return false;
4962 if (IS_IPC(fsp->conn)) {
4963 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4964 return false;
4966 if (IS_PRINT(fsp->conn)) {
4967 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4968 return false;
4970 doff = SVAL(inbuf,smb_vwv11);
4972 numtowrite = SVAL(inbuf,smb_vwv10);
4974 if (len > doff && len - doff > 0xFFFF) {
4975 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4978 if (numtowrite == 0) {
4979 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4980 return false;
4983 /* Ensure the sizes match up. */
4984 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4985 /* no pad byte...old smbclient :-( */
4986 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4987 (unsigned int)doff,
4988 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4989 return false;
4992 if (len - doff != numtowrite) {
4993 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4994 "len = %u, doff = %u, numtowrite = %u\n",
4995 (unsigned int)len,
4996 (unsigned int)doff,
4997 (unsigned int)numtowrite ));
4998 return false;
5001 DEBUG(10,("is_valid_writeX_buffer: true "
5002 "len = %u, doff = %u, numtowrite = %u\n",
5003 (unsigned int)len,
5004 (unsigned int)doff,
5005 (unsigned int)numtowrite ));
5007 return true;
5010 /****************************************************************************
5011 Reply to a write and X.
5012 ****************************************************************************/
5014 void reply_write_and_X(struct smb_request *req)
5016 connection_struct *conn = req->conn;
5017 struct smbXsrv_connection *xconn = req->xconn;
5018 files_struct *fsp;
5019 struct lock_struct lock;
5020 off_t startpos;
5021 size_t numtowrite;
5022 bool write_through;
5023 ssize_t nwritten;
5024 unsigned int smb_doff;
5025 unsigned int smblen;
5026 const char *data;
5027 NTSTATUS status;
5028 int saved_errno = 0;
5030 START_PROFILE(SMBwriteX);
5032 if ((req->wct != 12) && (req->wct != 14)) {
5033 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5034 goto out;
5037 numtowrite = SVAL(req->vwv+10, 0);
5038 smb_doff = SVAL(req->vwv+11, 0);
5039 smblen = smb_len(req->inbuf);
5041 if (req->unread_bytes > 0xFFFF ||
5042 (smblen > smb_doff &&
5043 smblen - smb_doff > 0xFFFF)) {
5044 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5047 if (req->unread_bytes) {
5048 /* Can't do a recvfile write on IPC$ */
5049 if (IS_IPC(conn)) {
5050 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5051 goto out;
5053 if (numtowrite != req->unread_bytes) {
5054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5055 goto out;
5057 } else {
5059 * This already protects us against CVE-2017-12163.
5061 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5062 smb_doff + numtowrite > smblen) {
5063 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5064 goto out;
5068 /* If it's an IPC, pass off the pipe handler. */
5069 if (IS_IPC(conn)) {
5070 if (req->unread_bytes) {
5071 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5072 goto out;
5074 reply_pipe_write_and_X(req);
5075 goto out;
5078 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5079 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5080 write_through = BITSETW(req->vwv+7,0);
5082 if (!check_fsp(conn, req, fsp)) {
5083 goto out;
5086 if (!CHECK_WRITE(fsp)) {
5087 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5088 goto out;
5091 data = smb_base(req->inbuf) + smb_doff;
5093 if(req->wct == 14) {
5095 * This is a large offset (64 bit) write.
5097 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5101 /* X/Open SMB protocol says that, unlike SMBwrite
5102 if the length is zero then NO truncation is
5103 done, just a write of zero. To truncate a file,
5104 use SMBwrite. */
5106 if(numtowrite == 0) {
5107 nwritten = 0;
5108 } else {
5109 if (req->unread_bytes == 0) {
5110 status = schedule_aio_write_and_X(conn,
5111 req,
5112 fsp,
5113 data,
5114 startpos,
5115 numtowrite);
5117 if (NT_STATUS_IS_OK(status)) {
5118 /* write scheduled - we're done. */
5119 goto out;
5121 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5122 /* Real error - report to client. */
5123 reply_nterror(req, status);
5124 goto out;
5126 /* NT_STATUS_RETRY - fall through to sync write. */
5129 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5130 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5131 &lock);
5133 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5134 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5135 goto out;
5138 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5139 saved_errno = errno;
5142 if(nwritten < 0) {
5143 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5144 goto out;
5147 if((nwritten == 0) && (numtowrite != 0)) {
5148 reply_nterror(req, NT_STATUS_DISK_FULL);
5149 goto out;
5152 reply_outbuf(req, 6, 0);
5153 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5154 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5155 SSVAL(req->outbuf,smb_vwv2,nwritten);
5156 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5158 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5159 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5161 status = sync_file(conn, fsp, write_through);
5162 if (!NT_STATUS_IS_OK(status)) {
5163 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5164 fsp_str_dbg(fsp), nt_errstr(status)));
5165 reply_nterror(req, status);
5166 goto out;
5169 END_PROFILE(SMBwriteX);
5170 return;
5172 out:
5173 if (req->unread_bytes) {
5174 /* writeX failed. drain socket. */
5175 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5176 req->unread_bytes) {
5177 smb_panic("failed to drain pending bytes");
5179 req->unread_bytes = 0;
5182 END_PROFILE(SMBwriteX);
5183 return;
5186 /****************************************************************************
5187 Reply to a lseek.
5188 ****************************************************************************/
5190 void reply_lseek(struct smb_request *req)
5192 connection_struct *conn = req->conn;
5193 off_t startpos;
5194 off_t res= -1;
5195 int mode,umode;
5196 files_struct *fsp;
5198 START_PROFILE(SMBlseek);
5200 if (req->wct < 4) {
5201 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5202 END_PROFILE(SMBlseek);
5203 return;
5206 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5208 if (!check_fsp(conn, req, fsp)) {
5209 return;
5212 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5214 mode = SVAL(req->vwv+1, 0) & 3;
5215 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5216 startpos = (off_t)IVALS(req->vwv+2, 0);
5218 switch (mode) {
5219 case 0:
5220 umode = SEEK_SET;
5221 res = startpos;
5222 break;
5223 case 1:
5224 umode = SEEK_CUR;
5225 res = fsp->fh->pos + startpos;
5226 break;
5227 case 2:
5228 umode = SEEK_END;
5229 break;
5230 default:
5231 umode = SEEK_SET;
5232 res = startpos;
5233 break;
5236 if (umode == SEEK_END) {
5237 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5238 if(errno == EINVAL) {
5239 off_t current_pos = startpos;
5241 if(fsp_stat(fsp) == -1) {
5242 reply_nterror(req,
5243 map_nt_error_from_unix(errno));
5244 END_PROFILE(SMBlseek);
5245 return;
5248 current_pos += fsp->fsp_name->st.st_ex_size;
5249 if(current_pos < 0)
5250 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5254 if(res == -1) {
5255 reply_nterror(req, map_nt_error_from_unix(errno));
5256 END_PROFILE(SMBlseek);
5257 return;
5261 fsp->fh->pos = res;
5263 reply_outbuf(req, 2, 0);
5264 SIVAL(req->outbuf,smb_vwv0,res);
5266 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5267 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5269 END_PROFILE(SMBlseek);
5270 return;
5273 /****************************************************************************
5274 Reply to a flush.
5275 ****************************************************************************/
5277 void reply_flush(struct smb_request *req)
5279 connection_struct *conn = req->conn;
5280 uint16_t fnum;
5281 files_struct *fsp;
5283 START_PROFILE(SMBflush);
5285 if (req->wct < 1) {
5286 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5287 return;
5290 fnum = SVAL(req->vwv+0, 0);
5291 fsp = file_fsp(req, fnum);
5293 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5294 return;
5297 if (!fsp) {
5298 file_sync_all(conn);
5299 } else {
5300 NTSTATUS status = sync_file(conn, fsp, True);
5301 if (!NT_STATUS_IS_OK(status)) {
5302 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5303 fsp_str_dbg(fsp), nt_errstr(status)));
5304 reply_nterror(req, status);
5305 END_PROFILE(SMBflush);
5306 return;
5310 reply_outbuf(req, 0, 0);
5312 DEBUG(3,("flush\n"));
5313 END_PROFILE(SMBflush);
5314 return;
5317 /****************************************************************************
5318 Reply to a exit.
5319 conn POINTER CAN BE NULL HERE !
5320 ****************************************************************************/
5322 void reply_exit(struct smb_request *req)
5324 START_PROFILE(SMBexit);
5326 file_close_pid(req->sconn, req->smbpid, req->vuid);
5328 reply_outbuf(req, 0, 0);
5330 DEBUG(3,("exit\n"));
5332 END_PROFILE(SMBexit);
5333 return;
5336 struct reply_close_state {
5337 files_struct *fsp;
5338 struct smb_request *smbreq;
5341 static void do_smb1_close(struct tevent_req *req);
5343 void reply_close(struct smb_request *req)
5345 connection_struct *conn = req->conn;
5346 NTSTATUS status = NT_STATUS_OK;
5347 files_struct *fsp = NULL;
5348 START_PROFILE(SMBclose);
5350 if (req->wct < 3) {
5351 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5352 END_PROFILE(SMBclose);
5353 return;
5356 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5359 * We can only use check_fsp if we know it's not a directory.
5362 if (!check_fsp_open(conn, req, fsp)) {
5363 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5364 END_PROFILE(SMBclose);
5365 return;
5368 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5369 fsp->is_directory ? "directory" : "file",
5370 fsp->fh->fd, fsp_fnum_dbg(fsp),
5371 conn->num_files_open));
5373 if (!fsp->is_directory) {
5374 time_t t;
5377 * Take care of any time sent in the close.
5380 t = srv_make_unix_date3(req->vwv+1);
5381 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5384 if (fsp->num_aio_requests != 0) {
5386 struct reply_close_state *state;
5388 DEBUG(10, ("closing with aio %u requests pending\n",
5389 fsp->num_aio_requests));
5392 * We depend on the aio_extra destructor to take care of this
5393 * close request once fsp->num_aio_request drops to 0.
5396 fsp->deferred_close = tevent_wait_send(
5397 fsp, fsp->conn->sconn->ev_ctx);
5398 if (fsp->deferred_close == NULL) {
5399 status = NT_STATUS_NO_MEMORY;
5400 goto done;
5403 state = talloc(fsp, struct reply_close_state);
5404 if (state == NULL) {
5405 TALLOC_FREE(fsp->deferred_close);
5406 status = NT_STATUS_NO_MEMORY;
5407 goto done;
5409 state->fsp = fsp;
5410 state->smbreq = talloc_move(fsp, &req);
5411 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5412 state);
5413 END_PROFILE(SMBclose);
5414 return;
5418 * close_file() returns the unix errno if an error was detected on
5419 * close - normally this is due to a disk full error. If not then it
5420 * was probably an I/O error.
5423 status = close_file(req, fsp, NORMAL_CLOSE);
5424 done:
5425 if (!NT_STATUS_IS_OK(status)) {
5426 reply_nterror(req, status);
5427 END_PROFILE(SMBclose);
5428 return;
5431 reply_outbuf(req, 0, 0);
5432 END_PROFILE(SMBclose);
5433 return;
5436 static void do_smb1_close(struct tevent_req *req)
5438 struct reply_close_state *state = tevent_req_callback_data(
5439 req, struct reply_close_state);
5440 struct smb_request *smbreq;
5441 NTSTATUS status;
5442 int ret;
5444 ret = tevent_wait_recv(req);
5445 TALLOC_FREE(req);
5446 if (ret != 0) {
5447 DEBUG(10, ("tevent_wait_recv returned %s\n",
5448 strerror(ret)));
5450 * Continue anyway, this should never happen
5455 * fsp->smb2_close_request right now is a talloc grandchild of
5456 * fsp. When we close_file(fsp), it would go with it. No chance to
5457 * reply...
5459 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5461 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5462 if (NT_STATUS_IS_OK(status)) {
5463 reply_outbuf(smbreq, 0, 0);
5464 } else {
5465 reply_nterror(smbreq, status);
5467 if (!srv_send_smb(smbreq->xconn,
5468 (char *)smbreq->outbuf,
5469 true,
5470 smbreq->seqnum+1,
5471 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5472 NULL)) {
5473 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5474 "failed.");
5476 TALLOC_FREE(smbreq);
5479 /****************************************************************************
5480 Reply to a writeclose (Core+ protocol).
5481 ****************************************************************************/
5483 void reply_writeclose(struct smb_request *req)
5485 connection_struct *conn = req->conn;
5486 size_t numtowrite;
5487 size_t remaining;
5488 ssize_t nwritten = -1;
5489 NTSTATUS close_status = NT_STATUS_OK;
5490 off_t startpos;
5491 const char *data;
5492 struct timespec mtime;
5493 files_struct *fsp;
5494 struct lock_struct lock;
5496 START_PROFILE(SMBwriteclose);
5498 if (req->wct < 6) {
5499 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5500 END_PROFILE(SMBwriteclose);
5501 return;
5504 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5506 if (!check_fsp(conn, req, fsp)) {
5507 END_PROFILE(SMBwriteclose);
5508 return;
5510 if (!CHECK_WRITE(fsp)) {
5511 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5512 END_PROFILE(SMBwriteclose);
5513 return;
5516 numtowrite = SVAL(req->vwv+1, 0);
5517 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5518 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5519 data = (const char *)req->buf + 1;
5522 * Ensure client isn't asking us to write more than
5523 * they sent. CVE-2017-12163.
5525 remaining = smbreq_bufrem(req, data);
5526 if (numtowrite > remaining) {
5527 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5528 END_PROFILE(SMBwriteclose);
5529 return;
5532 if (fsp->print_file == NULL) {
5533 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5534 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5535 &lock);
5537 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5538 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5539 END_PROFILE(SMBwriteclose);
5540 return;
5544 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5546 set_close_write_time(fsp, mtime);
5549 * More insanity. W2K only closes the file if writelen > 0.
5550 * JRA.
5553 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5554 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5555 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5557 if (numtowrite) {
5558 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5559 "file %s\n", fsp_str_dbg(fsp)));
5560 close_status = close_file(req, fsp, NORMAL_CLOSE);
5561 fsp = NULL;
5564 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5565 reply_nterror(req, NT_STATUS_DISK_FULL);
5566 goto out;
5569 if(!NT_STATUS_IS_OK(close_status)) {
5570 reply_nterror(req, close_status);
5571 goto out;
5574 reply_outbuf(req, 1, 0);
5576 SSVAL(req->outbuf,smb_vwv0,nwritten);
5578 out:
5580 END_PROFILE(SMBwriteclose);
5581 return;
5584 #undef DBGC_CLASS
5585 #define DBGC_CLASS DBGC_LOCKING
5587 /****************************************************************************
5588 Reply to a lock.
5589 ****************************************************************************/
5591 void reply_lock(struct smb_request *req)
5593 connection_struct *conn = req->conn;
5594 uint64_t count,offset;
5595 NTSTATUS status;
5596 files_struct *fsp;
5597 struct byte_range_lock *br_lck = NULL;
5599 START_PROFILE(SMBlock);
5601 if (req->wct < 5) {
5602 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5603 END_PROFILE(SMBlock);
5604 return;
5607 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5609 if (!check_fsp(conn, req, fsp)) {
5610 END_PROFILE(SMBlock);
5611 return;
5614 count = (uint64_t)IVAL(req->vwv+1, 0);
5615 offset = (uint64_t)IVAL(req->vwv+3, 0);
5617 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5618 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5620 br_lck = do_lock(req->sconn->msg_ctx,
5621 fsp,
5622 (uint64_t)req->smbpid,
5623 count,
5624 offset,
5625 WRITE_LOCK,
5626 WINDOWS_LOCK,
5627 False, /* Non-blocking lock. */
5628 &status,
5629 NULL);
5631 TALLOC_FREE(br_lck);
5633 if (NT_STATUS_V(status)) {
5634 reply_nterror(req, status);
5635 END_PROFILE(SMBlock);
5636 return;
5639 reply_outbuf(req, 0, 0);
5641 END_PROFILE(SMBlock);
5642 return;
5645 /****************************************************************************
5646 Reply to a unlock.
5647 ****************************************************************************/
5649 void reply_unlock(struct smb_request *req)
5651 connection_struct *conn = req->conn;
5652 uint64_t count,offset;
5653 NTSTATUS status;
5654 files_struct *fsp;
5656 START_PROFILE(SMBunlock);
5658 if (req->wct < 5) {
5659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5660 END_PROFILE(SMBunlock);
5661 return;
5664 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5666 if (!check_fsp(conn, req, fsp)) {
5667 END_PROFILE(SMBunlock);
5668 return;
5671 count = (uint64_t)IVAL(req->vwv+1, 0);
5672 offset = (uint64_t)IVAL(req->vwv+3, 0);
5674 status = do_unlock(req->sconn->msg_ctx,
5675 fsp,
5676 (uint64_t)req->smbpid,
5677 count,
5678 offset,
5679 WINDOWS_LOCK);
5681 if (NT_STATUS_V(status)) {
5682 reply_nterror(req, status);
5683 END_PROFILE(SMBunlock);
5684 return;
5687 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5688 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5690 reply_outbuf(req, 0, 0);
5692 END_PROFILE(SMBunlock);
5693 return;
5696 #undef DBGC_CLASS
5697 #define DBGC_CLASS DBGC_ALL
5699 /****************************************************************************
5700 Reply to a tdis.
5701 conn POINTER CAN BE NULL HERE !
5702 ****************************************************************************/
5704 void reply_tdis(struct smb_request *req)
5706 NTSTATUS status;
5707 connection_struct *conn = req->conn;
5708 struct smbXsrv_tcon *tcon;
5710 START_PROFILE(SMBtdis);
5712 if (!conn) {
5713 DEBUG(4,("Invalid connection in tdis\n"));
5714 reply_force_doserror(req, ERRSRV, ERRinvnid);
5715 END_PROFILE(SMBtdis);
5716 return;
5719 tcon = conn->tcon;
5720 req->conn = NULL;
5723 * TODO: cancel all outstanding requests on the tcon
5725 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5726 if (!NT_STATUS_IS_OK(status)) {
5727 DEBUG(0, ("reply_tdis: "
5728 "smbXsrv_tcon_disconnect() failed: %s\n",
5729 nt_errstr(status)));
5731 * If we hit this case, there is something completely
5732 * wrong, so we better disconnect the transport connection.
5734 END_PROFILE(SMBtdis);
5735 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5736 return;
5739 TALLOC_FREE(tcon);
5741 reply_outbuf(req, 0, 0);
5742 END_PROFILE(SMBtdis);
5743 return;
5746 /****************************************************************************
5747 Reply to a echo.
5748 conn POINTER CAN BE NULL HERE !
5749 ****************************************************************************/
5751 void reply_echo(struct smb_request *req)
5753 connection_struct *conn = req->conn;
5754 struct smb_perfcount_data local_pcd;
5755 struct smb_perfcount_data *cur_pcd;
5756 int smb_reverb;
5757 int seq_num;
5759 START_PROFILE(SMBecho);
5761 smb_init_perfcount_data(&local_pcd);
5763 if (req->wct < 1) {
5764 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5765 END_PROFILE(SMBecho);
5766 return;
5769 smb_reverb = SVAL(req->vwv+0, 0);
5771 reply_outbuf(req, 1, req->buflen);
5773 /* copy any incoming data back out */
5774 if (req->buflen > 0) {
5775 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5778 if (smb_reverb > 100) {
5779 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5780 smb_reverb = 100;
5783 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5785 /* this makes sure we catch the request pcd */
5786 if (seq_num == smb_reverb) {
5787 cur_pcd = &req->pcd;
5788 } else {
5789 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5790 cur_pcd = &local_pcd;
5793 SSVAL(req->outbuf,smb_vwv0,seq_num);
5795 show_msg((char *)req->outbuf);
5796 if (!srv_send_smb(req->xconn,
5797 (char *)req->outbuf,
5798 true, req->seqnum+1,
5799 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5800 cur_pcd))
5801 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5804 DEBUG(3,("echo %d times\n", smb_reverb));
5806 TALLOC_FREE(req->outbuf);
5808 END_PROFILE(SMBecho);
5809 return;
5812 /****************************************************************************
5813 Reply to a printopen.
5814 ****************************************************************************/
5816 void reply_printopen(struct smb_request *req)
5818 connection_struct *conn = req->conn;
5819 files_struct *fsp;
5820 NTSTATUS status;
5822 START_PROFILE(SMBsplopen);
5824 if (req->wct < 2) {
5825 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5826 END_PROFILE(SMBsplopen);
5827 return;
5830 if (!CAN_PRINT(conn)) {
5831 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5832 END_PROFILE(SMBsplopen);
5833 return;
5836 status = file_new(req, conn, &fsp);
5837 if(!NT_STATUS_IS_OK(status)) {
5838 reply_nterror(req, status);
5839 END_PROFILE(SMBsplopen);
5840 return;
5843 /* Open for exclusive use, write only. */
5844 status = print_spool_open(fsp, NULL, req->vuid);
5846 if (!NT_STATUS_IS_OK(status)) {
5847 file_free(req, fsp);
5848 reply_nterror(req, status);
5849 END_PROFILE(SMBsplopen);
5850 return;
5853 reply_outbuf(req, 1, 0);
5854 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5856 DEBUG(3,("openprint fd=%d %s\n",
5857 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5859 END_PROFILE(SMBsplopen);
5860 return;
5863 /****************************************************************************
5864 Reply to a printclose.
5865 ****************************************************************************/
5867 void reply_printclose(struct smb_request *req)
5869 connection_struct *conn = req->conn;
5870 files_struct *fsp;
5871 NTSTATUS status;
5873 START_PROFILE(SMBsplclose);
5875 if (req->wct < 1) {
5876 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5877 END_PROFILE(SMBsplclose);
5878 return;
5881 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5883 if (!check_fsp(conn, req, fsp)) {
5884 END_PROFILE(SMBsplclose);
5885 return;
5888 if (!CAN_PRINT(conn)) {
5889 reply_force_doserror(req, ERRSRV, ERRerror);
5890 END_PROFILE(SMBsplclose);
5891 return;
5894 DEBUG(3,("printclose fd=%d %s\n",
5895 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5897 status = close_file(req, fsp, NORMAL_CLOSE);
5899 if(!NT_STATUS_IS_OK(status)) {
5900 reply_nterror(req, status);
5901 END_PROFILE(SMBsplclose);
5902 return;
5905 reply_outbuf(req, 0, 0);
5907 END_PROFILE(SMBsplclose);
5908 return;
5911 /****************************************************************************
5912 Reply to a printqueue.
5913 ****************************************************************************/
5915 void reply_printqueue(struct smb_request *req)
5917 connection_struct *conn = req->conn;
5918 int max_count;
5919 int start_index;
5921 START_PROFILE(SMBsplretq);
5923 if (req->wct < 2) {
5924 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5925 END_PROFILE(SMBsplretq);
5926 return;
5929 max_count = SVAL(req->vwv+0, 0);
5930 start_index = SVAL(req->vwv+1, 0);
5932 /* we used to allow the client to get the cnum wrong, but that
5933 is really quite gross and only worked when there was only
5934 one printer - I think we should now only accept it if they
5935 get it right (tridge) */
5936 if (!CAN_PRINT(conn)) {
5937 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5938 END_PROFILE(SMBsplretq);
5939 return;
5942 reply_outbuf(req, 2, 3);
5943 SSVAL(req->outbuf,smb_vwv0,0);
5944 SSVAL(req->outbuf,smb_vwv1,0);
5945 SCVAL(smb_buf(req->outbuf),0,1);
5946 SSVAL(smb_buf(req->outbuf),1,0);
5948 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5949 start_index, max_count));
5952 TALLOC_CTX *mem_ctx = talloc_tos();
5953 NTSTATUS status;
5954 WERROR werr;
5955 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5956 struct rpc_pipe_client *cli = NULL;
5957 struct dcerpc_binding_handle *b = NULL;
5958 struct policy_handle handle;
5959 struct spoolss_DevmodeContainer devmode_ctr;
5960 union spoolss_JobInfo *info;
5961 uint32_t count;
5962 uint32_t num_to_get;
5963 uint32_t first;
5964 uint32_t i;
5966 ZERO_STRUCT(handle);
5968 status = rpc_pipe_open_interface(mem_ctx,
5969 &ndr_table_spoolss,
5970 conn->session_info,
5971 conn->sconn->remote_address,
5972 conn->sconn->local_address,
5973 conn->sconn->msg_ctx,
5974 &cli);
5975 if (!NT_STATUS_IS_OK(status)) {
5976 DEBUG(0, ("reply_printqueue: "
5977 "could not connect to spoolss: %s\n",
5978 nt_errstr(status)));
5979 reply_nterror(req, status);
5980 goto out;
5982 b = cli->binding_handle;
5984 ZERO_STRUCT(devmode_ctr);
5986 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5987 sharename,
5988 NULL, devmode_ctr,
5989 SEC_FLAG_MAXIMUM_ALLOWED,
5990 &handle,
5991 &werr);
5992 if (!NT_STATUS_IS_OK(status)) {
5993 reply_nterror(req, status);
5994 goto out;
5996 if (!W_ERROR_IS_OK(werr)) {
5997 reply_nterror(req, werror_to_ntstatus(werr));
5998 goto out;
6001 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6002 &handle,
6003 0, /* firstjob */
6004 0xff, /* numjobs */
6005 2, /* level */
6006 0, /* offered */
6007 &count,
6008 &info);
6009 if (!W_ERROR_IS_OK(werr)) {
6010 reply_nterror(req, werror_to_ntstatus(werr));
6011 goto out;
6014 if (max_count > 0) {
6015 first = start_index;
6016 } else {
6017 first = start_index + max_count + 1;
6020 if (first >= count) {
6021 num_to_get = first;
6022 } else {
6023 num_to_get = first + MIN(ABS(max_count), count - first);
6026 for (i = first; i < num_to_get; i++) {
6027 char blob[28];
6028 char *p = blob;
6029 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6030 int qstatus;
6031 size_t len = 0;
6032 uint16_t qrapjobid = pjobid_to_rap(sharename,
6033 info[i].info2.job_id);
6035 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6036 qstatus = 2;
6037 } else {
6038 qstatus = 3;
6041 srv_put_dos_date2(p, 0, qtime);
6042 SCVAL(p, 4, qstatus);
6043 SSVAL(p, 5, qrapjobid);
6044 SIVAL(p, 7, info[i].info2.size);
6045 SCVAL(p, 11, 0);
6046 status = srvstr_push(blob, req->flags2, p+12,
6047 info[i].info2.notify_name, 16, STR_ASCII, &len);
6048 if (!NT_STATUS_IS_OK(status)) {
6049 reply_nterror(req, status);
6050 goto out;
6052 if (message_push_blob(
6053 &req->outbuf,
6054 data_blob_const(
6055 blob, sizeof(blob))) == -1) {
6056 reply_nterror(req, NT_STATUS_NO_MEMORY);
6057 goto out;
6061 if (count > 0) {
6062 SSVAL(req->outbuf,smb_vwv0,count);
6063 SSVAL(req->outbuf,smb_vwv1,
6064 (max_count>0?first+count:first-1));
6065 SCVAL(smb_buf(req->outbuf),0,1);
6066 SSVAL(smb_buf(req->outbuf),1,28*count);
6070 DEBUG(3, ("%u entries returned in queue\n",
6071 (unsigned)count));
6073 out:
6074 if (b && is_valid_policy_hnd(&handle)) {
6075 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6080 END_PROFILE(SMBsplretq);
6081 return;
6084 /****************************************************************************
6085 Reply to a printwrite.
6086 ****************************************************************************/
6088 void reply_printwrite(struct smb_request *req)
6090 connection_struct *conn = req->conn;
6091 int numtowrite;
6092 const char *data;
6093 files_struct *fsp;
6095 START_PROFILE(SMBsplwr);
6097 if (req->wct < 1) {
6098 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6099 END_PROFILE(SMBsplwr);
6100 return;
6103 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6105 if (!check_fsp(conn, req, fsp)) {
6106 END_PROFILE(SMBsplwr);
6107 return;
6110 if (!fsp->print_file) {
6111 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6112 END_PROFILE(SMBsplwr);
6113 return;
6116 if (!CHECK_WRITE(fsp)) {
6117 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6118 END_PROFILE(SMBsplwr);
6119 return;
6122 numtowrite = SVAL(req->buf, 1);
6125 * This already protects us against CVE-2017-12163.
6127 if (req->buflen < numtowrite + 3) {
6128 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6129 END_PROFILE(SMBsplwr);
6130 return;
6133 data = (const char *)req->buf + 3;
6135 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6136 reply_nterror(req, map_nt_error_from_unix(errno));
6137 END_PROFILE(SMBsplwr);
6138 return;
6141 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6143 END_PROFILE(SMBsplwr);
6144 return;
6147 /****************************************************************************
6148 Reply to a mkdir.
6149 ****************************************************************************/
6151 void reply_mkdir(struct smb_request *req)
6153 connection_struct *conn = req->conn;
6154 struct smb_filename *smb_dname = NULL;
6155 char *directory = NULL;
6156 NTSTATUS status;
6157 uint32_t ucf_flags;
6158 TALLOC_CTX *ctx = talloc_tos();
6160 START_PROFILE(SMBmkdir);
6162 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6163 STR_TERMINATE, &status);
6164 if (!NT_STATUS_IS_OK(status)) {
6165 reply_nterror(req, status);
6166 goto out;
6169 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6170 status = filename_convert(ctx, conn,
6171 directory,
6172 ucf_flags,
6173 NULL,
6174 &smb_dname);
6175 if (!NT_STATUS_IS_OK(status)) {
6176 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6177 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6178 ERRSRV, ERRbadpath);
6179 goto out;
6181 reply_nterror(req, status);
6182 goto out;
6185 status = create_directory(conn, req, smb_dname);
6187 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6189 if (!NT_STATUS_IS_OK(status)) {
6191 if (!use_nt_status()
6192 && NT_STATUS_EQUAL(status,
6193 NT_STATUS_OBJECT_NAME_COLLISION)) {
6195 * Yes, in the DOS error code case we get a
6196 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6197 * samba4 torture test.
6199 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6202 reply_nterror(req, status);
6203 goto out;
6206 reply_outbuf(req, 0, 0);
6208 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6209 out:
6210 TALLOC_FREE(smb_dname);
6211 END_PROFILE(SMBmkdir);
6212 return;
6215 /****************************************************************************
6216 Reply to a rmdir.
6217 ****************************************************************************/
6219 void reply_rmdir(struct smb_request *req)
6221 connection_struct *conn = req->conn;
6222 struct smb_filename *smb_dname = NULL;
6223 char *directory = NULL;
6224 NTSTATUS status;
6225 TALLOC_CTX *ctx = talloc_tos();
6226 files_struct *fsp = NULL;
6227 int info = 0;
6228 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6229 struct smbd_server_connection *sconn = req->sconn;
6231 START_PROFILE(SMBrmdir);
6233 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6234 STR_TERMINATE, &status);
6235 if (!NT_STATUS_IS_OK(status)) {
6236 reply_nterror(req, status);
6237 goto out;
6240 status = filename_convert(ctx, conn,
6241 directory,
6242 ucf_flags,
6243 NULL,
6244 &smb_dname);
6245 if (!NT_STATUS_IS_OK(status)) {
6246 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6247 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6248 ERRSRV, ERRbadpath);
6249 goto out;
6251 reply_nterror(req, status);
6252 goto out;
6255 if (is_ntfs_stream_smb_fname(smb_dname)) {
6256 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6257 goto out;
6260 status = SMB_VFS_CREATE_FILE(
6261 conn, /* conn */
6262 req, /* req */
6263 0, /* root_dir_fid */
6264 smb_dname, /* fname */
6265 DELETE_ACCESS, /* access_mask */
6266 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6267 FILE_SHARE_DELETE),
6268 FILE_OPEN, /* create_disposition*/
6269 FILE_DIRECTORY_FILE, /* create_options */
6270 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6271 0, /* oplock_request */
6272 NULL, /* lease */
6273 0, /* allocation_size */
6274 0, /* private_flags */
6275 NULL, /* sd */
6276 NULL, /* ea_list */
6277 &fsp, /* result */
6278 &info, /* pinfo */
6279 NULL, NULL); /* create context */
6281 if (!NT_STATUS_IS_OK(status)) {
6282 if (open_was_deferred(req->xconn, req->mid)) {
6283 /* We have re-scheduled this call. */
6284 goto out;
6286 reply_nterror(req, status);
6287 goto out;
6290 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6291 if (!NT_STATUS_IS_OK(status)) {
6292 close_file(req, fsp, ERROR_CLOSE);
6293 reply_nterror(req, status);
6294 goto out;
6297 if (!set_delete_on_close(fsp, true,
6298 conn->session_info->security_token,
6299 conn->session_info->unix_token)) {
6300 close_file(req, fsp, ERROR_CLOSE);
6301 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6302 goto out;
6305 status = close_file(req, fsp, NORMAL_CLOSE);
6306 if (!NT_STATUS_IS_OK(status)) {
6307 reply_nterror(req, status);
6308 } else {
6309 reply_outbuf(req, 0, 0);
6312 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6314 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6315 out:
6316 TALLOC_FREE(smb_dname);
6317 END_PROFILE(SMBrmdir);
6318 return;
6321 /*******************************************************************
6322 Resolve wildcards in a filename rename.
6323 ********************************************************************/
6325 static bool resolve_wildcards(TALLOC_CTX *ctx,
6326 const char *name1,
6327 const char *name2,
6328 char **pp_newname)
6330 char *name2_copy = NULL;
6331 char *root1 = NULL;
6332 char *root2 = NULL;
6333 char *ext1 = NULL;
6334 char *ext2 = NULL;
6335 char *p,*p2, *pname1, *pname2;
6337 name2_copy = talloc_strdup(ctx, name2);
6338 if (!name2_copy) {
6339 return False;
6342 pname1 = strrchr_m(name1,'/');
6343 pname2 = strrchr_m(name2_copy,'/');
6345 if (!pname1 || !pname2) {
6346 return False;
6349 /* Truncate the copy of name2 at the last '/' */
6350 *pname2 = '\0';
6352 /* Now go past the '/' */
6353 pname1++;
6354 pname2++;
6356 root1 = talloc_strdup(ctx, pname1);
6357 root2 = talloc_strdup(ctx, pname2);
6359 if (!root1 || !root2) {
6360 return False;
6363 p = strrchr_m(root1,'.');
6364 if (p) {
6365 *p = 0;
6366 ext1 = talloc_strdup(ctx, p+1);
6367 } else {
6368 ext1 = talloc_strdup(ctx, "");
6370 p = strrchr_m(root2,'.');
6371 if (p) {
6372 *p = 0;
6373 ext2 = talloc_strdup(ctx, p+1);
6374 } else {
6375 ext2 = talloc_strdup(ctx, "");
6378 if (!ext1 || !ext2) {
6379 return False;
6382 p = root1;
6383 p2 = root2;
6384 while (*p2) {
6385 if (*p2 == '?') {
6386 /* Hmmm. Should this be mb-aware ? */
6387 *p2 = *p;
6388 p2++;
6389 } else if (*p2 == '*') {
6390 *p2 = '\0';
6391 root2 = talloc_asprintf(ctx, "%s%s",
6392 root2,
6394 if (!root2) {
6395 return False;
6397 break;
6398 } else {
6399 p2++;
6401 if (*p) {
6402 p++;
6406 p = ext1;
6407 p2 = ext2;
6408 while (*p2) {
6409 if (*p2 == '?') {
6410 /* Hmmm. Should this be mb-aware ? */
6411 *p2 = *p;
6412 p2++;
6413 } else if (*p2 == '*') {
6414 *p2 = '\0';
6415 ext2 = talloc_asprintf(ctx, "%s%s",
6416 ext2,
6418 if (!ext2) {
6419 return False;
6421 break;
6422 } else {
6423 p2++;
6425 if (*p) {
6426 p++;
6430 if (*ext2) {
6431 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6432 name2_copy,
6433 root2,
6434 ext2);
6435 } else {
6436 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6437 name2_copy,
6438 root2);
6441 if (!*pp_newname) {
6442 return False;
6445 return True;
6448 /****************************************************************************
6449 Ensure open files have their names updated. Updated to notify other smbd's
6450 asynchronously.
6451 ****************************************************************************/
6453 static void rename_open_files(connection_struct *conn,
6454 struct share_mode_lock *lck,
6455 struct file_id id,
6456 uint32_t orig_name_hash,
6457 const struct smb_filename *smb_fname_dst)
6459 files_struct *fsp;
6460 bool did_rename = False;
6461 NTSTATUS status;
6462 uint32_t new_name_hash = 0;
6464 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6465 fsp = file_find_di_next(fsp)) {
6466 /* fsp_name is a relative path under the fsp. To change this for other
6467 sharepaths we need to manipulate relative paths. */
6468 /* TODO - create the absolute path and manipulate the newname
6469 relative to the sharepath. */
6470 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6471 continue;
6473 if (fsp->name_hash != orig_name_hash) {
6474 continue;
6476 DEBUG(10, ("rename_open_files: renaming file %s "
6477 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6478 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6479 smb_fname_str_dbg(smb_fname_dst)));
6481 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6482 if (NT_STATUS_IS_OK(status)) {
6483 did_rename = True;
6484 new_name_hash = fsp->name_hash;
6488 if (!did_rename) {
6489 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6490 "for %s\n", file_id_string_tos(&id),
6491 smb_fname_str_dbg(smb_fname_dst)));
6494 /* Send messages to all smbd's (not ourself) that the name has changed. */
6495 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6496 orig_name_hash, new_name_hash,
6497 smb_fname_dst);
6501 /****************************************************************************
6502 We need to check if the source path is a parent directory of the destination
6503 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6504 refuse the rename with a sharing violation. Under UNIX the above call can
6505 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6506 probably need to check that the client is a Windows one before disallowing
6507 this as a UNIX client (one with UNIX extensions) can know the source is a
6508 symlink and make this decision intelligently. Found by an excellent bug
6509 report from <AndyLiebman@aol.com>.
6510 ****************************************************************************/
6512 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6513 const struct smb_filename *smb_fname_dst)
6515 const char *psrc = smb_fname_src->base_name;
6516 const char *pdst = smb_fname_dst->base_name;
6517 size_t slen;
6519 if (psrc[0] == '.' && psrc[1] == '/') {
6520 psrc += 2;
6522 if (pdst[0] == '.' && pdst[1] == '/') {
6523 pdst += 2;
6525 if ((slen = strlen(psrc)) > strlen(pdst)) {
6526 return False;
6528 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6532 * Do the notify calls from a rename
6535 static void notify_rename(connection_struct *conn, bool is_dir,
6536 const struct smb_filename *smb_fname_src,
6537 const struct smb_filename *smb_fname_dst)
6539 char *parent_dir_src = NULL;
6540 char *parent_dir_dst = NULL;
6541 uint32_t mask;
6543 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6544 : FILE_NOTIFY_CHANGE_FILE_NAME;
6546 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6547 &parent_dir_src, NULL) ||
6548 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6549 &parent_dir_dst, NULL)) {
6550 goto out;
6553 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6554 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6555 smb_fname_src->base_name);
6556 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6557 smb_fname_dst->base_name);
6559 else {
6560 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6561 smb_fname_src->base_name);
6562 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6563 smb_fname_dst->base_name);
6566 /* this is a strange one. w2k3 gives an additional event for
6567 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6568 files, but not directories */
6569 if (!is_dir) {
6570 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6571 FILE_NOTIFY_CHANGE_ATTRIBUTES
6572 |FILE_NOTIFY_CHANGE_CREATION,
6573 smb_fname_dst->base_name);
6575 out:
6576 TALLOC_FREE(parent_dir_src);
6577 TALLOC_FREE(parent_dir_dst);
6580 /****************************************************************************
6581 Returns an error if the parent directory for a filename is open in an
6582 incompatible way.
6583 ****************************************************************************/
6585 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6586 const struct smb_filename *smb_fname_dst_in)
6588 char *parent_dir = NULL;
6589 struct smb_filename smb_fname_parent;
6590 struct file_id id;
6591 files_struct *fsp = NULL;
6592 int ret;
6594 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6595 &parent_dir, NULL)) {
6596 return NT_STATUS_NO_MEMORY;
6598 ZERO_STRUCT(smb_fname_parent);
6599 smb_fname_parent.base_name = parent_dir;
6601 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6602 if (ret == -1) {
6603 return map_nt_error_from_unix(errno);
6607 * We're only checking on this smbd here, mostly good
6608 * enough.. and will pass tests.
6611 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6612 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6613 fsp = file_find_di_next(fsp)) {
6614 if (fsp->access_mask & DELETE_ACCESS) {
6615 return NT_STATUS_SHARING_VIOLATION;
6618 return NT_STATUS_OK;
6621 /****************************************************************************
6622 Rename an open file - given an fsp.
6623 ****************************************************************************/
6625 NTSTATUS rename_internals_fsp(connection_struct *conn,
6626 files_struct *fsp,
6627 const struct smb_filename *smb_fname_dst_in,
6628 uint32_t attrs,
6629 bool replace_if_exists)
6631 TALLOC_CTX *ctx = talloc_tos();
6632 struct smb_filename *smb_fname_dst = NULL;
6633 NTSTATUS status = NT_STATUS_OK;
6634 struct share_mode_lock *lck = NULL;
6635 uint32_t access_mask = SEC_DIR_ADD_FILE;
6636 bool dst_exists, old_is_stream, new_is_stream;
6638 status = check_name(conn, smb_fname_dst_in);
6639 if (!NT_STATUS_IS_OK(status)) {
6640 return status;
6643 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6644 if (!NT_STATUS_IS_OK(status)) {
6645 return status;
6648 if (file_has_open_streams(fsp)) {
6649 return NT_STATUS_ACCESS_DENIED;
6652 /* Make a copy of the dst smb_fname structs */
6654 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6655 if (smb_fname_dst == NULL) {
6656 status = NT_STATUS_NO_MEMORY;
6657 goto out;
6661 * Check for special case with case preserving and not
6662 * case sensitive. If the new last component differs from the original
6663 * last component only by case, then we should allow
6664 * the rename (user is trying to change the case of the
6665 * filename).
6667 if (!conn->case_sensitive && conn->case_preserve &&
6668 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6669 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6670 char *fname_dst_parent = NULL;
6671 const char *fname_dst_lcomp = NULL;
6672 char *orig_lcomp_path = NULL;
6673 char *orig_lcomp_stream = NULL;
6674 bool ok = true;
6677 * Split off the last component of the processed
6678 * destination name. We will compare this to
6679 * the split components of smb_fname_dst->original_lcomp.
6681 if (!parent_dirname(ctx,
6682 smb_fname_dst->base_name,
6683 &fname_dst_parent,
6684 &fname_dst_lcomp)) {
6685 status = NT_STATUS_NO_MEMORY;
6686 goto out;
6690 * The original_lcomp component contains
6691 * the last_component of the path + stream
6692 * name (if a stream exists).
6694 * Split off the stream name so we
6695 * can check them separately.
6698 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6699 /* POSIX - no stream component. */
6700 orig_lcomp_path = talloc_strdup(ctx,
6701 smb_fname_dst->original_lcomp);
6702 if (orig_lcomp_path == NULL) {
6703 ok = false;
6705 } else {
6706 ok = split_stream_filename(ctx,
6707 smb_fname_dst->original_lcomp,
6708 &orig_lcomp_path,
6709 &orig_lcomp_stream);
6712 if (!ok) {
6713 TALLOC_FREE(fname_dst_parent);
6714 status = NT_STATUS_NO_MEMORY;
6715 goto out;
6718 /* If the base names only differ by case, use original. */
6719 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6720 char *tmp;
6722 * Replace the modified last component with the
6723 * original.
6725 if (!ISDOT(fname_dst_parent)) {
6726 tmp = talloc_asprintf(smb_fname_dst,
6727 "%s/%s",
6728 fname_dst_parent,
6729 orig_lcomp_path);
6730 } else {
6731 tmp = talloc_strdup(smb_fname_dst,
6732 orig_lcomp_path);
6734 if (tmp == NULL) {
6735 status = NT_STATUS_NO_MEMORY;
6736 TALLOC_FREE(fname_dst_parent);
6737 TALLOC_FREE(orig_lcomp_path);
6738 TALLOC_FREE(orig_lcomp_stream);
6739 goto out;
6741 TALLOC_FREE(smb_fname_dst->base_name);
6742 smb_fname_dst->base_name = tmp;
6745 /* If the stream_names only differ by case, use original. */
6746 if(!strcsequal(smb_fname_dst->stream_name,
6747 orig_lcomp_stream)) {
6748 /* Use the original stream. */
6749 char *tmp = talloc_strdup(smb_fname_dst,
6750 orig_lcomp_stream);
6751 if (tmp == NULL) {
6752 status = NT_STATUS_NO_MEMORY;
6753 TALLOC_FREE(fname_dst_parent);
6754 TALLOC_FREE(orig_lcomp_path);
6755 TALLOC_FREE(orig_lcomp_stream);
6756 goto out;
6758 TALLOC_FREE(smb_fname_dst->stream_name);
6759 smb_fname_dst->stream_name = tmp;
6761 TALLOC_FREE(fname_dst_parent);
6762 TALLOC_FREE(orig_lcomp_path);
6763 TALLOC_FREE(orig_lcomp_stream);
6767 * If the src and dest names are identical - including case,
6768 * don't do the rename, just return success.
6771 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6772 strcsequal(fsp->fsp_name->stream_name,
6773 smb_fname_dst->stream_name)) {
6774 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6775 "- returning success\n",
6776 smb_fname_str_dbg(smb_fname_dst)));
6777 status = NT_STATUS_OK;
6778 goto out;
6781 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6782 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6784 /* Return the correct error code if both names aren't streams. */
6785 if (!old_is_stream && new_is_stream) {
6786 status = NT_STATUS_OBJECT_NAME_INVALID;
6787 goto out;
6790 if (old_is_stream && !new_is_stream) {
6791 status = NT_STATUS_INVALID_PARAMETER;
6792 goto out;
6795 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6797 if(!replace_if_exists && dst_exists) {
6798 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6799 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6800 smb_fname_str_dbg(smb_fname_dst)));
6801 status = NT_STATUS_OBJECT_NAME_COLLISION;
6802 goto out;
6805 if (dst_exists) {
6806 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6807 &smb_fname_dst->st);
6808 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6809 fileid);
6810 /* The file can be open when renaming a stream */
6811 if (dst_fsp && !new_is_stream) {
6812 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6813 status = NT_STATUS_ACCESS_DENIED;
6814 goto out;
6818 /* Ensure we have a valid stat struct for the source. */
6819 status = vfs_stat_fsp(fsp);
6820 if (!NT_STATUS_IS_OK(status)) {
6821 goto out;
6824 status = can_rename(conn, fsp, attrs);
6826 if (!NT_STATUS_IS_OK(status)) {
6827 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6828 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6829 smb_fname_str_dbg(smb_fname_dst)));
6830 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6831 status = NT_STATUS_ACCESS_DENIED;
6832 goto out;
6835 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6836 status = NT_STATUS_ACCESS_DENIED;
6837 goto out;
6840 /* Do we have rights to move into the destination ? */
6841 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
6842 /* We're moving a directory. */
6843 access_mask = SEC_DIR_ADD_SUBDIR;
6845 status = check_parent_access(conn,
6846 smb_fname_dst,
6847 access_mask);
6848 if (!NT_STATUS_IS_OK(status)) {
6849 DBG_INFO("check_parent_access on "
6850 "dst %s returned %s\n",
6851 smb_fname_str_dbg(smb_fname_dst),
6852 nt_errstr(status));
6853 goto out;
6856 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6859 * We have the file open ourselves, so not being able to get the
6860 * corresponding share mode lock is a fatal error.
6863 SMB_ASSERT(lck != NULL);
6865 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6866 uint32_t create_options = fsp->fh->private_options;
6868 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6869 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6870 smb_fname_str_dbg(smb_fname_dst)));
6872 if (!fsp->is_directory &&
6873 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6874 (lp_map_archive(SNUM(conn)) ||
6875 lp_store_dos_attributes(SNUM(conn)))) {
6876 /* We must set the archive bit on the newly
6877 renamed file. */
6878 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6879 uint32_t old_dosmode = dos_mode(conn,
6880 smb_fname_dst);
6881 file_set_dosmode(conn,
6882 smb_fname_dst,
6883 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6884 NULL,
6885 true);
6889 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6890 smb_fname_dst);
6892 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6893 smb_fname_dst);
6896 * A rename acts as a new file create w.r.t. allowing an initial delete
6897 * on close, probably because in Windows there is a new handle to the
6898 * new file. If initial delete on close was requested but not
6899 * originally set, we need to set it here. This is probably not 100% correct,
6900 * but will work for the CIFSFS client which in non-posix mode
6901 * depends on these semantics. JRA.
6904 if (create_options & FILE_DELETE_ON_CLOSE) {
6905 status = can_set_delete_on_close(fsp, 0);
6907 if (NT_STATUS_IS_OK(status)) {
6908 /* Note that here we set the *inital* delete on close flag,
6909 * not the regular one. The magic gets handled in close. */
6910 fsp->initial_delete_on_close = True;
6913 TALLOC_FREE(lck);
6914 status = NT_STATUS_OK;
6915 goto out;
6918 TALLOC_FREE(lck);
6920 if (errno == ENOTDIR || errno == EISDIR) {
6921 status = NT_STATUS_OBJECT_NAME_COLLISION;
6922 } else {
6923 status = map_nt_error_from_unix(errno);
6926 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6927 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6928 smb_fname_str_dbg(smb_fname_dst)));
6930 out:
6931 TALLOC_FREE(smb_fname_dst);
6933 return status;
6936 /****************************************************************************
6937 The guts of the rename command, split out so it may be called by the NT SMB
6938 code.
6939 ****************************************************************************/
6941 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6942 connection_struct *conn,
6943 struct smb_request *req,
6944 struct smb_filename *smb_fname_src,
6945 struct smb_filename *smb_fname_dst,
6946 uint32_t attrs,
6947 bool replace_if_exists,
6948 bool src_has_wild,
6949 bool dest_has_wild,
6950 uint32_t access_mask)
6952 char *fname_src_dir = NULL;
6953 struct smb_filename *smb_fname_src_dir = NULL;
6954 char *fname_src_mask = NULL;
6955 int count=0;
6956 NTSTATUS status = NT_STATUS_OK;
6957 struct smb_Dir *dir_hnd = NULL;
6958 const char *dname = NULL;
6959 char *talloced = NULL;
6960 long offset = 0;
6961 int create_options = 0;
6962 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6963 int rc;
6966 * Split the old name into directory and last component
6967 * strings. Note that unix_convert may have stripped off a
6968 * leading ./ from both name and newname if the rename is
6969 * at the root of the share. We need to make sure either both
6970 * name and newname contain a / character or neither of them do
6971 * as this is checked in resolve_wildcards().
6974 /* Split up the directory from the filename/mask. */
6975 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6976 &fname_src_dir, &fname_src_mask);
6977 if (!NT_STATUS_IS_OK(status)) {
6978 status = NT_STATUS_NO_MEMORY;
6979 goto out;
6983 * We should only check the mangled cache
6984 * here if unix_convert failed. This means
6985 * that the path in 'mask' doesn't exist
6986 * on the file system and so we need to look
6987 * for a possible mangle. This patch from
6988 * Tine Smukavec <valentin.smukavec@hermes.si>.
6991 if (!VALID_STAT(smb_fname_src->st) &&
6992 mangle_is_mangled(fname_src_mask, conn->params)) {
6993 char *new_mask = NULL;
6994 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6995 conn->params);
6996 if (new_mask) {
6997 TALLOC_FREE(fname_src_mask);
6998 fname_src_mask = new_mask;
7002 if (!src_has_wild) {
7003 files_struct *fsp;
7006 * Only one file needs to be renamed. Append the mask back
7007 * onto the directory.
7009 TALLOC_FREE(smb_fname_src->base_name);
7010 if (ISDOT(fname_src_dir)) {
7011 /* Ensure we use canonical names on open. */
7012 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7013 "%s",
7014 fname_src_mask);
7015 } else {
7016 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7017 "%s/%s",
7018 fname_src_dir,
7019 fname_src_mask);
7021 if (!smb_fname_src->base_name) {
7022 status = NT_STATUS_NO_MEMORY;
7023 goto out;
7026 DEBUG(3, ("rename_internals: case_sensitive = %d, "
7027 "case_preserve = %d, short case preserve = %d, "
7028 "directory = %s, newname = %s, "
7029 "last_component_dest = %s\n",
7030 conn->case_sensitive, conn->case_preserve,
7031 conn->short_case_preserve,
7032 smb_fname_str_dbg(smb_fname_src),
7033 smb_fname_str_dbg(smb_fname_dst),
7034 smb_fname_dst->original_lcomp));
7036 /* The dest name still may have wildcards. */
7037 if (dest_has_wild) {
7038 char *fname_dst_mod = NULL;
7039 if (!resolve_wildcards(smb_fname_dst,
7040 smb_fname_src->base_name,
7041 smb_fname_dst->base_name,
7042 &fname_dst_mod)) {
7043 DEBUG(6, ("rename_internals: resolve_wildcards "
7044 "%s %s failed\n",
7045 smb_fname_src->base_name,
7046 smb_fname_dst->base_name));
7047 status = NT_STATUS_NO_MEMORY;
7048 goto out;
7050 TALLOC_FREE(smb_fname_dst->base_name);
7051 smb_fname_dst->base_name = fname_dst_mod;
7054 ZERO_STRUCT(smb_fname_src->st);
7055 if (posix_pathnames) {
7056 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7057 } else {
7058 rc = SMB_VFS_STAT(conn, smb_fname_src);
7060 if (rc == -1) {
7061 status = map_nt_error_from_unix_common(errno);
7062 goto out;
7065 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7066 create_options |= FILE_DIRECTORY_FILE;
7069 status = SMB_VFS_CREATE_FILE(
7070 conn, /* conn */
7071 req, /* req */
7072 0, /* root_dir_fid */
7073 smb_fname_src, /* fname */
7074 access_mask, /* access_mask */
7075 (FILE_SHARE_READ | /* share_access */
7076 FILE_SHARE_WRITE),
7077 FILE_OPEN, /* create_disposition*/
7078 create_options, /* create_options */
7079 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7080 0, /* oplock_request */
7081 NULL, /* lease */
7082 0, /* allocation_size */
7083 0, /* private_flags */
7084 NULL, /* sd */
7085 NULL, /* ea_list */
7086 &fsp, /* result */
7087 NULL, /* pinfo */
7088 NULL, NULL); /* create context */
7090 if (!NT_STATUS_IS_OK(status)) {
7091 DEBUG(3, ("Could not open rename source %s: %s\n",
7092 smb_fname_str_dbg(smb_fname_src),
7093 nt_errstr(status)));
7094 goto out;
7097 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7098 attrs, replace_if_exists);
7100 close_file(req, fsp, NORMAL_CLOSE);
7102 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7103 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7104 smb_fname_str_dbg(smb_fname_dst)));
7106 goto out;
7110 * Wildcards - process each file that matches.
7112 if (strequal(fname_src_mask, "????????.???")) {
7113 TALLOC_FREE(fname_src_mask);
7114 fname_src_mask = talloc_strdup(ctx, "*");
7115 if (!fname_src_mask) {
7116 status = NT_STATUS_NO_MEMORY;
7117 goto out;
7121 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7122 fname_src_dir,
7123 NULL,
7124 NULL,
7125 smb_fname_src->flags);
7126 if (smb_fname_src_dir == NULL) {
7127 status = NT_STATUS_NO_MEMORY;
7128 goto out;
7131 status = check_name(conn, smb_fname_src_dir);
7132 if (!NT_STATUS_IS_OK(status)) {
7133 goto out;
7136 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7137 attrs);
7138 if (dir_hnd == NULL) {
7139 status = map_nt_error_from_unix(errno);
7140 goto out;
7143 status = NT_STATUS_NO_SUCH_FILE;
7145 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7146 * - gentest fix. JRA
7149 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7150 &talloced))) {
7151 files_struct *fsp = NULL;
7152 char *destname = NULL;
7153 bool sysdir_entry = False;
7155 /* Quick check for "." and ".." */
7156 if (ISDOT(dname) || ISDOTDOT(dname)) {
7157 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7158 sysdir_entry = True;
7159 } else {
7160 TALLOC_FREE(talloced);
7161 continue;
7165 if (!is_visible_file(conn, fname_src_dir, dname,
7166 &smb_fname_src->st, false)) {
7167 TALLOC_FREE(talloced);
7168 continue;
7171 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7172 TALLOC_FREE(talloced);
7173 continue;
7176 if (sysdir_entry) {
7177 status = NT_STATUS_OBJECT_NAME_INVALID;
7178 break;
7181 TALLOC_FREE(smb_fname_src->base_name);
7182 if (ISDOT(fname_src_dir)) {
7183 /* Ensure we use canonical names on open. */
7184 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7185 "%s",
7186 dname);
7187 } else {
7188 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7189 "%s/%s",
7190 fname_src_dir,
7191 dname);
7193 if (!smb_fname_src->base_name) {
7194 status = NT_STATUS_NO_MEMORY;
7195 goto out;
7198 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7199 smb_fname_dst->base_name,
7200 &destname)) {
7201 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7202 smb_fname_src->base_name, destname));
7203 TALLOC_FREE(talloced);
7204 continue;
7206 if (!destname) {
7207 status = NT_STATUS_NO_MEMORY;
7208 goto out;
7211 TALLOC_FREE(smb_fname_dst->base_name);
7212 smb_fname_dst->base_name = destname;
7214 ZERO_STRUCT(smb_fname_src->st);
7215 if (posix_pathnames) {
7216 SMB_VFS_LSTAT(conn, smb_fname_src);
7217 } else {
7218 SMB_VFS_STAT(conn, smb_fname_src);
7221 create_options = 0;
7223 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7224 create_options |= FILE_DIRECTORY_FILE;
7227 status = SMB_VFS_CREATE_FILE(
7228 conn, /* conn */
7229 req, /* req */
7230 0, /* root_dir_fid */
7231 smb_fname_src, /* fname */
7232 access_mask, /* access_mask */
7233 (FILE_SHARE_READ | /* share_access */
7234 FILE_SHARE_WRITE),
7235 FILE_OPEN, /* create_disposition*/
7236 create_options, /* create_options */
7237 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7238 0, /* oplock_request */
7239 NULL, /* lease */
7240 0, /* allocation_size */
7241 0, /* private_flags */
7242 NULL, /* sd */
7243 NULL, /* ea_list */
7244 &fsp, /* result */
7245 NULL, /* pinfo */
7246 NULL, NULL); /* create context */
7248 if (!NT_STATUS_IS_OK(status)) {
7249 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7250 "returned %s rename %s -> %s\n",
7251 nt_errstr(status),
7252 smb_fname_str_dbg(smb_fname_src),
7253 smb_fname_str_dbg(smb_fname_dst)));
7254 break;
7257 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7258 dname);
7259 if (!smb_fname_dst->original_lcomp) {
7260 status = NT_STATUS_NO_MEMORY;
7261 goto out;
7264 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7265 attrs, replace_if_exists);
7267 close_file(req, fsp, NORMAL_CLOSE);
7269 if (!NT_STATUS_IS_OK(status)) {
7270 DEBUG(3, ("rename_internals_fsp returned %s for "
7271 "rename %s -> %s\n", nt_errstr(status),
7272 smb_fname_str_dbg(smb_fname_src),
7273 smb_fname_str_dbg(smb_fname_dst)));
7274 break;
7277 count++;
7279 DEBUG(3,("rename_internals: doing rename on %s -> "
7280 "%s\n", smb_fname_str_dbg(smb_fname_src),
7281 smb_fname_str_dbg(smb_fname_src)));
7282 TALLOC_FREE(talloced);
7284 TALLOC_FREE(dir_hnd);
7286 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7287 status = map_nt_error_from_unix(errno);
7290 out:
7291 TALLOC_FREE(talloced);
7292 TALLOC_FREE(smb_fname_src_dir);
7293 TALLOC_FREE(fname_src_dir);
7294 TALLOC_FREE(fname_src_mask);
7295 return status;
7298 /****************************************************************************
7299 Reply to a mv.
7300 ****************************************************************************/
7302 void reply_mv(struct smb_request *req)
7304 connection_struct *conn = req->conn;
7305 char *name = NULL;
7306 char *newname = NULL;
7307 const char *p;
7308 uint32_t attrs;
7309 NTSTATUS status;
7310 bool src_has_wcard = False;
7311 bool dest_has_wcard = False;
7312 TALLOC_CTX *ctx = talloc_tos();
7313 struct smb_filename *smb_fname_src = NULL;
7314 struct smb_filename *smb_fname_dst = NULL;
7315 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
7316 (req->posix_pathnames ?
7317 UCF_UNIX_NAME_LOOKUP :
7318 UCF_COND_ALLOW_WCARD_LCOMP);
7319 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
7320 UCF_SAVE_LCOMP |
7321 (req->posix_pathnames ?
7323 UCF_COND_ALLOW_WCARD_LCOMP);
7324 bool stream_rename = false;
7326 START_PROFILE(SMBmv);
7328 if (req->wct < 1) {
7329 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7330 goto out;
7333 attrs = SVAL(req->vwv+0, 0);
7335 p = (const char *)req->buf + 1;
7336 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7337 &status, &src_has_wcard);
7338 if (!NT_STATUS_IS_OK(status)) {
7339 reply_nterror(req, status);
7340 goto out;
7342 p++;
7343 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7344 &status, &dest_has_wcard);
7345 if (!NT_STATUS_IS_OK(status)) {
7346 reply_nterror(req, status);
7347 goto out;
7350 if (!req->posix_pathnames) {
7351 /* The newname must begin with a ':' if the
7352 name contains a ':'. */
7353 if (strchr_m(name, ':')) {
7354 if (newname[0] != ':') {
7355 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7356 goto out;
7358 stream_rename = true;
7362 status = filename_convert(ctx,
7363 conn,
7364 name,
7365 src_ucf_flags,
7366 &src_has_wcard,
7367 &smb_fname_src);
7369 if (!NT_STATUS_IS_OK(status)) {
7370 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7371 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7372 ERRSRV, ERRbadpath);
7373 goto out;
7375 reply_nterror(req, status);
7376 goto out;
7379 status = filename_convert(ctx,
7380 conn,
7381 newname,
7382 dst_ucf_flags,
7383 &dest_has_wcard,
7384 &smb_fname_dst);
7386 if (!NT_STATUS_IS_OK(status)) {
7387 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7388 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7389 ERRSRV, ERRbadpath);
7390 goto out;
7392 reply_nterror(req, status);
7393 goto out;
7396 if (stream_rename) {
7397 /* smb_fname_dst->base_name must be the same as
7398 smb_fname_src->base_name. */
7399 TALLOC_FREE(smb_fname_dst->base_name);
7400 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7401 smb_fname_src->base_name);
7402 if (!smb_fname_dst->base_name) {
7403 reply_nterror(req, NT_STATUS_NO_MEMORY);
7404 goto out;
7408 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7409 smb_fname_str_dbg(smb_fname_dst)));
7411 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7412 attrs, False, src_has_wcard, dest_has_wcard,
7413 DELETE_ACCESS);
7414 if (!NT_STATUS_IS_OK(status)) {
7415 if (open_was_deferred(req->xconn, req->mid)) {
7416 /* We have re-scheduled this call. */
7417 goto out;
7419 reply_nterror(req, status);
7420 goto out;
7423 reply_outbuf(req, 0, 0);
7424 out:
7425 TALLOC_FREE(smb_fname_src);
7426 TALLOC_FREE(smb_fname_dst);
7427 END_PROFILE(SMBmv);
7428 return;
7431 /*******************************************************************
7432 Copy a file as part of a reply_copy.
7433 ******************************************************************/
7436 * TODO: check error codes on all callers
7439 NTSTATUS copy_file(TALLOC_CTX *ctx,
7440 connection_struct *conn,
7441 struct smb_filename *smb_fname_src,
7442 struct smb_filename *smb_fname_dst,
7443 int ofun,
7444 int count,
7445 bool target_is_directory)
7447 struct smb_filename *smb_fname_dst_tmp = NULL;
7448 off_t ret=-1;
7449 files_struct *fsp1,*fsp2;
7450 uint32_t dosattrs;
7451 uint32_t new_create_disposition;
7452 NTSTATUS status;
7455 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7456 if (smb_fname_dst_tmp == NULL) {
7457 return NT_STATUS_NO_MEMORY;
7461 * If the target is a directory, extract the last component from the
7462 * src filename and append it to the dst filename
7464 if (target_is_directory) {
7465 const char *p;
7467 /* dest/target can't be a stream if it's a directory. */
7468 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7470 p = strrchr_m(smb_fname_src->base_name,'/');
7471 if (p) {
7472 p++;
7473 } else {
7474 p = smb_fname_src->base_name;
7476 smb_fname_dst_tmp->base_name =
7477 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7479 if (!smb_fname_dst_tmp->base_name) {
7480 status = NT_STATUS_NO_MEMORY;
7481 goto out;
7485 status = vfs_file_exist(conn, smb_fname_src);
7486 if (!NT_STATUS_IS_OK(status)) {
7487 goto out;
7490 if (!target_is_directory && count) {
7491 new_create_disposition = FILE_OPEN;
7492 } else {
7493 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7494 0, ofun,
7495 NULL, NULL,
7496 &new_create_disposition,
7497 NULL,
7498 NULL)) {
7499 status = NT_STATUS_INVALID_PARAMETER;
7500 goto out;
7504 /* Open the src file for reading. */
7505 status = SMB_VFS_CREATE_FILE(
7506 conn, /* conn */
7507 NULL, /* req */
7508 0, /* root_dir_fid */
7509 smb_fname_src, /* fname */
7510 FILE_GENERIC_READ, /* access_mask */
7511 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7512 FILE_OPEN, /* create_disposition*/
7513 0, /* create_options */
7514 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7515 INTERNAL_OPEN_ONLY, /* oplock_request */
7516 NULL, /* lease */
7517 0, /* allocation_size */
7518 0, /* private_flags */
7519 NULL, /* sd */
7520 NULL, /* ea_list */
7521 &fsp1, /* result */
7522 NULL, /* psbuf */
7523 NULL, NULL); /* create context */
7525 if (!NT_STATUS_IS_OK(status)) {
7526 goto out;
7529 dosattrs = dos_mode(conn, smb_fname_src);
7531 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7532 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7535 /* Open the dst file for writing. */
7536 status = SMB_VFS_CREATE_FILE(
7537 conn, /* conn */
7538 NULL, /* req */
7539 0, /* root_dir_fid */
7540 smb_fname_dst, /* fname */
7541 FILE_GENERIC_WRITE, /* access_mask */
7542 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7543 new_create_disposition, /* create_disposition*/
7544 0, /* create_options */
7545 dosattrs, /* file_attributes */
7546 INTERNAL_OPEN_ONLY, /* oplock_request */
7547 NULL, /* lease */
7548 0, /* allocation_size */
7549 0, /* private_flags */
7550 NULL, /* sd */
7551 NULL, /* ea_list */
7552 &fsp2, /* result */
7553 NULL, /* psbuf */
7554 NULL, NULL); /* create context */
7556 if (!NT_STATUS_IS_OK(status)) {
7557 close_file(NULL, fsp1, ERROR_CLOSE);
7558 goto out;
7561 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7562 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7563 if (ret == -1) {
7564 DEBUG(0, ("error - vfs lseek returned error %s\n",
7565 strerror(errno)));
7566 status = map_nt_error_from_unix(errno);
7567 close_file(NULL, fsp1, ERROR_CLOSE);
7568 close_file(NULL, fsp2, ERROR_CLOSE);
7569 goto out;
7573 /* Do the actual copy. */
7574 if (smb_fname_src->st.st_ex_size) {
7575 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7576 } else {
7577 ret = 0;
7580 close_file(NULL, fsp1, NORMAL_CLOSE);
7582 /* Ensure the modtime is set correctly on the destination file. */
7583 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7586 * As we are opening fsp1 read-only we only expect
7587 * an error on close on fsp2 if we are out of space.
7588 * Thus we don't look at the error return from the
7589 * close of fsp1.
7591 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7593 if (!NT_STATUS_IS_OK(status)) {
7594 goto out;
7597 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7598 status = NT_STATUS_DISK_FULL;
7599 goto out;
7602 status = NT_STATUS_OK;
7604 out:
7605 TALLOC_FREE(smb_fname_dst_tmp);
7606 return status;
7609 /****************************************************************************
7610 Reply to a file copy.
7611 ****************************************************************************/
7613 void reply_copy(struct smb_request *req)
7615 connection_struct *conn = req->conn;
7616 struct smb_filename *smb_fname_src = NULL;
7617 struct smb_filename *smb_fname_src_dir = NULL;
7618 struct smb_filename *smb_fname_dst = NULL;
7619 char *fname_src = NULL;
7620 char *fname_dst = NULL;
7621 char *fname_src_mask = NULL;
7622 char *fname_src_dir = NULL;
7623 const char *p;
7624 int count=0;
7625 int error = ERRnoaccess;
7626 int tid2;
7627 int ofun;
7628 int flags;
7629 bool target_is_directory=False;
7630 bool source_has_wild = False;
7631 bool dest_has_wild = False;
7632 NTSTATUS status;
7633 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7634 ucf_flags_from_smb_request(req);
7635 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7636 ucf_flags_from_smb_request(req);
7637 TALLOC_CTX *ctx = talloc_tos();
7639 START_PROFILE(SMBcopy);
7641 if (req->wct < 3) {
7642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7643 goto out;
7646 tid2 = SVAL(req->vwv+0, 0);
7647 ofun = SVAL(req->vwv+1, 0);
7648 flags = SVAL(req->vwv+2, 0);
7650 p = (const char *)req->buf;
7651 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7652 &status, &source_has_wild);
7653 if (!NT_STATUS_IS_OK(status)) {
7654 reply_nterror(req, status);
7655 goto out;
7657 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7658 &status, &dest_has_wild);
7659 if (!NT_STATUS_IS_OK(status)) {
7660 reply_nterror(req, status);
7661 goto out;
7664 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7666 if (tid2 != conn->cnum) {
7667 /* can't currently handle inter share copies XXXX */
7668 DEBUG(3,("Rejecting inter-share copy\n"));
7669 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7670 goto out;
7673 status = filename_convert(ctx, conn,
7674 fname_src,
7675 ucf_flags_src,
7676 &source_has_wild,
7677 &smb_fname_src);
7678 if (!NT_STATUS_IS_OK(status)) {
7679 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7680 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7681 ERRSRV, ERRbadpath);
7682 goto out;
7684 reply_nterror(req, status);
7685 goto out;
7688 status = filename_convert(ctx, conn,
7689 fname_dst,
7690 ucf_flags_dst,
7691 &dest_has_wild,
7692 &smb_fname_dst);
7693 if (!NT_STATUS_IS_OK(status)) {
7694 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7695 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7696 ERRSRV, ERRbadpath);
7697 goto out;
7699 reply_nterror(req, status);
7700 goto out;
7703 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7705 if ((flags&1) && target_is_directory) {
7706 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7707 goto out;
7710 if ((flags&2) && !target_is_directory) {
7711 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7712 goto out;
7715 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7716 /* wants a tree copy! XXXX */
7717 DEBUG(3,("Rejecting tree copy\n"));
7718 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7719 goto out;
7722 /* Split up the directory from the filename/mask. */
7723 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7724 &fname_src_dir, &fname_src_mask);
7725 if (!NT_STATUS_IS_OK(status)) {
7726 reply_nterror(req, NT_STATUS_NO_MEMORY);
7727 goto out;
7731 * We should only check the mangled cache
7732 * here if unix_convert failed. This means
7733 * that the path in 'mask' doesn't exist
7734 * on the file system and so we need to look
7735 * for a possible mangle. This patch from
7736 * Tine Smukavec <valentin.smukavec@hermes.si>.
7738 if (!VALID_STAT(smb_fname_src->st) &&
7739 mangle_is_mangled(fname_src_mask, conn->params)) {
7740 char *new_mask = NULL;
7741 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7742 &new_mask, conn->params);
7744 /* Use demangled name if one was successfully found. */
7745 if (new_mask) {
7746 TALLOC_FREE(fname_src_mask);
7747 fname_src_mask = new_mask;
7751 if (!source_has_wild) {
7754 * Only one file needs to be copied. Append the mask back onto
7755 * the directory.
7757 TALLOC_FREE(smb_fname_src->base_name);
7758 if (ISDOT(fname_src_dir)) {
7759 /* Ensure we use canonical names on open. */
7760 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7761 "%s",
7762 fname_src_mask);
7763 } else {
7764 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7765 "%s/%s",
7766 fname_src_dir,
7767 fname_src_mask);
7769 if (!smb_fname_src->base_name) {
7770 reply_nterror(req, NT_STATUS_NO_MEMORY);
7771 goto out;
7774 if (dest_has_wild) {
7775 char *fname_dst_mod = NULL;
7776 if (!resolve_wildcards(smb_fname_dst,
7777 smb_fname_src->base_name,
7778 smb_fname_dst->base_name,
7779 &fname_dst_mod)) {
7780 reply_nterror(req, NT_STATUS_NO_MEMORY);
7781 goto out;
7783 TALLOC_FREE(smb_fname_dst->base_name);
7784 smb_fname_dst->base_name = fname_dst_mod;
7787 status = check_name(conn, smb_fname_src);
7788 if (!NT_STATUS_IS_OK(status)) {
7789 reply_nterror(req, status);
7790 goto out;
7793 status = check_name(conn, smb_fname_dst);
7794 if (!NT_STATUS_IS_OK(status)) {
7795 reply_nterror(req, status);
7796 goto out;
7799 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7800 ofun, count, target_is_directory);
7802 if(!NT_STATUS_IS_OK(status)) {
7803 reply_nterror(req, status);
7804 goto out;
7805 } else {
7806 count++;
7808 } else {
7809 struct smb_Dir *dir_hnd = NULL;
7810 const char *dname = NULL;
7811 char *talloced = NULL;
7812 long offset = 0;
7815 * There is a wildcard that requires us to actually read the
7816 * src dir and copy each file matching the mask to the dst.
7817 * Right now streams won't be copied, but this could
7818 * presumably be added with a nested loop for reach dir entry.
7820 SMB_ASSERT(!smb_fname_src->stream_name);
7821 SMB_ASSERT(!smb_fname_dst->stream_name);
7823 smb_fname_src->stream_name = NULL;
7824 smb_fname_dst->stream_name = NULL;
7826 if (strequal(fname_src_mask,"????????.???")) {
7827 TALLOC_FREE(fname_src_mask);
7828 fname_src_mask = talloc_strdup(ctx, "*");
7829 if (!fname_src_mask) {
7830 reply_nterror(req, NT_STATUS_NO_MEMORY);
7831 goto out;
7835 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7836 fname_src_dir,
7837 NULL,
7838 NULL,
7839 smb_fname_src->flags);
7840 if (smb_fname_src_dir == NULL) {
7841 reply_nterror(req, NT_STATUS_NO_MEMORY);
7842 goto out;
7845 status = check_name(conn, smb_fname_src_dir);
7846 if (!NT_STATUS_IS_OK(status)) {
7847 reply_nterror(req, status);
7848 goto out;
7851 dir_hnd = OpenDir(ctx,
7852 conn,
7853 smb_fname_src_dir,
7854 fname_src_mask,
7856 if (dir_hnd == NULL) {
7857 status = map_nt_error_from_unix(errno);
7858 reply_nterror(req, status);
7859 goto out;
7862 error = ERRbadfile;
7864 /* Iterate over the src dir copying each entry to the dst. */
7865 while ((dname = ReadDirName(dir_hnd, &offset,
7866 &smb_fname_src->st, &talloced))) {
7867 char *destname = NULL;
7869 if (ISDOT(dname) || ISDOTDOT(dname)) {
7870 TALLOC_FREE(talloced);
7871 continue;
7874 if (!is_visible_file(conn, fname_src_dir, dname,
7875 &smb_fname_src->st, false)) {
7876 TALLOC_FREE(talloced);
7877 continue;
7880 if(!mask_match(dname, fname_src_mask,
7881 conn->case_sensitive)) {
7882 TALLOC_FREE(talloced);
7883 continue;
7886 error = ERRnoaccess;
7888 /* Get the src smb_fname struct setup. */
7889 TALLOC_FREE(smb_fname_src->base_name);
7890 if (ISDOT(fname_src_dir)) {
7891 /* Ensure we use canonical names on open. */
7892 smb_fname_src->base_name =
7893 talloc_asprintf(smb_fname_src, "%s",
7894 dname);
7895 } else {
7896 smb_fname_src->base_name =
7897 talloc_asprintf(smb_fname_src, "%s/%s",
7898 fname_src_dir, dname);
7901 if (!smb_fname_src->base_name) {
7902 TALLOC_FREE(dir_hnd);
7903 TALLOC_FREE(talloced);
7904 reply_nterror(req, NT_STATUS_NO_MEMORY);
7905 goto out;
7908 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7909 smb_fname_dst->base_name,
7910 &destname)) {
7911 TALLOC_FREE(talloced);
7912 continue;
7914 if (!destname) {
7915 TALLOC_FREE(dir_hnd);
7916 TALLOC_FREE(talloced);
7917 reply_nterror(req, NT_STATUS_NO_MEMORY);
7918 goto out;
7921 TALLOC_FREE(smb_fname_dst->base_name);
7922 smb_fname_dst->base_name = destname;
7924 status = check_name(conn, smb_fname_src);
7925 if (!NT_STATUS_IS_OK(status)) {
7926 TALLOC_FREE(dir_hnd);
7927 TALLOC_FREE(talloced);
7928 reply_nterror(req, status);
7929 goto out;
7932 status = check_name(conn, smb_fname_dst);
7933 if (!NT_STATUS_IS_OK(status)) {
7934 TALLOC_FREE(dir_hnd);
7935 TALLOC_FREE(talloced);
7936 reply_nterror(req, status);
7937 goto out;
7940 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7941 smb_fname_src->base_name,
7942 smb_fname_dst->base_name));
7944 status = copy_file(ctx, conn, smb_fname_src,
7945 smb_fname_dst, ofun, count,
7946 target_is_directory);
7947 if (NT_STATUS_IS_OK(status)) {
7948 count++;
7951 TALLOC_FREE(talloced);
7953 TALLOC_FREE(dir_hnd);
7956 if (count == 0) {
7957 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7958 goto out;
7961 reply_outbuf(req, 1, 0);
7962 SSVAL(req->outbuf,smb_vwv0,count);
7963 out:
7964 TALLOC_FREE(smb_fname_src);
7965 TALLOC_FREE(smb_fname_src_dir);
7966 TALLOC_FREE(smb_fname_dst);
7967 TALLOC_FREE(fname_src);
7968 TALLOC_FREE(fname_dst);
7969 TALLOC_FREE(fname_src_mask);
7970 TALLOC_FREE(fname_src_dir);
7972 END_PROFILE(SMBcopy);
7973 return;
7976 #undef DBGC_CLASS
7977 #define DBGC_CLASS DBGC_LOCKING
7979 /****************************************************************************
7980 Get a lock pid, dealing with large count requests.
7981 ****************************************************************************/
7983 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7984 bool large_file_format)
7986 if(!large_file_format)
7987 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7988 else
7989 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7992 /****************************************************************************
7993 Get a lock count, dealing with large count requests.
7994 ****************************************************************************/
7996 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7997 bool large_file_format)
7999 uint64_t count = 0;
8001 if(!large_file_format) {
8002 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
8003 } else {
8005 * No BVAL, this is reversed!
8007 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
8008 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
8011 return count;
8014 /****************************************************************************
8015 Get a lock offset, dealing with large offset requests.
8016 ****************************************************************************/
8018 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
8019 bool large_file_format)
8021 uint64_t offset = 0;
8023 if(!large_file_format) {
8024 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
8025 } else {
8027 * No BVAL, this is reversed!
8029 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
8030 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
8033 return offset;
8036 NTSTATUS smbd_do_locking(struct smb_request *req,
8037 files_struct *fsp,
8038 uint8_t type,
8039 int32_t timeout,
8040 uint16_t num_locks,
8041 struct smbd_lock_element *locks,
8042 bool *async)
8044 connection_struct *conn = req->conn;
8045 int i;
8046 NTSTATUS status = NT_STATUS_OK;
8048 *async = false;
8050 /* Setup the timeout in seconds. */
8052 if (!lp_blocking_locks(SNUM(conn))) {
8053 timeout = 0;
8056 for(i = 0; i < (int)num_locks; i++) {
8057 struct smbd_lock_element *e = &locks[i];
8059 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8060 "%llu, file %s timeout = %d\n",
8061 (double)e->offset,
8062 (double)e->count,
8063 (unsigned long long)e->smblctx,
8064 fsp_str_dbg(fsp),
8065 (int)timeout));
8067 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8068 struct blocking_lock_record *blr = NULL;
8070 if (num_locks > 1) {
8072 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8073 * if the lock vector contains one entry. When given multiple cancel
8074 * requests in a single PDU we expect the server to return an
8075 * error. Windows servers seem to accept the request but only
8076 * cancel the first lock.
8077 * JRA - Do what Windows does (tm) :-).
8080 #if 0
8081 /* MS-CIFS (2.2.4.32.1) behavior. */
8082 return NT_STATUS_DOS(ERRDOS,
8083 ERRcancelviolation);
8084 #else
8085 /* Windows behavior. */
8086 if (i != 0) {
8087 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8088 "cancel request\n"));
8089 continue;
8091 #endif
8094 if (lp_blocking_locks(SNUM(conn))) {
8096 /* Schedule a message to ourselves to
8097 remove the blocking lock record and
8098 return the right error. */
8100 blr = blocking_lock_cancel_smb1(fsp,
8101 e->smblctx,
8102 e->offset,
8103 e->count,
8104 WINDOWS_LOCK,
8105 type,
8106 NT_STATUS_FILE_LOCK_CONFLICT);
8107 if (blr == NULL) {
8108 return NT_STATUS_DOS(
8109 ERRDOS,
8110 ERRcancelviolation);
8113 /* Remove a matching pending lock. */
8114 status = do_lock_cancel(fsp,
8115 e->smblctx,
8116 e->count,
8117 e->offset,
8118 WINDOWS_LOCK);
8119 } else {
8120 bool blocking_lock = timeout ? true : false;
8121 bool defer_lock = false;
8122 struct byte_range_lock *br_lck;
8123 uint64_t block_smblctx;
8125 br_lck = do_lock(req->sconn->msg_ctx,
8126 fsp,
8127 e->smblctx,
8128 e->count,
8129 e->offset,
8130 e->brltype,
8131 WINDOWS_LOCK,
8132 blocking_lock,
8133 &status,
8134 &block_smblctx);
8136 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8137 /* Windows internal resolution for blocking locks seems
8138 to be about 200ms... Don't wait for less than that. JRA. */
8139 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8140 timeout = lp_lock_spin_time();
8142 defer_lock = true;
8145 /* If a lock sent with timeout of zero would fail, and
8146 * this lock has been requested multiple times,
8147 * according to brl_lock_failed() we convert this
8148 * request to a blocking lock with a timeout of between
8149 * 150 - 300 milliseconds.
8151 * If lp_lock_spin_time() has been set to 0, we skip
8152 * this blocking retry and fail immediately.
8154 * Replacement for do_lock_spin(). JRA. */
8156 if (!req->sconn->using_smb2 &&
8157 br_lck && lp_blocking_locks(SNUM(conn)) &&
8158 lp_lock_spin_time() && !blocking_lock &&
8159 NT_STATUS_EQUAL((status),
8160 NT_STATUS_FILE_LOCK_CONFLICT))
8162 defer_lock = true;
8163 timeout = lp_lock_spin_time();
8166 if (br_lck && defer_lock) {
8168 * A blocking lock was requested. Package up
8169 * this smb into a queued request and push it
8170 * onto the blocking lock queue.
8172 if(push_blocking_lock_request(br_lck,
8173 req,
8174 fsp,
8175 timeout,
8177 e->smblctx,
8178 e->brltype,
8179 WINDOWS_LOCK,
8180 e->offset,
8181 e->count,
8182 block_smblctx)) {
8183 TALLOC_FREE(br_lck);
8184 *async = true;
8185 return NT_STATUS_OK;
8189 TALLOC_FREE(br_lck);
8192 if (!NT_STATUS_IS_OK(status)) {
8193 break;
8197 /* If any of the above locks failed, then we must unlock
8198 all of the previous locks (X/Open spec). */
8200 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8202 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8203 i = -1; /* we want to skip the for loop */
8207 * Ensure we don't do a remove on the lock that just failed,
8208 * as under POSIX rules, if we have a lock already there, we
8209 * will delete it (and we shouldn't) .....
8211 for(i--; i >= 0; i--) {
8212 struct smbd_lock_element *e = &locks[i];
8214 do_unlock(req->sconn->msg_ctx,
8215 fsp,
8216 e->smblctx,
8217 e->count,
8218 e->offset,
8219 WINDOWS_LOCK);
8221 return status;
8224 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8225 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8227 return NT_STATUS_OK;
8230 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8231 files_struct *fsp,
8232 uint16_t num_ulocks,
8233 struct smbd_lock_element *ulocks)
8235 int i;
8237 for(i = 0; i < (int)num_ulocks; i++) {
8238 struct smbd_lock_element *e = &ulocks[i];
8239 NTSTATUS status;
8241 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8242 "pid %u, file %s\n", __func__,
8243 (double)e->offset,
8244 (double)e->count,
8245 (unsigned int)e->smblctx,
8246 fsp_str_dbg(fsp)));
8248 if (e->brltype != UNLOCK_LOCK) {
8249 /* this can only happen with SMB2 */
8250 return NT_STATUS_INVALID_PARAMETER;
8253 status = do_unlock(req->sconn->msg_ctx,
8254 fsp,
8255 e->smblctx,
8256 e->count,
8257 e->offset,
8258 WINDOWS_LOCK);
8260 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8261 nt_errstr(status)));
8263 if (!NT_STATUS_IS_OK(status)) {
8264 return status;
8268 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8269 num_ulocks));
8271 return NT_STATUS_OK;
8274 /****************************************************************************
8275 Reply to a lockingX request.
8276 ****************************************************************************/
8278 void reply_lockingX(struct smb_request *req)
8280 connection_struct *conn = req->conn;
8281 files_struct *fsp;
8282 unsigned char locktype;
8283 unsigned char oplocklevel;
8284 uint16_t num_ulocks;
8285 uint16_t num_locks;
8286 int32_t lock_timeout;
8287 int i;
8288 const uint8_t *data;
8289 bool large_file_format;
8290 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8291 struct smbd_lock_element *ulocks;
8292 struct smbd_lock_element *locks;
8293 bool async = false;
8295 START_PROFILE(SMBlockingX);
8297 if (req->wct < 8) {
8298 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8299 END_PROFILE(SMBlockingX);
8300 return;
8303 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8304 locktype = CVAL(req->vwv+3, 0);
8305 oplocklevel = CVAL(req->vwv+3, 1);
8306 num_ulocks = SVAL(req->vwv+6, 0);
8307 num_locks = SVAL(req->vwv+7, 0);
8308 lock_timeout = IVAL(req->vwv+4, 0);
8309 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8311 if (!check_fsp(conn, req, fsp)) {
8312 END_PROFILE(SMBlockingX);
8313 return;
8316 data = req->buf;
8318 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8319 /* we don't support these - and CANCEL_LOCK makes w2k
8320 and XP reboot so I don't really want to be
8321 compatible! (tridge) */
8322 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8323 END_PROFILE(SMBlockingX);
8324 return;
8327 /* Check if this is an oplock break on a file
8328 we have granted an oplock on.
8330 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8331 /* Client can insist on breaking to none. */
8332 bool break_to_none = (oplocklevel == 0);
8333 bool result;
8335 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8336 "for %s\n", (unsigned int)oplocklevel,
8337 fsp_fnum_dbg(fsp)));
8340 * Make sure we have granted an exclusive or batch oplock on
8341 * this file.
8344 if (fsp->oplock_type == 0) {
8346 /* The Samba4 nbench simulator doesn't understand
8347 the difference between break to level2 and break
8348 to none from level2 - it sends oplock break
8349 replies in both cases. Don't keep logging an error
8350 message here - just ignore it. JRA. */
8352 DEBUG(5,("reply_lockingX: Error : oplock break from "
8353 "client for %s (oplock=%d) and no "
8354 "oplock granted on this file (%s).\n",
8355 fsp_fnum_dbg(fsp), fsp->oplock_type,
8356 fsp_str_dbg(fsp)));
8358 /* if this is a pure oplock break request then don't
8359 * send a reply */
8360 if (num_locks == 0 && num_ulocks == 0) {
8361 END_PROFILE(SMBlockingX);
8362 return;
8363 } else {
8364 END_PROFILE(SMBlockingX);
8365 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8366 return;
8370 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8371 (break_to_none)) {
8372 result = remove_oplock(fsp);
8373 } else {
8374 result = downgrade_oplock(fsp);
8377 if (!result) {
8378 DEBUG(0, ("reply_lockingX: error in removing "
8379 "oplock on file %s\n", fsp_str_dbg(fsp)));
8380 /* Hmmm. Is this panic justified? */
8381 smb_panic("internal tdb error");
8384 /* if this is a pure oplock break request then don't send a
8385 * reply */
8386 if (num_locks == 0 && num_ulocks == 0) {
8387 /* Sanity check - ensure a pure oplock break is not a
8388 chained request. */
8389 if (CVAL(req->vwv+0, 0) != 0xff) {
8390 DEBUG(0,("reply_lockingX: Error : pure oplock "
8391 "break is a chained %d request !\n",
8392 (unsigned int)CVAL(req->vwv+0, 0)));
8394 END_PROFILE(SMBlockingX);
8395 return;
8399 if (req->buflen <
8400 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8401 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8402 END_PROFILE(SMBlockingX);
8403 return;
8406 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8407 if (ulocks == NULL) {
8408 reply_nterror(req, NT_STATUS_NO_MEMORY);
8409 END_PROFILE(SMBlockingX);
8410 return;
8413 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8414 if (locks == NULL) {
8415 reply_nterror(req, NT_STATUS_NO_MEMORY);
8416 END_PROFILE(SMBlockingX);
8417 return;
8420 /* Data now points at the beginning of the list
8421 of smb_unlkrng structs */
8422 for(i = 0; i < (int)num_ulocks; i++) {
8423 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8424 ulocks[i].count = get_lock_count(data, i, large_file_format);
8425 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8426 ulocks[i].brltype = UNLOCK_LOCK;
8429 /* Now do any requested locks */
8430 data += ((large_file_format ? 20 : 10)*num_ulocks);
8432 /* Data now points at the beginning of the list
8433 of smb_lkrng structs */
8435 for(i = 0; i < (int)num_locks; i++) {
8436 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8437 locks[i].count = get_lock_count(data, i, large_file_format);
8438 locks[i].offset = get_lock_offset(data, i, large_file_format);
8440 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8441 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8442 locks[i].brltype = PENDING_READ_LOCK;
8443 } else {
8444 locks[i].brltype = READ_LOCK;
8446 } else {
8447 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8448 locks[i].brltype = PENDING_WRITE_LOCK;
8449 } else {
8450 locks[i].brltype = WRITE_LOCK;
8455 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8456 if (!NT_STATUS_IS_OK(status)) {
8457 END_PROFILE(SMBlockingX);
8458 reply_nterror(req, status);
8459 return;
8462 status = smbd_do_locking(req, fsp,
8463 locktype, lock_timeout,
8464 num_locks, locks,
8465 &async);
8466 if (!NT_STATUS_IS_OK(status)) {
8467 END_PROFILE(SMBlockingX);
8468 reply_nterror(req, status);
8469 return;
8471 if (async) {
8472 END_PROFILE(SMBlockingX);
8473 return;
8476 reply_outbuf(req, 2, 0);
8477 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8478 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8480 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8481 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8483 END_PROFILE(SMBlockingX);
8486 #undef DBGC_CLASS
8487 #define DBGC_CLASS DBGC_ALL
8489 /****************************************************************************
8490 Reply to a SMBreadbmpx (read block multiplex) request.
8491 Always reply with an error, if someone has a platform really needs this,
8492 please contact vl@samba.org
8493 ****************************************************************************/
8495 void reply_readbmpx(struct smb_request *req)
8497 START_PROFILE(SMBreadBmpx);
8498 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8499 END_PROFILE(SMBreadBmpx);
8500 return;
8503 /****************************************************************************
8504 Reply to a SMBreadbs (read block multiplex secondary) request.
8505 Always reply with an error, if someone has a platform really needs this,
8506 please contact vl@samba.org
8507 ****************************************************************************/
8509 void reply_readbs(struct smb_request *req)
8511 START_PROFILE(SMBreadBs);
8512 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8513 END_PROFILE(SMBreadBs);
8514 return;
8517 /****************************************************************************
8518 Reply to a SMBsetattrE.
8519 ****************************************************************************/
8521 void reply_setattrE(struct smb_request *req)
8523 connection_struct *conn = req->conn;
8524 struct smb_file_time ft;
8525 files_struct *fsp;
8526 NTSTATUS status;
8528 START_PROFILE(SMBsetattrE);
8529 ZERO_STRUCT(ft);
8531 if (req->wct < 7) {
8532 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8533 goto out;
8536 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8538 if(!fsp || (fsp->conn != conn)) {
8539 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8540 goto out;
8544 * Convert the DOS times into unix times.
8547 ft.atime = convert_time_t_to_timespec(
8548 srv_make_unix_date2(req->vwv+3));
8549 ft.mtime = convert_time_t_to_timespec(
8550 srv_make_unix_date2(req->vwv+5));
8551 ft.create_time = convert_time_t_to_timespec(
8552 srv_make_unix_date2(req->vwv+1));
8554 reply_outbuf(req, 0, 0);
8557 * Patch from Ray Frush <frush@engr.colostate.edu>
8558 * Sometimes times are sent as zero - ignore them.
8561 /* Ensure we have a valid stat struct for the source. */
8562 status = vfs_stat_fsp(fsp);
8563 if (!NT_STATUS_IS_OK(status)) {
8564 reply_nterror(req, status);
8565 goto out;
8568 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8569 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8570 goto out;
8573 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8574 if (!NT_STATUS_IS_OK(status)) {
8575 reply_nterror(req, status);
8576 goto out;
8579 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8580 " createtime=%u\n",
8581 fsp_fnum_dbg(fsp),
8582 (unsigned int)ft.atime.tv_sec,
8583 (unsigned int)ft.mtime.tv_sec,
8584 (unsigned int)ft.create_time.tv_sec
8586 out:
8587 END_PROFILE(SMBsetattrE);
8588 return;
8592 /* Back from the dead for OS/2..... JRA. */
8594 /****************************************************************************
8595 Reply to a SMBwritebmpx (write block multiplex primary) request.
8596 Always reply with an error, if someone has a platform really needs this,
8597 please contact vl@samba.org
8598 ****************************************************************************/
8600 void reply_writebmpx(struct smb_request *req)
8602 START_PROFILE(SMBwriteBmpx);
8603 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8604 END_PROFILE(SMBwriteBmpx);
8605 return;
8608 /****************************************************************************
8609 Reply to a SMBwritebs (write block multiplex secondary) request.
8610 Always reply with an error, if someone has a platform really needs this,
8611 please contact vl@samba.org
8612 ****************************************************************************/
8614 void reply_writebs(struct smb_request *req)
8616 START_PROFILE(SMBwriteBs);
8617 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8618 END_PROFILE(SMBwriteBs);
8619 return;
8622 /****************************************************************************
8623 Reply to a SMBgetattrE.
8624 ****************************************************************************/
8626 void reply_getattrE(struct smb_request *req)
8628 connection_struct *conn = req->conn;
8629 int mode;
8630 files_struct *fsp;
8631 struct timespec create_ts;
8633 START_PROFILE(SMBgetattrE);
8635 if (req->wct < 1) {
8636 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8637 END_PROFILE(SMBgetattrE);
8638 return;
8641 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8643 if(!fsp || (fsp->conn != conn)) {
8644 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8645 END_PROFILE(SMBgetattrE);
8646 return;
8649 /* Do an fstat on this file */
8650 if(fsp_stat(fsp)) {
8651 reply_nterror(req, map_nt_error_from_unix(errno));
8652 END_PROFILE(SMBgetattrE);
8653 return;
8656 mode = dos_mode(conn, fsp->fsp_name);
8659 * Convert the times into dos times. Set create
8660 * date to be last modify date as UNIX doesn't save
8661 * this.
8664 reply_outbuf(req, 11, 0);
8666 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8667 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8668 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8669 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8670 /* Should we check pending modtime here ? JRA */
8671 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8672 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8674 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8675 SIVAL(req->outbuf, smb_vwv6, 0);
8676 SIVAL(req->outbuf, smb_vwv8, 0);
8677 } else {
8678 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8679 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8680 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8682 SSVAL(req->outbuf,smb_vwv10, mode);
8684 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8686 END_PROFILE(SMBgetattrE);
8687 return;