smbd: Fix a typo
[Samba.git] / source3 / smbd / reply.c
blob42cf4c908ebc3d04923c54056ca3700b5b322596
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "libsmb/namequery.h"
29 #include "system/filesys.h"
30 #include "printing.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "fake_file.h"
34 #include "rpc_client/rpc_client.h"
35 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
46 #include "lib/util/sys_rw_data.h"
48 /****************************************************************************
49 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
50 path or anything including wildcards.
51 We're assuming here that '/' is not the second byte in any multibyte char
52 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
53 set.
54 ****************************************************************************/
56 /* Custom version for processing POSIX paths. */
57 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
59 static NTSTATUS check_path_syntax_internal(char *path,
60 bool posix_path,
61 bool *p_last_component_contains_wcard)
63 char *d = path;
64 const char *s = path;
65 NTSTATUS ret = NT_STATUS_OK;
66 bool start_of_name_component = True;
67 bool stream_started = false;
69 *p_last_component_contains_wcard = False;
71 while (*s) {
72 if (stream_started) {
73 switch (*s) {
74 case '/':
75 case '\\':
76 return NT_STATUS_OBJECT_NAME_INVALID;
77 case ':':
78 if (s[1] == '\0') {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 if (strchr_m(&s[1], ':')) {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 break;
88 if ((*s == ':') && !posix_path && !stream_started) {
89 if (*p_last_component_contains_wcard) {
90 return NT_STATUS_OBJECT_NAME_INVALID;
92 /* Stream names allow more characters than file names.
93 We're overloading posix_path here to allow a wider
94 range of characters. If stream_started is true this
95 is still a Windows path even if posix_path is true.
96 JRA.
98 stream_started = true;
99 start_of_name_component = false;
100 posix_path = true;
102 if (s[1] == '\0') {
103 return NT_STATUS_OBJECT_NAME_INVALID;
107 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
109 * Safe to assume is not the second part of a mb char
110 * as this is handled below.
112 /* Eat multiple '/' or '\\' */
113 while (IS_PATH_SEP(*s,posix_path)) {
114 s++;
116 if ((d != path) && (*s != '\0')) {
117 /* We only care about non-leading or trailing '/' or '\\' */
118 *d++ = '/';
121 start_of_name_component = True;
122 /* New component. */
123 *p_last_component_contains_wcard = False;
124 continue;
127 if (start_of_name_component) {
128 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
129 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
132 * No mb char starts with '.' so we're safe checking the directory separator here.
135 /* If we just added a '/' - delete it */
136 if ((d > path) && (*(d-1) == '/')) {
137 *(d-1) = '\0';
138 d--;
141 /* Are we at the start ? Can't go back further if so. */
142 if (d <= path) {
143 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
144 break;
146 /* Go back one level... */
147 /* We know this is safe as '/' cannot be part of a mb sequence. */
148 /* NOTE - if this assumption is invalid we are not in good shape... */
149 /* Decrement d first as d points to the *next* char to write into. */
150 for (d--; d > path; d--) {
151 if (*d == '/')
152 break;
154 s += 2; /* Else go past the .. */
155 /* We're still at the start of a name component, just the previous one. */
156 continue;
158 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
159 if (posix_path) {
160 /* Eat the '.' */
161 s++;
162 continue;
168 if (!(*s & 0x80)) {
169 if (!posix_path) {
170 if (*s <= 0x1f || *s == '|') {
171 return NT_STATUS_OBJECT_NAME_INVALID;
173 switch (*s) {
174 case '*':
175 case '?':
176 case '<':
177 case '>':
178 case '"':
179 *p_last_component_contains_wcard = True;
180 break;
181 default:
182 break;
185 *d++ = *s++;
186 } else {
187 size_t siz;
188 /* Get the size of the next MB character. */
189 next_codepoint(s,&siz);
190 switch(siz) {
191 case 5:
192 *d++ = *s++;
193 FALL_THROUGH;
194 case 4:
195 *d++ = *s++;
196 FALL_THROUGH;
197 case 3:
198 *d++ = *s++;
199 FALL_THROUGH;
200 case 2:
201 *d++ = *s++;
202 FALL_THROUGH;
203 case 1:
204 *d++ = *s++;
205 break;
206 default:
207 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
208 *d = '\0';
209 return NT_STATUS_INVALID_PARAMETER;
212 start_of_name_component = False;
215 *d = '\0';
217 return ret;
220 /****************************************************************************
221 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
222 No wildcards allowed.
223 ****************************************************************************/
225 NTSTATUS check_path_syntax(char *path)
227 bool ignore;
228 return check_path_syntax_internal(path, False, &ignore);
231 /****************************************************************************
232 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
233 Wildcards allowed - p_contains_wcard returns true if the last component contained
234 a wildcard.
235 ****************************************************************************/
237 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
239 return check_path_syntax_internal(path, False, p_contains_wcard);
242 /****************************************************************************
243 Check the path for a POSIX client.
244 We're assuming here that '/' is not the second byte in any multibyte char
245 set (a safe assumption).
246 ****************************************************************************/
248 NTSTATUS check_path_syntax_posix(char *path)
250 bool ignore;
251 return check_path_syntax_internal(path, True, &ignore);
254 /****************************************************************************
255 Pull a string and check the path allowing a wilcard - provide for error return.
256 Passes in posix flag.
257 ****************************************************************************/
259 static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
260 const char *base_ptr,
261 uint16_t smb_flags2,
262 char **pp_dest,
263 const char *src,
264 size_t src_len,
265 int flags,
266 bool posix_pathnames,
267 NTSTATUS *err,
268 bool *contains_wcard)
270 size_t ret;
272 *pp_dest = NULL;
274 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
275 src_len, flags);
277 if (!*pp_dest) {
278 *err = NT_STATUS_INVALID_PARAMETER;
279 return ret;
282 *contains_wcard = False;
284 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
286 * For a DFS path the function parse_dfs_path()
287 * will do the path processing, just make a copy.
289 *err = NT_STATUS_OK;
290 return ret;
293 if (posix_pathnames) {
294 *err = check_path_syntax_posix(*pp_dest);
295 } else {
296 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
299 return ret;
302 /****************************************************************************
303 Pull a string and check the path allowing a wilcard - provide for error return.
304 ****************************************************************************/
306 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
307 const char *base_ptr,
308 uint16_t smb_flags2,
309 char **pp_dest,
310 const char *src,
311 size_t src_len,
312 int flags,
313 NTSTATUS *err,
314 bool *contains_wcard)
316 return srvstr_get_path_wcard_internal(ctx,
317 base_ptr,
318 smb_flags2,
319 pp_dest,
320 src,
321 src_len,
322 flags,
323 false,
324 err,
325 contains_wcard);
328 /****************************************************************************
329 Pull a string and check the path allowing a wilcard - provide for error return.
330 posix_pathnames version.
331 ****************************************************************************/
333 size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
334 const char *base_ptr,
335 uint16_t smb_flags2,
336 char **pp_dest,
337 const char *src,
338 size_t src_len,
339 int flags,
340 NTSTATUS *err,
341 bool *contains_wcard)
343 return srvstr_get_path_wcard_internal(ctx,
344 base_ptr,
345 smb_flags2,
346 pp_dest,
347 src,
348 src_len,
349 flags,
350 true,
351 err,
352 contains_wcard);
355 /****************************************************************************
356 Pull a string and check the path - provide for error return.
357 ****************************************************************************/
359 size_t srvstr_get_path(TALLOC_CTX *ctx,
360 const char *base_ptr,
361 uint16_t smb_flags2,
362 char **pp_dest,
363 const char *src,
364 size_t src_len,
365 int flags,
366 NTSTATUS *err)
368 bool ignore;
369 return srvstr_get_path_wcard_internal(ctx,
370 base_ptr,
371 smb_flags2,
372 pp_dest,
373 src,
374 src_len,
375 flags,
376 false,
377 err,
378 &ignore);
381 /****************************************************************************
382 Pull a string and check the path - provide for error return.
383 posix_pathnames version.
384 ****************************************************************************/
386 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
387 const char *base_ptr,
388 uint16_t smb_flags2,
389 char **pp_dest,
390 const char *src,
391 size_t src_len,
392 int flags,
393 NTSTATUS *err)
395 bool ignore;
396 return srvstr_get_path_wcard_internal(ctx,
397 base_ptr,
398 smb_flags2,
399 pp_dest,
400 src,
401 src_len,
402 flags,
403 true,
404 err,
405 &ignore);
409 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
410 char **pp_dest, const char *src, int flags,
411 NTSTATUS *err, bool *contains_wcard)
413 ssize_t bufrem = smbreq_bufrem(req, src);
415 if (bufrem < 0) {
416 *err = NT_STATUS_INVALID_PARAMETER;
417 return 0;
420 if (req->posix_pathnames) {
421 return srvstr_get_path_wcard_internal(mem_ctx,
422 (const char *)req->inbuf,
423 req->flags2,
424 pp_dest,
425 src,
426 bufrem,
427 flags,
428 true,
429 err,
430 contains_wcard);
431 } else {
432 return srvstr_get_path_wcard_internal(mem_ctx,
433 (const char *)req->inbuf,
434 req->flags2,
435 pp_dest,
436 src,
437 bufrem,
438 flags,
439 false,
440 err,
441 contains_wcard);
445 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
446 char **pp_dest, const char *src, int flags,
447 NTSTATUS *err)
449 bool ignore;
450 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
451 flags, err, &ignore);
455 * pull a string from the smb_buf part of a packet. In this case the
456 * string can either be null terminated or it can be terminated by the
457 * end of the smbbuf area
459 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
460 char **dest, const uint8_t *src, int flags)
462 ssize_t bufrem = smbreq_bufrem(req, src);
464 if (bufrem < 0) {
465 return 0;
468 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
469 bufrem, flags);
472 /****************************************************************************
473 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
474 ****************************************************************************/
476 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
477 files_struct *fsp)
479 if ((fsp == NULL) || (conn == NULL)) {
480 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
481 return False;
483 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
484 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
485 return False;
487 return True;
490 /****************************************************************************
491 Check if we have a correct fsp pointing to a file.
492 ****************************************************************************/
494 bool check_fsp(connection_struct *conn, struct smb_request *req,
495 files_struct *fsp)
497 if (!check_fsp_open(conn, req, fsp)) {
498 return False;
500 if (fsp->is_directory) {
501 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
502 return False;
504 if (fsp->fh->fd == -1) {
505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
506 return False;
508 fsp->num_smb_operations++;
509 return True;
512 /****************************************************************************
513 Check if we have a correct fsp pointing to a quota fake file. Replacement for
514 the CHECK_NTQUOTA_HANDLE_OK macro.
515 ****************************************************************************/
517 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
518 files_struct *fsp)
520 if (!check_fsp_open(conn, req, fsp)) {
521 return false;
524 if (fsp->is_directory) {
525 return false;
528 if (fsp->fake_file_handle == NULL) {
529 return false;
532 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
533 return false;
536 if (fsp->fake_file_handle->private_data == NULL) {
537 return false;
540 return true;
543 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
544 const char *name, int name_type)
546 char *trim_name;
547 char *trim_name_type;
548 const char *retarget_parm;
549 char *retarget;
550 char *p;
551 int retarget_type = 0x20;
552 int retarget_port = NBT_SMB_PORT;
553 struct sockaddr_storage retarget_addr;
554 struct sockaddr_in *in_addr;
555 bool ret = false;
556 uint8_t outbuf[10];
558 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
559 return false;
562 trim_name = talloc_strdup(talloc_tos(), name);
563 if (trim_name == NULL) {
564 goto fail;
566 trim_char(trim_name, ' ', ' ');
568 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
569 name_type);
570 if (trim_name_type == NULL) {
571 goto fail;
574 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
575 trim_name_type, NULL);
576 if (retarget_parm == NULL) {
577 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
578 trim_name, NULL);
580 if (retarget_parm == NULL) {
581 goto fail;
584 retarget = talloc_strdup(trim_name, retarget_parm);
585 if (retarget == NULL) {
586 goto fail;
589 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
591 p = strchr(retarget, ':');
592 if (p != NULL) {
593 *p++ = '\0';
594 retarget_port = atoi(p);
597 p = strchr_m(retarget, '#');
598 if (p != NULL) {
599 *p++ = '\0';
600 if (sscanf(p, "%x", &retarget_type) != 1) {
601 goto fail;
605 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
606 if (!ret) {
607 DEBUG(10, ("could not resolve %s\n", retarget));
608 goto fail;
611 if (retarget_addr.ss_family != AF_INET) {
612 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
613 goto fail;
616 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
618 _smb_setlen(outbuf, 6);
619 SCVAL(outbuf, 0, 0x84);
620 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
621 *(uint16_t *)(outbuf+8) = htons(retarget_port);
623 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
624 NULL)) {
625 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
626 "failed.");
629 ret = true;
630 fail:
631 TALLOC_FREE(trim_name);
632 return ret;
635 static void reply_called_name_not_present(char *outbuf)
637 smb_setlen(outbuf, 1);
638 SCVAL(outbuf, 0, 0x83);
639 SCVAL(outbuf, 4, 0x82);
642 /****************************************************************************
643 Reply to a (netbios-level) special message.
644 ****************************************************************************/
646 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
648 struct smbd_server_connection *sconn = xconn->client->sconn;
649 int msg_type = CVAL(inbuf,0);
650 int msg_flags = CVAL(inbuf,1);
652 * We only really use 4 bytes of the outbuf, but for the smb_setlen
653 * calculation & friends (srv_send_smb uses that) we need the full smb
654 * header.
656 char outbuf[smb_size];
658 memset(outbuf, '\0', sizeof(outbuf));
660 smb_setlen(outbuf,0);
662 switch (msg_type) {
663 case NBSSrequest: /* session request */
665 /* inbuf_size is guarenteed to be at least 4. */
666 fstring name1,name2;
667 int name_type1, name_type2;
668 int name_len1, name_len2;
670 *name1 = *name2 = 0;
672 if (xconn->transport.nbt.got_session) {
673 exit_server_cleanly("multiple session request not permitted");
676 SCVAL(outbuf,0,NBSSpositive);
677 SCVAL(outbuf,3,0);
679 /* inbuf_size is guaranteed to be at least 4. */
680 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
681 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
682 DEBUG(0,("Invalid name length in session request\n"));
683 reply_called_name_not_present(outbuf);
684 break;
686 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
687 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
688 DEBUG(0,("Invalid name length in session request\n"));
689 reply_called_name_not_present(outbuf);
690 break;
693 name_type1 = name_extract((unsigned char *)inbuf,
694 inbuf_size,(unsigned int)4,name1);
695 name_type2 = name_extract((unsigned char *)inbuf,
696 inbuf_size,(unsigned int)(4 + name_len1),name2);
698 if (name_type1 == -1 || name_type2 == -1) {
699 DEBUG(0,("Invalid name type in session request\n"));
700 reply_called_name_not_present(outbuf);
701 break;
704 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
705 name1, name_type1, name2, name_type2));
707 if (netbios_session_retarget(xconn, name1, name_type1)) {
708 exit_server_cleanly("retargeted client");
712 * Windows NT/2k uses "*SMBSERVER" and XP uses
713 * "*SMBSERV" arrggg!!!
715 if (strequal(name1, "*SMBSERVER ")
716 || strequal(name1, "*SMBSERV ")) {
717 char *raddr;
719 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
720 talloc_tos());
721 if (raddr == NULL) {
722 exit_server_cleanly("could not allocate raddr");
725 fstrcpy(name1, raddr);
728 set_local_machine_name(name1, True);
729 set_remote_machine_name(name2, True);
731 if (is_ipaddress(sconn->remote_hostname)) {
732 char *p = discard_const_p(char, sconn->remote_hostname);
734 talloc_free(p);
736 sconn->remote_hostname = talloc_strdup(sconn,
737 get_remote_machine_name());
738 if (sconn->remote_hostname == NULL) {
739 exit_server_cleanly("could not copy remote name");
741 xconn->remote_hostname = sconn->remote_hostname;
744 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
745 get_local_machine_name(), get_remote_machine_name(),
746 name_type2));
748 if (name_type2 == 'R') {
749 /* We are being asked for a pathworks session ---
750 no thanks! */
751 reply_called_name_not_present(outbuf);
752 break;
755 reload_services(sconn, conn_snum_used, true);
756 reopen_logs();
758 xconn->transport.nbt.got_session = true;
759 break;
762 case 0x89: /* session keepalive request
763 (some old clients produce this?) */
764 SCVAL(outbuf,0,NBSSkeepalive);
765 SCVAL(outbuf,3,0);
766 break;
768 case NBSSpositive: /* positive session response */
769 case NBSSnegative: /* negative session response */
770 case NBSSretarget: /* retarget session response */
771 DEBUG(0,("Unexpected session response\n"));
772 break;
774 case NBSSkeepalive: /* session keepalive */
775 default:
776 return;
779 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
780 msg_type, msg_flags));
782 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
783 exit_server_cleanly("reply_special: srv_send_smb failed.");
786 if (CVAL(outbuf, 0) != 0x82) {
787 exit_server_cleanly("invalid netbios session");
789 return;
792 /****************************************************************************
793 Reply to a tcon.
794 conn POINTER CAN BE NULL HERE !
795 ****************************************************************************/
797 void reply_tcon(struct smb_request *req)
799 connection_struct *conn = req->conn;
800 const char *service;
801 char *service_buf = NULL;
802 char *password = NULL;
803 char *dev = NULL;
804 int pwlen=0;
805 NTSTATUS nt_status;
806 const uint8_t *p;
807 const char *p2;
808 TALLOC_CTX *ctx = talloc_tos();
809 struct smbXsrv_connection *xconn = req->xconn;
810 NTTIME now = timeval_to_nttime(&req->request_time);
812 START_PROFILE(SMBtcon);
814 if (req->buflen < 4) {
815 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
816 END_PROFILE(SMBtcon);
817 return;
820 p = req->buf + 1;
821 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
822 p += 1;
823 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
824 p += pwlen+1;
825 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
826 p += 1;
828 if (service_buf == NULL || password == NULL || dev == NULL) {
829 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
830 END_PROFILE(SMBtcon);
831 return;
833 p2 = strrchr_m(service_buf,'\\');
834 if (p2) {
835 service = p2+1;
836 } else {
837 service = service_buf;
840 conn = make_connection(req, now, service, dev,
841 req->vuid,&nt_status);
842 req->conn = conn;
844 if (!conn) {
845 reply_nterror(req, nt_status);
846 END_PROFILE(SMBtcon);
847 return;
850 reply_outbuf(req, 2, 0);
851 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
852 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
853 SSVAL(req->outbuf,smb_tid,conn->cnum);
855 DEBUG(3,("tcon service=%s cnum=%d\n",
856 service, conn->cnum));
858 END_PROFILE(SMBtcon);
859 return;
862 /****************************************************************************
863 Reply to a tcon and X.
864 conn POINTER CAN BE NULL HERE !
865 ****************************************************************************/
867 void reply_tcon_and_X(struct smb_request *req)
869 connection_struct *conn = req->conn;
870 const char *service = NULL;
871 TALLOC_CTX *ctx = talloc_tos();
872 /* what the client thinks the device is */
873 char *client_devicetype = NULL;
874 /* what the server tells the client the share represents */
875 const char *server_devicetype;
876 NTSTATUS nt_status;
877 int passlen;
878 char *path = NULL;
879 const uint8_t *p;
880 const char *q;
881 uint16_t tcon_flags;
882 struct smbXsrv_session *session = NULL;
883 NTTIME now = timeval_to_nttime(&req->request_time);
884 bool session_key_updated = false;
885 uint16_t optional_support = 0;
886 struct smbXsrv_connection *xconn = req->xconn;
888 START_PROFILE(SMBtconX);
890 if (req->wct < 4) {
891 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
892 END_PROFILE(SMBtconX);
893 return;
896 passlen = SVAL(req->vwv+3, 0);
897 tcon_flags = SVAL(req->vwv+2, 0);
899 /* we might have to close an old one */
900 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
901 struct smbXsrv_tcon *tcon;
902 NTSTATUS status;
904 tcon = conn->tcon;
905 req->conn = NULL;
906 conn = NULL;
909 * TODO: cancel all outstanding requests on the tcon
911 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
912 if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(0, ("reply_tcon_and_X: "
914 "smbXsrv_tcon_disconnect() failed: %s\n",
915 nt_errstr(status)));
917 * If we hit this case, there is something completely
918 * wrong, so we better disconnect the transport connection.
920 END_PROFILE(SMBtconX);
921 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
922 return;
925 TALLOC_FREE(tcon);
927 * This tree id is gone. Make sure we can't re-use it
928 * by accident.
930 req->tid = 0;
933 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
934 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
935 END_PROFILE(SMBtconX);
936 return;
939 if (xconn->smb1.negprot.encrypted_passwords) {
940 p = req->buf + passlen;
941 } else {
942 p = req->buf + passlen + 1;
945 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
947 if (path == NULL) {
948 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
949 END_PROFILE(SMBtconX);
950 return;
954 * the service name can be either: \\server\share
955 * or share directly like on the DELL PowerVault 705
957 if (*path=='\\') {
958 q = strchr_m(path+2,'\\');
959 if (!q) {
960 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
961 END_PROFILE(SMBtconX);
962 return;
964 service = q+1;
965 } else {
966 service = path;
969 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
970 &client_devicetype, p,
971 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
973 if (client_devicetype == NULL) {
974 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
975 END_PROFILE(SMBtconX);
976 return;
979 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
981 nt_status = smb1srv_session_lookup(xconn,
982 req->vuid, now, &session);
983 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
984 reply_force_doserror(req, ERRSRV, ERRbaduid);
985 END_PROFILE(SMBtconX);
986 return;
988 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
989 reply_nterror(req, nt_status);
990 END_PROFILE(SMBtconX);
991 return;
993 if (!NT_STATUS_IS_OK(nt_status)) {
994 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
995 END_PROFILE(SMBtconX);
996 return;
999 if (session->global->auth_session_info == NULL) {
1000 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1001 END_PROFILE(SMBtconX);
1002 return;
1006 * If there is no application key defined yet
1007 * we create one.
1009 * This means we setup the application key on the
1010 * first tcon that happens via the given session.
1012 * Once the application key is defined, it does not
1013 * change any more.
1015 if (session->global->application_key.length == 0 &&
1016 smb2_signing_key_valid(session->global->signing_key))
1018 struct smbXsrv_session *x = session;
1019 struct auth_session_info *session_info =
1020 session->global->auth_session_info;
1021 uint8_t session_key[16];
1023 ZERO_STRUCT(session_key);
1024 memcpy(session_key, x->global->signing_key->blob.data,
1025 MIN(x->global->signing_key->blob.length, sizeof(session_key)));
1028 * The application key is truncated/padded to 16 bytes
1030 x->global->application_key = data_blob_talloc(x->global,
1031 session_key,
1032 sizeof(session_key));
1033 ZERO_STRUCT(session_key);
1034 if (x->global->application_key.data == NULL) {
1035 reply_nterror(req, NT_STATUS_NO_MEMORY);
1036 END_PROFILE(SMBtconX);
1037 return;
1040 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1041 NTSTATUS status;
1043 status = smb_key_derivation(x->global->application_key.data,
1044 x->global->application_key.length,
1045 x->global->application_key.data);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 DBG_ERR("smb_key_derivation failed: %s\n",
1048 nt_errstr(status));
1049 return;
1051 optional_support |= SMB_EXTENDED_SIGNATURES;
1055 * Place the application key into the session_info
1057 data_blob_clear_free(&session_info->session_key);
1058 session_info->session_key = data_blob_dup_talloc(session_info,
1059 x->global->application_key);
1060 if (session_info->session_key.data == NULL) {
1061 data_blob_clear_free(&x->global->application_key);
1062 reply_nterror(req, NT_STATUS_NO_MEMORY);
1063 END_PROFILE(SMBtconX);
1064 return;
1066 session_key_updated = true;
1069 conn = make_connection(req, now, service, client_devicetype,
1070 req->vuid, &nt_status);
1071 req->conn =conn;
1073 if (!conn) {
1074 if (session_key_updated) {
1075 struct smbXsrv_session *x = session;
1076 struct auth_session_info *session_info =
1077 session->global->auth_session_info;
1078 data_blob_clear_free(&x->global->application_key);
1079 data_blob_clear_free(&session_info->session_key);
1081 reply_nterror(req, nt_status);
1082 END_PROFILE(SMBtconX);
1083 return;
1086 if ( IS_IPC(conn) )
1087 server_devicetype = "IPC";
1088 else if ( IS_PRINT(conn) )
1089 server_devicetype = "LPT1:";
1090 else
1091 server_devicetype = "A:";
1093 if (get_Protocol() < PROTOCOL_NT1) {
1094 reply_outbuf(req, 2, 0);
1095 if (message_push_string(&req->outbuf, server_devicetype,
1096 STR_TERMINATE|STR_ASCII) == -1) {
1097 reply_nterror(req, NT_STATUS_NO_MEMORY);
1098 END_PROFILE(SMBtconX);
1099 return;
1101 } else {
1102 /* NT sets the fstype of IPC$ to the null string */
1103 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1105 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1106 /* Return permissions. */
1107 uint32_t perm1 = 0;
1108 uint32_t perm2 = 0;
1110 reply_outbuf(req, 7, 0);
1112 if (IS_IPC(conn)) {
1113 perm1 = FILE_ALL_ACCESS;
1114 perm2 = FILE_ALL_ACCESS;
1115 } else {
1116 perm1 = conn->share_access;
1119 SIVAL(req->outbuf, smb_vwv3, perm1);
1120 SIVAL(req->outbuf, smb_vwv5, perm2);
1121 } else {
1122 reply_outbuf(req, 3, 0);
1125 if ((message_push_string(&req->outbuf, server_devicetype,
1126 STR_TERMINATE|STR_ASCII) == -1)
1127 || (message_push_string(&req->outbuf, fstype,
1128 STR_TERMINATE) == -1)) {
1129 reply_nterror(req, NT_STATUS_NO_MEMORY);
1130 END_PROFILE(SMBtconX);
1131 return;
1134 /* what does setting this bit do? It is set by NT4 and
1135 may affect the ability to autorun mounted cdroms */
1136 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1137 optional_support |=
1138 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1140 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1141 DEBUG(2,("Serving %s as a Dfs root\n",
1142 lp_servicename(ctx, SNUM(conn)) ));
1143 optional_support |= SMB_SHARE_IN_DFS;
1146 SSVAL(req->outbuf, smb_vwv2, optional_support);
1149 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1150 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1152 DEBUG(3,("tconX service=%s \n",
1153 service));
1155 /* set the incoming and outgoing tid to the just created one */
1156 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1157 SSVAL(req->outbuf,smb_tid,conn->cnum);
1159 END_PROFILE(SMBtconX);
1161 req->tid = conn->cnum;
1164 /****************************************************************************
1165 Reply to an unknown type.
1166 ****************************************************************************/
1168 void reply_unknown_new(struct smb_request *req, uint8_t type)
1170 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1171 smb_fn_name(type), type, type));
1172 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1173 return;
1176 /****************************************************************************
1177 Reply to an ioctl.
1178 conn POINTER CAN BE NULL HERE !
1179 ****************************************************************************/
1181 void reply_ioctl(struct smb_request *req)
1183 connection_struct *conn = req->conn;
1184 uint16_t device;
1185 uint16_t function;
1186 uint32_t ioctl_code;
1187 int replysize;
1188 char *p;
1190 START_PROFILE(SMBioctl);
1192 if (req->wct < 3) {
1193 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1194 END_PROFILE(SMBioctl);
1195 return;
1198 device = SVAL(req->vwv+1, 0);
1199 function = SVAL(req->vwv+2, 0);
1200 ioctl_code = (device << 16) + function;
1202 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1204 switch (ioctl_code) {
1205 case IOCTL_QUERY_JOB_INFO:
1206 replysize = 32;
1207 break;
1208 default:
1209 reply_force_doserror(req, ERRSRV, ERRnosupport);
1210 END_PROFILE(SMBioctl);
1211 return;
1214 reply_outbuf(req, 8, replysize+1);
1215 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1216 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1217 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1218 p = smb_buf(req->outbuf);
1219 memset(p, '\0', replysize+1); /* valgrind-safe. */
1220 p += 1; /* Allow for alignment */
1222 switch (ioctl_code) {
1223 case IOCTL_QUERY_JOB_INFO:
1225 NTSTATUS status;
1226 size_t len = 0;
1227 files_struct *fsp = file_fsp(
1228 req, SVAL(req->vwv+0, 0));
1229 if (!fsp) {
1230 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1231 END_PROFILE(SMBioctl);
1232 return;
1234 /* Job number */
1235 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1237 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1238 lp_netbios_name(), 15,
1239 STR_TERMINATE|STR_ASCII, &len);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 reply_nterror(req, status);
1242 END_PROFILE(SMBioctl);
1243 return;
1245 if (conn) {
1246 status = srvstr_push((char *)req->outbuf, req->flags2,
1247 p+18,
1248 lp_servicename(talloc_tos(),
1249 SNUM(conn)),
1250 13, STR_TERMINATE|STR_ASCII, &len);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 reply_nterror(req, status);
1253 END_PROFILE(SMBioctl);
1254 return;
1256 } else {
1257 memset(p+18, 0, 13);
1259 break;
1263 END_PROFILE(SMBioctl);
1264 return;
1267 /****************************************************************************
1268 Strange checkpath NTSTATUS mapping.
1269 ****************************************************************************/
1271 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1273 /* Strange DOS error code semantics only for checkpath... */
1274 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1275 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1276 /* We need to map to ERRbadpath */
1277 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1280 return status;
1283 /****************************************************************************
1284 Reply to a checkpath.
1285 ****************************************************************************/
1287 void reply_checkpath(struct smb_request *req)
1289 connection_struct *conn = req->conn;
1290 struct smb_filename *smb_fname = NULL;
1291 char *name = NULL;
1292 NTSTATUS status;
1293 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1294 TALLOC_CTX *ctx = talloc_tos();
1296 START_PROFILE(SMBcheckpath);
1298 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1299 STR_TERMINATE, &status);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 status = map_checkpath_error(req->flags2, status);
1303 reply_nterror(req, status);
1304 END_PROFILE(SMBcheckpath);
1305 return;
1308 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1310 status = filename_convert(ctx,
1311 conn,
1312 name,
1313 ucf_flags,
1314 NULL,
1315 NULL,
1316 &smb_fname);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1320 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1321 ERRSRV, ERRbadpath);
1322 END_PROFILE(SMBcheckpath);
1323 return;
1325 goto path_err;
1328 if (!VALID_STAT(smb_fname->st) &&
1329 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1330 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1331 smb_fname_str_dbg(smb_fname), strerror(errno)));
1332 status = map_nt_error_from_unix(errno);
1333 goto path_err;
1336 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1337 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1338 ERRDOS, ERRbadpath);
1339 goto out;
1342 reply_outbuf(req, 0, 0);
1344 path_err:
1345 /* We special case this - as when a Windows machine
1346 is parsing a path is steps through the components
1347 one at a time - if a component fails it expects
1348 ERRbadpath, not ERRbadfile.
1350 status = map_checkpath_error(req->flags2, status);
1351 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1353 * Windows returns different error codes if
1354 * the parent directory is valid but not the
1355 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1356 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1357 * if the path is invalid.
1359 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1360 ERRDOS, ERRbadpath);
1361 goto out;
1364 reply_nterror(req, status);
1366 out:
1367 TALLOC_FREE(smb_fname);
1368 END_PROFILE(SMBcheckpath);
1369 return;
1372 /****************************************************************************
1373 Reply to a getatr.
1374 ****************************************************************************/
1376 void reply_getatr(struct smb_request *req)
1378 connection_struct *conn = req->conn;
1379 struct smb_filename *smb_fname = NULL;
1380 char *fname = NULL;
1381 int mode=0;
1382 off_t size=0;
1383 time_t mtime=0;
1384 const char *p;
1385 NTSTATUS status;
1386 TALLOC_CTX *ctx = talloc_tos();
1387 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1389 START_PROFILE(SMBgetatr);
1391 p = (const char *)req->buf + 1;
1392 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 reply_nterror(req, status);
1395 goto out;
1398 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1399 under WfWg - weird! */
1400 if (*fname == '\0') {
1401 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1402 if (!CAN_WRITE(conn)) {
1403 mode |= FILE_ATTRIBUTE_READONLY;
1405 size = 0;
1406 mtime = 0;
1407 } else {
1408 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1409 status = filename_convert(ctx,
1410 conn,
1411 fname,
1412 ucf_flags,
1413 NULL,
1414 NULL,
1415 &smb_fname);
1416 if (!NT_STATUS_IS_OK(status)) {
1417 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1418 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1419 ERRSRV, ERRbadpath);
1420 goto out;
1422 reply_nterror(req, status);
1423 goto out;
1425 if (!VALID_STAT(smb_fname->st) &&
1426 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1427 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1428 smb_fname_str_dbg(smb_fname),
1429 strerror(errno)));
1430 reply_nterror(req, map_nt_error_from_unix(errno));
1431 goto out;
1434 mode = dos_mode(conn, smb_fname);
1435 size = smb_fname->st.st_ex_size;
1437 if (ask_sharemode) {
1438 struct timespec write_time_ts;
1439 struct file_id fileid;
1441 ZERO_STRUCT(write_time_ts);
1442 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1443 get_file_infos(fileid, 0, NULL, &write_time_ts);
1444 if (!null_timespec(write_time_ts)) {
1445 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1449 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1450 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1451 size = 0;
1455 reply_outbuf(req, 10, 0);
1457 SSVAL(req->outbuf,smb_vwv0,mode);
1458 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1459 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1460 } else {
1461 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1463 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1465 if (get_Protocol() >= PROTOCOL_NT1) {
1466 SSVAL(req->outbuf, smb_flg2,
1467 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1470 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1471 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1473 out:
1474 TALLOC_FREE(smb_fname);
1475 TALLOC_FREE(fname);
1476 END_PROFILE(SMBgetatr);
1477 return;
1480 /****************************************************************************
1481 Reply to a setatr.
1482 ****************************************************************************/
1484 void reply_setatr(struct smb_request *req)
1486 struct smb_file_time ft;
1487 connection_struct *conn = req->conn;
1488 struct smb_filename *smb_fname = NULL;
1489 char *fname = NULL;
1490 int mode;
1491 time_t mtime;
1492 const char *p;
1493 NTSTATUS status;
1494 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1495 TALLOC_CTX *ctx = talloc_tos();
1497 START_PROFILE(SMBsetatr);
1499 if (req->wct < 2) {
1500 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1501 goto out;
1504 p = (const char *)req->buf + 1;
1505 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1506 if (!NT_STATUS_IS_OK(status)) {
1507 reply_nterror(req, status);
1508 goto out;
1511 status = filename_convert(ctx,
1512 conn,
1513 fname,
1514 ucf_flags,
1515 NULL,
1516 NULL,
1517 &smb_fname);
1518 if (!NT_STATUS_IS_OK(status)) {
1519 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1520 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1521 ERRSRV, ERRbadpath);
1522 goto out;
1524 reply_nterror(req, status);
1525 goto out;
1528 if (ISDOT(smb_fname->base_name)) {
1530 * Not sure here is the right place to catch this
1531 * condition. Might be moved to somewhere else later -- vl
1533 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1534 goto out;
1537 mode = SVAL(req->vwv+0, 0);
1538 mtime = srv_make_unix_date3(req->vwv+1);
1540 if (mode != FILE_ATTRIBUTE_NORMAL) {
1541 if (VALID_STAT_OF_DIR(smb_fname->st))
1542 mode |= FILE_ATTRIBUTE_DIRECTORY;
1543 else
1544 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1546 status = smbd_check_access_rights(
1547 conn, smb_fname, false, FILE_WRITE_ATTRIBUTES);
1548 if (!NT_STATUS_IS_OK(status)) {
1549 reply_nterror(req, status);
1550 goto out;
1553 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1554 false) != 0) {
1555 reply_nterror(req, map_nt_error_from_unix(errno));
1556 goto out;
1560 ft = (struct smb_file_time) {
1561 .mtime = convert_time_t_to_timespec(mtime)
1564 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1565 if (!NT_STATUS_IS_OK(status)) {
1566 reply_nterror(req, status);
1567 goto out;
1570 reply_outbuf(req, 0, 0);
1572 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1573 mode));
1574 out:
1575 TALLOC_FREE(smb_fname);
1576 END_PROFILE(SMBsetatr);
1577 return;
1580 /****************************************************************************
1581 Reply to a dskattr.
1582 ****************************************************************************/
1584 void reply_dskattr(struct smb_request *req)
1586 connection_struct *conn = req->conn;
1587 uint64_t ret;
1588 uint64_t dfree,dsize,bsize;
1589 struct smb_filename smb_fname;
1590 START_PROFILE(SMBdskattr);
1592 ZERO_STRUCT(smb_fname);
1593 smb_fname.base_name = discard_const_p(char, ".");
1595 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1596 reply_nterror(req, map_nt_error_from_unix(errno));
1597 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1598 END_PROFILE(SMBdskattr);
1599 return;
1602 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1603 if (ret == (uint64_t)-1) {
1604 reply_nterror(req, map_nt_error_from_unix(errno));
1605 END_PROFILE(SMBdskattr);
1606 return;
1610 * Force max to fit in 16 bit fields.
1612 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1613 dfree /= 2;
1614 dsize /= 2;
1615 bsize *= 2;
1616 if (bsize > (WORDMAX*512)) {
1617 bsize = (WORDMAX*512);
1618 if (dsize > WORDMAX)
1619 dsize = WORDMAX;
1620 if (dfree > WORDMAX)
1621 dfree = WORDMAX;
1622 break;
1626 reply_outbuf(req, 5, 0);
1628 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1629 double total_space, free_space;
1630 /* we need to scale this to a number that DOS6 can handle. We
1631 use floating point so we can handle large drives on systems
1632 that don't have 64 bit integers
1634 we end up displaying a maximum of 2G to DOS systems
1636 total_space = dsize * (double)bsize;
1637 free_space = dfree * (double)bsize;
1639 dsize = (uint64_t)((total_space+63*512) / (64*512));
1640 dfree = (uint64_t)((free_space+63*512) / (64*512));
1642 if (dsize > 0xFFFF) dsize = 0xFFFF;
1643 if (dfree > 0xFFFF) dfree = 0xFFFF;
1645 SSVAL(req->outbuf,smb_vwv0,dsize);
1646 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1647 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1648 SSVAL(req->outbuf,smb_vwv3,dfree);
1649 } else {
1650 SSVAL(req->outbuf,smb_vwv0,dsize);
1651 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1652 SSVAL(req->outbuf,smb_vwv2,512);
1653 SSVAL(req->outbuf,smb_vwv3,dfree);
1656 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1658 END_PROFILE(SMBdskattr);
1659 return;
1663 * Utility function to split the filename from the directory.
1665 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1666 char **fname_dir_out,
1667 char **fname_mask_out)
1669 const char *p = NULL;
1670 char *fname_dir = NULL;
1671 char *fname_mask = NULL;
1673 p = strrchr_m(fname_in, '/');
1674 if (!p) {
1675 fname_dir = talloc_strdup(ctx, ".");
1676 fname_mask = talloc_strdup(ctx, fname_in);
1677 } else {
1678 fname_dir = talloc_strndup(ctx, fname_in,
1679 PTR_DIFF(p, fname_in));
1680 fname_mask = talloc_strdup(ctx, p+1);
1683 if (!fname_dir || !fname_mask) {
1684 TALLOC_FREE(fname_dir);
1685 TALLOC_FREE(fname_mask);
1686 return NT_STATUS_NO_MEMORY;
1689 *fname_dir_out = fname_dir;
1690 *fname_mask_out = fname_mask;
1691 return NT_STATUS_OK;
1694 /****************************************************************************
1695 Make a dir struct.
1696 ****************************************************************************/
1698 static bool make_dir_struct(TALLOC_CTX *ctx,
1699 char *buf,
1700 const char *mask,
1701 const char *fname,
1702 off_t size,
1703 uint32_t mode,
1704 time_t date,
1705 bool uc)
1707 char *p;
1708 char *mask2 = talloc_strdup(ctx, mask);
1710 if (!mask2) {
1711 return False;
1714 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1715 size = 0;
1718 memset(buf+1,' ',11);
1719 if ((p = strchr_m(mask2,'.')) != NULL) {
1720 *p = 0;
1721 push_ascii(buf+1,mask2,8, 0);
1722 push_ascii(buf+9,p+1,3, 0);
1723 *p = '.';
1724 } else {
1725 push_ascii(buf+1,mask2,11, 0);
1728 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1729 SCVAL(buf,21,mode);
1730 srv_put_dos_date(buf,22,date);
1731 SSVAL(buf,26,size & 0xFFFF);
1732 SSVAL(buf,28,(size >> 16)&0xFFFF);
1733 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1734 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1735 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1736 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1737 return True;
1740 /****************************************************************************
1741 Reply to a search.
1742 Can be called from SMBsearch, SMBffirst or SMBfunique.
1743 ****************************************************************************/
1745 void reply_search(struct smb_request *req)
1747 connection_struct *conn = req->conn;
1748 char *path = NULL;
1749 char *mask = NULL;
1750 char *directory = NULL;
1751 struct smb_filename *smb_fname = NULL;
1752 char *fname = NULL;
1753 off_t size;
1754 uint32_t mode;
1755 struct timespec date;
1756 uint32_t dirtype;
1757 unsigned int numentries = 0;
1758 unsigned int maxentries = 0;
1759 bool finished = False;
1760 const char *p;
1761 int status_len;
1762 char status[21];
1763 int dptr_num= -1;
1764 bool check_descend = False;
1765 bool expect_close = False;
1766 NTSTATUS nt_status;
1767 bool mask_contains_wcard = False;
1768 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1769 TALLOC_CTX *ctx = talloc_tos();
1770 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1771 struct dptr_struct *dirptr = NULL;
1772 struct smbXsrv_connection *xconn = req->xconn;
1773 struct smbd_server_connection *sconn = req->sconn;
1775 START_PROFILE(SMBsearch);
1777 if (req->wct < 2) {
1778 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1779 goto out;
1782 if (req->posix_pathnames) {
1783 reply_unknown_new(req, req->cmd);
1784 goto out;
1787 /* If we were called as SMBffirst then we must expect close. */
1788 if(req->cmd == SMBffirst) {
1789 expect_close = True;
1792 reply_outbuf(req, 1, 3);
1793 maxentries = SVAL(req->vwv+0, 0);
1794 dirtype = SVAL(req->vwv+1, 0);
1795 p = (const char *)req->buf + 1;
1796 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1797 &nt_status, &mask_contains_wcard);
1798 if (!NT_STATUS_IS_OK(nt_status)) {
1799 reply_nterror(req, nt_status);
1800 goto out;
1803 p++;
1804 status_len = SVAL(p, 0);
1805 p += 2;
1807 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1809 if (status_len == 0) {
1810 struct smb_filename *smb_dname = NULL;
1811 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1812 ucf_flags_from_smb_request(req);
1813 nt_status = filename_convert(ctx, conn,
1814 path,
1815 ucf_flags,
1816 NULL,
1817 &mask_contains_wcard,
1818 &smb_fname);
1819 if (!NT_STATUS_IS_OK(nt_status)) {
1820 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1821 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1822 ERRSRV, ERRbadpath);
1823 goto out;
1825 reply_nterror(req, nt_status);
1826 goto out;
1829 directory = smb_fname->base_name;
1831 p = strrchr_m(directory,'/');
1832 if ((p != NULL) && (*directory != '/')) {
1833 mask = talloc_strdup(ctx, p + 1);
1834 directory = talloc_strndup(ctx, directory,
1835 PTR_DIFF(p, directory));
1836 } else {
1837 mask = talloc_strdup(ctx, directory);
1838 directory = talloc_strdup(ctx,".");
1841 if (!directory) {
1842 reply_nterror(req, NT_STATUS_NO_MEMORY);
1843 goto out;
1846 memset((char *)status,'\0',21);
1847 SCVAL(status,0,(dirtype & 0x1F));
1849 smb_dname = synthetic_smb_fname(talloc_tos(),
1850 directory,
1851 NULL,
1852 NULL,
1853 smb_fname->flags);
1854 if (smb_dname == NULL) {
1855 reply_nterror(req, NT_STATUS_NO_MEMORY);
1856 goto out;
1859 nt_status = dptr_create(conn,
1860 NULL, /* req */
1861 NULL, /* fsp */
1862 smb_dname,
1863 True,
1864 expect_close,
1865 req->smbpid,
1866 mask,
1867 mask_contains_wcard,
1868 dirtype,
1869 &dirptr);
1871 TALLOC_FREE(smb_dname);
1873 if (!NT_STATUS_IS_OK(nt_status)) {
1874 reply_nterror(req, nt_status);
1875 goto out;
1877 dptr_num = dptr_dnum(dirptr);
1878 } else {
1879 int status_dirtype;
1880 const char *dirpath;
1882 memcpy(status,p,21);
1883 status_dirtype = CVAL(status,0) & 0x1F;
1884 if (status_dirtype != (dirtype & 0x1F)) {
1885 dirtype = status_dirtype;
1888 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1889 if (!dirptr) {
1890 goto SearchEmpty;
1892 dirpath = dptr_path(sconn, dptr_num);
1893 directory = talloc_strdup(ctx, dirpath);
1894 if (!directory) {
1895 reply_nterror(req, NT_STATUS_NO_MEMORY);
1896 goto out;
1899 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1900 if (!mask) {
1901 goto SearchEmpty;
1904 * For a 'continue' search we have no string. So
1905 * check from the initial saved string.
1907 if (!req->posix_pathnames) {
1908 mask_contains_wcard = ms_has_wild(mask);
1910 dirtype = dptr_attr(sconn, dptr_num);
1913 DEBUG(4,("dptr_num is %d\n",dptr_num));
1915 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1916 char buf[DIR_STRUCT_SIZE];
1917 memcpy(buf,status,21);
1918 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1919 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1920 reply_nterror(req, NT_STATUS_NO_MEMORY);
1921 goto out;
1923 dptr_fill(sconn, buf+12,dptr_num);
1924 if (dptr_zero(buf+12) && (status_len==0)) {
1925 numentries = 1;
1926 } else {
1927 numentries = 0;
1929 if (message_push_blob(&req->outbuf,
1930 data_blob_const(buf, sizeof(buf)))
1931 == -1) {
1932 reply_nterror(req, NT_STATUS_NO_MEMORY);
1933 goto out;
1935 } else {
1936 unsigned int i;
1937 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1938 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1940 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1942 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1943 directory,lp_dont_descend(ctx, SNUM(conn))));
1944 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1945 check_descend = True;
1948 for (i=numentries;(i<maxentries) && !finished;i++) {
1949 finished = !get_dir_entry(ctx,
1950 dirptr,
1951 mask,
1952 dirtype,
1953 &fname,
1954 &size,
1955 &mode,
1956 &date,
1957 check_descend,
1958 ask_sharemode);
1959 if (!finished) {
1960 char buf[DIR_STRUCT_SIZE];
1961 memcpy(buf,status,21);
1962 if (!make_dir_struct(ctx,
1963 buf,
1964 mask,
1965 fname,
1966 size,
1967 mode,
1968 convert_timespec_to_time_t(date),
1969 !allow_long_path_components)) {
1970 reply_nterror(req, NT_STATUS_NO_MEMORY);
1971 goto out;
1973 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1974 break;
1976 if (message_push_blob(&req->outbuf,
1977 data_blob_const(buf, sizeof(buf)))
1978 == -1) {
1979 reply_nterror(req, NT_STATUS_NO_MEMORY);
1980 goto out;
1982 numentries++;
1987 SearchEmpty:
1989 /* If we were called as SMBffirst with smb_search_id == NULL
1990 and no entries were found then return error and close dirptr
1991 (X/Open spec) */
1993 if (numentries == 0) {
1994 dptr_close(sconn, &dptr_num);
1995 } else if(expect_close && status_len == 0) {
1996 /* Close the dptr - we know it's gone */
1997 dptr_close(sconn, &dptr_num);
2000 /* If we were called as SMBfunique, then we can close the dirptr now ! */
2001 if(dptr_num >= 0 && req->cmd == SMBfunique) {
2002 dptr_close(sconn, &dptr_num);
2005 if ((numentries == 0) && !mask_contains_wcard) {
2006 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
2007 goto out;
2010 SSVAL(req->outbuf,smb_vwv0,numentries);
2011 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
2012 SCVAL(smb_buf(req->outbuf),0,5);
2013 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2015 /* The replies here are never long name. */
2016 SSVAL(req->outbuf, smb_flg2,
2017 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2018 if (!allow_long_path_components) {
2019 SSVAL(req->outbuf, smb_flg2,
2020 SVAL(req->outbuf, smb_flg2)
2021 & (~FLAGS2_LONG_PATH_COMPONENTS));
2024 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2025 SSVAL(req->outbuf, smb_flg2,
2026 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2028 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2029 smb_fn_name(req->cmd),
2030 mask,
2031 directory,
2032 dirtype,
2033 numentries,
2034 maxentries ));
2035 out:
2036 TALLOC_FREE(directory);
2037 TALLOC_FREE(mask);
2038 TALLOC_FREE(smb_fname);
2039 END_PROFILE(SMBsearch);
2040 return;
2043 /****************************************************************************
2044 Reply to a fclose (stop directory search).
2045 ****************************************************************************/
2047 void reply_fclose(struct smb_request *req)
2049 int status_len;
2050 char status[21];
2051 int dptr_num= -2;
2052 const char *p;
2053 char *path = NULL;
2054 NTSTATUS err;
2055 bool path_contains_wcard = False;
2056 TALLOC_CTX *ctx = talloc_tos();
2057 struct smbd_server_connection *sconn = req->sconn;
2059 START_PROFILE(SMBfclose);
2061 if (req->posix_pathnames) {
2062 reply_unknown_new(req, req->cmd);
2063 END_PROFILE(SMBfclose);
2064 return;
2067 p = (const char *)req->buf + 1;
2068 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2069 &err, &path_contains_wcard);
2070 if (!NT_STATUS_IS_OK(err)) {
2071 reply_nterror(req, err);
2072 END_PROFILE(SMBfclose);
2073 return;
2075 p++;
2076 status_len = SVAL(p,0);
2077 p += 2;
2079 if (status_len == 0) {
2080 reply_force_doserror(req, ERRSRV, ERRsrverror);
2081 END_PROFILE(SMBfclose);
2082 return;
2085 memcpy(status,p,21);
2087 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2088 /* Close the dptr - we know it's gone */
2089 dptr_close(sconn, &dptr_num);
2092 reply_outbuf(req, 1, 0);
2093 SSVAL(req->outbuf,smb_vwv0,0);
2095 DEBUG(3,("search close\n"));
2097 END_PROFILE(SMBfclose);
2098 return;
2101 /****************************************************************************
2102 Reply to an open.
2103 ****************************************************************************/
2105 void reply_open(struct smb_request *req)
2107 connection_struct *conn = req->conn;
2108 struct smb_filename *smb_fname = NULL;
2109 char *fname = NULL;
2110 uint32_t fattr=0;
2111 off_t size = 0;
2112 time_t mtime=0;
2113 int info;
2114 files_struct *fsp;
2115 int oplock_request;
2116 int deny_mode;
2117 uint32_t dos_attr;
2118 uint32_t access_mask;
2119 uint32_t share_mode;
2120 uint32_t create_disposition;
2121 uint32_t create_options = 0;
2122 uint32_t private_flags = 0;
2123 NTSTATUS status;
2124 uint32_t ucf_flags;
2125 TALLOC_CTX *ctx = talloc_tos();
2127 START_PROFILE(SMBopen);
2129 if (req->wct < 2) {
2130 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2131 goto out;
2134 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2135 deny_mode = SVAL(req->vwv+0, 0);
2136 dos_attr = SVAL(req->vwv+1, 0);
2138 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2139 STR_TERMINATE, &status);
2140 if (!NT_STATUS_IS_OK(status)) {
2141 reply_nterror(req, status);
2142 goto out;
2145 if (!map_open_params_to_ntcreate(fname, deny_mode,
2146 OPENX_FILE_EXISTS_OPEN, &access_mask,
2147 &share_mode, &create_disposition,
2148 &create_options, &private_flags)) {
2149 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2150 goto out;
2153 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2155 status = filename_convert(ctx,
2156 conn,
2157 fname,
2158 ucf_flags,
2159 NULL,
2160 NULL,
2161 &smb_fname);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2164 reply_botherror(req,
2165 NT_STATUS_PATH_NOT_COVERED,
2166 ERRSRV, ERRbadpath);
2167 goto out;
2169 reply_nterror(req, status);
2170 goto out;
2173 status = SMB_VFS_CREATE_FILE(
2174 conn, /* conn */
2175 req, /* req */
2176 0, /* root_dir_fid */
2177 smb_fname, /* fname */
2178 access_mask, /* access_mask */
2179 share_mode, /* share_access */
2180 create_disposition, /* create_disposition*/
2181 create_options, /* create_options */
2182 dos_attr, /* file_attributes */
2183 oplock_request, /* oplock_request */
2184 NULL, /* lease */
2185 0, /* allocation_size */
2186 private_flags,
2187 NULL, /* sd */
2188 NULL, /* ea_list */
2189 &fsp, /* result */
2190 &info, /* pinfo */
2191 NULL, NULL); /* create context */
2193 if (!NT_STATUS_IS_OK(status)) {
2194 if (open_was_deferred(req->xconn, req->mid)) {
2195 /* We have re-scheduled this call. */
2196 goto out;
2198 reply_openerror(req, status);
2199 goto out;
2202 /* Ensure we're pointing at the correct stat struct. */
2203 TALLOC_FREE(smb_fname);
2204 smb_fname = fsp->fsp_name;
2206 size = smb_fname->st.st_ex_size;
2207 fattr = dos_mode(conn, smb_fname);
2209 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2211 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2212 DEBUG(3,("attempt to open a directory %s\n",
2213 fsp_str_dbg(fsp)));
2214 close_file(req, fsp, ERROR_CLOSE);
2215 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2216 ERRDOS, ERRnoaccess);
2217 goto out;
2220 reply_outbuf(req, 7, 0);
2221 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2222 SSVAL(req->outbuf,smb_vwv1,fattr);
2223 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2224 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2225 } else {
2226 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2228 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2229 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2231 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2232 SCVAL(req->outbuf,smb_flg,
2233 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2236 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2237 SCVAL(req->outbuf,smb_flg,
2238 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2240 out:
2241 END_PROFILE(SMBopen);
2242 return;
2245 /****************************************************************************
2246 Reply to an open and X.
2247 ****************************************************************************/
2249 void reply_open_and_X(struct smb_request *req)
2251 connection_struct *conn = req->conn;
2252 struct smb_filename *smb_fname = NULL;
2253 char *fname = NULL;
2254 uint16_t open_flags;
2255 int deny_mode;
2256 uint32_t smb_attr;
2257 /* Breakout the oplock request bits so we can set the
2258 reply bits separately. */
2259 int ex_oplock_request;
2260 int core_oplock_request;
2261 int oplock_request;
2262 #if 0
2263 int smb_sattr = SVAL(req->vwv+4, 0);
2264 uint32_t smb_time = make_unix_date3(req->vwv+6);
2265 #endif
2266 int smb_ofun;
2267 uint32_t fattr=0;
2268 int mtime=0;
2269 int smb_action = 0;
2270 files_struct *fsp;
2271 NTSTATUS status;
2272 uint64_t allocation_size;
2273 ssize_t retval = -1;
2274 uint32_t access_mask;
2275 uint32_t share_mode;
2276 uint32_t create_disposition;
2277 uint32_t create_options = 0;
2278 uint32_t private_flags = 0;
2279 uint32_t ucf_flags;
2280 TALLOC_CTX *ctx = talloc_tos();
2282 START_PROFILE(SMBopenX);
2284 if (req->wct < 15) {
2285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2286 goto out;
2289 open_flags = SVAL(req->vwv+2, 0);
2290 deny_mode = SVAL(req->vwv+3, 0);
2291 smb_attr = SVAL(req->vwv+5, 0);
2292 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2293 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2294 oplock_request = ex_oplock_request | core_oplock_request;
2295 smb_ofun = SVAL(req->vwv+8, 0);
2296 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2298 /* If it's an IPC, pass off the pipe handler. */
2299 if (IS_IPC(conn)) {
2300 if (lp_nt_pipe_support()) {
2301 reply_open_pipe_and_X(conn, req);
2302 } else {
2303 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2305 goto out;
2308 /* XXXX we need to handle passed times, sattr and flags */
2309 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2310 STR_TERMINATE, &status);
2311 if (!NT_STATUS_IS_OK(status)) {
2312 reply_nterror(req, status);
2313 goto out;
2316 if (!map_open_params_to_ntcreate(fname, deny_mode,
2317 smb_ofun,
2318 &access_mask, &share_mode,
2319 &create_disposition,
2320 &create_options,
2321 &private_flags)) {
2322 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2323 goto out;
2326 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2328 status = filename_convert(ctx,
2329 conn,
2330 fname,
2331 ucf_flags,
2332 NULL,
2333 NULL,
2334 &smb_fname);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2337 reply_botherror(req,
2338 NT_STATUS_PATH_NOT_COVERED,
2339 ERRSRV, ERRbadpath);
2340 goto out;
2342 reply_nterror(req, status);
2343 goto out;
2346 status = SMB_VFS_CREATE_FILE(
2347 conn, /* conn */
2348 req, /* req */
2349 0, /* root_dir_fid */
2350 smb_fname, /* fname */
2351 access_mask, /* access_mask */
2352 share_mode, /* share_access */
2353 create_disposition, /* create_disposition*/
2354 create_options, /* create_options */
2355 smb_attr, /* file_attributes */
2356 oplock_request, /* oplock_request */
2357 NULL, /* lease */
2358 0, /* allocation_size */
2359 private_flags,
2360 NULL, /* sd */
2361 NULL, /* ea_list */
2362 &fsp, /* result */
2363 &smb_action, /* pinfo */
2364 NULL, NULL); /* create context */
2366 if (!NT_STATUS_IS_OK(status)) {
2367 if (open_was_deferred(req->xconn, req->mid)) {
2368 /* We have re-scheduled this call. */
2369 goto out;
2371 reply_openerror(req, status);
2372 goto out;
2375 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2376 if the file is truncated or created. */
2377 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2378 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2379 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2380 close_file(req, fsp, ERROR_CLOSE);
2381 reply_nterror(req, NT_STATUS_DISK_FULL);
2382 goto out;
2384 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2385 if (retval < 0) {
2386 close_file(req, fsp, ERROR_CLOSE);
2387 reply_nterror(req, NT_STATUS_DISK_FULL);
2388 goto out;
2390 status = vfs_stat_fsp(fsp);
2391 if (!NT_STATUS_IS_OK(status)) {
2392 close_file(req, fsp, ERROR_CLOSE);
2393 reply_nterror(req, status);
2394 goto out;
2398 fattr = dos_mode(conn, fsp->fsp_name);
2399 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2400 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2401 close_file(req, fsp, ERROR_CLOSE);
2402 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2403 goto out;
2406 /* If the caller set the extended oplock request bit
2407 and we granted one (by whatever means) - set the
2408 correct bit for extended oplock reply.
2411 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2412 smb_action |= EXTENDED_OPLOCK_GRANTED;
2415 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2416 smb_action |= EXTENDED_OPLOCK_GRANTED;
2419 /* If the caller set the core oplock request bit
2420 and we granted one (by whatever means) - set the
2421 correct bit for core oplock reply.
2424 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2425 reply_outbuf(req, 19, 0);
2426 } else {
2427 reply_outbuf(req, 15, 0);
2430 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2431 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2433 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2434 SCVAL(req->outbuf, smb_flg,
2435 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2438 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2439 SCVAL(req->outbuf, smb_flg,
2440 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2443 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2444 SSVAL(req->outbuf,smb_vwv3,fattr);
2445 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2446 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2447 } else {
2448 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2450 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2451 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2452 SSVAL(req->outbuf,smb_vwv11,smb_action);
2454 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2455 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2458 out:
2459 TALLOC_FREE(smb_fname);
2460 END_PROFILE(SMBopenX);
2461 return;
2464 /****************************************************************************
2465 Reply to a SMBulogoffX.
2466 ****************************************************************************/
2468 void reply_ulogoffX(struct smb_request *req)
2470 struct smbd_server_connection *sconn = req->sconn;
2471 struct user_struct *vuser;
2472 struct smbXsrv_session *session = NULL;
2473 NTSTATUS status;
2475 START_PROFILE(SMBulogoffX);
2477 vuser = get_valid_user_struct(sconn, req->vuid);
2479 if(vuser == NULL) {
2480 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2481 (unsigned long long)req->vuid));
2483 req->vuid = UID_FIELD_INVALID;
2484 reply_force_doserror(req, ERRSRV, ERRbaduid);
2485 END_PROFILE(SMBulogoffX);
2486 return;
2489 session = vuser->session;
2490 vuser = NULL;
2493 * TODO: cancel all outstanding requests on the session
2495 status = smbXsrv_session_logoff(session);
2496 if (!NT_STATUS_IS_OK(status)) {
2497 DEBUG(0, ("reply_ulogoff: "
2498 "smbXsrv_session_logoff() failed: %s\n",
2499 nt_errstr(status)));
2501 * If we hit this case, there is something completely
2502 * wrong, so we better disconnect the transport connection.
2504 END_PROFILE(SMBulogoffX);
2505 exit_server(__location__ ": smbXsrv_session_logoff failed");
2506 return;
2509 TALLOC_FREE(session);
2511 reply_outbuf(req, 2, 0);
2512 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2513 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2515 DEBUG(3, ("ulogoffX vuid=%llu\n",
2516 (unsigned long long)req->vuid));
2518 END_PROFILE(SMBulogoffX);
2519 req->vuid = UID_FIELD_INVALID;
2522 /****************************************************************************
2523 Reply to a mknew or a create.
2524 ****************************************************************************/
2526 void reply_mknew(struct smb_request *req)
2528 connection_struct *conn = req->conn;
2529 struct smb_filename *smb_fname = NULL;
2530 char *fname = NULL;
2531 uint32_t fattr = 0;
2532 struct smb_file_time ft;
2533 files_struct *fsp;
2534 int oplock_request = 0;
2535 NTSTATUS status;
2536 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2537 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2538 uint32_t create_disposition;
2539 uint32_t create_options = 0;
2540 uint32_t ucf_flags;
2541 TALLOC_CTX *ctx = talloc_tos();
2543 START_PROFILE(SMBcreate);
2544 ZERO_STRUCT(ft);
2546 if (req->wct < 3) {
2547 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2548 goto out;
2551 fattr = SVAL(req->vwv+0, 0);
2552 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2554 if (req->cmd == SMBmknew) {
2555 /* We should fail if file exists. */
2556 create_disposition = FILE_CREATE;
2557 } else {
2558 /* Create if file doesn't exist, truncate if it does. */
2559 create_disposition = FILE_OVERWRITE_IF;
2562 /* mtime. */
2563 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2565 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2566 STR_TERMINATE, &status);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 reply_nterror(req, status);
2569 goto out;
2572 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2573 status = filename_convert(ctx,
2574 conn,
2575 fname,
2576 ucf_flags,
2577 NULL,
2578 NULL,
2579 &smb_fname);
2580 if (!NT_STATUS_IS_OK(status)) {
2581 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2582 reply_botherror(req,
2583 NT_STATUS_PATH_NOT_COVERED,
2584 ERRSRV, ERRbadpath);
2585 goto out;
2587 reply_nterror(req, status);
2588 goto out;
2591 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2592 DEBUG(0,("Attempt to create file (%s) with volid set - "
2593 "please report this\n",
2594 smb_fname_str_dbg(smb_fname)));
2597 status = SMB_VFS_CREATE_FILE(
2598 conn, /* conn */
2599 req, /* req */
2600 0, /* root_dir_fid */
2601 smb_fname, /* fname */
2602 access_mask, /* access_mask */
2603 share_mode, /* share_access */
2604 create_disposition, /* create_disposition*/
2605 create_options, /* create_options */
2606 fattr, /* file_attributes */
2607 oplock_request, /* oplock_request */
2608 NULL, /* lease */
2609 0, /* allocation_size */
2610 0, /* private_flags */
2611 NULL, /* sd */
2612 NULL, /* ea_list */
2613 &fsp, /* result */
2614 NULL, /* pinfo */
2615 NULL, NULL); /* create context */
2617 if (!NT_STATUS_IS_OK(status)) {
2618 if (open_was_deferred(req->xconn, req->mid)) {
2619 /* We have re-scheduled this call. */
2620 goto out;
2622 reply_openerror(req, status);
2623 goto out;
2626 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2627 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2628 if (!NT_STATUS_IS_OK(status)) {
2629 END_PROFILE(SMBcreate);
2630 goto out;
2633 reply_outbuf(req, 1, 0);
2634 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2636 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2637 SCVAL(req->outbuf,smb_flg,
2638 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2641 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2642 SCVAL(req->outbuf,smb_flg,
2643 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2646 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2647 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2648 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2649 (unsigned int)fattr));
2651 out:
2652 TALLOC_FREE(smb_fname);
2653 END_PROFILE(SMBcreate);
2654 return;
2657 /****************************************************************************
2658 Reply to a create temporary file.
2659 ****************************************************************************/
2661 void reply_ctemp(struct smb_request *req)
2663 connection_struct *conn = req->conn;
2664 struct smb_filename *smb_fname = NULL;
2665 char *wire_name = NULL;
2666 char *fname = NULL;
2667 uint32_t fattr;
2668 files_struct *fsp;
2669 int oplock_request;
2670 char *s;
2671 NTSTATUS status;
2672 int i;
2673 uint32_t ucf_flags;
2674 TALLOC_CTX *ctx = talloc_tos();
2676 START_PROFILE(SMBctemp);
2678 if (req->wct < 3) {
2679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2680 goto out;
2683 fattr = SVAL(req->vwv+0, 0);
2684 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2686 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2687 STR_TERMINATE, &status);
2688 if (!NT_STATUS_IS_OK(status)) {
2689 reply_nterror(req, status);
2690 goto out;
2693 for (i = 0; i < 10; i++) {
2694 if (*wire_name) {
2695 fname = talloc_asprintf(ctx,
2696 "%s/TMP%s",
2697 wire_name,
2698 generate_random_str_list(ctx, 5, "0123456789"));
2699 } else {
2700 fname = talloc_asprintf(ctx,
2701 "TMP%s",
2702 generate_random_str_list(ctx, 5, "0123456789"));
2705 if (!fname) {
2706 reply_nterror(req, NT_STATUS_NO_MEMORY);
2707 goto out;
2710 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2711 status = filename_convert(ctx, conn,
2712 fname,
2713 ucf_flags,
2714 NULL,
2715 NULL,
2716 &smb_fname);
2717 if (!NT_STATUS_IS_OK(status)) {
2718 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2719 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2720 ERRSRV, ERRbadpath);
2721 goto out;
2723 reply_nterror(req, status);
2724 goto out;
2727 /* Create the file. */
2728 status = SMB_VFS_CREATE_FILE(
2729 conn, /* conn */
2730 req, /* req */
2731 0, /* root_dir_fid */
2732 smb_fname, /* fname */
2733 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2734 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2735 FILE_CREATE, /* create_disposition*/
2736 0, /* create_options */
2737 fattr, /* file_attributes */
2738 oplock_request, /* oplock_request */
2739 NULL, /* lease */
2740 0, /* allocation_size */
2741 0, /* private_flags */
2742 NULL, /* sd */
2743 NULL, /* ea_list */
2744 &fsp, /* result */
2745 NULL, /* pinfo */
2746 NULL, NULL); /* create context */
2748 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2749 TALLOC_FREE(fname);
2750 TALLOC_FREE(smb_fname);
2751 continue;
2754 if (!NT_STATUS_IS_OK(status)) {
2755 if (open_was_deferred(req->xconn, req->mid)) {
2756 /* We have re-scheduled this call. */
2757 goto out;
2759 reply_openerror(req, status);
2760 goto out;
2763 break;
2766 if (i == 10) {
2767 /* Collision after 10 times... */
2768 reply_nterror(req, status);
2769 goto out;
2772 reply_outbuf(req, 1, 0);
2773 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2775 /* the returned filename is relative to the directory */
2776 s = strrchr_m(fsp->fsp_name->base_name, '/');
2777 if (!s) {
2778 s = fsp->fsp_name->base_name;
2779 } else {
2780 s++;
2783 #if 0
2784 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2785 thing in the byte section. JRA */
2786 SSVALS(p, 0, -1); /* what is this? not in spec */
2787 #endif
2788 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2789 == -1) {
2790 reply_nterror(req, NT_STATUS_NO_MEMORY);
2791 goto out;
2794 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2795 SCVAL(req->outbuf, smb_flg,
2796 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2799 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2800 SCVAL(req->outbuf, smb_flg,
2801 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2804 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2805 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2806 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2807 out:
2808 TALLOC_FREE(smb_fname);
2809 TALLOC_FREE(wire_name);
2810 END_PROFILE(SMBctemp);
2811 return;
2814 /*******************************************************************
2815 Check if a user is allowed to rename a file.
2816 ********************************************************************/
2818 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2819 uint16_t dirtype)
2821 if (!CAN_WRITE(conn)) {
2822 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2825 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2826 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2827 /* Only bother to read the DOS attribute if we might deny the
2828 rename on the grounds of attribute mismatch. */
2829 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2830 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2831 return NT_STATUS_NO_SUCH_FILE;
2835 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2836 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2837 return NT_STATUS_OK;
2840 /* If no pathnames are open below this
2841 directory, allow the rename. */
2843 if (lp_strict_rename(SNUM(conn))) {
2845 * Strict rename, check open file db.
2847 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2848 return NT_STATUS_ACCESS_DENIED;
2850 } else if (file_find_subpath(fsp)) {
2852 * No strict rename, just look in local process.
2854 return NT_STATUS_ACCESS_DENIED;
2856 return NT_STATUS_OK;
2859 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2860 return NT_STATUS_OK;
2863 return NT_STATUS_ACCESS_DENIED;
2866 /*******************************************************************
2867 * unlink a file with all relevant access checks
2868 *******************************************************************/
2870 static NTSTATUS do_unlink(connection_struct *conn,
2871 struct smb_request *req,
2872 struct smb_filename *smb_fname,
2873 uint32_t dirtype)
2875 uint32_t fattr;
2876 files_struct *fsp;
2877 uint32_t dirtype_orig = dirtype;
2878 NTSTATUS status;
2879 int ret;
2880 bool posix_paths = (req != NULL && req->posix_pathnames);
2882 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2883 smb_fname_str_dbg(smb_fname),
2884 dirtype));
2886 if (!CAN_WRITE(conn)) {
2887 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2890 if (posix_paths) {
2891 ret = SMB_VFS_LSTAT(conn, smb_fname);
2892 } else {
2893 ret = SMB_VFS_STAT(conn, smb_fname);
2895 if (ret != 0) {
2896 return map_nt_error_from_unix(errno);
2899 fattr = dos_mode(conn, smb_fname);
2901 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2902 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2905 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2906 if (!dirtype) {
2907 return NT_STATUS_NO_SUCH_FILE;
2910 if (!dir_check_ftype(fattr, dirtype)) {
2911 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2912 return NT_STATUS_FILE_IS_A_DIRECTORY;
2914 return NT_STATUS_NO_SUCH_FILE;
2917 if (dirtype_orig & 0x8000) {
2918 /* These will never be set for POSIX. */
2919 return NT_STATUS_NO_SUCH_FILE;
2922 #if 0
2923 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2924 return NT_STATUS_FILE_IS_A_DIRECTORY;
2927 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2928 return NT_STATUS_NO_SUCH_FILE;
2931 if (dirtype & 0xFF00) {
2932 /* These will never be set for POSIX. */
2933 return NT_STATUS_NO_SUCH_FILE;
2936 dirtype &= 0xFF;
2937 if (!dirtype) {
2938 return NT_STATUS_NO_SUCH_FILE;
2941 /* Can't delete a directory. */
2942 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2943 return NT_STATUS_FILE_IS_A_DIRECTORY;
2945 #endif
2947 #if 0 /* JRATEST */
2948 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2949 return NT_STATUS_OBJECT_NAME_INVALID;
2950 #endif /* JRATEST */
2952 /* On open checks the open itself will check the share mode, so
2953 don't do it here as we'll get it wrong. */
2955 status = SMB_VFS_CREATE_FILE
2956 (conn, /* conn */
2957 req, /* req */
2958 0, /* root_dir_fid */
2959 smb_fname, /* fname */
2960 DELETE_ACCESS, /* access_mask */
2961 FILE_SHARE_NONE, /* share_access */
2962 FILE_OPEN, /* create_disposition*/
2963 FILE_NON_DIRECTORY_FILE, /* create_options */
2964 /* file_attributes */
2965 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2966 FILE_ATTRIBUTE_NORMAL,
2967 0, /* oplock_request */
2968 NULL, /* lease */
2969 0, /* allocation_size */
2970 0, /* private_flags */
2971 NULL, /* sd */
2972 NULL, /* ea_list */
2973 &fsp, /* result */
2974 NULL, /* pinfo */
2975 NULL, NULL); /* create context */
2977 if (!NT_STATUS_IS_OK(status)) {
2978 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2979 nt_errstr(status)));
2980 return status;
2983 status = can_set_delete_on_close(fsp, fattr);
2984 if (!NT_STATUS_IS_OK(status)) {
2985 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2986 "(%s)\n",
2987 smb_fname_str_dbg(smb_fname),
2988 nt_errstr(status)));
2989 close_file(req, fsp, NORMAL_CLOSE);
2990 return status;
2993 /* The set is across all open files on this dev/inode pair. */
2994 if (!set_delete_on_close(fsp, True,
2995 conn->session_info->security_token,
2996 conn->session_info->unix_token)) {
2997 close_file(req, fsp, NORMAL_CLOSE);
2998 return NT_STATUS_ACCESS_DENIED;
3001 return close_file(req, fsp, NORMAL_CLOSE);
3004 /****************************************************************************
3005 The guts of the unlink command, split out so it may be called by the NT SMB
3006 code.
3007 ****************************************************************************/
3009 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
3010 uint32_t dirtype, struct smb_filename *smb_fname,
3011 bool has_wild)
3013 char *fname_dir = NULL;
3014 char *fname_mask = NULL;
3015 int count=0;
3016 NTSTATUS status = NT_STATUS_OK;
3017 struct smb_filename *smb_fname_dir = NULL;
3018 TALLOC_CTX *ctx = talloc_tos();
3020 /* Split up the directory from the filename/mask. */
3021 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3022 &fname_dir, &fname_mask);
3023 if (!NT_STATUS_IS_OK(status)) {
3024 goto out;
3028 * We should only check the mangled cache
3029 * here if unix_convert failed. This means
3030 * that the path in 'mask' doesn't exist
3031 * on the file system and so we need to look
3032 * for a possible mangle. This patch from
3033 * Tine Smukavec <valentin.smukavec@hermes.si>.
3036 if (!VALID_STAT(smb_fname->st) &&
3037 mangle_is_mangled(fname_mask, conn->params)) {
3038 char *new_mask = NULL;
3039 mangle_lookup_name_from_8_3(ctx, fname_mask,
3040 &new_mask, conn->params);
3041 if (new_mask) {
3042 TALLOC_FREE(fname_mask);
3043 fname_mask = new_mask;
3047 if (!has_wild) {
3050 * Only one file needs to be unlinked. Append the mask back
3051 * onto the directory.
3053 TALLOC_FREE(smb_fname->base_name);
3054 if (ISDOT(fname_dir)) {
3055 /* Ensure we use canonical names on open. */
3056 smb_fname->base_name = talloc_asprintf(smb_fname,
3057 "%s",
3058 fname_mask);
3059 } else {
3060 smb_fname->base_name = talloc_asprintf(smb_fname,
3061 "%s/%s",
3062 fname_dir,
3063 fname_mask);
3065 if (!smb_fname->base_name) {
3066 status = NT_STATUS_NO_MEMORY;
3067 goto out;
3069 if (dirtype == 0) {
3070 dirtype = FILE_ATTRIBUTE_NORMAL;
3073 status = check_name(conn, smb_fname);
3074 if (!NT_STATUS_IS_OK(status)) {
3075 goto out;
3078 status = do_unlink(conn, req, smb_fname, dirtype);
3079 if (!NT_STATUS_IS_OK(status)) {
3080 goto out;
3083 count++;
3084 } else {
3085 struct smb_Dir *dir_hnd = NULL;
3086 long offset = 0;
3087 const char *dname = NULL;
3088 char *talloced = NULL;
3090 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3091 status = NT_STATUS_OBJECT_NAME_INVALID;
3092 goto out;
3094 if (dirtype == 0) {
3095 dirtype = FILE_ATTRIBUTE_NORMAL;
3098 if (strequal(fname_mask,"????????.???")) {
3099 TALLOC_FREE(fname_mask);
3100 fname_mask = talloc_strdup(ctx, "*");
3101 if (!fname_mask) {
3102 status = NT_STATUS_NO_MEMORY;
3103 goto out;
3107 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3108 fname_dir,
3109 NULL,
3110 NULL,
3111 smb_fname->flags);
3112 if (smb_fname_dir == NULL) {
3113 status = NT_STATUS_NO_MEMORY;
3114 goto out;
3117 status = check_name(conn, smb_fname_dir);
3118 if (!NT_STATUS_IS_OK(status)) {
3119 goto out;
3122 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3123 dirtype);
3124 if (dir_hnd == NULL) {
3125 status = map_nt_error_from_unix(errno);
3126 goto out;
3129 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3130 the pattern matches against the long name, otherwise the short name
3131 We don't implement this yet XXXX
3134 status = NT_STATUS_NO_SUCH_FILE;
3136 while ((dname = ReadDirName(dir_hnd, &offset,
3137 &smb_fname->st, &talloced))) {
3138 TALLOC_CTX *frame = talloc_stackframe();
3140 if (!is_visible_file(conn, fname_dir, dname,
3141 &smb_fname->st, true)) {
3142 TALLOC_FREE(frame);
3143 TALLOC_FREE(talloced);
3144 continue;
3147 /* Quick check for "." and ".." */
3148 if (ISDOT(dname) || ISDOTDOT(dname)) {
3149 TALLOC_FREE(frame);
3150 TALLOC_FREE(talloced);
3151 continue;
3154 if(!mask_match(dname, fname_mask,
3155 conn->case_sensitive)) {
3156 TALLOC_FREE(frame);
3157 TALLOC_FREE(talloced);
3158 continue;
3161 TALLOC_FREE(smb_fname->base_name);
3162 if (ISDOT(fname_dir)) {
3163 /* Ensure we use canonical names on open. */
3164 smb_fname->base_name =
3165 talloc_asprintf(smb_fname, "%s",
3166 dname);
3167 } else {
3168 smb_fname->base_name =
3169 talloc_asprintf(smb_fname, "%s/%s",
3170 fname_dir, dname);
3173 if (!smb_fname->base_name) {
3174 TALLOC_FREE(dir_hnd);
3175 status = NT_STATUS_NO_MEMORY;
3176 TALLOC_FREE(frame);
3177 TALLOC_FREE(talloced);
3178 goto out;
3181 status = check_name(conn, smb_fname);
3182 if (!NT_STATUS_IS_OK(status)) {
3183 TALLOC_FREE(dir_hnd);
3184 TALLOC_FREE(frame);
3185 TALLOC_FREE(talloced);
3186 goto out;
3189 status = do_unlink(conn, req, smb_fname, dirtype);
3190 if (!NT_STATUS_IS_OK(status)) {
3191 TALLOC_FREE(dir_hnd);
3192 TALLOC_FREE(frame);
3193 TALLOC_FREE(talloced);
3194 goto out;
3197 count++;
3198 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3199 smb_fname->base_name));
3201 TALLOC_FREE(frame);
3202 TALLOC_FREE(talloced);
3204 TALLOC_FREE(dir_hnd);
3207 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3208 status = map_nt_error_from_unix(errno);
3211 out:
3212 TALLOC_FREE(smb_fname_dir);
3213 TALLOC_FREE(fname_dir);
3214 TALLOC_FREE(fname_mask);
3215 return status;
3218 /****************************************************************************
3219 Reply to a unlink
3220 ****************************************************************************/
3222 void reply_unlink(struct smb_request *req)
3224 connection_struct *conn = req->conn;
3225 char *name = NULL;
3226 struct smb_filename *smb_fname = NULL;
3227 uint32_t dirtype;
3228 NTSTATUS status;
3229 bool path_contains_wcard = False;
3230 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3231 ucf_flags_from_smb_request(req);
3232 TALLOC_CTX *ctx = talloc_tos();
3234 START_PROFILE(SMBunlink);
3236 if (req->wct < 1) {
3237 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3238 goto out;
3241 dirtype = SVAL(req->vwv+0, 0);
3243 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3244 STR_TERMINATE, &status,
3245 &path_contains_wcard);
3246 if (!NT_STATUS_IS_OK(status)) {
3247 reply_nterror(req, status);
3248 goto out;
3251 status = filename_convert(ctx, conn,
3252 name,
3253 ucf_flags,
3254 NULL,
3255 &path_contains_wcard,
3256 &smb_fname);
3257 if (!NT_STATUS_IS_OK(status)) {
3258 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3259 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3260 ERRSRV, ERRbadpath);
3261 goto out;
3263 reply_nterror(req, status);
3264 goto out;
3267 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3269 status = unlink_internals(conn, req, dirtype, smb_fname,
3270 path_contains_wcard);
3271 if (!NT_STATUS_IS_OK(status)) {
3272 if (open_was_deferred(req->xconn, req->mid)) {
3273 /* We have re-scheduled this call. */
3274 goto out;
3276 reply_nterror(req, status);
3277 goto out;
3280 reply_outbuf(req, 0, 0);
3281 out:
3282 TALLOC_FREE(smb_fname);
3283 END_PROFILE(SMBunlink);
3284 return;
3287 /****************************************************************************
3288 Fail for readbraw.
3289 ****************************************************************************/
3291 static void fail_readraw(void)
3293 const char *errstr = talloc_asprintf(talloc_tos(),
3294 "FAIL ! reply_readbraw: socket write fail (%s)",
3295 strerror(errno));
3296 if (!errstr) {
3297 errstr = "";
3299 exit_server_cleanly(errstr);
3302 /****************************************************************************
3303 Fake (read/write) sendfile. Returns -1 on read or write fail.
3304 ****************************************************************************/
3306 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3307 off_t startpos, size_t nread)
3309 size_t bufsize;
3310 size_t tosend = nread;
3311 char *buf;
3313 if (nread == 0) {
3314 return 0;
3317 bufsize = MIN(nread, 65536);
3319 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3320 return -1;
3323 while (tosend > 0) {
3324 ssize_t ret;
3325 size_t cur_read;
3327 cur_read = MIN(tosend, bufsize);
3328 ret = read_file(fsp,buf,startpos,cur_read);
3329 if (ret == -1) {
3330 SAFE_FREE(buf);
3331 return -1;
3334 /* If we had a short read, fill with zeros. */
3335 if (ret < cur_read) {
3336 memset(buf + ret, '\0', cur_read - ret);
3339 ret = write_data(xconn->transport.sock, buf, cur_read);
3340 if (ret != cur_read) {
3341 int saved_errno = errno;
3343 * Try and give an error message saying what
3344 * client failed.
3346 DEBUG(0, ("write_data failed for client %s. "
3347 "Error %s\n",
3348 smbXsrv_connection_dbg(xconn),
3349 strerror(saved_errno)));
3350 SAFE_FREE(buf);
3351 errno = saved_errno;
3352 return -1;
3354 tosend -= cur_read;
3355 startpos += cur_read;
3358 SAFE_FREE(buf);
3359 return (ssize_t)nread;
3362 /****************************************************************************
3363 Deal with the case of sendfile reading less bytes from the file than
3364 requested. Fill with zeros (all we can do). Returns 0 on success
3365 ****************************************************************************/
3367 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3368 files_struct *fsp,
3369 ssize_t nread,
3370 size_t headersize,
3371 size_t smb_maxcnt)
3373 #define SHORT_SEND_BUFSIZE 1024
3374 if (nread < headersize) {
3375 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3376 "header for file %s (%s). Terminating\n",
3377 fsp_str_dbg(fsp), strerror(errno)));
3378 return -1;
3381 nread -= headersize;
3383 if (nread < smb_maxcnt) {
3384 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3385 if (!buf) {
3386 DEBUG(0,("sendfile_short_send: malloc failed "
3387 "for file %s (%s). Terminating\n",
3388 fsp_str_dbg(fsp), strerror(errno)));
3389 return -1;
3392 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3393 "with zeros !\n", fsp_str_dbg(fsp)));
3395 while (nread < smb_maxcnt) {
3397 * We asked for the real file size and told sendfile
3398 * to not go beyond the end of the file. But it can
3399 * happen that in between our fstat call and the
3400 * sendfile call the file was truncated. This is very
3401 * bad because we have already announced the larger
3402 * number of bytes to the client.
3404 * The best we can do now is to send 0-bytes, just as
3405 * a read from a hole in a sparse file would do.
3407 * This should happen rarely enough that I don't care
3408 * about efficiency here :-)
3410 size_t to_write;
3411 ssize_t ret;
3413 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3414 ret = write_data(xconn->transport.sock, buf, to_write);
3415 if (ret != to_write) {
3416 int saved_errno = errno;
3418 * Try and give an error message saying what
3419 * client failed.
3421 DEBUG(0, ("write_data failed for client %s. "
3422 "Error %s\n",
3423 smbXsrv_connection_dbg(xconn),
3424 strerror(saved_errno)));
3425 errno = saved_errno;
3426 return -1;
3428 nread += to_write;
3430 SAFE_FREE(buf);
3433 return 0;
3436 /****************************************************************************
3437 Return a readbraw error (4 bytes of zero).
3438 ****************************************************************************/
3440 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3442 char header[4];
3444 SIVAL(header,0,0);
3446 smbd_lock_socket(xconn);
3447 if (write_data(xconn->transport.sock,header,4) != 4) {
3448 int saved_errno = errno;
3450 * Try and give an error message saying what
3451 * client failed.
3453 DEBUG(0, ("write_data failed for client %s. "
3454 "Error %s\n",
3455 smbXsrv_connection_dbg(xconn),
3456 strerror(saved_errno)));
3457 errno = saved_errno;
3459 fail_readraw();
3461 smbd_unlock_socket(xconn);
3464 /****************************************************************************
3465 Use sendfile in readbraw.
3466 ****************************************************************************/
3468 static void send_file_readbraw(connection_struct *conn,
3469 struct smb_request *req,
3470 files_struct *fsp,
3471 off_t startpos,
3472 size_t nread,
3473 ssize_t mincount)
3475 struct smbXsrv_connection *xconn = req->xconn;
3476 char *outbuf = NULL;
3477 ssize_t ret=0;
3480 * We can only use sendfile on a non-chained packet
3481 * but we can use on a non-oplocked file. tridge proved this
3482 * on a train in Germany :-). JRA.
3483 * reply_readbraw has already checked the length.
3486 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3487 (fsp->wcp == NULL) &&
3488 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3489 ssize_t sendfile_read = -1;
3490 char header[4];
3491 DATA_BLOB header_blob;
3493 _smb_setlen(header,nread);
3494 header_blob = data_blob_const(header, 4);
3496 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3497 &header_blob, startpos,
3498 nread);
3499 if (sendfile_read == -1) {
3500 /* Returning ENOSYS means no data at all was sent.
3501 * Do this as a normal read. */
3502 if (errno == ENOSYS) {
3503 goto normal_readbraw;
3507 * Special hack for broken Linux with no working sendfile. If we
3508 * return EINTR we sent the header but not the rest of the data.
3509 * Fake this up by doing read/write calls.
3511 if (errno == EINTR) {
3512 /* Ensure we don't do this again. */
3513 set_use_sendfile(SNUM(conn), False);
3514 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3516 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3517 DEBUG(0,("send_file_readbraw: "
3518 "fake_sendfile failed for "
3519 "file %s (%s).\n",
3520 fsp_str_dbg(fsp),
3521 strerror(errno)));
3522 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3524 return;
3527 DEBUG(0,("send_file_readbraw: sendfile failed for "
3528 "file %s (%s). Terminating\n",
3529 fsp_str_dbg(fsp), strerror(errno)));
3530 exit_server_cleanly("send_file_readbraw sendfile failed");
3531 } else if (sendfile_read == 0) {
3533 * Some sendfile implementations return 0 to indicate
3534 * that there was a short read, but nothing was
3535 * actually written to the socket. In this case,
3536 * fallback to the normal read path so the header gets
3537 * the correct byte count.
3539 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3540 "bytes falling back to the normal read: "
3541 "%s\n", fsp_str_dbg(fsp)));
3542 goto normal_readbraw;
3545 /* Deal with possible short send. */
3546 if (sendfile_read != 4+nread) {
3547 ret = sendfile_short_send(xconn, fsp,
3548 sendfile_read, 4, nread);
3549 if (ret == -1) {
3550 fail_readraw();
3553 return;
3556 normal_readbraw:
3558 outbuf = talloc_array(NULL, char, nread+4);
3559 if (!outbuf) {
3560 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3561 (unsigned)(nread+4)));
3562 reply_readbraw_error(xconn);
3563 return;
3566 if (nread > 0) {
3567 ret = read_file(fsp,outbuf+4,startpos,nread);
3568 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3569 if (ret < mincount)
3570 ret = 0;
3571 #else
3572 if (ret < nread)
3573 ret = 0;
3574 #endif
3577 _smb_setlen(outbuf,ret);
3578 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3579 int saved_errno = errno;
3581 * Try and give an error message saying what
3582 * client failed.
3584 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3585 smbXsrv_connection_dbg(xconn),
3586 strerror(saved_errno)));
3587 errno = saved_errno;
3589 fail_readraw();
3592 TALLOC_FREE(outbuf);
3595 /****************************************************************************
3596 Reply to a readbraw (core+ protocol).
3597 ****************************************************************************/
3599 void reply_readbraw(struct smb_request *req)
3601 connection_struct *conn = req->conn;
3602 struct smbXsrv_connection *xconn = req->xconn;
3603 ssize_t maxcount,mincount;
3604 size_t nread = 0;
3605 off_t startpos;
3606 files_struct *fsp;
3607 struct lock_struct lock;
3608 off_t size = 0;
3610 START_PROFILE(SMBreadbraw);
3612 if (srv_is_signing_active(xconn) || req->encrypted) {
3613 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3614 "raw reads/writes are disallowed.");
3617 if (req->wct < 8) {
3618 reply_readbraw_error(xconn);
3619 END_PROFILE(SMBreadbraw);
3620 return;
3623 if (xconn->smb1.echo_handler.trusted_fde) {
3624 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3625 "'async smb echo handler = yes'\n"));
3626 reply_readbraw_error(xconn);
3627 END_PROFILE(SMBreadbraw);
3628 return;
3632 * Special check if an oplock break has been issued
3633 * and the readraw request croses on the wire, we must
3634 * return a zero length response here.
3637 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3640 * We have to do a check_fsp by hand here, as
3641 * we must always return 4 zero bytes on error,
3642 * not a NTSTATUS.
3645 if (!fsp || !conn || conn != fsp->conn ||
3646 req->vuid != fsp->vuid ||
3647 fsp->is_directory || fsp->fh->fd == -1) {
3649 * fsp could be NULL here so use the value from the packet. JRA.
3651 DEBUG(3,("reply_readbraw: fnum %d not valid "
3652 "- cache prime?\n",
3653 (int)SVAL(req->vwv+0, 0)));
3654 reply_readbraw_error(xconn);
3655 END_PROFILE(SMBreadbraw);
3656 return;
3659 /* Do a "by hand" version of CHECK_READ. */
3660 if (!(fsp->can_read ||
3661 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3662 (fsp->access_mask & FILE_EXECUTE)))) {
3663 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3664 (int)SVAL(req->vwv+0, 0)));
3665 reply_readbraw_error(xconn);
3666 END_PROFILE(SMBreadbraw);
3667 return;
3670 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3672 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3673 if(req->wct == 10) {
3675 * This is a large offset (64 bit) read.
3678 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3680 if(startpos < 0) {
3681 DEBUG(0,("reply_readbraw: negative 64 bit "
3682 "readraw offset (%.0f) !\n",
3683 (double)startpos ));
3684 reply_readbraw_error(xconn);
3685 END_PROFILE(SMBreadbraw);
3686 return;
3690 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3691 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3693 /* ensure we don't overrun the packet size */
3694 maxcount = MIN(65535,maxcount);
3696 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3697 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3698 &lock);
3700 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3701 reply_readbraw_error(xconn);
3702 END_PROFILE(SMBreadbraw);
3703 return;
3706 if (fsp_stat(fsp) == 0) {
3707 size = fsp->fsp_name->st.st_ex_size;
3710 if (startpos >= size) {
3711 nread = 0;
3712 } else {
3713 nread = MIN(maxcount,(size - startpos));
3716 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3717 if (nread < mincount)
3718 nread = 0;
3719 #endif
3721 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3722 "min=%lu nread=%lu\n",
3723 fsp_fnum_dbg(fsp), (double)startpos,
3724 (unsigned long)maxcount,
3725 (unsigned long)mincount,
3726 (unsigned long)nread ) );
3728 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3730 DEBUG(5,("reply_readbraw finished\n"));
3732 END_PROFILE(SMBreadbraw);
3733 return;
3736 #undef DBGC_CLASS
3737 #define DBGC_CLASS DBGC_LOCKING
3739 /****************************************************************************
3740 Reply to a lockread (core+ protocol).
3741 ****************************************************************************/
3743 void reply_lockread(struct smb_request *req)
3745 connection_struct *conn = req->conn;
3746 ssize_t nread = -1;
3747 char *data;
3748 off_t startpos;
3749 size_t numtoread;
3750 size_t maxtoread;
3751 NTSTATUS status;
3752 files_struct *fsp;
3753 struct byte_range_lock *br_lck = NULL;
3754 char *p = NULL;
3755 struct smbXsrv_connection *xconn = req->xconn;
3757 START_PROFILE(SMBlockread);
3759 if (req->wct < 5) {
3760 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3761 END_PROFILE(SMBlockread);
3762 return;
3765 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3767 if (!check_fsp(conn, req, fsp)) {
3768 END_PROFILE(SMBlockread);
3769 return;
3772 if (!CHECK_READ(fsp,req)) {
3773 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3774 END_PROFILE(SMBlockread);
3775 return;
3778 numtoread = SVAL(req->vwv+1, 0);
3779 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3782 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3783 * protocol request that predates the read/write lock concept.
3784 * Thus instead of asking for a read lock here we need to ask
3785 * for a write lock. JRA.
3786 * Note that the requested lock size is unaffected by max_send.
3789 br_lck = do_lock(req->sconn->msg_ctx,
3790 fsp,
3791 (uint64_t)req->smbpid,
3792 (uint64_t)numtoread,
3793 (uint64_t)startpos,
3794 WRITE_LOCK,
3795 WINDOWS_LOCK,
3796 False, /* Non-blocking lock. */
3797 &status,
3798 NULL);
3799 TALLOC_FREE(br_lck);
3801 if (NT_STATUS_V(status)) {
3802 reply_nterror(req, status);
3803 END_PROFILE(SMBlockread);
3804 return;
3808 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3810 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3812 if (numtoread > maxtoread) {
3813 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3814 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3815 (unsigned int)numtoread, (unsigned int)maxtoread,
3816 (unsigned int)xconn->smb1.sessions.max_send));
3817 numtoread = maxtoread;
3820 reply_outbuf(req, 5, numtoread + 3);
3822 data = smb_buf(req->outbuf) + 3;
3824 nread = read_file(fsp,data,startpos,numtoread);
3826 if (nread < 0) {
3827 reply_nterror(req, map_nt_error_from_unix(errno));
3828 END_PROFILE(SMBlockread);
3829 return;
3832 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3834 SSVAL(req->outbuf,smb_vwv0,nread);
3835 SSVAL(req->outbuf,smb_vwv5,nread+3);
3836 p = smb_buf(req->outbuf);
3837 SCVAL(p,0,0); /* pad byte. */
3838 SSVAL(p,1,nread);
3840 DEBUG(3,("lockread %s num=%d nread=%d\n",
3841 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3843 END_PROFILE(SMBlockread);
3844 return;
3847 #undef DBGC_CLASS
3848 #define DBGC_CLASS DBGC_ALL
3850 /****************************************************************************
3851 Reply to a read.
3852 ****************************************************************************/
3854 void reply_read(struct smb_request *req)
3856 connection_struct *conn = req->conn;
3857 size_t numtoread;
3858 size_t maxtoread;
3859 ssize_t nread = 0;
3860 char *data;
3861 off_t startpos;
3862 files_struct *fsp;
3863 struct lock_struct lock;
3864 struct smbXsrv_connection *xconn = req->xconn;
3866 START_PROFILE(SMBread);
3868 if (req->wct < 3) {
3869 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3870 END_PROFILE(SMBread);
3871 return;
3874 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3876 if (!check_fsp(conn, req, fsp)) {
3877 END_PROFILE(SMBread);
3878 return;
3881 if (!CHECK_READ(fsp,req)) {
3882 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3883 END_PROFILE(SMBread);
3884 return;
3887 numtoread = SVAL(req->vwv+1, 0);
3888 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3891 * The requested read size cannot be greater than max_send. JRA.
3893 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3895 if (numtoread > maxtoread) {
3896 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3897 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3898 (unsigned int)numtoread, (unsigned int)maxtoread,
3899 (unsigned int)xconn->smb1.sessions.max_send));
3900 numtoread = maxtoread;
3903 reply_outbuf(req, 5, numtoread+3);
3905 data = smb_buf(req->outbuf) + 3;
3907 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3908 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3909 &lock);
3911 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3912 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3913 END_PROFILE(SMBread);
3914 return;
3917 if (numtoread > 0)
3918 nread = read_file(fsp,data,startpos,numtoread);
3920 if (nread < 0) {
3921 reply_nterror(req, map_nt_error_from_unix(errno));
3922 goto out;
3925 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3927 SSVAL(req->outbuf,smb_vwv0,nread);
3928 SSVAL(req->outbuf,smb_vwv5,nread+3);
3929 SCVAL(smb_buf(req->outbuf),0,1);
3930 SSVAL(smb_buf(req->outbuf),1,nread);
3932 DEBUG(3, ("read %s num=%d nread=%d\n",
3933 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3935 out:
3936 END_PROFILE(SMBread);
3937 return;
3940 /****************************************************************************
3941 Setup readX header.
3942 ****************************************************************************/
3944 size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
3946 size_t outsize;
3948 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3949 False);
3951 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3953 SCVAL(outbuf,smb_vwv0,0xFF);
3954 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3955 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3956 SSVAL(outbuf,smb_vwv6,
3957 (smb_wct - 4) /* offset from smb header to wct */
3958 + 1 /* the wct field */
3959 + 12 * sizeof(uint16_t) /* vwv */
3960 + 2 /* the buflen field */
3961 + 1); /* padding byte */
3962 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3963 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3964 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3965 _smb_setlen_large(outbuf,
3966 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3967 return outsize;
3970 /****************************************************************************
3971 Reply to a read and X - possibly using sendfile.
3972 ****************************************************************************/
3974 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3975 files_struct *fsp, off_t startpos,
3976 size_t smb_maxcnt)
3978 struct smbXsrv_connection *xconn = req->xconn;
3979 ssize_t nread = -1;
3980 struct lock_struct lock;
3981 int saved_errno = 0;
3983 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3984 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3985 &lock);
3987 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3988 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3989 return;
3993 * We can only use sendfile on a non-chained packet
3994 * but we can use on a non-oplocked file. tridge proved this
3995 * on a train in Germany :-). JRA.
3998 if (!req_is_in_chain(req) &&
3999 !req->encrypted &&
4000 (fsp->base_fsp == NULL) &&
4001 (fsp->wcp == NULL) &&
4002 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
4003 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
4004 DATA_BLOB header;
4006 if(fsp_stat(fsp) == -1) {
4007 reply_nterror(req, map_nt_error_from_unix(errno));
4008 goto out;
4011 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4012 (startpos > fsp->fsp_name->st.st_ex_size) ||
4013 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4015 * We already know that we would do a short read, so don't
4016 * try the sendfile() path.
4018 goto nosendfile_read;
4022 * Set up the packet header before send. We
4023 * assume here the sendfile will work (get the
4024 * correct amount of data).
4027 header = data_blob_const(headerbuf, sizeof(headerbuf));
4029 construct_reply_common_req(req, (char *)headerbuf);
4030 setup_readX_header((char *)headerbuf, smb_maxcnt);
4032 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4033 startpos, smb_maxcnt);
4034 if (nread == -1) {
4035 saved_errno = errno;
4037 /* Returning ENOSYS means no data at all was sent.
4038 Do this as a normal read. */
4039 if (errno == ENOSYS) {
4040 goto normal_read;
4044 * Special hack for broken Linux with no working sendfile. If we
4045 * return EINTR we sent the header but not the rest of the data.
4046 * Fake this up by doing read/write calls.
4049 if (errno == EINTR) {
4050 /* Ensure we don't do this again. */
4051 set_use_sendfile(SNUM(conn), False);
4052 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4053 nread = fake_sendfile(xconn, fsp, startpos,
4054 smb_maxcnt);
4055 if (nread == -1) {
4056 saved_errno = errno;
4057 DEBUG(0,("send_file_readX: "
4058 "fake_sendfile failed for "
4059 "file %s (%s) for client %s. "
4060 "Terminating\n",
4061 fsp_str_dbg(fsp),
4062 smbXsrv_connection_dbg(xconn),
4063 strerror(saved_errno)));
4064 errno = saved_errno;
4065 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4067 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4068 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4069 /* No outbuf here means successful sendfile. */
4070 goto out;
4073 DEBUG(0,("send_file_readX: sendfile failed for file "
4074 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4075 strerror(errno)));
4076 exit_server_cleanly("send_file_readX sendfile failed");
4077 } else if (nread == 0) {
4079 * Some sendfile implementations return 0 to indicate
4080 * that there was a short read, but nothing was
4081 * actually written to the socket. In this case,
4082 * fallback to the normal read path so the header gets
4083 * the correct byte count.
4085 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4086 "falling back to the normal read: %s\n",
4087 fsp_str_dbg(fsp)));
4088 goto normal_read;
4091 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4092 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4094 /* Deal with possible short send. */
4095 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4096 ssize_t ret;
4098 ret = sendfile_short_send(xconn, fsp, nread,
4099 sizeof(headerbuf), smb_maxcnt);
4100 if (ret == -1) {
4101 const char *r;
4102 r = "send_file_readX: sendfile_short_send failed";
4103 DEBUG(0,("%s for file %s (%s).\n",
4104 r, fsp_str_dbg(fsp), strerror(errno)));
4105 exit_server_cleanly(r);
4108 /* No outbuf here means successful sendfile. */
4109 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4110 SMB_PERFCOUNT_END(&req->pcd);
4111 goto out;
4114 normal_read:
4116 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4117 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4118 ssize_t ret;
4120 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4121 (startpos > fsp->fsp_name->st.st_ex_size) ||
4122 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4124 * We already know that we would do a short
4125 * read, so don't try the sendfile() path.
4127 goto nosendfile_read;
4130 construct_reply_common_req(req, (char *)headerbuf);
4131 setup_readX_header((char *)headerbuf, smb_maxcnt);
4133 /* Send out the header. */
4134 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4135 sizeof(headerbuf));
4136 if (ret != sizeof(headerbuf)) {
4137 saved_errno = errno;
4139 * Try and give an error message saying what
4140 * client failed.
4142 DEBUG(0,("send_file_readX: write_data failed for file "
4143 "%s (%s) for client %s. Terminating\n",
4144 fsp_str_dbg(fsp),
4145 smbXsrv_connection_dbg(xconn),
4146 strerror(saved_errno)));
4147 errno = saved_errno;
4148 exit_server_cleanly("send_file_readX sendfile failed");
4150 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4151 if (nread == -1) {
4152 saved_errno = errno;
4153 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4154 "%s (%s) for client %s. Terminating\n",
4155 fsp_str_dbg(fsp),
4156 smbXsrv_connection_dbg(xconn),
4157 strerror(saved_errno)));
4158 errno = saved_errno;
4159 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4161 goto out;
4164 nosendfile_read:
4166 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4167 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4168 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4170 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4171 startpos, smb_maxcnt);
4172 saved_errno = errno;
4174 if (nread < 0) {
4175 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4176 return;
4179 setup_readX_header((char *)req->outbuf, nread);
4181 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4182 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4183 return;
4185 out:
4186 TALLOC_FREE(req->outbuf);
4187 return;
4190 /****************************************************************************
4191 Work out how much space we have for a read return.
4192 ****************************************************************************/
4194 static size_t calc_max_read_pdu(const struct smb_request *req)
4196 struct smbXsrv_connection *xconn = req->xconn;
4198 if (xconn->protocol < PROTOCOL_NT1) {
4199 return xconn->smb1.sessions.max_send;
4202 if (!lp_large_readwrite()) {
4203 return xconn->smb1.sessions.max_send;
4206 if (req_is_in_chain(req)) {
4207 return xconn->smb1.sessions.max_send;
4210 if (req->encrypted) {
4212 * Don't take encrypted traffic up to the
4213 * limit. There are padding considerations
4214 * that make that tricky.
4216 return xconn->smb1.sessions.max_send;
4219 if (srv_is_signing_active(xconn)) {
4220 return 0x1FFFF;
4223 if (!lp_unix_extensions()) {
4224 return 0x1FFFF;
4228 * We can do ultra-large POSIX reads.
4230 return 0xFFFFFF;
4233 /****************************************************************************
4234 Calculate how big a read can be. Copes with all clients. It's always
4235 safe to return a short read - Windows does this.
4236 ****************************************************************************/
4238 static size_t calc_read_size(const struct smb_request *req,
4239 size_t upper_size,
4240 size_t lower_size)
4242 struct smbXsrv_connection *xconn = req->xconn;
4243 size_t max_pdu = calc_max_read_pdu(req);
4244 size_t total_size = 0;
4245 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4246 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4249 * Windows explicitly ignores upper size of 0xFFFF.
4250 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4251 * We must do the same as these will never fit even in
4252 * an extended size NetBIOS packet.
4254 if (upper_size == 0xFFFF) {
4255 upper_size = 0;
4258 if (xconn->protocol < PROTOCOL_NT1) {
4259 upper_size = 0;
4262 total_size = ((upper_size<<16) | lower_size);
4265 * LARGE_READX test shows it's always safe to return
4266 * a short read. Windows does so.
4268 return MIN(total_size, max_len);
4271 /****************************************************************************
4272 Reply to a read and X.
4273 ****************************************************************************/
4275 void reply_read_and_X(struct smb_request *req)
4277 connection_struct *conn = req->conn;
4278 files_struct *fsp;
4279 off_t startpos;
4280 size_t smb_maxcnt;
4281 size_t upper_size;
4282 bool big_readX = False;
4283 #if 0
4284 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4285 #endif
4287 START_PROFILE(SMBreadX);
4289 if ((req->wct != 10) && (req->wct != 12)) {
4290 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4291 return;
4294 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4295 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4296 smb_maxcnt = SVAL(req->vwv+5, 0);
4298 /* If it's an IPC, pass off the pipe handler. */
4299 if (IS_IPC(conn)) {
4300 reply_pipe_read_and_X(req);
4301 END_PROFILE(SMBreadX);
4302 return;
4305 if (!check_fsp(conn, req, fsp)) {
4306 END_PROFILE(SMBreadX);
4307 return;
4310 if (!CHECK_READ(fsp,req)) {
4311 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4312 END_PROFILE(SMBreadX);
4313 return;
4316 upper_size = SVAL(req->vwv+7, 0);
4317 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4318 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4320 * This is a heuristic to avoid keeping large
4321 * outgoing buffers around over long-lived aio
4322 * requests.
4324 big_readX = True;
4327 if (req->wct == 12) {
4329 * This is a large offset (64 bit) read.
4331 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4335 if (!big_readX) {
4336 NTSTATUS status = schedule_aio_read_and_X(conn,
4337 req,
4338 fsp,
4339 startpos,
4340 smb_maxcnt);
4341 if (NT_STATUS_IS_OK(status)) {
4342 /* Read scheduled - we're done. */
4343 goto out;
4345 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4346 /* Real error - report to client. */
4347 END_PROFILE(SMBreadX);
4348 reply_nterror(req, status);
4349 return;
4351 /* NT_STATUS_RETRY - fall back to sync read. */
4354 smbd_lock_socket(req->xconn);
4355 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4356 smbd_unlock_socket(req->xconn);
4358 out:
4359 END_PROFILE(SMBreadX);
4360 return;
4363 /****************************************************************************
4364 Error replies to writebraw must have smb_wct == 1. Fix this up.
4365 ****************************************************************************/
4367 void error_to_writebrawerr(struct smb_request *req)
4369 uint8_t *old_outbuf = req->outbuf;
4371 reply_outbuf(req, 1, 0);
4373 memcpy(req->outbuf, old_outbuf, smb_size);
4374 TALLOC_FREE(old_outbuf);
4377 /****************************************************************************
4378 Read 4 bytes of a smb packet and return the smb length of the packet.
4379 Store the result in the buffer. This version of the function will
4380 never return a session keepalive (length of zero).
4381 Timeout is in milliseconds.
4382 ****************************************************************************/
4384 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4385 size_t *len)
4387 uint8_t msgtype = NBSSkeepalive;
4389 while (msgtype == NBSSkeepalive) {
4390 NTSTATUS status;
4392 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4393 len);
4394 if (!NT_STATUS_IS_OK(status)) {
4395 char addr[INET6_ADDRSTRLEN];
4396 /* Try and give an error message
4397 * saying what client failed. */
4398 DEBUG(0, ("read_smb_length_return_keepalive failed for "
4399 "client %s read error = %s.\n",
4400 get_peer_addr(fd,addr,sizeof(addr)),
4401 nt_errstr(status)));
4402 return status;
4405 msgtype = CVAL(inbuf, 0);
4408 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4409 (unsigned long)len));
4411 return NT_STATUS_OK;
4414 /****************************************************************************
4415 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4416 ****************************************************************************/
4418 void reply_writebraw(struct smb_request *req)
4420 connection_struct *conn = req->conn;
4421 struct smbXsrv_connection *xconn = req->xconn;
4422 char *buf = NULL;
4423 ssize_t nwritten=0;
4424 ssize_t total_written=0;
4425 size_t numtowrite=0;
4426 size_t tcount;
4427 off_t startpos;
4428 const char *data=NULL;
4429 bool write_through;
4430 files_struct *fsp;
4431 struct lock_struct lock;
4432 NTSTATUS status;
4434 START_PROFILE(SMBwritebraw);
4437 * If we ever reply with an error, it must have the SMB command
4438 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4439 * we're finished.
4441 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4443 if (srv_is_signing_active(xconn)) {
4444 END_PROFILE(SMBwritebraw);
4445 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4446 "raw reads/writes are disallowed.");
4449 if (req->wct < 12) {
4450 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4451 error_to_writebrawerr(req);
4452 END_PROFILE(SMBwritebraw);
4453 return;
4456 if (xconn->smb1.echo_handler.trusted_fde) {
4457 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4458 "'async smb echo handler = yes'\n"));
4459 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4460 error_to_writebrawerr(req);
4461 END_PROFILE(SMBwritebraw);
4462 return;
4465 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4466 if (!check_fsp(conn, req, fsp)) {
4467 error_to_writebrawerr(req);
4468 END_PROFILE(SMBwritebraw);
4469 return;
4472 if (!CHECK_WRITE(fsp)) {
4473 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4474 error_to_writebrawerr(req);
4475 END_PROFILE(SMBwritebraw);
4476 return;
4479 tcount = IVAL(req->vwv+1, 0);
4480 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4481 write_through = BITSETW(req->vwv+7,0);
4483 /* We have to deal with slightly different formats depending
4484 on whether we are using the core+ or lanman1.0 protocol */
4486 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4487 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4488 data = smb_buf_const(req->inbuf);
4489 } else {
4490 numtowrite = SVAL(req->vwv+10, 0);
4491 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4494 /* Ensure we don't write bytes past the end of this packet. */
4496 * This already protects us against CVE-2017-12163.
4498 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4499 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4500 error_to_writebrawerr(req);
4501 END_PROFILE(SMBwritebraw);
4502 return;
4505 if (!fsp->print_file) {
4506 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4507 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4508 &lock);
4510 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4511 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4512 error_to_writebrawerr(req);
4513 END_PROFILE(SMBwritebraw);
4514 return;
4518 if (numtowrite>0) {
4519 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4522 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4523 "wrote=%d sync=%d\n",
4524 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4525 (int)nwritten, (int)write_through));
4527 if (nwritten < (ssize_t)numtowrite) {
4528 reply_nterror(req, NT_STATUS_DISK_FULL);
4529 error_to_writebrawerr(req);
4530 goto out;
4533 total_written = nwritten;
4535 /* Allocate a buffer of 64k + length. */
4536 buf = talloc_array(NULL, char, 65540);
4537 if (!buf) {
4538 reply_nterror(req, NT_STATUS_NO_MEMORY);
4539 error_to_writebrawerr(req);
4540 goto out;
4543 /* Return a SMBwritebraw message to the redirector to tell
4544 * it to send more bytes */
4546 memcpy(buf, req->inbuf, smb_size);
4547 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4548 SCVAL(buf,smb_com,SMBwritebraw);
4549 SSVALS(buf,smb_vwv0,0xFFFF);
4550 show_msg(buf);
4551 if (!srv_send_smb(req->xconn,
4552 buf,
4553 false, 0, /* no signing */
4554 IS_CONN_ENCRYPTED(conn),
4555 &req->pcd)) {
4556 exit_server_cleanly("reply_writebraw: srv_send_smb "
4557 "failed.");
4560 /* Now read the raw data into the buffer and write it */
4561 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4562 &numtowrite);
4563 if (!NT_STATUS_IS_OK(status)) {
4564 exit_server_cleanly("secondary writebraw failed");
4567 /* Set up outbuf to return the correct size */
4568 reply_outbuf(req, 1, 0);
4570 if (numtowrite != 0) {
4572 if (numtowrite > 0xFFFF) {
4573 DEBUG(0,("reply_writebraw: Oversize secondary write "
4574 "raw requested (%u). Terminating\n",
4575 (unsigned int)numtowrite ));
4576 exit_server_cleanly("secondary writebraw failed");
4579 if (tcount > nwritten+numtowrite) {
4580 DEBUG(3,("reply_writebraw: Client overestimated the "
4581 "write %d %d %d\n",
4582 (int)tcount,(int)nwritten,(int)numtowrite));
4585 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4586 numtowrite);
4588 if (!NT_STATUS_IS_OK(status)) {
4589 /* Try and give an error message
4590 * saying what client failed. */
4591 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4592 "raw read failed (%s) for client %s. "
4593 "Terminating\n", nt_errstr(status),
4594 smbXsrv_connection_dbg(xconn)));
4595 exit_server_cleanly("secondary writebraw failed");
4599 * We are not vulnerable to CVE-2017-12163
4600 * here as we are guaranteed to have numtowrite
4601 * bytes available - we just read from the client.
4603 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4604 if (nwritten == -1) {
4605 TALLOC_FREE(buf);
4606 reply_nterror(req, map_nt_error_from_unix(errno));
4607 error_to_writebrawerr(req);
4608 goto out;
4611 if (nwritten < (ssize_t)numtowrite) {
4612 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4613 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4616 if (nwritten > 0) {
4617 total_written += nwritten;
4621 TALLOC_FREE(buf);
4622 SSVAL(req->outbuf,smb_vwv0,total_written);
4624 status = sync_file(conn, fsp, write_through);
4625 if (!NT_STATUS_IS_OK(status)) {
4626 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4627 fsp_str_dbg(fsp), nt_errstr(status)));
4628 reply_nterror(req, status);
4629 error_to_writebrawerr(req);
4630 goto out;
4633 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4634 "wrote=%d\n",
4635 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4636 (int)total_written));
4638 /* We won't return a status if write through is not selected - this
4639 * follows what WfWg does */
4640 END_PROFILE(SMBwritebraw);
4642 if (!write_through && total_written==tcount) {
4644 #if RABBIT_PELLET_FIX
4646 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4647 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4648 * JRA.
4650 if (!send_keepalive(xconn->transport.sock)) {
4651 exit_server_cleanly("reply_writebraw: send of "
4652 "keepalive failed");
4654 #endif
4655 TALLOC_FREE(req->outbuf);
4657 return;
4659 out:
4660 END_PROFILE(SMBwritebraw);
4661 return;
4664 #undef DBGC_CLASS
4665 #define DBGC_CLASS DBGC_LOCKING
4667 /****************************************************************************
4668 Reply to a writeunlock (core+).
4669 ****************************************************************************/
4671 void reply_writeunlock(struct smb_request *req)
4673 connection_struct *conn = req->conn;
4674 ssize_t nwritten = -1;
4675 size_t numtowrite;
4676 size_t remaining;
4677 off_t startpos;
4678 const char *data;
4679 NTSTATUS status = NT_STATUS_OK;
4680 files_struct *fsp;
4681 struct lock_struct lock;
4682 int saved_errno = 0;
4684 START_PROFILE(SMBwriteunlock);
4686 if (req->wct < 5) {
4687 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4688 END_PROFILE(SMBwriteunlock);
4689 return;
4692 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4694 if (!check_fsp(conn, req, fsp)) {
4695 END_PROFILE(SMBwriteunlock);
4696 return;
4699 if (!CHECK_WRITE(fsp)) {
4700 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4701 END_PROFILE(SMBwriteunlock);
4702 return;
4705 numtowrite = SVAL(req->vwv+1, 0);
4706 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4707 data = (const char *)req->buf + 3;
4710 * Ensure client isn't asking us to write more than
4711 * they sent. CVE-2017-12163.
4713 remaining = smbreq_bufrem(req, data);
4714 if (numtowrite > remaining) {
4715 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4716 END_PROFILE(SMBwriteunlock);
4717 return;
4720 if (!fsp->print_file && numtowrite > 0) {
4721 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4722 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4723 &lock);
4725 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4726 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4727 END_PROFILE(SMBwriteunlock);
4728 return;
4732 /* The special X/Open SMB protocol handling of
4733 zero length writes is *NOT* done for
4734 this call */
4735 if(numtowrite == 0) {
4736 nwritten = 0;
4737 } else {
4738 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4739 saved_errno = errno;
4742 status = sync_file(conn, fsp, False /* write through */);
4743 if (!NT_STATUS_IS_OK(status)) {
4744 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4745 fsp_str_dbg(fsp), nt_errstr(status)));
4746 reply_nterror(req, status);
4747 goto out;
4750 if(nwritten < 0) {
4751 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4752 goto out;
4755 if((nwritten < numtowrite) && (numtowrite != 0)) {
4756 reply_nterror(req, NT_STATUS_DISK_FULL);
4757 goto out;
4760 if (numtowrite && !fsp->print_file) {
4761 status = do_unlock(req->sconn->msg_ctx,
4762 fsp,
4763 (uint64_t)req->smbpid,
4764 (uint64_t)numtowrite,
4765 (uint64_t)startpos,
4766 WINDOWS_LOCK);
4768 if (NT_STATUS_V(status)) {
4769 reply_nterror(req, status);
4770 goto out;
4774 reply_outbuf(req, 1, 0);
4776 SSVAL(req->outbuf,smb_vwv0,nwritten);
4778 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4779 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4781 out:
4782 END_PROFILE(SMBwriteunlock);
4783 return;
4786 #undef DBGC_CLASS
4787 #define DBGC_CLASS DBGC_ALL
4789 /****************************************************************************
4790 Reply to a write.
4791 ****************************************************************************/
4793 void reply_write(struct smb_request *req)
4795 connection_struct *conn = req->conn;
4796 size_t numtowrite;
4797 size_t remaining;
4798 ssize_t nwritten = -1;
4799 off_t startpos;
4800 const char *data;
4801 files_struct *fsp;
4802 struct lock_struct lock;
4803 NTSTATUS status;
4804 int saved_errno = 0;
4806 START_PROFILE(SMBwrite);
4808 if (req->wct < 5) {
4809 END_PROFILE(SMBwrite);
4810 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4811 return;
4814 /* If it's an IPC, pass off the pipe handler. */
4815 if (IS_IPC(conn)) {
4816 reply_pipe_write(req);
4817 END_PROFILE(SMBwrite);
4818 return;
4821 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4823 if (!check_fsp(conn, req, fsp)) {
4824 END_PROFILE(SMBwrite);
4825 return;
4828 if (!CHECK_WRITE(fsp)) {
4829 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4830 END_PROFILE(SMBwrite);
4831 return;
4834 numtowrite = SVAL(req->vwv+1, 0);
4835 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4836 data = (const char *)req->buf + 3;
4839 * Ensure client isn't asking us to write more than
4840 * they sent. CVE-2017-12163.
4842 remaining = smbreq_bufrem(req, data);
4843 if (numtowrite > remaining) {
4844 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4845 END_PROFILE(SMBwrite);
4846 return;
4849 if (!fsp->print_file) {
4850 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4851 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4852 &lock);
4854 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4855 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4856 END_PROFILE(SMBwrite);
4857 return;
4862 * X/Open SMB protocol says that if smb_vwv1 is
4863 * zero then the file size should be extended or
4864 * truncated to the size given in smb_vwv[2-3].
4867 if(numtowrite == 0) {
4869 * This is actually an allocate call, and set EOF. JRA.
4871 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4872 if (nwritten < 0) {
4873 reply_nterror(req, NT_STATUS_DISK_FULL);
4874 goto out;
4876 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4877 if (nwritten < 0) {
4878 reply_nterror(req, NT_STATUS_DISK_FULL);
4879 goto out;
4881 trigger_write_time_update_immediate(fsp);
4882 } else {
4883 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4886 status = sync_file(conn, fsp, False);
4887 if (!NT_STATUS_IS_OK(status)) {
4888 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4889 fsp_str_dbg(fsp), nt_errstr(status)));
4890 reply_nterror(req, status);
4891 goto out;
4894 if(nwritten < 0) {
4895 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4896 goto out;
4899 if((nwritten == 0) && (numtowrite != 0)) {
4900 reply_nterror(req, NT_STATUS_DISK_FULL);
4901 goto out;
4904 reply_outbuf(req, 1, 0);
4906 SSVAL(req->outbuf,smb_vwv0,nwritten);
4908 if (nwritten < (ssize_t)numtowrite) {
4909 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4910 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4913 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4915 out:
4916 END_PROFILE(SMBwrite);
4917 return;
4920 /****************************************************************************
4921 Ensure a buffer is a valid writeX for recvfile purposes.
4922 ****************************************************************************/
4924 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4925 (2*14) + /* word count (including bcc) */ \
4926 1 /* pad byte */)
4928 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4929 const uint8_t *inbuf)
4931 size_t numtowrite;
4932 unsigned int doff = 0;
4933 size_t len = smb_len_large(inbuf);
4934 uint16_t fnum;
4935 struct smbXsrv_open *op = NULL;
4936 struct files_struct *fsp = NULL;
4937 NTSTATUS status;
4939 if (is_encrypted_packet(inbuf)) {
4940 /* Can't do this on encrypted
4941 * connections. */
4942 return false;
4945 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4946 return false;
4949 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4950 CVAL(inbuf,smb_wct) != 14) {
4951 DEBUG(10,("is_valid_writeX_buffer: chained or "
4952 "invalid word length.\n"));
4953 return false;
4956 fnum = SVAL(inbuf, smb_vwv2);
4957 status = smb1srv_open_lookup(xconn,
4958 fnum,
4959 0, /* now */
4960 &op);
4961 if (!NT_STATUS_IS_OK(status)) {
4962 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4963 return false;
4965 fsp = op->compat;
4966 if (fsp == NULL) {
4967 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4968 return false;
4970 if (fsp->conn == NULL) {
4971 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4972 return false;
4975 if (IS_IPC(fsp->conn)) {
4976 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4977 return false;
4979 if (IS_PRINT(fsp->conn)) {
4980 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4981 return false;
4983 if (fsp->base_fsp != NULL) {
4984 DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
4985 return false;
4987 doff = SVAL(inbuf,smb_vwv11);
4989 numtowrite = SVAL(inbuf,smb_vwv10);
4991 if (len > doff && len - doff > 0xFFFF) {
4992 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4995 if (numtowrite == 0) {
4996 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4997 return false;
5000 /* Ensure the sizes match up. */
5001 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
5002 /* no pad byte...old smbclient :-( */
5003 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
5004 (unsigned int)doff,
5005 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
5006 return false;
5009 if (len - doff != numtowrite) {
5010 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
5011 "len = %u, doff = %u, numtowrite = %u\n",
5012 (unsigned int)len,
5013 (unsigned int)doff,
5014 (unsigned int)numtowrite ));
5015 return false;
5018 DEBUG(10,("is_valid_writeX_buffer: true "
5019 "len = %u, doff = %u, numtowrite = %u\n",
5020 (unsigned int)len,
5021 (unsigned int)doff,
5022 (unsigned int)numtowrite ));
5024 return true;
5027 /****************************************************************************
5028 Reply to a write and X.
5029 ****************************************************************************/
5031 void reply_write_and_X(struct smb_request *req)
5033 connection_struct *conn = req->conn;
5034 struct smbXsrv_connection *xconn = req->xconn;
5035 files_struct *fsp;
5036 struct lock_struct lock;
5037 off_t startpos;
5038 size_t numtowrite;
5039 bool write_through;
5040 ssize_t nwritten;
5041 unsigned int smb_doff;
5042 unsigned int smblen;
5043 const char *data;
5044 NTSTATUS status;
5045 int saved_errno = 0;
5047 START_PROFILE(SMBwriteX);
5049 if ((req->wct != 12) && (req->wct != 14)) {
5050 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5051 goto out;
5054 numtowrite = SVAL(req->vwv+10, 0);
5055 smb_doff = SVAL(req->vwv+11, 0);
5056 smblen = smb_len(req->inbuf);
5058 if (req->unread_bytes > 0xFFFF ||
5059 (smblen > smb_doff &&
5060 smblen - smb_doff > 0xFFFF)) {
5061 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5064 if (req->unread_bytes) {
5065 /* Can't do a recvfile write on IPC$ */
5066 if (IS_IPC(conn)) {
5067 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5068 goto out;
5070 if (numtowrite != req->unread_bytes) {
5071 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5072 goto out;
5074 } else {
5076 * This already protects us against CVE-2017-12163.
5078 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5079 smb_doff + numtowrite > smblen) {
5080 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5081 goto out;
5085 /* If it's an IPC, pass off the pipe handler. */
5086 if (IS_IPC(conn)) {
5087 if (req->unread_bytes) {
5088 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5089 goto out;
5091 reply_pipe_write_and_X(req);
5092 goto out;
5095 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5096 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5097 write_through = BITSETW(req->vwv+7,0);
5099 if (!check_fsp(conn, req, fsp)) {
5100 goto out;
5103 if (!CHECK_WRITE(fsp)) {
5104 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5105 goto out;
5108 data = smb_base(req->inbuf) + smb_doff;
5110 if(req->wct == 14) {
5112 * This is a large offset (64 bit) write.
5114 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5118 /* X/Open SMB protocol says that, unlike SMBwrite
5119 if the length is zero then NO truncation is
5120 done, just a write of zero. To truncate a file,
5121 use SMBwrite. */
5123 if(numtowrite == 0) {
5124 nwritten = 0;
5125 } else {
5126 if (req->unread_bytes == 0) {
5127 status = schedule_aio_write_and_X(conn,
5128 req,
5129 fsp,
5130 data,
5131 startpos,
5132 numtowrite);
5134 if (NT_STATUS_IS_OK(status)) {
5135 /* write scheduled - we're done. */
5136 goto out;
5138 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5139 /* Real error - report to client. */
5140 reply_nterror(req, status);
5141 goto out;
5143 /* NT_STATUS_RETRY - fall through to sync write. */
5146 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5147 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5148 &lock);
5150 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5151 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5152 goto out;
5155 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5156 saved_errno = errno;
5159 if(nwritten < 0) {
5160 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5161 goto out;
5164 if((nwritten == 0) && (numtowrite != 0)) {
5165 reply_nterror(req, NT_STATUS_DISK_FULL);
5166 goto out;
5169 reply_outbuf(req, 6, 0);
5170 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5171 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5172 SSVAL(req->outbuf,smb_vwv2,nwritten);
5173 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5175 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5176 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5178 status = sync_file(conn, fsp, write_through);
5179 if (!NT_STATUS_IS_OK(status)) {
5180 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5181 fsp_str_dbg(fsp), nt_errstr(status)));
5182 reply_nterror(req, status);
5183 goto out;
5186 END_PROFILE(SMBwriteX);
5187 return;
5189 out:
5190 if (req->unread_bytes) {
5191 /* writeX failed. drain socket. */
5192 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5193 req->unread_bytes) {
5194 smb_panic("failed to drain pending bytes");
5196 req->unread_bytes = 0;
5199 END_PROFILE(SMBwriteX);
5200 return;
5203 /****************************************************************************
5204 Reply to a lseek.
5205 ****************************************************************************/
5207 void reply_lseek(struct smb_request *req)
5209 connection_struct *conn = req->conn;
5210 off_t startpos;
5211 off_t res= -1;
5212 int mode,umode;
5213 files_struct *fsp;
5215 START_PROFILE(SMBlseek);
5217 if (req->wct < 4) {
5218 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5219 END_PROFILE(SMBlseek);
5220 return;
5223 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5225 if (!check_fsp(conn, req, fsp)) {
5226 return;
5229 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5231 mode = SVAL(req->vwv+1, 0) & 3;
5232 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5233 startpos = (off_t)IVALS(req->vwv+2, 0);
5235 switch (mode) {
5236 case 0:
5237 umode = SEEK_SET;
5238 res = startpos;
5239 break;
5240 case 1:
5241 umode = SEEK_CUR;
5242 res = fsp->fh->pos + startpos;
5243 break;
5244 case 2:
5245 umode = SEEK_END;
5246 break;
5247 default:
5248 umode = SEEK_SET;
5249 res = startpos;
5250 break;
5253 if (umode == SEEK_END) {
5254 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5255 if(errno == EINVAL) {
5256 off_t current_pos = startpos;
5258 if(fsp_stat(fsp) == -1) {
5259 reply_nterror(req,
5260 map_nt_error_from_unix(errno));
5261 END_PROFILE(SMBlseek);
5262 return;
5265 current_pos += fsp->fsp_name->st.st_ex_size;
5266 if(current_pos < 0)
5267 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5271 if(res == -1) {
5272 reply_nterror(req, map_nt_error_from_unix(errno));
5273 END_PROFILE(SMBlseek);
5274 return;
5278 fsp->fh->pos = res;
5280 reply_outbuf(req, 2, 0);
5281 SIVAL(req->outbuf,smb_vwv0,res);
5283 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5284 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5286 END_PROFILE(SMBlseek);
5287 return;
5290 static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
5291 void *private_data)
5293 connection_struct *conn = talloc_get_type_abort(
5294 private_data, connection_struct);
5296 if (conn != fsp->conn) {
5297 return NULL;
5299 if (fsp->fh->fd == -1) {
5300 return NULL;
5302 sync_file(conn, fsp, True /* write through */);
5304 return NULL;
5307 /****************************************************************************
5308 Reply to a flush.
5309 ****************************************************************************/
5311 void reply_flush(struct smb_request *req)
5313 connection_struct *conn = req->conn;
5314 uint16_t fnum;
5315 files_struct *fsp;
5317 START_PROFILE(SMBflush);
5319 if (req->wct < 1) {
5320 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5321 return;
5324 fnum = SVAL(req->vwv+0, 0);
5325 fsp = file_fsp(req, fnum);
5327 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5328 return;
5331 if (!fsp) {
5332 files_forall(req->sconn, file_sync_one_fn, conn);
5333 } else {
5334 NTSTATUS status = sync_file(conn, fsp, True);
5335 if (!NT_STATUS_IS_OK(status)) {
5336 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5337 fsp_str_dbg(fsp), nt_errstr(status)));
5338 reply_nterror(req, status);
5339 END_PROFILE(SMBflush);
5340 return;
5344 reply_outbuf(req, 0, 0);
5346 DEBUG(3,("flush\n"));
5347 END_PROFILE(SMBflush);
5348 return;
5351 /****************************************************************************
5352 Reply to a exit.
5353 conn POINTER CAN BE NULL HERE !
5354 ****************************************************************************/
5356 void reply_exit(struct smb_request *req)
5358 START_PROFILE(SMBexit);
5360 file_close_pid(req->sconn, req->smbpid, req->vuid);
5362 reply_outbuf(req, 0, 0);
5364 DEBUG(3,("exit\n"));
5366 END_PROFILE(SMBexit);
5367 return;
5370 struct reply_close_state {
5371 files_struct *fsp;
5372 struct smb_request *smbreq;
5375 static void do_smb1_close(struct tevent_req *req);
5377 void reply_close(struct smb_request *req)
5379 connection_struct *conn = req->conn;
5380 NTSTATUS status = NT_STATUS_OK;
5381 files_struct *fsp = NULL;
5382 START_PROFILE(SMBclose);
5384 if (req->wct < 3) {
5385 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5386 END_PROFILE(SMBclose);
5387 return;
5390 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5393 * We can only use check_fsp if we know it's not a directory.
5396 if (!check_fsp_open(conn, req, fsp)) {
5397 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5398 END_PROFILE(SMBclose);
5399 return;
5402 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5403 fsp->is_directory ? "directory" : "file",
5404 fsp->fh->fd, fsp_fnum_dbg(fsp),
5405 conn->num_files_open));
5407 if (!fsp->is_directory) {
5408 time_t t;
5411 * Take care of any time sent in the close.
5414 t = srv_make_unix_date3(req->vwv+1);
5415 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5418 if (fsp->num_aio_requests != 0) {
5420 struct reply_close_state *state;
5422 DEBUG(10, ("closing with aio %u requests pending\n",
5423 fsp->num_aio_requests));
5426 * We depend on the aio_extra destructor to take care of this
5427 * close request once fsp->num_aio_request drops to 0.
5430 fsp->deferred_close = tevent_wait_send(
5431 fsp, fsp->conn->sconn->ev_ctx);
5432 if (fsp->deferred_close == NULL) {
5433 status = NT_STATUS_NO_MEMORY;
5434 goto done;
5437 state = talloc(fsp, struct reply_close_state);
5438 if (state == NULL) {
5439 TALLOC_FREE(fsp->deferred_close);
5440 status = NT_STATUS_NO_MEMORY;
5441 goto done;
5443 state->fsp = fsp;
5444 state->smbreq = talloc_move(fsp, &req);
5445 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5446 state);
5447 END_PROFILE(SMBclose);
5448 return;
5452 * close_file() returns the unix errno if an error was detected on
5453 * close - normally this is due to a disk full error. If not then it
5454 * was probably an I/O error.
5457 status = close_file(req, fsp, NORMAL_CLOSE);
5458 done:
5459 if (!NT_STATUS_IS_OK(status)) {
5460 reply_nterror(req, status);
5461 END_PROFILE(SMBclose);
5462 return;
5465 reply_outbuf(req, 0, 0);
5466 END_PROFILE(SMBclose);
5467 return;
5470 static void do_smb1_close(struct tevent_req *req)
5472 struct reply_close_state *state = tevent_req_callback_data(
5473 req, struct reply_close_state);
5474 struct smb_request *smbreq;
5475 NTSTATUS status;
5476 int ret;
5478 ret = tevent_wait_recv(req);
5479 TALLOC_FREE(req);
5480 if (ret != 0) {
5481 DEBUG(10, ("tevent_wait_recv returned %s\n",
5482 strerror(ret)));
5484 * Continue anyway, this should never happen
5489 * fsp->smb2_close_request right now is a talloc grandchild of
5490 * fsp. When we close_file(fsp), it would go with it. No chance to
5491 * reply...
5493 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5495 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5496 if (NT_STATUS_IS_OK(status)) {
5497 reply_outbuf(smbreq, 0, 0);
5498 } else {
5499 reply_nterror(smbreq, status);
5501 if (!srv_send_smb(smbreq->xconn,
5502 (char *)smbreq->outbuf,
5503 true,
5504 smbreq->seqnum+1,
5505 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5506 NULL)) {
5507 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5508 "failed.");
5510 TALLOC_FREE(smbreq);
5513 /****************************************************************************
5514 Reply to a writeclose (Core+ protocol).
5515 ****************************************************************************/
5517 void reply_writeclose(struct smb_request *req)
5519 connection_struct *conn = req->conn;
5520 size_t numtowrite;
5521 size_t remaining;
5522 ssize_t nwritten = -1;
5523 NTSTATUS close_status = NT_STATUS_OK;
5524 off_t startpos;
5525 const char *data;
5526 struct timespec mtime;
5527 files_struct *fsp;
5528 struct lock_struct lock;
5530 START_PROFILE(SMBwriteclose);
5532 if (req->wct < 6) {
5533 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5534 END_PROFILE(SMBwriteclose);
5535 return;
5538 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5540 if (!check_fsp(conn, req, fsp)) {
5541 END_PROFILE(SMBwriteclose);
5542 return;
5544 if (!CHECK_WRITE(fsp)) {
5545 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5546 END_PROFILE(SMBwriteclose);
5547 return;
5550 numtowrite = SVAL(req->vwv+1, 0);
5551 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5552 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5553 data = (const char *)req->buf + 1;
5556 * Ensure client isn't asking us to write more than
5557 * they sent. CVE-2017-12163.
5559 remaining = smbreq_bufrem(req, data);
5560 if (numtowrite > remaining) {
5561 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5562 END_PROFILE(SMBwriteclose);
5563 return;
5566 if (fsp->print_file == NULL) {
5567 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5568 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5569 &lock);
5571 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5572 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5573 END_PROFILE(SMBwriteclose);
5574 return;
5578 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5580 set_close_write_time(fsp, mtime);
5583 * More insanity. W2K only closes the file if writelen > 0.
5584 * JRA.
5587 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5588 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5589 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5591 if (numtowrite) {
5592 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5593 "file %s\n", fsp_str_dbg(fsp)));
5594 close_status = close_file(req, fsp, NORMAL_CLOSE);
5595 fsp = NULL;
5598 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5599 reply_nterror(req, NT_STATUS_DISK_FULL);
5600 goto out;
5603 if(!NT_STATUS_IS_OK(close_status)) {
5604 reply_nterror(req, close_status);
5605 goto out;
5608 reply_outbuf(req, 1, 0);
5610 SSVAL(req->outbuf,smb_vwv0,nwritten);
5612 out:
5614 END_PROFILE(SMBwriteclose);
5615 return;
5618 #undef DBGC_CLASS
5619 #define DBGC_CLASS DBGC_LOCKING
5621 /****************************************************************************
5622 Reply to a lock.
5623 ****************************************************************************/
5625 void reply_lock(struct smb_request *req)
5627 connection_struct *conn = req->conn;
5628 uint64_t count,offset;
5629 NTSTATUS status;
5630 files_struct *fsp;
5631 struct byte_range_lock *br_lck = NULL;
5633 START_PROFILE(SMBlock);
5635 if (req->wct < 5) {
5636 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5637 END_PROFILE(SMBlock);
5638 return;
5641 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5643 if (!check_fsp(conn, req, fsp)) {
5644 END_PROFILE(SMBlock);
5645 return;
5648 count = (uint64_t)IVAL(req->vwv+1, 0);
5649 offset = (uint64_t)IVAL(req->vwv+3, 0);
5651 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5652 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5654 br_lck = do_lock(req->sconn->msg_ctx,
5655 fsp,
5656 (uint64_t)req->smbpid,
5657 count,
5658 offset,
5659 WRITE_LOCK,
5660 WINDOWS_LOCK,
5661 False, /* Non-blocking lock. */
5662 &status,
5663 NULL);
5665 TALLOC_FREE(br_lck);
5667 if (NT_STATUS_V(status)) {
5668 reply_nterror(req, status);
5669 END_PROFILE(SMBlock);
5670 return;
5673 reply_outbuf(req, 0, 0);
5675 END_PROFILE(SMBlock);
5676 return;
5679 /****************************************************************************
5680 Reply to a unlock.
5681 ****************************************************************************/
5683 void reply_unlock(struct smb_request *req)
5685 connection_struct *conn = req->conn;
5686 uint64_t count,offset;
5687 NTSTATUS status;
5688 files_struct *fsp;
5690 START_PROFILE(SMBunlock);
5692 if (req->wct < 5) {
5693 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5694 END_PROFILE(SMBunlock);
5695 return;
5698 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5700 if (!check_fsp(conn, req, fsp)) {
5701 END_PROFILE(SMBunlock);
5702 return;
5705 count = (uint64_t)IVAL(req->vwv+1, 0);
5706 offset = (uint64_t)IVAL(req->vwv+3, 0);
5708 status = do_unlock(req->sconn->msg_ctx,
5709 fsp,
5710 (uint64_t)req->smbpid,
5711 count,
5712 offset,
5713 WINDOWS_LOCK);
5715 if (NT_STATUS_V(status)) {
5716 reply_nterror(req, status);
5717 END_PROFILE(SMBunlock);
5718 return;
5721 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5722 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5724 reply_outbuf(req, 0, 0);
5726 END_PROFILE(SMBunlock);
5727 return;
5730 #undef DBGC_CLASS
5731 #define DBGC_CLASS DBGC_ALL
5733 /****************************************************************************
5734 Reply to a tdis.
5735 conn POINTER CAN BE NULL HERE !
5736 ****************************************************************************/
5738 void reply_tdis(struct smb_request *req)
5740 NTSTATUS status;
5741 connection_struct *conn = req->conn;
5742 struct smbXsrv_tcon *tcon;
5744 START_PROFILE(SMBtdis);
5746 if (!conn) {
5747 DEBUG(4,("Invalid connection in tdis\n"));
5748 reply_force_doserror(req, ERRSRV, ERRinvnid);
5749 END_PROFILE(SMBtdis);
5750 return;
5753 tcon = conn->tcon;
5754 req->conn = NULL;
5757 * TODO: cancel all outstanding requests on the tcon
5759 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5760 if (!NT_STATUS_IS_OK(status)) {
5761 DEBUG(0, ("reply_tdis: "
5762 "smbXsrv_tcon_disconnect() failed: %s\n",
5763 nt_errstr(status)));
5765 * If we hit this case, there is something completely
5766 * wrong, so we better disconnect the transport connection.
5768 END_PROFILE(SMBtdis);
5769 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5770 return;
5773 TALLOC_FREE(tcon);
5775 reply_outbuf(req, 0, 0);
5776 END_PROFILE(SMBtdis);
5777 return;
5780 /****************************************************************************
5781 Reply to a echo.
5782 conn POINTER CAN BE NULL HERE !
5783 ****************************************************************************/
5785 void reply_echo(struct smb_request *req)
5787 connection_struct *conn = req->conn;
5788 struct smb_perfcount_data local_pcd;
5789 struct smb_perfcount_data *cur_pcd;
5790 int smb_reverb;
5791 int seq_num;
5793 START_PROFILE(SMBecho);
5795 smb_init_perfcount_data(&local_pcd);
5797 if (req->wct < 1) {
5798 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5799 END_PROFILE(SMBecho);
5800 return;
5803 smb_reverb = SVAL(req->vwv+0, 0);
5805 reply_outbuf(req, 1, req->buflen);
5807 /* copy any incoming data back out */
5808 if (req->buflen > 0) {
5809 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5812 if (smb_reverb > 100) {
5813 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5814 smb_reverb = 100;
5817 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5819 /* this makes sure we catch the request pcd */
5820 if (seq_num == smb_reverb) {
5821 cur_pcd = &req->pcd;
5822 } else {
5823 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5824 cur_pcd = &local_pcd;
5827 SSVAL(req->outbuf,smb_vwv0,seq_num);
5829 show_msg((char *)req->outbuf);
5830 if (!srv_send_smb(req->xconn,
5831 (char *)req->outbuf,
5832 true, req->seqnum+1,
5833 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5834 cur_pcd))
5835 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5838 DEBUG(3,("echo %d times\n", smb_reverb));
5840 TALLOC_FREE(req->outbuf);
5842 END_PROFILE(SMBecho);
5843 return;
5846 /****************************************************************************
5847 Reply to a printopen.
5848 ****************************************************************************/
5850 void reply_printopen(struct smb_request *req)
5852 connection_struct *conn = req->conn;
5853 files_struct *fsp;
5854 NTSTATUS status;
5856 START_PROFILE(SMBsplopen);
5858 if (req->wct < 2) {
5859 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5860 END_PROFILE(SMBsplopen);
5861 return;
5864 if (!CAN_PRINT(conn)) {
5865 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5866 END_PROFILE(SMBsplopen);
5867 return;
5870 status = file_new(req, conn, &fsp);
5871 if(!NT_STATUS_IS_OK(status)) {
5872 reply_nterror(req, status);
5873 END_PROFILE(SMBsplopen);
5874 return;
5877 /* Open for exclusive use, write only. */
5878 status = print_spool_open(fsp, NULL, req->vuid);
5880 if (!NT_STATUS_IS_OK(status)) {
5881 file_free(req, fsp);
5882 reply_nterror(req, status);
5883 END_PROFILE(SMBsplopen);
5884 return;
5887 reply_outbuf(req, 1, 0);
5888 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5890 DEBUG(3,("openprint fd=%d %s\n",
5891 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5893 END_PROFILE(SMBsplopen);
5894 return;
5897 /****************************************************************************
5898 Reply to a printclose.
5899 ****************************************************************************/
5901 void reply_printclose(struct smb_request *req)
5903 connection_struct *conn = req->conn;
5904 files_struct *fsp;
5905 NTSTATUS status;
5907 START_PROFILE(SMBsplclose);
5909 if (req->wct < 1) {
5910 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5911 END_PROFILE(SMBsplclose);
5912 return;
5915 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5917 if (!check_fsp(conn, req, fsp)) {
5918 END_PROFILE(SMBsplclose);
5919 return;
5922 if (!CAN_PRINT(conn)) {
5923 reply_force_doserror(req, ERRSRV, ERRerror);
5924 END_PROFILE(SMBsplclose);
5925 return;
5928 DEBUG(3,("printclose fd=%d %s\n",
5929 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5931 status = close_file(req, fsp, NORMAL_CLOSE);
5933 if(!NT_STATUS_IS_OK(status)) {
5934 reply_nterror(req, status);
5935 END_PROFILE(SMBsplclose);
5936 return;
5939 reply_outbuf(req, 0, 0);
5941 END_PROFILE(SMBsplclose);
5942 return;
5945 /****************************************************************************
5946 Reply to a printqueue.
5947 ****************************************************************************/
5949 void reply_printqueue(struct smb_request *req)
5951 connection_struct *conn = req->conn;
5952 int max_count;
5953 int start_index;
5955 START_PROFILE(SMBsplretq);
5957 if (req->wct < 2) {
5958 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5959 END_PROFILE(SMBsplretq);
5960 return;
5963 max_count = SVAL(req->vwv+0, 0);
5964 start_index = SVAL(req->vwv+1, 0);
5966 /* we used to allow the client to get the cnum wrong, but that
5967 is really quite gross and only worked when there was only
5968 one printer - I think we should now only accept it if they
5969 get it right (tridge) */
5970 if (!CAN_PRINT(conn)) {
5971 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5972 END_PROFILE(SMBsplretq);
5973 return;
5976 reply_outbuf(req, 2, 3);
5977 SSVAL(req->outbuf,smb_vwv0,0);
5978 SSVAL(req->outbuf,smb_vwv1,0);
5979 SCVAL(smb_buf(req->outbuf),0,1);
5980 SSVAL(smb_buf(req->outbuf),1,0);
5982 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5983 start_index, max_count));
5986 TALLOC_CTX *mem_ctx = talloc_tos();
5987 NTSTATUS status;
5988 WERROR werr;
5989 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5990 struct rpc_pipe_client *cli = NULL;
5991 struct dcerpc_binding_handle *b = NULL;
5992 struct policy_handle handle;
5993 struct spoolss_DevmodeContainer devmode_ctr;
5994 union spoolss_JobInfo *info;
5995 uint32_t count;
5996 uint32_t num_to_get;
5997 uint32_t first;
5998 uint32_t i;
6000 ZERO_STRUCT(handle);
6002 status = rpc_pipe_open_interface(mem_ctx,
6003 &ndr_table_spoolss,
6004 conn->session_info,
6005 conn->sconn->remote_address,
6006 conn->sconn->local_address,
6007 conn->sconn->msg_ctx,
6008 &cli);
6009 if (!NT_STATUS_IS_OK(status)) {
6010 DEBUG(0, ("reply_printqueue: "
6011 "could not connect to spoolss: %s\n",
6012 nt_errstr(status)));
6013 reply_nterror(req, status);
6014 goto out;
6016 b = cli->binding_handle;
6018 ZERO_STRUCT(devmode_ctr);
6020 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
6021 sharename,
6022 NULL, devmode_ctr,
6023 SEC_FLAG_MAXIMUM_ALLOWED,
6024 &handle,
6025 &werr);
6026 if (!NT_STATUS_IS_OK(status)) {
6027 reply_nterror(req, status);
6028 goto out;
6030 if (!W_ERROR_IS_OK(werr)) {
6031 reply_nterror(req, werror_to_ntstatus(werr));
6032 goto out;
6035 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
6036 &handle,
6037 0, /* firstjob */
6038 0xff, /* numjobs */
6039 2, /* level */
6040 0, /* offered */
6041 &count,
6042 &info);
6043 if (!W_ERROR_IS_OK(werr)) {
6044 reply_nterror(req, werror_to_ntstatus(werr));
6045 goto out;
6048 if (max_count > 0) {
6049 first = start_index;
6050 } else {
6051 first = start_index + max_count + 1;
6054 if (first >= count) {
6055 num_to_get = first;
6056 } else {
6057 num_to_get = first + MIN(ABS(max_count), count - first);
6060 for (i = first; i < num_to_get; i++) {
6061 char blob[28];
6062 char *p = blob;
6063 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6064 int qstatus;
6065 size_t len = 0;
6066 uint16_t qrapjobid = pjobid_to_rap(sharename,
6067 info[i].info2.job_id);
6069 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6070 qstatus = 2;
6071 } else {
6072 qstatus = 3;
6075 srv_put_dos_date2(p, 0, qtime);
6076 SCVAL(p, 4, qstatus);
6077 SSVAL(p, 5, qrapjobid);
6078 SIVAL(p, 7, info[i].info2.size);
6079 SCVAL(p, 11, 0);
6080 status = srvstr_push(blob, req->flags2, p+12,
6081 info[i].info2.notify_name, 16, STR_ASCII, &len);
6082 if (!NT_STATUS_IS_OK(status)) {
6083 reply_nterror(req, status);
6084 goto out;
6086 if (message_push_blob(
6087 &req->outbuf,
6088 data_blob_const(
6089 blob, sizeof(blob))) == -1) {
6090 reply_nterror(req, NT_STATUS_NO_MEMORY);
6091 goto out;
6095 if (count > 0) {
6096 SSVAL(req->outbuf,smb_vwv0,count);
6097 SSVAL(req->outbuf,smb_vwv1,
6098 (max_count>0?first+count:first-1));
6099 SCVAL(smb_buf(req->outbuf),0,1);
6100 SSVAL(smb_buf(req->outbuf),1,28*count);
6104 DEBUG(3, ("%u entries returned in queue\n",
6105 (unsigned)count));
6107 out:
6108 if (b && is_valid_policy_hnd(&handle)) {
6109 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6114 END_PROFILE(SMBsplretq);
6115 return;
6118 /****************************************************************************
6119 Reply to a printwrite.
6120 ****************************************************************************/
6122 void reply_printwrite(struct smb_request *req)
6124 connection_struct *conn = req->conn;
6125 int numtowrite;
6126 const char *data;
6127 files_struct *fsp;
6129 START_PROFILE(SMBsplwr);
6131 if (req->wct < 1) {
6132 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6133 END_PROFILE(SMBsplwr);
6134 return;
6137 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6139 if (!check_fsp(conn, req, fsp)) {
6140 END_PROFILE(SMBsplwr);
6141 return;
6144 if (!fsp->print_file) {
6145 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6146 END_PROFILE(SMBsplwr);
6147 return;
6150 if (!CHECK_WRITE(fsp)) {
6151 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6152 END_PROFILE(SMBsplwr);
6153 return;
6156 numtowrite = SVAL(req->buf, 1);
6159 * This already protects us against CVE-2017-12163.
6161 if (req->buflen < numtowrite + 3) {
6162 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6163 END_PROFILE(SMBsplwr);
6164 return;
6167 data = (const char *)req->buf + 3;
6169 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6170 reply_nterror(req, map_nt_error_from_unix(errno));
6171 END_PROFILE(SMBsplwr);
6172 return;
6175 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6177 END_PROFILE(SMBsplwr);
6178 return;
6181 /****************************************************************************
6182 Reply to a mkdir.
6183 ****************************************************************************/
6185 void reply_mkdir(struct smb_request *req)
6187 connection_struct *conn = req->conn;
6188 struct smb_filename *smb_dname = NULL;
6189 char *directory = NULL;
6190 NTSTATUS status;
6191 uint32_t ucf_flags;
6192 TALLOC_CTX *ctx = talloc_tos();
6194 START_PROFILE(SMBmkdir);
6196 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6197 STR_TERMINATE, &status);
6198 if (!NT_STATUS_IS_OK(status)) {
6199 reply_nterror(req, status);
6200 goto out;
6203 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6204 status = filename_convert(ctx, conn,
6205 directory,
6206 ucf_flags,
6207 NULL,
6208 NULL,
6209 &smb_dname);
6210 if (!NT_STATUS_IS_OK(status)) {
6211 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6212 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6213 ERRSRV, ERRbadpath);
6214 goto out;
6216 reply_nterror(req, status);
6217 goto out;
6220 status = create_directory(conn, req, smb_dname);
6222 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6224 if (!NT_STATUS_IS_OK(status)) {
6226 if (!use_nt_status()
6227 && NT_STATUS_EQUAL(status,
6228 NT_STATUS_OBJECT_NAME_COLLISION)) {
6230 * Yes, in the DOS error code case we get a
6231 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6232 * samba4 torture test.
6234 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6237 reply_nterror(req, status);
6238 goto out;
6241 reply_outbuf(req, 0, 0);
6243 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6244 out:
6245 TALLOC_FREE(smb_dname);
6246 END_PROFILE(SMBmkdir);
6247 return;
6250 /****************************************************************************
6251 Reply to a rmdir.
6252 ****************************************************************************/
6254 void reply_rmdir(struct smb_request *req)
6256 connection_struct *conn = req->conn;
6257 struct smb_filename *smb_dname = NULL;
6258 char *directory = NULL;
6259 NTSTATUS status;
6260 TALLOC_CTX *ctx = talloc_tos();
6261 files_struct *fsp = NULL;
6262 int info = 0;
6263 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6264 struct smbd_server_connection *sconn = req->sconn;
6266 START_PROFILE(SMBrmdir);
6268 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6269 STR_TERMINATE, &status);
6270 if (!NT_STATUS_IS_OK(status)) {
6271 reply_nterror(req, status);
6272 goto out;
6275 status = filename_convert(ctx, conn,
6276 directory,
6277 ucf_flags,
6278 NULL,
6279 NULL,
6280 &smb_dname);
6281 if (!NT_STATUS_IS_OK(status)) {
6282 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6283 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6284 ERRSRV, ERRbadpath);
6285 goto out;
6287 reply_nterror(req, status);
6288 goto out;
6291 if (is_ntfs_stream_smb_fname(smb_dname)) {
6292 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6293 goto out;
6296 status = SMB_VFS_CREATE_FILE(
6297 conn, /* conn */
6298 req, /* req */
6299 0, /* root_dir_fid */
6300 smb_dname, /* fname */
6301 DELETE_ACCESS, /* access_mask */
6302 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6303 FILE_SHARE_DELETE),
6304 FILE_OPEN, /* create_disposition*/
6305 FILE_DIRECTORY_FILE, /* create_options */
6306 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6307 0, /* oplock_request */
6308 NULL, /* lease */
6309 0, /* allocation_size */
6310 0, /* private_flags */
6311 NULL, /* sd */
6312 NULL, /* ea_list */
6313 &fsp, /* result */
6314 &info, /* pinfo */
6315 NULL, NULL); /* create context */
6317 if (!NT_STATUS_IS_OK(status)) {
6318 if (open_was_deferred(req->xconn, req->mid)) {
6319 /* We have re-scheduled this call. */
6320 goto out;
6322 reply_nterror(req, status);
6323 goto out;
6326 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6327 if (!NT_STATUS_IS_OK(status)) {
6328 close_file(req, fsp, ERROR_CLOSE);
6329 reply_nterror(req, status);
6330 goto out;
6333 if (!set_delete_on_close(fsp, true,
6334 conn->session_info->security_token,
6335 conn->session_info->unix_token)) {
6336 close_file(req, fsp, ERROR_CLOSE);
6337 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6338 goto out;
6341 status = close_file(req, fsp, NORMAL_CLOSE);
6342 if (!NT_STATUS_IS_OK(status)) {
6343 reply_nterror(req, status);
6344 } else {
6345 reply_outbuf(req, 0, 0);
6348 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6350 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6351 out:
6352 TALLOC_FREE(smb_dname);
6353 END_PROFILE(SMBrmdir);
6354 return;
6357 /*******************************************************************
6358 Resolve wildcards in a filename rename.
6359 ********************************************************************/
6361 static bool resolve_wildcards(TALLOC_CTX *ctx,
6362 const char *name1,
6363 const char *name2,
6364 char **pp_newname)
6366 char *name2_copy = NULL;
6367 char *root1 = NULL;
6368 char *root2 = NULL;
6369 char *ext1 = NULL;
6370 char *ext2 = NULL;
6371 char *p,*p2, *pname1, *pname2;
6373 name2_copy = talloc_strdup(ctx, name2);
6374 if (!name2_copy) {
6375 return False;
6378 pname1 = strrchr_m(name1,'/');
6379 pname2 = strrchr_m(name2_copy,'/');
6381 if (!pname1 || !pname2) {
6382 return False;
6385 /* Truncate the copy of name2 at the last '/' */
6386 *pname2 = '\0';
6388 /* Now go past the '/' */
6389 pname1++;
6390 pname2++;
6392 root1 = talloc_strdup(ctx, pname1);
6393 root2 = talloc_strdup(ctx, pname2);
6395 if (!root1 || !root2) {
6396 return False;
6399 p = strrchr_m(root1,'.');
6400 if (p) {
6401 *p = 0;
6402 ext1 = talloc_strdup(ctx, p+1);
6403 } else {
6404 ext1 = talloc_strdup(ctx, "");
6406 p = strrchr_m(root2,'.');
6407 if (p) {
6408 *p = 0;
6409 ext2 = talloc_strdup(ctx, p+1);
6410 } else {
6411 ext2 = talloc_strdup(ctx, "");
6414 if (!ext1 || !ext2) {
6415 return False;
6418 p = root1;
6419 p2 = root2;
6420 while (*p2) {
6421 if (*p2 == '?') {
6422 /* Hmmm. Should this be mb-aware ? */
6423 *p2 = *p;
6424 p2++;
6425 } else if (*p2 == '*') {
6426 *p2 = '\0';
6427 root2 = talloc_asprintf(ctx, "%s%s",
6428 root2,
6430 if (!root2) {
6431 return False;
6433 break;
6434 } else {
6435 p2++;
6437 if (*p) {
6438 p++;
6442 p = ext1;
6443 p2 = ext2;
6444 while (*p2) {
6445 if (*p2 == '?') {
6446 /* Hmmm. Should this be mb-aware ? */
6447 *p2 = *p;
6448 p2++;
6449 } else if (*p2 == '*') {
6450 *p2 = '\0';
6451 ext2 = talloc_asprintf(ctx, "%s%s",
6452 ext2,
6454 if (!ext2) {
6455 return False;
6457 break;
6458 } else {
6459 p2++;
6461 if (*p) {
6462 p++;
6466 if (*ext2) {
6467 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6468 name2_copy,
6469 root2,
6470 ext2);
6471 } else {
6472 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6473 name2_copy,
6474 root2);
6477 if (!*pp_newname) {
6478 return False;
6481 return True;
6484 /****************************************************************************
6485 Ensure open files have their names updated. Updated to notify other smbd's
6486 asynchronously.
6487 ****************************************************************************/
6489 static void rename_open_files(connection_struct *conn,
6490 struct share_mode_lock *lck,
6491 struct file_id id,
6492 uint32_t orig_name_hash,
6493 const struct smb_filename *smb_fname_dst)
6495 files_struct *fsp;
6496 bool did_rename = False;
6497 NTSTATUS status;
6498 uint32_t new_name_hash = 0;
6500 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6501 fsp = file_find_di_next(fsp)) {
6502 /* fsp_name is a relative path under the fsp. To change this for other
6503 sharepaths we need to manipulate relative paths. */
6504 /* TODO - create the absolute path and manipulate the newname
6505 relative to the sharepath. */
6506 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6507 continue;
6509 if (fsp->name_hash != orig_name_hash) {
6510 continue;
6512 DEBUG(10, ("rename_open_files: renaming file %s "
6513 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6514 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6515 smb_fname_str_dbg(smb_fname_dst)));
6517 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6518 if (NT_STATUS_IS_OK(status)) {
6519 did_rename = True;
6520 new_name_hash = fsp->name_hash;
6524 if (!did_rename) {
6525 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6526 "for %s\n", file_id_string_tos(&id),
6527 smb_fname_str_dbg(smb_fname_dst)));
6530 /* Send messages to all smbd's (not ourself) that the name has changed. */
6531 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6532 orig_name_hash, new_name_hash,
6533 smb_fname_dst);
6537 /****************************************************************************
6538 We need to check if the source path is a parent directory of the destination
6539 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6540 refuse the rename with a sharing violation. Under UNIX the above call can
6541 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6542 probably need to check that the client is a Windows one before disallowing
6543 this as a UNIX client (one with UNIX extensions) can know the source is a
6544 symlink and make this decision intelligently. Found by an excellent bug
6545 report from <AndyLiebman@aol.com>.
6546 ****************************************************************************/
6548 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6549 const struct smb_filename *smb_fname_dst)
6551 const char *psrc = smb_fname_src->base_name;
6552 const char *pdst = smb_fname_dst->base_name;
6553 size_t slen;
6555 if (psrc[0] == '.' && psrc[1] == '/') {
6556 psrc += 2;
6558 if (pdst[0] == '.' && pdst[1] == '/') {
6559 pdst += 2;
6561 if ((slen = strlen(psrc)) > strlen(pdst)) {
6562 return False;
6564 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6568 * Do the notify calls from a rename
6571 static void notify_rename(connection_struct *conn, bool is_dir,
6572 const struct smb_filename *smb_fname_src,
6573 const struct smb_filename *smb_fname_dst)
6575 char *parent_dir_src = NULL;
6576 char *parent_dir_dst = NULL;
6577 uint32_t mask;
6579 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6580 : FILE_NOTIFY_CHANGE_FILE_NAME;
6582 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6583 &parent_dir_src, NULL) ||
6584 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6585 &parent_dir_dst, NULL)) {
6586 goto out;
6589 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6590 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6591 smb_fname_src->base_name);
6592 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6593 smb_fname_dst->base_name);
6595 else {
6596 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6597 smb_fname_src->base_name);
6598 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6599 smb_fname_dst->base_name);
6602 /* this is a strange one. w2k3 gives an additional event for
6603 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6604 files, but not directories */
6605 if (!is_dir) {
6606 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6607 FILE_NOTIFY_CHANGE_ATTRIBUTES
6608 |FILE_NOTIFY_CHANGE_CREATION,
6609 smb_fname_dst->base_name);
6611 out:
6612 TALLOC_FREE(parent_dir_src);
6613 TALLOC_FREE(parent_dir_dst);
6616 /****************************************************************************
6617 Returns an error if the parent directory for a filename is open in an
6618 incompatible way.
6619 ****************************************************************************/
6621 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6622 const struct smb_filename *smb_fname_dst_in)
6624 char *parent_dir = NULL;
6625 struct smb_filename smb_fname_parent;
6626 struct file_id id;
6627 files_struct *fsp = NULL;
6628 int ret;
6630 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6631 &parent_dir, NULL)) {
6632 return NT_STATUS_NO_MEMORY;
6634 ZERO_STRUCT(smb_fname_parent);
6635 smb_fname_parent.base_name = parent_dir;
6637 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6638 if (ret == -1) {
6639 return map_nt_error_from_unix(errno);
6643 * We're only checking on this smbd here, mostly good
6644 * enough.. and will pass tests.
6647 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6648 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6649 fsp = file_find_di_next(fsp)) {
6650 if (fsp->access_mask & DELETE_ACCESS) {
6651 return NT_STATUS_SHARING_VIOLATION;
6654 return NT_STATUS_OK;
6657 /****************************************************************************
6658 Rename an open file - given an fsp.
6659 ****************************************************************************/
6661 NTSTATUS rename_internals_fsp(connection_struct *conn,
6662 files_struct *fsp,
6663 const struct smb_filename *smb_fname_dst_in,
6664 uint32_t attrs,
6665 bool replace_if_exists)
6667 TALLOC_CTX *ctx = talloc_tos();
6668 struct smb_filename *smb_fname_dst = NULL;
6669 NTSTATUS status = NT_STATUS_OK;
6670 struct share_mode_lock *lck = NULL;
6671 uint32_t access_mask = SEC_DIR_ADD_FILE;
6672 bool dst_exists, old_is_stream, new_is_stream;
6674 status = check_name(conn, smb_fname_dst_in);
6675 if (!NT_STATUS_IS_OK(status)) {
6676 return status;
6679 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6680 if (!NT_STATUS_IS_OK(status)) {
6681 return status;
6684 if (file_has_open_streams(fsp)) {
6685 return NT_STATUS_ACCESS_DENIED;
6688 /* Make a copy of the dst smb_fname structs */
6690 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6691 if (smb_fname_dst == NULL) {
6692 status = NT_STATUS_NO_MEMORY;
6693 goto out;
6697 * Check for special case with case preserving and not
6698 * case sensitive. If the new last component differs from the original
6699 * last component only by case, then we should allow
6700 * the rename (user is trying to change the case of the
6701 * filename).
6703 if (!conn->case_sensitive && conn->case_preserve &&
6704 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6705 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6706 char *fname_dst_parent = NULL;
6707 const char *fname_dst_lcomp = NULL;
6708 char *orig_lcomp_path = NULL;
6709 char *orig_lcomp_stream = NULL;
6710 bool ok = true;
6713 * Split off the last component of the processed
6714 * destination name. We will compare this to
6715 * the split components of smb_fname_dst->original_lcomp.
6717 if (!parent_dirname(ctx,
6718 smb_fname_dst->base_name,
6719 &fname_dst_parent,
6720 &fname_dst_lcomp)) {
6721 status = NT_STATUS_NO_MEMORY;
6722 goto out;
6726 * The original_lcomp component contains
6727 * the last_component of the path + stream
6728 * name (if a stream exists).
6730 * Split off the stream name so we
6731 * can check them separately.
6734 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6735 /* POSIX - no stream component. */
6736 orig_lcomp_path = talloc_strdup(ctx,
6737 smb_fname_dst->original_lcomp);
6738 if (orig_lcomp_path == NULL) {
6739 ok = false;
6741 } else {
6742 ok = split_stream_filename(ctx,
6743 smb_fname_dst->original_lcomp,
6744 &orig_lcomp_path,
6745 &orig_lcomp_stream);
6748 if (!ok) {
6749 TALLOC_FREE(fname_dst_parent);
6750 status = NT_STATUS_NO_MEMORY;
6751 goto out;
6754 /* If the base names only differ by case, use original. */
6755 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6756 char *tmp;
6758 * Replace the modified last component with the
6759 * original.
6761 if (!ISDOT(fname_dst_parent)) {
6762 tmp = talloc_asprintf(smb_fname_dst,
6763 "%s/%s",
6764 fname_dst_parent,
6765 orig_lcomp_path);
6766 } else {
6767 tmp = talloc_strdup(smb_fname_dst,
6768 orig_lcomp_path);
6770 if (tmp == NULL) {
6771 status = NT_STATUS_NO_MEMORY;
6772 TALLOC_FREE(fname_dst_parent);
6773 TALLOC_FREE(orig_lcomp_path);
6774 TALLOC_FREE(orig_lcomp_stream);
6775 goto out;
6777 TALLOC_FREE(smb_fname_dst->base_name);
6778 smb_fname_dst->base_name = tmp;
6781 /* If the stream_names only differ by case, use original. */
6782 if(!strcsequal(smb_fname_dst->stream_name,
6783 orig_lcomp_stream)) {
6784 /* Use the original stream. */
6785 char *tmp = talloc_strdup(smb_fname_dst,
6786 orig_lcomp_stream);
6787 if (tmp == NULL) {
6788 status = NT_STATUS_NO_MEMORY;
6789 TALLOC_FREE(fname_dst_parent);
6790 TALLOC_FREE(orig_lcomp_path);
6791 TALLOC_FREE(orig_lcomp_stream);
6792 goto out;
6794 TALLOC_FREE(smb_fname_dst->stream_name);
6795 smb_fname_dst->stream_name = tmp;
6797 TALLOC_FREE(fname_dst_parent);
6798 TALLOC_FREE(orig_lcomp_path);
6799 TALLOC_FREE(orig_lcomp_stream);
6803 * If the src and dest names are identical - including case,
6804 * don't do the rename, just return success.
6807 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6808 strcsequal(fsp->fsp_name->stream_name,
6809 smb_fname_dst->stream_name)) {
6810 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6811 "- returning success\n",
6812 smb_fname_str_dbg(smb_fname_dst)));
6813 status = NT_STATUS_OK;
6814 goto out;
6817 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6818 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6820 /* Return the correct error code if both names aren't streams. */
6821 if (!old_is_stream && new_is_stream) {
6822 status = NT_STATUS_OBJECT_NAME_INVALID;
6823 goto out;
6826 if (old_is_stream && !new_is_stream) {
6827 status = NT_STATUS_INVALID_PARAMETER;
6828 goto out;
6831 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6833 if(!replace_if_exists && dst_exists) {
6834 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6835 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6836 smb_fname_str_dbg(smb_fname_dst)));
6837 status = NT_STATUS_OBJECT_NAME_COLLISION;
6838 goto out;
6841 if (dst_exists) {
6842 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6843 &smb_fname_dst->st);
6844 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6845 fileid);
6846 /* The file can be open when renaming a stream */
6847 if (dst_fsp && !new_is_stream) {
6848 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6849 status = NT_STATUS_ACCESS_DENIED;
6850 goto out;
6854 /* Ensure we have a valid stat struct for the source. */
6855 status = vfs_stat_fsp(fsp);
6856 if (!NT_STATUS_IS_OK(status)) {
6857 goto out;
6860 status = can_rename(conn, fsp, attrs);
6862 if (!NT_STATUS_IS_OK(status)) {
6863 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6864 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6865 smb_fname_str_dbg(smb_fname_dst)));
6866 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6867 status = NT_STATUS_ACCESS_DENIED;
6868 goto out;
6871 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6872 status = NT_STATUS_ACCESS_DENIED;
6873 goto out;
6876 /* Do we have rights to move into the destination ? */
6877 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
6878 /* We're moving a directory. */
6879 access_mask = SEC_DIR_ADD_SUBDIR;
6881 status = check_parent_access(conn,
6882 smb_fname_dst,
6883 access_mask);
6884 if (!NT_STATUS_IS_OK(status)) {
6885 DBG_INFO("check_parent_access on "
6886 "dst %s returned %s\n",
6887 smb_fname_str_dbg(smb_fname_dst),
6888 nt_errstr(status));
6889 goto out;
6892 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6895 * We have the file open ourselves, so not being able to get the
6896 * corresponding share mode lock is a fatal error.
6899 SMB_ASSERT(lck != NULL);
6901 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6902 uint32_t create_options = fsp->fh->private_options;
6904 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6905 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6906 smb_fname_str_dbg(smb_fname_dst)));
6908 if (!fsp->is_directory &&
6909 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6910 (lp_map_archive(SNUM(conn)) ||
6911 lp_store_dos_attributes(SNUM(conn)))) {
6912 /* We must set the archive bit on the newly
6913 renamed file. */
6914 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6915 uint32_t old_dosmode = dos_mode(conn,
6916 smb_fname_dst);
6917 file_set_dosmode(conn,
6918 smb_fname_dst,
6919 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6920 NULL,
6921 true);
6925 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6926 smb_fname_dst);
6928 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6929 smb_fname_dst);
6932 * A rename acts as a new file create w.r.t. allowing an initial delete
6933 * on close, probably because in Windows there is a new handle to the
6934 * new file. If initial delete on close was requested but not
6935 * originally set, we need to set it here. This is probably not 100% correct,
6936 * but will work for the CIFSFS client which in non-posix mode
6937 * depends on these semantics. JRA.
6940 if (create_options & FILE_DELETE_ON_CLOSE) {
6941 status = can_set_delete_on_close(fsp, 0);
6943 if (NT_STATUS_IS_OK(status)) {
6944 /* Note that here we set the *initial* delete on close flag,
6945 * not the regular one. The magic gets handled in close. */
6946 fsp->initial_delete_on_close = True;
6949 TALLOC_FREE(lck);
6950 status = NT_STATUS_OK;
6951 goto out;
6954 TALLOC_FREE(lck);
6956 if (errno == ENOTDIR || errno == EISDIR) {
6957 status = NT_STATUS_OBJECT_NAME_COLLISION;
6958 } else {
6959 status = map_nt_error_from_unix(errno);
6962 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6963 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6964 smb_fname_str_dbg(smb_fname_dst)));
6966 out:
6967 TALLOC_FREE(smb_fname_dst);
6969 return status;
6972 /****************************************************************************
6973 The guts of the rename command, split out so it may be called by the NT SMB
6974 code.
6975 ****************************************************************************/
6977 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6978 connection_struct *conn,
6979 struct smb_request *req,
6980 struct smb_filename *smb_fname_src,
6981 struct smb_filename *smb_fname_dst,
6982 uint32_t attrs,
6983 bool replace_if_exists,
6984 bool src_has_wild,
6985 bool dest_has_wild,
6986 uint32_t access_mask)
6988 char *fname_src_dir = NULL;
6989 struct smb_filename *smb_fname_src_dir = NULL;
6990 char *fname_src_mask = NULL;
6991 int count=0;
6992 NTSTATUS status = NT_STATUS_OK;
6993 struct smb_Dir *dir_hnd = NULL;
6994 const char *dname = NULL;
6995 char *talloced = NULL;
6996 long offset = 0;
6997 int create_options = 0;
6998 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6999 int rc;
7002 * Split the old name into directory and last component
7003 * strings. Note that unix_convert may have stripped off a
7004 * leading ./ from both name and newname if the rename is
7005 * at the root of the share. We need to make sure either both
7006 * name and newname contain a / character or neither of them do
7007 * as this is checked in resolve_wildcards().
7010 /* Split up the directory from the filename/mask. */
7011 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7012 &fname_src_dir, &fname_src_mask);
7013 if (!NT_STATUS_IS_OK(status)) {
7014 status = NT_STATUS_NO_MEMORY;
7015 goto out;
7019 * We should only check the mangled cache
7020 * here if unix_convert failed. This means
7021 * that the path in 'mask' doesn't exist
7022 * on the file system and so we need to look
7023 * for a possible mangle. This patch from
7024 * Tine Smukavec <valentin.smukavec@hermes.si>.
7027 if (!VALID_STAT(smb_fname_src->st) &&
7028 mangle_is_mangled(fname_src_mask, conn->params)) {
7029 char *new_mask = NULL;
7030 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
7031 conn->params);
7032 if (new_mask) {
7033 TALLOC_FREE(fname_src_mask);
7034 fname_src_mask = new_mask;
7038 if (!src_has_wild) {
7039 files_struct *fsp;
7042 * Only one file needs to be renamed. Append the mask back
7043 * onto the directory.
7045 TALLOC_FREE(smb_fname_src->base_name);
7046 if (ISDOT(fname_src_dir)) {
7047 /* Ensure we use canonical names on open. */
7048 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7049 "%s",
7050 fname_src_mask);
7051 } else {
7052 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7053 "%s/%s",
7054 fname_src_dir,
7055 fname_src_mask);
7057 if (!smb_fname_src->base_name) {
7058 status = NT_STATUS_NO_MEMORY;
7059 goto out;
7062 DEBUG(3, ("rename_internals: case_sensitive = %d, "
7063 "case_preserve = %d, short case preserve = %d, "
7064 "directory = %s, newname = %s, "
7065 "last_component_dest = %s\n",
7066 conn->case_sensitive, conn->case_preserve,
7067 conn->short_case_preserve,
7068 smb_fname_str_dbg(smb_fname_src),
7069 smb_fname_str_dbg(smb_fname_dst),
7070 smb_fname_dst->original_lcomp));
7072 /* The dest name still may have wildcards. */
7073 if (dest_has_wild) {
7074 char *fname_dst_mod = NULL;
7075 if (!resolve_wildcards(smb_fname_dst,
7076 smb_fname_src->base_name,
7077 smb_fname_dst->base_name,
7078 &fname_dst_mod)) {
7079 DEBUG(6, ("rename_internals: resolve_wildcards "
7080 "%s %s failed\n",
7081 smb_fname_src->base_name,
7082 smb_fname_dst->base_name));
7083 status = NT_STATUS_NO_MEMORY;
7084 goto out;
7086 TALLOC_FREE(smb_fname_dst->base_name);
7087 smb_fname_dst->base_name = fname_dst_mod;
7090 ZERO_STRUCT(smb_fname_src->st);
7091 if (posix_pathnames) {
7092 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7093 } else {
7094 rc = SMB_VFS_STAT(conn, smb_fname_src);
7096 if (rc == -1) {
7097 status = map_nt_error_from_unix_common(errno);
7098 goto out;
7101 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7102 create_options |= FILE_DIRECTORY_FILE;
7105 status = SMB_VFS_CREATE_FILE(
7106 conn, /* conn */
7107 req, /* req */
7108 0, /* root_dir_fid */
7109 smb_fname_src, /* fname */
7110 access_mask, /* access_mask */
7111 (FILE_SHARE_READ | /* share_access */
7112 FILE_SHARE_WRITE),
7113 FILE_OPEN, /* create_disposition*/
7114 create_options, /* create_options */
7115 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7116 0, /* oplock_request */
7117 NULL, /* lease */
7118 0, /* allocation_size */
7119 0, /* private_flags */
7120 NULL, /* sd */
7121 NULL, /* ea_list */
7122 &fsp, /* result */
7123 NULL, /* pinfo */
7124 NULL, NULL); /* create context */
7126 if (!NT_STATUS_IS_OK(status)) {
7127 DEBUG(3, ("Could not open rename source %s: %s\n",
7128 smb_fname_str_dbg(smb_fname_src),
7129 nt_errstr(status)));
7130 goto out;
7133 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7134 attrs, replace_if_exists);
7136 close_file(req, fsp, NORMAL_CLOSE);
7138 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7139 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7140 smb_fname_str_dbg(smb_fname_dst)));
7142 goto out;
7146 * Wildcards - process each file that matches.
7148 if (strequal(fname_src_mask, "????????.???")) {
7149 TALLOC_FREE(fname_src_mask);
7150 fname_src_mask = talloc_strdup(ctx, "*");
7151 if (!fname_src_mask) {
7152 status = NT_STATUS_NO_MEMORY;
7153 goto out;
7157 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7158 fname_src_dir,
7159 NULL,
7160 NULL,
7161 smb_fname_src->flags);
7162 if (smb_fname_src_dir == NULL) {
7163 status = NT_STATUS_NO_MEMORY;
7164 goto out;
7167 status = check_name(conn, smb_fname_src_dir);
7168 if (!NT_STATUS_IS_OK(status)) {
7169 goto out;
7172 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7173 attrs);
7174 if (dir_hnd == NULL) {
7175 status = map_nt_error_from_unix(errno);
7176 goto out;
7179 status = NT_STATUS_NO_SUCH_FILE;
7181 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7182 * - gentest fix. JRA
7185 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7186 &talloced))) {
7187 files_struct *fsp = NULL;
7188 char *destname = NULL;
7189 bool sysdir_entry = False;
7191 /* Quick check for "." and ".." */
7192 if (ISDOT(dname) || ISDOTDOT(dname)) {
7193 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7194 sysdir_entry = True;
7195 } else {
7196 TALLOC_FREE(talloced);
7197 continue;
7201 if (!is_visible_file(conn, fname_src_dir, dname,
7202 &smb_fname_src->st, false)) {
7203 TALLOC_FREE(talloced);
7204 continue;
7207 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7208 TALLOC_FREE(talloced);
7209 continue;
7212 if (sysdir_entry) {
7213 status = NT_STATUS_OBJECT_NAME_INVALID;
7214 break;
7217 TALLOC_FREE(smb_fname_src->base_name);
7218 if (ISDOT(fname_src_dir)) {
7219 /* Ensure we use canonical names on open. */
7220 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7221 "%s",
7222 dname);
7223 } else {
7224 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7225 "%s/%s",
7226 fname_src_dir,
7227 dname);
7229 if (!smb_fname_src->base_name) {
7230 status = NT_STATUS_NO_MEMORY;
7231 goto out;
7234 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7235 smb_fname_dst->base_name,
7236 &destname)) {
7237 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7238 smb_fname_src->base_name, destname));
7239 TALLOC_FREE(talloced);
7240 continue;
7242 if (!destname) {
7243 status = NT_STATUS_NO_MEMORY;
7244 goto out;
7247 TALLOC_FREE(smb_fname_dst->base_name);
7248 smb_fname_dst->base_name = destname;
7250 ZERO_STRUCT(smb_fname_src->st);
7251 if (posix_pathnames) {
7252 SMB_VFS_LSTAT(conn, smb_fname_src);
7253 } else {
7254 SMB_VFS_STAT(conn, smb_fname_src);
7257 create_options = 0;
7259 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7260 create_options |= FILE_DIRECTORY_FILE;
7263 status = SMB_VFS_CREATE_FILE(
7264 conn, /* conn */
7265 req, /* req */
7266 0, /* root_dir_fid */
7267 smb_fname_src, /* fname */
7268 access_mask, /* access_mask */
7269 (FILE_SHARE_READ | /* share_access */
7270 FILE_SHARE_WRITE),
7271 FILE_OPEN, /* create_disposition*/
7272 create_options, /* create_options */
7273 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7274 0, /* oplock_request */
7275 NULL, /* lease */
7276 0, /* allocation_size */
7277 0, /* private_flags */
7278 NULL, /* sd */
7279 NULL, /* ea_list */
7280 &fsp, /* result */
7281 NULL, /* pinfo */
7282 NULL, NULL); /* create context */
7284 if (!NT_STATUS_IS_OK(status)) {
7285 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7286 "returned %s rename %s -> %s\n",
7287 nt_errstr(status),
7288 smb_fname_str_dbg(smb_fname_src),
7289 smb_fname_str_dbg(smb_fname_dst)));
7290 break;
7293 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7294 dname);
7295 if (!smb_fname_dst->original_lcomp) {
7296 status = NT_STATUS_NO_MEMORY;
7297 goto out;
7300 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7301 attrs, replace_if_exists);
7303 close_file(req, fsp, NORMAL_CLOSE);
7305 if (!NT_STATUS_IS_OK(status)) {
7306 DEBUG(3, ("rename_internals_fsp returned %s for "
7307 "rename %s -> %s\n", nt_errstr(status),
7308 smb_fname_str_dbg(smb_fname_src),
7309 smb_fname_str_dbg(smb_fname_dst)));
7310 break;
7313 count++;
7315 DEBUG(3,("rename_internals: doing rename on %s -> "
7316 "%s\n", smb_fname_str_dbg(smb_fname_src),
7317 smb_fname_str_dbg(smb_fname_src)));
7318 TALLOC_FREE(talloced);
7320 TALLOC_FREE(dir_hnd);
7322 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7323 status = map_nt_error_from_unix(errno);
7326 out:
7327 TALLOC_FREE(talloced);
7328 TALLOC_FREE(smb_fname_src_dir);
7329 TALLOC_FREE(fname_src_dir);
7330 TALLOC_FREE(fname_src_mask);
7331 return status;
7334 /****************************************************************************
7335 Reply to a mv.
7336 ****************************************************************************/
7338 void reply_mv(struct smb_request *req)
7340 connection_struct *conn = req->conn;
7341 char *name = NULL;
7342 char *newname = NULL;
7343 const char *p;
7344 uint32_t attrs;
7345 NTSTATUS status;
7346 bool src_has_wcard = False;
7347 bool dest_has_wcard = False;
7348 TALLOC_CTX *ctx = talloc_tos();
7349 struct smb_filename *smb_fname_src = NULL;
7350 struct smb_filename *smb_fname_dst = NULL;
7351 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
7352 (req->posix_pathnames ?
7353 UCF_UNIX_NAME_LOOKUP :
7354 UCF_COND_ALLOW_WCARD_LCOMP);
7355 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
7356 UCF_SAVE_LCOMP |
7357 (req->posix_pathnames ?
7359 UCF_COND_ALLOW_WCARD_LCOMP);
7360 bool stream_rename = false;
7362 START_PROFILE(SMBmv);
7364 if (req->wct < 1) {
7365 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7366 goto out;
7369 attrs = SVAL(req->vwv+0, 0);
7371 p = (const char *)req->buf + 1;
7372 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7373 &status, &src_has_wcard);
7374 if (!NT_STATUS_IS_OK(status)) {
7375 reply_nterror(req, status);
7376 goto out;
7378 p++;
7379 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7380 &status, &dest_has_wcard);
7381 if (!NT_STATUS_IS_OK(status)) {
7382 reply_nterror(req, status);
7383 goto out;
7386 if (!req->posix_pathnames) {
7387 /* The newname must begin with a ':' if the
7388 name contains a ':'. */
7389 if (strchr_m(name, ':')) {
7390 if (newname[0] != ':') {
7391 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7392 goto out;
7394 stream_rename = true;
7398 status = filename_convert(ctx,
7399 conn,
7400 name,
7401 src_ucf_flags,
7402 NULL,
7403 &src_has_wcard,
7404 &smb_fname_src);
7406 if (!NT_STATUS_IS_OK(status)) {
7407 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7408 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7409 ERRSRV, ERRbadpath);
7410 goto out;
7412 reply_nterror(req, status);
7413 goto out;
7416 status = filename_convert(ctx,
7417 conn,
7418 newname,
7419 dst_ucf_flags,
7420 NULL,
7421 &dest_has_wcard,
7422 &smb_fname_dst);
7424 if (!NT_STATUS_IS_OK(status)) {
7425 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7426 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7427 ERRSRV, ERRbadpath);
7428 goto out;
7430 reply_nterror(req, status);
7431 goto out;
7434 if (stream_rename) {
7435 /* smb_fname_dst->base_name must be the same as
7436 smb_fname_src->base_name. */
7437 TALLOC_FREE(smb_fname_dst->base_name);
7438 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7439 smb_fname_src->base_name);
7440 if (!smb_fname_dst->base_name) {
7441 reply_nterror(req, NT_STATUS_NO_MEMORY);
7442 goto out;
7446 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7447 smb_fname_str_dbg(smb_fname_dst)));
7449 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7450 attrs, False, src_has_wcard, dest_has_wcard,
7451 DELETE_ACCESS);
7452 if (!NT_STATUS_IS_OK(status)) {
7453 if (open_was_deferred(req->xconn, req->mid)) {
7454 /* We have re-scheduled this call. */
7455 goto out;
7457 reply_nterror(req, status);
7458 goto out;
7461 reply_outbuf(req, 0, 0);
7462 out:
7463 TALLOC_FREE(smb_fname_src);
7464 TALLOC_FREE(smb_fname_dst);
7465 END_PROFILE(SMBmv);
7466 return;
7469 /*******************************************************************
7470 Copy a file as part of a reply_copy.
7471 ******************************************************************/
7474 * TODO: check error codes on all callers
7477 NTSTATUS copy_file(TALLOC_CTX *ctx,
7478 connection_struct *conn,
7479 struct smb_filename *smb_fname_src,
7480 struct smb_filename *smb_fname_dst,
7481 int ofun,
7482 int count,
7483 bool target_is_directory)
7485 struct smb_filename *smb_fname_dst_tmp = NULL;
7486 off_t ret=-1;
7487 files_struct *fsp1,*fsp2;
7488 uint32_t dosattrs;
7489 uint32_t new_create_disposition;
7490 NTSTATUS status;
7493 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7494 if (smb_fname_dst_tmp == NULL) {
7495 return NT_STATUS_NO_MEMORY;
7499 * If the target is a directory, extract the last component from the
7500 * src filename and append it to the dst filename
7502 if (target_is_directory) {
7503 const char *p;
7505 /* dest/target can't be a stream if it's a directory. */
7506 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7508 p = strrchr_m(smb_fname_src->base_name,'/');
7509 if (p) {
7510 p++;
7511 } else {
7512 p = smb_fname_src->base_name;
7514 smb_fname_dst_tmp->base_name =
7515 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7517 if (!smb_fname_dst_tmp->base_name) {
7518 status = NT_STATUS_NO_MEMORY;
7519 goto out;
7523 status = vfs_file_exist(conn, smb_fname_src);
7524 if (!NT_STATUS_IS_OK(status)) {
7525 goto out;
7528 if (!target_is_directory && count) {
7529 new_create_disposition = FILE_OPEN;
7530 } else {
7531 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7532 0, ofun,
7533 NULL, NULL,
7534 &new_create_disposition,
7535 NULL,
7536 NULL)) {
7537 status = NT_STATUS_INVALID_PARAMETER;
7538 goto out;
7542 /* Open the src file for reading. */
7543 status = SMB_VFS_CREATE_FILE(
7544 conn, /* conn */
7545 NULL, /* req */
7546 0, /* root_dir_fid */
7547 smb_fname_src, /* fname */
7548 FILE_GENERIC_READ, /* access_mask */
7549 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7550 FILE_OPEN, /* create_disposition*/
7551 0, /* create_options */
7552 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7553 INTERNAL_OPEN_ONLY, /* oplock_request */
7554 NULL, /* lease */
7555 0, /* allocation_size */
7556 0, /* private_flags */
7557 NULL, /* sd */
7558 NULL, /* ea_list */
7559 &fsp1, /* result */
7560 NULL, /* psbuf */
7561 NULL, NULL); /* create context */
7563 if (!NT_STATUS_IS_OK(status)) {
7564 goto out;
7567 dosattrs = dos_mode(conn, smb_fname_src);
7569 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7570 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7573 /* Open the dst file for writing. */
7574 status = SMB_VFS_CREATE_FILE(
7575 conn, /* conn */
7576 NULL, /* req */
7577 0, /* root_dir_fid */
7578 smb_fname_dst, /* fname */
7579 FILE_GENERIC_WRITE, /* access_mask */
7580 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7581 new_create_disposition, /* create_disposition*/
7582 0, /* create_options */
7583 dosattrs, /* file_attributes */
7584 INTERNAL_OPEN_ONLY, /* oplock_request */
7585 NULL, /* lease */
7586 0, /* allocation_size */
7587 0, /* private_flags */
7588 NULL, /* sd */
7589 NULL, /* ea_list */
7590 &fsp2, /* result */
7591 NULL, /* psbuf */
7592 NULL, NULL); /* create context */
7594 if (!NT_STATUS_IS_OK(status)) {
7595 close_file(NULL, fsp1, ERROR_CLOSE);
7596 goto out;
7599 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7600 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7601 if (ret == -1) {
7602 DEBUG(0, ("error - vfs lseek returned error %s\n",
7603 strerror(errno)));
7604 status = map_nt_error_from_unix(errno);
7605 close_file(NULL, fsp1, ERROR_CLOSE);
7606 close_file(NULL, fsp2, ERROR_CLOSE);
7607 goto out;
7611 /* Do the actual copy. */
7612 if (smb_fname_src->st.st_ex_size) {
7613 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7614 } else {
7615 ret = 0;
7618 close_file(NULL, fsp1, NORMAL_CLOSE);
7620 /* Ensure the modtime is set correctly on the destination file. */
7621 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7624 * As we are opening fsp1 read-only we only expect
7625 * an error on close on fsp2 if we are out of space.
7626 * Thus we don't look at the error return from the
7627 * close of fsp1.
7629 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7631 if (!NT_STATUS_IS_OK(status)) {
7632 goto out;
7635 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7636 status = NT_STATUS_DISK_FULL;
7637 goto out;
7640 status = NT_STATUS_OK;
7642 out:
7643 TALLOC_FREE(smb_fname_dst_tmp);
7644 return status;
7647 /****************************************************************************
7648 Reply to a file copy.
7649 ****************************************************************************/
7651 void reply_copy(struct smb_request *req)
7653 connection_struct *conn = req->conn;
7654 struct smb_filename *smb_fname_src = NULL;
7655 struct smb_filename *smb_fname_src_dir = NULL;
7656 struct smb_filename *smb_fname_dst = NULL;
7657 char *fname_src = NULL;
7658 char *fname_dst = NULL;
7659 char *fname_src_mask = NULL;
7660 char *fname_src_dir = NULL;
7661 const char *p;
7662 int count=0;
7663 int error = ERRnoaccess;
7664 int tid2;
7665 int ofun;
7666 int flags;
7667 bool target_is_directory=False;
7668 bool source_has_wild = False;
7669 bool dest_has_wild = False;
7670 NTSTATUS status;
7671 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7672 ucf_flags_from_smb_request(req);
7673 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7674 ucf_flags_from_smb_request(req);
7675 TALLOC_CTX *ctx = talloc_tos();
7677 START_PROFILE(SMBcopy);
7679 if (req->wct < 3) {
7680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7681 goto out;
7684 tid2 = SVAL(req->vwv+0, 0);
7685 ofun = SVAL(req->vwv+1, 0);
7686 flags = SVAL(req->vwv+2, 0);
7688 p = (const char *)req->buf;
7689 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7690 &status, &source_has_wild);
7691 if (!NT_STATUS_IS_OK(status)) {
7692 reply_nterror(req, status);
7693 goto out;
7695 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7696 &status, &dest_has_wild);
7697 if (!NT_STATUS_IS_OK(status)) {
7698 reply_nterror(req, status);
7699 goto out;
7702 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7704 if (tid2 != conn->cnum) {
7705 /* can't currently handle inter share copies XXXX */
7706 DEBUG(3,("Rejecting inter-share copy\n"));
7707 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7708 goto out;
7711 status = filename_convert(ctx, conn,
7712 fname_src,
7713 ucf_flags_src,
7714 NULL,
7715 &source_has_wild,
7716 &smb_fname_src);
7717 if (!NT_STATUS_IS_OK(status)) {
7718 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7719 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7720 ERRSRV, ERRbadpath);
7721 goto out;
7723 reply_nterror(req, status);
7724 goto out;
7727 status = filename_convert(ctx, conn,
7728 fname_dst,
7729 ucf_flags_dst,
7730 NULL,
7731 &dest_has_wild,
7732 &smb_fname_dst);
7733 if (!NT_STATUS_IS_OK(status)) {
7734 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7735 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7736 ERRSRV, ERRbadpath);
7737 goto out;
7739 reply_nterror(req, status);
7740 goto out;
7743 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7745 if ((flags&1) && target_is_directory) {
7746 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7747 goto out;
7750 if ((flags&2) && !target_is_directory) {
7751 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7752 goto out;
7755 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7756 /* wants a tree copy! XXXX */
7757 DEBUG(3,("Rejecting tree copy\n"));
7758 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7759 goto out;
7762 /* Split up the directory from the filename/mask. */
7763 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7764 &fname_src_dir, &fname_src_mask);
7765 if (!NT_STATUS_IS_OK(status)) {
7766 reply_nterror(req, NT_STATUS_NO_MEMORY);
7767 goto out;
7771 * We should only check the mangled cache
7772 * here if unix_convert failed. This means
7773 * that the path in 'mask' doesn't exist
7774 * on the file system and so we need to look
7775 * for a possible mangle. This patch from
7776 * Tine Smukavec <valentin.smukavec@hermes.si>.
7778 if (!VALID_STAT(smb_fname_src->st) &&
7779 mangle_is_mangled(fname_src_mask, conn->params)) {
7780 char *new_mask = NULL;
7781 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7782 &new_mask, conn->params);
7784 /* Use demangled name if one was successfully found. */
7785 if (new_mask) {
7786 TALLOC_FREE(fname_src_mask);
7787 fname_src_mask = new_mask;
7791 if (!source_has_wild) {
7794 * Only one file needs to be copied. Append the mask back onto
7795 * the directory.
7797 TALLOC_FREE(smb_fname_src->base_name);
7798 if (ISDOT(fname_src_dir)) {
7799 /* Ensure we use canonical names on open. */
7800 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7801 "%s",
7802 fname_src_mask);
7803 } else {
7804 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7805 "%s/%s",
7806 fname_src_dir,
7807 fname_src_mask);
7809 if (!smb_fname_src->base_name) {
7810 reply_nterror(req, NT_STATUS_NO_MEMORY);
7811 goto out;
7814 if (dest_has_wild) {
7815 char *fname_dst_mod = NULL;
7816 if (!resolve_wildcards(smb_fname_dst,
7817 smb_fname_src->base_name,
7818 smb_fname_dst->base_name,
7819 &fname_dst_mod)) {
7820 reply_nterror(req, NT_STATUS_NO_MEMORY);
7821 goto out;
7823 TALLOC_FREE(smb_fname_dst->base_name);
7824 smb_fname_dst->base_name = fname_dst_mod;
7827 status = check_name(conn, smb_fname_src);
7828 if (!NT_STATUS_IS_OK(status)) {
7829 reply_nterror(req, status);
7830 goto out;
7833 status = check_name(conn, smb_fname_dst);
7834 if (!NT_STATUS_IS_OK(status)) {
7835 reply_nterror(req, status);
7836 goto out;
7839 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7840 ofun, count, target_is_directory);
7842 if(!NT_STATUS_IS_OK(status)) {
7843 reply_nterror(req, status);
7844 goto out;
7845 } else {
7846 count++;
7848 } else {
7849 struct smb_Dir *dir_hnd = NULL;
7850 const char *dname = NULL;
7851 char *talloced = NULL;
7852 long offset = 0;
7855 * There is a wildcard that requires us to actually read the
7856 * src dir and copy each file matching the mask to the dst.
7857 * Right now streams won't be copied, but this could
7858 * presumably be added with a nested loop for reach dir entry.
7860 SMB_ASSERT(!smb_fname_src->stream_name);
7861 SMB_ASSERT(!smb_fname_dst->stream_name);
7863 smb_fname_src->stream_name = NULL;
7864 smb_fname_dst->stream_name = NULL;
7866 if (strequal(fname_src_mask,"????????.???")) {
7867 TALLOC_FREE(fname_src_mask);
7868 fname_src_mask = talloc_strdup(ctx, "*");
7869 if (!fname_src_mask) {
7870 reply_nterror(req, NT_STATUS_NO_MEMORY);
7871 goto out;
7875 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7876 fname_src_dir,
7877 NULL,
7878 NULL,
7879 smb_fname_src->flags);
7880 if (smb_fname_src_dir == NULL) {
7881 reply_nterror(req, NT_STATUS_NO_MEMORY);
7882 goto out;
7885 status = check_name(conn, smb_fname_src_dir);
7886 if (!NT_STATUS_IS_OK(status)) {
7887 reply_nterror(req, status);
7888 goto out;
7891 dir_hnd = OpenDir(ctx,
7892 conn,
7893 smb_fname_src_dir,
7894 fname_src_mask,
7896 if (dir_hnd == NULL) {
7897 status = map_nt_error_from_unix(errno);
7898 reply_nterror(req, status);
7899 goto out;
7902 error = ERRbadfile;
7904 /* Iterate over the src dir copying each entry to the dst. */
7905 while ((dname = ReadDirName(dir_hnd, &offset,
7906 &smb_fname_src->st, &talloced))) {
7907 char *destname = NULL;
7909 if (ISDOT(dname) || ISDOTDOT(dname)) {
7910 TALLOC_FREE(talloced);
7911 continue;
7914 if (!is_visible_file(conn, fname_src_dir, dname,
7915 &smb_fname_src->st, false)) {
7916 TALLOC_FREE(talloced);
7917 continue;
7920 if(!mask_match(dname, fname_src_mask,
7921 conn->case_sensitive)) {
7922 TALLOC_FREE(talloced);
7923 continue;
7926 error = ERRnoaccess;
7928 /* Get the src smb_fname struct setup. */
7929 TALLOC_FREE(smb_fname_src->base_name);
7930 if (ISDOT(fname_src_dir)) {
7931 /* Ensure we use canonical names on open. */
7932 smb_fname_src->base_name =
7933 talloc_asprintf(smb_fname_src, "%s",
7934 dname);
7935 } else {
7936 smb_fname_src->base_name =
7937 talloc_asprintf(smb_fname_src, "%s/%s",
7938 fname_src_dir, dname);
7941 if (!smb_fname_src->base_name) {
7942 TALLOC_FREE(dir_hnd);
7943 TALLOC_FREE(talloced);
7944 reply_nterror(req, NT_STATUS_NO_MEMORY);
7945 goto out;
7948 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7949 smb_fname_dst->base_name,
7950 &destname)) {
7951 TALLOC_FREE(talloced);
7952 continue;
7954 if (!destname) {
7955 TALLOC_FREE(dir_hnd);
7956 TALLOC_FREE(talloced);
7957 reply_nterror(req, NT_STATUS_NO_MEMORY);
7958 goto out;
7961 TALLOC_FREE(smb_fname_dst->base_name);
7962 smb_fname_dst->base_name = destname;
7964 status = check_name(conn, smb_fname_src);
7965 if (!NT_STATUS_IS_OK(status)) {
7966 TALLOC_FREE(dir_hnd);
7967 TALLOC_FREE(talloced);
7968 reply_nterror(req, status);
7969 goto out;
7972 status = check_name(conn, smb_fname_dst);
7973 if (!NT_STATUS_IS_OK(status)) {
7974 TALLOC_FREE(dir_hnd);
7975 TALLOC_FREE(talloced);
7976 reply_nterror(req, status);
7977 goto out;
7980 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7981 smb_fname_src->base_name,
7982 smb_fname_dst->base_name));
7984 status = copy_file(ctx, conn, smb_fname_src,
7985 smb_fname_dst, ofun, count,
7986 target_is_directory);
7987 if (NT_STATUS_IS_OK(status)) {
7988 count++;
7991 TALLOC_FREE(talloced);
7993 TALLOC_FREE(dir_hnd);
7996 if (count == 0) {
7997 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7998 goto out;
8001 reply_outbuf(req, 1, 0);
8002 SSVAL(req->outbuf,smb_vwv0,count);
8003 out:
8004 TALLOC_FREE(smb_fname_src);
8005 TALLOC_FREE(smb_fname_src_dir);
8006 TALLOC_FREE(smb_fname_dst);
8007 TALLOC_FREE(fname_src);
8008 TALLOC_FREE(fname_dst);
8009 TALLOC_FREE(fname_src_mask);
8010 TALLOC_FREE(fname_src_dir);
8012 END_PROFILE(SMBcopy);
8013 return;
8016 #undef DBGC_CLASS
8017 #define DBGC_CLASS DBGC_LOCKING
8019 /****************************************************************************
8020 Get a lock pid, dealing with large count requests.
8021 ****************************************************************************/
8023 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
8024 bool large_file_format)
8026 if(!large_file_format)
8027 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
8028 else
8029 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
8032 /****************************************************************************
8033 Get a lock count, dealing with large count requests.
8034 ****************************************************************************/
8036 uint64_t get_lock_count(const uint8_t *data, int data_offset,
8037 bool large_file_format)
8039 uint64_t count = 0;
8041 if(!large_file_format) {
8042 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
8043 } else {
8045 * No BVAL, this is reversed!
8047 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
8048 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
8051 return count;
8054 /****************************************************************************
8055 Get a lock offset, dealing with large offset requests.
8056 ****************************************************************************/
8058 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
8059 bool large_file_format)
8061 uint64_t offset = 0;
8063 if(!large_file_format) {
8064 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
8065 } else {
8067 * No BVAL, this is reversed!
8069 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
8070 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
8073 return offset;
8076 NTSTATUS smbd_do_locking(struct smb_request *req,
8077 files_struct *fsp,
8078 uint8_t type,
8079 int32_t timeout,
8080 uint16_t num_locks,
8081 struct smbd_lock_element *locks,
8082 bool *async)
8084 connection_struct *conn = req->conn;
8085 int i;
8086 NTSTATUS status = NT_STATUS_OK;
8088 *async = false;
8090 /* Setup the timeout in seconds. */
8092 if (!lp_blocking_locks(SNUM(conn))) {
8093 timeout = 0;
8096 for(i = 0; i < (int)num_locks; i++) {
8097 struct smbd_lock_element *e = &locks[i];
8099 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8100 "%llu, file %s timeout = %d\n",
8101 (double)e->offset,
8102 (double)e->count,
8103 (unsigned long long)e->smblctx,
8104 fsp_str_dbg(fsp),
8105 (int)timeout));
8107 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8108 struct blocking_lock_record *blr = NULL;
8110 if (num_locks > 1) {
8112 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8113 * if the lock vector contains one entry. When given multiple cancel
8114 * requests in a single PDU we expect the server to return an
8115 * error. Windows servers seem to accept the request but only
8116 * cancel the first lock.
8117 * JRA - Do what Windows does (tm) :-).
8120 #if 0
8121 /* MS-CIFS (2.2.4.32.1) behavior. */
8122 return NT_STATUS_DOS(ERRDOS,
8123 ERRcancelviolation);
8124 #else
8125 /* Windows behavior. */
8126 if (i != 0) {
8127 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8128 "cancel request\n"));
8129 continue;
8131 #endif
8134 if (lp_blocking_locks(SNUM(conn))) {
8136 /* Schedule a message to ourselves to
8137 remove the blocking lock record and
8138 return the right error. */
8140 blr = blocking_lock_cancel_smb1(fsp,
8141 e->smblctx,
8142 e->offset,
8143 e->count,
8144 WINDOWS_LOCK,
8145 type,
8146 NT_STATUS_FILE_LOCK_CONFLICT);
8147 if (blr == NULL) {
8148 return NT_STATUS_DOS(
8149 ERRDOS,
8150 ERRcancelviolation);
8153 /* Remove a matching pending lock. */
8154 status = do_lock_cancel(fsp,
8155 e->smblctx,
8156 e->count,
8157 e->offset,
8158 WINDOWS_LOCK);
8159 } else {
8160 bool blocking_lock = timeout ? true : false;
8161 bool defer_lock = false;
8162 struct byte_range_lock *br_lck;
8163 uint64_t block_smblctx;
8165 br_lck = do_lock(req->sconn->msg_ctx,
8166 fsp,
8167 e->smblctx,
8168 e->count,
8169 e->offset,
8170 e->brltype,
8171 WINDOWS_LOCK,
8172 blocking_lock,
8173 &status,
8174 &block_smblctx);
8176 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8177 /* Windows internal resolution for blocking locks seems
8178 to be about 200ms... Don't wait for less than that. JRA. */
8179 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8180 timeout = lp_lock_spin_time();
8182 defer_lock = true;
8185 /* If a lock sent with timeout of zero would fail, and
8186 * this lock has been requested multiple times,
8187 * according to brl_lock_failed() we convert this
8188 * request to a blocking lock with a timeout of between
8189 * 150 - 300 milliseconds.
8191 * If lp_lock_spin_time() has been set to 0, we skip
8192 * this blocking retry and fail immediately.
8194 * Replacement for do_lock_spin(). JRA. */
8196 if (!req->sconn->using_smb2 &&
8197 br_lck && lp_blocking_locks(SNUM(conn)) &&
8198 lp_lock_spin_time() && !blocking_lock &&
8199 NT_STATUS_EQUAL((status),
8200 NT_STATUS_FILE_LOCK_CONFLICT))
8202 defer_lock = true;
8203 timeout = lp_lock_spin_time();
8206 if (br_lck && defer_lock) {
8208 * A blocking lock was requested. Package up
8209 * this smb into a queued request and push it
8210 * onto the blocking lock queue.
8212 if(push_blocking_lock_request(br_lck,
8213 req,
8214 fsp,
8215 timeout,
8217 e->smblctx,
8218 e->brltype,
8219 WINDOWS_LOCK,
8220 e->offset,
8221 e->count,
8222 block_smblctx)) {
8223 TALLOC_FREE(br_lck);
8224 *async = true;
8225 return NT_STATUS_OK;
8229 TALLOC_FREE(br_lck);
8232 if (!NT_STATUS_IS_OK(status)) {
8233 break;
8237 /* If any of the above locks failed, then we must unlock
8238 all of the previous locks (X/Open spec). */
8240 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8242 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8243 i = -1; /* we want to skip the for loop */
8247 * Ensure we don't do a remove on the lock that just failed,
8248 * as under POSIX rules, if we have a lock already there, we
8249 * will delete it (and we shouldn't) .....
8251 for(i--; i >= 0; i--) {
8252 struct smbd_lock_element *e = &locks[i];
8254 do_unlock(req->sconn->msg_ctx,
8255 fsp,
8256 e->smblctx,
8257 e->count,
8258 e->offset,
8259 WINDOWS_LOCK);
8261 return status;
8264 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8265 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8267 return NT_STATUS_OK;
8270 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8271 files_struct *fsp,
8272 uint16_t num_ulocks,
8273 struct smbd_lock_element *ulocks)
8275 int i;
8277 for(i = 0; i < (int)num_ulocks; i++) {
8278 struct smbd_lock_element *e = &ulocks[i];
8279 NTSTATUS status;
8281 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8282 "pid %u, file %s\n", __func__,
8283 (double)e->offset,
8284 (double)e->count,
8285 (unsigned int)e->smblctx,
8286 fsp_str_dbg(fsp)));
8288 if (e->brltype != UNLOCK_LOCK) {
8289 /* this can only happen with SMB2 */
8290 return NT_STATUS_INVALID_PARAMETER;
8293 status = do_unlock(req->sconn->msg_ctx,
8294 fsp,
8295 e->smblctx,
8296 e->count,
8297 e->offset,
8298 WINDOWS_LOCK);
8300 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8301 nt_errstr(status)));
8303 if (!NT_STATUS_IS_OK(status)) {
8304 return status;
8308 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8309 num_ulocks));
8311 return NT_STATUS_OK;
8314 /****************************************************************************
8315 Reply to a lockingX request.
8316 ****************************************************************************/
8318 void reply_lockingX(struct smb_request *req)
8320 connection_struct *conn = req->conn;
8321 files_struct *fsp;
8322 unsigned char locktype;
8323 unsigned char oplocklevel;
8324 uint16_t num_ulocks;
8325 uint16_t num_locks;
8326 int32_t lock_timeout;
8327 int i;
8328 const uint8_t *data;
8329 bool large_file_format;
8330 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8331 struct smbd_lock_element *ulocks;
8332 struct smbd_lock_element *locks;
8333 bool async = false;
8335 START_PROFILE(SMBlockingX);
8337 if (req->wct < 8) {
8338 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8339 END_PROFILE(SMBlockingX);
8340 return;
8343 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8344 locktype = CVAL(req->vwv+3, 0);
8345 oplocklevel = CVAL(req->vwv+3, 1);
8346 num_ulocks = SVAL(req->vwv+6, 0);
8347 num_locks = SVAL(req->vwv+7, 0);
8348 lock_timeout = IVAL(req->vwv+4, 0);
8349 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8351 if (!check_fsp(conn, req, fsp)) {
8352 END_PROFILE(SMBlockingX);
8353 return;
8356 data = req->buf;
8358 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8359 /* we don't support these - and CANCEL_LOCK makes w2k
8360 and XP reboot so I don't really want to be
8361 compatible! (tridge) */
8362 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8363 END_PROFILE(SMBlockingX);
8364 return;
8367 /* Check if this is an oplock break on a file
8368 we have granted an oplock on.
8370 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8371 /* Client can insist on breaking to none. */
8372 bool break_to_none = (oplocklevel == 0);
8373 bool result;
8375 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8376 "for %s\n", (unsigned int)oplocklevel,
8377 fsp_fnum_dbg(fsp)));
8380 * Make sure we have granted an exclusive or batch oplock on
8381 * this file.
8384 if (fsp->oplock_type == 0) {
8386 /* The Samba4 nbench simulator doesn't understand
8387 the difference between break to level2 and break
8388 to none from level2 - it sends oplock break
8389 replies in both cases. Don't keep logging an error
8390 message here - just ignore it. JRA. */
8392 DEBUG(5,("reply_lockingX: Error : oplock break from "
8393 "client for %s (oplock=%d) and no "
8394 "oplock granted on this file (%s).\n",
8395 fsp_fnum_dbg(fsp), fsp->oplock_type,
8396 fsp_str_dbg(fsp)));
8398 /* if this is a pure oplock break request then don't
8399 * send a reply */
8400 if (num_locks == 0 && num_ulocks == 0) {
8401 END_PROFILE(SMBlockingX);
8402 return;
8403 } else {
8404 END_PROFILE(SMBlockingX);
8405 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8406 return;
8410 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8411 (break_to_none)) {
8412 result = remove_oplock(fsp);
8413 } else {
8414 result = downgrade_oplock(fsp);
8417 if (!result) {
8418 DEBUG(0, ("reply_lockingX: error in removing "
8419 "oplock on file %s\n", fsp_str_dbg(fsp)));
8420 /* Hmmm. Is this panic justified? */
8421 smb_panic("internal tdb error");
8424 /* if this is a pure oplock break request then don't send a
8425 * reply */
8426 if (num_locks == 0 && num_ulocks == 0) {
8427 /* Sanity check - ensure a pure oplock break is not a
8428 chained request. */
8429 if (CVAL(req->vwv+0, 0) != 0xff) {
8430 DEBUG(0,("reply_lockingX: Error : pure oplock "
8431 "break is a chained %d request !\n",
8432 (unsigned int)CVAL(req->vwv+0, 0)));
8434 END_PROFILE(SMBlockingX);
8435 return;
8439 if (req->buflen <
8440 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8441 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8442 END_PROFILE(SMBlockingX);
8443 return;
8446 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8447 if (ulocks == NULL) {
8448 reply_nterror(req, NT_STATUS_NO_MEMORY);
8449 END_PROFILE(SMBlockingX);
8450 return;
8453 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8454 if (locks == NULL) {
8455 reply_nterror(req, NT_STATUS_NO_MEMORY);
8456 END_PROFILE(SMBlockingX);
8457 return;
8460 /* Data now points at the beginning of the list
8461 of smb_unlkrng structs */
8462 for(i = 0; i < (int)num_ulocks; i++) {
8463 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8464 ulocks[i].count = get_lock_count(data, i, large_file_format);
8465 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8466 ulocks[i].brltype = UNLOCK_LOCK;
8469 /* Now do any requested locks */
8470 data += ((large_file_format ? 20 : 10)*num_ulocks);
8472 /* Data now points at the beginning of the list
8473 of smb_lkrng structs */
8475 for(i = 0; i < (int)num_locks; i++) {
8476 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8477 locks[i].count = get_lock_count(data, i, large_file_format);
8478 locks[i].offset = get_lock_offset(data, i, large_file_format);
8480 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8481 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8482 locks[i].brltype = PENDING_READ_LOCK;
8483 } else {
8484 locks[i].brltype = READ_LOCK;
8486 } else {
8487 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8488 locks[i].brltype = PENDING_WRITE_LOCK;
8489 } else {
8490 locks[i].brltype = WRITE_LOCK;
8495 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8496 if (!NT_STATUS_IS_OK(status)) {
8497 END_PROFILE(SMBlockingX);
8498 reply_nterror(req, status);
8499 return;
8502 status = smbd_do_locking(req, fsp,
8503 locktype, lock_timeout,
8504 num_locks, locks,
8505 &async);
8506 if (!NT_STATUS_IS_OK(status)) {
8507 END_PROFILE(SMBlockingX);
8508 reply_nterror(req, status);
8509 return;
8511 if (async) {
8512 END_PROFILE(SMBlockingX);
8513 return;
8516 reply_outbuf(req, 2, 0);
8517 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8518 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8520 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8521 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8523 END_PROFILE(SMBlockingX);
8526 #undef DBGC_CLASS
8527 #define DBGC_CLASS DBGC_ALL
8529 /****************************************************************************
8530 Reply to a SMBreadbmpx (read block multiplex) request.
8531 Always reply with an error, if someone has a platform really needs this,
8532 please contact vl@samba.org
8533 ****************************************************************************/
8535 void reply_readbmpx(struct smb_request *req)
8537 START_PROFILE(SMBreadBmpx);
8538 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8539 END_PROFILE(SMBreadBmpx);
8540 return;
8543 /****************************************************************************
8544 Reply to a SMBreadbs (read block multiplex secondary) request.
8545 Always reply with an error, if someone has a platform really needs this,
8546 please contact vl@samba.org
8547 ****************************************************************************/
8549 void reply_readbs(struct smb_request *req)
8551 START_PROFILE(SMBreadBs);
8552 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8553 END_PROFILE(SMBreadBs);
8554 return;
8557 /****************************************************************************
8558 Reply to a SMBsetattrE.
8559 ****************************************************************************/
8561 void reply_setattrE(struct smb_request *req)
8563 connection_struct *conn = req->conn;
8564 struct smb_file_time ft;
8565 files_struct *fsp;
8566 NTSTATUS status;
8568 START_PROFILE(SMBsetattrE);
8569 ZERO_STRUCT(ft);
8571 if (req->wct < 7) {
8572 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8573 goto out;
8576 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8578 if(!fsp || (fsp->conn != conn)) {
8579 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8580 goto out;
8584 * Convert the DOS times into unix times.
8587 ft.atime = convert_time_t_to_timespec(
8588 srv_make_unix_date2(req->vwv+3));
8589 ft.mtime = convert_time_t_to_timespec(
8590 srv_make_unix_date2(req->vwv+5));
8591 ft.create_time = convert_time_t_to_timespec(
8592 srv_make_unix_date2(req->vwv+1));
8594 reply_outbuf(req, 0, 0);
8597 * Patch from Ray Frush <frush@engr.colostate.edu>
8598 * Sometimes times are sent as zero - ignore them.
8601 /* Ensure we have a valid stat struct for the source. */
8602 status = vfs_stat_fsp(fsp);
8603 if (!NT_STATUS_IS_OK(status)) {
8604 reply_nterror(req, status);
8605 goto out;
8608 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8609 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8610 goto out;
8613 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8614 if (!NT_STATUS_IS_OK(status)) {
8615 reply_nterror(req, status);
8616 goto out;
8619 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8620 " createtime=%u\n",
8621 fsp_fnum_dbg(fsp),
8622 (unsigned int)ft.atime.tv_sec,
8623 (unsigned int)ft.mtime.tv_sec,
8624 (unsigned int)ft.create_time.tv_sec
8626 out:
8627 END_PROFILE(SMBsetattrE);
8628 return;
8632 /* Back from the dead for OS/2..... JRA. */
8634 /****************************************************************************
8635 Reply to a SMBwritebmpx (write block multiplex primary) request.
8636 Always reply with an error, if someone has a platform really needs this,
8637 please contact vl@samba.org
8638 ****************************************************************************/
8640 void reply_writebmpx(struct smb_request *req)
8642 START_PROFILE(SMBwriteBmpx);
8643 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8644 END_PROFILE(SMBwriteBmpx);
8645 return;
8648 /****************************************************************************
8649 Reply to a SMBwritebs (write block multiplex secondary) request.
8650 Always reply with an error, if someone has a platform really needs this,
8651 please contact vl@samba.org
8652 ****************************************************************************/
8654 void reply_writebs(struct smb_request *req)
8656 START_PROFILE(SMBwriteBs);
8657 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8658 END_PROFILE(SMBwriteBs);
8659 return;
8662 /****************************************************************************
8663 Reply to a SMBgetattrE.
8664 ****************************************************************************/
8666 void reply_getattrE(struct smb_request *req)
8668 connection_struct *conn = req->conn;
8669 int mode;
8670 files_struct *fsp;
8671 struct timespec create_ts;
8673 START_PROFILE(SMBgetattrE);
8675 if (req->wct < 1) {
8676 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8677 END_PROFILE(SMBgetattrE);
8678 return;
8681 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8683 if(!fsp || (fsp->conn != conn)) {
8684 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8685 END_PROFILE(SMBgetattrE);
8686 return;
8689 /* Do an fstat on this file */
8690 if(fsp_stat(fsp)) {
8691 reply_nterror(req, map_nt_error_from_unix(errno));
8692 END_PROFILE(SMBgetattrE);
8693 return;
8696 mode = dos_mode(conn, fsp->fsp_name);
8699 * Convert the times into dos times. Set create
8700 * date to be last modify date as UNIX doesn't save
8701 * this.
8704 reply_outbuf(req, 11, 0);
8706 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8707 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8708 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8709 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8710 /* Should we check pending modtime here ? JRA */
8711 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8712 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8714 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8715 SIVAL(req->outbuf, smb_vwv6, 0);
8716 SIVAL(req->outbuf, smb_vwv8, 0);
8717 } else {
8718 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8719 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8720 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8722 SSVAL(req->outbuf,smb_vwv10, mode);
8724 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8726 END_PROFILE(SMBgetattrE);
8727 return;