s3: libsmb: Do some hardening in the receive processing of cli_shadow_copy_data_recv().
[Samba.git] / source3 / smbd / reply.c
blob4f1ecb1ae8395e49a0afea88a872abc12540feaa
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 srv_send_smb(xconn, outbuf, false, 0, false, NULL);
784 if (CVAL(outbuf, 0) != 0x82) {
785 exit_server_cleanly("invalid netbios session");
787 return;
790 /****************************************************************************
791 Reply to a tcon.
792 conn POINTER CAN BE NULL HERE !
793 ****************************************************************************/
795 void reply_tcon(struct smb_request *req)
797 connection_struct *conn = req->conn;
798 const char *service;
799 char *service_buf = NULL;
800 char *password = NULL;
801 char *dev = NULL;
802 int pwlen=0;
803 NTSTATUS nt_status;
804 const uint8_t *p;
805 const char *p2;
806 TALLOC_CTX *ctx = talloc_tos();
807 struct smbXsrv_connection *xconn = req->xconn;
808 NTTIME now = timeval_to_nttime(&req->request_time);
810 START_PROFILE(SMBtcon);
812 if (req->buflen < 4) {
813 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
814 END_PROFILE(SMBtcon);
815 return;
818 p = req->buf + 1;
819 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
820 p += 1;
821 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
822 p += pwlen+1;
823 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
824 p += 1;
826 if (service_buf == NULL || password == NULL || dev == NULL) {
827 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
828 END_PROFILE(SMBtcon);
829 return;
831 p2 = strrchr_m(service_buf,'\\');
832 if (p2) {
833 service = p2+1;
834 } else {
835 service = service_buf;
838 conn = make_connection(req, now, service, dev,
839 req->vuid,&nt_status);
840 req->conn = conn;
842 if (!conn) {
843 reply_nterror(req, nt_status);
844 END_PROFILE(SMBtcon);
845 return;
848 reply_outbuf(req, 2, 0);
849 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
850 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
851 SSVAL(req->outbuf,smb_tid,conn->cnum);
853 DEBUG(3,("tcon service=%s cnum=%d\n",
854 service, conn->cnum));
856 END_PROFILE(SMBtcon);
857 return;
860 /****************************************************************************
861 Reply to a tcon and X.
862 conn POINTER CAN BE NULL HERE !
863 ****************************************************************************/
865 void reply_tcon_and_X(struct smb_request *req)
867 connection_struct *conn = req->conn;
868 const char *service = NULL;
869 TALLOC_CTX *ctx = talloc_tos();
870 /* what the cleint thinks the device is */
871 char *client_devicetype = NULL;
872 /* what the server tells the client the share represents */
873 const char *server_devicetype;
874 NTSTATUS nt_status;
875 int passlen;
876 char *path = NULL;
877 const uint8_t *p;
878 const char *q;
879 uint16_t tcon_flags;
880 struct smbXsrv_session *session = NULL;
881 NTTIME now = timeval_to_nttime(&req->request_time);
882 bool session_key_updated = false;
883 uint16_t optional_support = 0;
884 struct smbXsrv_connection *xconn = req->xconn;
886 START_PROFILE(SMBtconX);
888 if (req->wct < 4) {
889 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
890 END_PROFILE(SMBtconX);
891 return;
894 passlen = SVAL(req->vwv+3, 0);
895 tcon_flags = SVAL(req->vwv+2, 0);
897 /* we might have to close an old one */
898 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
899 struct smbXsrv_tcon *tcon;
900 NTSTATUS status;
902 tcon = conn->tcon;
903 req->conn = NULL;
904 conn = NULL;
907 * TODO: cancel all outstanding requests on the tcon
909 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
910 if (!NT_STATUS_IS_OK(status)) {
911 DEBUG(0, ("reply_tcon_and_X: "
912 "smbXsrv_tcon_disconnect() failed: %s\n",
913 nt_errstr(status)));
915 * If we hit this case, there is something completely
916 * wrong, so we better disconnect the transport connection.
918 END_PROFILE(SMBtconX);
919 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
920 return;
923 TALLOC_FREE(tcon);
926 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
927 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
928 END_PROFILE(SMBtconX);
929 return;
932 if (xconn->smb1.negprot.encrypted_passwords) {
933 p = req->buf + passlen;
934 } else {
935 p = req->buf + passlen + 1;
938 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
940 if (path == NULL) {
941 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
942 END_PROFILE(SMBtconX);
943 return;
947 * the service name can be either: \\server\share
948 * or share directly like on the DELL PowerVault 705
950 if (*path=='\\') {
951 q = strchr_m(path+2,'\\');
952 if (!q) {
953 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
954 END_PROFILE(SMBtconX);
955 return;
957 service = q+1;
958 } else {
959 service = path;
962 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
963 &client_devicetype, p,
964 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
966 if (client_devicetype == NULL) {
967 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
968 END_PROFILE(SMBtconX);
969 return;
972 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
974 nt_status = smb1srv_session_lookup(xconn,
975 req->vuid, now, &session);
976 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
977 reply_force_doserror(req, ERRSRV, ERRbaduid);
978 END_PROFILE(SMBtconX);
979 return;
981 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
982 reply_nterror(req, nt_status);
983 END_PROFILE(SMBtconX);
984 return;
986 if (!NT_STATUS_IS_OK(nt_status)) {
987 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
988 END_PROFILE(SMBtconX);
989 return;
992 if (session->global->auth_session_info == NULL) {
993 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
994 END_PROFILE(SMBtconX);
995 return;
999 * If there is no application key defined yet
1000 * we create one.
1002 * This means we setup the application key on the
1003 * first tcon that happens via the given session.
1005 * Once the application key is defined, it does not
1006 * change any more.
1008 if (session->global->application_key.length == 0 &&
1009 session->global->signing_key.length > 0)
1011 struct smbXsrv_session *x = session;
1012 struct auth_session_info *session_info =
1013 session->global->auth_session_info;
1014 uint8_t session_key[16];
1016 ZERO_STRUCT(session_key);
1017 memcpy(session_key, x->global->signing_key.data,
1018 MIN(x->global->signing_key.length, sizeof(session_key)));
1021 * The application key is truncated/padded to 16 bytes
1023 x->global->application_key = data_blob_talloc(x->global,
1024 session_key,
1025 sizeof(session_key));
1026 ZERO_STRUCT(session_key);
1027 if (x->global->application_key.data == NULL) {
1028 reply_nterror(req, NT_STATUS_NO_MEMORY);
1029 END_PROFILE(SMBtconX);
1030 return;
1033 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1034 smb_key_derivation(x->global->application_key.data,
1035 x->global->application_key.length,
1036 x->global->application_key.data);
1037 optional_support |= SMB_EXTENDED_SIGNATURES;
1041 * Place the application key into the session_info
1043 data_blob_clear_free(&session_info->session_key);
1044 session_info->session_key = data_blob_dup_talloc(session_info,
1045 x->global->application_key);
1046 if (session_info->session_key.data == NULL) {
1047 data_blob_clear_free(&x->global->application_key);
1048 reply_nterror(req, NT_STATUS_NO_MEMORY);
1049 END_PROFILE(SMBtconX);
1050 return;
1052 session_key_updated = true;
1055 conn = make_connection(req, now, service, client_devicetype,
1056 req->vuid, &nt_status);
1057 req->conn =conn;
1059 if (!conn) {
1060 if (session_key_updated) {
1061 struct smbXsrv_session *x = session;
1062 struct auth_session_info *session_info =
1063 session->global->auth_session_info;
1064 data_blob_clear_free(&x->global->application_key);
1065 data_blob_clear_free(&session_info->session_key);
1067 reply_nterror(req, nt_status);
1068 END_PROFILE(SMBtconX);
1069 return;
1072 if ( IS_IPC(conn) )
1073 server_devicetype = "IPC";
1074 else if ( IS_PRINT(conn) )
1075 server_devicetype = "LPT1:";
1076 else
1077 server_devicetype = "A:";
1079 if (get_Protocol() < PROTOCOL_NT1) {
1080 reply_outbuf(req, 2, 0);
1081 if (message_push_string(&req->outbuf, server_devicetype,
1082 STR_TERMINATE|STR_ASCII) == -1) {
1083 reply_nterror(req, NT_STATUS_NO_MEMORY);
1084 END_PROFILE(SMBtconX);
1085 return;
1087 } else {
1088 /* NT sets the fstype of IPC$ to the null string */
1089 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1091 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1092 /* Return permissions. */
1093 uint32_t perm1 = 0;
1094 uint32_t perm2 = 0;
1096 reply_outbuf(req, 7, 0);
1098 if (IS_IPC(conn)) {
1099 perm1 = FILE_ALL_ACCESS;
1100 perm2 = FILE_ALL_ACCESS;
1101 } else {
1102 perm1 = conn->share_access;
1105 SIVAL(req->outbuf, smb_vwv3, perm1);
1106 SIVAL(req->outbuf, smb_vwv5, perm2);
1107 } else {
1108 reply_outbuf(req, 3, 0);
1111 if ((message_push_string(&req->outbuf, server_devicetype,
1112 STR_TERMINATE|STR_ASCII) == -1)
1113 || (message_push_string(&req->outbuf, fstype,
1114 STR_TERMINATE) == -1)) {
1115 reply_nterror(req, NT_STATUS_NO_MEMORY);
1116 END_PROFILE(SMBtconX);
1117 return;
1120 /* what does setting this bit do? It is set by NT4 and
1121 may affect the ability to autorun mounted cdroms */
1122 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1123 optional_support |=
1124 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1126 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1127 DEBUG(2,("Serving %s as a Dfs root\n",
1128 lp_servicename(ctx, SNUM(conn)) ));
1129 optional_support |= SMB_SHARE_IN_DFS;
1132 SSVAL(req->outbuf, smb_vwv2, optional_support);
1135 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1136 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1138 DEBUG(3,("tconX service=%s \n",
1139 service));
1141 /* set the incoming and outgoing tid to the just created one */
1142 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1143 SSVAL(req->outbuf,smb_tid,conn->cnum);
1145 END_PROFILE(SMBtconX);
1147 req->tid = conn->cnum;
1150 /****************************************************************************
1151 Reply to an unknown type.
1152 ****************************************************************************/
1154 void reply_unknown_new(struct smb_request *req, uint8_t type)
1156 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1157 smb_fn_name(type), type, type));
1158 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1159 return;
1162 /****************************************************************************
1163 Reply to an ioctl.
1164 conn POINTER CAN BE NULL HERE !
1165 ****************************************************************************/
1167 void reply_ioctl(struct smb_request *req)
1169 connection_struct *conn = req->conn;
1170 uint16_t device;
1171 uint16_t function;
1172 uint32_t ioctl_code;
1173 int replysize;
1174 char *p;
1176 START_PROFILE(SMBioctl);
1178 if (req->wct < 3) {
1179 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1180 END_PROFILE(SMBioctl);
1181 return;
1184 device = SVAL(req->vwv+1, 0);
1185 function = SVAL(req->vwv+2, 0);
1186 ioctl_code = (device << 16) + function;
1188 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1190 switch (ioctl_code) {
1191 case IOCTL_QUERY_JOB_INFO:
1192 replysize = 32;
1193 break;
1194 default:
1195 reply_force_doserror(req, ERRSRV, ERRnosupport);
1196 END_PROFILE(SMBioctl);
1197 return;
1200 reply_outbuf(req, 8, replysize+1);
1201 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1202 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1203 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1204 p = smb_buf(req->outbuf);
1205 memset(p, '\0', replysize+1); /* valgrind-safe. */
1206 p += 1; /* Allow for alignment */
1208 switch (ioctl_code) {
1209 case IOCTL_QUERY_JOB_INFO:
1211 NTSTATUS status;
1212 size_t len = 0;
1213 files_struct *fsp = file_fsp(
1214 req, SVAL(req->vwv+0, 0));
1215 if (!fsp) {
1216 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1217 END_PROFILE(SMBioctl);
1218 return;
1220 /* Job number */
1221 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1223 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1224 lp_netbios_name(), 15,
1225 STR_TERMINATE|STR_ASCII, &len);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 reply_nterror(req, status);
1228 END_PROFILE(SMBioctl);
1229 return;
1231 if (conn) {
1232 status = srvstr_push((char *)req->outbuf, req->flags2,
1233 p+18,
1234 lp_servicename(talloc_tos(),
1235 SNUM(conn)),
1236 13, STR_TERMINATE|STR_ASCII, &len);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 reply_nterror(req, status);
1239 END_PROFILE(SMBioctl);
1240 return;
1242 } else {
1243 memset(p+18, 0, 13);
1245 break;
1249 END_PROFILE(SMBioctl);
1250 return;
1253 /****************************************************************************
1254 Strange checkpath NTSTATUS mapping.
1255 ****************************************************************************/
1257 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1259 /* Strange DOS error code semantics only for checkpath... */
1260 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1261 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1262 /* We need to map to ERRbadpath */
1263 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1266 return status;
1269 /****************************************************************************
1270 Reply to a checkpath.
1271 ****************************************************************************/
1273 void reply_checkpath(struct smb_request *req)
1275 connection_struct *conn = req->conn;
1276 struct smb_filename *smb_fname = NULL;
1277 char *name = NULL;
1278 NTSTATUS status;
1279 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
1280 TALLOC_CTX *ctx = talloc_tos();
1282 START_PROFILE(SMBcheckpath);
1284 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1285 STR_TERMINATE, &status);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 status = map_checkpath_error(req->flags2, status);
1289 reply_nterror(req, status);
1290 END_PROFILE(SMBcheckpath);
1291 return;
1294 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1296 status = filename_convert(ctx,
1297 conn,
1298 req->flags2 & FLAGS2_DFS_PATHNAMES,
1299 name,
1300 ucf_flags,
1301 NULL,
1302 &smb_fname);
1304 if (!NT_STATUS_IS_OK(status)) {
1305 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1306 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1307 ERRSRV, ERRbadpath);
1308 END_PROFILE(SMBcheckpath);
1309 return;
1311 goto path_err;
1314 if (!VALID_STAT(smb_fname->st) &&
1315 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1316 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1317 smb_fname_str_dbg(smb_fname), strerror(errno)));
1318 status = map_nt_error_from_unix(errno);
1319 goto path_err;
1322 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1323 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1324 ERRDOS, ERRbadpath);
1325 goto out;
1328 reply_outbuf(req, 0, 0);
1330 path_err:
1331 /* We special case this - as when a Windows machine
1332 is parsing a path is steps through the components
1333 one at a time - if a component fails it expects
1334 ERRbadpath, not ERRbadfile.
1336 status = map_checkpath_error(req->flags2, status);
1337 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1339 * Windows returns different error codes if
1340 * the parent directory is valid but not the
1341 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1342 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1343 * if the path is invalid.
1345 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1346 ERRDOS, ERRbadpath);
1347 goto out;
1350 reply_nterror(req, status);
1352 out:
1353 TALLOC_FREE(smb_fname);
1354 END_PROFILE(SMBcheckpath);
1355 return;
1358 /****************************************************************************
1359 Reply to a getatr.
1360 ****************************************************************************/
1362 void reply_getatr(struct smb_request *req)
1364 connection_struct *conn = req->conn;
1365 struct smb_filename *smb_fname = NULL;
1366 char *fname = NULL;
1367 int mode=0;
1368 off_t size=0;
1369 time_t mtime=0;
1370 const char *p;
1371 NTSTATUS status;
1372 TALLOC_CTX *ctx = talloc_tos();
1373 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1375 START_PROFILE(SMBgetatr);
1377 p = (const char *)req->buf + 1;
1378 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 reply_nterror(req, status);
1381 goto out;
1384 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1385 under WfWg - weird! */
1386 if (*fname == '\0') {
1387 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1388 if (!CAN_WRITE(conn)) {
1389 mode |= FILE_ATTRIBUTE_READONLY;
1391 size = 0;
1392 mtime = 0;
1393 } else {
1394 uint32_t ucf_flags = (req->posix_pathnames ?
1395 UCF_POSIX_PATHNAMES : 0);
1396 status = filename_convert(ctx,
1397 conn,
1398 req->flags2 & FLAGS2_DFS_PATHNAMES,
1399 fname,
1400 ucf_flags,
1401 NULL,
1402 &smb_fname);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1405 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1406 ERRSRV, ERRbadpath);
1407 goto out;
1409 reply_nterror(req, status);
1410 goto out;
1412 if (!VALID_STAT(smb_fname->st) &&
1413 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1414 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1415 smb_fname_str_dbg(smb_fname),
1416 strerror(errno)));
1417 reply_nterror(req, map_nt_error_from_unix(errno));
1418 goto out;
1421 mode = dos_mode(conn, smb_fname);
1422 size = smb_fname->st.st_ex_size;
1424 if (ask_sharemode) {
1425 struct timespec write_time_ts;
1426 struct file_id fileid;
1428 ZERO_STRUCT(write_time_ts);
1429 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1430 get_file_infos(fileid, 0, NULL, &write_time_ts);
1431 if (!null_timespec(write_time_ts)) {
1432 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1436 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1437 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1438 size = 0;
1442 reply_outbuf(req, 10, 0);
1444 SSVAL(req->outbuf,smb_vwv0,mode);
1445 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1446 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1447 } else {
1448 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1450 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1452 if (get_Protocol() >= PROTOCOL_NT1) {
1453 SSVAL(req->outbuf, smb_flg2,
1454 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1457 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1458 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1460 out:
1461 TALLOC_FREE(smb_fname);
1462 TALLOC_FREE(fname);
1463 END_PROFILE(SMBgetatr);
1464 return;
1467 /****************************************************************************
1468 Reply to a setatr.
1469 ****************************************************************************/
1471 void reply_setatr(struct smb_request *req)
1473 struct smb_file_time ft;
1474 connection_struct *conn = req->conn;
1475 struct smb_filename *smb_fname = NULL;
1476 char *fname = NULL;
1477 int mode;
1478 time_t mtime;
1479 const char *p;
1480 NTSTATUS status;
1481 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
1482 TALLOC_CTX *ctx = talloc_tos();
1484 START_PROFILE(SMBsetatr);
1486 ZERO_STRUCT(ft);
1488 if (req->wct < 2) {
1489 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1490 goto out;
1493 p = (const char *)req->buf + 1;
1494 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1495 if (!NT_STATUS_IS_OK(status)) {
1496 reply_nterror(req, status);
1497 goto out;
1500 status = filename_convert(ctx,
1501 conn,
1502 req->flags2 & FLAGS2_DFS_PATHNAMES,
1503 fname,
1504 ucf_flags,
1505 NULL,
1506 &smb_fname);
1507 if (!NT_STATUS_IS_OK(status)) {
1508 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1509 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1510 ERRSRV, ERRbadpath);
1511 goto out;
1513 reply_nterror(req, status);
1514 goto out;
1517 if (smb_fname->base_name[0] == '.' &&
1518 smb_fname->base_name[1] == '\0') {
1520 * Not sure here is the right place to catch this
1521 * condition. Might be moved to somewhere else later -- vl
1523 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1524 goto out;
1527 mode = SVAL(req->vwv+0, 0);
1528 mtime = srv_make_unix_date3(req->vwv+1);
1530 if (mode != FILE_ATTRIBUTE_NORMAL) {
1531 if (VALID_STAT_OF_DIR(smb_fname->st))
1532 mode |= FILE_ATTRIBUTE_DIRECTORY;
1533 else
1534 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1536 status = check_access(conn, NULL, smb_fname,
1537 FILE_WRITE_ATTRIBUTES);
1538 if (!NT_STATUS_IS_OK(status)) {
1539 reply_nterror(req, status);
1540 goto out;
1543 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1544 false) != 0) {
1545 reply_nterror(req, map_nt_error_from_unix(errno));
1546 goto out;
1550 ft.mtime = convert_time_t_to_timespec(mtime);
1551 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1552 if (!NT_STATUS_IS_OK(status)) {
1553 reply_nterror(req, status);
1554 goto out;
1557 reply_outbuf(req, 0, 0);
1559 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1560 mode));
1561 out:
1562 TALLOC_FREE(smb_fname);
1563 END_PROFILE(SMBsetatr);
1564 return;
1567 /****************************************************************************
1568 Reply to a dskattr.
1569 ****************************************************************************/
1571 void reply_dskattr(struct smb_request *req)
1573 connection_struct *conn = req->conn;
1574 uint64_t ret;
1575 uint64_t dfree,dsize,bsize;
1576 struct smb_filename smb_fname;
1577 START_PROFILE(SMBdskattr);
1579 ZERO_STRUCT(smb_fname);
1580 smb_fname.base_name = discard_const_p(char, ".");
1582 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1583 reply_nterror(req, map_nt_error_from_unix(errno));
1584 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1585 END_PROFILE(SMBdskattr);
1586 return;
1589 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1590 if (ret == (uint64_t)-1) {
1591 reply_nterror(req, map_nt_error_from_unix(errno));
1592 END_PROFILE(SMBdskattr);
1593 return;
1597 * Force max to fit in 16 bit fields.
1599 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1600 dfree /= 2;
1601 dsize /= 2;
1602 bsize *= 2;
1603 if (bsize > (WORDMAX*512)) {
1604 bsize = (WORDMAX*512);
1605 if (dsize > WORDMAX)
1606 dsize = WORDMAX;
1607 if (dfree > WORDMAX)
1608 dfree = WORDMAX;
1609 break;
1613 reply_outbuf(req, 5, 0);
1615 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1616 double total_space, free_space;
1617 /* we need to scale this to a number that DOS6 can handle. We
1618 use floating point so we can handle large drives on systems
1619 that don't have 64 bit integers
1621 we end up displaying a maximum of 2G to DOS systems
1623 total_space = dsize * (double)bsize;
1624 free_space = dfree * (double)bsize;
1626 dsize = (uint64_t)((total_space+63*512) / (64*512));
1627 dfree = (uint64_t)((free_space+63*512) / (64*512));
1629 if (dsize > 0xFFFF) dsize = 0xFFFF;
1630 if (dfree > 0xFFFF) dfree = 0xFFFF;
1632 SSVAL(req->outbuf,smb_vwv0,dsize);
1633 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1634 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1635 SSVAL(req->outbuf,smb_vwv3,dfree);
1636 } else {
1637 SSVAL(req->outbuf,smb_vwv0,dsize);
1638 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1639 SSVAL(req->outbuf,smb_vwv2,512);
1640 SSVAL(req->outbuf,smb_vwv3,dfree);
1643 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1645 END_PROFILE(SMBdskattr);
1646 return;
1650 * Utility function to split the filename from the directory.
1652 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1653 char **fname_dir_out,
1654 char **fname_mask_out)
1656 const char *p = NULL;
1657 char *fname_dir = NULL;
1658 char *fname_mask = NULL;
1660 p = strrchr_m(fname_in, '/');
1661 if (!p) {
1662 fname_dir = talloc_strdup(ctx, ".");
1663 fname_mask = talloc_strdup(ctx, fname_in);
1664 } else {
1665 fname_dir = talloc_strndup(ctx, fname_in,
1666 PTR_DIFF(p, fname_in));
1667 fname_mask = talloc_strdup(ctx, p+1);
1670 if (!fname_dir || !fname_mask) {
1671 TALLOC_FREE(fname_dir);
1672 TALLOC_FREE(fname_mask);
1673 return NT_STATUS_NO_MEMORY;
1676 *fname_dir_out = fname_dir;
1677 *fname_mask_out = fname_mask;
1678 return NT_STATUS_OK;
1681 /****************************************************************************
1682 Make a dir struct.
1683 ****************************************************************************/
1685 static bool make_dir_struct(TALLOC_CTX *ctx,
1686 char *buf,
1687 const char *mask,
1688 const char *fname,
1689 off_t size,
1690 uint32_t mode,
1691 time_t date,
1692 bool uc)
1694 char *p;
1695 char *mask2 = talloc_strdup(ctx, mask);
1697 if (!mask2) {
1698 return False;
1701 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1702 size = 0;
1705 memset(buf+1,' ',11);
1706 if ((p = strchr_m(mask2,'.')) != NULL) {
1707 *p = 0;
1708 push_ascii(buf+1,mask2,8, 0);
1709 push_ascii(buf+9,p+1,3, 0);
1710 *p = '.';
1711 } else {
1712 push_ascii(buf+1,mask2,11, 0);
1715 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1716 SCVAL(buf,21,mode);
1717 srv_put_dos_date(buf,22,date);
1718 SSVAL(buf,26,size & 0xFFFF);
1719 SSVAL(buf,28,(size >> 16)&0xFFFF);
1720 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1721 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1722 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1723 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1724 return True;
1727 /****************************************************************************
1728 Reply to a search.
1729 Can be called from SMBsearch, SMBffirst or SMBfunique.
1730 ****************************************************************************/
1732 void reply_search(struct smb_request *req)
1734 connection_struct *conn = req->conn;
1735 char *path = NULL;
1736 char *mask = NULL;
1737 char *directory = NULL;
1738 struct smb_filename *smb_fname = NULL;
1739 char *fname = NULL;
1740 off_t size;
1741 uint32_t mode;
1742 struct timespec date;
1743 uint32_t dirtype;
1744 unsigned int numentries = 0;
1745 unsigned int maxentries = 0;
1746 bool finished = False;
1747 const char *p;
1748 int status_len;
1749 char status[21];
1750 int dptr_num= -1;
1751 bool check_descend = False;
1752 bool expect_close = False;
1753 NTSTATUS nt_status;
1754 bool mask_contains_wcard = False;
1755 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1756 TALLOC_CTX *ctx = talloc_tos();
1757 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1758 struct dptr_struct *dirptr = NULL;
1759 struct smbXsrv_connection *xconn = req->xconn;
1760 struct smbd_server_connection *sconn = req->sconn;
1762 START_PROFILE(SMBsearch);
1764 if (req->wct < 2) {
1765 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1766 goto out;
1769 if (req->posix_pathnames) {
1770 reply_unknown_new(req, req->cmd);
1771 goto out;
1774 /* If we were called as SMBffirst then we must expect close. */
1775 if(req->cmd == SMBffirst) {
1776 expect_close = True;
1779 reply_outbuf(req, 1, 3);
1780 maxentries = SVAL(req->vwv+0, 0);
1781 dirtype = SVAL(req->vwv+1, 0);
1782 p = (const char *)req->buf + 1;
1783 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1784 &nt_status, &mask_contains_wcard);
1785 if (!NT_STATUS_IS_OK(nt_status)) {
1786 reply_nterror(req, nt_status);
1787 goto out;
1790 p++;
1791 status_len = SVAL(p, 0);
1792 p += 2;
1794 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1796 if (status_len == 0) {
1797 struct smb_filename *smb_dname = NULL;
1798 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1799 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
1800 nt_status = filename_convert(ctx, conn,
1801 req->flags2 & FLAGS2_DFS_PATHNAMES,
1802 path,
1803 ucf_flags,
1804 &mask_contains_wcard,
1805 &smb_fname);
1806 if (!NT_STATUS_IS_OK(nt_status)) {
1807 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1808 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1809 ERRSRV, ERRbadpath);
1810 goto out;
1812 reply_nterror(req, nt_status);
1813 goto out;
1816 directory = smb_fname->base_name;
1818 p = strrchr_m(directory,'/');
1819 if ((p != NULL) && (*directory != '/')) {
1820 mask = talloc_strdup(ctx, p + 1);
1821 directory = talloc_strndup(ctx, directory,
1822 PTR_DIFF(p, directory));
1823 } else {
1824 mask = talloc_strdup(ctx, directory);
1825 directory = talloc_strdup(ctx,".");
1828 if (!directory) {
1829 reply_nterror(req, NT_STATUS_NO_MEMORY);
1830 goto out;
1833 memset((char *)status,'\0',21);
1834 SCVAL(status,0,(dirtype & 0x1F));
1836 smb_dname = synthetic_smb_fname(talloc_tos(),
1837 directory,
1838 NULL,
1839 NULL,
1840 smb_fname->flags);
1841 if (smb_dname == NULL) {
1842 reply_nterror(req, NT_STATUS_NO_MEMORY);
1843 goto out;
1846 nt_status = dptr_create(conn,
1847 NULL, /* req */
1848 NULL, /* fsp */
1849 smb_dname,
1850 True,
1851 expect_close,
1852 req->smbpid,
1853 mask,
1854 mask_contains_wcard,
1855 dirtype,
1856 &dirptr);
1858 TALLOC_FREE(smb_dname);
1860 if (!NT_STATUS_IS_OK(nt_status)) {
1861 reply_nterror(req, nt_status);
1862 goto out;
1864 dptr_num = dptr_dnum(dirptr);
1865 } else {
1866 int status_dirtype;
1867 const char *dirpath;
1869 memcpy(status,p,21);
1870 status_dirtype = CVAL(status,0) & 0x1F;
1871 if (status_dirtype != (dirtype & 0x1F)) {
1872 dirtype = status_dirtype;
1875 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1876 if (!dirptr) {
1877 goto SearchEmpty;
1879 dirpath = dptr_path(sconn, dptr_num);
1880 directory = talloc_strdup(ctx, dirpath);
1881 if (!directory) {
1882 reply_nterror(req, NT_STATUS_NO_MEMORY);
1883 goto out;
1886 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1887 if (!mask) {
1888 goto SearchEmpty;
1891 * For a 'continue' search we have no string. So
1892 * check from the initial saved string.
1894 if (!req->posix_pathnames) {
1895 mask_contains_wcard = ms_has_wild(mask);
1897 dirtype = dptr_attr(sconn, dptr_num);
1900 DEBUG(4,("dptr_num is %d\n",dptr_num));
1902 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1903 dptr_init_search_op(dirptr);
1905 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1906 char buf[DIR_STRUCT_SIZE];
1907 memcpy(buf,status,21);
1908 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1909 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1910 reply_nterror(req, NT_STATUS_NO_MEMORY);
1911 goto out;
1913 dptr_fill(sconn, buf+12,dptr_num);
1914 if (dptr_zero(buf+12) && (status_len==0)) {
1915 numentries = 1;
1916 } else {
1917 numentries = 0;
1919 if (message_push_blob(&req->outbuf,
1920 data_blob_const(buf, sizeof(buf)))
1921 == -1) {
1922 reply_nterror(req, NT_STATUS_NO_MEMORY);
1923 goto out;
1925 } else {
1926 unsigned int i;
1927 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1928 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1930 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1932 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1933 directory,lp_dont_descend(ctx, SNUM(conn))));
1934 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1935 check_descend = True;
1938 for (i=numentries;(i<maxentries) && !finished;i++) {
1939 finished = !get_dir_entry(ctx,
1940 dirptr,
1941 mask,
1942 dirtype,
1943 &fname,
1944 &size,
1945 &mode,
1946 &date,
1947 check_descend,
1948 ask_sharemode);
1949 if (!finished) {
1950 char buf[DIR_STRUCT_SIZE];
1951 memcpy(buf,status,21);
1952 if (!make_dir_struct(ctx,
1953 buf,
1954 mask,
1955 fname,
1956 size,
1957 mode,
1958 convert_timespec_to_time_t(date),
1959 !allow_long_path_components)) {
1960 reply_nterror(req, NT_STATUS_NO_MEMORY);
1961 goto out;
1963 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1964 break;
1966 if (message_push_blob(&req->outbuf,
1967 data_blob_const(buf, sizeof(buf)))
1968 == -1) {
1969 reply_nterror(req, NT_STATUS_NO_MEMORY);
1970 goto out;
1972 numentries++;
1977 SearchEmpty:
1979 /* If we were called as SMBffirst with smb_search_id == NULL
1980 and no entries were found then return error and close dirptr
1981 (X/Open spec) */
1983 if (numentries == 0) {
1984 dptr_close(sconn, &dptr_num);
1985 } else if(expect_close && status_len == 0) {
1986 /* Close the dptr - we know it's gone */
1987 dptr_close(sconn, &dptr_num);
1990 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1991 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1992 dptr_close(sconn, &dptr_num);
1995 if ((numentries == 0) && !mask_contains_wcard) {
1996 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1997 goto out;
2000 SSVAL(req->outbuf,smb_vwv0,numentries);
2001 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2002 SCVAL(smb_buf(req->outbuf),0,5);
2003 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2005 /* The replies here are never long name. */
2006 SSVAL(req->outbuf, smb_flg2,
2007 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2008 if (!allow_long_path_components) {
2009 SSVAL(req->outbuf, smb_flg2,
2010 SVAL(req->outbuf, smb_flg2)
2011 & (~FLAGS2_LONG_PATH_COMPONENTS));
2014 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2015 SSVAL(req->outbuf, smb_flg2,
2016 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2018 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2019 smb_fn_name(req->cmd),
2020 mask,
2021 directory,
2022 dirtype,
2023 numentries,
2024 maxentries ));
2025 out:
2026 TALLOC_FREE(directory);
2027 TALLOC_FREE(mask);
2028 TALLOC_FREE(smb_fname);
2029 END_PROFILE(SMBsearch);
2030 return;
2033 /****************************************************************************
2034 Reply to a fclose (stop directory search).
2035 ****************************************************************************/
2037 void reply_fclose(struct smb_request *req)
2039 int status_len;
2040 char status[21];
2041 int dptr_num= -2;
2042 const char *p;
2043 char *path = NULL;
2044 NTSTATUS err;
2045 bool path_contains_wcard = False;
2046 TALLOC_CTX *ctx = talloc_tos();
2047 struct smbd_server_connection *sconn = req->sconn;
2049 START_PROFILE(SMBfclose);
2051 if (req->posix_pathnames) {
2052 reply_unknown_new(req, req->cmd);
2053 END_PROFILE(SMBfclose);
2054 return;
2057 p = (const char *)req->buf + 1;
2058 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2059 &err, &path_contains_wcard);
2060 if (!NT_STATUS_IS_OK(err)) {
2061 reply_nterror(req, err);
2062 END_PROFILE(SMBfclose);
2063 return;
2065 p++;
2066 status_len = SVAL(p,0);
2067 p += 2;
2069 if (status_len == 0) {
2070 reply_force_doserror(req, ERRSRV, ERRsrverror);
2071 END_PROFILE(SMBfclose);
2072 return;
2075 memcpy(status,p,21);
2077 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2078 /* Close the dptr - we know it's gone */
2079 dptr_close(sconn, &dptr_num);
2082 reply_outbuf(req, 1, 0);
2083 SSVAL(req->outbuf,smb_vwv0,0);
2085 DEBUG(3,("search close\n"));
2087 END_PROFILE(SMBfclose);
2088 return;
2091 /****************************************************************************
2092 Reply to an open.
2093 ****************************************************************************/
2095 void reply_open(struct smb_request *req)
2097 connection_struct *conn = req->conn;
2098 struct smb_filename *smb_fname = NULL;
2099 char *fname = NULL;
2100 uint32_t fattr=0;
2101 off_t size = 0;
2102 time_t mtime=0;
2103 int info;
2104 files_struct *fsp;
2105 int oplock_request;
2106 int deny_mode;
2107 uint32_t dos_attr;
2108 uint32_t access_mask;
2109 uint32_t share_mode;
2110 uint32_t create_disposition;
2111 uint32_t create_options = 0;
2112 uint32_t private_flags = 0;
2113 NTSTATUS status;
2114 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2115 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2116 TALLOC_CTX *ctx = talloc_tos();
2118 START_PROFILE(SMBopen);
2120 if (req->wct < 2) {
2121 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2122 goto out;
2125 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2126 deny_mode = SVAL(req->vwv+0, 0);
2127 dos_attr = SVAL(req->vwv+1, 0);
2129 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2130 STR_TERMINATE, &status);
2131 if (!NT_STATUS_IS_OK(status)) {
2132 reply_nterror(req, status);
2133 goto out;
2136 if (!map_open_params_to_ntcreate(fname, deny_mode,
2137 OPENX_FILE_EXISTS_OPEN, &access_mask,
2138 &share_mode, &create_disposition,
2139 &create_options, &private_flags)) {
2140 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2141 goto out;
2144 status = filename_convert(ctx,
2145 conn,
2146 req->flags2 & FLAGS2_DFS_PATHNAMES,
2147 fname,
2148 ucf_flags,
2149 NULL,
2150 &smb_fname);
2151 if (!NT_STATUS_IS_OK(status)) {
2152 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2153 reply_botherror(req,
2154 NT_STATUS_PATH_NOT_COVERED,
2155 ERRSRV, ERRbadpath);
2156 goto out;
2158 reply_nterror(req, status);
2159 goto out;
2162 status = SMB_VFS_CREATE_FILE(
2163 conn, /* conn */
2164 req, /* req */
2165 0, /* root_dir_fid */
2166 smb_fname, /* fname */
2167 access_mask, /* access_mask */
2168 share_mode, /* share_access */
2169 create_disposition, /* create_disposition*/
2170 create_options, /* create_options */
2171 dos_attr, /* file_attributes */
2172 oplock_request, /* oplock_request */
2173 NULL, /* lease */
2174 0, /* allocation_size */
2175 private_flags,
2176 NULL, /* sd */
2177 NULL, /* ea_list */
2178 &fsp, /* result */
2179 &info, /* pinfo */
2180 NULL, NULL); /* create context */
2182 if (!NT_STATUS_IS_OK(status)) {
2183 if (open_was_deferred(req->xconn, req->mid)) {
2184 /* We have re-scheduled this call. */
2185 goto out;
2187 reply_openerror(req, status);
2188 goto out;
2191 /* Ensure we're pointing at the correct stat struct. */
2192 TALLOC_FREE(smb_fname);
2193 smb_fname = fsp->fsp_name;
2195 size = smb_fname->st.st_ex_size;
2196 fattr = dos_mode(conn, smb_fname);
2198 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2200 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2201 DEBUG(3,("attempt to open a directory %s\n",
2202 fsp_str_dbg(fsp)));
2203 close_file(req, fsp, ERROR_CLOSE);
2204 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2205 ERRDOS, ERRnoaccess);
2206 goto out;
2209 reply_outbuf(req, 7, 0);
2210 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2211 SSVAL(req->outbuf,smb_vwv1,fattr);
2212 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2213 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2214 } else {
2215 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2217 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2218 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2220 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2221 SCVAL(req->outbuf,smb_flg,
2222 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2225 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2226 SCVAL(req->outbuf,smb_flg,
2227 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2229 out:
2230 END_PROFILE(SMBopen);
2231 return;
2234 /****************************************************************************
2235 Reply to an open and X.
2236 ****************************************************************************/
2238 void reply_open_and_X(struct smb_request *req)
2240 connection_struct *conn = req->conn;
2241 struct smb_filename *smb_fname = NULL;
2242 char *fname = NULL;
2243 uint16_t open_flags;
2244 int deny_mode;
2245 uint32_t smb_attr;
2246 /* Breakout the oplock request bits so we can set the
2247 reply bits separately. */
2248 int ex_oplock_request;
2249 int core_oplock_request;
2250 int oplock_request;
2251 #if 0
2252 int smb_sattr = SVAL(req->vwv+4, 0);
2253 uint32_t smb_time = make_unix_date3(req->vwv+6);
2254 #endif
2255 int smb_ofun;
2256 uint32_t fattr=0;
2257 int mtime=0;
2258 int smb_action = 0;
2259 files_struct *fsp;
2260 NTSTATUS status;
2261 uint64_t allocation_size;
2262 ssize_t retval = -1;
2263 uint32_t access_mask;
2264 uint32_t share_mode;
2265 uint32_t create_disposition;
2266 uint32_t create_options = 0;
2267 uint32_t private_flags = 0;
2268 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2269 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2270 TALLOC_CTX *ctx = talloc_tos();
2272 START_PROFILE(SMBopenX);
2274 if (req->wct < 15) {
2275 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2276 goto out;
2279 open_flags = SVAL(req->vwv+2, 0);
2280 deny_mode = SVAL(req->vwv+3, 0);
2281 smb_attr = SVAL(req->vwv+5, 0);
2282 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2283 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2284 oplock_request = ex_oplock_request | core_oplock_request;
2285 smb_ofun = SVAL(req->vwv+8, 0);
2286 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2288 /* If it's an IPC, pass off the pipe handler. */
2289 if (IS_IPC(conn)) {
2290 if (lp_nt_pipe_support()) {
2291 reply_open_pipe_and_X(conn, req);
2292 } else {
2293 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2295 goto out;
2298 /* XXXX we need to handle passed times, sattr and flags */
2299 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2300 STR_TERMINATE, &status);
2301 if (!NT_STATUS_IS_OK(status)) {
2302 reply_nterror(req, status);
2303 goto out;
2306 if (!map_open_params_to_ntcreate(fname, deny_mode,
2307 smb_ofun,
2308 &access_mask, &share_mode,
2309 &create_disposition,
2310 &create_options,
2311 &private_flags)) {
2312 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2313 goto out;
2316 status = filename_convert(ctx,
2317 conn,
2318 req->flags2 & FLAGS2_DFS_PATHNAMES,
2319 fname,
2320 ucf_flags,
2321 NULL,
2322 &smb_fname);
2323 if (!NT_STATUS_IS_OK(status)) {
2324 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2325 reply_botherror(req,
2326 NT_STATUS_PATH_NOT_COVERED,
2327 ERRSRV, ERRbadpath);
2328 goto out;
2330 reply_nterror(req, status);
2331 goto out;
2334 status = SMB_VFS_CREATE_FILE(
2335 conn, /* conn */
2336 req, /* req */
2337 0, /* root_dir_fid */
2338 smb_fname, /* fname */
2339 access_mask, /* access_mask */
2340 share_mode, /* share_access */
2341 create_disposition, /* create_disposition*/
2342 create_options, /* create_options */
2343 smb_attr, /* file_attributes */
2344 oplock_request, /* oplock_request */
2345 NULL, /* lease */
2346 0, /* allocation_size */
2347 private_flags,
2348 NULL, /* sd */
2349 NULL, /* ea_list */
2350 &fsp, /* result */
2351 &smb_action, /* pinfo */
2352 NULL, NULL); /* create context */
2354 if (!NT_STATUS_IS_OK(status)) {
2355 if (open_was_deferred(req->xconn, req->mid)) {
2356 /* We have re-scheduled this call. */
2357 goto out;
2359 reply_openerror(req, status);
2360 goto out;
2363 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2364 if the file is truncated or created. */
2365 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2366 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2367 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2368 close_file(req, fsp, ERROR_CLOSE);
2369 reply_nterror(req, NT_STATUS_DISK_FULL);
2370 goto out;
2372 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2373 if (retval < 0) {
2374 close_file(req, fsp, ERROR_CLOSE);
2375 reply_nterror(req, NT_STATUS_DISK_FULL);
2376 goto out;
2378 status = vfs_stat_fsp(fsp);
2379 if (!NT_STATUS_IS_OK(status)) {
2380 close_file(req, fsp, ERROR_CLOSE);
2381 reply_nterror(req, status);
2382 goto out;
2386 fattr = dos_mode(conn, fsp->fsp_name);
2387 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2388 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2389 close_file(req, fsp, ERROR_CLOSE);
2390 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2391 goto out;
2394 /* If the caller set the extended oplock request bit
2395 and we granted one (by whatever means) - set the
2396 correct bit for extended oplock reply.
2399 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2400 smb_action |= EXTENDED_OPLOCK_GRANTED;
2403 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2404 smb_action |= EXTENDED_OPLOCK_GRANTED;
2407 /* If the caller set the core oplock request bit
2408 and we granted one (by whatever means) - set the
2409 correct bit for core oplock reply.
2412 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2413 reply_outbuf(req, 19, 0);
2414 } else {
2415 reply_outbuf(req, 15, 0);
2418 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2419 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2421 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2422 SCVAL(req->outbuf, smb_flg,
2423 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2426 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2427 SCVAL(req->outbuf, smb_flg,
2428 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2431 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2432 SSVAL(req->outbuf,smb_vwv3,fattr);
2433 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2434 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2435 } else {
2436 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2438 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2439 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2440 SSVAL(req->outbuf,smb_vwv11,smb_action);
2442 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2443 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2446 out:
2447 TALLOC_FREE(smb_fname);
2448 END_PROFILE(SMBopenX);
2449 return;
2452 /****************************************************************************
2453 Reply to a SMBulogoffX.
2454 ****************************************************************************/
2456 void reply_ulogoffX(struct smb_request *req)
2458 struct smbd_server_connection *sconn = req->sconn;
2459 struct user_struct *vuser;
2460 struct smbXsrv_session *session = NULL;
2461 NTSTATUS status;
2463 START_PROFILE(SMBulogoffX);
2465 vuser = get_valid_user_struct(sconn, req->vuid);
2467 if(vuser == NULL) {
2468 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2469 (unsigned long long)req->vuid));
2471 req->vuid = UID_FIELD_INVALID;
2472 reply_force_doserror(req, ERRSRV, ERRbaduid);
2473 END_PROFILE(SMBulogoffX);
2474 return;
2477 session = vuser->session;
2478 vuser = NULL;
2481 * TODO: cancel all outstanding requests on the session
2483 status = smbXsrv_session_logoff(session);
2484 if (!NT_STATUS_IS_OK(status)) {
2485 DEBUG(0, ("reply_ulogoff: "
2486 "smbXsrv_session_logoff() failed: %s\n",
2487 nt_errstr(status)));
2489 * If we hit this case, there is something completely
2490 * wrong, so we better disconnect the transport connection.
2492 END_PROFILE(SMBulogoffX);
2493 exit_server(__location__ ": smbXsrv_session_logoff failed");
2494 return;
2497 TALLOC_FREE(session);
2499 reply_outbuf(req, 2, 0);
2500 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2501 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2503 DEBUG(3, ("ulogoffX vuid=%llu\n",
2504 (unsigned long long)req->vuid));
2506 END_PROFILE(SMBulogoffX);
2507 req->vuid = UID_FIELD_INVALID;
2510 /****************************************************************************
2511 Reply to a mknew or a create.
2512 ****************************************************************************/
2514 void reply_mknew(struct smb_request *req)
2516 connection_struct *conn = req->conn;
2517 struct smb_filename *smb_fname = NULL;
2518 char *fname = NULL;
2519 uint32_t fattr = 0;
2520 struct smb_file_time ft;
2521 files_struct *fsp;
2522 int oplock_request = 0;
2523 NTSTATUS status;
2524 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2525 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2526 uint32_t create_disposition;
2527 uint32_t create_options = 0;
2528 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2529 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2530 TALLOC_CTX *ctx = talloc_tos();
2532 START_PROFILE(SMBcreate);
2533 ZERO_STRUCT(ft);
2535 if (req->wct < 3) {
2536 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2537 goto out;
2540 fattr = SVAL(req->vwv+0, 0);
2541 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2543 /* mtime. */
2544 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2546 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2547 STR_TERMINATE, &status);
2548 if (!NT_STATUS_IS_OK(status)) {
2549 reply_nterror(req, status);
2550 goto out;
2553 status = filename_convert(ctx,
2554 conn,
2555 req->flags2 & FLAGS2_DFS_PATHNAMES,
2556 fname,
2557 ucf_flags,
2558 NULL,
2559 &smb_fname);
2560 if (!NT_STATUS_IS_OK(status)) {
2561 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2562 reply_botherror(req,
2563 NT_STATUS_PATH_NOT_COVERED,
2564 ERRSRV, ERRbadpath);
2565 goto out;
2567 reply_nterror(req, status);
2568 goto out;
2571 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2572 DEBUG(0,("Attempt to create file (%s) with volid set - "
2573 "please report this\n",
2574 smb_fname_str_dbg(smb_fname)));
2577 if(req->cmd == SMBmknew) {
2578 /* We should fail if file exists. */
2579 create_disposition = FILE_CREATE;
2580 } else {
2581 /* Create if file doesn't exist, truncate if it does. */
2582 create_disposition = FILE_OVERWRITE_IF;
2585 status = SMB_VFS_CREATE_FILE(
2586 conn, /* conn */
2587 req, /* req */
2588 0, /* root_dir_fid */
2589 smb_fname, /* fname */
2590 access_mask, /* access_mask */
2591 share_mode, /* share_access */
2592 create_disposition, /* create_disposition*/
2593 create_options, /* create_options */
2594 fattr, /* file_attributes */
2595 oplock_request, /* oplock_request */
2596 NULL, /* lease */
2597 0, /* allocation_size */
2598 0, /* private_flags */
2599 NULL, /* sd */
2600 NULL, /* ea_list */
2601 &fsp, /* result */
2602 NULL, /* pinfo */
2603 NULL, NULL); /* create context */
2605 if (!NT_STATUS_IS_OK(status)) {
2606 if (open_was_deferred(req->xconn, req->mid)) {
2607 /* We have re-scheduled this call. */
2608 goto out;
2610 reply_openerror(req, status);
2611 goto out;
2614 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2615 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2616 if (!NT_STATUS_IS_OK(status)) {
2617 END_PROFILE(SMBcreate);
2618 goto out;
2621 reply_outbuf(req, 1, 0);
2622 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2624 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2625 SCVAL(req->outbuf,smb_flg,
2626 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2629 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2630 SCVAL(req->outbuf,smb_flg,
2631 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2634 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2635 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2636 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2637 (unsigned int)fattr));
2639 out:
2640 TALLOC_FREE(smb_fname);
2641 END_PROFILE(SMBcreate);
2642 return;
2645 /****************************************************************************
2646 Reply to a create temporary file.
2647 ****************************************************************************/
2649 void reply_ctemp(struct smb_request *req)
2651 connection_struct *conn = req->conn;
2652 struct smb_filename *smb_fname = NULL;
2653 char *wire_name = NULL;
2654 char *fname = NULL;
2655 uint32_t fattr;
2656 files_struct *fsp;
2657 int oplock_request;
2658 char *s;
2659 NTSTATUS status;
2660 int i;
2661 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2662 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
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 status = filename_convert(ctx, conn,
2700 req->flags2 & FLAGS2_DFS_PATHNAMES,
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->base_name);
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 status = check_name(conn, fname_dir);
3096 if (!NT_STATUS_IS_OK(status)) {
3097 goto out;
3100 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3101 fname_dir,
3102 NULL,
3103 NULL,
3104 smb_fname->flags);
3105 if (smb_fname_dir == NULL) {
3106 status = NT_STATUS_NO_MEMORY;
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->base_name);
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 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
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 req->flags2 & FLAGS2_DFS_PATHNAMES,
3241 name,
3242 ucf_flags,
3243 &path_contains_wcard,
3244 &smb_fname);
3245 if (!NT_STATUS_IS_OK(status)) {
3246 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3247 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3248 ERRSRV, ERRbadpath);
3249 goto out;
3251 reply_nterror(req, status);
3252 goto out;
3255 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3257 status = unlink_internals(conn, req, dirtype, smb_fname,
3258 path_contains_wcard);
3259 if (!NT_STATUS_IS_OK(status)) {
3260 if (open_was_deferred(req->xconn, req->mid)) {
3261 /* We have re-scheduled this call. */
3262 goto out;
3264 reply_nterror(req, status);
3265 goto out;
3268 reply_outbuf(req, 0, 0);
3269 out:
3270 TALLOC_FREE(smb_fname);
3271 END_PROFILE(SMBunlink);
3272 return;
3275 /****************************************************************************
3276 Fail for readbraw.
3277 ****************************************************************************/
3279 static void fail_readraw(void)
3281 const char *errstr = talloc_asprintf(talloc_tos(),
3282 "FAIL ! reply_readbraw: socket write fail (%s)",
3283 strerror(errno));
3284 if (!errstr) {
3285 errstr = "";
3287 exit_server_cleanly(errstr);
3290 /****************************************************************************
3291 Fake (read/write) sendfile. Returns -1 on read or write fail.
3292 ****************************************************************************/
3294 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3295 off_t startpos, size_t nread)
3297 size_t bufsize;
3298 size_t tosend = nread;
3299 char *buf;
3301 if (nread == 0) {
3302 return 0;
3305 bufsize = MIN(nread, 65536);
3307 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3308 return -1;
3311 while (tosend > 0) {
3312 ssize_t ret;
3313 size_t cur_read;
3315 cur_read = MIN(tosend, bufsize);
3316 ret = read_file(fsp,buf,startpos,cur_read);
3317 if (ret == -1) {
3318 SAFE_FREE(buf);
3319 return -1;
3322 /* If we had a short read, fill with zeros. */
3323 if (ret < cur_read) {
3324 memset(buf + ret, '\0', cur_read - ret);
3327 ret = write_data(xconn->transport.sock, buf, cur_read);
3328 if (ret != cur_read) {
3329 int saved_errno = errno;
3331 * Try and give an error message saying what
3332 * client failed.
3334 DEBUG(0, ("write_data failed for client %s. "
3335 "Error %s\n",
3336 smbXsrv_connection_dbg(xconn),
3337 strerror(saved_errno)));
3338 SAFE_FREE(buf);
3339 errno = saved_errno;
3340 return -1;
3342 tosend -= cur_read;
3343 startpos += cur_read;
3346 SAFE_FREE(buf);
3347 return (ssize_t)nread;
3350 /****************************************************************************
3351 Deal with the case of sendfile reading less bytes from the file than
3352 requested. Fill with zeros (all we can do). Returns 0 on success
3353 ****************************************************************************/
3355 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3356 files_struct *fsp,
3357 ssize_t nread,
3358 size_t headersize,
3359 size_t smb_maxcnt)
3361 #define SHORT_SEND_BUFSIZE 1024
3362 if (nread < headersize) {
3363 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3364 "header for file %s (%s). Terminating\n",
3365 fsp_str_dbg(fsp), strerror(errno)));
3366 return -1;
3369 nread -= headersize;
3371 if (nread < smb_maxcnt) {
3372 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3373 if (!buf) {
3374 DEBUG(0,("sendfile_short_send: malloc failed "
3375 "for file %s (%s). Terminating\n",
3376 fsp_str_dbg(fsp), strerror(errno)));
3377 return -1;
3380 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3381 "with zeros !\n", fsp_str_dbg(fsp)));
3383 while (nread < smb_maxcnt) {
3385 * We asked for the real file size and told sendfile
3386 * to not go beyond the end of the file. But it can
3387 * happen that in between our fstat call and the
3388 * sendfile call the file was truncated. This is very
3389 * bad because we have already announced the larger
3390 * number of bytes to the client.
3392 * The best we can do now is to send 0-bytes, just as
3393 * a read from a hole in a sparse file would do.
3395 * This should happen rarely enough that I don't care
3396 * about efficiency here :-)
3398 size_t to_write;
3399 ssize_t ret;
3401 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3402 ret = write_data(xconn->transport.sock, buf, to_write);
3403 if (ret != to_write) {
3404 int saved_errno = errno;
3406 * Try and give an error message saying what
3407 * client failed.
3409 DEBUG(0, ("write_data failed for client %s. "
3410 "Error %s\n",
3411 smbXsrv_connection_dbg(xconn),
3412 strerror(saved_errno)));
3413 errno = saved_errno;
3414 return -1;
3416 nread += to_write;
3418 SAFE_FREE(buf);
3421 return 0;
3424 /****************************************************************************
3425 Return a readbraw error (4 bytes of zero).
3426 ****************************************************************************/
3428 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3430 char header[4];
3432 SIVAL(header,0,0);
3434 smbd_lock_socket(xconn);
3435 if (write_data(xconn->transport.sock,header,4) != 4) {
3436 int saved_errno = errno;
3438 * Try and give an error message saying what
3439 * client failed.
3441 DEBUG(0, ("write_data failed for client %s. "
3442 "Error %s\n",
3443 smbXsrv_connection_dbg(xconn),
3444 strerror(saved_errno)));
3445 errno = saved_errno;
3447 fail_readraw();
3449 smbd_unlock_socket(xconn);
3452 /****************************************************************************
3453 Use sendfile in readbraw.
3454 ****************************************************************************/
3456 static void send_file_readbraw(connection_struct *conn,
3457 struct smb_request *req,
3458 files_struct *fsp,
3459 off_t startpos,
3460 size_t nread,
3461 ssize_t mincount)
3463 struct smbXsrv_connection *xconn = req->xconn;
3464 char *outbuf = NULL;
3465 ssize_t ret=0;
3468 * We can only use sendfile on a non-chained packet
3469 * but we can use on a non-oplocked file. tridge proved this
3470 * on a train in Germany :-). JRA.
3471 * reply_readbraw has already checked the length.
3474 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3475 (fsp->wcp == NULL) &&
3476 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3477 ssize_t sendfile_read = -1;
3478 char header[4];
3479 DATA_BLOB header_blob;
3481 _smb_setlen(header,nread);
3482 header_blob = data_blob_const(header, 4);
3484 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3485 &header_blob, startpos,
3486 nread);
3487 if (sendfile_read == -1) {
3488 /* Returning ENOSYS means no data at all was sent.
3489 * Do this as a normal read. */
3490 if (errno == ENOSYS) {
3491 goto normal_readbraw;
3495 * Special hack for broken Linux with no working sendfile. If we
3496 * return EINTR we sent the header but not the rest of the data.
3497 * Fake this up by doing read/write calls.
3499 if (errno == EINTR) {
3500 /* Ensure we don't do this again. */
3501 set_use_sendfile(SNUM(conn), False);
3502 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3504 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3505 DEBUG(0,("send_file_readbraw: "
3506 "fake_sendfile failed for "
3507 "file %s (%s).\n",
3508 fsp_str_dbg(fsp),
3509 strerror(errno)));
3510 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3512 return;
3515 DEBUG(0,("send_file_readbraw: sendfile failed for "
3516 "file %s (%s). Terminating\n",
3517 fsp_str_dbg(fsp), strerror(errno)));
3518 exit_server_cleanly("send_file_readbraw sendfile failed");
3519 } else if (sendfile_read == 0) {
3521 * Some sendfile implementations return 0 to indicate
3522 * that there was a short read, but nothing was
3523 * actually written to the socket. In this case,
3524 * fallback to the normal read path so the header gets
3525 * the correct byte count.
3527 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3528 "bytes falling back to the normal read: "
3529 "%s\n", fsp_str_dbg(fsp)));
3530 goto normal_readbraw;
3533 /* Deal with possible short send. */
3534 if (sendfile_read != 4+nread) {
3535 ret = sendfile_short_send(xconn, fsp,
3536 sendfile_read, 4, nread);
3537 if (ret == -1) {
3538 fail_readraw();
3541 return;
3544 normal_readbraw:
3546 outbuf = talloc_array(NULL, char, nread+4);
3547 if (!outbuf) {
3548 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3549 (unsigned)(nread+4)));
3550 reply_readbraw_error(xconn);
3551 return;
3554 if (nread > 0) {
3555 ret = read_file(fsp,outbuf+4,startpos,nread);
3556 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3557 if (ret < mincount)
3558 ret = 0;
3559 #else
3560 if (ret < nread)
3561 ret = 0;
3562 #endif
3565 _smb_setlen(outbuf,ret);
3566 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3567 int saved_errno = errno;
3569 * Try and give an error message saying what
3570 * client failed.
3572 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3573 smbXsrv_connection_dbg(xconn),
3574 strerror(saved_errno)));
3575 errno = saved_errno;
3577 fail_readraw();
3580 TALLOC_FREE(outbuf);
3583 /****************************************************************************
3584 Reply to a readbraw (core+ protocol).
3585 ****************************************************************************/
3587 void reply_readbraw(struct smb_request *req)
3589 connection_struct *conn = req->conn;
3590 struct smbXsrv_connection *xconn = req->xconn;
3591 ssize_t maxcount,mincount;
3592 size_t nread = 0;
3593 off_t startpos;
3594 files_struct *fsp;
3595 struct lock_struct lock;
3596 off_t size = 0;
3598 START_PROFILE(SMBreadbraw);
3600 if (srv_is_signing_active(xconn) || req->encrypted) {
3601 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3602 "raw reads/writes are disallowed.");
3605 if (req->wct < 8) {
3606 reply_readbraw_error(xconn);
3607 END_PROFILE(SMBreadbraw);
3608 return;
3611 if (xconn->smb1.echo_handler.trusted_fde) {
3612 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3613 "'async smb echo handler = yes'\n"));
3614 reply_readbraw_error(xconn);
3615 END_PROFILE(SMBreadbraw);
3616 return;
3620 * Special check if an oplock break has been issued
3621 * and the readraw request croses on the wire, we must
3622 * return a zero length response here.
3625 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3628 * We have to do a check_fsp by hand here, as
3629 * we must always return 4 zero bytes on error,
3630 * not a NTSTATUS.
3633 if (!fsp || !conn || conn != fsp->conn ||
3634 req->vuid != fsp->vuid ||
3635 fsp->is_directory || fsp->fh->fd == -1) {
3637 * fsp could be NULL here so use the value from the packet. JRA.
3639 DEBUG(3,("reply_readbraw: fnum %d not valid "
3640 "- cache prime?\n",
3641 (int)SVAL(req->vwv+0, 0)));
3642 reply_readbraw_error(xconn);
3643 END_PROFILE(SMBreadbraw);
3644 return;
3647 /* Do a "by hand" version of CHECK_READ. */
3648 if (!(fsp->can_read ||
3649 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3650 (fsp->access_mask & FILE_EXECUTE)))) {
3651 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3652 (int)SVAL(req->vwv+0, 0)));
3653 reply_readbraw_error(xconn);
3654 END_PROFILE(SMBreadbraw);
3655 return;
3658 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3660 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3661 if(req->wct == 10) {
3663 * This is a large offset (64 bit) read.
3666 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3668 if(startpos < 0) {
3669 DEBUG(0,("reply_readbraw: negative 64 bit "
3670 "readraw offset (%.0f) !\n",
3671 (double)startpos ));
3672 reply_readbraw_error(xconn);
3673 END_PROFILE(SMBreadbraw);
3674 return;
3678 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3679 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3681 /* ensure we don't overrun the packet size */
3682 maxcount = MIN(65535,maxcount);
3684 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3685 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3686 &lock);
3688 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3689 reply_readbraw_error(xconn);
3690 END_PROFILE(SMBreadbraw);
3691 return;
3694 if (fsp_stat(fsp) == 0) {
3695 size = fsp->fsp_name->st.st_ex_size;
3698 if (startpos >= size) {
3699 nread = 0;
3700 } else {
3701 nread = MIN(maxcount,(size - startpos));
3704 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3705 if (nread < mincount)
3706 nread = 0;
3707 #endif
3709 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3710 "min=%lu nread=%lu\n",
3711 fsp_fnum_dbg(fsp), (double)startpos,
3712 (unsigned long)maxcount,
3713 (unsigned long)mincount,
3714 (unsigned long)nread ) );
3716 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3718 DEBUG(5,("reply_readbraw finished\n"));
3720 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3722 END_PROFILE(SMBreadbraw);
3723 return;
3726 #undef DBGC_CLASS
3727 #define DBGC_CLASS DBGC_LOCKING
3729 /****************************************************************************
3730 Reply to a lockread (core+ protocol).
3731 ****************************************************************************/
3733 void reply_lockread(struct smb_request *req)
3735 connection_struct *conn = req->conn;
3736 ssize_t nread = -1;
3737 char *data;
3738 off_t startpos;
3739 size_t numtoread;
3740 size_t maxtoread;
3741 NTSTATUS status;
3742 files_struct *fsp;
3743 struct byte_range_lock *br_lck = NULL;
3744 char *p = NULL;
3745 struct smbXsrv_connection *xconn = req->xconn;
3747 START_PROFILE(SMBlockread);
3749 if (req->wct < 5) {
3750 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3751 END_PROFILE(SMBlockread);
3752 return;
3755 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3757 if (!check_fsp(conn, req, fsp)) {
3758 END_PROFILE(SMBlockread);
3759 return;
3762 if (!CHECK_READ(fsp,req)) {
3763 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3764 END_PROFILE(SMBlockread);
3765 return;
3768 numtoread = SVAL(req->vwv+1, 0);
3769 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3772 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3773 * protocol request that predates the read/write lock concept.
3774 * Thus instead of asking for a read lock here we need to ask
3775 * for a write lock. JRA.
3776 * Note that the requested lock size is unaffected by max_send.
3779 br_lck = do_lock(req->sconn->msg_ctx,
3780 fsp,
3781 (uint64_t)req->smbpid,
3782 (uint64_t)numtoread,
3783 (uint64_t)startpos,
3784 WRITE_LOCK,
3785 WINDOWS_LOCK,
3786 False, /* Non-blocking lock. */
3787 &status,
3788 NULL);
3789 TALLOC_FREE(br_lck);
3791 if (NT_STATUS_V(status)) {
3792 reply_nterror(req, status);
3793 END_PROFILE(SMBlockread);
3794 return;
3798 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3800 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3802 if (numtoread > maxtoread) {
3803 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3804 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3805 (unsigned int)numtoread, (unsigned int)maxtoread,
3806 (unsigned int)xconn->smb1.sessions.max_send));
3807 numtoread = maxtoread;
3810 reply_outbuf(req, 5, numtoread + 3);
3812 data = smb_buf(req->outbuf) + 3;
3814 nread = read_file(fsp,data,startpos,numtoread);
3816 if (nread < 0) {
3817 reply_nterror(req, map_nt_error_from_unix(errno));
3818 END_PROFILE(SMBlockread);
3819 return;
3822 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3824 SSVAL(req->outbuf,smb_vwv0,nread);
3825 SSVAL(req->outbuf,smb_vwv5,nread+3);
3826 p = smb_buf(req->outbuf);
3827 SCVAL(p,0,0); /* pad byte. */
3828 SSVAL(p,1,nread);
3830 DEBUG(3,("lockread %s num=%d nread=%d\n",
3831 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3833 END_PROFILE(SMBlockread);
3834 return;
3837 #undef DBGC_CLASS
3838 #define DBGC_CLASS DBGC_ALL
3840 /****************************************************************************
3841 Reply to a read.
3842 ****************************************************************************/
3844 void reply_read(struct smb_request *req)
3846 connection_struct *conn = req->conn;
3847 size_t numtoread;
3848 size_t maxtoread;
3849 ssize_t nread = 0;
3850 char *data;
3851 off_t startpos;
3852 files_struct *fsp;
3853 struct lock_struct lock;
3854 struct smbXsrv_connection *xconn = req->xconn;
3856 START_PROFILE(SMBread);
3858 if (req->wct < 3) {
3859 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3860 END_PROFILE(SMBread);
3861 return;
3864 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3866 if (!check_fsp(conn, req, fsp)) {
3867 END_PROFILE(SMBread);
3868 return;
3871 if (!CHECK_READ(fsp,req)) {
3872 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3873 END_PROFILE(SMBread);
3874 return;
3877 numtoread = SVAL(req->vwv+1, 0);
3878 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3881 * The requested read size cannot be greater than max_send. JRA.
3883 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3885 if (numtoread > maxtoread) {
3886 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3887 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3888 (unsigned int)numtoread, (unsigned int)maxtoread,
3889 (unsigned int)xconn->smb1.sessions.max_send));
3890 numtoread = maxtoread;
3893 reply_outbuf(req, 5, numtoread+3);
3895 data = smb_buf(req->outbuf) + 3;
3897 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3898 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3899 &lock);
3901 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3902 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3903 END_PROFILE(SMBread);
3904 return;
3907 if (numtoread > 0)
3908 nread = read_file(fsp,data,startpos,numtoread);
3910 if (nread < 0) {
3911 reply_nterror(req, map_nt_error_from_unix(errno));
3912 goto strict_unlock;
3915 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3917 SSVAL(req->outbuf,smb_vwv0,nread);
3918 SSVAL(req->outbuf,smb_vwv5,nread+3);
3919 SCVAL(smb_buf(req->outbuf),0,1);
3920 SSVAL(smb_buf(req->outbuf),1,nread);
3922 DEBUG(3, ("read %s num=%d nread=%d\n",
3923 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3925 strict_unlock:
3926 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3928 END_PROFILE(SMBread);
3929 return;
3932 /****************************************************************************
3933 Setup readX header.
3934 ****************************************************************************/
3936 int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3938 int outsize;
3940 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3941 False);
3943 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3945 SCVAL(outbuf,smb_vwv0,0xFF);
3946 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3947 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3948 SSVAL(outbuf,smb_vwv6,
3949 (smb_wct - 4) /* offset from smb header to wct */
3950 + 1 /* the wct field */
3951 + 12 * sizeof(uint16_t) /* vwv */
3952 + 2 /* the buflen field */
3953 + 1); /* padding byte */
3954 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3955 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3956 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3957 _smb_setlen_large(outbuf,
3958 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3959 return outsize;
3962 /****************************************************************************
3963 Reply to a read and X - possibly using sendfile.
3964 ****************************************************************************/
3966 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3967 files_struct *fsp, off_t startpos,
3968 size_t smb_maxcnt)
3970 struct smbXsrv_connection *xconn = req->xconn;
3971 ssize_t nread = -1;
3972 struct lock_struct lock;
3973 int saved_errno = 0;
3975 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3976 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3977 &lock);
3979 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3980 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3981 return;
3985 * We can only use sendfile on a non-chained packet
3986 * but we can use on a non-oplocked file. tridge proved this
3987 * on a train in Germany :-). JRA.
3990 if (!req_is_in_chain(req) &&
3991 !req->encrypted &&
3992 (fsp->base_fsp == NULL) &&
3993 (fsp->wcp == NULL) &&
3994 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3995 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3996 DATA_BLOB header;
3998 if(fsp_stat(fsp) == -1) {
3999 reply_nterror(req, map_nt_error_from_unix(errno));
4000 goto strict_unlock;
4003 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4004 (startpos > fsp->fsp_name->st.st_ex_size) ||
4005 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4007 * We already know that we would do a short read, so don't
4008 * try the sendfile() path.
4010 goto nosendfile_read;
4014 * Set up the packet header before send. We
4015 * assume here the sendfile will work (get the
4016 * correct amount of data).
4019 header = data_blob_const(headerbuf, sizeof(headerbuf));
4021 construct_reply_common_req(req, (char *)headerbuf);
4022 setup_readX_header((char *)headerbuf, smb_maxcnt);
4024 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4025 startpos, smb_maxcnt);
4026 if (nread == -1) {
4027 saved_errno = errno;
4029 /* Returning ENOSYS means no data at all was sent.
4030 Do this as a normal read. */
4031 if (errno == ENOSYS) {
4032 goto normal_read;
4036 * Special hack for broken Linux with no working sendfile. If we
4037 * return EINTR we sent the header but not the rest of the data.
4038 * Fake this up by doing read/write calls.
4041 if (errno == EINTR) {
4042 /* Ensure we don't do this again. */
4043 set_use_sendfile(SNUM(conn), False);
4044 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4045 nread = fake_sendfile(xconn, fsp, startpos,
4046 smb_maxcnt);
4047 if (nread == -1) {
4048 saved_errno = errno;
4049 DEBUG(0,("send_file_readX: "
4050 "fake_sendfile failed for "
4051 "file %s (%s) for client %s. "
4052 "Terminating\n",
4053 fsp_str_dbg(fsp),
4054 smbXsrv_connection_dbg(xconn),
4055 strerror(saved_errno)));
4056 errno = saved_errno;
4057 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4059 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4060 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4061 /* No outbuf here means successful sendfile. */
4062 goto strict_unlock;
4065 DEBUG(0,("send_file_readX: sendfile failed for file "
4066 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4067 strerror(errno)));
4068 exit_server_cleanly("send_file_readX sendfile failed");
4069 } else if (nread == 0) {
4071 * Some sendfile implementations return 0 to indicate
4072 * that there was a short read, but nothing was
4073 * actually written to the socket. In this case,
4074 * fallback to the normal read path so the header gets
4075 * the correct byte count.
4077 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4078 "falling back to the normal read: %s\n",
4079 fsp_str_dbg(fsp)));
4080 goto normal_read;
4083 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4084 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4086 /* Deal with possible short send. */
4087 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4088 ssize_t ret;
4090 ret = sendfile_short_send(xconn, fsp, nread,
4091 sizeof(headerbuf), smb_maxcnt);
4092 if (ret == -1) {
4093 const char *r;
4094 r = "send_file_readX: sendfile_short_send failed";
4095 DEBUG(0,("%s for file %s (%s).\n",
4096 r, fsp_str_dbg(fsp), strerror(errno)));
4097 exit_server_cleanly(r);
4100 /* No outbuf here means successful sendfile. */
4101 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4102 SMB_PERFCOUNT_END(&req->pcd);
4103 goto strict_unlock;
4106 normal_read:
4108 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4109 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4110 ssize_t ret;
4112 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4113 (startpos > fsp->fsp_name->st.st_ex_size) ||
4114 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4116 * We already know that we would do a short
4117 * read, so don't try the sendfile() path.
4119 goto nosendfile_read;
4122 construct_reply_common_req(req, (char *)headerbuf);
4123 setup_readX_header((char *)headerbuf, smb_maxcnt);
4125 /* Send out the header. */
4126 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4127 sizeof(headerbuf));
4128 if (ret != sizeof(headerbuf)) {
4129 saved_errno = errno;
4131 * Try and give an error message saying what
4132 * client failed.
4134 DEBUG(0,("send_file_readX: write_data failed for file "
4135 "%s (%s) for client %s. Terminating\n",
4136 fsp_str_dbg(fsp),
4137 smbXsrv_connection_dbg(xconn),
4138 strerror(saved_errno)));
4139 errno = saved_errno;
4140 exit_server_cleanly("send_file_readX sendfile failed");
4142 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4143 if (nread == -1) {
4144 saved_errno = errno;
4145 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4146 "%s (%s) for client %s. Terminating\n",
4147 fsp_str_dbg(fsp),
4148 smbXsrv_connection_dbg(xconn),
4149 strerror(saved_errno)));
4150 errno = saved_errno;
4151 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4153 goto strict_unlock;
4156 nosendfile_read:
4158 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4159 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4160 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4162 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4163 startpos, smb_maxcnt);
4164 saved_errno = errno;
4166 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4168 if (nread < 0) {
4169 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4170 return;
4173 setup_readX_header((char *)req->outbuf, nread);
4175 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4176 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4177 return;
4179 strict_unlock:
4180 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4181 TALLOC_FREE(req->outbuf);
4182 return;
4185 /****************************************************************************
4186 Work out how much space we have for a read return.
4187 ****************************************************************************/
4189 static size_t calc_max_read_pdu(const struct smb_request *req)
4191 struct smbXsrv_connection *xconn = req->xconn;
4193 if (xconn->protocol < PROTOCOL_NT1) {
4194 return xconn->smb1.sessions.max_send;
4197 if (!lp_large_readwrite()) {
4198 return xconn->smb1.sessions.max_send;
4201 if (req_is_in_chain(req)) {
4202 return xconn->smb1.sessions.max_send;
4205 if (req->encrypted) {
4207 * Don't take encrypted traffic up to the
4208 * limit. There are padding considerations
4209 * that make that tricky.
4211 return xconn->smb1.sessions.max_send;
4214 if (srv_is_signing_active(xconn)) {
4215 return 0x1FFFF;
4218 if (!lp_unix_extensions()) {
4219 return 0x1FFFF;
4223 * We can do ultra-large POSIX reads.
4225 return 0xFFFFFF;
4228 /****************************************************************************
4229 Calculate how big a read can be. Copes with all clients. It's always
4230 safe to return a short read - Windows does this.
4231 ****************************************************************************/
4233 static size_t calc_read_size(const struct smb_request *req,
4234 size_t upper_size,
4235 size_t lower_size)
4237 struct smbXsrv_connection *xconn = req->xconn;
4238 size_t max_pdu = calc_max_read_pdu(req);
4239 size_t total_size = 0;
4240 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4241 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4244 * Windows explicitly ignores upper size of 0xFFFF.
4245 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4246 * We must do the same as these will never fit even in
4247 * an extended size NetBIOS packet.
4249 if (upper_size == 0xFFFF) {
4250 upper_size = 0;
4253 if (xconn->protocol < PROTOCOL_NT1) {
4254 upper_size = 0;
4257 total_size = ((upper_size<<16) | lower_size);
4260 * LARGE_READX test shows it's always safe to return
4261 * a short read. Windows does so.
4263 return MIN(total_size, max_len);
4266 /****************************************************************************
4267 Reply to a read and X.
4268 ****************************************************************************/
4270 void reply_read_and_X(struct smb_request *req)
4272 connection_struct *conn = req->conn;
4273 files_struct *fsp;
4274 off_t startpos;
4275 size_t smb_maxcnt;
4276 size_t upper_size;
4277 bool big_readX = False;
4278 #if 0
4279 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4280 #endif
4282 START_PROFILE(SMBreadX);
4284 if ((req->wct != 10) && (req->wct != 12)) {
4285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4286 return;
4289 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4290 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4291 smb_maxcnt = SVAL(req->vwv+5, 0);
4293 /* If it's an IPC, pass off the pipe handler. */
4294 if (IS_IPC(conn)) {
4295 reply_pipe_read_and_X(req);
4296 END_PROFILE(SMBreadX);
4297 return;
4300 if (!check_fsp(conn, req, fsp)) {
4301 END_PROFILE(SMBreadX);
4302 return;
4305 if (!CHECK_READ(fsp,req)) {
4306 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4307 END_PROFILE(SMBreadX);
4308 return;
4311 upper_size = SVAL(req->vwv+7, 0);
4312 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4313 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4315 * This is a heuristic to avoid keeping large
4316 * outgoing buffers around over long-lived aio
4317 * requests.
4319 big_readX = True;
4322 if (req->wct == 12) {
4324 * This is a large offset (64 bit) read.
4326 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4330 if (!big_readX) {
4331 NTSTATUS status = schedule_aio_read_and_X(conn,
4332 req,
4333 fsp,
4334 startpos,
4335 smb_maxcnt);
4336 if (NT_STATUS_IS_OK(status)) {
4337 /* Read scheduled - we're done. */
4338 goto out;
4340 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4341 /* Real error - report to client. */
4342 END_PROFILE(SMBreadX);
4343 reply_nterror(req, status);
4344 return;
4346 /* NT_STATUS_RETRY - fall back to sync read. */
4349 smbd_lock_socket(req->xconn);
4350 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4351 smbd_unlock_socket(req->xconn);
4353 out:
4354 END_PROFILE(SMBreadX);
4355 return;
4358 /****************************************************************************
4359 Error replies to writebraw must have smb_wct == 1. Fix this up.
4360 ****************************************************************************/
4362 void error_to_writebrawerr(struct smb_request *req)
4364 uint8_t *old_outbuf = req->outbuf;
4366 reply_outbuf(req, 1, 0);
4368 memcpy(req->outbuf, old_outbuf, smb_size);
4369 TALLOC_FREE(old_outbuf);
4372 /****************************************************************************
4373 Read 4 bytes of a smb packet and return the smb length of the packet.
4374 Store the result in the buffer. This version of the function will
4375 never return a session keepalive (length of zero).
4376 Timeout is in milliseconds.
4377 ****************************************************************************/
4379 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4380 size_t *len)
4382 uint8_t msgtype = NBSSkeepalive;
4384 while (msgtype == NBSSkeepalive) {
4385 NTSTATUS status;
4387 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4388 len);
4389 if (!NT_STATUS_IS_OK(status)) {
4390 char addr[INET6_ADDRSTRLEN];
4391 /* Try and give an error message
4392 * saying what client failed. */
4393 DEBUG(0, ("read_fd_with_timeout failed for "
4394 "client %s read error = %s.\n",
4395 get_peer_addr(fd,addr,sizeof(addr)),
4396 nt_errstr(status)));
4397 return status;
4400 msgtype = CVAL(inbuf, 0);
4403 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4404 (unsigned long)len));
4406 return NT_STATUS_OK;
4409 /****************************************************************************
4410 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4411 ****************************************************************************/
4413 void reply_writebraw(struct smb_request *req)
4415 connection_struct *conn = req->conn;
4416 struct smbXsrv_connection *xconn = req->xconn;
4417 char *buf = NULL;
4418 ssize_t nwritten=0;
4419 ssize_t total_written=0;
4420 size_t numtowrite=0;
4421 size_t tcount;
4422 off_t startpos;
4423 const char *data=NULL;
4424 bool write_through;
4425 files_struct *fsp;
4426 struct lock_struct lock;
4427 NTSTATUS status;
4429 START_PROFILE(SMBwritebraw);
4432 * If we ever reply with an error, it must have the SMB command
4433 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4434 * we're finished.
4436 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4438 if (srv_is_signing_active(xconn)) {
4439 END_PROFILE(SMBwritebraw);
4440 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4441 "raw reads/writes are disallowed.");
4444 if (req->wct < 12) {
4445 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4446 error_to_writebrawerr(req);
4447 END_PROFILE(SMBwritebraw);
4448 return;
4451 if (xconn->smb1.echo_handler.trusted_fde) {
4452 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4453 "'async smb echo handler = yes'\n"));
4454 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4455 error_to_writebrawerr(req);
4456 END_PROFILE(SMBwritebraw);
4457 return;
4460 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4461 if (!check_fsp(conn, req, fsp)) {
4462 error_to_writebrawerr(req);
4463 END_PROFILE(SMBwritebraw);
4464 return;
4467 if (!CHECK_WRITE(fsp)) {
4468 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4469 error_to_writebrawerr(req);
4470 END_PROFILE(SMBwritebraw);
4471 return;
4474 tcount = IVAL(req->vwv+1, 0);
4475 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4476 write_through = BITSETW(req->vwv+7,0);
4478 /* We have to deal with slightly different formats depending
4479 on whether we are using the core+ or lanman1.0 protocol */
4481 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4482 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4483 data = smb_buf_const(req->inbuf);
4484 } else {
4485 numtowrite = SVAL(req->vwv+10, 0);
4486 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4489 /* Ensure we don't write bytes past the end of this packet. */
4490 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4491 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4492 error_to_writebrawerr(req);
4493 END_PROFILE(SMBwritebraw);
4494 return;
4497 if (!fsp->print_file) {
4498 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4499 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4500 &lock);
4502 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4503 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4504 error_to_writebrawerr(req);
4505 END_PROFILE(SMBwritebraw);
4506 return;
4510 if (numtowrite>0) {
4511 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4514 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4515 "wrote=%d sync=%d\n",
4516 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4517 (int)nwritten, (int)write_through));
4519 if (nwritten < (ssize_t)numtowrite) {
4520 reply_nterror(req, NT_STATUS_DISK_FULL);
4521 error_to_writebrawerr(req);
4522 goto strict_unlock;
4525 total_written = nwritten;
4527 /* Allocate a buffer of 64k + length. */
4528 buf = talloc_array(NULL, char, 65540);
4529 if (!buf) {
4530 reply_nterror(req, NT_STATUS_NO_MEMORY);
4531 error_to_writebrawerr(req);
4532 goto strict_unlock;
4535 /* Return a SMBwritebraw message to the redirector to tell
4536 * it to send more bytes */
4538 memcpy(buf, req->inbuf, smb_size);
4539 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4540 SCVAL(buf,smb_com,SMBwritebraw);
4541 SSVALS(buf,smb_vwv0,0xFFFF);
4542 show_msg(buf);
4543 if (!srv_send_smb(req->xconn,
4544 buf,
4545 false, 0, /* no signing */
4546 IS_CONN_ENCRYPTED(conn),
4547 &req->pcd)) {
4548 exit_server_cleanly("reply_writebraw: srv_send_smb "
4549 "failed.");
4552 /* Now read the raw data into the buffer and write it */
4553 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4554 &numtowrite);
4555 if (!NT_STATUS_IS_OK(status)) {
4556 exit_server_cleanly("secondary writebraw failed");
4559 /* Set up outbuf to return the correct size */
4560 reply_outbuf(req, 1, 0);
4562 if (numtowrite != 0) {
4564 if (numtowrite > 0xFFFF) {
4565 DEBUG(0,("reply_writebraw: Oversize secondary write "
4566 "raw requested (%u). Terminating\n",
4567 (unsigned int)numtowrite ));
4568 exit_server_cleanly("secondary writebraw failed");
4571 if (tcount > nwritten+numtowrite) {
4572 DEBUG(3,("reply_writebraw: Client overestimated the "
4573 "write %d %d %d\n",
4574 (int)tcount,(int)nwritten,(int)numtowrite));
4577 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4578 numtowrite);
4580 if (!NT_STATUS_IS_OK(status)) {
4581 /* Try and give an error message
4582 * saying what client failed. */
4583 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4584 "raw read failed (%s) for client %s. "
4585 "Terminating\n", nt_errstr(status),
4586 smbXsrv_connection_dbg(xconn)));
4587 exit_server_cleanly("secondary writebraw failed");
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 strict_unlock;
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 strict_unlock;
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 if (!fsp->print_file) {
4626 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4629 /* We won't return a status if write through is not selected - this
4630 * follows what WfWg does */
4631 END_PROFILE(SMBwritebraw);
4633 if (!write_through && total_written==tcount) {
4635 #if RABBIT_PELLET_FIX
4637 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4638 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4639 * JRA.
4641 if (!send_keepalive(xconn->transport.sock)) {
4642 exit_server_cleanly("reply_writebraw: send of "
4643 "keepalive failed");
4645 #endif
4646 TALLOC_FREE(req->outbuf);
4648 return;
4650 strict_unlock:
4651 if (!fsp->print_file) {
4652 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4655 END_PROFILE(SMBwritebraw);
4656 return;
4659 #undef DBGC_CLASS
4660 #define DBGC_CLASS DBGC_LOCKING
4662 /****************************************************************************
4663 Reply to a writeunlock (core+).
4664 ****************************************************************************/
4666 void reply_writeunlock(struct smb_request *req)
4668 connection_struct *conn = req->conn;
4669 ssize_t nwritten = -1;
4670 size_t numtowrite;
4671 off_t startpos;
4672 const char *data;
4673 NTSTATUS status = NT_STATUS_OK;
4674 files_struct *fsp;
4675 struct lock_struct lock;
4676 int saved_errno = 0;
4678 START_PROFILE(SMBwriteunlock);
4680 if (req->wct < 5) {
4681 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4682 END_PROFILE(SMBwriteunlock);
4683 return;
4686 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4688 if (!check_fsp(conn, req, fsp)) {
4689 END_PROFILE(SMBwriteunlock);
4690 return;
4693 if (!CHECK_WRITE(fsp)) {
4694 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4695 END_PROFILE(SMBwriteunlock);
4696 return;
4699 numtowrite = SVAL(req->vwv+1, 0);
4700 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4701 data = (const char *)req->buf + 3;
4703 if (!fsp->print_file && numtowrite > 0) {
4704 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4705 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4706 &lock);
4708 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4709 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4710 END_PROFILE(SMBwriteunlock);
4711 return;
4715 /* The special X/Open SMB protocol handling of
4716 zero length writes is *NOT* done for
4717 this call */
4718 if(numtowrite == 0) {
4719 nwritten = 0;
4720 } else {
4721 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4722 saved_errno = errno;
4725 status = sync_file(conn, fsp, False /* write through */);
4726 if (!NT_STATUS_IS_OK(status)) {
4727 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4728 fsp_str_dbg(fsp), nt_errstr(status)));
4729 reply_nterror(req, status);
4730 goto strict_unlock;
4733 if(nwritten < 0) {
4734 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4735 goto strict_unlock;
4738 if((nwritten < numtowrite) && (numtowrite != 0)) {
4739 reply_nterror(req, NT_STATUS_DISK_FULL);
4740 goto strict_unlock;
4743 if (numtowrite && !fsp->print_file) {
4744 status = do_unlock(req->sconn->msg_ctx,
4745 fsp,
4746 (uint64_t)req->smbpid,
4747 (uint64_t)numtowrite,
4748 (uint64_t)startpos,
4749 WINDOWS_LOCK);
4751 if (NT_STATUS_V(status)) {
4752 reply_nterror(req, status);
4753 goto strict_unlock;
4757 reply_outbuf(req, 1, 0);
4759 SSVAL(req->outbuf,smb_vwv0,nwritten);
4761 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4762 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4764 strict_unlock:
4765 if (numtowrite && !fsp->print_file) {
4766 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
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 ssize_t nwritten = -1;
4785 off_t startpos;
4786 const char *data;
4787 files_struct *fsp;
4788 struct lock_struct lock;
4789 NTSTATUS status;
4790 int saved_errno = 0;
4792 START_PROFILE(SMBwrite);
4794 if (req->wct < 5) {
4795 END_PROFILE(SMBwrite);
4796 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4797 return;
4800 /* If it's an IPC, pass off the pipe handler. */
4801 if (IS_IPC(conn)) {
4802 reply_pipe_write(req);
4803 END_PROFILE(SMBwrite);
4804 return;
4807 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4809 if (!check_fsp(conn, req, fsp)) {
4810 END_PROFILE(SMBwrite);
4811 return;
4814 if (!CHECK_WRITE(fsp)) {
4815 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4816 END_PROFILE(SMBwrite);
4817 return;
4820 numtowrite = SVAL(req->vwv+1, 0);
4821 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4822 data = (const char *)req->buf + 3;
4824 if (!fsp->print_file) {
4825 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4826 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4827 &lock);
4829 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4830 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4831 END_PROFILE(SMBwrite);
4832 return;
4837 * X/Open SMB protocol says that if smb_vwv1 is
4838 * zero then the file size should be extended or
4839 * truncated to the size given in smb_vwv[2-3].
4842 if(numtowrite == 0) {
4844 * This is actually an allocate call, and set EOF. JRA.
4846 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4847 if (nwritten < 0) {
4848 reply_nterror(req, NT_STATUS_DISK_FULL);
4849 goto strict_unlock;
4851 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4852 if (nwritten < 0) {
4853 reply_nterror(req, NT_STATUS_DISK_FULL);
4854 goto strict_unlock;
4856 trigger_write_time_update_immediate(fsp);
4857 } else {
4858 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4861 status = sync_file(conn, fsp, False);
4862 if (!NT_STATUS_IS_OK(status)) {
4863 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4864 fsp_str_dbg(fsp), nt_errstr(status)));
4865 reply_nterror(req, status);
4866 goto strict_unlock;
4869 if(nwritten < 0) {
4870 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4871 goto strict_unlock;
4874 if((nwritten == 0) && (numtowrite != 0)) {
4875 reply_nterror(req, NT_STATUS_DISK_FULL);
4876 goto strict_unlock;
4879 reply_outbuf(req, 1, 0);
4881 SSVAL(req->outbuf,smb_vwv0,nwritten);
4883 if (nwritten < (ssize_t)numtowrite) {
4884 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4885 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4888 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4890 strict_unlock:
4891 if (!fsp->print_file) {
4892 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4895 END_PROFILE(SMBwrite);
4896 return;
4899 /****************************************************************************
4900 Ensure a buffer is a valid writeX for recvfile purposes.
4901 ****************************************************************************/
4903 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4904 (2*14) + /* word count (including bcc) */ \
4905 1 /* pad byte */)
4907 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4908 const uint8_t *inbuf)
4910 size_t numtowrite;
4911 unsigned int doff = 0;
4912 size_t len = smb_len_large(inbuf);
4913 uint16_t fnum;
4914 struct smbXsrv_open *op = NULL;
4915 struct files_struct *fsp = NULL;
4916 NTSTATUS status;
4918 if (is_encrypted_packet(inbuf)) {
4919 /* Can't do this on encrypted
4920 * connections. */
4921 return false;
4924 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4925 return false;
4928 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4929 CVAL(inbuf,smb_wct) != 14) {
4930 DEBUG(10,("is_valid_writeX_buffer: chained or "
4931 "invalid word length.\n"));
4932 return false;
4935 fnum = SVAL(inbuf, smb_vwv2);
4936 status = smb1srv_open_lookup(xconn,
4937 fnum,
4938 0, /* now */
4939 &op);
4940 if (!NT_STATUS_IS_OK(status)) {
4941 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4942 return false;
4944 fsp = op->compat;
4945 if (fsp == NULL) {
4946 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4947 return false;
4949 if (fsp->conn == NULL) {
4950 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4951 return false;
4954 if (IS_IPC(fsp->conn)) {
4955 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4956 return false;
4958 if (IS_PRINT(fsp->conn)) {
4959 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4960 return false;
4962 doff = SVAL(inbuf,smb_vwv11);
4964 numtowrite = SVAL(inbuf,smb_vwv10);
4966 if (len > doff && len - doff > 0xFFFF) {
4967 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4970 if (numtowrite == 0) {
4971 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4972 return false;
4975 /* Ensure the sizes match up. */
4976 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4977 /* no pad byte...old smbclient :-( */
4978 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4979 (unsigned int)doff,
4980 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4981 return false;
4984 if (len - doff != numtowrite) {
4985 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4986 "len = %u, doff = %u, numtowrite = %u\n",
4987 (unsigned int)len,
4988 (unsigned int)doff,
4989 (unsigned int)numtowrite ));
4990 return false;
4993 DEBUG(10,("is_valid_writeX_buffer: true "
4994 "len = %u, doff = %u, numtowrite = %u\n",
4995 (unsigned int)len,
4996 (unsigned int)doff,
4997 (unsigned int)numtowrite ));
4999 return true;
5002 /****************************************************************************
5003 Reply to a write and X.
5004 ****************************************************************************/
5006 void reply_write_and_X(struct smb_request *req)
5008 connection_struct *conn = req->conn;
5009 struct smbXsrv_connection *xconn = req->xconn;
5010 files_struct *fsp;
5011 struct lock_struct lock;
5012 off_t startpos;
5013 size_t numtowrite;
5014 bool write_through;
5015 ssize_t nwritten;
5016 unsigned int smb_doff;
5017 unsigned int smblen;
5018 const char *data;
5019 NTSTATUS status;
5020 int saved_errno = 0;
5022 START_PROFILE(SMBwriteX);
5024 if ((req->wct != 12) && (req->wct != 14)) {
5025 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5026 goto out;
5029 numtowrite = SVAL(req->vwv+10, 0);
5030 smb_doff = SVAL(req->vwv+11, 0);
5031 smblen = smb_len(req->inbuf);
5033 if (req->unread_bytes > 0xFFFF ||
5034 (smblen > smb_doff &&
5035 smblen - smb_doff > 0xFFFF)) {
5036 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5039 if (req->unread_bytes) {
5040 /* Can't do a recvfile write on IPC$ */
5041 if (IS_IPC(conn)) {
5042 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5043 goto out;
5045 if (numtowrite != req->unread_bytes) {
5046 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5047 goto out;
5049 } else {
5050 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5051 smb_doff + numtowrite > smblen) {
5052 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5053 goto out;
5057 /* If it's an IPC, pass off the pipe handler. */
5058 if (IS_IPC(conn)) {
5059 if (req->unread_bytes) {
5060 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5061 goto out;
5063 reply_pipe_write_and_X(req);
5064 goto out;
5067 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5068 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5069 write_through = BITSETW(req->vwv+7,0);
5071 if (!check_fsp(conn, req, fsp)) {
5072 goto out;
5075 if (!CHECK_WRITE(fsp)) {
5076 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5077 goto out;
5080 data = smb_base(req->inbuf) + smb_doff;
5082 if(req->wct == 14) {
5084 * This is a large offset (64 bit) write.
5086 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5090 /* X/Open SMB protocol says that, unlike SMBwrite
5091 if the length is zero then NO truncation is
5092 done, just a write of zero. To truncate a file,
5093 use SMBwrite. */
5095 if(numtowrite == 0) {
5096 nwritten = 0;
5097 } else {
5098 if (req->unread_bytes == 0) {
5099 status = schedule_aio_write_and_X(conn,
5100 req,
5101 fsp,
5102 data,
5103 startpos,
5104 numtowrite);
5106 if (NT_STATUS_IS_OK(status)) {
5107 /* write scheduled - we're done. */
5108 goto out;
5110 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5111 /* Real error - report to client. */
5112 reply_nterror(req, status);
5113 goto out;
5115 /* NT_STATUS_RETRY - fall through to sync write. */
5118 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5119 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5120 &lock);
5122 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5123 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5124 goto out;
5127 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5128 saved_errno = errno;
5130 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5133 if(nwritten < 0) {
5134 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5135 goto out;
5138 if((nwritten == 0) && (numtowrite != 0)) {
5139 reply_nterror(req, NT_STATUS_DISK_FULL);
5140 goto out;
5143 reply_outbuf(req, 6, 0);
5144 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5145 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5146 SSVAL(req->outbuf,smb_vwv2,nwritten);
5147 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5149 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5150 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5152 status = sync_file(conn, fsp, write_through);
5153 if (!NT_STATUS_IS_OK(status)) {
5154 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5155 fsp_str_dbg(fsp), nt_errstr(status)));
5156 reply_nterror(req, status);
5157 goto out;
5160 END_PROFILE(SMBwriteX);
5161 return;
5163 out:
5164 if (req->unread_bytes) {
5165 /* writeX failed. drain socket. */
5166 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5167 req->unread_bytes) {
5168 smb_panic("failed to drain pending bytes");
5170 req->unread_bytes = 0;
5173 END_PROFILE(SMBwriteX);
5174 return;
5177 /****************************************************************************
5178 Reply to a lseek.
5179 ****************************************************************************/
5181 void reply_lseek(struct smb_request *req)
5183 connection_struct *conn = req->conn;
5184 off_t startpos;
5185 off_t res= -1;
5186 int mode,umode;
5187 files_struct *fsp;
5189 START_PROFILE(SMBlseek);
5191 if (req->wct < 4) {
5192 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5193 END_PROFILE(SMBlseek);
5194 return;
5197 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5199 if (!check_fsp(conn, req, fsp)) {
5200 return;
5203 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5205 mode = SVAL(req->vwv+1, 0) & 3;
5206 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5207 startpos = (off_t)IVALS(req->vwv+2, 0);
5209 switch (mode) {
5210 case 0:
5211 umode = SEEK_SET;
5212 res = startpos;
5213 break;
5214 case 1:
5215 umode = SEEK_CUR;
5216 res = fsp->fh->pos + startpos;
5217 break;
5218 case 2:
5219 umode = SEEK_END;
5220 break;
5221 default:
5222 umode = SEEK_SET;
5223 res = startpos;
5224 break;
5227 if (umode == SEEK_END) {
5228 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5229 if(errno == EINVAL) {
5230 off_t current_pos = startpos;
5232 if(fsp_stat(fsp) == -1) {
5233 reply_nterror(req,
5234 map_nt_error_from_unix(errno));
5235 END_PROFILE(SMBlseek);
5236 return;
5239 current_pos += fsp->fsp_name->st.st_ex_size;
5240 if(current_pos < 0)
5241 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5245 if(res == -1) {
5246 reply_nterror(req, map_nt_error_from_unix(errno));
5247 END_PROFILE(SMBlseek);
5248 return;
5252 fsp->fh->pos = res;
5254 reply_outbuf(req, 2, 0);
5255 SIVAL(req->outbuf,smb_vwv0,res);
5257 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5258 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5260 END_PROFILE(SMBlseek);
5261 return;
5264 /****************************************************************************
5265 Reply to a flush.
5266 ****************************************************************************/
5268 void reply_flush(struct smb_request *req)
5270 connection_struct *conn = req->conn;
5271 uint16_t fnum;
5272 files_struct *fsp;
5274 START_PROFILE(SMBflush);
5276 if (req->wct < 1) {
5277 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5278 return;
5281 fnum = SVAL(req->vwv+0, 0);
5282 fsp = file_fsp(req, fnum);
5284 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5285 return;
5288 if (!fsp) {
5289 file_sync_all(conn);
5290 } else {
5291 NTSTATUS status = sync_file(conn, fsp, True);
5292 if (!NT_STATUS_IS_OK(status)) {
5293 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5294 fsp_str_dbg(fsp), nt_errstr(status)));
5295 reply_nterror(req, status);
5296 END_PROFILE(SMBflush);
5297 return;
5301 reply_outbuf(req, 0, 0);
5303 DEBUG(3,("flush\n"));
5304 END_PROFILE(SMBflush);
5305 return;
5308 /****************************************************************************
5309 Reply to a exit.
5310 conn POINTER CAN BE NULL HERE !
5311 ****************************************************************************/
5313 void reply_exit(struct smb_request *req)
5315 START_PROFILE(SMBexit);
5317 file_close_pid(req->sconn, req->smbpid, req->vuid);
5319 reply_outbuf(req, 0, 0);
5321 DEBUG(3,("exit\n"));
5323 END_PROFILE(SMBexit);
5324 return;
5327 struct reply_close_state {
5328 files_struct *fsp;
5329 struct smb_request *smbreq;
5332 static void do_smb1_close(struct tevent_req *req);
5334 void reply_close(struct smb_request *req)
5336 connection_struct *conn = req->conn;
5337 NTSTATUS status = NT_STATUS_OK;
5338 files_struct *fsp = NULL;
5339 START_PROFILE(SMBclose);
5341 if (req->wct < 3) {
5342 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5343 END_PROFILE(SMBclose);
5344 return;
5347 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5350 * We can only use check_fsp if we know it's not a directory.
5353 if (!check_fsp_open(conn, req, fsp)) {
5354 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5355 END_PROFILE(SMBclose);
5356 return;
5359 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5360 fsp->is_directory ? "directory" : "file",
5361 fsp->fh->fd, fsp_fnum_dbg(fsp),
5362 conn->num_files_open));
5364 if (!fsp->is_directory) {
5365 time_t t;
5368 * Take care of any time sent in the close.
5371 t = srv_make_unix_date3(req->vwv+1);
5372 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5375 if (fsp->num_aio_requests != 0) {
5377 struct reply_close_state *state;
5379 DEBUG(10, ("closing with aio %u requests pending\n",
5380 fsp->num_aio_requests));
5383 * We depend on the aio_extra destructor to take care of this
5384 * close request once fsp->num_aio_request drops to 0.
5387 fsp->deferred_close = tevent_wait_send(
5388 fsp, fsp->conn->sconn->ev_ctx);
5389 if (fsp->deferred_close == NULL) {
5390 status = NT_STATUS_NO_MEMORY;
5391 goto done;
5394 state = talloc(fsp, struct reply_close_state);
5395 if (state == NULL) {
5396 TALLOC_FREE(fsp->deferred_close);
5397 status = NT_STATUS_NO_MEMORY;
5398 goto done;
5400 state->fsp = fsp;
5401 state->smbreq = talloc_move(fsp, &req);
5402 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5403 state);
5404 END_PROFILE(SMBclose);
5405 return;
5409 * close_file() returns the unix errno if an error was detected on
5410 * close - normally this is due to a disk full error. If not then it
5411 * was probably an I/O error.
5414 status = close_file(req, fsp, NORMAL_CLOSE);
5415 done:
5416 if (!NT_STATUS_IS_OK(status)) {
5417 reply_nterror(req, status);
5418 END_PROFILE(SMBclose);
5419 return;
5422 reply_outbuf(req, 0, 0);
5423 END_PROFILE(SMBclose);
5424 return;
5427 static void do_smb1_close(struct tevent_req *req)
5429 struct reply_close_state *state = tevent_req_callback_data(
5430 req, struct reply_close_state);
5431 struct smb_request *smbreq;
5432 NTSTATUS status;
5433 int ret;
5435 ret = tevent_wait_recv(req);
5436 TALLOC_FREE(req);
5437 if (ret != 0) {
5438 DEBUG(10, ("tevent_wait_recv returned %s\n",
5439 strerror(ret)));
5441 * Continue anyway, this should never happen
5446 * fsp->smb2_close_request right now is a talloc grandchild of
5447 * fsp. When we close_file(fsp), it would go with it. No chance to
5448 * reply...
5450 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5452 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5453 if (NT_STATUS_IS_OK(status)) {
5454 reply_outbuf(smbreq, 0, 0);
5455 } else {
5456 reply_nterror(smbreq, status);
5458 if (!srv_send_smb(smbreq->xconn,
5459 (char *)smbreq->outbuf,
5460 true,
5461 smbreq->seqnum+1,
5462 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5463 NULL)) {
5464 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5465 "failed.");
5467 TALLOC_FREE(smbreq);
5470 /****************************************************************************
5471 Reply to a writeclose (Core+ protocol).
5472 ****************************************************************************/
5474 void reply_writeclose(struct smb_request *req)
5476 connection_struct *conn = req->conn;
5477 size_t numtowrite;
5478 ssize_t nwritten = -1;
5479 NTSTATUS close_status = NT_STATUS_OK;
5480 off_t startpos;
5481 const char *data;
5482 struct timespec mtime;
5483 files_struct *fsp;
5484 struct lock_struct lock;
5486 START_PROFILE(SMBwriteclose);
5488 if (req->wct < 6) {
5489 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5490 END_PROFILE(SMBwriteclose);
5491 return;
5494 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5496 if (!check_fsp(conn, req, fsp)) {
5497 END_PROFILE(SMBwriteclose);
5498 return;
5500 if (!CHECK_WRITE(fsp)) {
5501 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5502 END_PROFILE(SMBwriteclose);
5503 return;
5506 numtowrite = SVAL(req->vwv+1, 0);
5507 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5508 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5509 data = (const char *)req->buf + 1;
5511 if (fsp->print_file == NULL) {
5512 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5513 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5514 &lock);
5516 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5517 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5518 END_PROFILE(SMBwriteclose);
5519 return;
5523 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5525 if (fsp->print_file == NULL) {
5526 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5529 set_close_write_time(fsp, mtime);
5532 * More insanity. W2K only closes the file if writelen > 0.
5533 * JRA.
5536 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5537 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5538 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5540 if (numtowrite) {
5541 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5542 "file %s\n", fsp_str_dbg(fsp)));
5543 close_status = close_file(req, fsp, NORMAL_CLOSE);
5544 fsp = NULL;
5547 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5548 reply_nterror(req, NT_STATUS_DISK_FULL);
5549 goto out;
5552 if(!NT_STATUS_IS_OK(close_status)) {
5553 reply_nterror(req, close_status);
5554 goto out;
5557 reply_outbuf(req, 1, 0);
5559 SSVAL(req->outbuf,smb_vwv0,nwritten);
5561 out:
5563 END_PROFILE(SMBwriteclose);
5564 return;
5567 #undef DBGC_CLASS
5568 #define DBGC_CLASS DBGC_LOCKING
5570 /****************************************************************************
5571 Reply to a lock.
5572 ****************************************************************************/
5574 void reply_lock(struct smb_request *req)
5576 connection_struct *conn = req->conn;
5577 uint64_t count,offset;
5578 NTSTATUS status;
5579 files_struct *fsp;
5580 struct byte_range_lock *br_lck = NULL;
5582 START_PROFILE(SMBlock);
5584 if (req->wct < 5) {
5585 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5586 END_PROFILE(SMBlock);
5587 return;
5590 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5592 if (!check_fsp(conn, req, fsp)) {
5593 END_PROFILE(SMBlock);
5594 return;
5597 count = (uint64_t)IVAL(req->vwv+1, 0);
5598 offset = (uint64_t)IVAL(req->vwv+3, 0);
5600 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5601 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5603 br_lck = do_lock(req->sconn->msg_ctx,
5604 fsp,
5605 (uint64_t)req->smbpid,
5606 count,
5607 offset,
5608 WRITE_LOCK,
5609 WINDOWS_LOCK,
5610 False, /* Non-blocking lock. */
5611 &status,
5612 NULL);
5614 TALLOC_FREE(br_lck);
5616 if (NT_STATUS_V(status)) {
5617 reply_nterror(req, status);
5618 END_PROFILE(SMBlock);
5619 return;
5622 reply_outbuf(req, 0, 0);
5624 END_PROFILE(SMBlock);
5625 return;
5628 /****************************************************************************
5629 Reply to a unlock.
5630 ****************************************************************************/
5632 void reply_unlock(struct smb_request *req)
5634 connection_struct *conn = req->conn;
5635 uint64_t count,offset;
5636 NTSTATUS status;
5637 files_struct *fsp;
5639 START_PROFILE(SMBunlock);
5641 if (req->wct < 5) {
5642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5643 END_PROFILE(SMBunlock);
5644 return;
5647 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5649 if (!check_fsp(conn, req, fsp)) {
5650 END_PROFILE(SMBunlock);
5651 return;
5654 count = (uint64_t)IVAL(req->vwv+1, 0);
5655 offset = (uint64_t)IVAL(req->vwv+3, 0);
5657 status = do_unlock(req->sconn->msg_ctx,
5658 fsp,
5659 (uint64_t)req->smbpid,
5660 count,
5661 offset,
5662 WINDOWS_LOCK);
5664 if (NT_STATUS_V(status)) {
5665 reply_nterror(req, status);
5666 END_PROFILE(SMBunlock);
5667 return;
5670 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5671 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5673 reply_outbuf(req, 0, 0);
5675 END_PROFILE(SMBunlock);
5676 return;
5679 #undef DBGC_CLASS
5680 #define DBGC_CLASS DBGC_ALL
5682 /****************************************************************************
5683 Reply to a tdis.
5684 conn POINTER CAN BE NULL HERE !
5685 ****************************************************************************/
5687 void reply_tdis(struct smb_request *req)
5689 NTSTATUS status;
5690 connection_struct *conn = req->conn;
5691 struct smbXsrv_tcon *tcon;
5693 START_PROFILE(SMBtdis);
5695 if (!conn) {
5696 DEBUG(4,("Invalid connection in tdis\n"));
5697 reply_force_doserror(req, ERRSRV, ERRinvnid);
5698 END_PROFILE(SMBtdis);
5699 return;
5702 tcon = conn->tcon;
5703 req->conn = NULL;
5706 * TODO: cancel all outstanding requests on the tcon
5708 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5709 if (!NT_STATUS_IS_OK(status)) {
5710 DEBUG(0, ("reply_tdis: "
5711 "smbXsrv_tcon_disconnect() failed: %s\n",
5712 nt_errstr(status)));
5714 * If we hit this case, there is something completely
5715 * wrong, so we better disconnect the transport connection.
5717 END_PROFILE(SMBtdis);
5718 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5719 return;
5722 TALLOC_FREE(tcon);
5724 reply_outbuf(req, 0, 0);
5725 END_PROFILE(SMBtdis);
5726 return;
5729 /****************************************************************************
5730 Reply to a echo.
5731 conn POINTER CAN BE NULL HERE !
5732 ****************************************************************************/
5734 void reply_echo(struct smb_request *req)
5736 connection_struct *conn = req->conn;
5737 struct smb_perfcount_data local_pcd;
5738 struct smb_perfcount_data *cur_pcd;
5739 int smb_reverb;
5740 int seq_num;
5742 START_PROFILE(SMBecho);
5744 smb_init_perfcount_data(&local_pcd);
5746 if (req->wct < 1) {
5747 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5748 END_PROFILE(SMBecho);
5749 return;
5752 smb_reverb = SVAL(req->vwv+0, 0);
5754 reply_outbuf(req, 1, req->buflen);
5756 /* copy any incoming data back out */
5757 if (req->buflen > 0) {
5758 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5761 if (smb_reverb > 100) {
5762 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5763 smb_reverb = 100;
5766 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5768 /* this makes sure we catch the request pcd */
5769 if (seq_num == smb_reverb) {
5770 cur_pcd = &req->pcd;
5771 } else {
5772 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5773 cur_pcd = &local_pcd;
5776 SSVAL(req->outbuf,smb_vwv0,seq_num);
5778 show_msg((char *)req->outbuf);
5779 if (!srv_send_smb(req->xconn,
5780 (char *)req->outbuf,
5781 true, req->seqnum+1,
5782 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5783 cur_pcd))
5784 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5787 DEBUG(3,("echo %d times\n", smb_reverb));
5789 TALLOC_FREE(req->outbuf);
5791 END_PROFILE(SMBecho);
5792 return;
5795 /****************************************************************************
5796 Reply to a printopen.
5797 ****************************************************************************/
5799 void reply_printopen(struct smb_request *req)
5801 connection_struct *conn = req->conn;
5802 files_struct *fsp;
5803 NTSTATUS status;
5805 START_PROFILE(SMBsplopen);
5807 if (req->wct < 2) {
5808 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5809 END_PROFILE(SMBsplopen);
5810 return;
5813 if (!CAN_PRINT(conn)) {
5814 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5815 END_PROFILE(SMBsplopen);
5816 return;
5819 status = file_new(req, conn, &fsp);
5820 if(!NT_STATUS_IS_OK(status)) {
5821 reply_nterror(req, status);
5822 END_PROFILE(SMBsplopen);
5823 return;
5826 /* Open for exclusive use, write only. */
5827 status = print_spool_open(fsp, NULL, req->vuid);
5829 if (!NT_STATUS_IS_OK(status)) {
5830 file_free(req, fsp);
5831 reply_nterror(req, status);
5832 END_PROFILE(SMBsplopen);
5833 return;
5836 reply_outbuf(req, 1, 0);
5837 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5839 DEBUG(3,("openprint fd=%d %s\n",
5840 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5842 END_PROFILE(SMBsplopen);
5843 return;
5846 /****************************************************************************
5847 Reply to a printclose.
5848 ****************************************************************************/
5850 void reply_printclose(struct smb_request *req)
5852 connection_struct *conn = req->conn;
5853 files_struct *fsp;
5854 NTSTATUS status;
5856 START_PROFILE(SMBsplclose);
5858 if (req->wct < 1) {
5859 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5860 END_PROFILE(SMBsplclose);
5861 return;
5864 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5866 if (!check_fsp(conn, req, fsp)) {
5867 END_PROFILE(SMBsplclose);
5868 return;
5871 if (!CAN_PRINT(conn)) {
5872 reply_force_doserror(req, ERRSRV, ERRerror);
5873 END_PROFILE(SMBsplclose);
5874 return;
5877 DEBUG(3,("printclose fd=%d %s\n",
5878 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5880 status = close_file(req, fsp, NORMAL_CLOSE);
5882 if(!NT_STATUS_IS_OK(status)) {
5883 reply_nterror(req, status);
5884 END_PROFILE(SMBsplclose);
5885 return;
5888 reply_outbuf(req, 0, 0);
5890 END_PROFILE(SMBsplclose);
5891 return;
5894 /****************************************************************************
5895 Reply to a printqueue.
5896 ****************************************************************************/
5898 void reply_printqueue(struct smb_request *req)
5900 connection_struct *conn = req->conn;
5901 int max_count;
5902 int start_index;
5904 START_PROFILE(SMBsplretq);
5906 if (req->wct < 2) {
5907 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5908 END_PROFILE(SMBsplretq);
5909 return;
5912 max_count = SVAL(req->vwv+0, 0);
5913 start_index = SVAL(req->vwv+1, 0);
5915 /* we used to allow the client to get the cnum wrong, but that
5916 is really quite gross and only worked when there was only
5917 one printer - I think we should now only accept it if they
5918 get it right (tridge) */
5919 if (!CAN_PRINT(conn)) {
5920 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5921 END_PROFILE(SMBsplretq);
5922 return;
5925 reply_outbuf(req, 2, 3);
5926 SSVAL(req->outbuf,smb_vwv0,0);
5927 SSVAL(req->outbuf,smb_vwv1,0);
5928 SCVAL(smb_buf(req->outbuf),0,1);
5929 SSVAL(smb_buf(req->outbuf),1,0);
5931 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5932 start_index, max_count));
5935 TALLOC_CTX *mem_ctx = talloc_tos();
5936 NTSTATUS status;
5937 WERROR werr;
5938 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5939 struct rpc_pipe_client *cli = NULL;
5940 struct dcerpc_binding_handle *b = NULL;
5941 struct policy_handle handle;
5942 struct spoolss_DevmodeContainer devmode_ctr;
5943 union spoolss_JobInfo *info;
5944 uint32_t count;
5945 uint32_t num_to_get;
5946 uint32_t first;
5947 uint32_t i;
5949 ZERO_STRUCT(handle);
5951 status = rpc_pipe_open_interface(conn,
5952 &ndr_table_spoolss,
5953 conn->session_info,
5954 conn->sconn->remote_address,
5955 conn->sconn->msg_ctx,
5956 &cli);
5957 if (!NT_STATUS_IS_OK(status)) {
5958 DEBUG(0, ("reply_printqueue: "
5959 "could not connect to spoolss: %s\n",
5960 nt_errstr(status)));
5961 reply_nterror(req, status);
5962 goto out;
5964 b = cli->binding_handle;
5966 ZERO_STRUCT(devmode_ctr);
5968 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5969 sharename,
5970 NULL, devmode_ctr,
5971 SEC_FLAG_MAXIMUM_ALLOWED,
5972 &handle,
5973 &werr);
5974 if (!NT_STATUS_IS_OK(status)) {
5975 reply_nterror(req, status);
5976 goto out;
5978 if (!W_ERROR_IS_OK(werr)) {
5979 reply_nterror(req, werror_to_ntstatus(werr));
5980 goto out;
5983 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5984 &handle,
5985 0, /* firstjob */
5986 0xff, /* numjobs */
5987 2, /* level */
5988 0, /* offered */
5989 &count,
5990 &info);
5991 if (!W_ERROR_IS_OK(werr)) {
5992 reply_nterror(req, werror_to_ntstatus(werr));
5993 goto out;
5996 if (max_count > 0) {
5997 first = start_index;
5998 } else {
5999 first = start_index + max_count + 1;
6002 if (first >= count) {
6003 num_to_get = first;
6004 } else {
6005 num_to_get = first + MIN(ABS(max_count), count - first);
6008 for (i = first; i < num_to_get; i++) {
6009 char blob[28];
6010 char *p = blob;
6011 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6012 int qstatus;
6013 size_t len = 0;
6014 uint16_t qrapjobid = pjobid_to_rap(sharename,
6015 info[i].info2.job_id);
6017 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6018 qstatus = 2;
6019 } else {
6020 qstatus = 3;
6023 srv_put_dos_date2(p, 0, qtime);
6024 SCVAL(p, 4, qstatus);
6025 SSVAL(p, 5, qrapjobid);
6026 SIVAL(p, 7, info[i].info2.size);
6027 SCVAL(p, 11, 0);
6028 status = srvstr_push(blob, req->flags2, p+12,
6029 info[i].info2.notify_name, 16, STR_ASCII, &len);
6030 if (!NT_STATUS_IS_OK(status)) {
6031 reply_nterror(req, status);
6032 goto out;
6034 if (message_push_blob(
6035 &req->outbuf,
6036 data_blob_const(
6037 blob, sizeof(blob))) == -1) {
6038 reply_nterror(req, NT_STATUS_NO_MEMORY);
6039 goto out;
6043 if (count > 0) {
6044 SSVAL(req->outbuf,smb_vwv0,count);
6045 SSVAL(req->outbuf,smb_vwv1,
6046 (max_count>0?first+count:first-1));
6047 SCVAL(smb_buf(req->outbuf),0,1);
6048 SSVAL(smb_buf(req->outbuf),1,28*count);
6052 DEBUG(3, ("%u entries returned in queue\n",
6053 (unsigned)count));
6055 out:
6056 if (b && is_valid_policy_hnd(&handle)) {
6057 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6062 END_PROFILE(SMBsplretq);
6063 return;
6066 /****************************************************************************
6067 Reply to a printwrite.
6068 ****************************************************************************/
6070 void reply_printwrite(struct smb_request *req)
6072 connection_struct *conn = req->conn;
6073 int numtowrite;
6074 const char *data;
6075 files_struct *fsp;
6077 START_PROFILE(SMBsplwr);
6079 if (req->wct < 1) {
6080 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6081 END_PROFILE(SMBsplwr);
6082 return;
6085 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6087 if (!check_fsp(conn, req, fsp)) {
6088 END_PROFILE(SMBsplwr);
6089 return;
6092 if (!fsp->print_file) {
6093 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6094 END_PROFILE(SMBsplwr);
6095 return;
6098 if (!CHECK_WRITE(fsp)) {
6099 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6100 END_PROFILE(SMBsplwr);
6101 return;
6104 numtowrite = SVAL(req->buf, 1);
6106 if (req->buflen < numtowrite + 3) {
6107 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6108 END_PROFILE(SMBsplwr);
6109 return;
6112 data = (const char *)req->buf + 3;
6114 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6115 reply_nterror(req, map_nt_error_from_unix(errno));
6116 END_PROFILE(SMBsplwr);
6117 return;
6120 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6122 END_PROFILE(SMBsplwr);
6123 return;
6126 /****************************************************************************
6127 Reply to a mkdir.
6128 ****************************************************************************/
6130 void reply_mkdir(struct smb_request *req)
6132 connection_struct *conn = req->conn;
6133 struct smb_filename *smb_dname = NULL;
6134 char *directory = NULL;
6135 NTSTATUS status;
6136 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
6137 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
6138 TALLOC_CTX *ctx = talloc_tos();
6140 START_PROFILE(SMBmkdir);
6142 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6143 STR_TERMINATE, &status);
6144 if (!NT_STATUS_IS_OK(status)) {
6145 reply_nterror(req, status);
6146 goto out;
6149 status = filename_convert(ctx, conn,
6150 req->flags2 & FLAGS2_DFS_PATHNAMES,
6151 directory,
6152 ucf_flags,
6153 NULL,
6154 &smb_dname);
6155 if (!NT_STATUS_IS_OK(status)) {
6156 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6157 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6158 ERRSRV, ERRbadpath);
6159 goto out;
6161 reply_nterror(req, status);
6162 goto out;
6165 status = create_directory(conn, req, smb_dname);
6167 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6169 if (!NT_STATUS_IS_OK(status)) {
6171 if (!use_nt_status()
6172 && NT_STATUS_EQUAL(status,
6173 NT_STATUS_OBJECT_NAME_COLLISION)) {
6175 * Yes, in the DOS error code case we get a
6176 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6177 * samba4 torture test.
6179 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6182 reply_nterror(req, status);
6183 goto out;
6186 reply_outbuf(req, 0, 0);
6188 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6189 out:
6190 TALLOC_FREE(smb_dname);
6191 END_PROFILE(SMBmkdir);
6192 return;
6195 /****************************************************************************
6196 Reply to a rmdir.
6197 ****************************************************************************/
6199 void reply_rmdir(struct smb_request *req)
6201 connection_struct *conn = req->conn;
6202 struct smb_filename *smb_dname = NULL;
6203 char *directory = NULL;
6204 NTSTATUS status;
6205 TALLOC_CTX *ctx = talloc_tos();
6206 files_struct *fsp = NULL;
6207 int info = 0;
6208 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
6209 struct smbd_server_connection *sconn = req->sconn;
6211 START_PROFILE(SMBrmdir);
6213 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6214 STR_TERMINATE, &status);
6215 if (!NT_STATUS_IS_OK(status)) {
6216 reply_nterror(req, status);
6217 goto out;
6220 status = filename_convert(ctx, conn,
6221 req->flags2 & FLAGS2_DFS_PATHNAMES,
6222 directory,
6223 ucf_flags,
6224 NULL,
6225 &smb_dname);
6226 if (!NT_STATUS_IS_OK(status)) {
6227 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6228 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6229 ERRSRV, ERRbadpath);
6230 goto out;
6232 reply_nterror(req, status);
6233 goto out;
6236 if (is_ntfs_stream_smb_fname(smb_dname)) {
6237 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6238 goto out;
6241 status = SMB_VFS_CREATE_FILE(
6242 conn, /* conn */
6243 req, /* req */
6244 0, /* root_dir_fid */
6245 smb_dname, /* fname */
6246 DELETE_ACCESS, /* access_mask */
6247 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6248 FILE_SHARE_DELETE),
6249 FILE_OPEN, /* create_disposition*/
6250 FILE_DIRECTORY_FILE, /* create_options */
6251 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6252 0, /* oplock_request */
6253 NULL, /* lease */
6254 0, /* allocation_size */
6255 0, /* private_flags */
6256 NULL, /* sd */
6257 NULL, /* ea_list */
6258 &fsp, /* result */
6259 &info, /* pinfo */
6260 NULL, NULL); /* create context */
6262 if (!NT_STATUS_IS_OK(status)) {
6263 if (open_was_deferred(req->xconn, req->mid)) {
6264 /* We have re-scheduled this call. */
6265 goto out;
6267 reply_nterror(req, status);
6268 goto out;
6271 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6272 if (!NT_STATUS_IS_OK(status)) {
6273 close_file(req, fsp, ERROR_CLOSE);
6274 reply_nterror(req, status);
6275 goto out;
6278 if (!set_delete_on_close(fsp, true,
6279 conn->session_info->security_token,
6280 conn->session_info->unix_token)) {
6281 close_file(req, fsp, ERROR_CLOSE);
6282 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6283 goto out;
6286 status = close_file(req, fsp, NORMAL_CLOSE);
6287 if (!NT_STATUS_IS_OK(status)) {
6288 reply_nterror(req, status);
6289 } else {
6290 reply_outbuf(req, 0, 0);
6293 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6295 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6296 out:
6297 TALLOC_FREE(smb_dname);
6298 END_PROFILE(SMBrmdir);
6299 return;
6302 /*******************************************************************
6303 Resolve wildcards in a filename rename.
6304 ********************************************************************/
6306 static bool resolve_wildcards(TALLOC_CTX *ctx,
6307 const char *name1,
6308 const char *name2,
6309 char **pp_newname)
6311 char *name2_copy = NULL;
6312 char *root1 = NULL;
6313 char *root2 = NULL;
6314 char *ext1 = NULL;
6315 char *ext2 = NULL;
6316 char *p,*p2, *pname1, *pname2;
6318 name2_copy = talloc_strdup(ctx, name2);
6319 if (!name2_copy) {
6320 return False;
6323 pname1 = strrchr_m(name1,'/');
6324 pname2 = strrchr_m(name2_copy,'/');
6326 if (!pname1 || !pname2) {
6327 return False;
6330 /* Truncate the copy of name2 at the last '/' */
6331 *pname2 = '\0';
6333 /* Now go past the '/' */
6334 pname1++;
6335 pname2++;
6337 root1 = talloc_strdup(ctx, pname1);
6338 root2 = talloc_strdup(ctx, pname2);
6340 if (!root1 || !root2) {
6341 return False;
6344 p = strrchr_m(root1,'.');
6345 if (p) {
6346 *p = 0;
6347 ext1 = talloc_strdup(ctx, p+1);
6348 } else {
6349 ext1 = talloc_strdup(ctx, "");
6351 p = strrchr_m(root2,'.');
6352 if (p) {
6353 *p = 0;
6354 ext2 = talloc_strdup(ctx, p+1);
6355 } else {
6356 ext2 = talloc_strdup(ctx, "");
6359 if (!ext1 || !ext2) {
6360 return False;
6363 p = root1;
6364 p2 = root2;
6365 while (*p2) {
6366 if (*p2 == '?') {
6367 /* Hmmm. Should this be mb-aware ? */
6368 *p2 = *p;
6369 p2++;
6370 } else if (*p2 == '*') {
6371 *p2 = '\0';
6372 root2 = talloc_asprintf(ctx, "%s%s",
6373 root2,
6375 if (!root2) {
6376 return False;
6378 break;
6379 } else {
6380 p2++;
6382 if (*p) {
6383 p++;
6387 p = ext1;
6388 p2 = ext2;
6389 while (*p2) {
6390 if (*p2 == '?') {
6391 /* Hmmm. Should this be mb-aware ? */
6392 *p2 = *p;
6393 p2++;
6394 } else if (*p2 == '*') {
6395 *p2 = '\0';
6396 ext2 = talloc_asprintf(ctx, "%s%s",
6397 ext2,
6399 if (!ext2) {
6400 return False;
6402 break;
6403 } else {
6404 p2++;
6406 if (*p) {
6407 p++;
6411 if (*ext2) {
6412 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6413 name2_copy,
6414 root2,
6415 ext2);
6416 } else {
6417 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6418 name2_copy,
6419 root2);
6422 if (!*pp_newname) {
6423 return False;
6426 return True;
6429 /****************************************************************************
6430 Ensure open files have their names updated. Updated to notify other smbd's
6431 asynchronously.
6432 ****************************************************************************/
6434 static void rename_open_files(connection_struct *conn,
6435 struct share_mode_lock *lck,
6436 struct file_id id,
6437 uint32_t orig_name_hash,
6438 const struct smb_filename *smb_fname_dst)
6440 files_struct *fsp;
6441 bool did_rename = False;
6442 NTSTATUS status;
6443 uint32_t new_name_hash = 0;
6445 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6446 fsp = file_find_di_next(fsp)) {
6447 /* fsp_name is a relative path under the fsp. To change this for other
6448 sharepaths we need to manipulate relative paths. */
6449 /* TODO - create the absolute path and manipulate the newname
6450 relative to the sharepath. */
6451 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6452 continue;
6454 if (fsp->name_hash != orig_name_hash) {
6455 continue;
6457 DEBUG(10, ("rename_open_files: renaming file %s "
6458 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6459 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6460 smb_fname_str_dbg(smb_fname_dst)));
6462 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6463 if (NT_STATUS_IS_OK(status)) {
6464 did_rename = True;
6465 new_name_hash = fsp->name_hash;
6469 if (!did_rename) {
6470 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6471 "for %s\n", file_id_string_tos(&id),
6472 smb_fname_str_dbg(smb_fname_dst)));
6475 /* Send messages to all smbd's (not ourself) that the name has changed. */
6476 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6477 orig_name_hash, new_name_hash,
6478 smb_fname_dst);
6482 /****************************************************************************
6483 We need to check if the source path is a parent directory of the destination
6484 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6485 refuse the rename with a sharing violation. Under UNIX the above call can
6486 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6487 probably need to check that the client is a Windows one before disallowing
6488 this as a UNIX client (one with UNIX extensions) can know the source is a
6489 symlink and make this decision intelligently. Found by an excellent bug
6490 report from <AndyLiebman@aol.com>.
6491 ****************************************************************************/
6493 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6494 const struct smb_filename *smb_fname_dst)
6496 const char *psrc = smb_fname_src->base_name;
6497 const char *pdst = smb_fname_dst->base_name;
6498 size_t slen;
6500 if (psrc[0] == '.' && psrc[1] == '/') {
6501 psrc += 2;
6503 if (pdst[0] == '.' && pdst[1] == '/') {
6504 pdst += 2;
6506 if ((slen = strlen(psrc)) > strlen(pdst)) {
6507 return False;
6509 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6513 * Do the notify calls from a rename
6516 static void notify_rename(connection_struct *conn, bool is_dir,
6517 const struct smb_filename *smb_fname_src,
6518 const struct smb_filename *smb_fname_dst)
6520 char *parent_dir_src = NULL;
6521 char *parent_dir_dst = NULL;
6522 uint32_t mask;
6524 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6525 : FILE_NOTIFY_CHANGE_FILE_NAME;
6527 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6528 &parent_dir_src, NULL) ||
6529 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6530 &parent_dir_dst, NULL)) {
6531 goto out;
6534 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6535 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6536 smb_fname_src->base_name);
6537 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6538 smb_fname_dst->base_name);
6540 else {
6541 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6542 smb_fname_src->base_name);
6543 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6544 smb_fname_dst->base_name);
6547 /* this is a strange one. w2k3 gives an additional event for
6548 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6549 files, but not directories */
6550 if (!is_dir) {
6551 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6552 FILE_NOTIFY_CHANGE_ATTRIBUTES
6553 |FILE_NOTIFY_CHANGE_CREATION,
6554 smb_fname_dst->base_name);
6556 out:
6557 TALLOC_FREE(parent_dir_src);
6558 TALLOC_FREE(parent_dir_dst);
6561 /****************************************************************************
6562 Returns an error if the parent directory for a filename is open in an
6563 incompatible way.
6564 ****************************************************************************/
6566 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6567 const struct smb_filename *smb_fname_dst_in)
6569 char *parent_dir = NULL;
6570 struct smb_filename smb_fname_parent;
6571 struct file_id id;
6572 files_struct *fsp = NULL;
6573 int ret;
6575 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6576 &parent_dir, NULL)) {
6577 return NT_STATUS_NO_MEMORY;
6579 ZERO_STRUCT(smb_fname_parent);
6580 smb_fname_parent.base_name = parent_dir;
6582 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6583 if (ret == -1) {
6584 return map_nt_error_from_unix(errno);
6588 * We're only checking on this smbd here, mostly good
6589 * enough.. and will pass tests.
6592 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6593 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6594 fsp = file_find_di_next(fsp)) {
6595 if (fsp->access_mask & DELETE_ACCESS) {
6596 return NT_STATUS_SHARING_VIOLATION;
6599 return NT_STATUS_OK;
6602 /****************************************************************************
6603 Rename an open file - given an fsp.
6604 ****************************************************************************/
6606 NTSTATUS rename_internals_fsp(connection_struct *conn,
6607 files_struct *fsp,
6608 const struct smb_filename *smb_fname_dst_in,
6609 uint32_t attrs,
6610 bool replace_if_exists)
6612 TALLOC_CTX *ctx = talloc_tos();
6613 struct smb_filename *smb_fname_dst = NULL;
6614 NTSTATUS status = NT_STATUS_OK;
6615 struct share_mode_lock *lck = NULL;
6616 bool dst_exists, old_is_stream, new_is_stream;
6618 status = check_name(conn, smb_fname_dst_in->base_name);
6619 if (!NT_STATUS_IS_OK(status)) {
6620 return status;
6623 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6624 if (!NT_STATUS_IS_OK(status)) {
6625 return status;
6628 /* Make a copy of the dst smb_fname structs */
6630 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6631 if (smb_fname_dst == NULL) {
6632 status = NT_STATUS_NO_MEMORY;
6633 goto out;
6637 * Check for special case with case preserving and not
6638 * case sensitive. If the new last component differs from the original
6639 * last component only by case, then we should allow
6640 * the rename (user is trying to change the case of the
6641 * filename).
6643 if (!conn->case_sensitive && conn->case_preserve &&
6644 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6645 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6646 char *fname_dst_parent = NULL;
6647 const char *fname_dst_lcomp = NULL;
6648 char *orig_lcomp_path = NULL;
6649 char *orig_lcomp_stream = NULL;
6650 bool ok = true;
6653 * Split off the last component of the processed
6654 * destination name. We will compare this to
6655 * the split components of smb_fname_dst->original_lcomp.
6657 if (!parent_dirname(ctx,
6658 smb_fname_dst->base_name,
6659 &fname_dst_parent,
6660 &fname_dst_lcomp)) {
6661 status = NT_STATUS_NO_MEMORY;
6662 goto out;
6666 * The original_lcomp component contains
6667 * the last_component of the path + stream
6668 * name (if a stream exists).
6670 * Split off the stream name so we
6671 * can check them separately.
6674 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6675 /* POSIX - no stream component. */
6676 orig_lcomp_path = talloc_strdup(ctx,
6677 smb_fname_dst->original_lcomp);
6678 if (orig_lcomp_path == NULL) {
6679 ok = false;
6681 } else {
6682 ok = split_stream_filename(ctx,
6683 smb_fname_dst->original_lcomp,
6684 &orig_lcomp_path,
6685 &orig_lcomp_stream);
6688 if (!ok) {
6689 TALLOC_FREE(fname_dst_parent);
6690 status = NT_STATUS_NO_MEMORY;
6691 goto out;
6694 /* If the base names only differ by case, use original. */
6695 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6696 char *tmp;
6698 * Replace the modified last component with the
6699 * original.
6701 if (!ISDOT(fname_dst_parent)) {
6702 tmp = talloc_asprintf(smb_fname_dst,
6703 "%s/%s",
6704 fname_dst_parent,
6705 orig_lcomp_path);
6706 } else {
6707 tmp = talloc_strdup(smb_fname_dst,
6708 orig_lcomp_path);
6710 if (tmp == NULL) {
6711 status = NT_STATUS_NO_MEMORY;
6712 TALLOC_FREE(fname_dst_parent);
6713 TALLOC_FREE(orig_lcomp_path);
6714 TALLOC_FREE(orig_lcomp_stream);
6715 goto out;
6717 TALLOC_FREE(smb_fname_dst->base_name);
6718 smb_fname_dst->base_name = tmp;
6721 /* If the stream_names only differ by case, use original. */
6722 if(!strcsequal(smb_fname_dst->stream_name,
6723 orig_lcomp_stream)) {
6724 /* Use the original stream. */
6725 char *tmp = talloc_strdup(smb_fname_dst,
6726 orig_lcomp_stream);
6727 if (tmp == NULL) {
6728 status = NT_STATUS_NO_MEMORY;
6729 TALLOC_FREE(fname_dst_parent);
6730 TALLOC_FREE(orig_lcomp_path);
6731 TALLOC_FREE(orig_lcomp_stream);
6732 goto out;
6734 TALLOC_FREE(smb_fname_dst->stream_name);
6735 smb_fname_dst->stream_name = tmp;
6737 TALLOC_FREE(fname_dst_parent);
6738 TALLOC_FREE(orig_lcomp_path);
6739 TALLOC_FREE(orig_lcomp_stream);
6743 * If the src and dest names are identical - including case,
6744 * don't do the rename, just return success.
6747 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6748 strcsequal(fsp->fsp_name->stream_name,
6749 smb_fname_dst->stream_name)) {
6750 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6751 "- returning success\n",
6752 smb_fname_str_dbg(smb_fname_dst)));
6753 status = NT_STATUS_OK;
6754 goto out;
6757 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6758 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6760 /* Return the correct error code if both names aren't streams. */
6761 if (!old_is_stream && new_is_stream) {
6762 status = NT_STATUS_OBJECT_NAME_INVALID;
6763 goto out;
6766 if (old_is_stream && !new_is_stream) {
6767 status = NT_STATUS_INVALID_PARAMETER;
6768 goto out;
6771 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6773 if(!replace_if_exists && dst_exists) {
6774 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6775 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6776 smb_fname_str_dbg(smb_fname_dst)));
6777 status = NT_STATUS_OBJECT_NAME_COLLISION;
6778 goto out;
6781 if (dst_exists) {
6782 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6783 &smb_fname_dst->st);
6784 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6785 fileid);
6786 /* The file can be open when renaming a stream */
6787 if (dst_fsp && !new_is_stream) {
6788 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6789 status = NT_STATUS_ACCESS_DENIED;
6790 goto out;
6794 /* Ensure we have a valid stat struct for the source. */
6795 status = vfs_stat_fsp(fsp);
6796 if (!NT_STATUS_IS_OK(status)) {
6797 goto out;
6800 status = can_rename(conn, fsp, attrs);
6802 if (!NT_STATUS_IS_OK(status)) {
6803 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6804 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6805 smb_fname_str_dbg(smb_fname_dst)));
6806 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6807 status = NT_STATUS_ACCESS_DENIED;
6808 goto out;
6811 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6812 status = NT_STATUS_ACCESS_DENIED;
6815 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6818 * We have the file open ourselves, so not being able to get the
6819 * corresponding share mode lock is a fatal error.
6822 SMB_ASSERT(lck != NULL);
6824 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6825 uint32_t create_options = fsp->fh->private_options;
6827 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6828 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6829 smb_fname_str_dbg(smb_fname_dst)));
6831 if (!fsp->is_directory &&
6832 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6833 (lp_map_archive(SNUM(conn)) ||
6834 lp_store_dos_attributes(SNUM(conn)))) {
6835 /* We must set the archive bit on the newly
6836 renamed file. */
6837 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6838 uint32_t old_dosmode = dos_mode(conn,
6839 smb_fname_dst);
6840 file_set_dosmode(conn,
6841 smb_fname_dst,
6842 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6843 NULL,
6844 true);
6848 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6849 smb_fname_dst);
6851 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6852 smb_fname_dst);
6855 * A rename acts as a new file create w.r.t. allowing an initial delete
6856 * on close, probably because in Windows there is a new handle to the
6857 * new file. If initial delete on close was requested but not
6858 * originally set, we need to set it here. This is probably not 100% correct,
6859 * but will work for the CIFSFS client which in non-posix mode
6860 * depends on these semantics. JRA.
6863 if (create_options & FILE_DELETE_ON_CLOSE) {
6864 status = can_set_delete_on_close(fsp, 0);
6866 if (NT_STATUS_IS_OK(status)) {
6867 /* Note that here we set the *inital* delete on close flag,
6868 * not the regular one. The magic gets handled in close. */
6869 fsp->initial_delete_on_close = True;
6872 TALLOC_FREE(lck);
6873 status = NT_STATUS_OK;
6874 goto out;
6877 TALLOC_FREE(lck);
6879 if (errno == ENOTDIR || errno == EISDIR) {
6880 status = NT_STATUS_OBJECT_NAME_COLLISION;
6881 } else {
6882 status = map_nt_error_from_unix(errno);
6885 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6886 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6887 smb_fname_str_dbg(smb_fname_dst)));
6889 out:
6890 TALLOC_FREE(smb_fname_dst);
6892 return status;
6895 /****************************************************************************
6896 The guts of the rename command, split out so it may be called by the NT SMB
6897 code.
6898 ****************************************************************************/
6900 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6901 connection_struct *conn,
6902 struct smb_request *req,
6903 struct smb_filename *smb_fname_src,
6904 struct smb_filename *smb_fname_dst,
6905 uint32_t attrs,
6906 bool replace_if_exists,
6907 bool src_has_wild,
6908 bool dest_has_wild,
6909 uint32_t access_mask)
6911 char *fname_src_dir = NULL;
6912 struct smb_filename *smb_fname_src_dir = NULL;
6913 char *fname_src_mask = NULL;
6914 int count=0;
6915 NTSTATUS status = NT_STATUS_OK;
6916 struct smb_Dir *dir_hnd = NULL;
6917 const char *dname = NULL;
6918 char *talloced = NULL;
6919 long offset = 0;
6920 int create_options = 0;
6921 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6922 int rc;
6925 * Split the old name into directory and last component
6926 * strings. Note that unix_convert may have stripped off a
6927 * leading ./ from both name and newname if the rename is
6928 * at the root of the share. We need to make sure either both
6929 * name and newname contain a / character or neither of them do
6930 * as this is checked in resolve_wildcards().
6933 /* Split up the directory from the filename/mask. */
6934 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6935 &fname_src_dir, &fname_src_mask);
6936 if (!NT_STATUS_IS_OK(status)) {
6937 status = NT_STATUS_NO_MEMORY;
6938 goto out;
6942 * We should only check the mangled cache
6943 * here if unix_convert failed. This means
6944 * that the path in 'mask' doesn't exist
6945 * on the file system and so we need to look
6946 * for a possible mangle. This patch from
6947 * Tine Smukavec <valentin.smukavec@hermes.si>.
6950 if (!VALID_STAT(smb_fname_src->st) &&
6951 mangle_is_mangled(fname_src_mask, conn->params)) {
6952 char *new_mask = NULL;
6953 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6954 conn->params);
6955 if (new_mask) {
6956 TALLOC_FREE(fname_src_mask);
6957 fname_src_mask = new_mask;
6961 if (!src_has_wild) {
6962 files_struct *fsp;
6965 * Only one file needs to be renamed. Append the mask back
6966 * onto the directory.
6968 TALLOC_FREE(smb_fname_src->base_name);
6969 if (ISDOT(fname_src_dir)) {
6970 /* Ensure we use canonical names on open. */
6971 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6972 "%s",
6973 fname_src_mask);
6974 } else {
6975 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6976 "%s/%s",
6977 fname_src_dir,
6978 fname_src_mask);
6980 if (!smb_fname_src->base_name) {
6981 status = NT_STATUS_NO_MEMORY;
6982 goto out;
6985 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6986 "case_preserve = %d, short case preserve = %d, "
6987 "directory = %s, newname = %s, "
6988 "last_component_dest = %s\n",
6989 conn->case_sensitive, conn->case_preserve,
6990 conn->short_case_preserve,
6991 smb_fname_str_dbg(smb_fname_src),
6992 smb_fname_str_dbg(smb_fname_dst),
6993 smb_fname_dst->original_lcomp));
6995 /* The dest name still may have wildcards. */
6996 if (dest_has_wild) {
6997 char *fname_dst_mod = NULL;
6998 if (!resolve_wildcards(smb_fname_dst,
6999 smb_fname_src->base_name,
7000 smb_fname_dst->base_name,
7001 &fname_dst_mod)) {
7002 DEBUG(6, ("rename_internals: resolve_wildcards "
7003 "%s %s failed\n",
7004 smb_fname_src->base_name,
7005 smb_fname_dst->base_name));
7006 status = NT_STATUS_NO_MEMORY;
7007 goto out;
7009 TALLOC_FREE(smb_fname_dst->base_name);
7010 smb_fname_dst->base_name = fname_dst_mod;
7013 ZERO_STRUCT(smb_fname_src->st);
7014 if (posix_pathnames) {
7015 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7016 } else {
7017 rc = SMB_VFS_STAT(conn, smb_fname_src);
7019 if (rc == -1) {
7020 status = map_nt_error_from_unix_common(errno);
7021 goto out;
7024 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7025 create_options |= FILE_DIRECTORY_FILE;
7028 status = SMB_VFS_CREATE_FILE(
7029 conn, /* conn */
7030 req, /* req */
7031 0, /* root_dir_fid */
7032 smb_fname_src, /* fname */
7033 access_mask, /* access_mask */
7034 (FILE_SHARE_READ | /* share_access */
7035 FILE_SHARE_WRITE),
7036 FILE_OPEN, /* create_disposition*/
7037 create_options, /* create_options */
7038 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7039 0, /* oplock_request */
7040 NULL, /* lease */
7041 0, /* allocation_size */
7042 0, /* private_flags */
7043 NULL, /* sd */
7044 NULL, /* ea_list */
7045 &fsp, /* result */
7046 NULL, /* pinfo */
7047 NULL, NULL); /* create context */
7049 if (!NT_STATUS_IS_OK(status)) {
7050 DEBUG(3, ("Could not open rename source %s: %s\n",
7051 smb_fname_str_dbg(smb_fname_src),
7052 nt_errstr(status)));
7053 goto out;
7056 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7057 attrs, replace_if_exists);
7059 close_file(req, fsp, NORMAL_CLOSE);
7061 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7062 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7063 smb_fname_str_dbg(smb_fname_dst)));
7065 goto out;
7069 * Wildcards - process each file that matches.
7071 if (strequal(fname_src_mask, "????????.???")) {
7072 TALLOC_FREE(fname_src_mask);
7073 fname_src_mask = talloc_strdup(ctx, "*");
7074 if (!fname_src_mask) {
7075 status = NT_STATUS_NO_MEMORY;
7076 goto out;
7080 status = check_name(conn, fname_src_dir);
7081 if (!NT_STATUS_IS_OK(status)) {
7082 goto out;
7085 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7086 fname_src_dir,
7087 NULL,
7088 NULL,
7089 smb_fname_src->flags);
7090 if (smb_fname_src_dir == NULL) {
7091 status = NT_STATUS_NO_MEMORY;
7092 goto out;
7095 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7096 attrs);
7097 if (dir_hnd == NULL) {
7098 status = map_nt_error_from_unix(errno);
7099 goto out;
7102 status = NT_STATUS_NO_SUCH_FILE;
7104 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7105 * - gentest fix. JRA
7108 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7109 &talloced))) {
7110 files_struct *fsp = NULL;
7111 char *destname = NULL;
7112 bool sysdir_entry = False;
7114 /* Quick check for "." and ".." */
7115 if (ISDOT(dname) || ISDOTDOT(dname)) {
7116 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7117 sysdir_entry = True;
7118 } else {
7119 TALLOC_FREE(talloced);
7120 continue;
7124 if (!is_visible_file(conn, fname_src_dir, dname,
7125 &smb_fname_src->st, false)) {
7126 TALLOC_FREE(talloced);
7127 continue;
7130 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7131 TALLOC_FREE(talloced);
7132 continue;
7135 if (sysdir_entry) {
7136 status = NT_STATUS_OBJECT_NAME_INVALID;
7137 break;
7140 TALLOC_FREE(smb_fname_src->base_name);
7141 if (ISDOT(fname_src_dir)) {
7142 /* Ensure we use canonical names on open. */
7143 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7144 "%s",
7145 dname);
7146 } else {
7147 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7148 "%s/%s",
7149 fname_src_dir,
7150 dname);
7152 if (!smb_fname_src->base_name) {
7153 status = NT_STATUS_NO_MEMORY;
7154 goto out;
7157 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7158 smb_fname_dst->base_name,
7159 &destname)) {
7160 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7161 smb_fname_src->base_name, destname));
7162 TALLOC_FREE(talloced);
7163 continue;
7165 if (!destname) {
7166 status = NT_STATUS_NO_MEMORY;
7167 goto out;
7170 TALLOC_FREE(smb_fname_dst->base_name);
7171 smb_fname_dst->base_name = destname;
7173 ZERO_STRUCT(smb_fname_src->st);
7174 if (posix_pathnames) {
7175 SMB_VFS_LSTAT(conn, smb_fname_src);
7176 } else {
7177 SMB_VFS_STAT(conn, smb_fname_src);
7180 create_options = 0;
7182 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7183 create_options |= FILE_DIRECTORY_FILE;
7186 status = SMB_VFS_CREATE_FILE(
7187 conn, /* conn */
7188 req, /* req */
7189 0, /* root_dir_fid */
7190 smb_fname_src, /* fname */
7191 access_mask, /* access_mask */
7192 (FILE_SHARE_READ | /* share_access */
7193 FILE_SHARE_WRITE),
7194 FILE_OPEN, /* create_disposition*/
7195 create_options, /* create_options */
7196 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7197 0, /* oplock_request */
7198 NULL, /* lease */
7199 0, /* allocation_size */
7200 0, /* private_flags */
7201 NULL, /* sd */
7202 NULL, /* ea_list */
7203 &fsp, /* result */
7204 NULL, /* pinfo */
7205 NULL, NULL); /* create context */
7207 if (!NT_STATUS_IS_OK(status)) {
7208 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7209 "returned %s rename %s -> %s\n",
7210 nt_errstr(status),
7211 smb_fname_str_dbg(smb_fname_src),
7212 smb_fname_str_dbg(smb_fname_dst)));
7213 break;
7216 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7217 dname);
7218 if (!smb_fname_dst->original_lcomp) {
7219 status = NT_STATUS_NO_MEMORY;
7220 goto out;
7223 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7224 attrs, replace_if_exists);
7226 close_file(req, fsp, NORMAL_CLOSE);
7228 if (!NT_STATUS_IS_OK(status)) {
7229 DEBUG(3, ("rename_internals_fsp returned %s for "
7230 "rename %s -> %s\n", nt_errstr(status),
7231 smb_fname_str_dbg(smb_fname_src),
7232 smb_fname_str_dbg(smb_fname_dst)));
7233 break;
7236 count++;
7238 DEBUG(3,("rename_internals: doing rename on %s -> "
7239 "%s\n", smb_fname_str_dbg(smb_fname_src),
7240 smb_fname_str_dbg(smb_fname_src)));
7241 TALLOC_FREE(talloced);
7243 TALLOC_FREE(dir_hnd);
7245 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7246 status = map_nt_error_from_unix(errno);
7249 out:
7250 TALLOC_FREE(talloced);
7251 TALLOC_FREE(smb_fname_src_dir);
7252 TALLOC_FREE(fname_src_dir);
7253 TALLOC_FREE(fname_src_mask);
7254 return status;
7257 /****************************************************************************
7258 Reply to a mv.
7259 ****************************************************************************/
7261 void reply_mv(struct smb_request *req)
7263 connection_struct *conn = req->conn;
7264 char *name = NULL;
7265 char *newname = NULL;
7266 const char *p;
7267 uint32_t attrs;
7268 NTSTATUS status;
7269 bool src_has_wcard = False;
7270 bool dest_has_wcard = False;
7271 TALLOC_CTX *ctx = talloc_tos();
7272 struct smb_filename *smb_fname_src = NULL;
7273 struct smb_filename *smb_fname_dst = NULL;
7274 uint32_t src_ucf_flags = (req->posix_pathnames ?
7275 (UCF_UNIX_NAME_LOOKUP|UCF_POSIX_PATHNAMES) :
7276 UCF_COND_ALLOW_WCARD_LCOMP);
7277 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP |
7278 (req->posix_pathnames ? UCF_POSIX_PATHNAMES :
7279 UCF_COND_ALLOW_WCARD_LCOMP);
7280 bool stream_rename = false;
7282 START_PROFILE(SMBmv);
7284 if (req->wct < 1) {
7285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7286 goto out;
7289 attrs = SVAL(req->vwv+0, 0);
7291 p = (const char *)req->buf + 1;
7292 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7293 &status, &src_has_wcard);
7294 if (!NT_STATUS_IS_OK(status)) {
7295 reply_nterror(req, status);
7296 goto out;
7298 p++;
7299 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7300 &status, &dest_has_wcard);
7301 if (!NT_STATUS_IS_OK(status)) {
7302 reply_nterror(req, status);
7303 goto out;
7306 if (!req->posix_pathnames) {
7307 /* The newname must begin with a ':' if the
7308 name contains a ':'. */
7309 if (strchr_m(name, ':')) {
7310 if (newname[0] != ':') {
7311 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7312 goto out;
7314 stream_rename = true;
7318 status = filename_convert(ctx,
7319 conn,
7320 req->flags2 & FLAGS2_DFS_PATHNAMES,
7321 name,
7322 src_ucf_flags,
7323 &src_has_wcard,
7324 &smb_fname_src);
7326 if (!NT_STATUS_IS_OK(status)) {
7327 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7328 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7329 ERRSRV, ERRbadpath);
7330 goto out;
7332 reply_nterror(req, status);
7333 goto out;
7336 status = filename_convert(ctx,
7337 conn,
7338 req->flags2 & FLAGS2_DFS_PATHNAMES,
7339 newname,
7340 dst_ucf_flags,
7341 &dest_has_wcard,
7342 &smb_fname_dst);
7344 if (!NT_STATUS_IS_OK(status)) {
7345 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7346 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7347 ERRSRV, ERRbadpath);
7348 goto out;
7350 reply_nterror(req, status);
7351 goto out;
7354 if (stream_rename) {
7355 /* smb_fname_dst->base_name must be the same as
7356 smb_fname_src->base_name. */
7357 TALLOC_FREE(smb_fname_dst->base_name);
7358 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7359 smb_fname_src->base_name);
7360 if (!smb_fname_dst->base_name) {
7361 reply_nterror(req, NT_STATUS_NO_MEMORY);
7362 goto out;
7366 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7367 smb_fname_str_dbg(smb_fname_dst)));
7369 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7370 attrs, False, src_has_wcard, dest_has_wcard,
7371 DELETE_ACCESS);
7372 if (!NT_STATUS_IS_OK(status)) {
7373 if (open_was_deferred(req->xconn, req->mid)) {
7374 /* We have re-scheduled this call. */
7375 goto out;
7377 reply_nterror(req, status);
7378 goto out;
7381 reply_outbuf(req, 0, 0);
7382 out:
7383 TALLOC_FREE(smb_fname_src);
7384 TALLOC_FREE(smb_fname_dst);
7385 END_PROFILE(SMBmv);
7386 return;
7389 /*******************************************************************
7390 Copy a file as part of a reply_copy.
7391 ******************************************************************/
7394 * TODO: check error codes on all callers
7397 NTSTATUS copy_file(TALLOC_CTX *ctx,
7398 connection_struct *conn,
7399 struct smb_filename *smb_fname_src,
7400 struct smb_filename *smb_fname_dst,
7401 int ofun,
7402 int count,
7403 bool target_is_directory)
7405 struct smb_filename *smb_fname_dst_tmp = NULL;
7406 off_t ret=-1;
7407 files_struct *fsp1,*fsp2;
7408 uint32_t dosattrs;
7409 uint32_t new_create_disposition;
7410 NTSTATUS status;
7413 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7414 if (smb_fname_dst_tmp == NULL) {
7415 return NT_STATUS_NO_MEMORY;
7419 * If the target is a directory, extract the last component from the
7420 * src filename and append it to the dst filename
7422 if (target_is_directory) {
7423 const char *p;
7425 /* dest/target can't be a stream if it's a directory. */
7426 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7428 p = strrchr_m(smb_fname_src->base_name,'/');
7429 if (p) {
7430 p++;
7431 } else {
7432 p = smb_fname_src->base_name;
7434 smb_fname_dst_tmp->base_name =
7435 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7437 if (!smb_fname_dst_tmp->base_name) {
7438 status = NT_STATUS_NO_MEMORY;
7439 goto out;
7443 status = vfs_file_exist(conn, smb_fname_src);
7444 if (!NT_STATUS_IS_OK(status)) {
7445 goto out;
7448 if (!target_is_directory && count) {
7449 new_create_disposition = FILE_OPEN;
7450 } else {
7451 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7452 0, ofun,
7453 NULL, NULL,
7454 &new_create_disposition,
7455 NULL,
7456 NULL)) {
7457 status = NT_STATUS_INVALID_PARAMETER;
7458 goto out;
7462 /* Open the src file for reading. */
7463 status = SMB_VFS_CREATE_FILE(
7464 conn, /* conn */
7465 NULL, /* req */
7466 0, /* root_dir_fid */
7467 smb_fname_src, /* fname */
7468 FILE_GENERIC_READ, /* access_mask */
7469 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7470 FILE_OPEN, /* create_disposition*/
7471 0, /* create_options */
7472 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7473 INTERNAL_OPEN_ONLY, /* oplock_request */
7474 NULL, /* lease */
7475 0, /* allocation_size */
7476 0, /* private_flags */
7477 NULL, /* sd */
7478 NULL, /* ea_list */
7479 &fsp1, /* result */
7480 NULL, /* psbuf */
7481 NULL, NULL); /* create context */
7483 if (!NT_STATUS_IS_OK(status)) {
7484 goto out;
7487 dosattrs = dos_mode(conn, smb_fname_src);
7489 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7490 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7493 /* Open the dst file for writing. */
7494 status = SMB_VFS_CREATE_FILE(
7495 conn, /* conn */
7496 NULL, /* req */
7497 0, /* root_dir_fid */
7498 smb_fname_dst, /* fname */
7499 FILE_GENERIC_WRITE, /* access_mask */
7500 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7501 new_create_disposition, /* create_disposition*/
7502 0, /* create_options */
7503 dosattrs, /* file_attributes */
7504 INTERNAL_OPEN_ONLY, /* oplock_request */
7505 NULL, /* lease */
7506 0, /* allocation_size */
7507 0, /* private_flags */
7508 NULL, /* sd */
7509 NULL, /* ea_list */
7510 &fsp2, /* result */
7511 NULL, /* psbuf */
7512 NULL, NULL); /* create context */
7514 if (!NT_STATUS_IS_OK(status)) {
7515 close_file(NULL, fsp1, ERROR_CLOSE);
7516 goto out;
7519 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7520 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7521 if (ret == -1) {
7522 DEBUG(0, ("error - vfs lseek returned error %s\n",
7523 strerror(errno)));
7524 status = map_nt_error_from_unix(errno);
7525 close_file(NULL, fsp1, ERROR_CLOSE);
7526 close_file(NULL, fsp2, ERROR_CLOSE);
7527 goto out;
7531 /* Do the actual copy. */
7532 if (smb_fname_src->st.st_ex_size) {
7533 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7534 } else {
7535 ret = 0;
7538 close_file(NULL, fsp1, NORMAL_CLOSE);
7540 /* Ensure the modtime is set correctly on the destination file. */
7541 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7544 * As we are opening fsp1 read-only we only expect
7545 * an error on close on fsp2 if we are out of space.
7546 * Thus we don't look at the error return from the
7547 * close of fsp1.
7549 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7551 if (!NT_STATUS_IS_OK(status)) {
7552 goto out;
7555 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7556 status = NT_STATUS_DISK_FULL;
7557 goto out;
7560 status = NT_STATUS_OK;
7562 out:
7563 TALLOC_FREE(smb_fname_dst_tmp);
7564 return status;
7567 /****************************************************************************
7568 Reply to a file copy.
7569 ****************************************************************************/
7571 void reply_copy(struct smb_request *req)
7573 connection_struct *conn = req->conn;
7574 struct smb_filename *smb_fname_src = NULL;
7575 struct smb_filename *smb_fname_src_dir = NULL;
7576 struct smb_filename *smb_fname_dst = NULL;
7577 char *fname_src = NULL;
7578 char *fname_dst = NULL;
7579 char *fname_src_mask = NULL;
7580 char *fname_src_dir = NULL;
7581 const char *p;
7582 int count=0;
7583 int error = ERRnoaccess;
7584 int tid2;
7585 int ofun;
7586 int flags;
7587 bool target_is_directory=False;
7588 bool source_has_wild = False;
7589 bool dest_has_wild = False;
7590 NTSTATUS status;
7591 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7592 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
7593 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7594 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
7595 TALLOC_CTX *ctx = talloc_tos();
7597 START_PROFILE(SMBcopy);
7599 if (req->wct < 3) {
7600 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7601 goto out;
7604 tid2 = SVAL(req->vwv+0, 0);
7605 ofun = SVAL(req->vwv+1, 0);
7606 flags = SVAL(req->vwv+2, 0);
7608 p = (const char *)req->buf;
7609 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7610 &status, &source_has_wild);
7611 if (!NT_STATUS_IS_OK(status)) {
7612 reply_nterror(req, status);
7613 goto out;
7615 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7616 &status, &dest_has_wild);
7617 if (!NT_STATUS_IS_OK(status)) {
7618 reply_nterror(req, status);
7619 goto out;
7622 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7624 if (tid2 != conn->cnum) {
7625 /* can't currently handle inter share copies XXXX */
7626 DEBUG(3,("Rejecting inter-share copy\n"));
7627 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7628 goto out;
7631 status = filename_convert(ctx, conn,
7632 req->flags2 & FLAGS2_DFS_PATHNAMES,
7633 fname_src,
7634 ucf_flags_src,
7635 &source_has_wild,
7636 &smb_fname_src);
7637 if (!NT_STATUS_IS_OK(status)) {
7638 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7639 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7640 ERRSRV, ERRbadpath);
7641 goto out;
7643 reply_nterror(req, status);
7644 goto out;
7647 status = filename_convert(ctx, conn,
7648 req->flags2 & FLAGS2_DFS_PATHNAMES,
7649 fname_dst,
7650 ucf_flags_dst,
7651 &dest_has_wild,
7652 &smb_fname_dst);
7653 if (!NT_STATUS_IS_OK(status)) {
7654 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7655 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7656 ERRSRV, ERRbadpath);
7657 goto out;
7659 reply_nterror(req, status);
7660 goto out;
7663 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7665 if ((flags&1) && target_is_directory) {
7666 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7667 goto out;
7670 if ((flags&2) && !target_is_directory) {
7671 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7672 goto out;
7675 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7676 /* wants a tree copy! XXXX */
7677 DEBUG(3,("Rejecting tree copy\n"));
7678 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7679 goto out;
7682 /* Split up the directory from the filename/mask. */
7683 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7684 &fname_src_dir, &fname_src_mask);
7685 if (!NT_STATUS_IS_OK(status)) {
7686 reply_nterror(req, NT_STATUS_NO_MEMORY);
7687 goto out;
7691 * We should only check the mangled cache
7692 * here if unix_convert failed. This means
7693 * that the path in 'mask' doesn't exist
7694 * on the file system and so we need to look
7695 * for a possible mangle. This patch from
7696 * Tine Smukavec <valentin.smukavec@hermes.si>.
7698 if (!VALID_STAT(smb_fname_src->st) &&
7699 mangle_is_mangled(fname_src_mask, conn->params)) {
7700 char *new_mask = NULL;
7701 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7702 &new_mask, conn->params);
7704 /* Use demangled name if one was successfully found. */
7705 if (new_mask) {
7706 TALLOC_FREE(fname_src_mask);
7707 fname_src_mask = new_mask;
7711 if (!source_has_wild) {
7714 * Only one file needs to be copied. Append the mask back onto
7715 * the directory.
7717 TALLOC_FREE(smb_fname_src->base_name);
7718 if (ISDOT(fname_src_dir)) {
7719 /* Ensure we use canonical names on open. */
7720 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7721 "%s",
7722 fname_src_mask);
7723 } else {
7724 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7725 "%s/%s",
7726 fname_src_dir,
7727 fname_src_mask);
7729 if (!smb_fname_src->base_name) {
7730 reply_nterror(req, NT_STATUS_NO_MEMORY);
7731 goto out;
7734 if (dest_has_wild) {
7735 char *fname_dst_mod = NULL;
7736 if (!resolve_wildcards(smb_fname_dst,
7737 smb_fname_src->base_name,
7738 smb_fname_dst->base_name,
7739 &fname_dst_mod)) {
7740 reply_nterror(req, NT_STATUS_NO_MEMORY);
7741 goto out;
7743 TALLOC_FREE(smb_fname_dst->base_name);
7744 smb_fname_dst->base_name = fname_dst_mod;
7747 status = check_name(conn, smb_fname_src->base_name);
7748 if (!NT_STATUS_IS_OK(status)) {
7749 reply_nterror(req, status);
7750 goto out;
7753 status = check_name(conn, smb_fname_dst->base_name);
7754 if (!NT_STATUS_IS_OK(status)) {
7755 reply_nterror(req, status);
7756 goto out;
7759 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7760 ofun, count, target_is_directory);
7762 if(!NT_STATUS_IS_OK(status)) {
7763 reply_nterror(req, status);
7764 goto out;
7765 } else {
7766 count++;
7768 } else {
7769 struct smb_Dir *dir_hnd = NULL;
7770 const char *dname = NULL;
7771 char *talloced = NULL;
7772 long offset = 0;
7775 * There is a wildcard that requires us to actually read the
7776 * src dir and copy each file matching the mask to the dst.
7777 * Right now streams won't be copied, but this could
7778 * presumably be added with a nested loop for reach dir entry.
7780 SMB_ASSERT(!smb_fname_src->stream_name);
7781 SMB_ASSERT(!smb_fname_dst->stream_name);
7783 smb_fname_src->stream_name = NULL;
7784 smb_fname_dst->stream_name = NULL;
7786 if (strequal(fname_src_mask,"????????.???")) {
7787 TALLOC_FREE(fname_src_mask);
7788 fname_src_mask = talloc_strdup(ctx, "*");
7789 if (!fname_src_mask) {
7790 reply_nterror(req, NT_STATUS_NO_MEMORY);
7791 goto out;
7795 status = check_name(conn, fname_src_dir);
7796 if (!NT_STATUS_IS_OK(status)) {
7797 reply_nterror(req, status);
7798 goto out;
7801 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7802 fname_src_dir,
7803 NULL,
7804 NULL,
7805 smb_fname_src->flags);
7806 if (smb_fname_src_dir == NULL) {
7807 reply_nterror(req, NT_STATUS_NO_MEMORY);
7808 goto out;
7811 dir_hnd = OpenDir(ctx,
7812 conn,
7813 smb_fname_src_dir,
7814 fname_src_mask,
7816 if (dir_hnd == NULL) {
7817 status = map_nt_error_from_unix(errno);
7818 reply_nterror(req, status);
7819 goto out;
7822 error = ERRbadfile;
7824 /* Iterate over the src dir copying each entry to the dst. */
7825 while ((dname = ReadDirName(dir_hnd, &offset,
7826 &smb_fname_src->st, &talloced))) {
7827 char *destname = NULL;
7829 if (ISDOT(dname) || ISDOTDOT(dname)) {
7830 TALLOC_FREE(talloced);
7831 continue;
7834 if (!is_visible_file(conn, fname_src_dir, dname,
7835 &smb_fname_src->st, false)) {
7836 TALLOC_FREE(talloced);
7837 continue;
7840 if(!mask_match(dname, fname_src_mask,
7841 conn->case_sensitive)) {
7842 TALLOC_FREE(talloced);
7843 continue;
7846 error = ERRnoaccess;
7848 /* Get the src smb_fname struct setup. */
7849 TALLOC_FREE(smb_fname_src->base_name);
7850 if (ISDOT(fname_src_dir)) {
7851 /* Ensure we use canonical names on open. */
7852 smb_fname_src->base_name =
7853 talloc_asprintf(smb_fname_src, "%s",
7854 dname);
7855 } else {
7856 smb_fname_src->base_name =
7857 talloc_asprintf(smb_fname_src, "%s/%s",
7858 fname_src_dir, dname);
7861 if (!smb_fname_src->base_name) {
7862 TALLOC_FREE(dir_hnd);
7863 TALLOC_FREE(talloced);
7864 reply_nterror(req, NT_STATUS_NO_MEMORY);
7865 goto out;
7868 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7869 smb_fname_dst->base_name,
7870 &destname)) {
7871 TALLOC_FREE(talloced);
7872 continue;
7874 if (!destname) {
7875 TALLOC_FREE(dir_hnd);
7876 TALLOC_FREE(talloced);
7877 reply_nterror(req, NT_STATUS_NO_MEMORY);
7878 goto out;
7881 TALLOC_FREE(smb_fname_dst->base_name);
7882 smb_fname_dst->base_name = destname;
7884 status = check_name(conn, smb_fname_src->base_name);
7885 if (!NT_STATUS_IS_OK(status)) {
7886 TALLOC_FREE(dir_hnd);
7887 TALLOC_FREE(talloced);
7888 reply_nterror(req, status);
7889 goto out;
7892 status = check_name(conn, smb_fname_dst->base_name);
7893 if (!NT_STATUS_IS_OK(status)) {
7894 TALLOC_FREE(dir_hnd);
7895 TALLOC_FREE(talloced);
7896 reply_nterror(req, status);
7897 goto out;
7900 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7901 smb_fname_src->base_name,
7902 smb_fname_dst->base_name));
7904 status = copy_file(ctx, conn, smb_fname_src,
7905 smb_fname_dst, ofun, count,
7906 target_is_directory);
7907 if (NT_STATUS_IS_OK(status)) {
7908 count++;
7911 TALLOC_FREE(talloced);
7913 TALLOC_FREE(dir_hnd);
7916 if (count == 0) {
7917 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7918 goto out;
7921 reply_outbuf(req, 1, 0);
7922 SSVAL(req->outbuf,smb_vwv0,count);
7923 out:
7924 TALLOC_FREE(smb_fname_src);
7925 TALLOC_FREE(smb_fname_src_dir);
7926 TALLOC_FREE(smb_fname_dst);
7927 TALLOC_FREE(fname_src);
7928 TALLOC_FREE(fname_dst);
7929 TALLOC_FREE(fname_src_mask);
7930 TALLOC_FREE(fname_src_dir);
7932 END_PROFILE(SMBcopy);
7933 return;
7936 #undef DBGC_CLASS
7937 #define DBGC_CLASS DBGC_LOCKING
7939 /****************************************************************************
7940 Get a lock pid, dealing with large count requests.
7941 ****************************************************************************/
7943 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7944 bool large_file_format)
7946 if(!large_file_format)
7947 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7948 else
7949 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7952 /****************************************************************************
7953 Get a lock count, dealing with large count requests.
7954 ****************************************************************************/
7956 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7957 bool large_file_format)
7959 uint64_t count = 0;
7961 if(!large_file_format) {
7962 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7963 } else {
7965 * No BVAL, this is reversed!
7967 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7968 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7971 return count;
7974 /****************************************************************************
7975 Get a lock offset, dealing with large offset requests.
7976 ****************************************************************************/
7978 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7979 bool large_file_format)
7981 uint64_t offset = 0;
7983 if(!large_file_format) {
7984 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7985 } else {
7987 * No BVAL, this is reversed!
7989 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7990 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7993 return offset;
7996 NTSTATUS smbd_do_locking(struct smb_request *req,
7997 files_struct *fsp,
7998 uint8_t type,
7999 int32_t timeout,
8000 uint16_t num_locks,
8001 struct smbd_lock_element *locks,
8002 bool *async)
8004 connection_struct *conn = req->conn;
8005 int i;
8006 NTSTATUS status = NT_STATUS_OK;
8008 *async = false;
8010 /* Setup the timeout in seconds. */
8012 if (!lp_blocking_locks(SNUM(conn))) {
8013 timeout = 0;
8016 for(i = 0; i < (int)num_locks; i++) {
8017 struct smbd_lock_element *e = &locks[i];
8019 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8020 "%llu, file %s timeout = %d\n",
8021 (double)e->offset,
8022 (double)e->count,
8023 (unsigned long long)e->smblctx,
8024 fsp_str_dbg(fsp),
8025 (int)timeout));
8027 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8028 struct blocking_lock_record *blr = NULL;
8030 if (num_locks > 1) {
8032 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8033 * if the lock vector contains one entry. When given multiple cancel
8034 * requests in a single PDU we expect the server to return an
8035 * error. Windows servers seem to accept the request but only
8036 * cancel the first lock.
8037 * JRA - Do what Windows does (tm) :-).
8040 #if 0
8041 /* MS-CIFS (2.2.4.32.1) behavior. */
8042 return NT_STATUS_DOS(ERRDOS,
8043 ERRcancelviolation);
8044 #else
8045 /* Windows behavior. */
8046 if (i != 0) {
8047 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8048 "cancel request\n"));
8049 continue;
8051 #endif
8054 if (lp_blocking_locks(SNUM(conn))) {
8056 /* Schedule a message to ourselves to
8057 remove the blocking lock record and
8058 return the right error. */
8060 blr = blocking_lock_cancel_smb1(fsp,
8061 e->smblctx,
8062 e->offset,
8063 e->count,
8064 WINDOWS_LOCK,
8065 type,
8066 NT_STATUS_FILE_LOCK_CONFLICT);
8067 if (blr == NULL) {
8068 return NT_STATUS_DOS(
8069 ERRDOS,
8070 ERRcancelviolation);
8073 /* Remove a matching pending lock. */
8074 status = do_lock_cancel(fsp,
8075 e->smblctx,
8076 e->count,
8077 e->offset,
8078 WINDOWS_LOCK);
8079 } else {
8080 bool blocking_lock = timeout ? true : false;
8081 bool defer_lock = false;
8082 struct byte_range_lock *br_lck;
8083 uint64_t block_smblctx;
8085 br_lck = do_lock(req->sconn->msg_ctx,
8086 fsp,
8087 e->smblctx,
8088 e->count,
8089 e->offset,
8090 e->brltype,
8091 WINDOWS_LOCK,
8092 blocking_lock,
8093 &status,
8094 &block_smblctx);
8096 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8097 /* Windows internal resolution for blocking locks seems
8098 to be about 200ms... Don't wait for less than that. JRA. */
8099 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8100 timeout = lp_lock_spin_time();
8102 defer_lock = true;
8105 /* If a lock sent with timeout of zero would fail, and
8106 * this lock has been requested multiple times,
8107 * according to brl_lock_failed() we convert this
8108 * request to a blocking lock with a timeout of between
8109 * 150 - 300 milliseconds.
8111 * If lp_lock_spin_time() has been set to 0, we skip
8112 * this blocking retry and fail immediately.
8114 * Replacement for do_lock_spin(). JRA. */
8116 if (!req->sconn->using_smb2 &&
8117 br_lck && lp_blocking_locks(SNUM(conn)) &&
8118 lp_lock_spin_time() && !blocking_lock &&
8119 NT_STATUS_EQUAL((status),
8120 NT_STATUS_FILE_LOCK_CONFLICT))
8122 defer_lock = true;
8123 timeout = lp_lock_spin_time();
8126 if (br_lck && defer_lock) {
8128 * A blocking lock was requested. Package up
8129 * this smb into a queued request and push it
8130 * onto the blocking lock queue.
8132 if(push_blocking_lock_request(br_lck,
8133 req,
8134 fsp,
8135 timeout,
8137 e->smblctx,
8138 e->brltype,
8139 WINDOWS_LOCK,
8140 e->offset,
8141 e->count,
8142 block_smblctx)) {
8143 TALLOC_FREE(br_lck);
8144 *async = true;
8145 return NT_STATUS_OK;
8149 TALLOC_FREE(br_lck);
8152 if (!NT_STATUS_IS_OK(status)) {
8153 break;
8157 /* If any of the above locks failed, then we must unlock
8158 all of the previous locks (X/Open spec). */
8160 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8162 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8163 i = -1; /* we want to skip the for loop */
8167 * Ensure we don't do a remove on the lock that just failed,
8168 * as under POSIX rules, if we have a lock already there, we
8169 * will delete it (and we shouldn't) .....
8171 for(i--; i >= 0; i--) {
8172 struct smbd_lock_element *e = &locks[i];
8174 do_unlock(req->sconn->msg_ctx,
8175 fsp,
8176 e->smblctx,
8177 e->count,
8178 e->offset,
8179 WINDOWS_LOCK);
8181 return status;
8184 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8185 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8187 return NT_STATUS_OK;
8190 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8191 files_struct *fsp,
8192 uint16_t num_ulocks,
8193 struct smbd_lock_element *ulocks)
8195 int i;
8197 for(i = 0; i < (int)num_ulocks; i++) {
8198 struct smbd_lock_element *e = &ulocks[i];
8199 NTSTATUS status;
8201 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8202 "pid %u, file %s\n", __func__,
8203 (double)e->offset,
8204 (double)e->count,
8205 (unsigned int)e->smblctx,
8206 fsp_str_dbg(fsp)));
8208 if (e->brltype != UNLOCK_LOCK) {
8209 /* this can only happen with SMB2 */
8210 return NT_STATUS_INVALID_PARAMETER;
8213 status = do_unlock(req->sconn->msg_ctx,
8214 fsp,
8215 e->smblctx,
8216 e->count,
8217 e->offset,
8218 WINDOWS_LOCK);
8220 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8221 nt_errstr(status)));
8223 if (!NT_STATUS_IS_OK(status)) {
8224 return status;
8228 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8229 num_ulocks));
8231 return NT_STATUS_OK;
8234 /****************************************************************************
8235 Reply to a lockingX request.
8236 ****************************************************************************/
8238 void reply_lockingX(struct smb_request *req)
8240 connection_struct *conn = req->conn;
8241 files_struct *fsp;
8242 unsigned char locktype;
8243 unsigned char oplocklevel;
8244 uint16_t num_ulocks;
8245 uint16_t num_locks;
8246 int32_t lock_timeout;
8247 int i;
8248 const uint8_t *data;
8249 bool large_file_format;
8250 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8251 struct smbd_lock_element *ulocks;
8252 struct smbd_lock_element *locks;
8253 bool async = false;
8255 START_PROFILE(SMBlockingX);
8257 if (req->wct < 8) {
8258 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8259 END_PROFILE(SMBlockingX);
8260 return;
8263 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8264 locktype = CVAL(req->vwv+3, 0);
8265 oplocklevel = CVAL(req->vwv+3, 1);
8266 num_ulocks = SVAL(req->vwv+6, 0);
8267 num_locks = SVAL(req->vwv+7, 0);
8268 lock_timeout = IVAL(req->vwv+4, 0);
8269 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8271 if (!check_fsp(conn, req, fsp)) {
8272 END_PROFILE(SMBlockingX);
8273 return;
8276 data = req->buf;
8278 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8279 /* we don't support these - and CANCEL_LOCK makes w2k
8280 and XP reboot so I don't really want to be
8281 compatible! (tridge) */
8282 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8283 END_PROFILE(SMBlockingX);
8284 return;
8287 /* Check if this is an oplock break on a file
8288 we have granted an oplock on.
8290 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8291 /* Client can insist on breaking to none. */
8292 bool break_to_none = (oplocklevel == 0);
8293 bool result;
8295 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8296 "for %s\n", (unsigned int)oplocklevel,
8297 fsp_fnum_dbg(fsp)));
8300 * Make sure we have granted an exclusive or batch oplock on
8301 * this file.
8304 if (fsp->oplock_type == 0) {
8306 /* The Samba4 nbench simulator doesn't understand
8307 the difference between break to level2 and break
8308 to none from level2 - it sends oplock break
8309 replies in both cases. Don't keep logging an error
8310 message here - just ignore it. JRA. */
8312 DEBUG(5,("reply_lockingX: Error : oplock break from "
8313 "client for %s (oplock=%d) and no "
8314 "oplock granted on this file (%s).\n",
8315 fsp_fnum_dbg(fsp), fsp->oplock_type,
8316 fsp_str_dbg(fsp)));
8318 /* if this is a pure oplock break request then don't
8319 * send a reply */
8320 if (num_locks == 0 && num_ulocks == 0) {
8321 END_PROFILE(SMBlockingX);
8322 return;
8323 } else {
8324 END_PROFILE(SMBlockingX);
8325 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8326 return;
8330 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8331 (break_to_none)) {
8332 result = remove_oplock(fsp);
8333 } else {
8334 result = downgrade_oplock(fsp);
8337 if (!result) {
8338 DEBUG(0, ("reply_lockingX: error in removing "
8339 "oplock on file %s\n", fsp_str_dbg(fsp)));
8340 /* Hmmm. Is this panic justified? */
8341 smb_panic("internal tdb error");
8344 /* if this is a pure oplock break request then don't send a
8345 * reply */
8346 if (num_locks == 0 && num_ulocks == 0) {
8347 /* Sanity check - ensure a pure oplock break is not a
8348 chained request. */
8349 if (CVAL(req->vwv+0, 0) != 0xff) {
8350 DEBUG(0,("reply_lockingX: Error : pure oplock "
8351 "break is a chained %d request !\n",
8352 (unsigned int)CVAL(req->vwv+0, 0)));
8354 END_PROFILE(SMBlockingX);
8355 return;
8359 if (req->buflen <
8360 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8361 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8362 END_PROFILE(SMBlockingX);
8363 return;
8366 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8367 if (ulocks == NULL) {
8368 reply_nterror(req, NT_STATUS_NO_MEMORY);
8369 END_PROFILE(SMBlockingX);
8370 return;
8373 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8374 if (locks == NULL) {
8375 reply_nterror(req, NT_STATUS_NO_MEMORY);
8376 END_PROFILE(SMBlockingX);
8377 return;
8380 /* Data now points at the beginning of the list
8381 of smb_unlkrng structs */
8382 for(i = 0; i < (int)num_ulocks; i++) {
8383 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8384 ulocks[i].count = get_lock_count(data, i, large_file_format);
8385 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8386 ulocks[i].brltype = UNLOCK_LOCK;
8389 /* Now do any requested locks */
8390 data += ((large_file_format ? 20 : 10)*num_ulocks);
8392 /* Data now points at the beginning of the list
8393 of smb_lkrng structs */
8395 for(i = 0; i < (int)num_locks; i++) {
8396 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8397 locks[i].count = get_lock_count(data, i, large_file_format);
8398 locks[i].offset = get_lock_offset(data, i, large_file_format);
8400 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8401 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8402 locks[i].brltype = PENDING_READ_LOCK;
8403 } else {
8404 locks[i].brltype = READ_LOCK;
8406 } else {
8407 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8408 locks[i].brltype = PENDING_WRITE_LOCK;
8409 } else {
8410 locks[i].brltype = WRITE_LOCK;
8415 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8416 if (!NT_STATUS_IS_OK(status)) {
8417 END_PROFILE(SMBlockingX);
8418 reply_nterror(req, status);
8419 return;
8422 status = smbd_do_locking(req, fsp,
8423 locktype, lock_timeout,
8424 num_locks, locks,
8425 &async);
8426 if (!NT_STATUS_IS_OK(status)) {
8427 END_PROFILE(SMBlockingX);
8428 reply_nterror(req, status);
8429 return;
8431 if (async) {
8432 END_PROFILE(SMBlockingX);
8433 return;
8436 reply_outbuf(req, 2, 0);
8437 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8438 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8440 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8441 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8443 END_PROFILE(SMBlockingX);
8446 #undef DBGC_CLASS
8447 #define DBGC_CLASS DBGC_ALL
8449 /****************************************************************************
8450 Reply to a SMBreadbmpx (read block multiplex) request.
8451 Always reply with an error, if someone has a platform really needs this,
8452 please contact vl@samba.org
8453 ****************************************************************************/
8455 void reply_readbmpx(struct smb_request *req)
8457 START_PROFILE(SMBreadBmpx);
8458 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8459 END_PROFILE(SMBreadBmpx);
8460 return;
8463 /****************************************************************************
8464 Reply to a SMBreadbs (read block multiplex secondary) request.
8465 Always reply with an error, if someone has a platform really needs this,
8466 please contact vl@samba.org
8467 ****************************************************************************/
8469 void reply_readbs(struct smb_request *req)
8471 START_PROFILE(SMBreadBs);
8472 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8473 END_PROFILE(SMBreadBs);
8474 return;
8477 /****************************************************************************
8478 Reply to a SMBsetattrE.
8479 ****************************************************************************/
8481 void reply_setattrE(struct smb_request *req)
8483 connection_struct *conn = req->conn;
8484 struct smb_file_time ft;
8485 files_struct *fsp;
8486 NTSTATUS status;
8488 START_PROFILE(SMBsetattrE);
8489 ZERO_STRUCT(ft);
8491 if (req->wct < 7) {
8492 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8493 goto out;
8496 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8498 if(!fsp || (fsp->conn != conn)) {
8499 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8500 goto out;
8504 * Convert the DOS times into unix times.
8507 ft.atime = convert_time_t_to_timespec(
8508 srv_make_unix_date2(req->vwv+3));
8509 ft.mtime = convert_time_t_to_timespec(
8510 srv_make_unix_date2(req->vwv+5));
8511 ft.create_time = convert_time_t_to_timespec(
8512 srv_make_unix_date2(req->vwv+1));
8514 reply_outbuf(req, 0, 0);
8517 * Patch from Ray Frush <frush@engr.colostate.edu>
8518 * Sometimes times are sent as zero - ignore them.
8521 /* Ensure we have a valid stat struct for the source. */
8522 status = vfs_stat_fsp(fsp);
8523 if (!NT_STATUS_IS_OK(status)) {
8524 reply_nterror(req, status);
8525 goto out;
8528 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8529 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8530 goto out;
8533 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8534 if (!NT_STATUS_IS_OK(status)) {
8535 reply_nterror(req, status);
8536 goto out;
8539 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8540 " createtime=%u\n",
8541 fsp_fnum_dbg(fsp),
8542 (unsigned int)ft.atime.tv_sec,
8543 (unsigned int)ft.mtime.tv_sec,
8544 (unsigned int)ft.create_time.tv_sec
8546 out:
8547 END_PROFILE(SMBsetattrE);
8548 return;
8552 /* Back from the dead for OS/2..... JRA. */
8554 /****************************************************************************
8555 Reply to a SMBwritebmpx (write block multiplex primary) request.
8556 Always reply with an error, if someone has a platform really needs this,
8557 please contact vl@samba.org
8558 ****************************************************************************/
8560 void reply_writebmpx(struct smb_request *req)
8562 START_PROFILE(SMBwriteBmpx);
8563 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8564 END_PROFILE(SMBwriteBmpx);
8565 return;
8568 /****************************************************************************
8569 Reply to a SMBwritebs (write block multiplex secondary) request.
8570 Always reply with an error, if someone has a platform really needs this,
8571 please contact vl@samba.org
8572 ****************************************************************************/
8574 void reply_writebs(struct smb_request *req)
8576 START_PROFILE(SMBwriteBs);
8577 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8578 END_PROFILE(SMBwriteBs);
8579 return;
8582 /****************************************************************************
8583 Reply to a SMBgetattrE.
8584 ****************************************************************************/
8586 void reply_getattrE(struct smb_request *req)
8588 connection_struct *conn = req->conn;
8589 int mode;
8590 files_struct *fsp;
8591 struct timespec create_ts;
8593 START_PROFILE(SMBgetattrE);
8595 if (req->wct < 1) {
8596 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8597 END_PROFILE(SMBgetattrE);
8598 return;
8601 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8603 if(!fsp || (fsp->conn != conn)) {
8604 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8605 END_PROFILE(SMBgetattrE);
8606 return;
8609 /* Do an fstat on this file */
8610 if(fsp_stat(fsp)) {
8611 reply_nterror(req, map_nt_error_from_unix(errno));
8612 END_PROFILE(SMBgetattrE);
8613 return;
8616 mode = dos_mode(conn, fsp->fsp_name);
8619 * Convert the times into dos times. Set create
8620 * date to be last modify date as UNIX doesn't save
8621 * this.
8624 reply_outbuf(req, 11, 0);
8626 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8627 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8628 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8629 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8630 /* Should we check pending modtime here ? JRA */
8631 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8632 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8634 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8635 SIVAL(req->outbuf, smb_vwv6, 0);
8636 SIVAL(req->outbuf, smb_vwv8, 0);
8637 } else {
8638 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8639 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8640 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8642 SSVAL(req->outbuf,smb_vwv10, mode);
8644 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8646 END_PROFILE(SMBgetattrE);
8647 return;