docs: Fix typo in man smb.conf.
[Samba.git] / source3 / smbd / reply.c
blob6acbaca416548b8af218bcde6f740fc67e45f5cc
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;
2115 TALLOC_CTX *ctx = talloc_tos();
2117 START_PROFILE(SMBopen);
2119 if (req->wct < 2) {
2120 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2121 goto out;
2124 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2125 deny_mode = SVAL(req->vwv+0, 0);
2126 dos_attr = SVAL(req->vwv+1, 0);
2128 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2129 STR_TERMINATE, &status);
2130 if (!NT_STATUS_IS_OK(status)) {
2131 reply_nterror(req, status);
2132 goto out;
2135 if (!map_open_params_to_ntcreate(fname, deny_mode,
2136 OPENX_FILE_EXISTS_OPEN, &access_mask,
2137 &share_mode, &create_disposition,
2138 &create_options, &private_flags)) {
2139 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2140 goto out;
2143 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2145 status = filename_convert(ctx,
2146 conn,
2147 req->flags2 & FLAGS2_DFS_PATHNAMES,
2148 fname,
2149 ucf_flags,
2150 NULL,
2151 &smb_fname);
2152 if (!NT_STATUS_IS_OK(status)) {
2153 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2154 reply_botherror(req,
2155 NT_STATUS_PATH_NOT_COVERED,
2156 ERRSRV, ERRbadpath);
2157 goto out;
2159 reply_nterror(req, status);
2160 goto out;
2163 status = SMB_VFS_CREATE_FILE(
2164 conn, /* conn */
2165 req, /* req */
2166 0, /* root_dir_fid */
2167 smb_fname, /* fname */
2168 access_mask, /* access_mask */
2169 share_mode, /* share_access */
2170 create_disposition, /* create_disposition*/
2171 create_options, /* create_options */
2172 dos_attr, /* file_attributes */
2173 oplock_request, /* oplock_request */
2174 NULL, /* lease */
2175 0, /* allocation_size */
2176 private_flags,
2177 NULL, /* sd */
2178 NULL, /* ea_list */
2179 &fsp, /* result */
2180 &info, /* pinfo */
2181 NULL, NULL); /* create context */
2183 if (!NT_STATUS_IS_OK(status)) {
2184 if (open_was_deferred(req->xconn, req->mid)) {
2185 /* We have re-scheduled this call. */
2186 goto out;
2188 reply_openerror(req, status);
2189 goto out;
2192 /* Ensure we're pointing at the correct stat struct. */
2193 TALLOC_FREE(smb_fname);
2194 smb_fname = fsp->fsp_name;
2196 size = smb_fname->st.st_ex_size;
2197 fattr = dos_mode(conn, smb_fname);
2199 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2201 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2202 DEBUG(3,("attempt to open a directory %s\n",
2203 fsp_str_dbg(fsp)));
2204 close_file(req, fsp, ERROR_CLOSE);
2205 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2206 ERRDOS, ERRnoaccess);
2207 goto out;
2210 reply_outbuf(req, 7, 0);
2211 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2212 SSVAL(req->outbuf,smb_vwv1,fattr);
2213 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2214 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2215 } else {
2216 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2218 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2219 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2221 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2222 SCVAL(req->outbuf,smb_flg,
2223 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2226 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2227 SCVAL(req->outbuf,smb_flg,
2228 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2230 out:
2231 END_PROFILE(SMBopen);
2232 return;
2235 /****************************************************************************
2236 Reply to an open and X.
2237 ****************************************************************************/
2239 void reply_open_and_X(struct smb_request *req)
2241 connection_struct *conn = req->conn;
2242 struct smb_filename *smb_fname = NULL;
2243 char *fname = NULL;
2244 uint16_t open_flags;
2245 int deny_mode;
2246 uint32_t smb_attr;
2247 /* Breakout the oplock request bits so we can set the
2248 reply bits separately. */
2249 int ex_oplock_request;
2250 int core_oplock_request;
2251 int oplock_request;
2252 #if 0
2253 int smb_sattr = SVAL(req->vwv+4, 0);
2254 uint32_t smb_time = make_unix_date3(req->vwv+6);
2255 #endif
2256 int smb_ofun;
2257 uint32_t fattr=0;
2258 int mtime=0;
2259 int smb_action = 0;
2260 files_struct *fsp;
2261 NTSTATUS status;
2262 uint64_t allocation_size;
2263 ssize_t retval = -1;
2264 uint32_t access_mask;
2265 uint32_t share_mode;
2266 uint32_t create_disposition;
2267 uint32_t create_options = 0;
2268 uint32_t private_flags = 0;
2269 uint32_t ucf_flags;
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 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2318 status = filename_convert(ctx,
2319 conn,
2320 req->flags2 & FLAGS2_DFS_PATHNAMES,
2321 fname,
2322 ucf_flags,
2323 NULL,
2324 &smb_fname);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2327 reply_botherror(req,
2328 NT_STATUS_PATH_NOT_COVERED,
2329 ERRSRV, ERRbadpath);
2330 goto out;
2332 reply_nterror(req, status);
2333 goto out;
2336 status = SMB_VFS_CREATE_FILE(
2337 conn, /* conn */
2338 req, /* req */
2339 0, /* root_dir_fid */
2340 smb_fname, /* fname */
2341 access_mask, /* access_mask */
2342 share_mode, /* share_access */
2343 create_disposition, /* create_disposition*/
2344 create_options, /* create_options */
2345 smb_attr, /* file_attributes */
2346 oplock_request, /* oplock_request */
2347 NULL, /* lease */
2348 0, /* allocation_size */
2349 private_flags,
2350 NULL, /* sd */
2351 NULL, /* ea_list */
2352 &fsp, /* result */
2353 &smb_action, /* pinfo */
2354 NULL, NULL); /* create context */
2356 if (!NT_STATUS_IS_OK(status)) {
2357 if (open_was_deferred(req->xconn, req->mid)) {
2358 /* We have re-scheduled this call. */
2359 goto out;
2361 reply_openerror(req, status);
2362 goto out;
2365 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2366 if the file is truncated or created. */
2367 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2368 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2369 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2370 close_file(req, fsp, ERROR_CLOSE);
2371 reply_nterror(req, NT_STATUS_DISK_FULL);
2372 goto out;
2374 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2375 if (retval < 0) {
2376 close_file(req, fsp, ERROR_CLOSE);
2377 reply_nterror(req, NT_STATUS_DISK_FULL);
2378 goto out;
2380 status = vfs_stat_fsp(fsp);
2381 if (!NT_STATUS_IS_OK(status)) {
2382 close_file(req, fsp, ERROR_CLOSE);
2383 reply_nterror(req, status);
2384 goto out;
2388 fattr = dos_mode(conn, fsp->fsp_name);
2389 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2390 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2391 close_file(req, fsp, ERROR_CLOSE);
2392 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2393 goto out;
2396 /* If the caller set the extended oplock request bit
2397 and we granted one (by whatever means) - set the
2398 correct bit for extended oplock reply.
2401 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2402 smb_action |= EXTENDED_OPLOCK_GRANTED;
2405 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2406 smb_action |= EXTENDED_OPLOCK_GRANTED;
2409 /* If the caller set the core oplock request bit
2410 and we granted one (by whatever means) - set the
2411 correct bit for core oplock reply.
2414 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2415 reply_outbuf(req, 19, 0);
2416 } else {
2417 reply_outbuf(req, 15, 0);
2420 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2421 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2423 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2424 SCVAL(req->outbuf, smb_flg,
2425 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2428 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2429 SCVAL(req->outbuf, smb_flg,
2430 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2433 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2434 SSVAL(req->outbuf,smb_vwv3,fattr);
2435 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2436 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2437 } else {
2438 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2440 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2441 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2442 SSVAL(req->outbuf,smb_vwv11,smb_action);
2444 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2445 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2448 out:
2449 TALLOC_FREE(smb_fname);
2450 END_PROFILE(SMBopenX);
2451 return;
2454 /****************************************************************************
2455 Reply to a SMBulogoffX.
2456 ****************************************************************************/
2458 void reply_ulogoffX(struct smb_request *req)
2460 struct smbd_server_connection *sconn = req->sconn;
2461 struct user_struct *vuser;
2462 struct smbXsrv_session *session = NULL;
2463 NTSTATUS status;
2465 START_PROFILE(SMBulogoffX);
2467 vuser = get_valid_user_struct(sconn, req->vuid);
2469 if(vuser == NULL) {
2470 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2471 (unsigned long long)req->vuid));
2473 req->vuid = UID_FIELD_INVALID;
2474 reply_force_doserror(req, ERRSRV, ERRbaduid);
2475 END_PROFILE(SMBulogoffX);
2476 return;
2479 session = vuser->session;
2480 vuser = NULL;
2483 * TODO: cancel all outstanding requests on the session
2485 status = smbXsrv_session_logoff(session);
2486 if (!NT_STATUS_IS_OK(status)) {
2487 DEBUG(0, ("reply_ulogoff: "
2488 "smbXsrv_session_logoff() failed: %s\n",
2489 nt_errstr(status)));
2491 * If we hit this case, there is something completely
2492 * wrong, so we better disconnect the transport connection.
2494 END_PROFILE(SMBulogoffX);
2495 exit_server(__location__ ": smbXsrv_session_logoff failed");
2496 return;
2499 TALLOC_FREE(session);
2501 reply_outbuf(req, 2, 0);
2502 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2503 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2505 DEBUG(3, ("ulogoffX vuid=%llu\n",
2506 (unsigned long long)req->vuid));
2508 END_PROFILE(SMBulogoffX);
2509 req->vuid = UID_FIELD_INVALID;
2512 /****************************************************************************
2513 Reply to a mknew or a create.
2514 ****************************************************************************/
2516 void reply_mknew(struct smb_request *req)
2518 connection_struct *conn = req->conn;
2519 struct smb_filename *smb_fname = NULL;
2520 char *fname = NULL;
2521 uint32_t fattr = 0;
2522 struct smb_file_time ft;
2523 files_struct *fsp;
2524 int oplock_request = 0;
2525 NTSTATUS status;
2526 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2527 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2528 uint32_t create_disposition;
2529 uint32_t create_options = 0;
2530 uint32_t ucf_flags;
2531 TALLOC_CTX *ctx = talloc_tos();
2533 START_PROFILE(SMBcreate);
2534 ZERO_STRUCT(ft);
2536 if (req->wct < 3) {
2537 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2538 goto out;
2541 fattr = SVAL(req->vwv+0, 0);
2542 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2544 if (req->cmd == SMBmknew) {
2545 /* We should fail if file exists. */
2546 create_disposition = FILE_CREATE;
2547 } else {
2548 /* Create if file doesn't exist, truncate if it does. */
2549 create_disposition = FILE_OVERWRITE_IF;
2552 /* mtime. */
2553 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2555 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2556 STR_TERMINATE, &status);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 reply_nterror(req, status);
2559 goto out;
2562 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2563 status = filename_convert(ctx,
2564 conn,
2565 req->flags2 & FLAGS2_DFS_PATHNAMES,
2566 fname,
2567 ucf_flags,
2568 NULL,
2569 &smb_fname);
2570 if (!NT_STATUS_IS_OK(status)) {
2571 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2572 reply_botherror(req,
2573 NT_STATUS_PATH_NOT_COVERED,
2574 ERRSRV, ERRbadpath);
2575 goto out;
2577 reply_nterror(req, status);
2578 goto out;
2581 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2582 DEBUG(0,("Attempt to create file (%s) with volid set - "
2583 "please report this\n",
2584 smb_fname_str_dbg(smb_fname)));
2587 status = SMB_VFS_CREATE_FILE(
2588 conn, /* conn */
2589 req, /* req */
2590 0, /* root_dir_fid */
2591 smb_fname, /* fname */
2592 access_mask, /* access_mask */
2593 share_mode, /* share_access */
2594 create_disposition, /* create_disposition*/
2595 create_options, /* create_options */
2596 fattr, /* file_attributes */
2597 oplock_request, /* oplock_request */
2598 NULL, /* lease */
2599 0, /* allocation_size */
2600 0, /* private_flags */
2601 NULL, /* sd */
2602 NULL, /* ea_list */
2603 &fsp, /* result */
2604 NULL, /* pinfo */
2605 NULL, NULL); /* create context */
2607 if (!NT_STATUS_IS_OK(status)) {
2608 if (open_was_deferred(req->xconn, req->mid)) {
2609 /* We have re-scheduled this call. */
2610 goto out;
2612 reply_openerror(req, status);
2613 goto out;
2616 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2617 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2618 if (!NT_STATUS_IS_OK(status)) {
2619 END_PROFILE(SMBcreate);
2620 goto out;
2623 reply_outbuf(req, 1, 0);
2624 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2626 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2627 SCVAL(req->outbuf,smb_flg,
2628 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2631 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2632 SCVAL(req->outbuf,smb_flg,
2633 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2636 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2637 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2638 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2639 (unsigned int)fattr));
2641 out:
2642 TALLOC_FREE(smb_fname);
2643 END_PROFILE(SMBcreate);
2644 return;
2647 /****************************************************************************
2648 Reply to a create temporary file.
2649 ****************************************************************************/
2651 void reply_ctemp(struct smb_request *req)
2653 connection_struct *conn = req->conn;
2654 struct smb_filename *smb_fname = NULL;
2655 char *wire_name = NULL;
2656 char *fname = NULL;
2657 uint32_t fattr;
2658 files_struct *fsp;
2659 int oplock_request;
2660 char *s;
2661 NTSTATUS status;
2662 int i;
2663 uint32_t ucf_flags;
2664 TALLOC_CTX *ctx = talloc_tos();
2666 START_PROFILE(SMBctemp);
2668 if (req->wct < 3) {
2669 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2670 goto out;
2673 fattr = SVAL(req->vwv+0, 0);
2674 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2676 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2677 STR_TERMINATE, &status);
2678 if (!NT_STATUS_IS_OK(status)) {
2679 reply_nterror(req, status);
2680 goto out;
2683 for (i = 0; i < 10; i++) {
2684 if (*wire_name) {
2685 fname = talloc_asprintf(ctx,
2686 "%s/TMP%s",
2687 wire_name,
2688 generate_random_str_list(ctx, 5, "0123456789"));
2689 } else {
2690 fname = talloc_asprintf(ctx,
2691 "TMP%s",
2692 generate_random_str_list(ctx, 5, "0123456789"));
2695 if (!fname) {
2696 reply_nterror(req, NT_STATUS_NO_MEMORY);
2697 goto out;
2700 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2701 status = filename_convert(ctx, conn,
2702 req->flags2 & FLAGS2_DFS_PATHNAMES,
2703 fname,
2704 ucf_flags,
2705 NULL,
2706 &smb_fname);
2707 if (!NT_STATUS_IS_OK(status)) {
2708 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2709 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2710 ERRSRV, ERRbadpath);
2711 goto out;
2713 reply_nterror(req, status);
2714 goto out;
2717 /* Create the file. */
2718 status = SMB_VFS_CREATE_FILE(
2719 conn, /* conn */
2720 req, /* req */
2721 0, /* root_dir_fid */
2722 smb_fname, /* fname */
2723 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2724 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2725 FILE_CREATE, /* create_disposition*/
2726 0, /* create_options */
2727 fattr, /* file_attributes */
2728 oplock_request, /* oplock_request */
2729 NULL, /* lease */
2730 0, /* allocation_size */
2731 0, /* private_flags */
2732 NULL, /* sd */
2733 NULL, /* ea_list */
2734 &fsp, /* result */
2735 NULL, /* pinfo */
2736 NULL, NULL); /* create context */
2738 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2739 TALLOC_FREE(fname);
2740 TALLOC_FREE(smb_fname);
2741 continue;
2744 if (!NT_STATUS_IS_OK(status)) {
2745 if (open_was_deferred(req->xconn, req->mid)) {
2746 /* We have re-scheduled this call. */
2747 goto out;
2749 reply_openerror(req, status);
2750 goto out;
2753 break;
2756 if (i == 10) {
2757 /* Collision after 10 times... */
2758 reply_nterror(req, status);
2759 goto out;
2762 reply_outbuf(req, 1, 0);
2763 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2765 /* the returned filename is relative to the directory */
2766 s = strrchr_m(fsp->fsp_name->base_name, '/');
2767 if (!s) {
2768 s = fsp->fsp_name->base_name;
2769 } else {
2770 s++;
2773 #if 0
2774 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2775 thing in the byte section. JRA */
2776 SSVALS(p, 0, -1); /* what is this? not in spec */
2777 #endif
2778 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2779 == -1) {
2780 reply_nterror(req, NT_STATUS_NO_MEMORY);
2781 goto out;
2784 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2785 SCVAL(req->outbuf, smb_flg,
2786 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2789 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2790 SCVAL(req->outbuf, smb_flg,
2791 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2794 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2795 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2796 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2797 out:
2798 TALLOC_FREE(smb_fname);
2799 TALLOC_FREE(wire_name);
2800 END_PROFILE(SMBctemp);
2801 return;
2804 /*******************************************************************
2805 Check if a user is allowed to rename a file.
2806 ********************************************************************/
2808 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2809 uint16_t dirtype)
2811 if (!CAN_WRITE(conn)) {
2812 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2815 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2816 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2817 /* Only bother to read the DOS attribute if we might deny the
2818 rename on the grounds of attribute mismatch. */
2819 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2820 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2821 return NT_STATUS_NO_SUCH_FILE;
2825 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2826 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2827 return NT_STATUS_OK;
2830 /* If no pathnames are open below this
2831 directory, allow the rename. */
2833 if (lp_strict_rename(SNUM(conn))) {
2835 * Strict rename, check open file db.
2837 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2838 return NT_STATUS_ACCESS_DENIED;
2840 } else if (file_find_subpath(fsp)) {
2842 * No strict rename, just look in local process.
2844 return NT_STATUS_ACCESS_DENIED;
2846 return NT_STATUS_OK;
2849 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2850 return NT_STATUS_OK;
2853 return NT_STATUS_ACCESS_DENIED;
2856 /*******************************************************************
2857 * unlink a file with all relevant access checks
2858 *******************************************************************/
2860 static NTSTATUS do_unlink(connection_struct *conn,
2861 struct smb_request *req,
2862 struct smb_filename *smb_fname,
2863 uint32_t dirtype)
2865 uint32_t fattr;
2866 files_struct *fsp;
2867 uint32_t dirtype_orig = dirtype;
2868 NTSTATUS status;
2869 int ret;
2870 bool posix_paths = (req != NULL && req->posix_pathnames);
2872 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2873 smb_fname_str_dbg(smb_fname),
2874 dirtype));
2876 if (!CAN_WRITE(conn)) {
2877 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2880 if (posix_paths) {
2881 ret = SMB_VFS_LSTAT(conn, smb_fname);
2882 } else {
2883 ret = SMB_VFS_STAT(conn, smb_fname);
2885 if (ret != 0) {
2886 return map_nt_error_from_unix(errno);
2889 fattr = dos_mode(conn, smb_fname);
2891 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2892 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2895 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2896 if (!dirtype) {
2897 return NT_STATUS_NO_SUCH_FILE;
2900 if (!dir_check_ftype(fattr, dirtype)) {
2901 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2902 return NT_STATUS_FILE_IS_A_DIRECTORY;
2904 return NT_STATUS_NO_SUCH_FILE;
2907 if (dirtype_orig & 0x8000) {
2908 /* These will never be set for POSIX. */
2909 return NT_STATUS_NO_SUCH_FILE;
2912 #if 0
2913 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2914 return NT_STATUS_FILE_IS_A_DIRECTORY;
2917 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2918 return NT_STATUS_NO_SUCH_FILE;
2921 if (dirtype & 0xFF00) {
2922 /* These will never be set for POSIX. */
2923 return NT_STATUS_NO_SUCH_FILE;
2926 dirtype &= 0xFF;
2927 if (!dirtype) {
2928 return NT_STATUS_NO_SUCH_FILE;
2931 /* Can't delete a directory. */
2932 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2933 return NT_STATUS_FILE_IS_A_DIRECTORY;
2935 #endif
2937 #if 0 /* JRATEST */
2938 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2939 return NT_STATUS_OBJECT_NAME_INVALID;
2940 #endif /* JRATEST */
2942 /* On open checks the open itself will check the share mode, so
2943 don't do it here as we'll get it wrong. */
2945 status = SMB_VFS_CREATE_FILE
2946 (conn, /* conn */
2947 req, /* req */
2948 0, /* root_dir_fid */
2949 smb_fname, /* fname */
2950 DELETE_ACCESS, /* access_mask */
2951 FILE_SHARE_NONE, /* share_access */
2952 FILE_OPEN, /* create_disposition*/
2953 FILE_NON_DIRECTORY_FILE, /* create_options */
2954 /* file_attributes */
2955 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2956 FILE_ATTRIBUTE_NORMAL,
2957 0, /* oplock_request */
2958 NULL, /* lease */
2959 0, /* allocation_size */
2960 0, /* private_flags */
2961 NULL, /* sd */
2962 NULL, /* ea_list */
2963 &fsp, /* result */
2964 NULL, /* pinfo */
2965 NULL, NULL); /* create context */
2967 if (!NT_STATUS_IS_OK(status)) {
2968 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2969 nt_errstr(status)));
2970 return status;
2973 status = can_set_delete_on_close(fsp, fattr);
2974 if (!NT_STATUS_IS_OK(status)) {
2975 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2976 "(%s)\n",
2977 smb_fname_str_dbg(smb_fname),
2978 nt_errstr(status)));
2979 close_file(req, fsp, NORMAL_CLOSE);
2980 return status;
2983 /* The set is across all open files on this dev/inode pair. */
2984 if (!set_delete_on_close(fsp, True,
2985 conn->session_info->security_token,
2986 conn->session_info->unix_token)) {
2987 close_file(req, fsp, NORMAL_CLOSE);
2988 return NT_STATUS_ACCESS_DENIED;
2991 return close_file(req, fsp, NORMAL_CLOSE);
2994 /****************************************************************************
2995 The guts of the unlink command, split out so it may be called by the NT SMB
2996 code.
2997 ****************************************************************************/
2999 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
3000 uint32_t dirtype, struct smb_filename *smb_fname,
3001 bool has_wild)
3003 char *fname_dir = NULL;
3004 char *fname_mask = NULL;
3005 int count=0;
3006 NTSTATUS status = NT_STATUS_OK;
3007 struct smb_filename *smb_fname_dir = NULL;
3008 TALLOC_CTX *ctx = talloc_tos();
3010 /* Split up the directory from the filename/mask. */
3011 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3012 &fname_dir, &fname_mask);
3013 if (!NT_STATUS_IS_OK(status)) {
3014 goto out;
3018 * We should only check the mangled cache
3019 * here if unix_convert failed. This means
3020 * that the path in 'mask' doesn't exist
3021 * on the file system and so we need to look
3022 * for a possible mangle. This patch from
3023 * Tine Smukavec <valentin.smukavec@hermes.si>.
3026 if (!VALID_STAT(smb_fname->st) &&
3027 mangle_is_mangled(fname_mask, conn->params)) {
3028 char *new_mask = NULL;
3029 mangle_lookup_name_from_8_3(ctx, fname_mask,
3030 &new_mask, conn->params);
3031 if (new_mask) {
3032 TALLOC_FREE(fname_mask);
3033 fname_mask = new_mask;
3037 if (!has_wild) {
3040 * Only one file needs to be unlinked. Append the mask back
3041 * onto the directory.
3043 TALLOC_FREE(smb_fname->base_name);
3044 if (ISDOT(fname_dir)) {
3045 /* Ensure we use canonical names on open. */
3046 smb_fname->base_name = talloc_asprintf(smb_fname,
3047 "%s",
3048 fname_mask);
3049 } else {
3050 smb_fname->base_name = talloc_asprintf(smb_fname,
3051 "%s/%s",
3052 fname_dir,
3053 fname_mask);
3055 if (!smb_fname->base_name) {
3056 status = NT_STATUS_NO_MEMORY;
3057 goto out;
3059 if (dirtype == 0) {
3060 dirtype = FILE_ATTRIBUTE_NORMAL;
3063 status = check_name(conn, smb_fname->base_name);
3064 if (!NT_STATUS_IS_OK(status)) {
3065 goto out;
3068 status = do_unlink(conn, req, smb_fname, dirtype);
3069 if (!NT_STATUS_IS_OK(status)) {
3070 goto out;
3073 count++;
3074 } else {
3075 struct smb_Dir *dir_hnd = NULL;
3076 long offset = 0;
3077 const char *dname = NULL;
3078 char *talloced = NULL;
3080 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3081 status = NT_STATUS_OBJECT_NAME_INVALID;
3082 goto out;
3084 if (dirtype == 0) {
3085 dirtype = FILE_ATTRIBUTE_NORMAL;
3088 if (strequal(fname_mask,"????????.???")) {
3089 TALLOC_FREE(fname_mask);
3090 fname_mask = talloc_strdup(ctx, "*");
3091 if (!fname_mask) {
3092 status = NT_STATUS_NO_MEMORY;
3093 goto out;
3097 status = check_name(conn, fname_dir);
3098 if (!NT_STATUS_IS_OK(status)) {
3099 goto out;
3102 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3103 fname_dir,
3104 NULL,
3105 NULL,
3106 smb_fname->flags);
3107 if (smb_fname_dir == NULL) {
3108 status = NT_STATUS_NO_MEMORY;
3109 goto out;
3112 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3113 dirtype);
3114 if (dir_hnd == NULL) {
3115 status = map_nt_error_from_unix(errno);
3116 goto out;
3119 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3120 the pattern matches against the long name, otherwise the short name
3121 We don't implement this yet XXXX
3124 status = NT_STATUS_NO_SUCH_FILE;
3126 while ((dname = ReadDirName(dir_hnd, &offset,
3127 &smb_fname->st, &talloced))) {
3128 TALLOC_CTX *frame = talloc_stackframe();
3130 if (!is_visible_file(conn, fname_dir, dname,
3131 &smb_fname->st, true)) {
3132 TALLOC_FREE(frame);
3133 TALLOC_FREE(talloced);
3134 continue;
3137 /* Quick check for "." and ".." */
3138 if (ISDOT(dname) || ISDOTDOT(dname)) {
3139 TALLOC_FREE(frame);
3140 TALLOC_FREE(talloced);
3141 continue;
3144 if(!mask_match(dname, fname_mask,
3145 conn->case_sensitive)) {
3146 TALLOC_FREE(frame);
3147 TALLOC_FREE(talloced);
3148 continue;
3151 TALLOC_FREE(smb_fname->base_name);
3152 if (ISDOT(fname_dir)) {
3153 /* Ensure we use canonical names on open. */
3154 smb_fname->base_name =
3155 talloc_asprintf(smb_fname, "%s",
3156 dname);
3157 } else {
3158 smb_fname->base_name =
3159 talloc_asprintf(smb_fname, "%s/%s",
3160 fname_dir, dname);
3163 if (!smb_fname->base_name) {
3164 TALLOC_FREE(dir_hnd);
3165 status = NT_STATUS_NO_MEMORY;
3166 TALLOC_FREE(frame);
3167 TALLOC_FREE(talloced);
3168 goto out;
3171 status = check_name(conn, smb_fname->base_name);
3172 if (!NT_STATUS_IS_OK(status)) {
3173 TALLOC_FREE(dir_hnd);
3174 TALLOC_FREE(frame);
3175 TALLOC_FREE(talloced);
3176 goto out;
3179 status = do_unlink(conn, req, smb_fname, dirtype);
3180 if (!NT_STATUS_IS_OK(status)) {
3181 TALLOC_FREE(dir_hnd);
3182 TALLOC_FREE(frame);
3183 TALLOC_FREE(talloced);
3184 goto out;
3187 count++;
3188 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3189 smb_fname->base_name));
3191 TALLOC_FREE(frame);
3192 TALLOC_FREE(talloced);
3194 TALLOC_FREE(dir_hnd);
3197 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3198 status = map_nt_error_from_unix(errno);
3201 out:
3202 TALLOC_FREE(smb_fname_dir);
3203 TALLOC_FREE(fname_dir);
3204 TALLOC_FREE(fname_mask);
3205 return status;
3208 /****************************************************************************
3209 Reply to a unlink
3210 ****************************************************************************/
3212 void reply_unlink(struct smb_request *req)
3214 connection_struct *conn = req->conn;
3215 char *name = NULL;
3216 struct smb_filename *smb_fname = NULL;
3217 uint32_t dirtype;
3218 NTSTATUS status;
3219 bool path_contains_wcard = False;
3220 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3221 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
3222 TALLOC_CTX *ctx = talloc_tos();
3224 START_PROFILE(SMBunlink);
3226 if (req->wct < 1) {
3227 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3228 goto out;
3231 dirtype = SVAL(req->vwv+0, 0);
3233 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3234 STR_TERMINATE, &status,
3235 &path_contains_wcard);
3236 if (!NT_STATUS_IS_OK(status)) {
3237 reply_nterror(req, status);
3238 goto out;
3241 status = filename_convert(ctx, conn,
3242 req->flags2 & FLAGS2_DFS_PATHNAMES,
3243 name,
3244 ucf_flags,
3245 &path_contains_wcard,
3246 &smb_fname);
3247 if (!NT_STATUS_IS_OK(status)) {
3248 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3249 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3250 ERRSRV, ERRbadpath);
3251 goto out;
3253 reply_nterror(req, status);
3254 goto out;
3257 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3259 status = unlink_internals(conn, req, dirtype, smb_fname,
3260 path_contains_wcard);
3261 if (!NT_STATUS_IS_OK(status)) {
3262 if (open_was_deferred(req->xconn, req->mid)) {
3263 /* We have re-scheduled this call. */
3264 goto out;
3266 reply_nterror(req, status);
3267 goto out;
3270 reply_outbuf(req, 0, 0);
3271 out:
3272 TALLOC_FREE(smb_fname);
3273 END_PROFILE(SMBunlink);
3274 return;
3277 /****************************************************************************
3278 Fail for readbraw.
3279 ****************************************************************************/
3281 static void fail_readraw(void)
3283 const char *errstr = talloc_asprintf(talloc_tos(),
3284 "FAIL ! reply_readbraw: socket write fail (%s)",
3285 strerror(errno));
3286 if (!errstr) {
3287 errstr = "";
3289 exit_server_cleanly(errstr);
3292 /****************************************************************************
3293 Fake (read/write) sendfile. Returns -1 on read or write fail.
3294 ****************************************************************************/
3296 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3297 off_t startpos, size_t nread)
3299 size_t bufsize;
3300 size_t tosend = nread;
3301 char *buf;
3303 if (nread == 0) {
3304 return 0;
3307 bufsize = MIN(nread, 65536);
3309 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3310 return -1;
3313 while (tosend > 0) {
3314 ssize_t ret;
3315 size_t cur_read;
3317 cur_read = MIN(tosend, bufsize);
3318 ret = read_file(fsp,buf,startpos,cur_read);
3319 if (ret == -1) {
3320 SAFE_FREE(buf);
3321 return -1;
3324 /* If we had a short read, fill with zeros. */
3325 if (ret < cur_read) {
3326 memset(buf + ret, '\0', cur_read - ret);
3329 ret = write_data(xconn->transport.sock, buf, cur_read);
3330 if (ret != cur_read) {
3331 int saved_errno = errno;
3333 * Try and give an error message saying what
3334 * client failed.
3336 DEBUG(0, ("write_data failed for client %s. "
3337 "Error %s\n",
3338 smbXsrv_connection_dbg(xconn),
3339 strerror(saved_errno)));
3340 SAFE_FREE(buf);
3341 errno = saved_errno;
3342 return -1;
3344 tosend -= cur_read;
3345 startpos += cur_read;
3348 SAFE_FREE(buf);
3349 return (ssize_t)nread;
3352 /****************************************************************************
3353 Deal with the case of sendfile reading less bytes from the file than
3354 requested. Fill with zeros (all we can do). Returns 0 on success
3355 ****************************************************************************/
3357 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3358 files_struct *fsp,
3359 ssize_t nread,
3360 size_t headersize,
3361 size_t smb_maxcnt)
3363 #define SHORT_SEND_BUFSIZE 1024
3364 if (nread < headersize) {
3365 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3366 "header for file %s (%s). Terminating\n",
3367 fsp_str_dbg(fsp), strerror(errno)));
3368 return -1;
3371 nread -= headersize;
3373 if (nread < smb_maxcnt) {
3374 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3375 if (!buf) {
3376 DEBUG(0,("sendfile_short_send: malloc failed "
3377 "for file %s (%s). Terminating\n",
3378 fsp_str_dbg(fsp), strerror(errno)));
3379 return -1;
3382 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3383 "with zeros !\n", fsp_str_dbg(fsp)));
3385 while (nread < smb_maxcnt) {
3387 * We asked for the real file size and told sendfile
3388 * to not go beyond the end of the file. But it can
3389 * happen that in between our fstat call and the
3390 * sendfile call the file was truncated. This is very
3391 * bad because we have already announced the larger
3392 * number of bytes to the client.
3394 * The best we can do now is to send 0-bytes, just as
3395 * a read from a hole in a sparse file would do.
3397 * This should happen rarely enough that I don't care
3398 * about efficiency here :-)
3400 size_t to_write;
3401 ssize_t ret;
3403 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3404 ret = write_data(xconn->transport.sock, buf, to_write);
3405 if (ret != to_write) {
3406 int saved_errno = errno;
3408 * Try and give an error message saying what
3409 * client failed.
3411 DEBUG(0, ("write_data failed for client %s. "
3412 "Error %s\n",
3413 smbXsrv_connection_dbg(xconn),
3414 strerror(saved_errno)));
3415 errno = saved_errno;
3416 return -1;
3418 nread += to_write;
3420 SAFE_FREE(buf);
3423 return 0;
3426 /****************************************************************************
3427 Return a readbraw error (4 bytes of zero).
3428 ****************************************************************************/
3430 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3432 char header[4];
3434 SIVAL(header,0,0);
3436 smbd_lock_socket(xconn);
3437 if (write_data(xconn->transport.sock,header,4) != 4) {
3438 int saved_errno = errno;
3440 * Try and give an error message saying what
3441 * client failed.
3443 DEBUG(0, ("write_data failed for client %s. "
3444 "Error %s\n",
3445 smbXsrv_connection_dbg(xconn),
3446 strerror(saved_errno)));
3447 errno = saved_errno;
3449 fail_readraw();
3451 smbd_unlock_socket(xconn);
3454 /****************************************************************************
3455 Use sendfile in readbraw.
3456 ****************************************************************************/
3458 static void send_file_readbraw(connection_struct *conn,
3459 struct smb_request *req,
3460 files_struct *fsp,
3461 off_t startpos,
3462 size_t nread,
3463 ssize_t mincount)
3465 struct smbXsrv_connection *xconn = req->xconn;
3466 char *outbuf = NULL;
3467 ssize_t ret=0;
3470 * We can only use sendfile on a non-chained packet
3471 * but we can use on a non-oplocked file. tridge proved this
3472 * on a train in Germany :-). JRA.
3473 * reply_readbraw has already checked the length.
3476 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3477 (fsp->wcp == NULL) &&
3478 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3479 ssize_t sendfile_read = -1;
3480 char header[4];
3481 DATA_BLOB header_blob;
3483 _smb_setlen(header,nread);
3484 header_blob = data_blob_const(header, 4);
3486 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3487 &header_blob, startpos,
3488 nread);
3489 if (sendfile_read == -1) {
3490 /* Returning ENOSYS means no data at all was sent.
3491 * Do this as a normal read. */
3492 if (errno == ENOSYS) {
3493 goto normal_readbraw;
3497 * Special hack for broken Linux with no working sendfile. If we
3498 * return EINTR we sent the header but not the rest of the data.
3499 * Fake this up by doing read/write calls.
3501 if (errno == EINTR) {
3502 /* Ensure we don't do this again. */
3503 set_use_sendfile(SNUM(conn), False);
3504 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3506 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3507 DEBUG(0,("send_file_readbraw: "
3508 "fake_sendfile failed for "
3509 "file %s (%s).\n",
3510 fsp_str_dbg(fsp),
3511 strerror(errno)));
3512 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3514 return;
3517 DEBUG(0,("send_file_readbraw: sendfile failed for "
3518 "file %s (%s). Terminating\n",
3519 fsp_str_dbg(fsp), strerror(errno)));
3520 exit_server_cleanly("send_file_readbraw sendfile failed");
3521 } else if (sendfile_read == 0) {
3523 * Some sendfile implementations return 0 to indicate
3524 * that there was a short read, but nothing was
3525 * actually written to the socket. In this case,
3526 * fallback to the normal read path so the header gets
3527 * the correct byte count.
3529 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3530 "bytes falling back to the normal read: "
3531 "%s\n", fsp_str_dbg(fsp)));
3532 goto normal_readbraw;
3535 /* Deal with possible short send. */
3536 if (sendfile_read != 4+nread) {
3537 ret = sendfile_short_send(xconn, fsp,
3538 sendfile_read, 4, nread);
3539 if (ret == -1) {
3540 fail_readraw();
3543 return;
3546 normal_readbraw:
3548 outbuf = talloc_array(NULL, char, nread+4);
3549 if (!outbuf) {
3550 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3551 (unsigned)(nread+4)));
3552 reply_readbraw_error(xconn);
3553 return;
3556 if (nread > 0) {
3557 ret = read_file(fsp,outbuf+4,startpos,nread);
3558 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3559 if (ret < mincount)
3560 ret = 0;
3561 #else
3562 if (ret < nread)
3563 ret = 0;
3564 #endif
3567 _smb_setlen(outbuf,ret);
3568 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3569 int saved_errno = errno;
3571 * Try and give an error message saying what
3572 * client failed.
3574 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3575 smbXsrv_connection_dbg(xconn),
3576 strerror(saved_errno)));
3577 errno = saved_errno;
3579 fail_readraw();
3582 TALLOC_FREE(outbuf);
3585 /****************************************************************************
3586 Reply to a readbraw (core+ protocol).
3587 ****************************************************************************/
3589 void reply_readbraw(struct smb_request *req)
3591 connection_struct *conn = req->conn;
3592 struct smbXsrv_connection *xconn = req->xconn;
3593 ssize_t maxcount,mincount;
3594 size_t nread = 0;
3595 off_t startpos;
3596 files_struct *fsp;
3597 struct lock_struct lock;
3598 off_t size = 0;
3600 START_PROFILE(SMBreadbraw);
3602 if (srv_is_signing_active(xconn) || req->encrypted) {
3603 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3604 "raw reads/writes are disallowed.");
3607 if (req->wct < 8) {
3608 reply_readbraw_error(xconn);
3609 END_PROFILE(SMBreadbraw);
3610 return;
3613 if (xconn->smb1.echo_handler.trusted_fde) {
3614 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3615 "'async smb echo handler = yes'\n"));
3616 reply_readbraw_error(xconn);
3617 END_PROFILE(SMBreadbraw);
3618 return;
3622 * Special check if an oplock break has been issued
3623 * and the readraw request croses on the wire, we must
3624 * return a zero length response here.
3627 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3630 * We have to do a check_fsp by hand here, as
3631 * we must always return 4 zero bytes on error,
3632 * not a NTSTATUS.
3635 if (!fsp || !conn || conn != fsp->conn ||
3636 req->vuid != fsp->vuid ||
3637 fsp->is_directory || fsp->fh->fd == -1) {
3639 * fsp could be NULL here so use the value from the packet. JRA.
3641 DEBUG(3,("reply_readbraw: fnum %d not valid "
3642 "- cache prime?\n",
3643 (int)SVAL(req->vwv+0, 0)));
3644 reply_readbraw_error(xconn);
3645 END_PROFILE(SMBreadbraw);
3646 return;
3649 /* Do a "by hand" version of CHECK_READ. */
3650 if (!(fsp->can_read ||
3651 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3652 (fsp->access_mask & FILE_EXECUTE)))) {
3653 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3654 (int)SVAL(req->vwv+0, 0)));
3655 reply_readbraw_error(xconn);
3656 END_PROFILE(SMBreadbraw);
3657 return;
3660 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3662 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3663 if(req->wct == 10) {
3665 * This is a large offset (64 bit) read.
3668 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3670 if(startpos < 0) {
3671 DEBUG(0,("reply_readbraw: negative 64 bit "
3672 "readraw offset (%.0f) !\n",
3673 (double)startpos ));
3674 reply_readbraw_error(xconn);
3675 END_PROFILE(SMBreadbraw);
3676 return;
3680 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3681 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3683 /* ensure we don't overrun the packet size */
3684 maxcount = MIN(65535,maxcount);
3686 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3687 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3688 &lock);
3690 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3691 reply_readbraw_error(xconn);
3692 END_PROFILE(SMBreadbraw);
3693 return;
3696 if (fsp_stat(fsp) == 0) {
3697 size = fsp->fsp_name->st.st_ex_size;
3700 if (startpos >= size) {
3701 nread = 0;
3702 } else {
3703 nread = MIN(maxcount,(size - startpos));
3706 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3707 if (nread < mincount)
3708 nread = 0;
3709 #endif
3711 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3712 "min=%lu nread=%lu\n",
3713 fsp_fnum_dbg(fsp), (double)startpos,
3714 (unsigned long)maxcount,
3715 (unsigned long)mincount,
3716 (unsigned long)nread ) );
3718 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3720 DEBUG(5,("reply_readbraw finished\n"));
3722 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3724 END_PROFILE(SMBreadbraw);
3725 return;
3728 #undef DBGC_CLASS
3729 #define DBGC_CLASS DBGC_LOCKING
3731 /****************************************************************************
3732 Reply to a lockread (core+ protocol).
3733 ****************************************************************************/
3735 void reply_lockread(struct smb_request *req)
3737 connection_struct *conn = req->conn;
3738 ssize_t nread = -1;
3739 char *data;
3740 off_t startpos;
3741 size_t numtoread;
3742 size_t maxtoread;
3743 NTSTATUS status;
3744 files_struct *fsp;
3745 struct byte_range_lock *br_lck = NULL;
3746 char *p = NULL;
3747 struct smbXsrv_connection *xconn = req->xconn;
3749 START_PROFILE(SMBlockread);
3751 if (req->wct < 5) {
3752 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3753 END_PROFILE(SMBlockread);
3754 return;
3757 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3759 if (!check_fsp(conn, req, fsp)) {
3760 END_PROFILE(SMBlockread);
3761 return;
3764 if (!CHECK_READ(fsp,req)) {
3765 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3766 END_PROFILE(SMBlockread);
3767 return;
3770 numtoread = SVAL(req->vwv+1, 0);
3771 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3774 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3775 * protocol request that predates the read/write lock concept.
3776 * Thus instead of asking for a read lock here we need to ask
3777 * for a write lock. JRA.
3778 * Note that the requested lock size is unaffected by max_send.
3781 br_lck = do_lock(req->sconn->msg_ctx,
3782 fsp,
3783 (uint64_t)req->smbpid,
3784 (uint64_t)numtoread,
3785 (uint64_t)startpos,
3786 WRITE_LOCK,
3787 WINDOWS_LOCK,
3788 False, /* Non-blocking lock. */
3789 &status,
3790 NULL);
3791 TALLOC_FREE(br_lck);
3793 if (NT_STATUS_V(status)) {
3794 reply_nterror(req, status);
3795 END_PROFILE(SMBlockread);
3796 return;
3800 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3802 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3804 if (numtoread > maxtoread) {
3805 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3806 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3807 (unsigned int)numtoread, (unsigned int)maxtoread,
3808 (unsigned int)xconn->smb1.sessions.max_send));
3809 numtoread = maxtoread;
3812 reply_outbuf(req, 5, numtoread + 3);
3814 data = smb_buf(req->outbuf) + 3;
3816 nread = read_file(fsp,data,startpos,numtoread);
3818 if (nread < 0) {
3819 reply_nterror(req, map_nt_error_from_unix(errno));
3820 END_PROFILE(SMBlockread);
3821 return;
3824 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3826 SSVAL(req->outbuf,smb_vwv0,nread);
3827 SSVAL(req->outbuf,smb_vwv5,nread+3);
3828 p = smb_buf(req->outbuf);
3829 SCVAL(p,0,0); /* pad byte. */
3830 SSVAL(p,1,nread);
3832 DEBUG(3,("lockread %s num=%d nread=%d\n",
3833 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3835 END_PROFILE(SMBlockread);
3836 return;
3839 #undef DBGC_CLASS
3840 #define DBGC_CLASS DBGC_ALL
3842 /****************************************************************************
3843 Reply to a read.
3844 ****************************************************************************/
3846 void reply_read(struct smb_request *req)
3848 connection_struct *conn = req->conn;
3849 size_t numtoread;
3850 size_t maxtoread;
3851 ssize_t nread = 0;
3852 char *data;
3853 off_t startpos;
3854 files_struct *fsp;
3855 struct lock_struct lock;
3856 struct smbXsrv_connection *xconn = req->xconn;
3858 START_PROFILE(SMBread);
3860 if (req->wct < 3) {
3861 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3862 END_PROFILE(SMBread);
3863 return;
3866 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3868 if (!check_fsp(conn, req, fsp)) {
3869 END_PROFILE(SMBread);
3870 return;
3873 if (!CHECK_READ(fsp,req)) {
3874 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3875 END_PROFILE(SMBread);
3876 return;
3879 numtoread = SVAL(req->vwv+1, 0);
3880 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3883 * The requested read size cannot be greater than max_send. JRA.
3885 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3887 if (numtoread > maxtoread) {
3888 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3889 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3890 (unsigned int)numtoread, (unsigned int)maxtoread,
3891 (unsigned int)xconn->smb1.sessions.max_send));
3892 numtoread = maxtoread;
3895 reply_outbuf(req, 5, numtoread+3);
3897 data = smb_buf(req->outbuf) + 3;
3899 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3900 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3901 &lock);
3903 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3904 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3905 END_PROFILE(SMBread);
3906 return;
3909 if (numtoread > 0)
3910 nread = read_file(fsp,data,startpos,numtoread);
3912 if (nread < 0) {
3913 reply_nterror(req, map_nt_error_from_unix(errno));
3914 goto strict_unlock;
3917 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3919 SSVAL(req->outbuf,smb_vwv0,nread);
3920 SSVAL(req->outbuf,smb_vwv5,nread+3);
3921 SCVAL(smb_buf(req->outbuf),0,1);
3922 SSVAL(smb_buf(req->outbuf),1,nread);
3924 DEBUG(3, ("read %s num=%d nread=%d\n",
3925 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3927 strict_unlock:
3928 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3930 END_PROFILE(SMBread);
3931 return;
3934 /****************************************************************************
3935 Setup readX header.
3936 ****************************************************************************/
3938 int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3940 int outsize;
3942 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3943 False);
3945 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3947 SCVAL(outbuf,smb_vwv0,0xFF);
3948 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3949 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3950 SSVAL(outbuf,smb_vwv6,
3951 (smb_wct - 4) /* offset from smb header to wct */
3952 + 1 /* the wct field */
3953 + 12 * sizeof(uint16_t) /* vwv */
3954 + 2 /* the buflen field */
3955 + 1); /* padding byte */
3956 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3957 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3958 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3959 _smb_setlen_large(outbuf,
3960 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3961 return outsize;
3964 /****************************************************************************
3965 Reply to a read and X - possibly using sendfile.
3966 ****************************************************************************/
3968 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3969 files_struct *fsp, off_t startpos,
3970 size_t smb_maxcnt)
3972 struct smbXsrv_connection *xconn = req->xconn;
3973 ssize_t nread = -1;
3974 struct lock_struct lock;
3975 int saved_errno = 0;
3977 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3978 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3979 &lock);
3981 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3982 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3983 return;
3987 * We can only use sendfile on a non-chained packet
3988 * but we can use on a non-oplocked file. tridge proved this
3989 * on a train in Germany :-). JRA.
3992 if (!req_is_in_chain(req) &&
3993 !req->encrypted &&
3994 (fsp->base_fsp == NULL) &&
3995 (fsp->wcp == NULL) &&
3996 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3997 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3998 DATA_BLOB header;
4000 if(fsp_stat(fsp) == -1) {
4001 reply_nterror(req, map_nt_error_from_unix(errno));
4002 goto strict_unlock;
4005 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4006 (startpos > fsp->fsp_name->st.st_ex_size) ||
4007 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4009 * We already know that we would do a short read, so don't
4010 * try the sendfile() path.
4012 goto nosendfile_read;
4016 * Set up the packet header before send. We
4017 * assume here the sendfile will work (get the
4018 * correct amount of data).
4021 header = data_blob_const(headerbuf, sizeof(headerbuf));
4023 construct_reply_common_req(req, (char *)headerbuf);
4024 setup_readX_header((char *)headerbuf, smb_maxcnt);
4026 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4027 startpos, smb_maxcnt);
4028 if (nread == -1) {
4029 saved_errno = errno;
4031 /* Returning ENOSYS means no data at all was sent.
4032 Do this as a normal read. */
4033 if (errno == ENOSYS) {
4034 goto normal_read;
4038 * Special hack for broken Linux with no working sendfile. If we
4039 * return EINTR we sent the header but not the rest of the data.
4040 * Fake this up by doing read/write calls.
4043 if (errno == EINTR) {
4044 /* Ensure we don't do this again. */
4045 set_use_sendfile(SNUM(conn), False);
4046 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4047 nread = fake_sendfile(xconn, fsp, startpos,
4048 smb_maxcnt);
4049 if (nread == -1) {
4050 saved_errno = errno;
4051 DEBUG(0,("send_file_readX: "
4052 "fake_sendfile failed for "
4053 "file %s (%s) for client %s. "
4054 "Terminating\n",
4055 fsp_str_dbg(fsp),
4056 smbXsrv_connection_dbg(xconn),
4057 strerror(saved_errno)));
4058 errno = saved_errno;
4059 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4061 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4062 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4063 /* No outbuf here means successful sendfile. */
4064 goto strict_unlock;
4067 DEBUG(0,("send_file_readX: sendfile failed for file "
4068 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4069 strerror(errno)));
4070 exit_server_cleanly("send_file_readX sendfile failed");
4071 } else if (nread == 0) {
4073 * Some sendfile implementations return 0 to indicate
4074 * that there was a short read, but nothing was
4075 * actually written to the socket. In this case,
4076 * fallback to the normal read path so the header gets
4077 * the correct byte count.
4079 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4080 "falling back to the normal read: %s\n",
4081 fsp_str_dbg(fsp)));
4082 goto normal_read;
4085 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4086 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4088 /* Deal with possible short send. */
4089 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4090 ssize_t ret;
4092 ret = sendfile_short_send(xconn, fsp, nread,
4093 sizeof(headerbuf), smb_maxcnt);
4094 if (ret == -1) {
4095 const char *r;
4096 r = "send_file_readX: sendfile_short_send failed";
4097 DEBUG(0,("%s for file %s (%s).\n",
4098 r, fsp_str_dbg(fsp), strerror(errno)));
4099 exit_server_cleanly(r);
4102 /* No outbuf here means successful sendfile. */
4103 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4104 SMB_PERFCOUNT_END(&req->pcd);
4105 goto strict_unlock;
4108 normal_read:
4110 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4111 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4112 ssize_t ret;
4114 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4115 (startpos > fsp->fsp_name->st.st_ex_size) ||
4116 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4118 * We already know that we would do a short
4119 * read, so don't try the sendfile() path.
4121 goto nosendfile_read;
4124 construct_reply_common_req(req, (char *)headerbuf);
4125 setup_readX_header((char *)headerbuf, smb_maxcnt);
4127 /* Send out the header. */
4128 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4129 sizeof(headerbuf));
4130 if (ret != sizeof(headerbuf)) {
4131 saved_errno = errno;
4133 * Try and give an error message saying what
4134 * client failed.
4136 DEBUG(0,("send_file_readX: write_data failed for file "
4137 "%s (%s) for client %s. Terminating\n",
4138 fsp_str_dbg(fsp),
4139 smbXsrv_connection_dbg(xconn),
4140 strerror(saved_errno)));
4141 errno = saved_errno;
4142 exit_server_cleanly("send_file_readX sendfile failed");
4144 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4145 if (nread == -1) {
4146 saved_errno = errno;
4147 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4148 "%s (%s) for client %s. Terminating\n",
4149 fsp_str_dbg(fsp),
4150 smbXsrv_connection_dbg(xconn),
4151 strerror(saved_errno)));
4152 errno = saved_errno;
4153 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4155 goto strict_unlock;
4158 nosendfile_read:
4160 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4161 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4162 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4164 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4165 startpos, smb_maxcnt);
4166 saved_errno = errno;
4168 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4170 if (nread < 0) {
4171 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4172 return;
4175 setup_readX_header((char *)req->outbuf, nread);
4177 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4178 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4179 return;
4181 strict_unlock:
4182 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4183 TALLOC_FREE(req->outbuf);
4184 return;
4187 /****************************************************************************
4188 Work out how much space we have for a read return.
4189 ****************************************************************************/
4191 static size_t calc_max_read_pdu(const struct smb_request *req)
4193 struct smbXsrv_connection *xconn = req->xconn;
4195 if (xconn->protocol < PROTOCOL_NT1) {
4196 return xconn->smb1.sessions.max_send;
4199 if (!lp_large_readwrite()) {
4200 return xconn->smb1.sessions.max_send;
4203 if (req_is_in_chain(req)) {
4204 return xconn->smb1.sessions.max_send;
4207 if (req->encrypted) {
4209 * Don't take encrypted traffic up to the
4210 * limit. There are padding considerations
4211 * that make that tricky.
4213 return xconn->smb1.sessions.max_send;
4216 if (srv_is_signing_active(xconn)) {
4217 return 0x1FFFF;
4220 if (!lp_unix_extensions()) {
4221 return 0x1FFFF;
4225 * We can do ultra-large POSIX reads.
4227 return 0xFFFFFF;
4230 /****************************************************************************
4231 Calculate how big a read can be. Copes with all clients. It's always
4232 safe to return a short read - Windows does this.
4233 ****************************************************************************/
4235 static size_t calc_read_size(const struct smb_request *req,
4236 size_t upper_size,
4237 size_t lower_size)
4239 struct smbXsrv_connection *xconn = req->xconn;
4240 size_t max_pdu = calc_max_read_pdu(req);
4241 size_t total_size = 0;
4242 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4243 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4246 * Windows explicitly ignores upper size of 0xFFFF.
4247 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4248 * We must do the same as these will never fit even in
4249 * an extended size NetBIOS packet.
4251 if (upper_size == 0xFFFF) {
4252 upper_size = 0;
4255 if (xconn->protocol < PROTOCOL_NT1) {
4256 upper_size = 0;
4259 total_size = ((upper_size<<16) | lower_size);
4262 * LARGE_READX test shows it's always safe to return
4263 * a short read. Windows does so.
4265 return MIN(total_size, max_len);
4268 /****************************************************************************
4269 Reply to a read and X.
4270 ****************************************************************************/
4272 void reply_read_and_X(struct smb_request *req)
4274 connection_struct *conn = req->conn;
4275 files_struct *fsp;
4276 off_t startpos;
4277 size_t smb_maxcnt;
4278 size_t upper_size;
4279 bool big_readX = False;
4280 #if 0
4281 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4282 #endif
4284 START_PROFILE(SMBreadX);
4286 if ((req->wct != 10) && (req->wct != 12)) {
4287 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4288 return;
4291 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4292 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4293 smb_maxcnt = SVAL(req->vwv+5, 0);
4295 /* If it's an IPC, pass off the pipe handler. */
4296 if (IS_IPC(conn)) {
4297 reply_pipe_read_and_X(req);
4298 END_PROFILE(SMBreadX);
4299 return;
4302 if (!check_fsp(conn, req, fsp)) {
4303 END_PROFILE(SMBreadX);
4304 return;
4307 if (!CHECK_READ(fsp,req)) {
4308 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4309 END_PROFILE(SMBreadX);
4310 return;
4313 upper_size = SVAL(req->vwv+7, 0);
4314 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4315 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4317 * This is a heuristic to avoid keeping large
4318 * outgoing buffers around over long-lived aio
4319 * requests.
4321 big_readX = True;
4324 if (req->wct == 12) {
4326 * This is a large offset (64 bit) read.
4328 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4332 if (!big_readX) {
4333 NTSTATUS status = schedule_aio_read_and_X(conn,
4334 req,
4335 fsp,
4336 startpos,
4337 smb_maxcnt);
4338 if (NT_STATUS_IS_OK(status)) {
4339 /* Read scheduled - we're done. */
4340 goto out;
4342 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4343 /* Real error - report to client. */
4344 END_PROFILE(SMBreadX);
4345 reply_nterror(req, status);
4346 return;
4348 /* NT_STATUS_RETRY - fall back to sync read. */
4351 smbd_lock_socket(req->xconn);
4352 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4353 smbd_unlock_socket(req->xconn);
4355 out:
4356 END_PROFILE(SMBreadX);
4357 return;
4360 /****************************************************************************
4361 Error replies to writebraw must have smb_wct == 1. Fix this up.
4362 ****************************************************************************/
4364 void error_to_writebrawerr(struct smb_request *req)
4366 uint8_t *old_outbuf = req->outbuf;
4368 reply_outbuf(req, 1, 0);
4370 memcpy(req->outbuf, old_outbuf, smb_size);
4371 TALLOC_FREE(old_outbuf);
4374 /****************************************************************************
4375 Read 4 bytes of a smb packet and return the smb length of the packet.
4376 Store the result in the buffer. This version of the function will
4377 never return a session keepalive (length of zero).
4378 Timeout is in milliseconds.
4379 ****************************************************************************/
4381 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4382 size_t *len)
4384 uint8_t msgtype = NBSSkeepalive;
4386 while (msgtype == NBSSkeepalive) {
4387 NTSTATUS status;
4389 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4390 len);
4391 if (!NT_STATUS_IS_OK(status)) {
4392 char addr[INET6_ADDRSTRLEN];
4393 /* Try and give an error message
4394 * saying what client failed. */
4395 DEBUG(0, ("read_fd_with_timeout failed for "
4396 "client %s read error = %s.\n",
4397 get_peer_addr(fd,addr,sizeof(addr)),
4398 nt_errstr(status)));
4399 return status;
4402 msgtype = CVAL(inbuf, 0);
4405 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4406 (unsigned long)len));
4408 return NT_STATUS_OK;
4411 /****************************************************************************
4412 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4413 ****************************************************************************/
4415 void reply_writebraw(struct smb_request *req)
4417 connection_struct *conn = req->conn;
4418 struct smbXsrv_connection *xconn = req->xconn;
4419 char *buf = NULL;
4420 ssize_t nwritten=0;
4421 ssize_t total_written=0;
4422 size_t numtowrite=0;
4423 size_t tcount;
4424 off_t startpos;
4425 const char *data=NULL;
4426 bool write_through;
4427 files_struct *fsp;
4428 struct lock_struct lock;
4429 NTSTATUS status;
4431 START_PROFILE(SMBwritebraw);
4434 * If we ever reply with an error, it must have the SMB command
4435 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4436 * we're finished.
4438 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4440 if (srv_is_signing_active(xconn)) {
4441 END_PROFILE(SMBwritebraw);
4442 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4443 "raw reads/writes are disallowed.");
4446 if (req->wct < 12) {
4447 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4448 error_to_writebrawerr(req);
4449 END_PROFILE(SMBwritebraw);
4450 return;
4453 if (xconn->smb1.echo_handler.trusted_fde) {
4454 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4455 "'async smb echo handler = yes'\n"));
4456 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4457 error_to_writebrawerr(req);
4458 END_PROFILE(SMBwritebraw);
4459 return;
4462 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4463 if (!check_fsp(conn, req, fsp)) {
4464 error_to_writebrawerr(req);
4465 END_PROFILE(SMBwritebraw);
4466 return;
4469 if (!CHECK_WRITE(fsp)) {
4470 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4471 error_to_writebrawerr(req);
4472 END_PROFILE(SMBwritebraw);
4473 return;
4476 tcount = IVAL(req->vwv+1, 0);
4477 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4478 write_through = BITSETW(req->vwv+7,0);
4480 /* We have to deal with slightly different formats depending
4481 on whether we are using the core+ or lanman1.0 protocol */
4483 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4484 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4485 data = smb_buf_const(req->inbuf);
4486 } else {
4487 numtowrite = SVAL(req->vwv+10, 0);
4488 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4491 /* Ensure we don't write bytes past the end of this packet. */
4492 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4493 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4494 error_to_writebrawerr(req);
4495 END_PROFILE(SMBwritebraw);
4496 return;
4499 if (!fsp->print_file) {
4500 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4501 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4502 &lock);
4504 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4505 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4506 error_to_writebrawerr(req);
4507 END_PROFILE(SMBwritebraw);
4508 return;
4512 if (numtowrite>0) {
4513 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4516 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4517 "wrote=%d sync=%d\n",
4518 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4519 (int)nwritten, (int)write_through));
4521 if (nwritten < (ssize_t)numtowrite) {
4522 reply_nterror(req, NT_STATUS_DISK_FULL);
4523 error_to_writebrawerr(req);
4524 goto strict_unlock;
4527 total_written = nwritten;
4529 /* Allocate a buffer of 64k + length. */
4530 buf = talloc_array(NULL, char, 65540);
4531 if (!buf) {
4532 reply_nterror(req, NT_STATUS_NO_MEMORY);
4533 error_to_writebrawerr(req);
4534 goto strict_unlock;
4537 /* Return a SMBwritebraw message to the redirector to tell
4538 * it to send more bytes */
4540 memcpy(buf, req->inbuf, smb_size);
4541 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4542 SCVAL(buf,smb_com,SMBwritebraw);
4543 SSVALS(buf,smb_vwv0,0xFFFF);
4544 show_msg(buf);
4545 if (!srv_send_smb(req->xconn,
4546 buf,
4547 false, 0, /* no signing */
4548 IS_CONN_ENCRYPTED(conn),
4549 &req->pcd)) {
4550 exit_server_cleanly("reply_writebraw: srv_send_smb "
4551 "failed.");
4554 /* Now read the raw data into the buffer and write it */
4555 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4556 &numtowrite);
4557 if (!NT_STATUS_IS_OK(status)) {
4558 exit_server_cleanly("secondary writebraw failed");
4561 /* Set up outbuf to return the correct size */
4562 reply_outbuf(req, 1, 0);
4564 if (numtowrite != 0) {
4566 if (numtowrite > 0xFFFF) {
4567 DEBUG(0,("reply_writebraw: Oversize secondary write "
4568 "raw requested (%u). Terminating\n",
4569 (unsigned int)numtowrite ));
4570 exit_server_cleanly("secondary writebraw failed");
4573 if (tcount > nwritten+numtowrite) {
4574 DEBUG(3,("reply_writebraw: Client overestimated the "
4575 "write %d %d %d\n",
4576 (int)tcount,(int)nwritten,(int)numtowrite));
4579 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4580 numtowrite);
4582 if (!NT_STATUS_IS_OK(status)) {
4583 /* Try and give an error message
4584 * saying what client failed. */
4585 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4586 "raw read failed (%s) for client %s. "
4587 "Terminating\n", nt_errstr(status),
4588 smbXsrv_connection_dbg(xconn)));
4589 exit_server_cleanly("secondary writebraw failed");
4592 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4593 if (nwritten == -1) {
4594 TALLOC_FREE(buf);
4595 reply_nterror(req, map_nt_error_from_unix(errno));
4596 error_to_writebrawerr(req);
4597 goto strict_unlock;
4600 if (nwritten < (ssize_t)numtowrite) {
4601 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4602 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4605 if (nwritten > 0) {
4606 total_written += nwritten;
4610 TALLOC_FREE(buf);
4611 SSVAL(req->outbuf,smb_vwv0,total_written);
4613 status = sync_file(conn, fsp, write_through);
4614 if (!NT_STATUS_IS_OK(status)) {
4615 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4616 fsp_str_dbg(fsp), nt_errstr(status)));
4617 reply_nterror(req, status);
4618 error_to_writebrawerr(req);
4619 goto strict_unlock;
4622 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4623 "wrote=%d\n",
4624 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4625 (int)total_written));
4627 if (!fsp->print_file) {
4628 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4631 /* We won't return a status if write through is not selected - this
4632 * follows what WfWg does */
4633 END_PROFILE(SMBwritebraw);
4635 if (!write_through && total_written==tcount) {
4637 #if RABBIT_PELLET_FIX
4639 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4640 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4641 * JRA.
4643 if (!send_keepalive(xconn->transport.sock)) {
4644 exit_server_cleanly("reply_writebraw: send of "
4645 "keepalive failed");
4647 #endif
4648 TALLOC_FREE(req->outbuf);
4650 return;
4652 strict_unlock:
4653 if (!fsp->print_file) {
4654 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4657 END_PROFILE(SMBwritebraw);
4658 return;
4661 #undef DBGC_CLASS
4662 #define DBGC_CLASS DBGC_LOCKING
4664 /****************************************************************************
4665 Reply to a writeunlock (core+).
4666 ****************************************************************************/
4668 void reply_writeunlock(struct smb_request *req)
4670 connection_struct *conn = req->conn;
4671 ssize_t nwritten = -1;
4672 size_t numtowrite;
4673 off_t startpos;
4674 const char *data;
4675 NTSTATUS status = NT_STATUS_OK;
4676 files_struct *fsp;
4677 struct lock_struct lock;
4678 int saved_errno = 0;
4680 START_PROFILE(SMBwriteunlock);
4682 if (req->wct < 5) {
4683 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4684 END_PROFILE(SMBwriteunlock);
4685 return;
4688 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4690 if (!check_fsp(conn, req, fsp)) {
4691 END_PROFILE(SMBwriteunlock);
4692 return;
4695 if (!CHECK_WRITE(fsp)) {
4696 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4697 END_PROFILE(SMBwriteunlock);
4698 return;
4701 numtowrite = SVAL(req->vwv+1, 0);
4702 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4703 data = (const char *)req->buf + 3;
4705 if (!fsp->print_file && numtowrite > 0) {
4706 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4707 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4708 &lock);
4710 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4711 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4712 END_PROFILE(SMBwriteunlock);
4713 return;
4717 /* The special X/Open SMB protocol handling of
4718 zero length writes is *NOT* done for
4719 this call */
4720 if(numtowrite == 0) {
4721 nwritten = 0;
4722 } else {
4723 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4724 saved_errno = errno;
4727 status = sync_file(conn, fsp, False /* write through */);
4728 if (!NT_STATUS_IS_OK(status)) {
4729 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4730 fsp_str_dbg(fsp), nt_errstr(status)));
4731 reply_nterror(req, status);
4732 goto strict_unlock;
4735 if(nwritten < 0) {
4736 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4737 goto strict_unlock;
4740 if((nwritten < numtowrite) && (numtowrite != 0)) {
4741 reply_nterror(req, NT_STATUS_DISK_FULL);
4742 goto strict_unlock;
4745 if (numtowrite && !fsp->print_file) {
4746 status = do_unlock(req->sconn->msg_ctx,
4747 fsp,
4748 (uint64_t)req->smbpid,
4749 (uint64_t)numtowrite,
4750 (uint64_t)startpos,
4751 WINDOWS_LOCK);
4753 if (NT_STATUS_V(status)) {
4754 reply_nterror(req, status);
4755 goto strict_unlock;
4759 reply_outbuf(req, 1, 0);
4761 SSVAL(req->outbuf,smb_vwv0,nwritten);
4763 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4764 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4766 strict_unlock:
4767 if (numtowrite && !fsp->print_file) {
4768 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4771 END_PROFILE(SMBwriteunlock);
4772 return;
4775 #undef DBGC_CLASS
4776 #define DBGC_CLASS DBGC_ALL
4778 /****************************************************************************
4779 Reply to a write.
4780 ****************************************************************************/
4782 void reply_write(struct smb_request *req)
4784 connection_struct *conn = req->conn;
4785 size_t numtowrite;
4786 ssize_t nwritten = -1;
4787 off_t startpos;
4788 const char *data;
4789 files_struct *fsp;
4790 struct lock_struct lock;
4791 NTSTATUS status;
4792 int saved_errno = 0;
4794 START_PROFILE(SMBwrite);
4796 if (req->wct < 5) {
4797 END_PROFILE(SMBwrite);
4798 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4799 return;
4802 /* If it's an IPC, pass off the pipe handler. */
4803 if (IS_IPC(conn)) {
4804 reply_pipe_write(req);
4805 END_PROFILE(SMBwrite);
4806 return;
4809 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4811 if (!check_fsp(conn, req, fsp)) {
4812 END_PROFILE(SMBwrite);
4813 return;
4816 if (!CHECK_WRITE(fsp)) {
4817 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4818 END_PROFILE(SMBwrite);
4819 return;
4822 numtowrite = SVAL(req->vwv+1, 0);
4823 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4824 data = (const char *)req->buf + 3;
4826 if (!fsp->print_file) {
4827 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4828 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4829 &lock);
4831 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4832 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4833 END_PROFILE(SMBwrite);
4834 return;
4839 * X/Open SMB protocol says that if smb_vwv1 is
4840 * zero then the file size should be extended or
4841 * truncated to the size given in smb_vwv[2-3].
4844 if(numtowrite == 0) {
4846 * This is actually an allocate call, and set EOF. JRA.
4848 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4849 if (nwritten < 0) {
4850 reply_nterror(req, NT_STATUS_DISK_FULL);
4851 goto strict_unlock;
4853 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4854 if (nwritten < 0) {
4855 reply_nterror(req, NT_STATUS_DISK_FULL);
4856 goto strict_unlock;
4858 trigger_write_time_update_immediate(fsp);
4859 } else {
4860 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4863 status = sync_file(conn, fsp, False);
4864 if (!NT_STATUS_IS_OK(status)) {
4865 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4866 fsp_str_dbg(fsp), nt_errstr(status)));
4867 reply_nterror(req, status);
4868 goto strict_unlock;
4871 if(nwritten < 0) {
4872 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4873 goto strict_unlock;
4876 if((nwritten == 0) && (numtowrite != 0)) {
4877 reply_nterror(req, NT_STATUS_DISK_FULL);
4878 goto strict_unlock;
4881 reply_outbuf(req, 1, 0);
4883 SSVAL(req->outbuf,smb_vwv0,nwritten);
4885 if (nwritten < (ssize_t)numtowrite) {
4886 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4887 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4890 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4892 strict_unlock:
4893 if (!fsp->print_file) {
4894 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4897 END_PROFILE(SMBwrite);
4898 return;
4901 /****************************************************************************
4902 Ensure a buffer is a valid writeX for recvfile purposes.
4903 ****************************************************************************/
4905 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4906 (2*14) + /* word count (including bcc) */ \
4907 1 /* pad byte */)
4909 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4910 const uint8_t *inbuf)
4912 size_t numtowrite;
4913 unsigned int doff = 0;
4914 size_t len = smb_len_large(inbuf);
4915 uint16_t fnum;
4916 struct smbXsrv_open *op = NULL;
4917 struct files_struct *fsp = NULL;
4918 NTSTATUS status;
4920 if (is_encrypted_packet(inbuf)) {
4921 /* Can't do this on encrypted
4922 * connections. */
4923 return false;
4926 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4927 return false;
4930 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4931 CVAL(inbuf,smb_wct) != 14) {
4932 DEBUG(10,("is_valid_writeX_buffer: chained or "
4933 "invalid word length.\n"));
4934 return false;
4937 fnum = SVAL(inbuf, smb_vwv2);
4938 status = smb1srv_open_lookup(xconn,
4939 fnum,
4940 0, /* now */
4941 &op);
4942 if (!NT_STATUS_IS_OK(status)) {
4943 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4944 return false;
4946 fsp = op->compat;
4947 if (fsp == NULL) {
4948 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4949 return false;
4951 if (fsp->conn == NULL) {
4952 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4953 return false;
4956 if (IS_IPC(fsp->conn)) {
4957 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4958 return false;
4960 if (IS_PRINT(fsp->conn)) {
4961 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4962 return false;
4964 doff = SVAL(inbuf,smb_vwv11);
4966 numtowrite = SVAL(inbuf,smb_vwv10);
4968 if (len > doff && len - doff > 0xFFFF) {
4969 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4972 if (numtowrite == 0) {
4973 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4974 return false;
4977 /* Ensure the sizes match up. */
4978 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4979 /* no pad byte...old smbclient :-( */
4980 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4981 (unsigned int)doff,
4982 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4983 return false;
4986 if (len - doff != numtowrite) {
4987 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4988 "len = %u, doff = %u, numtowrite = %u\n",
4989 (unsigned int)len,
4990 (unsigned int)doff,
4991 (unsigned int)numtowrite ));
4992 return false;
4995 DEBUG(10,("is_valid_writeX_buffer: true "
4996 "len = %u, doff = %u, numtowrite = %u\n",
4997 (unsigned int)len,
4998 (unsigned int)doff,
4999 (unsigned int)numtowrite ));
5001 return true;
5004 /****************************************************************************
5005 Reply to a write and X.
5006 ****************************************************************************/
5008 void reply_write_and_X(struct smb_request *req)
5010 connection_struct *conn = req->conn;
5011 struct smbXsrv_connection *xconn = req->xconn;
5012 files_struct *fsp;
5013 struct lock_struct lock;
5014 off_t startpos;
5015 size_t numtowrite;
5016 bool write_through;
5017 ssize_t nwritten;
5018 unsigned int smb_doff;
5019 unsigned int smblen;
5020 const char *data;
5021 NTSTATUS status;
5022 int saved_errno = 0;
5024 START_PROFILE(SMBwriteX);
5026 if ((req->wct != 12) && (req->wct != 14)) {
5027 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5028 goto out;
5031 numtowrite = SVAL(req->vwv+10, 0);
5032 smb_doff = SVAL(req->vwv+11, 0);
5033 smblen = smb_len(req->inbuf);
5035 if (req->unread_bytes > 0xFFFF ||
5036 (smblen > smb_doff &&
5037 smblen - smb_doff > 0xFFFF)) {
5038 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5041 if (req->unread_bytes) {
5042 /* Can't do a recvfile write on IPC$ */
5043 if (IS_IPC(conn)) {
5044 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5045 goto out;
5047 if (numtowrite != req->unread_bytes) {
5048 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5049 goto out;
5051 } else {
5052 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5053 smb_doff + numtowrite > smblen) {
5054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5055 goto out;
5059 /* If it's an IPC, pass off the pipe handler. */
5060 if (IS_IPC(conn)) {
5061 if (req->unread_bytes) {
5062 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5063 goto out;
5065 reply_pipe_write_and_X(req);
5066 goto out;
5069 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5070 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5071 write_through = BITSETW(req->vwv+7,0);
5073 if (!check_fsp(conn, req, fsp)) {
5074 goto out;
5077 if (!CHECK_WRITE(fsp)) {
5078 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5079 goto out;
5082 data = smb_base(req->inbuf) + smb_doff;
5084 if(req->wct == 14) {
5086 * This is a large offset (64 bit) write.
5088 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5092 /* X/Open SMB protocol says that, unlike SMBwrite
5093 if the length is zero then NO truncation is
5094 done, just a write of zero. To truncate a file,
5095 use SMBwrite. */
5097 if(numtowrite == 0) {
5098 nwritten = 0;
5099 } else {
5100 if (req->unread_bytes == 0) {
5101 status = schedule_aio_write_and_X(conn,
5102 req,
5103 fsp,
5104 data,
5105 startpos,
5106 numtowrite);
5108 if (NT_STATUS_IS_OK(status)) {
5109 /* write scheduled - we're done. */
5110 goto out;
5112 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5113 /* Real error - report to client. */
5114 reply_nterror(req, status);
5115 goto out;
5117 /* NT_STATUS_RETRY - fall through to sync write. */
5120 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5121 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5122 &lock);
5124 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5125 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5126 goto out;
5129 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5130 saved_errno = errno;
5132 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5135 if(nwritten < 0) {
5136 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5137 goto out;
5140 if((nwritten == 0) && (numtowrite != 0)) {
5141 reply_nterror(req, NT_STATUS_DISK_FULL);
5142 goto out;
5145 reply_outbuf(req, 6, 0);
5146 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5147 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5148 SSVAL(req->outbuf,smb_vwv2,nwritten);
5149 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5151 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5152 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5154 status = sync_file(conn, fsp, write_through);
5155 if (!NT_STATUS_IS_OK(status)) {
5156 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5157 fsp_str_dbg(fsp), nt_errstr(status)));
5158 reply_nterror(req, status);
5159 goto out;
5162 END_PROFILE(SMBwriteX);
5163 return;
5165 out:
5166 if (req->unread_bytes) {
5167 /* writeX failed. drain socket. */
5168 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5169 req->unread_bytes) {
5170 smb_panic("failed to drain pending bytes");
5172 req->unread_bytes = 0;
5175 END_PROFILE(SMBwriteX);
5176 return;
5179 /****************************************************************************
5180 Reply to a lseek.
5181 ****************************************************************************/
5183 void reply_lseek(struct smb_request *req)
5185 connection_struct *conn = req->conn;
5186 off_t startpos;
5187 off_t res= -1;
5188 int mode,umode;
5189 files_struct *fsp;
5191 START_PROFILE(SMBlseek);
5193 if (req->wct < 4) {
5194 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5195 END_PROFILE(SMBlseek);
5196 return;
5199 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5201 if (!check_fsp(conn, req, fsp)) {
5202 return;
5205 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5207 mode = SVAL(req->vwv+1, 0) & 3;
5208 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5209 startpos = (off_t)IVALS(req->vwv+2, 0);
5211 switch (mode) {
5212 case 0:
5213 umode = SEEK_SET;
5214 res = startpos;
5215 break;
5216 case 1:
5217 umode = SEEK_CUR;
5218 res = fsp->fh->pos + startpos;
5219 break;
5220 case 2:
5221 umode = SEEK_END;
5222 break;
5223 default:
5224 umode = SEEK_SET;
5225 res = startpos;
5226 break;
5229 if (umode == SEEK_END) {
5230 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5231 if(errno == EINVAL) {
5232 off_t current_pos = startpos;
5234 if(fsp_stat(fsp) == -1) {
5235 reply_nterror(req,
5236 map_nt_error_from_unix(errno));
5237 END_PROFILE(SMBlseek);
5238 return;
5241 current_pos += fsp->fsp_name->st.st_ex_size;
5242 if(current_pos < 0)
5243 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5247 if(res == -1) {
5248 reply_nterror(req, map_nt_error_from_unix(errno));
5249 END_PROFILE(SMBlseek);
5250 return;
5254 fsp->fh->pos = res;
5256 reply_outbuf(req, 2, 0);
5257 SIVAL(req->outbuf,smb_vwv0,res);
5259 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5260 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5262 END_PROFILE(SMBlseek);
5263 return;
5266 /****************************************************************************
5267 Reply to a flush.
5268 ****************************************************************************/
5270 void reply_flush(struct smb_request *req)
5272 connection_struct *conn = req->conn;
5273 uint16_t fnum;
5274 files_struct *fsp;
5276 START_PROFILE(SMBflush);
5278 if (req->wct < 1) {
5279 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5280 return;
5283 fnum = SVAL(req->vwv+0, 0);
5284 fsp = file_fsp(req, fnum);
5286 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5287 return;
5290 if (!fsp) {
5291 file_sync_all(conn);
5292 } else {
5293 NTSTATUS status = sync_file(conn, fsp, True);
5294 if (!NT_STATUS_IS_OK(status)) {
5295 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5296 fsp_str_dbg(fsp), nt_errstr(status)));
5297 reply_nterror(req, status);
5298 END_PROFILE(SMBflush);
5299 return;
5303 reply_outbuf(req, 0, 0);
5305 DEBUG(3,("flush\n"));
5306 END_PROFILE(SMBflush);
5307 return;
5310 /****************************************************************************
5311 Reply to a exit.
5312 conn POINTER CAN BE NULL HERE !
5313 ****************************************************************************/
5315 void reply_exit(struct smb_request *req)
5317 START_PROFILE(SMBexit);
5319 file_close_pid(req->sconn, req->smbpid, req->vuid);
5321 reply_outbuf(req, 0, 0);
5323 DEBUG(3,("exit\n"));
5325 END_PROFILE(SMBexit);
5326 return;
5329 struct reply_close_state {
5330 files_struct *fsp;
5331 struct smb_request *smbreq;
5334 static void do_smb1_close(struct tevent_req *req);
5336 void reply_close(struct smb_request *req)
5338 connection_struct *conn = req->conn;
5339 NTSTATUS status = NT_STATUS_OK;
5340 files_struct *fsp = NULL;
5341 START_PROFILE(SMBclose);
5343 if (req->wct < 3) {
5344 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5345 END_PROFILE(SMBclose);
5346 return;
5349 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5352 * We can only use check_fsp if we know it's not a directory.
5355 if (!check_fsp_open(conn, req, fsp)) {
5356 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5357 END_PROFILE(SMBclose);
5358 return;
5361 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5362 fsp->is_directory ? "directory" : "file",
5363 fsp->fh->fd, fsp_fnum_dbg(fsp),
5364 conn->num_files_open));
5366 if (!fsp->is_directory) {
5367 time_t t;
5370 * Take care of any time sent in the close.
5373 t = srv_make_unix_date3(req->vwv+1);
5374 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5377 if (fsp->num_aio_requests != 0) {
5379 struct reply_close_state *state;
5381 DEBUG(10, ("closing with aio %u requests pending\n",
5382 fsp->num_aio_requests));
5385 * We depend on the aio_extra destructor to take care of this
5386 * close request once fsp->num_aio_request drops to 0.
5389 fsp->deferred_close = tevent_wait_send(
5390 fsp, fsp->conn->sconn->ev_ctx);
5391 if (fsp->deferred_close == NULL) {
5392 status = NT_STATUS_NO_MEMORY;
5393 goto done;
5396 state = talloc(fsp, struct reply_close_state);
5397 if (state == NULL) {
5398 TALLOC_FREE(fsp->deferred_close);
5399 status = NT_STATUS_NO_MEMORY;
5400 goto done;
5402 state->fsp = fsp;
5403 state->smbreq = talloc_move(fsp, &req);
5404 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5405 state);
5406 END_PROFILE(SMBclose);
5407 return;
5411 * close_file() returns the unix errno if an error was detected on
5412 * close - normally this is due to a disk full error. If not then it
5413 * was probably an I/O error.
5416 status = close_file(req, fsp, NORMAL_CLOSE);
5417 done:
5418 if (!NT_STATUS_IS_OK(status)) {
5419 reply_nterror(req, status);
5420 END_PROFILE(SMBclose);
5421 return;
5424 reply_outbuf(req, 0, 0);
5425 END_PROFILE(SMBclose);
5426 return;
5429 static void do_smb1_close(struct tevent_req *req)
5431 struct reply_close_state *state = tevent_req_callback_data(
5432 req, struct reply_close_state);
5433 struct smb_request *smbreq;
5434 NTSTATUS status;
5435 int ret;
5437 ret = tevent_wait_recv(req);
5438 TALLOC_FREE(req);
5439 if (ret != 0) {
5440 DEBUG(10, ("tevent_wait_recv returned %s\n",
5441 strerror(ret)));
5443 * Continue anyway, this should never happen
5448 * fsp->smb2_close_request right now is a talloc grandchild of
5449 * fsp. When we close_file(fsp), it would go with it. No chance to
5450 * reply...
5452 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5454 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5455 if (NT_STATUS_IS_OK(status)) {
5456 reply_outbuf(smbreq, 0, 0);
5457 } else {
5458 reply_nterror(smbreq, status);
5460 if (!srv_send_smb(smbreq->xconn,
5461 (char *)smbreq->outbuf,
5462 true,
5463 smbreq->seqnum+1,
5464 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5465 NULL)) {
5466 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5467 "failed.");
5469 TALLOC_FREE(smbreq);
5472 /****************************************************************************
5473 Reply to a writeclose (Core+ protocol).
5474 ****************************************************************************/
5476 void reply_writeclose(struct smb_request *req)
5478 connection_struct *conn = req->conn;
5479 size_t numtowrite;
5480 ssize_t nwritten = -1;
5481 NTSTATUS close_status = NT_STATUS_OK;
5482 off_t startpos;
5483 const char *data;
5484 struct timespec mtime;
5485 files_struct *fsp;
5486 struct lock_struct lock;
5488 START_PROFILE(SMBwriteclose);
5490 if (req->wct < 6) {
5491 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5492 END_PROFILE(SMBwriteclose);
5493 return;
5496 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5498 if (!check_fsp(conn, req, fsp)) {
5499 END_PROFILE(SMBwriteclose);
5500 return;
5502 if (!CHECK_WRITE(fsp)) {
5503 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5504 END_PROFILE(SMBwriteclose);
5505 return;
5508 numtowrite = SVAL(req->vwv+1, 0);
5509 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5510 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5511 data = (const char *)req->buf + 1;
5513 if (fsp->print_file == NULL) {
5514 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5515 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5516 &lock);
5518 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5519 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5520 END_PROFILE(SMBwriteclose);
5521 return;
5525 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5527 if (fsp->print_file == NULL) {
5528 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5531 set_close_write_time(fsp, mtime);
5534 * More insanity. W2K only closes the file if writelen > 0.
5535 * JRA.
5538 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5539 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5540 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5542 if (numtowrite) {
5543 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5544 "file %s\n", fsp_str_dbg(fsp)));
5545 close_status = close_file(req, fsp, NORMAL_CLOSE);
5546 fsp = NULL;
5549 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5550 reply_nterror(req, NT_STATUS_DISK_FULL);
5551 goto out;
5554 if(!NT_STATUS_IS_OK(close_status)) {
5555 reply_nterror(req, close_status);
5556 goto out;
5559 reply_outbuf(req, 1, 0);
5561 SSVAL(req->outbuf,smb_vwv0,nwritten);
5563 out:
5565 END_PROFILE(SMBwriteclose);
5566 return;
5569 #undef DBGC_CLASS
5570 #define DBGC_CLASS DBGC_LOCKING
5572 /****************************************************************************
5573 Reply to a lock.
5574 ****************************************************************************/
5576 void reply_lock(struct smb_request *req)
5578 connection_struct *conn = req->conn;
5579 uint64_t count,offset;
5580 NTSTATUS status;
5581 files_struct *fsp;
5582 struct byte_range_lock *br_lck = NULL;
5584 START_PROFILE(SMBlock);
5586 if (req->wct < 5) {
5587 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5588 END_PROFILE(SMBlock);
5589 return;
5592 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5594 if (!check_fsp(conn, req, fsp)) {
5595 END_PROFILE(SMBlock);
5596 return;
5599 count = (uint64_t)IVAL(req->vwv+1, 0);
5600 offset = (uint64_t)IVAL(req->vwv+3, 0);
5602 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5603 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5605 br_lck = do_lock(req->sconn->msg_ctx,
5606 fsp,
5607 (uint64_t)req->smbpid,
5608 count,
5609 offset,
5610 WRITE_LOCK,
5611 WINDOWS_LOCK,
5612 False, /* Non-blocking lock. */
5613 &status,
5614 NULL);
5616 TALLOC_FREE(br_lck);
5618 if (NT_STATUS_V(status)) {
5619 reply_nterror(req, status);
5620 END_PROFILE(SMBlock);
5621 return;
5624 reply_outbuf(req, 0, 0);
5626 END_PROFILE(SMBlock);
5627 return;
5630 /****************************************************************************
5631 Reply to a unlock.
5632 ****************************************************************************/
5634 void reply_unlock(struct smb_request *req)
5636 connection_struct *conn = req->conn;
5637 uint64_t count,offset;
5638 NTSTATUS status;
5639 files_struct *fsp;
5641 START_PROFILE(SMBunlock);
5643 if (req->wct < 5) {
5644 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5645 END_PROFILE(SMBunlock);
5646 return;
5649 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5651 if (!check_fsp(conn, req, fsp)) {
5652 END_PROFILE(SMBunlock);
5653 return;
5656 count = (uint64_t)IVAL(req->vwv+1, 0);
5657 offset = (uint64_t)IVAL(req->vwv+3, 0);
5659 status = do_unlock(req->sconn->msg_ctx,
5660 fsp,
5661 (uint64_t)req->smbpid,
5662 count,
5663 offset,
5664 WINDOWS_LOCK);
5666 if (NT_STATUS_V(status)) {
5667 reply_nterror(req, status);
5668 END_PROFILE(SMBunlock);
5669 return;
5672 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5673 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5675 reply_outbuf(req, 0, 0);
5677 END_PROFILE(SMBunlock);
5678 return;
5681 #undef DBGC_CLASS
5682 #define DBGC_CLASS DBGC_ALL
5684 /****************************************************************************
5685 Reply to a tdis.
5686 conn POINTER CAN BE NULL HERE !
5687 ****************************************************************************/
5689 void reply_tdis(struct smb_request *req)
5691 NTSTATUS status;
5692 connection_struct *conn = req->conn;
5693 struct smbXsrv_tcon *tcon;
5695 START_PROFILE(SMBtdis);
5697 if (!conn) {
5698 DEBUG(4,("Invalid connection in tdis\n"));
5699 reply_force_doserror(req, ERRSRV, ERRinvnid);
5700 END_PROFILE(SMBtdis);
5701 return;
5704 tcon = conn->tcon;
5705 req->conn = NULL;
5708 * TODO: cancel all outstanding requests on the tcon
5710 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5711 if (!NT_STATUS_IS_OK(status)) {
5712 DEBUG(0, ("reply_tdis: "
5713 "smbXsrv_tcon_disconnect() failed: %s\n",
5714 nt_errstr(status)));
5716 * If we hit this case, there is something completely
5717 * wrong, so we better disconnect the transport connection.
5719 END_PROFILE(SMBtdis);
5720 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5721 return;
5724 TALLOC_FREE(tcon);
5726 reply_outbuf(req, 0, 0);
5727 END_PROFILE(SMBtdis);
5728 return;
5731 /****************************************************************************
5732 Reply to a echo.
5733 conn POINTER CAN BE NULL HERE !
5734 ****************************************************************************/
5736 void reply_echo(struct smb_request *req)
5738 connection_struct *conn = req->conn;
5739 struct smb_perfcount_data local_pcd;
5740 struct smb_perfcount_data *cur_pcd;
5741 int smb_reverb;
5742 int seq_num;
5744 START_PROFILE(SMBecho);
5746 smb_init_perfcount_data(&local_pcd);
5748 if (req->wct < 1) {
5749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5750 END_PROFILE(SMBecho);
5751 return;
5754 smb_reverb = SVAL(req->vwv+0, 0);
5756 reply_outbuf(req, 1, req->buflen);
5758 /* copy any incoming data back out */
5759 if (req->buflen > 0) {
5760 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5763 if (smb_reverb > 100) {
5764 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5765 smb_reverb = 100;
5768 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5770 /* this makes sure we catch the request pcd */
5771 if (seq_num == smb_reverb) {
5772 cur_pcd = &req->pcd;
5773 } else {
5774 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5775 cur_pcd = &local_pcd;
5778 SSVAL(req->outbuf,smb_vwv0,seq_num);
5780 show_msg((char *)req->outbuf);
5781 if (!srv_send_smb(req->xconn,
5782 (char *)req->outbuf,
5783 true, req->seqnum+1,
5784 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5785 cur_pcd))
5786 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5789 DEBUG(3,("echo %d times\n", smb_reverb));
5791 TALLOC_FREE(req->outbuf);
5793 END_PROFILE(SMBecho);
5794 return;
5797 /****************************************************************************
5798 Reply to a printopen.
5799 ****************************************************************************/
5801 void reply_printopen(struct smb_request *req)
5803 connection_struct *conn = req->conn;
5804 files_struct *fsp;
5805 NTSTATUS status;
5807 START_PROFILE(SMBsplopen);
5809 if (req->wct < 2) {
5810 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5811 END_PROFILE(SMBsplopen);
5812 return;
5815 if (!CAN_PRINT(conn)) {
5816 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5817 END_PROFILE(SMBsplopen);
5818 return;
5821 status = file_new(req, conn, &fsp);
5822 if(!NT_STATUS_IS_OK(status)) {
5823 reply_nterror(req, status);
5824 END_PROFILE(SMBsplopen);
5825 return;
5828 /* Open for exclusive use, write only. */
5829 status = print_spool_open(fsp, NULL, req->vuid);
5831 if (!NT_STATUS_IS_OK(status)) {
5832 file_free(req, fsp);
5833 reply_nterror(req, status);
5834 END_PROFILE(SMBsplopen);
5835 return;
5838 reply_outbuf(req, 1, 0);
5839 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5841 DEBUG(3,("openprint fd=%d %s\n",
5842 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5844 END_PROFILE(SMBsplopen);
5845 return;
5848 /****************************************************************************
5849 Reply to a printclose.
5850 ****************************************************************************/
5852 void reply_printclose(struct smb_request *req)
5854 connection_struct *conn = req->conn;
5855 files_struct *fsp;
5856 NTSTATUS status;
5858 START_PROFILE(SMBsplclose);
5860 if (req->wct < 1) {
5861 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5862 END_PROFILE(SMBsplclose);
5863 return;
5866 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5868 if (!check_fsp(conn, req, fsp)) {
5869 END_PROFILE(SMBsplclose);
5870 return;
5873 if (!CAN_PRINT(conn)) {
5874 reply_force_doserror(req, ERRSRV, ERRerror);
5875 END_PROFILE(SMBsplclose);
5876 return;
5879 DEBUG(3,("printclose fd=%d %s\n",
5880 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5882 status = close_file(req, fsp, NORMAL_CLOSE);
5884 if(!NT_STATUS_IS_OK(status)) {
5885 reply_nterror(req, status);
5886 END_PROFILE(SMBsplclose);
5887 return;
5890 reply_outbuf(req, 0, 0);
5892 END_PROFILE(SMBsplclose);
5893 return;
5896 /****************************************************************************
5897 Reply to a printqueue.
5898 ****************************************************************************/
5900 void reply_printqueue(struct smb_request *req)
5902 connection_struct *conn = req->conn;
5903 int max_count;
5904 int start_index;
5906 START_PROFILE(SMBsplretq);
5908 if (req->wct < 2) {
5909 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5910 END_PROFILE(SMBsplretq);
5911 return;
5914 max_count = SVAL(req->vwv+0, 0);
5915 start_index = SVAL(req->vwv+1, 0);
5917 /* we used to allow the client to get the cnum wrong, but that
5918 is really quite gross and only worked when there was only
5919 one printer - I think we should now only accept it if they
5920 get it right (tridge) */
5921 if (!CAN_PRINT(conn)) {
5922 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5923 END_PROFILE(SMBsplretq);
5924 return;
5927 reply_outbuf(req, 2, 3);
5928 SSVAL(req->outbuf,smb_vwv0,0);
5929 SSVAL(req->outbuf,smb_vwv1,0);
5930 SCVAL(smb_buf(req->outbuf),0,1);
5931 SSVAL(smb_buf(req->outbuf),1,0);
5933 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5934 start_index, max_count));
5937 TALLOC_CTX *mem_ctx = talloc_tos();
5938 NTSTATUS status;
5939 WERROR werr;
5940 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5941 struct rpc_pipe_client *cli = NULL;
5942 struct dcerpc_binding_handle *b = NULL;
5943 struct policy_handle handle;
5944 struct spoolss_DevmodeContainer devmode_ctr;
5945 union spoolss_JobInfo *info;
5946 uint32_t count;
5947 uint32_t num_to_get;
5948 uint32_t first;
5949 uint32_t i;
5951 ZERO_STRUCT(handle);
5953 status = rpc_pipe_open_interface(conn,
5954 &ndr_table_spoolss,
5955 conn->session_info,
5956 conn->sconn->remote_address,
5957 conn->sconn->msg_ctx,
5958 &cli);
5959 if (!NT_STATUS_IS_OK(status)) {
5960 DEBUG(0, ("reply_printqueue: "
5961 "could not connect to spoolss: %s\n",
5962 nt_errstr(status)));
5963 reply_nterror(req, status);
5964 goto out;
5966 b = cli->binding_handle;
5968 ZERO_STRUCT(devmode_ctr);
5970 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5971 sharename,
5972 NULL, devmode_ctr,
5973 SEC_FLAG_MAXIMUM_ALLOWED,
5974 &handle,
5975 &werr);
5976 if (!NT_STATUS_IS_OK(status)) {
5977 reply_nterror(req, status);
5978 goto out;
5980 if (!W_ERROR_IS_OK(werr)) {
5981 reply_nterror(req, werror_to_ntstatus(werr));
5982 goto out;
5985 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5986 &handle,
5987 0, /* firstjob */
5988 0xff, /* numjobs */
5989 2, /* level */
5990 0, /* offered */
5991 &count,
5992 &info);
5993 if (!W_ERROR_IS_OK(werr)) {
5994 reply_nterror(req, werror_to_ntstatus(werr));
5995 goto out;
5998 if (max_count > 0) {
5999 first = start_index;
6000 } else {
6001 first = start_index + max_count + 1;
6004 if (first >= count) {
6005 num_to_get = first;
6006 } else {
6007 num_to_get = first + MIN(ABS(max_count), count - first);
6010 for (i = first; i < num_to_get; i++) {
6011 char blob[28];
6012 char *p = blob;
6013 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6014 int qstatus;
6015 size_t len = 0;
6016 uint16_t qrapjobid = pjobid_to_rap(sharename,
6017 info[i].info2.job_id);
6019 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6020 qstatus = 2;
6021 } else {
6022 qstatus = 3;
6025 srv_put_dos_date2(p, 0, qtime);
6026 SCVAL(p, 4, qstatus);
6027 SSVAL(p, 5, qrapjobid);
6028 SIVAL(p, 7, info[i].info2.size);
6029 SCVAL(p, 11, 0);
6030 status = srvstr_push(blob, req->flags2, p+12,
6031 info[i].info2.notify_name, 16, STR_ASCII, &len);
6032 if (!NT_STATUS_IS_OK(status)) {
6033 reply_nterror(req, status);
6034 goto out;
6036 if (message_push_blob(
6037 &req->outbuf,
6038 data_blob_const(
6039 blob, sizeof(blob))) == -1) {
6040 reply_nterror(req, NT_STATUS_NO_MEMORY);
6041 goto out;
6045 if (count > 0) {
6046 SSVAL(req->outbuf,smb_vwv0,count);
6047 SSVAL(req->outbuf,smb_vwv1,
6048 (max_count>0?first+count:first-1));
6049 SCVAL(smb_buf(req->outbuf),0,1);
6050 SSVAL(smb_buf(req->outbuf),1,28*count);
6054 DEBUG(3, ("%u entries returned in queue\n",
6055 (unsigned)count));
6057 out:
6058 if (b && is_valid_policy_hnd(&handle)) {
6059 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6064 END_PROFILE(SMBsplretq);
6065 return;
6068 /****************************************************************************
6069 Reply to a printwrite.
6070 ****************************************************************************/
6072 void reply_printwrite(struct smb_request *req)
6074 connection_struct *conn = req->conn;
6075 int numtowrite;
6076 const char *data;
6077 files_struct *fsp;
6079 START_PROFILE(SMBsplwr);
6081 if (req->wct < 1) {
6082 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6083 END_PROFILE(SMBsplwr);
6084 return;
6087 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6089 if (!check_fsp(conn, req, fsp)) {
6090 END_PROFILE(SMBsplwr);
6091 return;
6094 if (!fsp->print_file) {
6095 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6096 END_PROFILE(SMBsplwr);
6097 return;
6100 if (!CHECK_WRITE(fsp)) {
6101 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6102 END_PROFILE(SMBsplwr);
6103 return;
6106 numtowrite = SVAL(req->buf, 1);
6108 if (req->buflen < numtowrite + 3) {
6109 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6110 END_PROFILE(SMBsplwr);
6111 return;
6114 data = (const char *)req->buf + 3;
6116 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6117 reply_nterror(req, map_nt_error_from_unix(errno));
6118 END_PROFILE(SMBsplwr);
6119 return;
6122 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6124 END_PROFILE(SMBsplwr);
6125 return;
6128 /****************************************************************************
6129 Reply to a mkdir.
6130 ****************************************************************************/
6132 void reply_mkdir(struct smb_request *req)
6134 connection_struct *conn = req->conn;
6135 struct smb_filename *smb_dname = NULL;
6136 char *directory = NULL;
6137 NTSTATUS status;
6138 uint32_t ucf_flags;
6139 TALLOC_CTX *ctx = talloc_tos();
6141 START_PROFILE(SMBmkdir);
6143 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6144 STR_TERMINATE, &status);
6145 if (!NT_STATUS_IS_OK(status)) {
6146 reply_nterror(req, status);
6147 goto out;
6150 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6151 status = filename_convert(ctx, conn,
6152 req->flags2 & FLAGS2_DFS_PATHNAMES,
6153 directory,
6154 ucf_flags,
6155 NULL,
6156 &smb_dname);
6157 if (!NT_STATUS_IS_OK(status)) {
6158 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6159 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6160 ERRSRV, ERRbadpath);
6161 goto out;
6163 reply_nterror(req, status);
6164 goto out;
6167 status = create_directory(conn, req, smb_dname);
6169 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6171 if (!NT_STATUS_IS_OK(status)) {
6173 if (!use_nt_status()
6174 && NT_STATUS_EQUAL(status,
6175 NT_STATUS_OBJECT_NAME_COLLISION)) {
6177 * Yes, in the DOS error code case we get a
6178 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6179 * samba4 torture test.
6181 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6184 reply_nterror(req, status);
6185 goto out;
6188 reply_outbuf(req, 0, 0);
6190 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6191 out:
6192 TALLOC_FREE(smb_dname);
6193 END_PROFILE(SMBmkdir);
6194 return;
6197 /****************************************************************************
6198 Reply to a rmdir.
6199 ****************************************************************************/
6201 void reply_rmdir(struct smb_request *req)
6203 connection_struct *conn = req->conn;
6204 struct smb_filename *smb_dname = NULL;
6205 char *directory = NULL;
6206 NTSTATUS status;
6207 TALLOC_CTX *ctx = talloc_tos();
6208 files_struct *fsp = NULL;
6209 int info = 0;
6210 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
6211 struct smbd_server_connection *sconn = req->sconn;
6213 START_PROFILE(SMBrmdir);
6215 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6216 STR_TERMINATE, &status);
6217 if (!NT_STATUS_IS_OK(status)) {
6218 reply_nterror(req, status);
6219 goto out;
6222 status = filename_convert(ctx, conn,
6223 req->flags2 & FLAGS2_DFS_PATHNAMES,
6224 directory,
6225 ucf_flags,
6226 NULL,
6227 &smb_dname);
6228 if (!NT_STATUS_IS_OK(status)) {
6229 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6230 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6231 ERRSRV, ERRbadpath);
6232 goto out;
6234 reply_nterror(req, status);
6235 goto out;
6238 if (is_ntfs_stream_smb_fname(smb_dname)) {
6239 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6240 goto out;
6243 status = SMB_VFS_CREATE_FILE(
6244 conn, /* conn */
6245 req, /* req */
6246 0, /* root_dir_fid */
6247 smb_dname, /* fname */
6248 DELETE_ACCESS, /* access_mask */
6249 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6250 FILE_SHARE_DELETE),
6251 FILE_OPEN, /* create_disposition*/
6252 FILE_DIRECTORY_FILE, /* create_options */
6253 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6254 0, /* oplock_request */
6255 NULL, /* lease */
6256 0, /* allocation_size */
6257 0, /* private_flags */
6258 NULL, /* sd */
6259 NULL, /* ea_list */
6260 &fsp, /* result */
6261 &info, /* pinfo */
6262 NULL, NULL); /* create context */
6264 if (!NT_STATUS_IS_OK(status)) {
6265 if (open_was_deferred(req->xconn, req->mid)) {
6266 /* We have re-scheduled this call. */
6267 goto out;
6269 reply_nterror(req, status);
6270 goto out;
6273 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6274 if (!NT_STATUS_IS_OK(status)) {
6275 close_file(req, fsp, ERROR_CLOSE);
6276 reply_nterror(req, status);
6277 goto out;
6280 if (!set_delete_on_close(fsp, true,
6281 conn->session_info->security_token,
6282 conn->session_info->unix_token)) {
6283 close_file(req, fsp, ERROR_CLOSE);
6284 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6285 goto out;
6288 status = close_file(req, fsp, NORMAL_CLOSE);
6289 if (!NT_STATUS_IS_OK(status)) {
6290 reply_nterror(req, status);
6291 } else {
6292 reply_outbuf(req, 0, 0);
6295 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6297 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6298 out:
6299 TALLOC_FREE(smb_dname);
6300 END_PROFILE(SMBrmdir);
6301 return;
6304 /*******************************************************************
6305 Resolve wildcards in a filename rename.
6306 ********************************************************************/
6308 static bool resolve_wildcards(TALLOC_CTX *ctx,
6309 const char *name1,
6310 const char *name2,
6311 char **pp_newname)
6313 char *name2_copy = NULL;
6314 char *root1 = NULL;
6315 char *root2 = NULL;
6316 char *ext1 = NULL;
6317 char *ext2 = NULL;
6318 char *p,*p2, *pname1, *pname2;
6320 name2_copy = talloc_strdup(ctx, name2);
6321 if (!name2_copy) {
6322 return False;
6325 pname1 = strrchr_m(name1,'/');
6326 pname2 = strrchr_m(name2_copy,'/');
6328 if (!pname1 || !pname2) {
6329 return False;
6332 /* Truncate the copy of name2 at the last '/' */
6333 *pname2 = '\0';
6335 /* Now go past the '/' */
6336 pname1++;
6337 pname2++;
6339 root1 = talloc_strdup(ctx, pname1);
6340 root2 = talloc_strdup(ctx, pname2);
6342 if (!root1 || !root2) {
6343 return False;
6346 p = strrchr_m(root1,'.');
6347 if (p) {
6348 *p = 0;
6349 ext1 = talloc_strdup(ctx, p+1);
6350 } else {
6351 ext1 = talloc_strdup(ctx, "");
6353 p = strrchr_m(root2,'.');
6354 if (p) {
6355 *p = 0;
6356 ext2 = talloc_strdup(ctx, p+1);
6357 } else {
6358 ext2 = talloc_strdup(ctx, "");
6361 if (!ext1 || !ext2) {
6362 return False;
6365 p = root1;
6366 p2 = root2;
6367 while (*p2) {
6368 if (*p2 == '?') {
6369 /* Hmmm. Should this be mb-aware ? */
6370 *p2 = *p;
6371 p2++;
6372 } else if (*p2 == '*') {
6373 *p2 = '\0';
6374 root2 = talloc_asprintf(ctx, "%s%s",
6375 root2,
6377 if (!root2) {
6378 return False;
6380 break;
6381 } else {
6382 p2++;
6384 if (*p) {
6385 p++;
6389 p = ext1;
6390 p2 = ext2;
6391 while (*p2) {
6392 if (*p2 == '?') {
6393 /* Hmmm. Should this be mb-aware ? */
6394 *p2 = *p;
6395 p2++;
6396 } else if (*p2 == '*') {
6397 *p2 = '\0';
6398 ext2 = talloc_asprintf(ctx, "%s%s",
6399 ext2,
6401 if (!ext2) {
6402 return False;
6404 break;
6405 } else {
6406 p2++;
6408 if (*p) {
6409 p++;
6413 if (*ext2) {
6414 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6415 name2_copy,
6416 root2,
6417 ext2);
6418 } else {
6419 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6420 name2_copy,
6421 root2);
6424 if (!*pp_newname) {
6425 return False;
6428 return True;
6431 /****************************************************************************
6432 Ensure open files have their names updated. Updated to notify other smbd's
6433 asynchronously.
6434 ****************************************************************************/
6436 static void rename_open_files(connection_struct *conn,
6437 struct share_mode_lock *lck,
6438 struct file_id id,
6439 uint32_t orig_name_hash,
6440 const struct smb_filename *smb_fname_dst)
6442 files_struct *fsp;
6443 bool did_rename = False;
6444 NTSTATUS status;
6445 uint32_t new_name_hash = 0;
6447 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6448 fsp = file_find_di_next(fsp)) {
6449 /* fsp_name is a relative path under the fsp. To change this for other
6450 sharepaths we need to manipulate relative paths. */
6451 /* TODO - create the absolute path and manipulate the newname
6452 relative to the sharepath. */
6453 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6454 continue;
6456 if (fsp->name_hash != orig_name_hash) {
6457 continue;
6459 DEBUG(10, ("rename_open_files: renaming file %s "
6460 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6461 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6462 smb_fname_str_dbg(smb_fname_dst)));
6464 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6465 if (NT_STATUS_IS_OK(status)) {
6466 did_rename = True;
6467 new_name_hash = fsp->name_hash;
6471 if (!did_rename) {
6472 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6473 "for %s\n", file_id_string_tos(&id),
6474 smb_fname_str_dbg(smb_fname_dst)));
6477 /* Send messages to all smbd's (not ourself) that the name has changed. */
6478 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6479 orig_name_hash, new_name_hash,
6480 smb_fname_dst);
6484 /****************************************************************************
6485 We need to check if the source path is a parent directory of the destination
6486 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6487 refuse the rename with a sharing violation. Under UNIX the above call can
6488 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6489 probably need to check that the client is a Windows one before disallowing
6490 this as a UNIX client (one with UNIX extensions) can know the source is a
6491 symlink and make this decision intelligently. Found by an excellent bug
6492 report from <AndyLiebman@aol.com>.
6493 ****************************************************************************/
6495 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6496 const struct smb_filename *smb_fname_dst)
6498 const char *psrc = smb_fname_src->base_name;
6499 const char *pdst = smb_fname_dst->base_name;
6500 size_t slen;
6502 if (psrc[0] == '.' && psrc[1] == '/') {
6503 psrc += 2;
6505 if (pdst[0] == '.' && pdst[1] == '/') {
6506 pdst += 2;
6508 if ((slen = strlen(psrc)) > strlen(pdst)) {
6509 return False;
6511 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6515 * Do the notify calls from a rename
6518 static void notify_rename(connection_struct *conn, bool is_dir,
6519 const struct smb_filename *smb_fname_src,
6520 const struct smb_filename *smb_fname_dst)
6522 char *parent_dir_src = NULL;
6523 char *parent_dir_dst = NULL;
6524 uint32_t mask;
6526 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6527 : FILE_NOTIFY_CHANGE_FILE_NAME;
6529 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6530 &parent_dir_src, NULL) ||
6531 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6532 &parent_dir_dst, NULL)) {
6533 goto out;
6536 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6537 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6538 smb_fname_src->base_name);
6539 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6540 smb_fname_dst->base_name);
6542 else {
6543 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6544 smb_fname_src->base_name);
6545 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6546 smb_fname_dst->base_name);
6549 /* this is a strange one. w2k3 gives an additional event for
6550 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6551 files, but not directories */
6552 if (!is_dir) {
6553 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6554 FILE_NOTIFY_CHANGE_ATTRIBUTES
6555 |FILE_NOTIFY_CHANGE_CREATION,
6556 smb_fname_dst->base_name);
6558 out:
6559 TALLOC_FREE(parent_dir_src);
6560 TALLOC_FREE(parent_dir_dst);
6563 /****************************************************************************
6564 Returns an error if the parent directory for a filename is open in an
6565 incompatible way.
6566 ****************************************************************************/
6568 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6569 const struct smb_filename *smb_fname_dst_in)
6571 char *parent_dir = NULL;
6572 struct smb_filename smb_fname_parent;
6573 struct file_id id;
6574 files_struct *fsp = NULL;
6575 int ret;
6577 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6578 &parent_dir, NULL)) {
6579 return NT_STATUS_NO_MEMORY;
6581 ZERO_STRUCT(smb_fname_parent);
6582 smb_fname_parent.base_name = parent_dir;
6584 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6585 if (ret == -1) {
6586 return map_nt_error_from_unix(errno);
6590 * We're only checking on this smbd here, mostly good
6591 * enough.. and will pass tests.
6594 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6595 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6596 fsp = file_find_di_next(fsp)) {
6597 if (fsp->access_mask & DELETE_ACCESS) {
6598 return NT_STATUS_SHARING_VIOLATION;
6601 return NT_STATUS_OK;
6604 /****************************************************************************
6605 Rename an open file - given an fsp.
6606 ****************************************************************************/
6608 NTSTATUS rename_internals_fsp(connection_struct *conn,
6609 files_struct *fsp,
6610 const struct smb_filename *smb_fname_dst_in,
6611 uint32_t attrs,
6612 bool replace_if_exists)
6614 TALLOC_CTX *ctx = talloc_tos();
6615 struct smb_filename *smb_fname_dst = NULL;
6616 NTSTATUS status = NT_STATUS_OK;
6617 struct share_mode_lock *lck = NULL;
6618 uint32_t access_mask = SEC_DIR_ADD_FILE;
6619 bool dst_exists, old_is_stream, new_is_stream;
6621 status = check_name(conn, smb_fname_dst_in->base_name);
6622 if (!NT_STATUS_IS_OK(status)) {
6623 return status;
6626 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6627 if (!NT_STATUS_IS_OK(status)) {
6628 return status;
6631 /* Make a copy of the dst smb_fname structs */
6633 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6634 if (smb_fname_dst == NULL) {
6635 status = NT_STATUS_NO_MEMORY;
6636 goto out;
6640 * Check for special case with case preserving and not
6641 * case sensitive. If the new last component differs from the original
6642 * last component only by case, then we should allow
6643 * the rename (user is trying to change the case of the
6644 * filename).
6646 if (!conn->case_sensitive && conn->case_preserve &&
6647 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6648 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6649 char *fname_dst_parent = NULL;
6650 const char *fname_dst_lcomp = NULL;
6651 char *orig_lcomp_path = NULL;
6652 char *orig_lcomp_stream = NULL;
6653 bool ok = true;
6656 * Split off the last component of the processed
6657 * destination name. We will compare this to
6658 * the split components of smb_fname_dst->original_lcomp.
6660 if (!parent_dirname(ctx,
6661 smb_fname_dst->base_name,
6662 &fname_dst_parent,
6663 &fname_dst_lcomp)) {
6664 status = NT_STATUS_NO_MEMORY;
6665 goto out;
6669 * The original_lcomp component contains
6670 * the last_component of the path + stream
6671 * name (if a stream exists).
6673 * Split off the stream name so we
6674 * can check them separately.
6677 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6678 /* POSIX - no stream component. */
6679 orig_lcomp_path = talloc_strdup(ctx,
6680 smb_fname_dst->original_lcomp);
6681 if (orig_lcomp_path == NULL) {
6682 ok = false;
6684 } else {
6685 ok = split_stream_filename(ctx,
6686 smb_fname_dst->original_lcomp,
6687 &orig_lcomp_path,
6688 &orig_lcomp_stream);
6691 if (!ok) {
6692 TALLOC_FREE(fname_dst_parent);
6693 status = NT_STATUS_NO_MEMORY;
6694 goto out;
6697 /* If the base names only differ by case, use original. */
6698 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6699 char *tmp;
6701 * Replace the modified last component with the
6702 * original.
6704 if (!ISDOT(fname_dst_parent)) {
6705 tmp = talloc_asprintf(smb_fname_dst,
6706 "%s/%s",
6707 fname_dst_parent,
6708 orig_lcomp_path);
6709 } else {
6710 tmp = talloc_strdup(smb_fname_dst,
6711 orig_lcomp_path);
6713 if (tmp == NULL) {
6714 status = NT_STATUS_NO_MEMORY;
6715 TALLOC_FREE(fname_dst_parent);
6716 TALLOC_FREE(orig_lcomp_path);
6717 TALLOC_FREE(orig_lcomp_stream);
6718 goto out;
6720 TALLOC_FREE(smb_fname_dst->base_name);
6721 smb_fname_dst->base_name = tmp;
6724 /* If the stream_names only differ by case, use original. */
6725 if(!strcsequal(smb_fname_dst->stream_name,
6726 orig_lcomp_stream)) {
6727 /* Use the original stream. */
6728 char *tmp = talloc_strdup(smb_fname_dst,
6729 orig_lcomp_stream);
6730 if (tmp == NULL) {
6731 status = NT_STATUS_NO_MEMORY;
6732 TALLOC_FREE(fname_dst_parent);
6733 TALLOC_FREE(orig_lcomp_path);
6734 TALLOC_FREE(orig_lcomp_stream);
6735 goto out;
6737 TALLOC_FREE(smb_fname_dst->stream_name);
6738 smb_fname_dst->stream_name = tmp;
6740 TALLOC_FREE(fname_dst_parent);
6741 TALLOC_FREE(orig_lcomp_path);
6742 TALLOC_FREE(orig_lcomp_stream);
6746 * If the src and dest names are identical - including case,
6747 * don't do the rename, just return success.
6750 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6751 strcsequal(fsp->fsp_name->stream_name,
6752 smb_fname_dst->stream_name)) {
6753 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6754 "- returning success\n",
6755 smb_fname_str_dbg(smb_fname_dst)));
6756 status = NT_STATUS_OK;
6757 goto out;
6760 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6761 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6763 /* Return the correct error code if both names aren't streams. */
6764 if (!old_is_stream && new_is_stream) {
6765 status = NT_STATUS_OBJECT_NAME_INVALID;
6766 goto out;
6769 if (old_is_stream && !new_is_stream) {
6770 status = NT_STATUS_INVALID_PARAMETER;
6771 goto out;
6774 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6776 if(!replace_if_exists && dst_exists) {
6777 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6778 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6779 smb_fname_str_dbg(smb_fname_dst)));
6780 status = NT_STATUS_OBJECT_NAME_COLLISION;
6781 goto out;
6784 if (dst_exists) {
6785 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6786 &smb_fname_dst->st);
6787 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6788 fileid);
6789 /* The file can be open when renaming a stream */
6790 if (dst_fsp && !new_is_stream) {
6791 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6792 status = NT_STATUS_ACCESS_DENIED;
6793 goto out;
6797 /* Ensure we have a valid stat struct for the source. */
6798 status = vfs_stat_fsp(fsp);
6799 if (!NT_STATUS_IS_OK(status)) {
6800 goto out;
6803 status = can_rename(conn, fsp, attrs);
6805 if (!NT_STATUS_IS_OK(status)) {
6806 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6807 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6808 smb_fname_str_dbg(smb_fname_dst)));
6809 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6810 status = NT_STATUS_ACCESS_DENIED;
6811 goto out;
6814 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6815 status = NT_STATUS_ACCESS_DENIED;
6816 goto out;
6819 /* Do we have rights to move into the destination ? */
6820 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
6821 /* We're moving a directory. */
6822 access_mask = SEC_DIR_ADD_SUBDIR;
6824 status = check_parent_access(conn,
6825 smb_fname_dst,
6826 access_mask);
6827 if (!NT_STATUS_IS_OK(status)) {
6828 DBG_INFO("check_parent_access on "
6829 "dst %s returned %s\n",
6830 smb_fname_str_dbg(smb_fname_dst),
6831 nt_errstr(status));
6832 goto out;
6835 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6838 * We have the file open ourselves, so not being able to get the
6839 * corresponding share mode lock is a fatal error.
6842 SMB_ASSERT(lck != NULL);
6844 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6845 uint32_t create_options = fsp->fh->private_options;
6847 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6848 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6849 smb_fname_str_dbg(smb_fname_dst)));
6851 if (!fsp->is_directory &&
6852 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6853 (lp_map_archive(SNUM(conn)) ||
6854 lp_store_dos_attributes(SNUM(conn)))) {
6855 /* We must set the archive bit on the newly
6856 renamed file. */
6857 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6858 uint32_t old_dosmode = dos_mode(conn,
6859 smb_fname_dst);
6860 file_set_dosmode(conn,
6861 smb_fname_dst,
6862 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6863 NULL,
6864 true);
6868 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6869 smb_fname_dst);
6871 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6872 smb_fname_dst);
6875 * A rename acts as a new file create w.r.t. allowing an initial delete
6876 * on close, probably because in Windows there is a new handle to the
6877 * new file. If initial delete on close was requested but not
6878 * originally set, we need to set it here. This is probably not 100% correct,
6879 * but will work for the CIFSFS client which in non-posix mode
6880 * depends on these semantics. JRA.
6883 if (create_options & FILE_DELETE_ON_CLOSE) {
6884 status = can_set_delete_on_close(fsp, 0);
6886 if (NT_STATUS_IS_OK(status)) {
6887 /* Note that here we set the *inital* delete on close flag,
6888 * not the regular one. The magic gets handled in close. */
6889 fsp->initial_delete_on_close = True;
6892 TALLOC_FREE(lck);
6893 status = NT_STATUS_OK;
6894 goto out;
6897 TALLOC_FREE(lck);
6899 if (errno == ENOTDIR || errno == EISDIR) {
6900 status = NT_STATUS_OBJECT_NAME_COLLISION;
6901 } else {
6902 status = map_nt_error_from_unix(errno);
6905 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6906 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6907 smb_fname_str_dbg(smb_fname_dst)));
6909 out:
6910 TALLOC_FREE(smb_fname_dst);
6912 return status;
6915 /****************************************************************************
6916 The guts of the rename command, split out so it may be called by the NT SMB
6917 code.
6918 ****************************************************************************/
6920 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6921 connection_struct *conn,
6922 struct smb_request *req,
6923 struct smb_filename *smb_fname_src,
6924 struct smb_filename *smb_fname_dst,
6925 uint32_t attrs,
6926 bool replace_if_exists,
6927 bool src_has_wild,
6928 bool dest_has_wild,
6929 uint32_t access_mask)
6931 char *fname_src_dir = NULL;
6932 struct smb_filename *smb_fname_src_dir = NULL;
6933 char *fname_src_mask = NULL;
6934 int count=0;
6935 NTSTATUS status = NT_STATUS_OK;
6936 struct smb_Dir *dir_hnd = NULL;
6937 const char *dname = NULL;
6938 char *talloced = NULL;
6939 long offset = 0;
6940 int create_options = 0;
6941 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6942 int rc;
6945 * Split the old name into directory and last component
6946 * strings. Note that unix_convert may have stripped off a
6947 * leading ./ from both name and newname if the rename is
6948 * at the root of the share. We need to make sure either both
6949 * name and newname contain a / character or neither of them do
6950 * as this is checked in resolve_wildcards().
6953 /* Split up the directory from the filename/mask. */
6954 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6955 &fname_src_dir, &fname_src_mask);
6956 if (!NT_STATUS_IS_OK(status)) {
6957 status = NT_STATUS_NO_MEMORY;
6958 goto out;
6962 * We should only check the mangled cache
6963 * here if unix_convert failed. This means
6964 * that the path in 'mask' doesn't exist
6965 * on the file system and so we need to look
6966 * for a possible mangle. This patch from
6967 * Tine Smukavec <valentin.smukavec@hermes.si>.
6970 if (!VALID_STAT(smb_fname_src->st) &&
6971 mangle_is_mangled(fname_src_mask, conn->params)) {
6972 char *new_mask = NULL;
6973 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6974 conn->params);
6975 if (new_mask) {
6976 TALLOC_FREE(fname_src_mask);
6977 fname_src_mask = new_mask;
6981 if (!src_has_wild) {
6982 files_struct *fsp;
6985 * Only one file needs to be renamed. Append the mask back
6986 * onto the directory.
6988 TALLOC_FREE(smb_fname_src->base_name);
6989 if (ISDOT(fname_src_dir)) {
6990 /* Ensure we use canonical names on open. */
6991 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6992 "%s",
6993 fname_src_mask);
6994 } else {
6995 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6996 "%s/%s",
6997 fname_src_dir,
6998 fname_src_mask);
7000 if (!smb_fname_src->base_name) {
7001 status = NT_STATUS_NO_MEMORY;
7002 goto out;
7005 DEBUG(3, ("rename_internals: case_sensitive = %d, "
7006 "case_preserve = %d, short case preserve = %d, "
7007 "directory = %s, newname = %s, "
7008 "last_component_dest = %s\n",
7009 conn->case_sensitive, conn->case_preserve,
7010 conn->short_case_preserve,
7011 smb_fname_str_dbg(smb_fname_src),
7012 smb_fname_str_dbg(smb_fname_dst),
7013 smb_fname_dst->original_lcomp));
7015 /* The dest name still may have wildcards. */
7016 if (dest_has_wild) {
7017 char *fname_dst_mod = NULL;
7018 if (!resolve_wildcards(smb_fname_dst,
7019 smb_fname_src->base_name,
7020 smb_fname_dst->base_name,
7021 &fname_dst_mod)) {
7022 DEBUG(6, ("rename_internals: resolve_wildcards "
7023 "%s %s failed\n",
7024 smb_fname_src->base_name,
7025 smb_fname_dst->base_name));
7026 status = NT_STATUS_NO_MEMORY;
7027 goto out;
7029 TALLOC_FREE(smb_fname_dst->base_name);
7030 smb_fname_dst->base_name = fname_dst_mod;
7033 ZERO_STRUCT(smb_fname_src->st);
7034 if (posix_pathnames) {
7035 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7036 } else {
7037 rc = SMB_VFS_STAT(conn, smb_fname_src);
7039 if (rc == -1) {
7040 status = map_nt_error_from_unix_common(errno);
7041 goto out;
7044 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7045 create_options |= FILE_DIRECTORY_FILE;
7048 status = SMB_VFS_CREATE_FILE(
7049 conn, /* conn */
7050 req, /* req */
7051 0, /* root_dir_fid */
7052 smb_fname_src, /* fname */
7053 access_mask, /* access_mask */
7054 (FILE_SHARE_READ | /* share_access */
7055 FILE_SHARE_WRITE),
7056 FILE_OPEN, /* create_disposition*/
7057 create_options, /* create_options */
7058 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7059 0, /* oplock_request */
7060 NULL, /* lease */
7061 0, /* allocation_size */
7062 0, /* private_flags */
7063 NULL, /* sd */
7064 NULL, /* ea_list */
7065 &fsp, /* result */
7066 NULL, /* pinfo */
7067 NULL, NULL); /* create context */
7069 if (!NT_STATUS_IS_OK(status)) {
7070 DEBUG(3, ("Could not open rename source %s: %s\n",
7071 smb_fname_str_dbg(smb_fname_src),
7072 nt_errstr(status)));
7073 goto out;
7076 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7077 attrs, replace_if_exists);
7079 close_file(req, fsp, NORMAL_CLOSE);
7081 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7082 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7083 smb_fname_str_dbg(smb_fname_dst)));
7085 goto out;
7089 * Wildcards - process each file that matches.
7091 if (strequal(fname_src_mask, "????????.???")) {
7092 TALLOC_FREE(fname_src_mask);
7093 fname_src_mask = talloc_strdup(ctx, "*");
7094 if (!fname_src_mask) {
7095 status = NT_STATUS_NO_MEMORY;
7096 goto out;
7100 status = check_name(conn, fname_src_dir);
7101 if (!NT_STATUS_IS_OK(status)) {
7102 goto out;
7105 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7106 fname_src_dir,
7107 NULL,
7108 NULL,
7109 smb_fname_src->flags);
7110 if (smb_fname_src_dir == NULL) {
7111 status = NT_STATUS_NO_MEMORY;
7112 goto out;
7115 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7116 attrs);
7117 if (dir_hnd == NULL) {
7118 status = map_nt_error_from_unix(errno);
7119 goto out;
7122 status = NT_STATUS_NO_SUCH_FILE;
7124 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7125 * - gentest fix. JRA
7128 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7129 &talloced))) {
7130 files_struct *fsp = NULL;
7131 char *destname = NULL;
7132 bool sysdir_entry = False;
7134 /* Quick check for "." and ".." */
7135 if (ISDOT(dname) || ISDOTDOT(dname)) {
7136 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7137 sysdir_entry = True;
7138 } else {
7139 TALLOC_FREE(talloced);
7140 continue;
7144 if (!is_visible_file(conn, fname_src_dir, dname,
7145 &smb_fname_src->st, false)) {
7146 TALLOC_FREE(talloced);
7147 continue;
7150 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7151 TALLOC_FREE(talloced);
7152 continue;
7155 if (sysdir_entry) {
7156 status = NT_STATUS_OBJECT_NAME_INVALID;
7157 break;
7160 TALLOC_FREE(smb_fname_src->base_name);
7161 if (ISDOT(fname_src_dir)) {
7162 /* Ensure we use canonical names on open. */
7163 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7164 "%s",
7165 dname);
7166 } else {
7167 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7168 "%s/%s",
7169 fname_src_dir,
7170 dname);
7172 if (!smb_fname_src->base_name) {
7173 status = NT_STATUS_NO_MEMORY;
7174 goto out;
7177 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7178 smb_fname_dst->base_name,
7179 &destname)) {
7180 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7181 smb_fname_src->base_name, destname));
7182 TALLOC_FREE(talloced);
7183 continue;
7185 if (!destname) {
7186 status = NT_STATUS_NO_MEMORY;
7187 goto out;
7190 TALLOC_FREE(smb_fname_dst->base_name);
7191 smb_fname_dst->base_name = destname;
7193 ZERO_STRUCT(smb_fname_src->st);
7194 if (posix_pathnames) {
7195 SMB_VFS_LSTAT(conn, smb_fname_src);
7196 } else {
7197 SMB_VFS_STAT(conn, smb_fname_src);
7200 create_options = 0;
7202 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7203 create_options |= FILE_DIRECTORY_FILE;
7206 status = SMB_VFS_CREATE_FILE(
7207 conn, /* conn */
7208 req, /* req */
7209 0, /* root_dir_fid */
7210 smb_fname_src, /* fname */
7211 access_mask, /* access_mask */
7212 (FILE_SHARE_READ | /* share_access */
7213 FILE_SHARE_WRITE),
7214 FILE_OPEN, /* create_disposition*/
7215 create_options, /* create_options */
7216 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7217 0, /* oplock_request */
7218 NULL, /* lease */
7219 0, /* allocation_size */
7220 0, /* private_flags */
7221 NULL, /* sd */
7222 NULL, /* ea_list */
7223 &fsp, /* result */
7224 NULL, /* pinfo */
7225 NULL, NULL); /* create context */
7227 if (!NT_STATUS_IS_OK(status)) {
7228 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7229 "returned %s rename %s -> %s\n",
7230 nt_errstr(status),
7231 smb_fname_str_dbg(smb_fname_src),
7232 smb_fname_str_dbg(smb_fname_dst)));
7233 break;
7236 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7237 dname);
7238 if (!smb_fname_dst->original_lcomp) {
7239 status = NT_STATUS_NO_MEMORY;
7240 goto out;
7243 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7244 attrs, replace_if_exists);
7246 close_file(req, fsp, NORMAL_CLOSE);
7248 if (!NT_STATUS_IS_OK(status)) {
7249 DEBUG(3, ("rename_internals_fsp returned %s for "
7250 "rename %s -> %s\n", nt_errstr(status),
7251 smb_fname_str_dbg(smb_fname_src),
7252 smb_fname_str_dbg(smb_fname_dst)));
7253 break;
7256 count++;
7258 DEBUG(3,("rename_internals: doing rename on %s -> "
7259 "%s\n", smb_fname_str_dbg(smb_fname_src),
7260 smb_fname_str_dbg(smb_fname_src)));
7261 TALLOC_FREE(talloced);
7263 TALLOC_FREE(dir_hnd);
7265 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7266 status = map_nt_error_from_unix(errno);
7269 out:
7270 TALLOC_FREE(talloced);
7271 TALLOC_FREE(smb_fname_src_dir);
7272 TALLOC_FREE(fname_src_dir);
7273 TALLOC_FREE(fname_src_mask);
7274 return status;
7277 /****************************************************************************
7278 Reply to a mv.
7279 ****************************************************************************/
7281 void reply_mv(struct smb_request *req)
7283 connection_struct *conn = req->conn;
7284 char *name = NULL;
7285 char *newname = NULL;
7286 const char *p;
7287 uint32_t attrs;
7288 NTSTATUS status;
7289 bool src_has_wcard = False;
7290 bool dest_has_wcard = False;
7291 TALLOC_CTX *ctx = talloc_tos();
7292 struct smb_filename *smb_fname_src = NULL;
7293 struct smb_filename *smb_fname_dst = NULL;
7294 uint32_t src_ucf_flags = (req->posix_pathnames ?
7295 (UCF_UNIX_NAME_LOOKUP|UCF_POSIX_PATHNAMES) :
7296 UCF_COND_ALLOW_WCARD_LCOMP);
7297 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP |
7298 (req->posix_pathnames ? UCF_POSIX_PATHNAMES :
7299 UCF_COND_ALLOW_WCARD_LCOMP);
7300 bool stream_rename = false;
7302 START_PROFILE(SMBmv);
7304 if (req->wct < 1) {
7305 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7306 goto out;
7309 attrs = SVAL(req->vwv+0, 0);
7311 p = (const char *)req->buf + 1;
7312 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7313 &status, &src_has_wcard);
7314 if (!NT_STATUS_IS_OK(status)) {
7315 reply_nterror(req, status);
7316 goto out;
7318 p++;
7319 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7320 &status, &dest_has_wcard);
7321 if (!NT_STATUS_IS_OK(status)) {
7322 reply_nterror(req, status);
7323 goto out;
7326 if (!req->posix_pathnames) {
7327 /* The newname must begin with a ':' if the
7328 name contains a ':'. */
7329 if (strchr_m(name, ':')) {
7330 if (newname[0] != ':') {
7331 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7332 goto out;
7334 stream_rename = true;
7338 status = filename_convert(ctx,
7339 conn,
7340 req->flags2 & FLAGS2_DFS_PATHNAMES,
7341 name,
7342 src_ucf_flags,
7343 &src_has_wcard,
7344 &smb_fname_src);
7346 if (!NT_STATUS_IS_OK(status)) {
7347 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7348 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7349 ERRSRV, ERRbadpath);
7350 goto out;
7352 reply_nterror(req, status);
7353 goto out;
7356 status = filename_convert(ctx,
7357 conn,
7358 req->flags2 & FLAGS2_DFS_PATHNAMES,
7359 newname,
7360 dst_ucf_flags,
7361 &dest_has_wcard,
7362 &smb_fname_dst);
7364 if (!NT_STATUS_IS_OK(status)) {
7365 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7366 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7367 ERRSRV, ERRbadpath);
7368 goto out;
7370 reply_nterror(req, status);
7371 goto out;
7374 if (stream_rename) {
7375 /* smb_fname_dst->base_name must be the same as
7376 smb_fname_src->base_name. */
7377 TALLOC_FREE(smb_fname_dst->base_name);
7378 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7379 smb_fname_src->base_name);
7380 if (!smb_fname_dst->base_name) {
7381 reply_nterror(req, NT_STATUS_NO_MEMORY);
7382 goto out;
7386 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7387 smb_fname_str_dbg(smb_fname_dst)));
7389 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7390 attrs, False, src_has_wcard, dest_has_wcard,
7391 DELETE_ACCESS);
7392 if (!NT_STATUS_IS_OK(status)) {
7393 if (open_was_deferred(req->xconn, req->mid)) {
7394 /* We have re-scheduled this call. */
7395 goto out;
7397 reply_nterror(req, status);
7398 goto out;
7401 reply_outbuf(req, 0, 0);
7402 out:
7403 TALLOC_FREE(smb_fname_src);
7404 TALLOC_FREE(smb_fname_dst);
7405 END_PROFILE(SMBmv);
7406 return;
7409 /*******************************************************************
7410 Copy a file as part of a reply_copy.
7411 ******************************************************************/
7414 * TODO: check error codes on all callers
7417 NTSTATUS copy_file(TALLOC_CTX *ctx,
7418 connection_struct *conn,
7419 struct smb_filename *smb_fname_src,
7420 struct smb_filename *smb_fname_dst,
7421 int ofun,
7422 int count,
7423 bool target_is_directory)
7425 struct smb_filename *smb_fname_dst_tmp = NULL;
7426 off_t ret=-1;
7427 files_struct *fsp1,*fsp2;
7428 uint32_t dosattrs;
7429 uint32_t new_create_disposition;
7430 NTSTATUS status;
7433 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7434 if (smb_fname_dst_tmp == NULL) {
7435 return NT_STATUS_NO_MEMORY;
7439 * If the target is a directory, extract the last component from the
7440 * src filename and append it to the dst filename
7442 if (target_is_directory) {
7443 const char *p;
7445 /* dest/target can't be a stream if it's a directory. */
7446 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7448 p = strrchr_m(smb_fname_src->base_name,'/');
7449 if (p) {
7450 p++;
7451 } else {
7452 p = smb_fname_src->base_name;
7454 smb_fname_dst_tmp->base_name =
7455 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7457 if (!smb_fname_dst_tmp->base_name) {
7458 status = NT_STATUS_NO_MEMORY;
7459 goto out;
7463 status = vfs_file_exist(conn, smb_fname_src);
7464 if (!NT_STATUS_IS_OK(status)) {
7465 goto out;
7468 if (!target_is_directory && count) {
7469 new_create_disposition = FILE_OPEN;
7470 } else {
7471 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7472 0, ofun,
7473 NULL, NULL,
7474 &new_create_disposition,
7475 NULL,
7476 NULL)) {
7477 status = NT_STATUS_INVALID_PARAMETER;
7478 goto out;
7482 /* Open the src file for reading. */
7483 status = SMB_VFS_CREATE_FILE(
7484 conn, /* conn */
7485 NULL, /* req */
7486 0, /* root_dir_fid */
7487 smb_fname_src, /* fname */
7488 FILE_GENERIC_READ, /* access_mask */
7489 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7490 FILE_OPEN, /* create_disposition*/
7491 0, /* create_options */
7492 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7493 INTERNAL_OPEN_ONLY, /* oplock_request */
7494 NULL, /* lease */
7495 0, /* allocation_size */
7496 0, /* private_flags */
7497 NULL, /* sd */
7498 NULL, /* ea_list */
7499 &fsp1, /* result */
7500 NULL, /* psbuf */
7501 NULL, NULL); /* create context */
7503 if (!NT_STATUS_IS_OK(status)) {
7504 goto out;
7507 dosattrs = dos_mode(conn, smb_fname_src);
7509 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7510 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7513 /* Open the dst file for writing. */
7514 status = SMB_VFS_CREATE_FILE(
7515 conn, /* conn */
7516 NULL, /* req */
7517 0, /* root_dir_fid */
7518 smb_fname_dst, /* fname */
7519 FILE_GENERIC_WRITE, /* access_mask */
7520 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7521 new_create_disposition, /* create_disposition*/
7522 0, /* create_options */
7523 dosattrs, /* file_attributes */
7524 INTERNAL_OPEN_ONLY, /* oplock_request */
7525 NULL, /* lease */
7526 0, /* allocation_size */
7527 0, /* private_flags */
7528 NULL, /* sd */
7529 NULL, /* ea_list */
7530 &fsp2, /* result */
7531 NULL, /* psbuf */
7532 NULL, NULL); /* create context */
7534 if (!NT_STATUS_IS_OK(status)) {
7535 close_file(NULL, fsp1, ERROR_CLOSE);
7536 goto out;
7539 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7540 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7541 if (ret == -1) {
7542 DEBUG(0, ("error - vfs lseek returned error %s\n",
7543 strerror(errno)));
7544 status = map_nt_error_from_unix(errno);
7545 close_file(NULL, fsp1, ERROR_CLOSE);
7546 close_file(NULL, fsp2, ERROR_CLOSE);
7547 goto out;
7551 /* Do the actual copy. */
7552 if (smb_fname_src->st.st_ex_size) {
7553 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7554 } else {
7555 ret = 0;
7558 close_file(NULL, fsp1, NORMAL_CLOSE);
7560 /* Ensure the modtime is set correctly on the destination file. */
7561 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7564 * As we are opening fsp1 read-only we only expect
7565 * an error on close on fsp2 if we are out of space.
7566 * Thus we don't look at the error return from the
7567 * close of fsp1.
7569 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7571 if (!NT_STATUS_IS_OK(status)) {
7572 goto out;
7575 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7576 status = NT_STATUS_DISK_FULL;
7577 goto out;
7580 status = NT_STATUS_OK;
7582 out:
7583 TALLOC_FREE(smb_fname_dst_tmp);
7584 return status;
7587 /****************************************************************************
7588 Reply to a file copy.
7589 ****************************************************************************/
7591 void reply_copy(struct smb_request *req)
7593 connection_struct *conn = req->conn;
7594 struct smb_filename *smb_fname_src = NULL;
7595 struct smb_filename *smb_fname_src_dir = NULL;
7596 struct smb_filename *smb_fname_dst = NULL;
7597 char *fname_src = NULL;
7598 char *fname_dst = NULL;
7599 char *fname_src_mask = NULL;
7600 char *fname_src_dir = NULL;
7601 const char *p;
7602 int count=0;
7603 int error = ERRnoaccess;
7604 int tid2;
7605 int ofun;
7606 int flags;
7607 bool target_is_directory=False;
7608 bool source_has_wild = False;
7609 bool dest_has_wild = False;
7610 NTSTATUS status;
7611 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7612 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
7613 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7614 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
7615 TALLOC_CTX *ctx = talloc_tos();
7617 START_PROFILE(SMBcopy);
7619 if (req->wct < 3) {
7620 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7621 goto out;
7624 tid2 = SVAL(req->vwv+0, 0);
7625 ofun = SVAL(req->vwv+1, 0);
7626 flags = SVAL(req->vwv+2, 0);
7628 p = (const char *)req->buf;
7629 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7630 &status, &source_has_wild);
7631 if (!NT_STATUS_IS_OK(status)) {
7632 reply_nterror(req, status);
7633 goto out;
7635 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7636 &status, &dest_has_wild);
7637 if (!NT_STATUS_IS_OK(status)) {
7638 reply_nterror(req, status);
7639 goto out;
7642 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7644 if (tid2 != conn->cnum) {
7645 /* can't currently handle inter share copies XXXX */
7646 DEBUG(3,("Rejecting inter-share copy\n"));
7647 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7648 goto out;
7651 status = filename_convert(ctx, conn,
7652 req->flags2 & FLAGS2_DFS_PATHNAMES,
7653 fname_src,
7654 ucf_flags_src,
7655 &source_has_wild,
7656 &smb_fname_src);
7657 if (!NT_STATUS_IS_OK(status)) {
7658 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7659 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7660 ERRSRV, ERRbadpath);
7661 goto out;
7663 reply_nterror(req, status);
7664 goto out;
7667 status = filename_convert(ctx, conn,
7668 req->flags2 & FLAGS2_DFS_PATHNAMES,
7669 fname_dst,
7670 ucf_flags_dst,
7671 &dest_has_wild,
7672 &smb_fname_dst);
7673 if (!NT_STATUS_IS_OK(status)) {
7674 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7675 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7676 ERRSRV, ERRbadpath);
7677 goto out;
7679 reply_nterror(req, status);
7680 goto out;
7683 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7685 if ((flags&1) && target_is_directory) {
7686 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7687 goto out;
7690 if ((flags&2) && !target_is_directory) {
7691 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7692 goto out;
7695 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7696 /* wants a tree copy! XXXX */
7697 DEBUG(3,("Rejecting tree copy\n"));
7698 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7699 goto out;
7702 /* Split up the directory from the filename/mask. */
7703 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7704 &fname_src_dir, &fname_src_mask);
7705 if (!NT_STATUS_IS_OK(status)) {
7706 reply_nterror(req, NT_STATUS_NO_MEMORY);
7707 goto out;
7711 * We should only check the mangled cache
7712 * here if unix_convert failed. This means
7713 * that the path in 'mask' doesn't exist
7714 * on the file system and so we need to look
7715 * for a possible mangle. This patch from
7716 * Tine Smukavec <valentin.smukavec@hermes.si>.
7718 if (!VALID_STAT(smb_fname_src->st) &&
7719 mangle_is_mangled(fname_src_mask, conn->params)) {
7720 char *new_mask = NULL;
7721 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7722 &new_mask, conn->params);
7724 /* Use demangled name if one was successfully found. */
7725 if (new_mask) {
7726 TALLOC_FREE(fname_src_mask);
7727 fname_src_mask = new_mask;
7731 if (!source_has_wild) {
7734 * Only one file needs to be copied. Append the mask back onto
7735 * the directory.
7737 TALLOC_FREE(smb_fname_src->base_name);
7738 if (ISDOT(fname_src_dir)) {
7739 /* Ensure we use canonical names on open. */
7740 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7741 "%s",
7742 fname_src_mask);
7743 } else {
7744 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7745 "%s/%s",
7746 fname_src_dir,
7747 fname_src_mask);
7749 if (!smb_fname_src->base_name) {
7750 reply_nterror(req, NT_STATUS_NO_MEMORY);
7751 goto out;
7754 if (dest_has_wild) {
7755 char *fname_dst_mod = NULL;
7756 if (!resolve_wildcards(smb_fname_dst,
7757 smb_fname_src->base_name,
7758 smb_fname_dst->base_name,
7759 &fname_dst_mod)) {
7760 reply_nterror(req, NT_STATUS_NO_MEMORY);
7761 goto out;
7763 TALLOC_FREE(smb_fname_dst->base_name);
7764 smb_fname_dst->base_name = fname_dst_mod;
7767 status = check_name(conn, smb_fname_src->base_name);
7768 if (!NT_STATUS_IS_OK(status)) {
7769 reply_nterror(req, status);
7770 goto out;
7773 status = check_name(conn, smb_fname_dst->base_name);
7774 if (!NT_STATUS_IS_OK(status)) {
7775 reply_nterror(req, status);
7776 goto out;
7779 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7780 ofun, count, target_is_directory);
7782 if(!NT_STATUS_IS_OK(status)) {
7783 reply_nterror(req, status);
7784 goto out;
7785 } else {
7786 count++;
7788 } else {
7789 struct smb_Dir *dir_hnd = NULL;
7790 const char *dname = NULL;
7791 char *talloced = NULL;
7792 long offset = 0;
7795 * There is a wildcard that requires us to actually read the
7796 * src dir and copy each file matching the mask to the dst.
7797 * Right now streams won't be copied, but this could
7798 * presumably be added with a nested loop for reach dir entry.
7800 SMB_ASSERT(!smb_fname_src->stream_name);
7801 SMB_ASSERT(!smb_fname_dst->stream_name);
7803 smb_fname_src->stream_name = NULL;
7804 smb_fname_dst->stream_name = NULL;
7806 if (strequal(fname_src_mask,"????????.???")) {
7807 TALLOC_FREE(fname_src_mask);
7808 fname_src_mask = talloc_strdup(ctx, "*");
7809 if (!fname_src_mask) {
7810 reply_nterror(req, NT_STATUS_NO_MEMORY);
7811 goto out;
7815 status = check_name(conn, fname_src_dir);
7816 if (!NT_STATUS_IS_OK(status)) {
7817 reply_nterror(req, status);
7818 goto out;
7821 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7822 fname_src_dir,
7823 NULL,
7824 NULL,
7825 smb_fname_src->flags);
7826 if (smb_fname_src_dir == NULL) {
7827 reply_nterror(req, NT_STATUS_NO_MEMORY);
7828 goto out;
7831 dir_hnd = OpenDir(ctx,
7832 conn,
7833 smb_fname_src_dir,
7834 fname_src_mask,
7836 if (dir_hnd == NULL) {
7837 status = map_nt_error_from_unix(errno);
7838 reply_nterror(req, status);
7839 goto out;
7842 error = ERRbadfile;
7844 /* Iterate over the src dir copying each entry to the dst. */
7845 while ((dname = ReadDirName(dir_hnd, &offset,
7846 &smb_fname_src->st, &talloced))) {
7847 char *destname = NULL;
7849 if (ISDOT(dname) || ISDOTDOT(dname)) {
7850 TALLOC_FREE(talloced);
7851 continue;
7854 if (!is_visible_file(conn, fname_src_dir, dname,
7855 &smb_fname_src->st, false)) {
7856 TALLOC_FREE(talloced);
7857 continue;
7860 if(!mask_match(dname, fname_src_mask,
7861 conn->case_sensitive)) {
7862 TALLOC_FREE(talloced);
7863 continue;
7866 error = ERRnoaccess;
7868 /* Get the src smb_fname struct setup. */
7869 TALLOC_FREE(smb_fname_src->base_name);
7870 if (ISDOT(fname_src_dir)) {
7871 /* Ensure we use canonical names on open. */
7872 smb_fname_src->base_name =
7873 talloc_asprintf(smb_fname_src, "%s",
7874 dname);
7875 } else {
7876 smb_fname_src->base_name =
7877 talloc_asprintf(smb_fname_src, "%s/%s",
7878 fname_src_dir, dname);
7881 if (!smb_fname_src->base_name) {
7882 TALLOC_FREE(dir_hnd);
7883 TALLOC_FREE(talloced);
7884 reply_nterror(req, NT_STATUS_NO_MEMORY);
7885 goto out;
7888 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7889 smb_fname_dst->base_name,
7890 &destname)) {
7891 TALLOC_FREE(talloced);
7892 continue;
7894 if (!destname) {
7895 TALLOC_FREE(dir_hnd);
7896 TALLOC_FREE(talloced);
7897 reply_nterror(req, NT_STATUS_NO_MEMORY);
7898 goto out;
7901 TALLOC_FREE(smb_fname_dst->base_name);
7902 smb_fname_dst->base_name = destname;
7904 status = check_name(conn, smb_fname_src->base_name);
7905 if (!NT_STATUS_IS_OK(status)) {
7906 TALLOC_FREE(dir_hnd);
7907 TALLOC_FREE(talloced);
7908 reply_nterror(req, status);
7909 goto out;
7912 status = check_name(conn, smb_fname_dst->base_name);
7913 if (!NT_STATUS_IS_OK(status)) {
7914 TALLOC_FREE(dir_hnd);
7915 TALLOC_FREE(talloced);
7916 reply_nterror(req, status);
7917 goto out;
7920 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7921 smb_fname_src->base_name,
7922 smb_fname_dst->base_name));
7924 status = copy_file(ctx, conn, smb_fname_src,
7925 smb_fname_dst, ofun, count,
7926 target_is_directory);
7927 if (NT_STATUS_IS_OK(status)) {
7928 count++;
7931 TALLOC_FREE(talloced);
7933 TALLOC_FREE(dir_hnd);
7936 if (count == 0) {
7937 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7938 goto out;
7941 reply_outbuf(req, 1, 0);
7942 SSVAL(req->outbuf,smb_vwv0,count);
7943 out:
7944 TALLOC_FREE(smb_fname_src);
7945 TALLOC_FREE(smb_fname_src_dir);
7946 TALLOC_FREE(smb_fname_dst);
7947 TALLOC_FREE(fname_src);
7948 TALLOC_FREE(fname_dst);
7949 TALLOC_FREE(fname_src_mask);
7950 TALLOC_FREE(fname_src_dir);
7952 END_PROFILE(SMBcopy);
7953 return;
7956 #undef DBGC_CLASS
7957 #define DBGC_CLASS DBGC_LOCKING
7959 /****************************************************************************
7960 Get a lock pid, dealing with large count requests.
7961 ****************************************************************************/
7963 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7964 bool large_file_format)
7966 if(!large_file_format)
7967 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7968 else
7969 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7972 /****************************************************************************
7973 Get a lock count, dealing with large count requests.
7974 ****************************************************************************/
7976 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7977 bool large_file_format)
7979 uint64_t count = 0;
7981 if(!large_file_format) {
7982 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7983 } else {
7985 * No BVAL, this is reversed!
7987 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7988 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7991 return count;
7994 /****************************************************************************
7995 Get a lock offset, dealing with large offset requests.
7996 ****************************************************************************/
7998 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7999 bool large_file_format)
8001 uint64_t offset = 0;
8003 if(!large_file_format) {
8004 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
8005 } else {
8007 * No BVAL, this is reversed!
8009 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
8010 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
8013 return offset;
8016 NTSTATUS smbd_do_locking(struct smb_request *req,
8017 files_struct *fsp,
8018 uint8_t type,
8019 int32_t timeout,
8020 uint16_t num_locks,
8021 struct smbd_lock_element *locks,
8022 bool *async)
8024 connection_struct *conn = req->conn;
8025 int i;
8026 NTSTATUS status = NT_STATUS_OK;
8028 *async = false;
8030 /* Setup the timeout in seconds. */
8032 if (!lp_blocking_locks(SNUM(conn))) {
8033 timeout = 0;
8036 for(i = 0; i < (int)num_locks; i++) {
8037 struct smbd_lock_element *e = &locks[i];
8039 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8040 "%llu, file %s timeout = %d\n",
8041 (double)e->offset,
8042 (double)e->count,
8043 (unsigned long long)e->smblctx,
8044 fsp_str_dbg(fsp),
8045 (int)timeout));
8047 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8048 struct blocking_lock_record *blr = NULL;
8050 if (num_locks > 1) {
8052 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8053 * if the lock vector contains one entry. When given multiple cancel
8054 * requests in a single PDU we expect the server to return an
8055 * error. Windows servers seem to accept the request but only
8056 * cancel the first lock.
8057 * JRA - Do what Windows does (tm) :-).
8060 #if 0
8061 /* MS-CIFS (2.2.4.32.1) behavior. */
8062 return NT_STATUS_DOS(ERRDOS,
8063 ERRcancelviolation);
8064 #else
8065 /* Windows behavior. */
8066 if (i != 0) {
8067 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8068 "cancel request\n"));
8069 continue;
8071 #endif
8074 if (lp_blocking_locks(SNUM(conn))) {
8076 /* Schedule a message to ourselves to
8077 remove the blocking lock record and
8078 return the right error. */
8080 blr = blocking_lock_cancel_smb1(fsp,
8081 e->smblctx,
8082 e->offset,
8083 e->count,
8084 WINDOWS_LOCK,
8085 type,
8086 NT_STATUS_FILE_LOCK_CONFLICT);
8087 if (blr == NULL) {
8088 return NT_STATUS_DOS(
8089 ERRDOS,
8090 ERRcancelviolation);
8093 /* Remove a matching pending lock. */
8094 status = do_lock_cancel(fsp,
8095 e->smblctx,
8096 e->count,
8097 e->offset,
8098 WINDOWS_LOCK);
8099 } else {
8100 bool blocking_lock = timeout ? true : false;
8101 bool defer_lock = false;
8102 struct byte_range_lock *br_lck;
8103 uint64_t block_smblctx;
8105 br_lck = do_lock(req->sconn->msg_ctx,
8106 fsp,
8107 e->smblctx,
8108 e->count,
8109 e->offset,
8110 e->brltype,
8111 WINDOWS_LOCK,
8112 blocking_lock,
8113 &status,
8114 &block_smblctx);
8116 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8117 /* Windows internal resolution for blocking locks seems
8118 to be about 200ms... Don't wait for less than that. JRA. */
8119 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8120 timeout = lp_lock_spin_time();
8122 defer_lock = true;
8125 /* If a lock sent with timeout of zero would fail, and
8126 * this lock has been requested multiple times,
8127 * according to brl_lock_failed() we convert this
8128 * request to a blocking lock with a timeout of between
8129 * 150 - 300 milliseconds.
8131 * If lp_lock_spin_time() has been set to 0, we skip
8132 * this blocking retry and fail immediately.
8134 * Replacement for do_lock_spin(). JRA. */
8136 if (!req->sconn->using_smb2 &&
8137 br_lck && lp_blocking_locks(SNUM(conn)) &&
8138 lp_lock_spin_time() && !blocking_lock &&
8139 NT_STATUS_EQUAL((status),
8140 NT_STATUS_FILE_LOCK_CONFLICT))
8142 defer_lock = true;
8143 timeout = lp_lock_spin_time();
8146 if (br_lck && defer_lock) {
8148 * A blocking lock was requested. Package up
8149 * this smb into a queued request and push it
8150 * onto the blocking lock queue.
8152 if(push_blocking_lock_request(br_lck,
8153 req,
8154 fsp,
8155 timeout,
8157 e->smblctx,
8158 e->brltype,
8159 WINDOWS_LOCK,
8160 e->offset,
8161 e->count,
8162 block_smblctx)) {
8163 TALLOC_FREE(br_lck);
8164 *async = true;
8165 return NT_STATUS_OK;
8169 TALLOC_FREE(br_lck);
8172 if (!NT_STATUS_IS_OK(status)) {
8173 break;
8177 /* If any of the above locks failed, then we must unlock
8178 all of the previous locks (X/Open spec). */
8180 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8182 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8183 i = -1; /* we want to skip the for loop */
8187 * Ensure we don't do a remove on the lock that just failed,
8188 * as under POSIX rules, if we have a lock already there, we
8189 * will delete it (and we shouldn't) .....
8191 for(i--; i >= 0; i--) {
8192 struct smbd_lock_element *e = &locks[i];
8194 do_unlock(req->sconn->msg_ctx,
8195 fsp,
8196 e->smblctx,
8197 e->count,
8198 e->offset,
8199 WINDOWS_LOCK);
8201 return status;
8204 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8205 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8207 return NT_STATUS_OK;
8210 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8211 files_struct *fsp,
8212 uint16_t num_ulocks,
8213 struct smbd_lock_element *ulocks)
8215 int i;
8217 for(i = 0; i < (int)num_ulocks; i++) {
8218 struct smbd_lock_element *e = &ulocks[i];
8219 NTSTATUS status;
8221 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8222 "pid %u, file %s\n", __func__,
8223 (double)e->offset,
8224 (double)e->count,
8225 (unsigned int)e->smblctx,
8226 fsp_str_dbg(fsp)));
8228 if (e->brltype != UNLOCK_LOCK) {
8229 /* this can only happen with SMB2 */
8230 return NT_STATUS_INVALID_PARAMETER;
8233 status = do_unlock(req->sconn->msg_ctx,
8234 fsp,
8235 e->smblctx,
8236 e->count,
8237 e->offset,
8238 WINDOWS_LOCK);
8240 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8241 nt_errstr(status)));
8243 if (!NT_STATUS_IS_OK(status)) {
8244 return status;
8248 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8249 num_ulocks));
8251 return NT_STATUS_OK;
8254 /****************************************************************************
8255 Reply to a lockingX request.
8256 ****************************************************************************/
8258 void reply_lockingX(struct smb_request *req)
8260 connection_struct *conn = req->conn;
8261 files_struct *fsp;
8262 unsigned char locktype;
8263 unsigned char oplocklevel;
8264 uint16_t num_ulocks;
8265 uint16_t num_locks;
8266 int32_t lock_timeout;
8267 int i;
8268 const uint8_t *data;
8269 bool large_file_format;
8270 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8271 struct smbd_lock_element *ulocks;
8272 struct smbd_lock_element *locks;
8273 bool async = false;
8275 START_PROFILE(SMBlockingX);
8277 if (req->wct < 8) {
8278 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8279 END_PROFILE(SMBlockingX);
8280 return;
8283 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8284 locktype = CVAL(req->vwv+3, 0);
8285 oplocklevel = CVAL(req->vwv+3, 1);
8286 num_ulocks = SVAL(req->vwv+6, 0);
8287 num_locks = SVAL(req->vwv+7, 0);
8288 lock_timeout = IVAL(req->vwv+4, 0);
8289 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8291 if (!check_fsp(conn, req, fsp)) {
8292 END_PROFILE(SMBlockingX);
8293 return;
8296 data = req->buf;
8298 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8299 /* we don't support these - and CANCEL_LOCK makes w2k
8300 and XP reboot so I don't really want to be
8301 compatible! (tridge) */
8302 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8303 END_PROFILE(SMBlockingX);
8304 return;
8307 /* Check if this is an oplock break on a file
8308 we have granted an oplock on.
8310 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8311 /* Client can insist on breaking to none. */
8312 bool break_to_none = (oplocklevel == 0);
8313 bool result;
8315 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8316 "for %s\n", (unsigned int)oplocklevel,
8317 fsp_fnum_dbg(fsp)));
8320 * Make sure we have granted an exclusive or batch oplock on
8321 * this file.
8324 if (fsp->oplock_type == 0) {
8326 /* The Samba4 nbench simulator doesn't understand
8327 the difference between break to level2 and break
8328 to none from level2 - it sends oplock break
8329 replies in both cases. Don't keep logging an error
8330 message here - just ignore it. JRA. */
8332 DEBUG(5,("reply_lockingX: Error : oplock break from "
8333 "client for %s (oplock=%d) and no "
8334 "oplock granted on this file (%s).\n",
8335 fsp_fnum_dbg(fsp), fsp->oplock_type,
8336 fsp_str_dbg(fsp)));
8338 /* if this is a pure oplock break request then don't
8339 * send a reply */
8340 if (num_locks == 0 && num_ulocks == 0) {
8341 END_PROFILE(SMBlockingX);
8342 return;
8343 } else {
8344 END_PROFILE(SMBlockingX);
8345 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8346 return;
8350 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8351 (break_to_none)) {
8352 result = remove_oplock(fsp);
8353 } else {
8354 result = downgrade_oplock(fsp);
8357 if (!result) {
8358 DEBUG(0, ("reply_lockingX: error in removing "
8359 "oplock on file %s\n", fsp_str_dbg(fsp)));
8360 /* Hmmm. Is this panic justified? */
8361 smb_panic("internal tdb error");
8364 /* if this is a pure oplock break request then don't send a
8365 * reply */
8366 if (num_locks == 0 && num_ulocks == 0) {
8367 /* Sanity check - ensure a pure oplock break is not a
8368 chained request. */
8369 if (CVAL(req->vwv+0, 0) != 0xff) {
8370 DEBUG(0,("reply_lockingX: Error : pure oplock "
8371 "break is a chained %d request !\n",
8372 (unsigned int)CVAL(req->vwv+0, 0)));
8374 END_PROFILE(SMBlockingX);
8375 return;
8379 if (req->buflen <
8380 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8381 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8382 END_PROFILE(SMBlockingX);
8383 return;
8386 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8387 if (ulocks == NULL) {
8388 reply_nterror(req, NT_STATUS_NO_MEMORY);
8389 END_PROFILE(SMBlockingX);
8390 return;
8393 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8394 if (locks == NULL) {
8395 reply_nterror(req, NT_STATUS_NO_MEMORY);
8396 END_PROFILE(SMBlockingX);
8397 return;
8400 /* Data now points at the beginning of the list
8401 of smb_unlkrng structs */
8402 for(i = 0; i < (int)num_ulocks; i++) {
8403 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8404 ulocks[i].count = get_lock_count(data, i, large_file_format);
8405 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8406 ulocks[i].brltype = UNLOCK_LOCK;
8409 /* Now do any requested locks */
8410 data += ((large_file_format ? 20 : 10)*num_ulocks);
8412 /* Data now points at the beginning of the list
8413 of smb_lkrng structs */
8415 for(i = 0; i < (int)num_locks; i++) {
8416 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8417 locks[i].count = get_lock_count(data, i, large_file_format);
8418 locks[i].offset = get_lock_offset(data, i, large_file_format);
8420 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8421 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8422 locks[i].brltype = PENDING_READ_LOCK;
8423 } else {
8424 locks[i].brltype = READ_LOCK;
8426 } else {
8427 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8428 locks[i].brltype = PENDING_WRITE_LOCK;
8429 } else {
8430 locks[i].brltype = WRITE_LOCK;
8435 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8436 if (!NT_STATUS_IS_OK(status)) {
8437 END_PROFILE(SMBlockingX);
8438 reply_nterror(req, status);
8439 return;
8442 status = smbd_do_locking(req, fsp,
8443 locktype, lock_timeout,
8444 num_locks, locks,
8445 &async);
8446 if (!NT_STATUS_IS_OK(status)) {
8447 END_PROFILE(SMBlockingX);
8448 reply_nterror(req, status);
8449 return;
8451 if (async) {
8452 END_PROFILE(SMBlockingX);
8453 return;
8456 reply_outbuf(req, 2, 0);
8457 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8458 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8460 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8461 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8463 END_PROFILE(SMBlockingX);
8466 #undef DBGC_CLASS
8467 #define DBGC_CLASS DBGC_ALL
8469 /****************************************************************************
8470 Reply to a SMBreadbmpx (read block multiplex) request.
8471 Always reply with an error, if someone has a platform really needs this,
8472 please contact vl@samba.org
8473 ****************************************************************************/
8475 void reply_readbmpx(struct smb_request *req)
8477 START_PROFILE(SMBreadBmpx);
8478 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8479 END_PROFILE(SMBreadBmpx);
8480 return;
8483 /****************************************************************************
8484 Reply to a SMBreadbs (read block multiplex secondary) request.
8485 Always reply with an error, if someone has a platform really needs this,
8486 please contact vl@samba.org
8487 ****************************************************************************/
8489 void reply_readbs(struct smb_request *req)
8491 START_PROFILE(SMBreadBs);
8492 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8493 END_PROFILE(SMBreadBs);
8494 return;
8497 /****************************************************************************
8498 Reply to a SMBsetattrE.
8499 ****************************************************************************/
8501 void reply_setattrE(struct smb_request *req)
8503 connection_struct *conn = req->conn;
8504 struct smb_file_time ft;
8505 files_struct *fsp;
8506 NTSTATUS status;
8508 START_PROFILE(SMBsetattrE);
8509 ZERO_STRUCT(ft);
8511 if (req->wct < 7) {
8512 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8513 goto out;
8516 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8518 if(!fsp || (fsp->conn != conn)) {
8519 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8520 goto out;
8524 * Convert the DOS times into unix times.
8527 ft.atime = convert_time_t_to_timespec(
8528 srv_make_unix_date2(req->vwv+3));
8529 ft.mtime = convert_time_t_to_timespec(
8530 srv_make_unix_date2(req->vwv+5));
8531 ft.create_time = convert_time_t_to_timespec(
8532 srv_make_unix_date2(req->vwv+1));
8534 reply_outbuf(req, 0, 0);
8537 * Patch from Ray Frush <frush@engr.colostate.edu>
8538 * Sometimes times are sent as zero - ignore them.
8541 /* Ensure we have a valid stat struct for the source. */
8542 status = vfs_stat_fsp(fsp);
8543 if (!NT_STATUS_IS_OK(status)) {
8544 reply_nterror(req, status);
8545 goto out;
8548 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8549 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8550 goto out;
8553 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8554 if (!NT_STATUS_IS_OK(status)) {
8555 reply_nterror(req, status);
8556 goto out;
8559 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8560 " createtime=%u\n",
8561 fsp_fnum_dbg(fsp),
8562 (unsigned int)ft.atime.tv_sec,
8563 (unsigned int)ft.mtime.tv_sec,
8564 (unsigned int)ft.create_time.tv_sec
8566 out:
8567 END_PROFILE(SMBsetattrE);
8568 return;
8572 /* Back from the dead for OS/2..... JRA. */
8574 /****************************************************************************
8575 Reply to a SMBwritebmpx (write block multiplex primary) request.
8576 Always reply with an error, if someone has a platform really needs this,
8577 please contact vl@samba.org
8578 ****************************************************************************/
8580 void reply_writebmpx(struct smb_request *req)
8582 START_PROFILE(SMBwriteBmpx);
8583 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8584 END_PROFILE(SMBwriteBmpx);
8585 return;
8588 /****************************************************************************
8589 Reply to a SMBwritebs (write block multiplex secondary) request.
8590 Always reply with an error, if someone has a platform really needs this,
8591 please contact vl@samba.org
8592 ****************************************************************************/
8594 void reply_writebs(struct smb_request *req)
8596 START_PROFILE(SMBwriteBs);
8597 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8598 END_PROFILE(SMBwriteBs);
8599 return;
8602 /****************************************************************************
8603 Reply to a SMBgetattrE.
8604 ****************************************************************************/
8606 void reply_getattrE(struct smb_request *req)
8608 connection_struct *conn = req->conn;
8609 int mode;
8610 files_struct *fsp;
8611 struct timespec create_ts;
8613 START_PROFILE(SMBgetattrE);
8615 if (req->wct < 1) {
8616 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8617 END_PROFILE(SMBgetattrE);
8618 return;
8621 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8623 if(!fsp || (fsp->conn != conn)) {
8624 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8625 END_PROFILE(SMBgetattrE);
8626 return;
8629 /* Do an fstat on this file */
8630 if(fsp_stat(fsp)) {
8631 reply_nterror(req, map_nt_error_from_unix(errno));
8632 END_PROFILE(SMBgetattrE);
8633 return;
8636 mode = dos_mode(conn, fsp->fsp_name);
8639 * Convert the times into dos times. Set create
8640 * date to be last modify date as UNIX doesn't save
8641 * this.
8644 reply_outbuf(req, 11, 0);
8646 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8647 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8648 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8649 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8650 /* Should we check pending modtime here ? JRA */
8651 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8652 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8654 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8655 SIVAL(req->outbuf, smb_vwv6, 0);
8656 SIVAL(req->outbuf, smb_vwv8, 0);
8657 } else {
8658 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8659 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8660 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8662 SSVAL(req->outbuf,smb_vwv10, mode);
8664 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8666 END_PROFILE(SMBgetattrE);
8667 return;