s4:dsdb/common: prepare dsdb_user_obj_set_defaults() for tombstone reanimation
[Samba.git] / source3 / smbd / reply.c
blob0b7a4fbd32991b67ae9d8456ce38eefd0ca1cb5d
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
46 #include "lib/util/sys_rw_data.h"
48 /****************************************************************************
49 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
50 path or anything including wildcards.
51 We're assuming here that '/' is not the second byte in any multibyte char
52 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
53 set.
54 ****************************************************************************/
56 /* Custom version for processing POSIX paths. */
57 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
59 static NTSTATUS check_path_syntax_internal(char *path,
60 bool posix_path,
61 bool *p_last_component_contains_wcard)
63 char *d = path;
64 const char *s = path;
65 NTSTATUS ret = NT_STATUS_OK;
66 bool start_of_name_component = True;
67 bool stream_started = false;
69 *p_last_component_contains_wcard = False;
71 while (*s) {
72 if (stream_started) {
73 switch (*s) {
74 case '/':
75 case '\\':
76 return NT_STATUS_OBJECT_NAME_INVALID;
77 case ':':
78 if (s[1] == '\0') {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 if (strchr_m(&s[1], ':')) {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 break;
88 if ((*s == ':') && !posix_path && !stream_started) {
89 if (*p_last_component_contains_wcard) {
90 return NT_STATUS_OBJECT_NAME_INVALID;
92 /* Stream names allow more characters than file names.
93 We're overloading posix_path here to allow a wider
94 range of characters. If stream_started is true this
95 is still a Windows path even if posix_path is true.
96 JRA.
98 stream_started = true;
99 start_of_name_component = false;
100 posix_path = true;
102 if (s[1] == '\0') {
103 return NT_STATUS_OBJECT_NAME_INVALID;
107 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
109 * Safe to assume is not the second part of a mb char
110 * as this is handled below.
112 /* Eat multiple '/' or '\\' */
113 while (IS_PATH_SEP(*s,posix_path)) {
114 s++;
116 if ((d != path) && (*s != '\0')) {
117 /* We only care about non-leading or trailing '/' or '\\' */
118 *d++ = '/';
121 start_of_name_component = True;
122 /* New component. */
123 *p_last_component_contains_wcard = False;
124 continue;
127 if (start_of_name_component) {
128 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
129 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
132 * No mb char starts with '.' so we're safe checking the directory separator here.
135 /* If we just added a '/' - delete it */
136 if ((d > path) && (*(d-1) == '/')) {
137 *(d-1) = '\0';
138 d--;
141 /* Are we at the start ? Can't go back further if so. */
142 if (d <= path) {
143 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
144 break;
146 /* Go back one level... */
147 /* We know this is safe as '/' cannot be part of a mb sequence. */
148 /* NOTE - if this assumption is invalid we are not in good shape... */
149 /* Decrement d first as d points to the *next* char to write into. */
150 for (d--; d > path; d--) {
151 if (*d == '/')
152 break;
154 s += 2; /* Else go past the .. */
155 /* We're still at the start of a name component, just the previous one. */
156 continue;
158 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
159 if (posix_path) {
160 /* Eat the '.' */
161 s++;
162 continue;
168 if (!(*s & 0x80)) {
169 if (!posix_path) {
170 if (*s <= 0x1f || *s == '|') {
171 return NT_STATUS_OBJECT_NAME_INVALID;
173 switch (*s) {
174 case '*':
175 case '?':
176 case '<':
177 case '>':
178 case '"':
179 *p_last_component_contains_wcard = True;
180 break;
181 default:
182 break;
185 *d++ = *s++;
186 } else {
187 size_t siz;
188 /* Get the size of the next MB character. */
189 next_codepoint(s,&siz);
190 switch(siz) {
191 case 5:
192 *d++ = *s++;
193 /*fall through*/
194 case 4:
195 *d++ = *s++;
196 /*fall through*/
197 case 3:
198 *d++ = *s++;
199 /*fall through*/
200 case 2:
201 *d++ = *s++;
202 /*fall through*/
203 case 1:
204 *d++ = *s++;
205 break;
206 default:
207 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
208 *d = '\0';
209 return NT_STATUS_INVALID_PARAMETER;
212 start_of_name_component = False;
215 *d = '\0';
217 return ret;
220 /****************************************************************************
221 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
222 No wildcards allowed.
223 ****************************************************************************/
225 NTSTATUS check_path_syntax(char *path)
227 bool ignore;
228 return check_path_syntax_internal(path, False, &ignore);
231 /****************************************************************************
232 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
233 Wildcards allowed - p_contains_wcard returns true if the last component contained
234 a wildcard.
235 ****************************************************************************/
237 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
239 return check_path_syntax_internal(path, False, p_contains_wcard);
242 /****************************************************************************
243 Check the path for a POSIX client.
244 We're assuming here that '/' is not the second byte in any multibyte char
245 set (a safe assumption).
246 ****************************************************************************/
248 NTSTATUS check_path_syntax_posix(char *path)
250 bool ignore;
251 return check_path_syntax_internal(path, True, &ignore);
254 /****************************************************************************
255 Pull a string and check the path allowing a wilcard - provide for error return.
256 Passes in posix flag.
257 ****************************************************************************/
259 static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
260 const char *base_ptr,
261 uint16_t smb_flags2,
262 char **pp_dest,
263 const char *src,
264 size_t src_len,
265 int flags,
266 bool posix_pathnames,
267 NTSTATUS *err,
268 bool *contains_wcard)
270 size_t ret;
272 *pp_dest = NULL;
274 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
275 src_len, flags);
277 if (!*pp_dest) {
278 *err = NT_STATUS_INVALID_PARAMETER;
279 return ret;
282 *contains_wcard = False;
284 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
286 * For a DFS path the function parse_dfs_path()
287 * will do the path processing, just make a copy.
289 *err = NT_STATUS_OK;
290 return ret;
293 if (posix_pathnames) {
294 *err = check_path_syntax_posix(*pp_dest);
295 } else {
296 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
299 return ret;
302 /****************************************************************************
303 Pull a string and check the path allowing a wilcard - provide for error return.
304 ****************************************************************************/
306 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
307 const char *base_ptr,
308 uint16_t smb_flags2,
309 char **pp_dest,
310 const char *src,
311 size_t src_len,
312 int flags,
313 NTSTATUS *err,
314 bool *contains_wcard)
316 return srvstr_get_path_wcard_internal(ctx,
317 base_ptr,
318 smb_flags2,
319 pp_dest,
320 src,
321 src_len,
322 flags,
323 false,
324 err,
325 contains_wcard);
328 /****************************************************************************
329 Pull a string and check the path allowing a wilcard - provide for error return.
330 posix_pathnames version.
331 ****************************************************************************/
333 size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
334 const char *base_ptr,
335 uint16_t smb_flags2,
336 char **pp_dest,
337 const char *src,
338 size_t src_len,
339 int flags,
340 NTSTATUS *err,
341 bool *contains_wcard)
343 return srvstr_get_path_wcard_internal(ctx,
344 base_ptr,
345 smb_flags2,
346 pp_dest,
347 src,
348 src_len,
349 flags,
350 true,
351 err,
352 contains_wcard);
355 /****************************************************************************
356 Pull a string and check the path - provide for error return.
357 ****************************************************************************/
359 size_t srvstr_get_path(TALLOC_CTX *ctx,
360 const char *base_ptr,
361 uint16_t smb_flags2,
362 char **pp_dest,
363 const char *src,
364 size_t src_len,
365 int flags,
366 NTSTATUS *err)
368 bool ignore;
369 return srvstr_get_path_wcard_internal(ctx,
370 base_ptr,
371 smb_flags2,
372 pp_dest,
373 src,
374 src_len,
375 flags,
376 false,
377 err,
378 &ignore);
381 /****************************************************************************
382 Pull a string and check the path - provide for error return.
383 posix_pathnames version.
384 ****************************************************************************/
386 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
387 const char *base_ptr,
388 uint16_t smb_flags2,
389 char **pp_dest,
390 const char *src,
391 size_t src_len,
392 int flags,
393 NTSTATUS *err)
395 bool ignore;
396 return srvstr_get_path_wcard_internal(ctx,
397 base_ptr,
398 smb_flags2,
399 pp_dest,
400 src,
401 src_len,
402 flags,
403 true,
404 err,
405 &ignore);
409 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
410 char **pp_dest, const char *src, int flags,
411 NTSTATUS *err, bool *contains_wcard)
413 ssize_t bufrem = smbreq_bufrem(req, src);
415 if (bufrem < 0) {
416 *err = NT_STATUS_INVALID_PARAMETER;
417 return 0;
420 if (req->posix_pathnames) {
421 return srvstr_get_path_wcard_internal(mem_ctx,
422 (const char *)req->inbuf,
423 req->flags2,
424 pp_dest,
425 src,
426 bufrem,
427 flags,
428 true,
429 err,
430 contains_wcard);
431 } else {
432 return srvstr_get_path_wcard_internal(mem_ctx,
433 (const char *)req->inbuf,
434 req->flags2,
435 pp_dest,
436 src,
437 bufrem,
438 flags,
439 false,
440 err,
441 contains_wcard);
445 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
446 char **pp_dest, const char *src, int flags,
447 NTSTATUS *err)
449 bool ignore;
450 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
451 flags, err, &ignore);
455 * pull a string from the smb_buf part of a packet. In this case the
456 * string can either be null terminated or it can be terminated by the
457 * end of the smbbuf area
459 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
460 char **dest, const uint8_t *src, int flags)
462 ssize_t bufrem = smbreq_bufrem(req, src);
464 if (bufrem < 0) {
465 return 0;
468 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
469 bufrem, flags);
472 /****************************************************************************
473 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
474 ****************************************************************************/
476 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
477 files_struct *fsp)
479 if ((fsp == NULL) || (conn == NULL)) {
480 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
481 return False;
483 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
484 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
485 return False;
487 return True;
490 /****************************************************************************
491 Check if we have a correct fsp pointing to a file.
492 ****************************************************************************/
494 bool check_fsp(connection_struct *conn, struct smb_request *req,
495 files_struct *fsp)
497 if (!check_fsp_open(conn, req, fsp)) {
498 return False;
500 if (fsp->is_directory) {
501 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
502 return False;
504 if (fsp->fh->fd == -1) {
505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
506 return False;
508 fsp->num_smb_operations++;
509 return True;
512 /****************************************************************************
513 Check if we have a correct fsp pointing to a quota fake file. Replacement for
514 the CHECK_NTQUOTA_HANDLE_OK macro.
515 ****************************************************************************/
517 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
518 files_struct *fsp)
520 if (!check_fsp_open(conn, req, fsp)) {
521 return false;
524 if (fsp->is_directory) {
525 return false;
528 if (fsp->fake_file_handle == NULL) {
529 return false;
532 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
533 return false;
536 if (fsp->fake_file_handle->private_data == NULL) {
537 return false;
540 return true;
543 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
544 const char *name, int name_type)
546 char *trim_name;
547 char *trim_name_type;
548 const char *retarget_parm;
549 char *retarget;
550 char *p;
551 int retarget_type = 0x20;
552 int retarget_port = NBT_SMB_PORT;
553 struct sockaddr_storage retarget_addr;
554 struct sockaddr_in *in_addr;
555 bool ret = false;
556 uint8_t outbuf[10];
558 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
559 return false;
562 trim_name = talloc_strdup(talloc_tos(), name);
563 if (trim_name == NULL) {
564 goto fail;
566 trim_char(trim_name, ' ', ' ');
568 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
569 name_type);
570 if (trim_name_type == NULL) {
571 goto fail;
574 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
575 trim_name_type, NULL);
576 if (retarget_parm == NULL) {
577 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
578 trim_name, NULL);
580 if (retarget_parm == NULL) {
581 goto fail;
584 retarget = talloc_strdup(trim_name, retarget_parm);
585 if (retarget == NULL) {
586 goto fail;
589 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
591 p = strchr(retarget, ':');
592 if (p != NULL) {
593 *p++ = '\0';
594 retarget_port = atoi(p);
597 p = strchr_m(retarget, '#');
598 if (p != NULL) {
599 *p++ = '\0';
600 if (sscanf(p, "%x", &retarget_type) != 1) {
601 goto fail;
605 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
606 if (!ret) {
607 DEBUG(10, ("could not resolve %s\n", retarget));
608 goto fail;
611 if (retarget_addr.ss_family != AF_INET) {
612 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
613 goto fail;
616 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
618 _smb_setlen(outbuf, 6);
619 SCVAL(outbuf, 0, 0x84);
620 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
621 *(uint16_t *)(outbuf+8) = htons(retarget_port);
623 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
624 NULL)) {
625 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
626 "failed.");
629 ret = true;
630 fail:
631 TALLOC_FREE(trim_name);
632 return ret;
635 static void reply_called_name_not_present(char *outbuf)
637 smb_setlen(outbuf, 1);
638 SCVAL(outbuf, 0, 0x83);
639 SCVAL(outbuf, 4, 0x82);
642 /****************************************************************************
643 Reply to a (netbios-level) special message.
644 ****************************************************************************/
646 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
648 struct smbd_server_connection *sconn = xconn->client->sconn;
649 int msg_type = CVAL(inbuf,0);
650 int msg_flags = CVAL(inbuf,1);
652 * We only really use 4 bytes of the outbuf, but for the smb_setlen
653 * calculation & friends (srv_send_smb uses that) we need the full smb
654 * header.
656 char outbuf[smb_size];
658 memset(outbuf, '\0', sizeof(outbuf));
660 smb_setlen(outbuf,0);
662 switch (msg_type) {
663 case NBSSrequest: /* session request */
665 /* inbuf_size is guarenteed to be at least 4. */
666 fstring name1,name2;
667 int name_type1, name_type2;
668 int name_len1, name_len2;
670 *name1 = *name2 = 0;
672 if (xconn->transport.nbt.got_session) {
673 exit_server_cleanly("multiple session request not permitted");
676 SCVAL(outbuf,0,NBSSpositive);
677 SCVAL(outbuf,3,0);
679 /* inbuf_size is guaranteed to be at least 4. */
680 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
681 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
682 DEBUG(0,("Invalid name length in session request\n"));
683 reply_called_name_not_present(outbuf);
684 break;
686 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
687 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
688 DEBUG(0,("Invalid name length in session request\n"));
689 reply_called_name_not_present(outbuf);
690 break;
693 name_type1 = name_extract((unsigned char *)inbuf,
694 inbuf_size,(unsigned int)4,name1);
695 name_type2 = name_extract((unsigned char *)inbuf,
696 inbuf_size,(unsigned int)(4 + name_len1),name2);
698 if (name_type1 == -1 || name_type2 == -1) {
699 DEBUG(0,("Invalid name type in session request\n"));
700 reply_called_name_not_present(outbuf);
701 break;
704 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
705 name1, name_type1, name2, name_type2));
707 if (netbios_session_retarget(xconn, name1, name_type1)) {
708 exit_server_cleanly("retargeted client");
712 * Windows NT/2k uses "*SMBSERVER" and XP uses
713 * "*SMBSERV" arrggg!!!
715 if (strequal(name1, "*SMBSERVER ")
716 || strequal(name1, "*SMBSERV ")) {
717 char *raddr;
719 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
720 talloc_tos());
721 if (raddr == NULL) {
722 exit_server_cleanly("could not allocate raddr");
725 fstrcpy(name1, raddr);
728 set_local_machine_name(name1, True);
729 set_remote_machine_name(name2, True);
731 if (is_ipaddress(sconn->remote_hostname)) {
732 char *p = discard_const_p(char, sconn->remote_hostname);
734 talloc_free(p);
736 sconn->remote_hostname = talloc_strdup(sconn,
737 get_remote_machine_name());
738 if (sconn->remote_hostname == NULL) {
739 exit_server_cleanly("could not copy remote name");
741 xconn->remote_hostname = sconn->remote_hostname;
744 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
745 get_local_machine_name(), get_remote_machine_name(),
746 name_type2));
748 if (name_type2 == 'R') {
749 /* We are being asked for a pathworks session ---
750 no thanks! */
751 reply_called_name_not_present(outbuf);
752 break;
755 reload_services(sconn, conn_snum_used, true);
756 reopen_logs();
758 xconn->transport.nbt.got_session = true;
759 break;
762 case 0x89: /* session keepalive request
763 (some old clients produce this?) */
764 SCVAL(outbuf,0,NBSSkeepalive);
765 SCVAL(outbuf,3,0);
766 break;
768 case NBSSpositive: /* positive session response */
769 case NBSSnegative: /* negative session response */
770 case NBSSretarget: /* retarget session response */
771 DEBUG(0,("Unexpected session response\n"));
772 break;
774 case NBSSkeepalive: /* session keepalive */
775 default:
776 return;
779 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
780 msg_type, msg_flags));
782 srv_send_smb(xconn, outbuf, false, 0, false, NULL);
784 if (CVAL(outbuf, 0) != 0x82) {
785 exit_server_cleanly("invalid netbios session");
787 return;
790 /****************************************************************************
791 Reply to a tcon.
792 conn POINTER CAN BE NULL HERE !
793 ****************************************************************************/
795 void reply_tcon(struct smb_request *req)
797 connection_struct *conn = req->conn;
798 const char *service;
799 char *service_buf = NULL;
800 char *password = NULL;
801 char *dev = NULL;
802 int pwlen=0;
803 NTSTATUS nt_status;
804 const uint8_t *p;
805 const char *p2;
806 TALLOC_CTX *ctx = talloc_tos();
807 struct smbXsrv_connection *xconn = req->xconn;
808 NTTIME now = timeval_to_nttime(&req->request_time);
810 START_PROFILE(SMBtcon);
812 if (req->buflen < 4) {
813 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
814 END_PROFILE(SMBtcon);
815 return;
818 p = req->buf + 1;
819 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
820 p += 1;
821 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
822 p += pwlen+1;
823 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
824 p += 1;
826 if (service_buf == NULL || password == NULL || dev == NULL) {
827 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
828 END_PROFILE(SMBtcon);
829 return;
831 p2 = strrchr_m(service_buf,'\\');
832 if (p2) {
833 service = p2+1;
834 } else {
835 service = service_buf;
838 conn = make_connection(req, now, service, dev,
839 req->vuid,&nt_status);
840 req->conn = conn;
842 if (!conn) {
843 reply_nterror(req, nt_status);
844 END_PROFILE(SMBtcon);
845 return;
848 reply_outbuf(req, 2, 0);
849 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
850 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
851 SSVAL(req->outbuf,smb_tid,conn->cnum);
853 DEBUG(3,("tcon service=%s cnum=%d\n",
854 service, conn->cnum));
856 END_PROFILE(SMBtcon);
857 return;
860 /****************************************************************************
861 Reply to a tcon and X.
862 conn POINTER CAN BE NULL HERE !
863 ****************************************************************************/
865 void reply_tcon_and_X(struct smb_request *req)
867 connection_struct *conn = req->conn;
868 const char *service = NULL;
869 TALLOC_CTX *ctx = talloc_tos();
870 /* what the cleint thinks the device is */
871 char *client_devicetype = NULL;
872 /* what the server tells the client the share represents */
873 const char *server_devicetype;
874 NTSTATUS nt_status;
875 int passlen;
876 char *path = NULL;
877 const uint8_t *p;
878 const char *q;
879 uint16_t tcon_flags;
880 struct smbXsrv_session *session = NULL;
881 NTTIME now = timeval_to_nttime(&req->request_time);
882 bool session_key_updated = false;
883 uint16_t optional_support = 0;
884 struct smbXsrv_connection *xconn = req->xconn;
886 START_PROFILE(SMBtconX);
888 if (req->wct < 4) {
889 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
890 END_PROFILE(SMBtconX);
891 return;
894 passlen = SVAL(req->vwv+3, 0);
895 tcon_flags = SVAL(req->vwv+2, 0);
897 /* we might have to close an old one */
898 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
899 struct smbXsrv_tcon *tcon;
900 NTSTATUS status;
902 tcon = conn->tcon;
903 req->conn = NULL;
904 conn = NULL;
907 * TODO: cancel all outstanding requests on the tcon
909 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
910 if (!NT_STATUS_IS_OK(status)) {
911 DEBUG(0, ("reply_tcon_and_X: "
912 "smbXsrv_tcon_disconnect() failed: %s\n",
913 nt_errstr(status)));
915 * If we hit this case, there is something completely
916 * wrong, so we better disconnect the transport connection.
918 END_PROFILE(SMBtconX);
919 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
920 return;
923 TALLOC_FREE(tcon);
926 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
927 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
928 END_PROFILE(SMBtconX);
929 return;
932 if (xconn->smb1.negprot.encrypted_passwords) {
933 p = req->buf + passlen;
934 } else {
935 p = req->buf + passlen + 1;
938 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
940 if (path == NULL) {
941 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
942 END_PROFILE(SMBtconX);
943 return;
947 * the service name can be either: \\server\share
948 * or share directly like on the DELL PowerVault 705
950 if (*path=='\\') {
951 q = strchr_m(path+2,'\\');
952 if (!q) {
953 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
954 END_PROFILE(SMBtconX);
955 return;
957 service = q+1;
958 } else {
959 service = path;
962 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
963 &client_devicetype, p,
964 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
966 if (client_devicetype == NULL) {
967 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
968 END_PROFILE(SMBtconX);
969 return;
972 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
974 nt_status = smb1srv_session_lookup(xconn,
975 req->vuid, now, &session);
976 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
977 reply_force_doserror(req, ERRSRV, ERRbaduid);
978 END_PROFILE(SMBtconX);
979 return;
981 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
982 reply_nterror(req, nt_status);
983 END_PROFILE(SMBtconX);
984 return;
986 if (!NT_STATUS_IS_OK(nt_status)) {
987 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
988 END_PROFILE(SMBtconX);
989 return;
992 if (session->global->auth_session_info == NULL) {
993 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
994 END_PROFILE(SMBtconX);
995 return;
999 * If there is no application key defined yet
1000 * we create one.
1002 * This means we setup the application key on the
1003 * first tcon that happens via the given session.
1005 * Once the application key is defined, it does not
1006 * change any more.
1008 if (session->global->application_key.length == 0 &&
1009 session->global->signing_key.length > 0)
1011 struct smbXsrv_session *x = session;
1012 struct auth_session_info *session_info =
1013 session->global->auth_session_info;
1014 uint8_t session_key[16];
1016 ZERO_STRUCT(session_key);
1017 memcpy(session_key, x->global->signing_key.data,
1018 MIN(x->global->signing_key.length, sizeof(session_key)));
1021 * The application key is truncated/padded to 16 bytes
1023 x->global->application_key = data_blob_talloc(x->global,
1024 session_key,
1025 sizeof(session_key));
1026 ZERO_STRUCT(session_key);
1027 if (x->global->application_key.data == NULL) {
1028 reply_nterror(req, NT_STATUS_NO_MEMORY);
1029 END_PROFILE(SMBtconX);
1030 return;
1033 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1034 smb_key_derivation(x->global->application_key.data,
1035 x->global->application_key.length,
1036 x->global->application_key.data);
1037 optional_support |= SMB_EXTENDED_SIGNATURES;
1041 * Place the application key into the session_info
1043 data_blob_clear_free(&session_info->session_key);
1044 session_info->session_key = data_blob_dup_talloc(session_info,
1045 x->global->application_key);
1046 if (session_info->session_key.data == NULL) {
1047 data_blob_clear_free(&x->global->application_key);
1048 reply_nterror(req, NT_STATUS_NO_MEMORY);
1049 END_PROFILE(SMBtconX);
1050 return;
1052 session_key_updated = true;
1055 conn = make_connection(req, now, service, client_devicetype,
1056 req->vuid, &nt_status);
1057 req->conn =conn;
1059 if (!conn) {
1060 if (session_key_updated) {
1061 struct smbXsrv_session *x = session;
1062 struct auth_session_info *session_info =
1063 session->global->auth_session_info;
1064 data_blob_clear_free(&x->global->application_key);
1065 data_blob_clear_free(&session_info->session_key);
1067 reply_nterror(req, nt_status);
1068 END_PROFILE(SMBtconX);
1069 return;
1072 if ( IS_IPC(conn) )
1073 server_devicetype = "IPC";
1074 else if ( IS_PRINT(conn) )
1075 server_devicetype = "LPT1:";
1076 else
1077 server_devicetype = "A:";
1079 if (get_Protocol() < PROTOCOL_NT1) {
1080 reply_outbuf(req, 2, 0);
1081 if (message_push_string(&req->outbuf, server_devicetype,
1082 STR_TERMINATE|STR_ASCII) == -1) {
1083 reply_nterror(req, NT_STATUS_NO_MEMORY);
1084 END_PROFILE(SMBtconX);
1085 return;
1087 } else {
1088 /* NT sets the fstype of IPC$ to the null string */
1089 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1091 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1092 /* Return permissions. */
1093 uint32_t perm1 = 0;
1094 uint32_t perm2 = 0;
1096 reply_outbuf(req, 7, 0);
1098 if (IS_IPC(conn)) {
1099 perm1 = FILE_ALL_ACCESS;
1100 perm2 = FILE_ALL_ACCESS;
1101 } else {
1102 perm1 = conn->share_access;
1105 SIVAL(req->outbuf, smb_vwv3, perm1);
1106 SIVAL(req->outbuf, smb_vwv5, perm2);
1107 } else {
1108 reply_outbuf(req, 3, 0);
1111 if ((message_push_string(&req->outbuf, server_devicetype,
1112 STR_TERMINATE|STR_ASCII) == -1)
1113 || (message_push_string(&req->outbuf, fstype,
1114 STR_TERMINATE) == -1)) {
1115 reply_nterror(req, NT_STATUS_NO_MEMORY);
1116 END_PROFILE(SMBtconX);
1117 return;
1120 /* what does setting this bit do? It is set by NT4 and
1121 may affect the ability to autorun mounted cdroms */
1122 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1123 optional_support |=
1124 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1126 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1127 DEBUG(2,("Serving %s as a Dfs root\n",
1128 lp_servicename(ctx, SNUM(conn)) ));
1129 optional_support |= SMB_SHARE_IN_DFS;
1132 SSVAL(req->outbuf, smb_vwv2, optional_support);
1135 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1136 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1138 DEBUG(3,("tconX service=%s \n",
1139 service));
1141 /* set the incoming and outgoing tid to the just created one */
1142 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1143 SSVAL(req->outbuf,smb_tid,conn->cnum);
1145 END_PROFILE(SMBtconX);
1147 req->tid = conn->cnum;
1150 /****************************************************************************
1151 Reply to an unknown type.
1152 ****************************************************************************/
1154 void reply_unknown_new(struct smb_request *req, uint8_t type)
1156 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1157 smb_fn_name(type), type, type));
1158 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1159 return;
1162 /****************************************************************************
1163 Reply to an ioctl.
1164 conn POINTER CAN BE NULL HERE !
1165 ****************************************************************************/
1167 void reply_ioctl(struct smb_request *req)
1169 connection_struct *conn = req->conn;
1170 uint16_t device;
1171 uint16_t function;
1172 uint32_t ioctl_code;
1173 int replysize;
1174 char *p;
1176 START_PROFILE(SMBioctl);
1178 if (req->wct < 3) {
1179 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1180 END_PROFILE(SMBioctl);
1181 return;
1184 device = SVAL(req->vwv+1, 0);
1185 function = SVAL(req->vwv+2, 0);
1186 ioctl_code = (device << 16) + function;
1188 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1190 switch (ioctl_code) {
1191 case IOCTL_QUERY_JOB_INFO:
1192 replysize = 32;
1193 break;
1194 default:
1195 reply_force_doserror(req, ERRSRV, ERRnosupport);
1196 END_PROFILE(SMBioctl);
1197 return;
1200 reply_outbuf(req, 8, replysize+1);
1201 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1202 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1203 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1204 p = smb_buf(req->outbuf);
1205 memset(p, '\0', replysize+1); /* valgrind-safe. */
1206 p += 1; /* Allow for alignment */
1208 switch (ioctl_code) {
1209 case IOCTL_QUERY_JOB_INFO:
1211 NTSTATUS status;
1212 size_t len = 0;
1213 files_struct *fsp = file_fsp(
1214 req, SVAL(req->vwv+0, 0));
1215 if (!fsp) {
1216 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1217 END_PROFILE(SMBioctl);
1218 return;
1220 /* Job number */
1221 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1223 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1224 lp_netbios_name(), 15,
1225 STR_TERMINATE|STR_ASCII, &len);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 reply_nterror(req, status);
1228 END_PROFILE(SMBioctl);
1229 return;
1231 if (conn) {
1232 status = srvstr_push((char *)req->outbuf, req->flags2,
1233 p+18,
1234 lp_servicename(talloc_tos(),
1235 SNUM(conn)),
1236 13, STR_TERMINATE|STR_ASCII, &len);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 reply_nterror(req, status);
1239 END_PROFILE(SMBioctl);
1240 return;
1242 } else {
1243 memset(p+18, 0, 13);
1245 break;
1249 END_PROFILE(SMBioctl);
1250 return;
1253 /****************************************************************************
1254 Strange checkpath NTSTATUS mapping.
1255 ****************************************************************************/
1257 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1259 /* Strange DOS error code semantics only for checkpath... */
1260 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1261 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1262 /* We need to map to ERRbadpath */
1263 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1266 return status;
1269 /****************************************************************************
1270 Reply to a checkpath.
1271 ****************************************************************************/
1273 void reply_checkpath(struct smb_request *req)
1275 connection_struct *conn = req->conn;
1276 struct smb_filename *smb_fname = NULL;
1277 char *name = NULL;
1278 NTSTATUS status;
1279 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
1280 TALLOC_CTX *ctx = talloc_tos();
1282 START_PROFILE(SMBcheckpath);
1284 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1285 STR_TERMINATE, &status);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 status = map_checkpath_error(req->flags2, status);
1289 reply_nterror(req, status);
1290 END_PROFILE(SMBcheckpath);
1291 return;
1294 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1296 status = filename_convert(ctx,
1297 conn,
1298 req->flags2 & FLAGS2_DFS_PATHNAMES,
1299 name,
1300 ucf_flags,
1301 NULL,
1302 &smb_fname);
1304 if (!NT_STATUS_IS_OK(status)) {
1305 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1306 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1307 ERRSRV, ERRbadpath);
1308 END_PROFILE(SMBcheckpath);
1309 return;
1311 goto path_err;
1314 if (!VALID_STAT(smb_fname->st) &&
1315 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1316 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1317 smb_fname_str_dbg(smb_fname), strerror(errno)));
1318 status = map_nt_error_from_unix(errno);
1319 goto path_err;
1322 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1323 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1324 ERRDOS, ERRbadpath);
1325 goto out;
1328 reply_outbuf(req, 0, 0);
1330 path_err:
1331 /* We special case this - as when a Windows machine
1332 is parsing a path is steps through the components
1333 one at a time - if a component fails it expects
1334 ERRbadpath, not ERRbadfile.
1336 status = map_checkpath_error(req->flags2, status);
1337 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1339 * Windows returns different error codes if
1340 * the parent directory is valid but not the
1341 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1342 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1343 * if the path is invalid.
1345 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1346 ERRDOS, ERRbadpath);
1347 goto out;
1350 reply_nterror(req, status);
1352 out:
1353 TALLOC_FREE(smb_fname);
1354 END_PROFILE(SMBcheckpath);
1355 return;
1358 /****************************************************************************
1359 Reply to a getatr.
1360 ****************************************************************************/
1362 void reply_getatr(struct smb_request *req)
1364 connection_struct *conn = req->conn;
1365 struct smb_filename *smb_fname = NULL;
1366 char *fname = NULL;
1367 int mode=0;
1368 off_t size=0;
1369 time_t mtime=0;
1370 const char *p;
1371 NTSTATUS status;
1372 TALLOC_CTX *ctx = talloc_tos();
1373 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1375 START_PROFILE(SMBgetatr);
1377 p = (const char *)req->buf + 1;
1378 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 reply_nterror(req, status);
1381 goto out;
1384 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1385 under WfWg - weird! */
1386 if (*fname == '\0') {
1387 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1388 if (!CAN_WRITE(conn)) {
1389 mode |= FILE_ATTRIBUTE_READONLY;
1391 size = 0;
1392 mtime = 0;
1393 } else {
1394 uint32_t ucf_flags = (req->posix_pathnames ?
1395 UCF_POSIX_PATHNAMES : 0);
1396 status = filename_convert(ctx,
1397 conn,
1398 req->flags2 & FLAGS2_DFS_PATHNAMES,
1399 fname,
1400 ucf_flags,
1401 NULL,
1402 &smb_fname);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1405 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1406 ERRSRV, ERRbadpath);
1407 goto out;
1409 reply_nterror(req, status);
1410 goto out;
1412 if (!VALID_STAT(smb_fname->st) &&
1413 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1414 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1415 smb_fname_str_dbg(smb_fname),
1416 strerror(errno)));
1417 reply_nterror(req, map_nt_error_from_unix(errno));
1418 goto out;
1421 mode = dos_mode(conn, smb_fname);
1422 size = smb_fname->st.st_ex_size;
1424 if (ask_sharemode) {
1425 struct timespec write_time_ts;
1426 struct file_id fileid;
1428 ZERO_STRUCT(write_time_ts);
1429 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1430 get_file_infos(fileid, 0, NULL, &write_time_ts);
1431 if (!null_timespec(write_time_ts)) {
1432 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1436 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1437 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1438 size = 0;
1442 reply_outbuf(req, 10, 0);
1444 SSVAL(req->outbuf,smb_vwv0,mode);
1445 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1446 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1447 } else {
1448 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1450 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1452 if (get_Protocol() >= PROTOCOL_NT1) {
1453 SSVAL(req->outbuf, smb_flg2,
1454 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1457 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1458 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1460 out:
1461 TALLOC_FREE(smb_fname);
1462 TALLOC_FREE(fname);
1463 END_PROFILE(SMBgetatr);
1464 return;
1467 /****************************************************************************
1468 Reply to a setatr.
1469 ****************************************************************************/
1471 void reply_setatr(struct smb_request *req)
1473 struct smb_file_time ft;
1474 connection_struct *conn = req->conn;
1475 struct smb_filename *smb_fname = NULL;
1476 char *fname = NULL;
1477 int mode;
1478 time_t mtime;
1479 const char *p;
1480 NTSTATUS status;
1481 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
1482 TALLOC_CTX *ctx = talloc_tos();
1484 START_PROFILE(SMBsetatr);
1486 ZERO_STRUCT(ft);
1488 if (req->wct < 2) {
1489 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1490 goto out;
1493 p = (const char *)req->buf + 1;
1494 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1495 if (!NT_STATUS_IS_OK(status)) {
1496 reply_nterror(req, status);
1497 goto out;
1500 status = filename_convert(ctx,
1501 conn,
1502 req->flags2 & FLAGS2_DFS_PATHNAMES,
1503 fname,
1504 ucf_flags,
1505 NULL,
1506 &smb_fname);
1507 if (!NT_STATUS_IS_OK(status)) {
1508 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1509 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1510 ERRSRV, ERRbadpath);
1511 goto out;
1513 reply_nterror(req, status);
1514 goto out;
1517 if (smb_fname->base_name[0] == '.' &&
1518 smb_fname->base_name[1] == '\0') {
1520 * Not sure here is the right place to catch this
1521 * condition. Might be moved to somewhere else later -- vl
1523 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1524 goto out;
1527 mode = SVAL(req->vwv+0, 0);
1528 mtime = srv_make_unix_date3(req->vwv+1);
1530 if (mode != FILE_ATTRIBUTE_NORMAL) {
1531 if (VALID_STAT_OF_DIR(smb_fname->st))
1532 mode |= FILE_ATTRIBUTE_DIRECTORY;
1533 else
1534 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1536 status = check_access(conn, NULL, smb_fname,
1537 FILE_WRITE_ATTRIBUTES);
1538 if (!NT_STATUS_IS_OK(status)) {
1539 reply_nterror(req, status);
1540 goto out;
1543 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1544 false) != 0) {
1545 reply_nterror(req, map_nt_error_from_unix(errno));
1546 goto out;
1550 ft.mtime = convert_time_t_to_timespec(mtime);
1551 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1552 if (!NT_STATUS_IS_OK(status)) {
1553 reply_nterror(req, status);
1554 goto out;
1557 reply_outbuf(req, 0, 0);
1559 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1560 mode));
1561 out:
1562 TALLOC_FREE(smb_fname);
1563 END_PROFILE(SMBsetatr);
1564 return;
1567 /****************************************************************************
1568 Reply to a dskattr.
1569 ****************************************************************************/
1571 void reply_dskattr(struct smb_request *req)
1573 connection_struct *conn = req->conn;
1574 uint64_t ret;
1575 uint64_t dfree,dsize,bsize;
1576 START_PROFILE(SMBdskattr);
1578 ret = get_dfree_info(conn, ".", &bsize, &dfree, &dsize);
1579 if (ret == (uint64_t)-1) {
1580 reply_nterror(req, map_nt_error_from_unix(errno));
1581 END_PROFILE(SMBdskattr);
1582 return;
1586 * Force max to fit in 16 bit fields.
1588 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1589 dfree /= 2;
1590 dsize /= 2;
1591 bsize *= 2;
1592 if (bsize > (WORDMAX*512)) {
1593 bsize = (WORDMAX*512);
1594 if (dsize > WORDMAX)
1595 dsize = WORDMAX;
1596 if (dfree > WORDMAX)
1597 dfree = WORDMAX;
1598 break;
1602 reply_outbuf(req, 5, 0);
1604 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1605 double total_space, free_space;
1606 /* we need to scale this to a number that DOS6 can handle. We
1607 use floating point so we can handle large drives on systems
1608 that don't have 64 bit integers
1610 we end up displaying a maximum of 2G to DOS systems
1612 total_space = dsize * (double)bsize;
1613 free_space = dfree * (double)bsize;
1615 dsize = (uint64_t)((total_space+63*512) / (64*512));
1616 dfree = (uint64_t)((free_space+63*512) / (64*512));
1618 if (dsize > 0xFFFF) dsize = 0xFFFF;
1619 if (dfree > 0xFFFF) dfree = 0xFFFF;
1621 SSVAL(req->outbuf,smb_vwv0,dsize);
1622 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1623 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1624 SSVAL(req->outbuf,smb_vwv3,dfree);
1625 } else {
1626 SSVAL(req->outbuf,smb_vwv0,dsize);
1627 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1628 SSVAL(req->outbuf,smb_vwv2,512);
1629 SSVAL(req->outbuf,smb_vwv3,dfree);
1632 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1634 END_PROFILE(SMBdskattr);
1635 return;
1639 * Utility function to split the filename from the directory.
1641 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1642 char **fname_dir_out,
1643 char **fname_mask_out)
1645 const char *p = NULL;
1646 char *fname_dir = NULL;
1647 char *fname_mask = NULL;
1649 p = strrchr_m(fname_in, '/');
1650 if (!p) {
1651 fname_dir = talloc_strdup(ctx, ".");
1652 fname_mask = talloc_strdup(ctx, fname_in);
1653 } else {
1654 fname_dir = talloc_strndup(ctx, fname_in,
1655 PTR_DIFF(p, fname_in));
1656 fname_mask = talloc_strdup(ctx, p+1);
1659 if (!fname_dir || !fname_mask) {
1660 TALLOC_FREE(fname_dir);
1661 TALLOC_FREE(fname_mask);
1662 return NT_STATUS_NO_MEMORY;
1665 *fname_dir_out = fname_dir;
1666 *fname_mask_out = fname_mask;
1667 return NT_STATUS_OK;
1670 /****************************************************************************
1671 Make a dir struct.
1672 ****************************************************************************/
1674 static bool make_dir_struct(TALLOC_CTX *ctx,
1675 char *buf,
1676 const char *mask,
1677 const char *fname,
1678 off_t size,
1679 uint32_t mode,
1680 time_t date,
1681 bool uc)
1683 char *p;
1684 char *mask2 = talloc_strdup(ctx, mask);
1686 if (!mask2) {
1687 return False;
1690 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1691 size = 0;
1694 memset(buf+1,' ',11);
1695 if ((p = strchr_m(mask2,'.')) != NULL) {
1696 *p = 0;
1697 push_ascii(buf+1,mask2,8, 0);
1698 push_ascii(buf+9,p+1,3, 0);
1699 *p = '.';
1700 } else {
1701 push_ascii(buf+1,mask2,11, 0);
1704 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1705 SCVAL(buf,21,mode);
1706 srv_put_dos_date(buf,22,date);
1707 SSVAL(buf,26,size & 0xFFFF);
1708 SSVAL(buf,28,(size >> 16)&0xFFFF);
1709 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1710 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1711 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1712 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1713 return True;
1716 /****************************************************************************
1717 Reply to a search.
1718 Can be called from SMBsearch, SMBffirst or SMBfunique.
1719 ****************************************************************************/
1721 void reply_search(struct smb_request *req)
1723 connection_struct *conn = req->conn;
1724 char *path = NULL;
1725 char *mask = NULL;
1726 char *directory = NULL;
1727 struct smb_filename *smb_fname = NULL;
1728 char *fname = NULL;
1729 off_t size;
1730 uint32_t mode;
1731 struct timespec date;
1732 uint32_t dirtype;
1733 unsigned int numentries = 0;
1734 unsigned int maxentries = 0;
1735 bool finished = False;
1736 const char *p;
1737 int status_len;
1738 char status[21];
1739 int dptr_num= -1;
1740 bool check_descend = False;
1741 bool expect_close = False;
1742 NTSTATUS nt_status;
1743 bool mask_contains_wcard = False;
1744 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1745 TALLOC_CTX *ctx = talloc_tos();
1746 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1747 struct dptr_struct *dirptr = NULL;
1748 struct smbXsrv_connection *xconn = req->xconn;
1749 struct smbd_server_connection *sconn = req->sconn;
1751 START_PROFILE(SMBsearch);
1753 if (req->wct < 2) {
1754 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1755 goto out;
1758 if (req->posix_pathnames) {
1759 reply_unknown_new(req, req->cmd);
1760 goto out;
1763 /* If we were called as SMBffirst then we must expect close. */
1764 if(req->cmd == SMBffirst) {
1765 expect_close = True;
1768 reply_outbuf(req, 1, 3);
1769 maxentries = SVAL(req->vwv+0, 0);
1770 dirtype = SVAL(req->vwv+1, 0);
1771 p = (const char *)req->buf + 1;
1772 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1773 &nt_status, &mask_contains_wcard);
1774 if (!NT_STATUS_IS_OK(nt_status)) {
1775 reply_nterror(req, nt_status);
1776 goto out;
1779 p++;
1780 status_len = SVAL(p, 0);
1781 p += 2;
1783 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1785 if (status_len == 0) {
1786 struct smb_filename *smb_dname = NULL;
1787 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1788 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
1789 nt_status = filename_convert(ctx, conn,
1790 req->flags2 & FLAGS2_DFS_PATHNAMES,
1791 path,
1792 ucf_flags,
1793 &mask_contains_wcard,
1794 &smb_fname);
1795 if (!NT_STATUS_IS_OK(nt_status)) {
1796 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1797 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1798 ERRSRV, ERRbadpath);
1799 goto out;
1801 reply_nterror(req, nt_status);
1802 goto out;
1805 directory = smb_fname->base_name;
1807 p = strrchr_m(directory,'/');
1808 if ((p != NULL) && (*directory != '/')) {
1809 mask = talloc_strdup(ctx, p + 1);
1810 directory = talloc_strndup(ctx, directory,
1811 PTR_DIFF(p, directory));
1812 } else {
1813 mask = talloc_strdup(ctx, directory);
1814 directory = talloc_strdup(ctx,".");
1817 if (!directory) {
1818 reply_nterror(req, NT_STATUS_NO_MEMORY);
1819 goto out;
1822 memset((char *)status,'\0',21);
1823 SCVAL(status,0,(dirtype & 0x1F));
1825 smb_dname = synthetic_smb_fname(talloc_tos(),
1826 directory,
1827 NULL,
1828 NULL,
1829 smb_fname->flags);
1830 if (smb_dname == NULL) {
1831 reply_nterror(req, NT_STATUS_NO_MEMORY);
1832 goto out;
1835 nt_status = dptr_create(conn,
1836 NULL, /* req */
1837 NULL, /* fsp */
1838 smb_dname,
1839 True,
1840 expect_close,
1841 req->smbpid,
1842 mask,
1843 mask_contains_wcard,
1844 dirtype,
1845 &dirptr);
1847 TALLOC_FREE(smb_dname);
1849 if (!NT_STATUS_IS_OK(nt_status)) {
1850 reply_nterror(req, nt_status);
1851 goto out;
1853 dptr_num = dptr_dnum(dirptr);
1854 } else {
1855 int status_dirtype;
1856 const char *dirpath;
1858 memcpy(status,p,21);
1859 status_dirtype = CVAL(status,0) & 0x1F;
1860 if (status_dirtype != (dirtype & 0x1F)) {
1861 dirtype = status_dirtype;
1864 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1865 if (!dirptr) {
1866 goto SearchEmpty;
1868 dirpath = dptr_path(sconn, dptr_num);
1869 directory = talloc_strdup(ctx, dirpath);
1870 if (!directory) {
1871 reply_nterror(req, NT_STATUS_NO_MEMORY);
1872 goto out;
1875 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1876 if (!mask) {
1877 goto SearchEmpty;
1880 * For a 'continue' search we have no string. So
1881 * check from the initial saved string.
1883 if (!req->posix_pathnames) {
1884 mask_contains_wcard = ms_has_wild(mask);
1886 dirtype = dptr_attr(sconn, dptr_num);
1889 DEBUG(4,("dptr_num is %d\n",dptr_num));
1891 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1892 dptr_init_search_op(dirptr);
1894 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1895 char buf[DIR_STRUCT_SIZE];
1896 memcpy(buf,status,21);
1897 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1898 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1899 reply_nterror(req, NT_STATUS_NO_MEMORY);
1900 goto out;
1902 dptr_fill(sconn, buf+12,dptr_num);
1903 if (dptr_zero(buf+12) && (status_len==0)) {
1904 numentries = 1;
1905 } else {
1906 numentries = 0;
1908 if (message_push_blob(&req->outbuf,
1909 data_blob_const(buf, sizeof(buf)))
1910 == -1) {
1911 reply_nterror(req, NT_STATUS_NO_MEMORY);
1912 goto out;
1914 } else {
1915 unsigned int i;
1916 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1917 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1919 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1921 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1922 directory,lp_dont_descend(ctx, SNUM(conn))));
1923 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1924 check_descend = True;
1927 for (i=numentries;(i<maxentries) && !finished;i++) {
1928 finished = !get_dir_entry(ctx,
1929 dirptr,
1930 mask,
1931 dirtype,
1932 &fname,
1933 &size,
1934 &mode,
1935 &date,
1936 check_descend,
1937 ask_sharemode);
1938 if (!finished) {
1939 char buf[DIR_STRUCT_SIZE];
1940 memcpy(buf,status,21);
1941 if (!make_dir_struct(ctx,
1942 buf,
1943 mask,
1944 fname,
1945 size,
1946 mode,
1947 convert_timespec_to_time_t(date),
1948 !allow_long_path_components)) {
1949 reply_nterror(req, NT_STATUS_NO_MEMORY);
1950 goto out;
1952 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1953 break;
1955 if (message_push_blob(&req->outbuf,
1956 data_blob_const(buf, sizeof(buf)))
1957 == -1) {
1958 reply_nterror(req, NT_STATUS_NO_MEMORY);
1959 goto out;
1961 numentries++;
1966 SearchEmpty:
1968 /* If we were called as SMBffirst with smb_search_id == NULL
1969 and no entries were found then return error and close dirptr
1970 (X/Open spec) */
1972 if (numentries == 0) {
1973 dptr_close(sconn, &dptr_num);
1974 } else if(expect_close && status_len == 0) {
1975 /* Close the dptr - we know it's gone */
1976 dptr_close(sconn, &dptr_num);
1979 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1980 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1981 dptr_close(sconn, &dptr_num);
1984 if ((numentries == 0) && !mask_contains_wcard) {
1985 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1986 goto out;
1989 SSVAL(req->outbuf,smb_vwv0,numentries);
1990 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1991 SCVAL(smb_buf(req->outbuf),0,5);
1992 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1994 /* The replies here are never long name. */
1995 SSVAL(req->outbuf, smb_flg2,
1996 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1997 if (!allow_long_path_components) {
1998 SSVAL(req->outbuf, smb_flg2,
1999 SVAL(req->outbuf, smb_flg2)
2000 & (~FLAGS2_LONG_PATH_COMPONENTS));
2003 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2004 SSVAL(req->outbuf, smb_flg2,
2005 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2007 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2008 smb_fn_name(req->cmd),
2009 mask,
2010 directory,
2011 dirtype,
2012 numentries,
2013 maxentries ));
2014 out:
2015 TALLOC_FREE(directory);
2016 TALLOC_FREE(mask);
2017 TALLOC_FREE(smb_fname);
2018 END_PROFILE(SMBsearch);
2019 return;
2022 /****************************************************************************
2023 Reply to a fclose (stop directory search).
2024 ****************************************************************************/
2026 void reply_fclose(struct smb_request *req)
2028 int status_len;
2029 char status[21];
2030 int dptr_num= -2;
2031 const char *p;
2032 char *path = NULL;
2033 NTSTATUS err;
2034 bool path_contains_wcard = False;
2035 TALLOC_CTX *ctx = talloc_tos();
2036 struct smbd_server_connection *sconn = req->sconn;
2038 START_PROFILE(SMBfclose);
2040 if (req->posix_pathnames) {
2041 reply_unknown_new(req, req->cmd);
2042 END_PROFILE(SMBfclose);
2043 return;
2046 p = (const char *)req->buf + 1;
2047 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2048 &err, &path_contains_wcard);
2049 if (!NT_STATUS_IS_OK(err)) {
2050 reply_nterror(req, err);
2051 END_PROFILE(SMBfclose);
2052 return;
2054 p++;
2055 status_len = SVAL(p,0);
2056 p += 2;
2058 if (status_len == 0) {
2059 reply_force_doserror(req, ERRSRV, ERRsrverror);
2060 END_PROFILE(SMBfclose);
2061 return;
2064 memcpy(status,p,21);
2066 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2067 /* Close the dptr - we know it's gone */
2068 dptr_close(sconn, &dptr_num);
2071 reply_outbuf(req, 1, 0);
2072 SSVAL(req->outbuf,smb_vwv0,0);
2074 DEBUG(3,("search close\n"));
2076 END_PROFILE(SMBfclose);
2077 return;
2080 /****************************************************************************
2081 Reply to an open.
2082 ****************************************************************************/
2084 void reply_open(struct smb_request *req)
2086 connection_struct *conn = req->conn;
2087 struct smb_filename *smb_fname = NULL;
2088 char *fname = NULL;
2089 uint32_t fattr=0;
2090 off_t size = 0;
2091 time_t mtime=0;
2092 int info;
2093 files_struct *fsp;
2094 int oplock_request;
2095 int deny_mode;
2096 uint32_t dos_attr;
2097 uint32_t access_mask;
2098 uint32_t share_mode;
2099 uint32_t create_disposition;
2100 uint32_t create_options = 0;
2101 uint32_t private_flags = 0;
2102 NTSTATUS status;
2103 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2104 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2105 TALLOC_CTX *ctx = talloc_tos();
2107 START_PROFILE(SMBopen);
2109 if (req->wct < 2) {
2110 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2111 goto out;
2114 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2115 deny_mode = SVAL(req->vwv+0, 0);
2116 dos_attr = SVAL(req->vwv+1, 0);
2118 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2119 STR_TERMINATE, &status);
2120 if (!NT_STATUS_IS_OK(status)) {
2121 reply_nterror(req, status);
2122 goto out;
2125 if (!map_open_params_to_ntcreate(fname, deny_mode,
2126 OPENX_FILE_EXISTS_OPEN, &access_mask,
2127 &share_mode, &create_disposition,
2128 &create_options, &private_flags)) {
2129 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2130 goto out;
2133 status = filename_convert(ctx,
2134 conn,
2135 req->flags2 & FLAGS2_DFS_PATHNAMES,
2136 fname,
2137 ucf_flags,
2138 NULL,
2139 &smb_fname);
2140 if (!NT_STATUS_IS_OK(status)) {
2141 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2142 reply_botherror(req,
2143 NT_STATUS_PATH_NOT_COVERED,
2144 ERRSRV, ERRbadpath);
2145 goto out;
2147 reply_nterror(req, status);
2148 goto out;
2151 status = SMB_VFS_CREATE_FILE(
2152 conn, /* conn */
2153 req, /* req */
2154 0, /* root_dir_fid */
2155 smb_fname, /* fname */
2156 access_mask, /* access_mask */
2157 share_mode, /* share_access */
2158 create_disposition, /* create_disposition*/
2159 create_options, /* create_options */
2160 dos_attr, /* file_attributes */
2161 oplock_request, /* oplock_request */
2162 NULL, /* lease */
2163 0, /* allocation_size */
2164 private_flags,
2165 NULL, /* sd */
2166 NULL, /* ea_list */
2167 &fsp, /* result */
2168 &info, /* pinfo */
2169 NULL, NULL); /* create context */
2171 if (!NT_STATUS_IS_OK(status)) {
2172 if (open_was_deferred(req->xconn, req->mid)) {
2173 /* We have re-scheduled this call. */
2174 goto out;
2176 reply_openerror(req, status);
2177 goto out;
2180 /* Ensure we're pointing at the correct stat struct. */
2181 TALLOC_FREE(smb_fname);
2182 smb_fname = fsp->fsp_name;
2184 size = smb_fname->st.st_ex_size;
2185 fattr = dos_mode(conn, smb_fname);
2187 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2189 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2190 DEBUG(3,("attempt to open a directory %s\n",
2191 fsp_str_dbg(fsp)));
2192 close_file(req, fsp, ERROR_CLOSE);
2193 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2194 ERRDOS, ERRnoaccess);
2195 goto out;
2198 reply_outbuf(req, 7, 0);
2199 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2200 SSVAL(req->outbuf,smb_vwv1,fattr);
2201 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2202 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2203 } else {
2204 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2206 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2207 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2209 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2210 SCVAL(req->outbuf,smb_flg,
2211 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2214 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2215 SCVAL(req->outbuf,smb_flg,
2216 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2218 out:
2219 END_PROFILE(SMBopen);
2220 return;
2223 /****************************************************************************
2224 Reply to an open and X.
2225 ****************************************************************************/
2227 void reply_open_and_X(struct smb_request *req)
2229 connection_struct *conn = req->conn;
2230 struct smb_filename *smb_fname = NULL;
2231 char *fname = NULL;
2232 uint16_t open_flags;
2233 int deny_mode;
2234 uint32_t smb_attr;
2235 /* Breakout the oplock request bits so we can set the
2236 reply bits separately. */
2237 int ex_oplock_request;
2238 int core_oplock_request;
2239 int oplock_request;
2240 #if 0
2241 int smb_sattr = SVAL(req->vwv+4, 0);
2242 uint32_t smb_time = make_unix_date3(req->vwv+6);
2243 #endif
2244 int smb_ofun;
2245 uint32_t fattr=0;
2246 int mtime=0;
2247 int smb_action = 0;
2248 files_struct *fsp;
2249 NTSTATUS status;
2250 uint64_t allocation_size;
2251 ssize_t retval = -1;
2252 uint32_t access_mask;
2253 uint32_t share_mode;
2254 uint32_t create_disposition;
2255 uint32_t create_options = 0;
2256 uint32_t private_flags = 0;
2257 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2258 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2259 TALLOC_CTX *ctx = talloc_tos();
2261 START_PROFILE(SMBopenX);
2263 if (req->wct < 15) {
2264 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2265 goto out;
2268 open_flags = SVAL(req->vwv+2, 0);
2269 deny_mode = SVAL(req->vwv+3, 0);
2270 smb_attr = SVAL(req->vwv+5, 0);
2271 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2272 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2273 oplock_request = ex_oplock_request | core_oplock_request;
2274 smb_ofun = SVAL(req->vwv+8, 0);
2275 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2277 /* If it's an IPC, pass off the pipe handler. */
2278 if (IS_IPC(conn)) {
2279 if (lp_nt_pipe_support()) {
2280 reply_open_pipe_and_X(conn, req);
2281 } else {
2282 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2284 goto out;
2287 /* XXXX we need to handle passed times, sattr and flags */
2288 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2289 STR_TERMINATE, &status);
2290 if (!NT_STATUS_IS_OK(status)) {
2291 reply_nterror(req, status);
2292 goto out;
2295 if (!map_open_params_to_ntcreate(fname, deny_mode,
2296 smb_ofun,
2297 &access_mask, &share_mode,
2298 &create_disposition,
2299 &create_options,
2300 &private_flags)) {
2301 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2302 goto out;
2305 status = filename_convert(ctx,
2306 conn,
2307 req->flags2 & FLAGS2_DFS_PATHNAMES,
2308 fname,
2309 ucf_flags,
2310 NULL,
2311 &smb_fname);
2312 if (!NT_STATUS_IS_OK(status)) {
2313 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2314 reply_botherror(req,
2315 NT_STATUS_PATH_NOT_COVERED,
2316 ERRSRV, ERRbadpath);
2317 goto out;
2319 reply_nterror(req, status);
2320 goto out;
2323 status = SMB_VFS_CREATE_FILE(
2324 conn, /* conn */
2325 req, /* req */
2326 0, /* root_dir_fid */
2327 smb_fname, /* fname */
2328 access_mask, /* access_mask */
2329 share_mode, /* share_access */
2330 create_disposition, /* create_disposition*/
2331 create_options, /* create_options */
2332 smb_attr, /* file_attributes */
2333 oplock_request, /* oplock_request */
2334 NULL, /* lease */
2335 0, /* allocation_size */
2336 private_flags,
2337 NULL, /* sd */
2338 NULL, /* ea_list */
2339 &fsp, /* result */
2340 &smb_action, /* pinfo */
2341 NULL, NULL); /* create context */
2343 if (!NT_STATUS_IS_OK(status)) {
2344 if (open_was_deferred(req->xconn, req->mid)) {
2345 /* We have re-scheduled this call. */
2346 goto out;
2348 reply_openerror(req, status);
2349 goto out;
2352 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2353 if the file is truncated or created. */
2354 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2355 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2356 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2357 close_file(req, fsp, ERROR_CLOSE);
2358 reply_nterror(req, NT_STATUS_DISK_FULL);
2359 goto out;
2361 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2362 if (retval < 0) {
2363 close_file(req, fsp, ERROR_CLOSE);
2364 reply_nterror(req, NT_STATUS_DISK_FULL);
2365 goto out;
2367 status = vfs_stat_fsp(fsp);
2368 if (!NT_STATUS_IS_OK(status)) {
2369 close_file(req, fsp, ERROR_CLOSE);
2370 reply_nterror(req, status);
2371 goto out;
2375 fattr = dos_mode(conn, fsp->fsp_name);
2376 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2377 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2378 close_file(req, fsp, ERROR_CLOSE);
2379 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2380 goto out;
2383 /* If the caller set the extended oplock request bit
2384 and we granted one (by whatever means) - set the
2385 correct bit for extended oplock reply.
2388 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2389 smb_action |= EXTENDED_OPLOCK_GRANTED;
2392 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2393 smb_action |= EXTENDED_OPLOCK_GRANTED;
2396 /* If the caller set the core oplock request bit
2397 and we granted one (by whatever means) - set the
2398 correct bit for core oplock reply.
2401 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2402 reply_outbuf(req, 19, 0);
2403 } else {
2404 reply_outbuf(req, 15, 0);
2407 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2408 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2410 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2411 SCVAL(req->outbuf, smb_flg,
2412 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2415 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2416 SCVAL(req->outbuf, smb_flg,
2417 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2420 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2421 SSVAL(req->outbuf,smb_vwv3,fattr);
2422 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2423 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2424 } else {
2425 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2427 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2428 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2429 SSVAL(req->outbuf,smb_vwv11,smb_action);
2431 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2432 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2435 out:
2436 TALLOC_FREE(smb_fname);
2437 END_PROFILE(SMBopenX);
2438 return;
2441 /****************************************************************************
2442 Reply to a SMBulogoffX.
2443 ****************************************************************************/
2445 void reply_ulogoffX(struct smb_request *req)
2447 struct smbd_server_connection *sconn = req->sconn;
2448 struct user_struct *vuser;
2449 struct smbXsrv_session *session = NULL;
2450 NTSTATUS status;
2452 START_PROFILE(SMBulogoffX);
2454 vuser = get_valid_user_struct(sconn, req->vuid);
2456 if(vuser == NULL) {
2457 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2458 (unsigned long long)req->vuid));
2460 req->vuid = UID_FIELD_INVALID;
2461 reply_force_doserror(req, ERRSRV, ERRbaduid);
2462 END_PROFILE(SMBulogoffX);
2463 return;
2466 session = vuser->session;
2467 vuser = NULL;
2470 * TODO: cancel all outstanding requests on the session
2472 status = smbXsrv_session_logoff(session);
2473 if (!NT_STATUS_IS_OK(status)) {
2474 DEBUG(0, ("reply_ulogoff: "
2475 "smbXsrv_session_logoff() failed: %s\n",
2476 nt_errstr(status)));
2478 * If we hit this case, there is something completely
2479 * wrong, so we better disconnect the transport connection.
2481 END_PROFILE(SMBulogoffX);
2482 exit_server(__location__ ": smbXsrv_session_logoff failed");
2483 return;
2486 TALLOC_FREE(session);
2488 reply_outbuf(req, 2, 0);
2489 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2490 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2492 DEBUG(3, ("ulogoffX vuid=%llu\n",
2493 (unsigned long long)req->vuid));
2495 END_PROFILE(SMBulogoffX);
2496 req->vuid = UID_FIELD_INVALID;
2499 /****************************************************************************
2500 Reply to a mknew or a create.
2501 ****************************************************************************/
2503 void reply_mknew(struct smb_request *req)
2505 connection_struct *conn = req->conn;
2506 struct smb_filename *smb_fname = NULL;
2507 char *fname = NULL;
2508 uint32_t fattr = 0;
2509 struct smb_file_time ft;
2510 files_struct *fsp;
2511 int oplock_request = 0;
2512 NTSTATUS status;
2513 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2514 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2515 uint32_t create_disposition;
2516 uint32_t create_options = 0;
2517 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2518 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2519 TALLOC_CTX *ctx = talloc_tos();
2521 START_PROFILE(SMBcreate);
2522 ZERO_STRUCT(ft);
2524 if (req->wct < 3) {
2525 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2526 goto out;
2529 fattr = SVAL(req->vwv+0, 0);
2530 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2532 /* mtime. */
2533 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2535 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2536 STR_TERMINATE, &status);
2537 if (!NT_STATUS_IS_OK(status)) {
2538 reply_nterror(req, status);
2539 goto out;
2542 status = filename_convert(ctx,
2543 conn,
2544 req->flags2 & FLAGS2_DFS_PATHNAMES,
2545 fname,
2546 ucf_flags,
2547 NULL,
2548 &smb_fname);
2549 if (!NT_STATUS_IS_OK(status)) {
2550 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2551 reply_botherror(req,
2552 NT_STATUS_PATH_NOT_COVERED,
2553 ERRSRV, ERRbadpath);
2554 goto out;
2556 reply_nterror(req, status);
2557 goto out;
2560 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2561 DEBUG(0,("Attempt to create file (%s) with volid set - "
2562 "please report this\n",
2563 smb_fname_str_dbg(smb_fname)));
2566 if(req->cmd == SMBmknew) {
2567 /* We should fail if file exists. */
2568 create_disposition = FILE_CREATE;
2569 } else {
2570 /* Create if file doesn't exist, truncate if it does. */
2571 create_disposition = FILE_OVERWRITE_IF;
2574 status = SMB_VFS_CREATE_FILE(
2575 conn, /* conn */
2576 req, /* req */
2577 0, /* root_dir_fid */
2578 smb_fname, /* fname */
2579 access_mask, /* access_mask */
2580 share_mode, /* share_access */
2581 create_disposition, /* create_disposition*/
2582 create_options, /* create_options */
2583 fattr, /* file_attributes */
2584 oplock_request, /* oplock_request */
2585 NULL, /* lease */
2586 0, /* allocation_size */
2587 0, /* private_flags */
2588 NULL, /* sd */
2589 NULL, /* ea_list */
2590 &fsp, /* result */
2591 NULL, /* pinfo */
2592 NULL, NULL); /* create context */
2594 if (!NT_STATUS_IS_OK(status)) {
2595 if (open_was_deferred(req->xconn, req->mid)) {
2596 /* We have re-scheduled this call. */
2597 goto out;
2599 reply_openerror(req, status);
2600 goto out;
2603 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2604 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2605 if (!NT_STATUS_IS_OK(status)) {
2606 END_PROFILE(SMBcreate);
2607 goto out;
2610 reply_outbuf(req, 1, 0);
2611 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2613 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2614 SCVAL(req->outbuf,smb_flg,
2615 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2618 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2619 SCVAL(req->outbuf,smb_flg,
2620 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2623 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2624 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2625 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2626 (unsigned int)fattr));
2628 out:
2629 TALLOC_FREE(smb_fname);
2630 END_PROFILE(SMBcreate);
2631 return;
2634 /****************************************************************************
2635 Reply to a create temporary file.
2636 ****************************************************************************/
2638 void reply_ctemp(struct smb_request *req)
2640 connection_struct *conn = req->conn;
2641 struct smb_filename *smb_fname = NULL;
2642 char *wire_name = NULL;
2643 char *fname = NULL;
2644 uint32_t fattr;
2645 files_struct *fsp;
2646 int oplock_request;
2647 char *s;
2648 NTSTATUS status;
2649 int i;
2650 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
2651 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
2652 TALLOC_CTX *ctx = talloc_tos();
2654 START_PROFILE(SMBctemp);
2656 if (req->wct < 3) {
2657 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2658 goto out;
2661 fattr = SVAL(req->vwv+0, 0);
2662 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2664 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2665 STR_TERMINATE, &status);
2666 if (!NT_STATUS_IS_OK(status)) {
2667 reply_nterror(req, status);
2668 goto out;
2671 for (i = 0; i < 10; i++) {
2672 if (*wire_name) {
2673 fname = talloc_asprintf(ctx,
2674 "%s/TMP%s",
2675 wire_name,
2676 generate_random_str_list(ctx, 5, "0123456789"));
2677 } else {
2678 fname = talloc_asprintf(ctx,
2679 "TMP%s",
2680 generate_random_str_list(ctx, 5, "0123456789"));
2683 if (!fname) {
2684 reply_nterror(req, NT_STATUS_NO_MEMORY);
2685 goto out;
2688 status = filename_convert(ctx, conn,
2689 req->flags2 & FLAGS2_DFS_PATHNAMES,
2690 fname,
2691 ucf_flags,
2692 NULL,
2693 &smb_fname);
2694 if (!NT_STATUS_IS_OK(status)) {
2695 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2696 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2697 ERRSRV, ERRbadpath);
2698 goto out;
2700 reply_nterror(req, status);
2701 goto out;
2704 /* Create the file. */
2705 status = SMB_VFS_CREATE_FILE(
2706 conn, /* conn */
2707 req, /* req */
2708 0, /* root_dir_fid */
2709 smb_fname, /* fname */
2710 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2711 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2712 FILE_CREATE, /* create_disposition*/
2713 0, /* create_options */
2714 fattr, /* file_attributes */
2715 oplock_request, /* oplock_request */
2716 NULL, /* lease */
2717 0, /* allocation_size */
2718 0, /* private_flags */
2719 NULL, /* sd */
2720 NULL, /* ea_list */
2721 &fsp, /* result */
2722 NULL, /* pinfo */
2723 NULL, NULL); /* create context */
2725 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2726 TALLOC_FREE(fname);
2727 TALLOC_FREE(smb_fname);
2728 continue;
2731 if (!NT_STATUS_IS_OK(status)) {
2732 if (open_was_deferred(req->xconn, req->mid)) {
2733 /* We have re-scheduled this call. */
2734 goto out;
2736 reply_openerror(req, status);
2737 goto out;
2740 break;
2743 if (i == 10) {
2744 /* Collision after 10 times... */
2745 reply_nterror(req, status);
2746 goto out;
2749 reply_outbuf(req, 1, 0);
2750 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2752 /* the returned filename is relative to the directory */
2753 s = strrchr_m(fsp->fsp_name->base_name, '/');
2754 if (!s) {
2755 s = fsp->fsp_name->base_name;
2756 } else {
2757 s++;
2760 #if 0
2761 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2762 thing in the byte section. JRA */
2763 SSVALS(p, 0, -1); /* what is this? not in spec */
2764 #endif
2765 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2766 == -1) {
2767 reply_nterror(req, NT_STATUS_NO_MEMORY);
2768 goto out;
2771 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2772 SCVAL(req->outbuf, smb_flg,
2773 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2776 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2777 SCVAL(req->outbuf, smb_flg,
2778 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2781 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2782 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2783 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2784 out:
2785 TALLOC_FREE(smb_fname);
2786 TALLOC_FREE(wire_name);
2787 END_PROFILE(SMBctemp);
2788 return;
2791 /*******************************************************************
2792 Check if a user is allowed to rename a file.
2793 ********************************************************************/
2795 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2796 uint16_t dirtype)
2798 if (!CAN_WRITE(conn)) {
2799 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2802 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2803 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2804 /* Only bother to read the DOS attribute if we might deny the
2805 rename on the grounds of attribute mismatch. */
2806 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2807 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2808 return NT_STATUS_NO_SUCH_FILE;
2812 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2813 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2814 return NT_STATUS_OK;
2817 /* If no pathnames are open below this
2818 directory, allow the rename. */
2820 if (lp_strict_rename(SNUM(conn))) {
2822 * Strict rename, check open file db.
2824 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2825 return NT_STATUS_ACCESS_DENIED;
2827 } else if (file_find_subpath(fsp)) {
2829 * No strict rename, just look in local process.
2831 return NT_STATUS_ACCESS_DENIED;
2833 return NT_STATUS_OK;
2836 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2837 return NT_STATUS_OK;
2840 return NT_STATUS_ACCESS_DENIED;
2843 /*******************************************************************
2844 * unlink a file with all relevant access checks
2845 *******************************************************************/
2847 static NTSTATUS do_unlink(connection_struct *conn,
2848 struct smb_request *req,
2849 struct smb_filename *smb_fname,
2850 uint32_t dirtype)
2852 uint32_t fattr;
2853 files_struct *fsp;
2854 uint32_t dirtype_orig = dirtype;
2855 NTSTATUS status;
2856 int ret;
2857 bool posix_paths = (req != NULL && req->posix_pathnames);
2859 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2860 smb_fname_str_dbg(smb_fname),
2861 dirtype));
2863 if (!CAN_WRITE(conn)) {
2864 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2867 if (posix_paths) {
2868 ret = SMB_VFS_LSTAT(conn, smb_fname);
2869 } else {
2870 ret = SMB_VFS_STAT(conn, smb_fname);
2872 if (ret != 0) {
2873 return map_nt_error_from_unix(errno);
2876 fattr = dos_mode(conn, smb_fname);
2878 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2879 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2882 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2883 if (!dirtype) {
2884 return NT_STATUS_NO_SUCH_FILE;
2887 if (!dir_check_ftype(fattr, dirtype)) {
2888 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2889 return NT_STATUS_FILE_IS_A_DIRECTORY;
2891 return NT_STATUS_NO_SUCH_FILE;
2894 if (dirtype_orig & 0x8000) {
2895 /* These will never be set for POSIX. */
2896 return NT_STATUS_NO_SUCH_FILE;
2899 #if 0
2900 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2901 return NT_STATUS_FILE_IS_A_DIRECTORY;
2904 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2905 return NT_STATUS_NO_SUCH_FILE;
2908 if (dirtype & 0xFF00) {
2909 /* These will never be set for POSIX. */
2910 return NT_STATUS_NO_SUCH_FILE;
2913 dirtype &= 0xFF;
2914 if (!dirtype) {
2915 return NT_STATUS_NO_SUCH_FILE;
2918 /* Can't delete a directory. */
2919 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2920 return NT_STATUS_FILE_IS_A_DIRECTORY;
2922 #endif
2924 #if 0 /* JRATEST */
2925 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2926 return NT_STATUS_OBJECT_NAME_INVALID;
2927 #endif /* JRATEST */
2929 /* On open checks the open itself will check the share mode, so
2930 don't do it here as we'll get it wrong. */
2932 status = SMB_VFS_CREATE_FILE
2933 (conn, /* conn */
2934 req, /* req */
2935 0, /* root_dir_fid */
2936 smb_fname, /* fname */
2937 DELETE_ACCESS, /* access_mask */
2938 FILE_SHARE_NONE, /* share_access */
2939 FILE_OPEN, /* create_disposition*/
2940 FILE_NON_DIRECTORY_FILE, /* create_options */
2941 /* file_attributes */
2942 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2943 FILE_ATTRIBUTE_NORMAL,
2944 0, /* oplock_request */
2945 NULL, /* lease */
2946 0, /* allocation_size */
2947 0, /* private_flags */
2948 NULL, /* sd */
2949 NULL, /* ea_list */
2950 &fsp, /* result */
2951 NULL, /* pinfo */
2952 NULL, NULL); /* create context */
2954 if (!NT_STATUS_IS_OK(status)) {
2955 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2956 nt_errstr(status)));
2957 return status;
2960 status = can_set_delete_on_close(fsp, fattr);
2961 if (!NT_STATUS_IS_OK(status)) {
2962 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2963 "(%s)\n",
2964 smb_fname_str_dbg(smb_fname),
2965 nt_errstr(status)));
2966 close_file(req, fsp, NORMAL_CLOSE);
2967 return status;
2970 /* The set is across all open files on this dev/inode pair. */
2971 if (!set_delete_on_close(fsp, True,
2972 conn->session_info->security_token,
2973 conn->session_info->unix_token)) {
2974 close_file(req, fsp, NORMAL_CLOSE);
2975 return NT_STATUS_ACCESS_DENIED;
2978 return close_file(req, fsp, NORMAL_CLOSE);
2981 /****************************************************************************
2982 The guts of the unlink command, split out so it may be called by the NT SMB
2983 code.
2984 ****************************************************************************/
2986 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2987 uint32_t dirtype, struct smb_filename *smb_fname,
2988 bool has_wild)
2990 char *fname_dir = NULL;
2991 char *fname_mask = NULL;
2992 int count=0;
2993 NTSTATUS status = NT_STATUS_OK;
2994 struct smb_filename *smb_fname_dir = NULL;
2995 TALLOC_CTX *ctx = talloc_tos();
2997 /* Split up the directory from the filename/mask. */
2998 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2999 &fname_dir, &fname_mask);
3000 if (!NT_STATUS_IS_OK(status)) {
3001 goto out;
3005 * We should only check the mangled cache
3006 * here if unix_convert failed. This means
3007 * that the path in 'mask' doesn't exist
3008 * on the file system and so we need to look
3009 * for a possible mangle. This patch from
3010 * Tine Smukavec <valentin.smukavec@hermes.si>.
3013 if (!VALID_STAT(smb_fname->st) &&
3014 mangle_is_mangled(fname_mask, conn->params)) {
3015 char *new_mask = NULL;
3016 mangle_lookup_name_from_8_3(ctx, fname_mask,
3017 &new_mask, conn->params);
3018 if (new_mask) {
3019 TALLOC_FREE(fname_mask);
3020 fname_mask = new_mask;
3024 if (!has_wild) {
3027 * Only one file needs to be unlinked. Append the mask back
3028 * onto the directory.
3030 TALLOC_FREE(smb_fname->base_name);
3031 if (ISDOT(fname_dir)) {
3032 /* Ensure we use canonical names on open. */
3033 smb_fname->base_name = talloc_asprintf(smb_fname,
3034 "%s",
3035 fname_mask);
3036 } else {
3037 smb_fname->base_name = talloc_asprintf(smb_fname,
3038 "%s/%s",
3039 fname_dir,
3040 fname_mask);
3042 if (!smb_fname->base_name) {
3043 status = NT_STATUS_NO_MEMORY;
3044 goto out;
3046 if (dirtype == 0) {
3047 dirtype = FILE_ATTRIBUTE_NORMAL;
3050 status = check_name(conn, smb_fname->base_name);
3051 if (!NT_STATUS_IS_OK(status)) {
3052 goto out;
3055 status = do_unlink(conn, req, smb_fname, dirtype);
3056 if (!NT_STATUS_IS_OK(status)) {
3057 goto out;
3060 count++;
3061 } else {
3062 struct smb_Dir *dir_hnd = NULL;
3063 long offset = 0;
3064 const char *dname = NULL;
3065 char *talloced = NULL;
3067 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3068 status = NT_STATUS_OBJECT_NAME_INVALID;
3069 goto out;
3071 if (dirtype == 0) {
3072 dirtype = FILE_ATTRIBUTE_NORMAL;
3075 if (strequal(fname_mask,"????????.???")) {
3076 TALLOC_FREE(fname_mask);
3077 fname_mask = talloc_strdup(ctx, "*");
3078 if (!fname_mask) {
3079 status = NT_STATUS_NO_MEMORY;
3080 goto out;
3084 status = check_name(conn, fname_dir);
3085 if (!NT_STATUS_IS_OK(status)) {
3086 goto out;
3089 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3090 fname_dir,
3091 NULL,
3092 NULL,
3093 smb_fname->flags);
3094 if (smb_fname_dir == NULL) {
3095 status = NT_STATUS_NO_MEMORY;
3096 goto out;
3099 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3100 dirtype);
3101 if (dir_hnd == NULL) {
3102 status = map_nt_error_from_unix(errno);
3103 goto out;
3106 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3107 the pattern matches against the long name, otherwise the short name
3108 We don't implement this yet XXXX
3111 status = NT_STATUS_NO_SUCH_FILE;
3113 while ((dname = ReadDirName(dir_hnd, &offset,
3114 &smb_fname->st, &talloced))) {
3115 TALLOC_CTX *frame = talloc_stackframe();
3117 if (!is_visible_file(conn, fname_dir, dname,
3118 &smb_fname->st, true)) {
3119 TALLOC_FREE(frame);
3120 TALLOC_FREE(talloced);
3121 continue;
3124 /* Quick check for "." and ".." */
3125 if (ISDOT(dname) || ISDOTDOT(dname)) {
3126 TALLOC_FREE(frame);
3127 TALLOC_FREE(talloced);
3128 continue;
3131 if(!mask_match(dname, fname_mask,
3132 conn->case_sensitive)) {
3133 TALLOC_FREE(frame);
3134 TALLOC_FREE(talloced);
3135 continue;
3138 TALLOC_FREE(smb_fname->base_name);
3139 if (ISDOT(fname_dir)) {
3140 /* Ensure we use canonical names on open. */
3141 smb_fname->base_name =
3142 talloc_asprintf(smb_fname, "%s",
3143 dname);
3144 } else {
3145 smb_fname->base_name =
3146 talloc_asprintf(smb_fname, "%s/%s",
3147 fname_dir, dname);
3150 if (!smb_fname->base_name) {
3151 TALLOC_FREE(dir_hnd);
3152 status = NT_STATUS_NO_MEMORY;
3153 TALLOC_FREE(frame);
3154 TALLOC_FREE(talloced);
3155 goto out;
3158 status = check_name(conn, smb_fname->base_name);
3159 if (!NT_STATUS_IS_OK(status)) {
3160 TALLOC_FREE(dir_hnd);
3161 TALLOC_FREE(frame);
3162 TALLOC_FREE(talloced);
3163 goto out;
3166 status = do_unlink(conn, req, smb_fname, dirtype);
3167 if (!NT_STATUS_IS_OK(status)) {
3168 TALLOC_FREE(dir_hnd);
3169 TALLOC_FREE(frame);
3170 TALLOC_FREE(talloced);
3171 goto out;
3174 count++;
3175 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3176 smb_fname->base_name));
3178 TALLOC_FREE(frame);
3179 TALLOC_FREE(talloced);
3181 TALLOC_FREE(dir_hnd);
3184 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3185 status = map_nt_error_from_unix(errno);
3188 out:
3189 TALLOC_FREE(smb_fname_dir);
3190 TALLOC_FREE(fname_dir);
3191 TALLOC_FREE(fname_mask);
3192 return status;
3195 /****************************************************************************
3196 Reply to a unlink
3197 ****************************************************************************/
3199 void reply_unlink(struct smb_request *req)
3201 connection_struct *conn = req->conn;
3202 char *name = NULL;
3203 struct smb_filename *smb_fname = NULL;
3204 uint32_t dirtype;
3205 NTSTATUS status;
3206 bool path_contains_wcard = False;
3207 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3208 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
3209 TALLOC_CTX *ctx = talloc_tos();
3211 START_PROFILE(SMBunlink);
3213 if (req->wct < 1) {
3214 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3215 goto out;
3218 dirtype = SVAL(req->vwv+0, 0);
3220 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3221 STR_TERMINATE, &status,
3222 &path_contains_wcard);
3223 if (!NT_STATUS_IS_OK(status)) {
3224 reply_nterror(req, status);
3225 goto out;
3228 status = filename_convert(ctx, conn,
3229 req->flags2 & FLAGS2_DFS_PATHNAMES,
3230 name,
3231 ucf_flags,
3232 &path_contains_wcard,
3233 &smb_fname);
3234 if (!NT_STATUS_IS_OK(status)) {
3235 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3236 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3237 ERRSRV, ERRbadpath);
3238 goto out;
3240 reply_nterror(req, status);
3241 goto out;
3244 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3246 status = unlink_internals(conn, req, dirtype, smb_fname,
3247 path_contains_wcard);
3248 if (!NT_STATUS_IS_OK(status)) {
3249 if (open_was_deferred(req->xconn, req->mid)) {
3250 /* We have re-scheduled this call. */
3251 goto out;
3253 reply_nterror(req, status);
3254 goto out;
3257 reply_outbuf(req, 0, 0);
3258 out:
3259 TALLOC_FREE(smb_fname);
3260 END_PROFILE(SMBunlink);
3261 return;
3264 /****************************************************************************
3265 Fail for readbraw.
3266 ****************************************************************************/
3268 static void fail_readraw(void)
3270 const char *errstr = talloc_asprintf(talloc_tos(),
3271 "FAIL ! reply_readbraw: socket write fail (%s)",
3272 strerror(errno));
3273 if (!errstr) {
3274 errstr = "";
3276 exit_server_cleanly(errstr);
3279 /****************************************************************************
3280 Fake (read/write) sendfile. Returns -1 on read or write fail.
3281 ****************************************************************************/
3283 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3284 off_t startpos, size_t nread)
3286 size_t bufsize;
3287 size_t tosend = nread;
3288 char *buf;
3290 if (nread == 0) {
3291 return 0;
3294 bufsize = MIN(nread, 65536);
3296 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3297 return -1;
3300 while (tosend > 0) {
3301 ssize_t ret;
3302 size_t cur_read;
3304 cur_read = MIN(tosend, bufsize);
3305 ret = read_file(fsp,buf,startpos,cur_read);
3306 if (ret == -1) {
3307 SAFE_FREE(buf);
3308 return -1;
3311 /* If we had a short read, fill with zeros. */
3312 if (ret < cur_read) {
3313 memset(buf + ret, '\0', cur_read - ret);
3316 ret = write_data(xconn->transport.sock, buf, cur_read);
3317 if (ret != cur_read) {
3318 int saved_errno = errno;
3320 * Try and give an error message saying what
3321 * client failed.
3323 DEBUG(0, ("write_data failed for client %s. "
3324 "Error %s\n",
3325 smbXsrv_connection_dbg(xconn),
3326 strerror(saved_errno)));
3327 SAFE_FREE(buf);
3328 errno = saved_errno;
3329 return -1;
3331 tosend -= cur_read;
3332 startpos += cur_read;
3335 SAFE_FREE(buf);
3336 return (ssize_t)nread;
3339 /****************************************************************************
3340 Deal with the case of sendfile reading less bytes from the file than
3341 requested. Fill with zeros (all we can do). Returns 0 on success
3342 ****************************************************************************/
3344 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3345 files_struct *fsp,
3346 ssize_t nread,
3347 size_t headersize,
3348 size_t smb_maxcnt)
3350 #define SHORT_SEND_BUFSIZE 1024
3351 if (nread < headersize) {
3352 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3353 "header for file %s (%s). Terminating\n",
3354 fsp_str_dbg(fsp), strerror(errno)));
3355 return -1;
3358 nread -= headersize;
3360 if (nread < smb_maxcnt) {
3361 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3362 if (!buf) {
3363 DEBUG(0,("sendfile_short_send: malloc failed "
3364 "for file %s (%s). Terminating\n",
3365 fsp_str_dbg(fsp), strerror(errno)));
3366 return -1;
3369 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3370 "with zeros !\n", fsp_str_dbg(fsp)));
3372 while (nread < smb_maxcnt) {
3374 * We asked for the real file size and told sendfile
3375 * to not go beyond the end of the file. But it can
3376 * happen that in between our fstat call and the
3377 * sendfile call the file was truncated. This is very
3378 * bad because we have already announced the larger
3379 * number of bytes to the client.
3381 * The best we can do now is to send 0-bytes, just as
3382 * a read from a hole in a sparse file would do.
3384 * This should happen rarely enough that I don't care
3385 * about efficiency here :-)
3387 size_t to_write;
3388 ssize_t ret;
3390 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3391 ret = write_data(xconn->transport.sock, buf, to_write);
3392 if (ret != to_write) {
3393 int saved_errno = errno;
3395 * Try and give an error message saying what
3396 * client failed.
3398 DEBUG(0, ("write_data failed for client %s. "
3399 "Error %s\n",
3400 smbXsrv_connection_dbg(xconn),
3401 strerror(saved_errno)));
3402 errno = saved_errno;
3403 return -1;
3405 nread += to_write;
3407 SAFE_FREE(buf);
3410 return 0;
3413 /****************************************************************************
3414 Return a readbraw error (4 bytes of zero).
3415 ****************************************************************************/
3417 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3419 char header[4];
3421 SIVAL(header,0,0);
3423 smbd_lock_socket(xconn);
3424 if (write_data(xconn->transport.sock,header,4) != 4) {
3425 int saved_errno = errno;
3427 * Try and give an error message saying what
3428 * client failed.
3430 DEBUG(0, ("write_data failed for client %s. "
3431 "Error %s\n",
3432 smbXsrv_connection_dbg(xconn),
3433 strerror(saved_errno)));
3434 errno = saved_errno;
3436 fail_readraw();
3438 smbd_unlock_socket(xconn);
3441 /****************************************************************************
3442 Use sendfile in readbraw.
3443 ****************************************************************************/
3445 static void send_file_readbraw(connection_struct *conn,
3446 struct smb_request *req,
3447 files_struct *fsp,
3448 off_t startpos,
3449 size_t nread,
3450 ssize_t mincount)
3452 struct smbXsrv_connection *xconn = req->xconn;
3453 char *outbuf = NULL;
3454 ssize_t ret=0;
3457 * We can only use sendfile on a non-chained packet
3458 * but we can use on a non-oplocked file. tridge proved this
3459 * on a train in Germany :-). JRA.
3460 * reply_readbraw has already checked the length.
3463 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3464 (fsp->wcp == NULL) &&
3465 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3466 ssize_t sendfile_read = -1;
3467 char header[4];
3468 DATA_BLOB header_blob;
3470 _smb_setlen(header,nread);
3471 header_blob = data_blob_const(header, 4);
3473 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3474 &header_blob, startpos,
3475 nread);
3476 if (sendfile_read == -1) {
3477 /* Returning ENOSYS means no data at all was sent.
3478 * Do this as a normal read. */
3479 if (errno == ENOSYS) {
3480 goto normal_readbraw;
3484 * Special hack for broken Linux with no working sendfile. If we
3485 * return EINTR we sent the header but not the rest of the data.
3486 * Fake this up by doing read/write calls.
3488 if (errno == EINTR) {
3489 /* Ensure we don't do this again. */
3490 set_use_sendfile(SNUM(conn), False);
3491 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3493 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3494 DEBUG(0,("send_file_readbraw: "
3495 "fake_sendfile failed for "
3496 "file %s (%s).\n",
3497 fsp_str_dbg(fsp),
3498 strerror(errno)));
3499 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3501 return;
3504 DEBUG(0,("send_file_readbraw: sendfile failed for "
3505 "file %s (%s). Terminating\n",
3506 fsp_str_dbg(fsp), strerror(errno)));
3507 exit_server_cleanly("send_file_readbraw sendfile failed");
3508 } else if (sendfile_read == 0) {
3510 * Some sendfile implementations return 0 to indicate
3511 * that there was a short read, but nothing was
3512 * actually written to the socket. In this case,
3513 * fallback to the normal read path so the header gets
3514 * the correct byte count.
3516 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3517 "bytes falling back to the normal read: "
3518 "%s\n", fsp_str_dbg(fsp)));
3519 goto normal_readbraw;
3522 /* Deal with possible short send. */
3523 if (sendfile_read != 4+nread) {
3524 ret = sendfile_short_send(xconn, fsp,
3525 sendfile_read, 4, nread);
3526 if (ret == -1) {
3527 fail_readraw();
3530 return;
3533 normal_readbraw:
3535 outbuf = talloc_array(NULL, char, nread+4);
3536 if (!outbuf) {
3537 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3538 (unsigned)(nread+4)));
3539 reply_readbraw_error(xconn);
3540 return;
3543 if (nread > 0) {
3544 ret = read_file(fsp,outbuf+4,startpos,nread);
3545 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3546 if (ret < mincount)
3547 ret = 0;
3548 #else
3549 if (ret < nread)
3550 ret = 0;
3551 #endif
3554 _smb_setlen(outbuf,ret);
3555 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3556 int saved_errno = errno;
3558 * Try and give an error message saying what
3559 * client failed.
3561 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3562 smbXsrv_connection_dbg(xconn),
3563 strerror(saved_errno)));
3564 errno = saved_errno;
3566 fail_readraw();
3569 TALLOC_FREE(outbuf);
3572 /****************************************************************************
3573 Reply to a readbraw (core+ protocol).
3574 ****************************************************************************/
3576 void reply_readbraw(struct smb_request *req)
3578 connection_struct *conn = req->conn;
3579 struct smbXsrv_connection *xconn = req->xconn;
3580 ssize_t maxcount,mincount;
3581 size_t nread = 0;
3582 off_t startpos;
3583 files_struct *fsp;
3584 struct lock_struct lock;
3585 off_t size = 0;
3587 START_PROFILE(SMBreadbraw);
3589 if (srv_is_signing_active(xconn) || req->encrypted) {
3590 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3591 "raw reads/writes are disallowed.");
3594 if (req->wct < 8) {
3595 reply_readbraw_error(xconn);
3596 END_PROFILE(SMBreadbraw);
3597 return;
3600 if (xconn->smb1.echo_handler.trusted_fde) {
3601 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3602 "'async smb echo handler = yes'\n"));
3603 reply_readbraw_error(xconn);
3604 END_PROFILE(SMBreadbraw);
3605 return;
3609 * Special check if an oplock break has been issued
3610 * and the readraw request croses on the wire, we must
3611 * return a zero length response here.
3614 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3617 * We have to do a check_fsp by hand here, as
3618 * we must always return 4 zero bytes on error,
3619 * not a NTSTATUS.
3622 if (!fsp || !conn || conn != fsp->conn ||
3623 req->vuid != fsp->vuid ||
3624 fsp->is_directory || fsp->fh->fd == -1) {
3626 * fsp could be NULL here so use the value from the packet. JRA.
3628 DEBUG(3,("reply_readbraw: fnum %d not valid "
3629 "- cache prime?\n",
3630 (int)SVAL(req->vwv+0, 0)));
3631 reply_readbraw_error(xconn);
3632 END_PROFILE(SMBreadbraw);
3633 return;
3636 /* Do a "by hand" version of CHECK_READ. */
3637 if (!(fsp->can_read ||
3638 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3639 (fsp->access_mask & FILE_EXECUTE)))) {
3640 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3641 (int)SVAL(req->vwv+0, 0)));
3642 reply_readbraw_error(xconn);
3643 END_PROFILE(SMBreadbraw);
3644 return;
3647 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3649 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3650 if(req->wct == 10) {
3652 * This is a large offset (64 bit) read.
3655 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3657 if(startpos < 0) {
3658 DEBUG(0,("reply_readbraw: negative 64 bit "
3659 "readraw offset (%.0f) !\n",
3660 (double)startpos ));
3661 reply_readbraw_error(xconn);
3662 END_PROFILE(SMBreadbraw);
3663 return;
3667 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3668 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3670 /* ensure we don't overrun the packet size */
3671 maxcount = MIN(65535,maxcount);
3673 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3674 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3675 &lock);
3677 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3678 reply_readbraw_error(xconn);
3679 END_PROFILE(SMBreadbraw);
3680 return;
3683 if (fsp_stat(fsp) == 0) {
3684 size = fsp->fsp_name->st.st_ex_size;
3687 if (startpos >= size) {
3688 nread = 0;
3689 } else {
3690 nread = MIN(maxcount,(size - startpos));
3693 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3694 if (nread < mincount)
3695 nread = 0;
3696 #endif
3698 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3699 "min=%lu nread=%lu\n",
3700 fsp_fnum_dbg(fsp), (double)startpos,
3701 (unsigned long)maxcount,
3702 (unsigned long)mincount,
3703 (unsigned long)nread ) );
3705 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3707 DEBUG(5,("reply_readbraw finished\n"));
3709 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3711 END_PROFILE(SMBreadbraw);
3712 return;
3715 #undef DBGC_CLASS
3716 #define DBGC_CLASS DBGC_LOCKING
3718 /****************************************************************************
3719 Reply to a lockread (core+ protocol).
3720 ****************************************************************************/
3722 void reply_lockread(struct smb_request *req)
3724 connection_struct *conn = req->conn;
3725 ssize_t nread = -1;
3726 char *data;
3727 off_t startpos;
3728 size_t numtoread;
3729 size_t maxtoread;
3730 NTSTATUS status;
3731 files_struct *fsp;
3732 struct byte_range_lock *br_lck = NULL;
3733 char *p = NULL;
3734 struct smbXsrv_connection *xconn = req->xconn;
3736 START_PROFILE(SMBlockread);
3738 if (req->wct < 5) {
3739 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3740 END_PROFILE(SMBlockread);
3741 return;
3744 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3746 if (!check_fsp(conn, req, fsp)) {
3747 END_PROFILE(SMBlockread);
3748 return;
3751 if (!CHECK_READ(fsp,req)) {
3752 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3753 END_PROFILE(SMBlockread);
3754 return;
3757 numtoread = SVAL(req->vwv+1, 0);
3758 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3761 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3762 * protocol request that predates the read/write lock concept.
3763 * Thus instead of asking for a read lock here we need to ask
3764 * for a write lock. JRA.
3765 * Note that the requested lock size is unaffected by max_send.
3768 br_lck = do_lock(req->sconn->msg_ctx,
3769 fsp,
3770 (uint64_t)req->smbpid,
3771 (uint64_t)numtoread,
3772 (uint64_t)startpos,
3773 WRITE_LOCK,
3774 WINDOWS_LOCK,
3775 False, /* Non-blocking lock. */
3776 &status,
3777 NULL);
3778 TALLOC_FREE(br_lck);
3780 if (NT_STATUS_V(status)) {
3781 reply_nterror(req, status);
3782 END_PROFILE(SMBlockread);
3783 return;
3787 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3789 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3791 if (numtoread > maxtoread) {
3792 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3793 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3794 (unsigned int)numtoread, (unsigned int)maxtoread,
3795 (unsigned int)xconn->smb1.sessions.max_send));
3796 numtoread = maxtoread;
3799 reply_outbuf(req, 5, numtoread + 3);
3801 data = smb_buf(req->outbuf) + 3;
3803 nread = read_file(fsp,data,startpos,numtoread);
3805 if (nread < 0) {
3806 reply_nterror(req, map_nt_error_from_unix(errno));
3807 END_PROFILE(SMBlockread);
3808 return;
3811 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3813 SSVAL(req->outbuf,smb_vwv0,nread);
3814 SSVAL(req->outbuf,smb_vwv5,nread+3);
3815 p = smb_buf(req->outbuf);
3816 SCVAL(p,0,0); /* pad byte. */
3817 SSVAL(p,1,nread);
3819 DEBUG(3,("lockread %s num=%d nread=%d\n",
3820 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3822 END_PROFILE(SMBlockread);
3823 return;
3826 #undef DBGC_CLASS
3827 #define DBGC_CLASS DBGC_ALL
3829 /****************************************************************************
3830 Reply to a read.
3831 ****************************************************************************/
3833 void reply_read(struct smb_request *req)
3835 connection_struct *conn = req->conn;
3836 size_t numtoread;
3837 size_t maxtoread;
3838 ssize_t nread = 0;
3839 char *data;
3840 off_t startpos;
3841 files_struct *fsp;
3842 struct lock_struct lock;
3843 struct smbXsrv_connection *xconn = req->xconn;
3845 START_PROFILE(SMBread);
3847 if (req->wct < 3) {
3848 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3849 END_PROFILE(SMBread);
3850 return;
3853 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3855 if (!check_fsp(conn, req, fsp)) {
3856 END_PROFILE(SMBread);
3857 return;
3860 if (!CHECK_READ(fsp,req)) {
3861 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3862 END_PROFILE(SMBread);
3863 return;
3866 numtoread = SVAL(req->vwv+1, 0);
3867 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3870 * The requested read size cannot be greater than max_send. JRA.
3872 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3874 if (numtoread > maxtoread) {
3875 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3876 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3877 (unsigned int)numtoread, (unsigned int)maxtoread,
3878 (unsigned int)xconn->smb1.sessions.max_send));
3879 numtoread = maxtoread;
3882 reply_outbuf(req, 5, numtoread+3);
3884 data = smb_buf(req->outbuf) + 3;
3886 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3887 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3888 &lock);
3890 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3891 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3892 END_PROFILE(SMBread);
3893 return;
3896 if (numtoread > 0)
3897 nread = read_file(fsp,data,startpos,numtoread);
3899 if (nread < 0) {
3900 reply_nterror(req, map_nt_error_from_unix(errno));
3901 goto strict_unlock;
3904 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3906 SSVAL(req->outbuf,smb_vwv0,nread);
3907 SSVAL(req->outbuf,smb_vwv5,nread+3);
3908 SCVAL(smb_buf(req->outbuf),0,1);
3909 SSVAL(smb_buf(req->outbuf),1,nread);
3911 DEBUG(3, ("read %s num=%d nread=%d\n",
3912 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3914 strict_unlock:
3915 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3917 END_PROFILE(SMBread);
3918 return;
3921 /****************************************************************************
3922 Setup readX header.
3923 ****************************************************************************/
3925 int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3927 int outsize;
3929 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3930 False);
3932 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3934 SCVAL(outbuf,smb_vwv0,0xFF);
3935 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3936 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3937 SSVAL(outbuf,smb_vwv6,
3938 (smb_wct - 4) /* offset from smb header to wct */
3939 + 1 /* the wct field */
3940 + 12 * sizeof(uint16_t) /* vwv */
3941 + 2 /* the buflen field */
3942 + 1); /* padding byte */
3943 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3944 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3945 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3946 _smb_setlen_large(outbuf,
3947 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3948 return outsize;
3951 /****************************************************************************
3952 Reply to a read and X - possibly using sendfile.
3953 ****************************************************************************/
3955 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3956 files_struct *fsp, off_t startpos,
3957 size_t smb_maxcnt)
3959 struct smbXsrv_connection *xconn = req->xconn;
3960 ssize_t nread = -1;
3961 struct lock_struct lock;
3962 int saved_errno = 0;
3964 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3965 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3966 &lock);
3968 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3969 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3970 return;
3974 * We can only use sendfile on a non-chained packet
3975 * but we can use on a non-oplocked file. tridge proved this
3976 * on a train in Germany :-). JRA.
3979 if (!req_is_in_chain(req) &&
3980 !req->encrypted &&
3981 (fsp->base_fsp == NULL) &&
3982 (fsp->wcp == NULL) &&
3983 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3984 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3985 DATA_BLOB header;
3987 if(fsp_stat(fsp) == -1) {
3988 reply_nterror(req, map_nt_error_from_unix(errno));
3989 goto strict_unlock;
3992 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3993 (startpos > fsp->fsp_name->st.st_ex_size) ||
3994 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3996 * We already know that we would do a short read, so don't
3997 * try the sendfile() path.
3999 goto nosendfile_read;
4003 * Set up the packet header before send. We
4004 * assume here the sendfile will work (get the
4005 * correct amount of data).
4008 header = data_blob_const(headerbuf, sizeof(headerbuf));
4010 construct_reply_common_req(req, (char *)headerbuf);
4011 setup_readX_header((char *)headerbuf, smb_maxcnt);
4013 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4014 startpos, smb_maxcnt);
4015 if (nread == -1) {
4016 saved_errno = errno;
4018 /* Returning ENOSYS means no data at all was sent.
4019 Do this as a normal read. */
4020 if (errno == ENOSYS) {
4021 goto normal_read;
4025 * Special hack for broken Linux with no working sendfile. If we
4026 * return EINTR we sent the header but not the rest of the data.
4027 * Fake this up by doing read/write calls.
4030 if (errno == EINTR) {
4031 /* Ensure we don't do this again. */
4032 set_use_sendfile(SNUM(conn), False);
4033 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4034 nread = fake_sendfile(xconn, fsp, startpos,
4035 smb_maxcnt);
4036 if (nread == -1) {
4037 saved_errno = errno;
4038 DEBUG(0,("send_file_readX: "
4039 "fake_sendfile failed for "
4040 "file %s (%s) for client %s. "
4041 "Terminating\n",
4042 fsp_str_dbg(fsp),
4043 smbXsrv_connection_dbg(xconn),
4044 strerror(saved_errno)));
4045 errno = saved_errno;
4046 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4048 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4049 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4050 /* No outbuf here means successful sendfile. */
4051 goto strict_unlock;
4054 DEBUG(0,("send_file_readX: sendfile failed for file "
4055 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4056 strerror(errno)));
4057 exit_server_cleanly("send_file_readX sendfile failed");
4058 } else if (nread == 0) {
4060 * Some sendfile implementations return 0 to indicate
4061 * that there was a short read, but nothing was
4062 * actually written to the socket. In this case,
4063 * fallback to the normal read path so the header gets
4064 * the correct byte count.
4066 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4067 "falling back to the normal read: %s\n",
4068 fsp_str_dbg(fsp)));
4069 goto normal_read;
4072 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4073 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4075 /* Deal with possible short send. */
4076 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4077 ssize_t ret;
4079 ret = sendfile_short_send(xconn, fsp, nread,
4080 sizeof(headerbuf), smb_maxcnt);
4081 if (ret == -1) {
4082 const char *r;
4083 r = "send_file_readX: sendfile_short_send failed";
4084 DEBUG(0,("%s for file %s (%s).\n",
4085 r, fsp_str_dbg(fsp), strerror(errno)));
4086 exit_server_cleanly(r);
4089 /* No outbuf here means successful sendfile. */
4090 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4091 SMB_PERFCOUNT_END(&req->pcd);
4092 goto strict_unlock;
4095 normal_read:
4097 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4098 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4099 ssize_t ret;
4101 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4102 (startpos > fsp->fsp_name->st.st_ex_size) ||
4103 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4105 * We already know that we would do a short
4106 * read, so don't try the sendfile() path.
4108 goto nosendfile_read;
4111 construct_reply_common_req(req, (char *)headerbuf);
4112 setup_readX_header((char *)headerbuf, smb_maxcnt);
4114 /* Send out the header. */
4115 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4116 sizeof(headerbuf));
4117 if (ret != sizeof(headerbuf)) {
4118 saved_errno = errno;
4120 * Try and give an error message saying what
4121 * client failed.
4123 DEBUG(0,("send_file_readX: write_data failed for file "
4124 "%s (%s) for client %s. Terminating\n",
4125 fsp_str_dbg(fsp),
4126 smbXsrv_connection_dbg(xconn),
4127 strerror(saved_errno)));
4128 errno = saved_errno;
4129 exit_server_cleanly("send_file_readX sendfile failed");
4131 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4132 if (nread == -1) {
4133 saved_errno = errno;
4134 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4135 "%s (%s) for client %s. Terminating\n",
4136 fsp_str_dbg(fsp),
4137 smbXsrv_connection_dbg(xconn),
4138 strerror(saved_errno)));
4139 errno = saved_errno;
4140 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4142 goto strict_unlock;
4145 nosendfile_read:
4147 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4148 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4149 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4151 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4152 startpos, smb_maxcnt);
4153 saved_errno = errno;
4155 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4157 if (nread < 0) {
4158 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4159 return;
4162 setup_readX_header((char *)req->outbuf, nread);
4164 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4165 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4166 return;
4168 strict_unlock:
4169 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4170 TALLOC_FREE(req->outbuf);
4171 return;
4174 /****************************************************************************
4175 Work out how much space we have for a read return.
4176 ****************************************************************************/
4178 static size_t calc_max_read_pdu(const struct smb_request *req)
4180 struct smbXsrv_connection *xconn = req->xconn;
4182 if (xconn->protocol < PROTOCOL_NT1) {
4183 return xconn->smb1.sessions.max_send;
4186 if (!lp_large_readwrite()) {
4187 return xconn->smb1.sessions.max_send;
4190 if (req_is_in_chain(req)) {
4191 return xconn->smb1.sessions.max_send;
4194 if (req->encrypted) {
4196 * Don't take encrypted traffic up to the
4197 * limit. There are padding considerations
4198 * that make that tricky.
4200 return xconn->smb1.sessions.max_send;
4203 if (srv_is_signing_active(xconn)) {
4204 return 0x1FFFF;
4207 if (!lp_unix_extensions()) {
4208 return 0x1FFFF;
4212 * We can do ultra-large POSIX reads.
4214 return 0xFFFFFF;
4217 /****************************************************************************
4218 Calculate how big a read can be. Copes with all clients. It's always
4219 safe to return a short read - Windows does this.
4220 ****************************************************************************/
4222 static size_t calc_read_size(const struct smb_request *req,
4223 size_t upper_size,
4224 size_t lower_size)
4226 struct smbXsrv_connection *xconn = req->xconn;
4227 size_t max_pdu = calc_max_read_pdu(req);
4228 size_t total_size = 0;
4229 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4230 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4233 * Windows explicitly ignores upper size of 0xFFFF.
4234 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4235 * We must do the same as these will never fit even in
4236 * an extended size NetBIOS packet.
4238 if (upper_size == 0xFFFF) {
4239 upper_size = 0;
4242 if (xconn->protocol < PROTOCOL_NT1) {
4243 upper_size = 0;
4246 total_size = ((upper_size<<16) | lower_size);
4249 * LARGE_READX test shows it's always safe to return
4250 * a short read. Windows does so.
4252 return MIN(total_size, max_len);
4255 /****************************************************************************
4256 Reply to a read and X.
4257 ****************************************************************************/
4259 void reply_read_and_X(struct smb_request *req)
4261 connection_struct *conn = req->conn;
4262 files_struct *fsp;
4263 off_t startpos;
4264 size_t smb_maxcnt;
4265 size_t upper_size;
4266 bool big_readX = False;
4267 #if 0
4268 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4269 #endif
4271 START_PROFILE(SMBreadX);
4273 if ((req->wct != 10) && (req->wct != 12)) {
4274 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4275 return;
4278 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4279 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4280 smb_maxcnt = SVAL(req->vwv+5, 0);
4282 /* If it's an IPC, pass off the pipe handler. */
4283 if (IS_IPC(conn)) {
4284 reply_pipe_read_and_X(req);
4285 END_PROFILE(SMBreadX);
4286 return;
4289 if (!check_fsp(conn, req, fsp)) {
4290 END_PROFILE(SMBreadX);
4291 return;
4294 if (!CHECK_READ(fsp,req)) {
4295 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4296 END_PROFILE(SMBreadX);
4297 return;
4300 upper_size = SVAL(req->vwv+7, 0);
4301 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4302 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4304 * This is a heuristic to avoid keeping large
4305 * outgoing buffers around over long-lived aio
4306 * requests.
4308 big_readX = True;
4311 if (req->wct == 12) {
4313 * This is a large offset (64 bit) read.
4315 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4319 if (!big_readX) {
4320 NTSTATUS status = schedule_aio_read_and_X(conn,
4321 req,
4322 fsp,
4323 startpos,
4324 smb_maxcnt);
4325 if (NT_STATUS_IS_OK(status)) {
4326 /* Read scheduled - we're done. */
4327 goto out;
4329 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4330 /* Real error - report to client. */
4331 END_PROFILE(SMBreadX);
4332 reply_nterror(req, status);
4333 return;
4335 /* NT_STATUS_RETRY - fall back to sync read. */
4338 smbd_lock_socket(req->xconn);
4339 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4340 smbd_unlock_socket(req->xconn);
4342 out:
4343 END_PROFILE(SMBreadX);
4344 return;
4347 /****************************************************************************
4348 Error replies to writebraw must have smb_wct == 1. Fix this up.
4349 ****************************************************************************/
4351 void error_to_writebrawerr(struct smb_request *req)
4353 uint8_t *old_outbuf = req->outbuf;
4355 reply_outbuf(req, 1, 0);
4357 memcpy(req->outbuf, old_outbuf, smb_size);
4358 TALLOC_FREE(old_outbuf);
4361 /****************************************************************************
4362 Read 4 bytes of a smb packet and return the smb length of the packet.
4363 Store the result in the buffer. This version of the function will
4364 never return a session keepalive (length of zero).
4365 Timeout is in milliseconds.
4366 ****************************************************************************/
4368 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4369 size_t *len)
4371 uint8_t msgtype = NBSSkeepalive;
4373 while (msgtype == NBSSkeepalive) {
4374 NTSTATUS status;
4376 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4377 len);
4378 if (!NT_STATUS_IS_OK(status)) {
4379 char addr[INET6_ADDRSTRLEN];
4380 /* Try and give an error message
4381 * saying what client failed. */
4382 DEBUG(0, ("read_fd_with_timeout failed for "
4383 "client %s read error = %s.\n",
4384 get_peer_addr(fd,addr,sizeof(addr)),
4385 nt_errstr(status)));
4386 return status;
4389 msgtype = CVAL(inbuf, 0);
4392 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4393 (unsigned long)len));
4395 return NT_STATUS_OK;
4398 /****************************************************************************
4399 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4400 ****************************************************************************/
4402 void reply_writebraw(struct smb_request *req)
4404 connection_struct *conn = req->conn;
4405 struct smbXsrv_connection *xconn = req->xconn;
4406 char *buf = NULL;
4407 ssize_t nwritten=0;
4408 ssize_t total_written=0;
4409 size_t numtowrite=0;
4410 size_t tcount;
4411 off_t startpos;
4412 const char *data=NULL;
4413 bool write_through;
4414 files_struct *fsp;
4415 struct lock_struct lock;
4416 NTSTATUS status;
4418 START_PROFILE(SMBwritebraw);
4421 * If we ever reply with an error, it must have the SMB command
4422 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4423 * we're finished.
4425 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4427 if (srv_is_signing_active(xconn)) {
4428 END_PROFILE(SMBwritebraw);
4429 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4430 "raw reads/writes are disallowed.");
4433 if (req->wct < 12) {
4434 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4435 error_to_writebrawerr(req);
4436 END_PROFILE(SMBwritebraw);
4437 return;
4440 if (xconn->smb1.echo_handler.trusted_fde) {
4441 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4442 "'async smb echo handler = yes'\n"));
4443 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4444 error_to_writebrawerr(req);
4445 END_PROFILE(SMBwritebraw);
4446 return;
4449 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4450 if (!check_fsp(conn, req, fsp)) {
4451 error_to_writebrawerr(req);
4452 END_PROFILE(SMBwritebraw);
4453 return;
4456 if (!CHECK_WRITE(fsp)) {
4457 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4458 error_to_writebrawerr(req);
4459 END_PROFILE(SMBwritebraw);
4460 return;
4463 tcount = IVAL(req->vwv+1, 0);
4464 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4465 write_through = BITSETW(req->vwv+7,0);
4467 /* We have to deal with slightly different formats depending
4468 on whether we are using the core+ or lanman1.0 protocol */
4470 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4471 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4472 data = smb_buf_const(req->inbuf);
4473 } else {
4474 numtowrite = SVAL(req->vwv+10, 0);
4475 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4478 /* Ensure we don't write bytes past the end of this packet. */
4479 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4480 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4481 error_to_writebrawerr(req);
4482 END_PROFILE(SMBwritebraw);
4483 return;
4486 if (!fsp->print_file) {
4487 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4488 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4489 &lock);
4491 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4492 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4493 error_to_writebrawerr(req);
4494 END_PROFILE(SMBwritebraw);
4495 return;
4499 if (numtowrite>0) {
4500 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4503 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4504 "wrote=%d sync=%d\n",
4505 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4506 (int)nwritten, (int)write_through));
4508 if (nwritten < (ssize_t)numtowrite) {
4509 reply_nterror(req, NT_STATUS_DISK_FULL);
4510 error_to_writebrawerr(req);
4511 goto strict_unlock;
4514 total_written = nwritten;
4516 /* Allocate a buffer of 64k + length. */
4517 buf = talloc_array(NULL, char, 65540);
4518 if (!buf) {
4519 reply_nterror(req, NT_STATUS_NO_MEMORY);
4520 error_to_writebrawerr(req);
4521 goto strict_unlock;
4524 /* Return a SMBwritebraw message to the redirector to tell
4525 * it to send more bytes */
4527 memcpy(buf, req->inbuf, smb_size);
4528 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4529 SCVAL(buf,smb_com,SMBwritebraw);
4530 SSVALS(buf,smb_vwv0,0xFFFF);
4531 show_msg(buf);
4532 if (!srv_send_smb(req->xconn,
4533 buf,
4534 false, 0, /* no signing */
4535 IS_CONN_ENCRYPTED(conn),
4536 &req->pcd)) {
4537 exit_server_cleanly("reply_writebraw: srv_send_smb "
4538 "failed.");
4541 /* Now read the raw data into the buffer and write it */
4542 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4543 &numtowrite);
4544 if (!NT_STATUS_IS_OK(status)) {
4545 exit_server_cleanly("secondary writebraw failed");
4548 /* Set up outbuf to return the correct size */
4549 reply_outbuf(req, 1, 0);
4551 if (numtowrite != 0) {
4553 if (numtowrite > 0xFFFF) {
4554 DEBUG(0,("reply_writebraw: Oversize secondary write "
4555 "raw requested (%u). Terminating\n",
4556 (unsigned int)numtowrite ));
4557 exit_server_cleanly("secondary writebraw failed");
4560 if (tcount > nwritten+numtowrite) {
4561 DEBUG(3,("reply_writebraw: Client overestimated the "
4562 "write %d %d %d\n",
4563 (int)tcount,(int)nwritten,(int)numtowrite));
4566 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4567 numtowrite);
4569 if (!NT_STATUS_IS_OK(status)) {
4570 /* Try and give an error message
4571 * saying what client failed. */
4572 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4573 "raw read failed (%s) for client %s. "
4574 "Terminating\n", nt_errstr(status),
4575 smbXsrv_connection_dbg(xconn)));
4576 exit_server_cleanly("secondary writebraw failed");
4579 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4580 if (nwritten == -1) {
4581 TALLOC_FREE(buf);
4582 reply_nterror(req, map_nt_error_from_unix(errno));
4583 error_to_writebrawerr(req);
4584 goto strict_unlock;
4587 if (nwritten < (ssize_t)numtowrite) {
4588 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4589 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4592 if (nwritten > 0) {
4593 total_written += nwritten;
4597 TALLOC_FREE(buf);
4598 SSVAL(req->outbuf,smb_vwv0,total_written);
4600 status = sync_file(conn, fsp, write_through);
4601 if (!NT_STATUS_IS_OK(status)) {
4602 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4603 fsp_str_dbg(fsp), nt_errstr(status)));
4604 reply_nterror(req, status);
4605 error_to_writebrawerr(req);
4606 goto strict_unlock;
4609 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4610 "wrote=%d\n",
4611 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4612 (int)total_written));
4614 if (!fsp->print_file) {
4615 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4618 /* We won't return a status if write through is not selected - this
4619 * follows what WfWg does */
4620 END_PROFILE(SMBwritebraw);
4622 if (!write_through && total_written==tcount) {
4624 #if RABBIT_PELLET_FIX
4626 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4627 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4628 * JRA.
4630 if (!send_keepalive(xconn->transport.sock)) {
4631 exit_server_cleanly("reply_writebraw: send of "
4632 "keepalive failed");
4634 #endif
4635 TALLOC_FREE(req->outbuf);
4637 return;
4639 strict_unlock:
4640 if (!fsp->print_file) {
4641 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4644 END_PROFILE(SMBwritebraw);
4645 return;
4648 #undef DBGC_CLASS
4649 #define DBGC_CLASS DBGC_LOCKING
4651 /****************************************************************************
4652 Reply to a writeunlock (core+).
4653 ****************************************************************************/
4655 void reply_writeunlock(struct smb_request *req)
4657 connection_struct *conn = req->conn;
4658 ssize_t nwritten = -1;
4659 size_t numtowrite;
4660 off_t startpos;
4661 const char *data;
4662 NTSTATUS status = NT_STATUS_OK;
4663 files_struct *fsp;
4664 struct lock_struct lock;
4665 int saved_errno = 0;
4667 START_PROFILE(SMBwriteunlock);
4669 if (req->wct < 5) {
4670 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4671 END_PROFILE(SMBwriteunlock);
4672 return;
4675 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4677 if (!check_fsp(conn, req, fsp)) {
4678 END_PROFILE(SMBwriteunlock);
4679 return;
4682 if (!CHECK_WRITE(fsp)) {
4683 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4684 END_PROFILE(SMBwriteunlock);
4685 return;
4688 numtowrite = SVAL(req->vwv+1, 0);
4689 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4690 data = (const char *)req->buf + 3;
4692 if (!fsp->print_file && numtowrite > 0) {
4693 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4694 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4695 &lock);
4697 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4698 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4699 END_PROFILE(SMBwriteunlock);
4700 return;
4704 /* The special X/Open SMB protocol handling of
4705 zero length writes is *NOT* done for
4706 this call */
4707 if(numtowrite == 0) {
4708 nwritten = 0;
4709 } else {
4710 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4711 saved_errno = errno;
4714 status = sync_file(conn, fsp, False /* write through */);
4715 if (!NT_STATUS_IS_OK(status)) {
4716 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4717 fsp_str_dbg(fsp), nt_errstr(status)));
4718 reply_nterror(req, status);
4719 goto strict_unlock;
4722 if(nwritten < 0) {
4723 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4724 goto strict_unlock;
4727 if((nwritten < numtowrite) && (numtowrite != 0)) {
4728 reply_nterror(req, NT_STATUS_DISK_FULL);
4729 goto strict_unlock;
4732 if (numtowrite && !fsp->print_file) {
4733 status = do_unlock(req->sconn->msg_ctx,
4734 fsp,
4735 (uint64_t)req->smbpid,
4736 (uint64_t)numtowrite,
4737 (uint64_t)startpos,
4738 WINDOWS_LOCK);
4740 if (NT_STATUS_V(status)) {
4741 reply_nterror(req, status);
4742 goto strict_unlock;
4746 reply_outbuf(req, 1, 0);
4748 SSVAL(req->outbuf,smb_vwv0,nwritten);
4750 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4751 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4753 strict_unlock:
4754 if (numtowrite && !fsp->print_file) {
4755 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4758 END_PROFILE(SMBwriteunlock);
4759 return;
4762 #undef DBGC_CLASS
4763 #define DBGC_CLASS DBGC_ALL
4765 /****************************************************************************
4766 Reply to a write.
4767 ****************************************************************************/
4769 void reply_write(struct smb_request *req)
4771 connection_struct *conn = req->conn;
4772 size_t numtowrite;
4773 ssize_t nwritten = -1;
4774 off_t startpos;
4775 const char *data;
4776 files_struct *fsp;
4777 struct lock_struct lock;
4778 NTSTATUS status;
4779 int saved_errno = 0;
4781 START_PROFILE(SMBwrite);
4783 if (req->wct < 5) {
4784 END_PROFILE(SMBwrite);
4785 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4786 return;
4789 /* If it's an IPC, pass off the pipe handler. */
4790 if (IS_IPC(conn)) {
4791 reply_pipe_write(req);
4792 END_PROFILE(SMBwrite);
4793 return;
4796 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4798 if (!check_fsp(conn, req, fsp)) {
4799 END_PROFILE(SMBwrite);
4800 return;
4803 if (!CHECK_WRITE(fsp)) {
4804 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4805 END_PROFILE(SMBwrite);
4806 return;
4809 numtowrite = SVAL(req->vwv+1, 0);
4810 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4811 data = (const char *)req->buf + 3;
4813 if (!fsp->print_file) {
4814 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4815 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4816 &lock);
4818 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4819 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4820 END_PROFILE(SMBwrite);
4821 return;
4826 * X/Open SMB protocol says that if smb_vwv1 is
4827 * zero then the file size should be extended or
4828 * truncated to the size given in smb_vwv[2-3].
4831 if(numtowrite == 0) {
4833 * This is actually an allocate call, and set EOF. JRA.
4835 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4836 if (nwritten < 0) {
4837 reply_nterror(req, NT_STATUS_DISK_FULL);
4838 goto strict_unlock;
4840 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4841 if (nwritten < 0) {
4842 reply_nterror(req, NT_STATUS_DISK_FULL);
4843 goto strict_unlock;
4845 trigger_write_time_update_immediate(fsp);
4846 } else {
4847 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4850 status = sync_file(conn, fsp, False);
4851 if (!NT_STATUS_IS_OK(status)) {
4852 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4853 fsp_str_dbg(fsp), nt_errstr(status)));
4854 reply_nterror(req, status);
4855 goto strict_unlock;
4858 if(nwritten < 0) {
4859 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4860 goto strict_unlock;
4863 if((nwritten == 0) && (numtowrite != 0)) {
4864 reply_nterror(req, NT_STATUS_DISK_FULL);
4865 goto strict_unlock;
4868 reply_outbuf(req, 1, 0);
4870 SSVAL(req->outbuf,smb_vwv0,nwritten);
4872 if (nwritten < (ssize_t)numtowrite) {
4873 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4874 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4877 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4879 strict_unlock:
4880 if (!fsp->print_file) {
4881 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4884 END_PROFILE(SMBwrite);
4885 return;
4888 /****************************************************************************
4889 Ensure a buffer is a valid writeX for recvfile purposes.
4890 ****************************************************************************/
4892 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4893 (2*14) + /* word count (including bcc) */ \
4894 1 /* pad byte */)
4896 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4897 const uint8_t *inbuf)
4899 size_t numtowrite;
4900 unsigned int doff = 0;
4901 size_t len = smb_len_large(inbuf);
4902 uint16_t fnum;
4903 struct smbXsrv_open *op = NULL;
4904 struct files_struct *fsp = NULL;
4905 NTSTATUS status;
4907 if (is_encrypted_packet(inbuf)) {
4908 /* Can't do this on encrypted
4909 * connections. */
4910 return false;
4913 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4914 return false;
4917 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4918 CVAL(inbuf,smb_wct) != 14) {
4919 DEBUG(10,("is_valid_writeX_buffer: chained or "
4920 "invalid word length.\n"));
4921 return false;
4924 fnum = SVAL(inbuf, smb_vwv2);
4925 status = smb1srv_open_lookup(xconn,
4926 fnum,
4927 0, /* now */
4928 &op);
4929 if (!NT_STATUS_IS_OK(status)) {
4930 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4931 return false;
4933 fsp = op->compat;
4934 if (fsp == NULL) {
4935 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4936 return false;
4938 if (fsp->conn == NULL) {
4939 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4940 return false;
4943 if (IS_IPC(fsp->conn)) {
4944 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4945 return false;
4947 if (IS_PRINT(fsp->conn)) {
4948 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4949 return false;
4951 doff = SVAL(inbuf,smb_vwv11);
4953 numtowrite = SVAL(inbuf,smb_vwv10);
4955 if (len > doff && len - doff > 0xFFFF) {
4956 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4959 if (numtowrite == 0) {
4960 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4961 return false;
4964 /* Ensure the sizes match up. */
4965 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4966 /* no pad byte...old smbclient :-( */
4967 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4968 (unsigned int)doff,
4969 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4970 return false;
4973 if (len - doff != numtowrite) {
4974 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4975 "len = %u, doff = %u, numtowrite = %u\n",
4976 (unsigned int)len,
4977 (unsigned int)doff,
4978 (unsigned int)numtowrite ));
4979 return false;
4982 DEBUG(10,("is_valid_writeX_buffer: true "
4983 "len = %u, doff = %u, numtowrite = %u\n",
4984 (unsigned int)len,
4985 (unsigned int)doff,
4986 (unsigned int)numtowrite ));
4988 return true;
4991 /****************************************************************************
4992 Reply to a write and X.
4993 ****************************************************************************/
4995 void reply_write_and_X(struct smb_request *req)
4997 connection_struct *conn = req->conn;
4998 struct smbXsrv_connection *xconn = req->xconn;
4999 files_struct *fsp;
5000 struct lock_struct lock;
5001 off_t startpos;
5002 size_t numtowrite;
5003 bool write_through;
5004 ssize_t nwritten;
5005 unsigned int smb_doff;
5006 unsigned int smblen;
5007 const char *data;
5008 NTSTATUS status;
5009 int saved_errno = 0;
5011 START_PROFILE(SMBwriteX);
5013 if ((req->wct != 12) && (req->wct != 14)) {
5014 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5015 goto out;
5018 numtowrite = SVAL(req->vwv+10, 0);
5019 smb_doff = SVAL(req->vwv+11, 0);
5020 smblen = smb_len(req->inbuf);
5022 if (req->unread_bytes > 0xFFFF ||
5023 (smblen > smb_doff &&
5024 smblen - smb_doff > 0xFFFF)) {
5025 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5028 if (req->unread_bytes) {
5029 /* Can't do a recvfile write on IPC$ */
5030 if (IS_IPC(conn)) {
5031 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5032 goto out;
5034 if (numtowrite != req->unread_bytes) {
5035 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5036 goto out;
5038 } else {
5039 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5040 smb_doff + numtowrite > smblen) {
5041 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5042 goto out;
5046 /* If it's an IPC, pass off the pipe handler. */
5047 if (IS_IPC(conn)) {
5048 if (req->unread_bytes) {
5049 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5050 goto out;
5052 reply_pipe_write_and_X(req);
5053 goto out;
5056 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5057 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5058 write_through = BITSETW(req->vwv+7,0);
5060 if (!check_fsp(conn, req, fsp)) {
5061 goto out;
5064 if (!CHECK_WRITE(fsp)) {
5065 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5066 goto out;
5069 data = smb_base(req->inbuf) + smb_doff;
5071 if(req->wct == 14) {
5073 * This is a large offset (64 bit) write.
5075 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5079 /* X/Open SMB protocol says that, unlike SMBwrite
5080 if the length is zero then NO truncation is
5081 done, just a write of zero. To truncate a file,
5082 use SMBwrite. */
5084 if(numtowrite == 0) {
5085 nwritten = 0;
5086 } else {
5087 if (req->unread_bytes == 0) {
5088 status = schedule_aio_write_and_X(conn,
5089 req,
5090 fsp,
5091 data,
5092 startpos,
5093 numtowrite);
5095 if (NT_STATUS_IS_OK(status)) {
5096 /* write scheduled - we're done. */
5097 goto out;
5099 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5100 /* Real error - report to client. */
5101 reply_nterror(req, status);
5102 goto out;
5104 /* NT_STATUS_RETRY - fall through to sync write. */
5107 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5108 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5109 &lock);
5111 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5112 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5113 goto out;
5116 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5117 saved_errno = errno;
5119 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5122 if(nwritten < 0) {
5123 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5124 goto out;
5127 if((nwritten == 0) && (numtowrite != 0)) {
5128 reply_nterror(req, NT_STATUS_DISK_FULL);
5129 goto out;
5132 reply_outbuf(req, 6, 0);
5133 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5134 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5135 SSVAL(req->outbuf,smb_vwv2,nwritten);
5136 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5138 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5139 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5141 status = sync_file(conn, fsp, write_through);
5142 if (!NT_STATUS_IS_OK(status)) {
5143 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5144 fsp_str_dbg(fsp), nt_errstr(status)));
5145 reply_nterror(req, status);
5146 goto out;
5149 END_PROFILE(SMBwriteX);
5150 return;
5152 out:
5153 if (req->unread_bytes) {
5154 /* writeX failed. drain socket. */
5155 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5156 req->unread_bytes) {
5157 smb_panic("failed to drain pending bytes");
5159 req->unread_bytes = 0;
5162 END_PROFILE(SMBwriteX);
5163 return;
5166 /****************************************************************************
5167 Reply to a lseek.
5168 ****************************************************************************/
5170 void reply_lseek(struct smb_request *req)
5172 connection_struct *conn = req->conn;
5173 off_t startpos;
5174 off_t res= -1;
5175 int mode,umode;
5176 files_struct *fsp;
5178 START_PROFILE(SMBlseek);
5180 if (req->wct < 4) {
5181 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5182 END_PROFILE(SMBlseek);
5183 return;
5186 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5188 if (!check_fsp(conn, req, fsp)) {
5189 return;
5192 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5194 mode = SVAL(req->vwv+1, 0) & 3;
5195 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5196 startpos = (off_t)IVALS(req->vwv+2, 0);
5198 switch (mode) {
5199 case 0:
5200 umode = SEEK_SET;
5201 res = startpos;
5202 break;
5203 case 1:
5204 umode = SEEK_CUR;
5205 res = fsp->fh->pos + startpos;
5206 break;
5207 case 2:
5208 umode = SEEK_END;
5209 break;
5210 default:
5211 umode = SEEK_SET;
5212 res = startpos;
5213 break;
5216 if (umode == SEEK_END) {
5217 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5218 if(errno == EINVAL) {
5219 off_t current_pos = startpos;
5221 if(fsp_stat(fsp) == -1) {
5222 reply_nterror(req,
5223 map_nt_error_from_unix(errno));
5224 END_PROFILE(SMBlseek);
5225 return;
5228 current_pos += fsp->fsp_name->st.st_ex_size;
5229 if(current_pos < 0)
5230 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5234 if(res == -1) {
5235 reply_nterror(req, map_nt_error_from_unix(errno));
5236 END_PROFILE(SMBlseek);
5237 return;
5241 fsp->fh->pos = res;
5243 reply_outbuf(req, 2, 0);
5244 SIVAL(req->outbuf,smb_vwv0,res);
5246 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5247 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5249 END_PROFILE(SMBlseek);
5250 return;
5253 /****************************************************************************
5254 Reply to a flush.
5255 ****************************************************************************/
5257 void reply_flush(struct smb_request *req)
5259 connection_struct *conn = req->conn;
5260 uint16_t fnum;
5261 files_struct *fsp;
5263 START_PROFILE(SMBflush);
5265 if (req->wct < 1) {
5266 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5267 return;
5270 fnum = SVAL(req->vwv+0, 0);
5271 fsp = file_fsp(req, fnum);
5273 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5274 return;
5277 if (!fsp) {
5278 file_sync_all(conn);
5279 } else {
5280 NTSTATUS status = sync_file(conn, fsp, True);
5281 if (!NT_STATUS_IS_OK(status)) {
5282 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5283 fsp_str_dbg(fsp), nt_errstr(status)));
5284 reply_nterror(req, status);
5285 END_PROFILE(SMBflush);
5286 return;
5290 reply_outbuf(req, 0, 0);
5292 DEBUG(3,("flush\n"));
5293 END_PROFILE(SMBflush);
5294 return;
5297 /****************************************************************************
5298 Reply to a exit.
5299 conn POINTER CAN BE NULL HERE !
5300 ****************************************************************************/
5302 void reply_exit(struct smb_request *req)
5304 START_PROFILE(SMBexit);
5306 file_close_pid(req->sconn, req->smbpid, req->vuid);
5308 reply_outbuf(req, 0, 0);
5310 DEBUG(3,("exit\n"));
5312 END_PROFILE(SMBexit);
5313 return;
5316 struct reply_close_state {
5317 files_struct *fsp;
5318 struct smb_request *smbreq;
5321 static void do_smb1_close(struct tevent_req *req);
5323 void reply_close(struct smb_request *req)
5325 connection_struct *conn = req->conn;
5326 NTSTATUS status = NT_STATUS_OK;
5327 files_struct *fsp = NULL;
5328 START_PROFILE(SMBclose);
5330 if (req->wct < 3) {
5331 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5332 END_PROFILE(SMBclose);
5333 return;
5336 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5339 * We can only use check_fsp if we know it's not a directory.
5342 if (!check_fsp_open(conn, req, fsp)) {
5343 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5344 END_PROFILE(SMBclose);
5345 return;
5348 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5349 fsp->is_directory ? "directory" : "file",
5350 fsp->fh->fd, fsp_fnum_dbg(fsp),
5351 conn->num_files_open));
5353 if (!fsp->is_directory) {
5354 time_t t;
5357 * Take care of any time sent in the close.
5360 t = srv_make_unix_date3(req->vwv+1);
5361 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5364 if (fsp->num_aio_requests != 0) {
5366 struct reply_close_state *state;
5368 DEBUG(10, ("closing with aio %u requests pending\n",
5369 fsp->num_aio_requests));
5372 * We depend on the aio_extra destructor to take care of this
5373 * close request once fsp->num_aio_request drops to 0.
5376 fsp->deferred_close = tevent_wait_send(
5377 fsp, fsp->conn->sconn->ev_ctx);
5378 if (fsp->deferred_close == NULL) {
5379 status = NT_STATUS_NO_MEMORY;
5380 goto done;
5383 state = talloc(fsp, struct reply_close_state);
5384 if (state == NULL) {
5385 TALLOC_FREE(fsp->deferred_close);
5386 status = NT_STATUS_NO_MEMORY;
5387 goto done;
5389 state->fsp = fsp;
5390 state->smbreq = talloc_move(fsp, &req);
5391 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5392 state);
5393 END_PROFILE(SMBclose);
5394 return;
5398 * close_file() returns the unix errno if an error was detected on
5399 * close - normally this is due to a disk full error. If not then it
5400 * was probably an I/O error.
5403 status = close_file(req, fsp, NORMAL_CLOSE);
5404 done:
5405 if (!NT_STATUS_IS_OK(status)) {
5406 reply_nterror(req, status);
5407 END_PROFILE(SMBclose);
5408 return;
5411 reply_outbuf(req, 0, 0);
5412 END_PROFILE(SMBclose);
5413 return;
5416 static void do_smb1_close(struct tevent_req *req)
5418 struct reply_close_state *state = tevent_req_callback_data(
5419 req, struct reply_close_state);
5420 struct smb_request *smbreq;
5421 NTSTATUS status;
5422 int ret;
5424 ret = tevent_wait_recv(req);
5425 TALLOC_FREE(req);
5426 if (ret != 0) {
5427 DEBUG(10, ("tevent_wait_recv returned %s\n",
5428 strerror(ret)));
5430 * Continue anyway, this should never happen
5435 * fsp->smb2_close_request right now is a talloc grandchild of
5436 * fsp. When we close_file(fsp), it would go with it. No chance to
5437 * reply...
5439 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5441 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5442 if (NT_STATUS_IS_OK(status)) {
5443 reply_outbuf(smbreq, 0, 0);
5444 } else {
5445 reply_nterror(smbreq, status);
5447 if (!srv_send_smb(smbreq->xconn,
5448 (char *)smbreq->outbuf,
5449 true,
5450 smbreq->seqnum+1,
5451 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5452 NULL)) {
5453 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5454 "failed.");
5456 TALLOC_FREE(smbreq);
5459 /****************************************************************************
5460 Reply to a writeclose (Core+ protocol).
5461 ****************************************************************************/
5463 void reply_writeclose(struct smb_request *req)
5465 connection_struct *conn = req->conn;
5466 size_t numtowrite;
5467 ssize_t nwritten = -1;
5468 NTSTATUS close_status = NT_STATUS_OK;
5469 off_t startpos;
5470 const char *data;
5471 struct timespec mtime;
5472 files_struct *fsp;
5473 struct lock_struct lock;
5475 START_PROFILE(SMBwriteclose);
5477 if (req->wct < 6) {
5478 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5479 END_PROFILE(SMBwriteclose);
5480 return;
5483 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5485 if (!check_fsp(conn, req, fsp)) {
5486 END_PROFILE(SMBwriteclose);
5487 return;
5489 if (!CHECK_WRITE(fsp)) {
5490 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5491 END_PROFILE(SMBwriteclose);
5492 return;
5495 numtowrite = SVAL(req->vwv+1, 0);
5496 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5497 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5498 data = (const char *)req->buf + 1;
5500 if (fsp->print_file == NULL) {
5501 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5502 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5503 &lock);
5505 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5506 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5507 END_PROFILE(SMBwriteclose);
5508 return;
5512 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5514 if (fsp->print_file == NULL) {
5515 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5518 set_close_write_time(fsp, mtime);
5521 * More insanity. W2K only closes the file if writelen > 0.
5522 * JRA.
5525 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5526 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5527 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5529 if (numtowrite) {
5530 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5531 "file %s\n", fsp_str_dbg(fsp)));
5532 close_status = close_file(req, fsp, NORMAL_CLOSE);
5533 fsp = NULL;
5536 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5537 reply_nterror(req, NT_STATUS_DISK_FULL);
5538 goto out;
5541 if(!NT_STATUS_IS_OK(close_status)) {
5542 reply_nterror(req, close_status);
5543 goto out;
5546 reply_outbuf(req, 1, 0);
5548 SSVAL(req->outbuf,smb_vwv0,nwritten);
5550 out:
5552 END_PROFILE(SMBwriteclose);
5553 return;
5556 #undef DBGC_CLASS
5557 #define DBGC_CLASS DBGC_LOCKING
5559 /****************************************************************************
5560 Reply to a lock.
5561 ****************************************************************************/
5563 void reply_lock(struct smb_request *req)
5565 connection_struct *conn = req->conn;
5566 uint64_t count,offset;
5567 NTSTATUS status;
5568 files_struct *fsp;
5569 struct byte_range_lock *br_lck = NULL;
5571 START_PROFILE(SMBlock);
5573 if (req->wct < 5) {
5574 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5575 END_PROFILE(SMBlock);
5576 return;
5579 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5581 if (!check_fsp(conn, req, fsp)) {
5582 END_PROFILE(SMBlock);
5583 return;
5586 count = (uint64_t)IVAL(req->vwv+1, 0);
5587 offset = (uint64_t)IVAL(req->vwv+3, 0);
5589 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5590 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5592 br_lck = do_lock(req->sconn->msg_ctx,
5593 fsp,
5594 (uint64_t)req->smbpid,
5595 count,
5596 offset,
5597 WRITE_LOCK,
5598 WINDOWS_LOCK,
5599 False, /* Non-blocking lock. */
5600 &status,
5601 NULL);
5603 TALLOC_FREE(br_lck);
5605 if (NT_STATUS_V(status)) {
5606 reply_nterror(req, status);
5607 END_PROFILE(SMBlock);
5608 return;
5611 reply_outbuf(req, 0, 0);
5613 END_PROFILE(SMBlock);
5614 return;
5617 /****************************************************************************
5618 Reply to a unlock.
5619 ****************************************************************************/
5621 void reply_unlock(struct smb_request *req)
5623 connection_struct *conn = req->conn;
5624 uint64_t count,offset;
5625 NTSTATUS status;
5626 files_struct *fsp;
5628 START_PROFILE(SMBunlock);
5630 if (req->wct < 5) {
5631 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5632 END_PROFILE(SMBunlock);
5633 return;
5636 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5638 if (!check_fsp(conn, req, fsp)) {
5639 END_PROFILE(SMBunlock);
5640 return;
5643 count = (uint64_t)IVAL(req->vwv+1, 0);
5644 offset = (uint64_t)IVAL(req->vwv+3, 0);
5646 status = do_unlock(req->sconn->msg_ctx,
5647 fsp,
5648 (uint64_t)req->smbpid,
5649 count,
5650 offset,
5651 WINDOWS_LOCK);
5653 if (NT_STATUS_V(status)) {
5654 reply_nterror(req, status);
5655 END_PROFILE(SMBunlock);
5656 return;
5659 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5660 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5662 reply_outbuf(req, 0, 0);
5664 END_PROFILE(SMBunlock);
5665 return;
5668 #undef DBGC_CLASS
5669 #define DBGC_CLASS DBGC_ALL
5671 /****************************************************************************
5672 Reply to a tdis.
5673 conn POINTER CAN BE NULL HERE !
5674 ****************************************************************************/
5676 void reply_tdis(struct smb_request *req)
5678 NTSTATUS status;
5679 connection_struct *conn = req->conn;
5680 struct smbXsrv_tcon *tcon;
5682 START_PROFILE(SMBtdis);
5684 if (!conn) {
5685 DEBUG(4,("Invalid connection in tdis\n"));
5686 reply_force_doserror(req, ERRSRV, ERRinvnid);
5687 END_PROFILE(SMBtdis);
5688 return;
5691 tcon = conn->tcon;
5692 req->conn = NULL;
5695 * TODO: cancel all outstanding requests on the tcon
5697 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5698 if (!NT_STATUS_IS_OK(status)) {
5699 DEBUG(0, ("reply_tdis: "
5700 "smbXsrv_tcon_disconnect() failed: %s\n",
5701 nt_errstr(status)));
5703 * If we hit this case, there is something completely
5704 * wrong, so we better disconnect the transport connection.
5706 END_PROFILE(SMBtdis);
5707 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5708 return;
5711 TALLOC_FREE(tcon);
5713 reply_outbuf(req, 0, 0);
5714 END_PROFILE(SMBtdis);
5715 return;
5718 /****************************************************************************
5719 Reply to a echo.
5720 conn POINTER CAN BE NULL HERE !
5721 ****************************************************************************/
5723 void reply_echo(struct smb_request *req)
5725 connection_struct *conn = req->conn;
5726 struct smb_perfcount_data local_pcd;
5727 struct smb_perfcount_data *cur_pcd;
5728 int smb_reverb;
5729 int seq_num;
5731 START_PROFILE(SMBecho);
5733 smb_init_perfcount_data(&local_pcd);
5735 if (req->wct < 1) {
5736 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5737 END_PROFILE(SMBecho);
5738 return;
5741 smb_reverb = SVAL(req->vwv+0, 0);
5743 reply_outbuf(req, 1, req->buflen);
5745 /* copy any incoming data back out */
5746 if (req->buflen > 0) {
5747 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5750 if (smb_reverb > 100) {
5751 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5752 smb_reverb = 100;
5755 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5757 /* this makes sure we catch the request pcd */
5758 if (seq_num == smb_reverb) {
5759 cur_pcd = &req->pcd;
5760 } else {
5761 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5762 cur_pcd = &local_pcd;
5765 SSVAL(req->outbuf,smb_vwv0,seq_num);
5767 show_msg((char *)req->outbuf);
5768 if (!srv_send_smb(req->xconn,
5769 (char *)req->outbuf,
5770 true, req->seqnum+1,
5771 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5772 cur_pcd))
5773 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5776 DEBUG(3,("echo %d times\n", smb_reverb));
5778 TALLOC_FREE(req->outbuf);
5780 END_PROFILE(SMBecho);
5781 return;
5784 /****************************************************************************
5785 Reply to a printopen.
5786 ****************************************************************************/
5788 void reply_printopen(struct smb_request *req)
5790 connection_struct *conn = req->conn;
5791 files_struct *fsp;
5792 NTSTATUS status;
5794 START_PROFILE(SMBsplopen);
5796 if (req->wct < 2) {
5797 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5798 END_PROFILE(SMBsplopen);
5799 return;
5802 if (!CAN_PRINT(conn)) {
5803 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5804 END_PROFILE(SMBsplopen);
5805 return;
5808 status = file_new(req, conn, &fsp);
5809 if(!NT_STATUS_IS_OK(status)) {
5810 reply_nterror(req, status);
5811 END_PROFILE(SMBsplopen);
5812 return;
5815 /* Open for exclusive use, write only. */
5816 status = print_spool_open(fsp, NULL, req->vuid);
5818 if (!NT_STATUS_IS_OK(status)) {
5819 file_free(req, fsp);
5820 reply_nterror(req, status);
5821 END_PROFILE(SMBsplopen);
5822 return;
5825 reply_outbuf(req, 1, 0);
5826 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5828 DEBUG(3,("openprint fd=%d %s\n",
5829 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5831 END_PROFILE(SMBsplopen);
5832 return;
5835 /****************************************************************************
5836 Reply to a printclose.
5837 ****************************************************************************/
5839 void reply_printclose(struct smb_request *req)
5841 connection_struct *conn = req->conn;
5842 files_struct *fsp;
5843 NTSTATUS status;
5845 START_PROFILE(SMBsplclose);
5847 if (req->wct < 1) {
5848 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5849 END_PROFILE(SMBsplclose);
5850 return;
5853 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5855 if (!check_fsp(conn, req, fsp)) {
5856 END_PROFILE(SMBsplclose);
5857 return;
5860 if (!CAN_PRINT(conn)) {
5861 reply_force_doserror(req, ERRSRV, ERRerror);
5862 END_PROFILE(SMBsplclose);
5863 return;
5866 DEBUG(3,("printclose fd=%d %s\n",
5867 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5869 status = close_file(req, fsp, NORMAL_CLOSE);
5871 if(!NT_STATUS_IS_OK(status)) {
5872 reply_nterror(req, status);
5873 END_PROFILE(SMBsplclose);
5874 return;
5877 reply_outbuf(req, 0, 0);
5879 END_PROFILE(SMBsplclose);
5880 return;
5883 /****************************************************************************
5884 Reply to a printqueue.
5885 ****************************************************************************/
5887 void reply_printqueue(struct smb_request *req)
5889 connection_struct *conn = req->conn;
5890 int max_count;
5891 int start_index;
5893 START_PROFILE(SMBsplretq);
5895 if (req->wct < 2) {
5896 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5897 END_PROFILE(SMBsplretq);
5898 return;
5901 max_count = SVAL(req->vwv+0, 0);
5902 start_index = SVAL(req->vwv+1, 0);
5904 /* we used to allow the client to get the cnum wrong, but that
5905 is really quite gross and only worked when there was only
5906 one printer - I think we should now only accept it if they
5907 get it right (tridge) */
5908 if (!CAN_PRINT(conn)) {
5909 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5910 END_PROFILE(SMBsplretq);
5911 return;
5914 reply_outbuf(req, 2, 3);
5915 SSVAL(req->outbuf,smb_vwv0,0);
5916 SSVAL(req->outbuf,smb_vwv1,0);
5917 SCVAL(smb_buf(req->outbuf),0,1);
5918 SSVAL(smb_buf(req->outbuf),1,0);
5920 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5921 start_index, max_count));
5924 TALLOC_CTX *mem_ctx = talloc_tos();
5925 NTSTATUS status;
5926 WERROR werr;
5927 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5928 struct rpc_pipe_client *cli = NULL;
5929 struct dcerpc_binding_handle *b = NULL;
5930 struct policy_handle handle;
5931 struct spoolss_DevmodeContainer devmode_ctr;
5932 union spoolss_JobInfo *info;
5933 uint32_t count;
5934 uint32_t num_to_get;
5935 uint32_t first;
5936 uint32_t i;
5938 ZERO_STRUCT(handle);
5940 status = rpc_pipe_open_interface(conn,
5941 &ndr_table_spoolss,
5942 conn->session_info,
5943 conn->sconn->remote_address,
5944 conn->sconn->msg_ctx,
5945 &cli);
5946 if (!NT_STATUS_IS_OK(status)) {
5947 DEBUG(0, ("reply_printqueue: "
5948 "could not connect to spoolss: %s\n",
5949 nt_errstr(status)));
5950 reply_nterror(req, status);
5951 goto out;
5953 b = cli->binding_handle;
5955 ZERO_STRUCT(devmode_ctr);
5957 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5958 sharename,
5959 NULL, devmode_ctr,
5960 SEC_FLAG_MAXIMUM_ALLOWED,
5961 &handle,
5962 &werr);
5963 if (!NT_STATUS_IS_OK(status)) {
5964 reply_nterror(req, status);
5965 goto out;
5967 if (!W_ERROR_IS_OK(werr)) {
5968 reply_nterror(req, werror_to_ntstatus(werr));
5969 goto out;
5972 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5973 &handle,
5974 0, /* firstjob */
5975 0xff, /* numjobs */
5976 2, /* level */
5977 0, /* offered */
5978 &count,
5979 &info);
5980 if (!W_ERROR_IS_OK(werr)) {
5981 reply_nterror(req, werror_to_ntstatus(werr));
5982 goto out;
5985 if (max_count > 0) {
5986 first = start_index;
5987 } else {
5988 first = start_index + max_count + 1;
5991 if (first >= count) {
5992 num_to_get = first;
5993 } else {
5994 num_to_get = first + MIN(ABS(max_count), count - first);
5997 for (i = first; i < num_to_get; i++) {
5998 char blob[28];
5999 char *p = blob;
6000 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6001 int qstatus;
6002 size_t len = 0;
6003 uint16_t qrapjobid = pjobid_to_rap(sharename,
6004 info[i].info2.job_id);
6006 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6007 qstatus = 2;
6008 } else {
6009 qstatus = 3;
6012 srv_put_dos_date2(p, 0, qtime);
6013 SCVAL(p, 4, qstatus);
6014 SSVAL(p, 5, qrapjobid);
6015 SIVAL(p, 7, info[i].info2.size);
6016 SCVAL(p, 11, 0);
6017 status = srvstr_push(blob, req->flags2, p+12,
6018 info[i].info2.notify_name, 16, STR_ASCII, &len);
6019 if (!NT_STATUS_IS_OK(status)) {
6020 reply_nterror(req, status);
6021 goto out;
6023 if (message_push_blob(
6024 &req->outbuf,
6025 data_blob_const(
6026 blob, sizeof(blob))) == -1) {
6027 reply_nterror(req, NT_STATUS_NO_MEMORY);
6028 goto out;
6032 if (count > 0) {
6033 SSVAL(req->outbuf,smb_vwv0,count);
6034 SSVAL(req->outbuf,smb_vwv1,
6035 (max_count>0?first+count:first-1));
6036 SCVAL(smb_buf(req->outbuf),0,1);
6037 SSVAL(smb_buf(req->outbuf),1,28*count);
6041 DEBUG(3, ("%u entries returned in queue\n",
6042 (unsigned)count));
6044 out:
6045 if (b && is_valid_policy_hnd(&handle)) {
6046 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6051 END_PROFILE(SMBsplretq);
6052 return;
6055 /****************************************************************************
6056 Reply to a printwrite.
6057 ****************************************************************************/
6059 void reply_printwrite(struct smb_request *req)
6061 connection_struct *conn = req->conn;
6062 int numtowrite;
6063 const char *data;
6064 files_struct *fsp;
6066 START_PROFILE(SMBsplwr);
6068 if (req->wct < 1) {
6069 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6070 END_PROFILE(SMBsplwr);
6071 return;
6074 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6076 if (!check_fsp(conn, req, fsp)) {
6077 END_PROFILE(SMBsplwr);
6078 return;
6081 if (!fsp->print_file) {
6082 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6083 END_PROFILE(SMBsplwr);
6084 return;
6087 if (!CHECK_WRITE(fsp)) {
6088 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6089 END_PROFILE(SMBsplwr);
6090 return;
6093 numtowrite = SVAL(req->buf, 1);
6095 if (req->buflen < numtowrite + 3) {
6096 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6097 END_PROFILE(SMBsplwr);
6098 return;
6101 data = (const char *)req->buf + 3;
6103 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6104 reply_nterror(req, map_nt_error_from_unix(errno));
6105 END_PROFILE(SMBsplwr);
6106 return;
6109 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6111 END_PROFILE(SMBsplwr);
6112 return;
6115 /****************************************************************************
6116 Reply to a mkdir.
6117 ****************************************************************************/
6119 void reply_mkdir(struct smb_request *req)
6121 connection_struct *conn = req->conn;
6122 struct smb_filename *smb_dname = NULL;
6123 char *directory = NULL;
6124 NTSTATUS status;
6125 uint32_t ucf_flags = UCF_PREP_CREATEFILE |
6126 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
6127 TALLOC_CTX *ctx = talloc_tos();
6129 START_PROFILE(SMBmkdir);
6131 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6132 STR_TERMINATE, &status);
6133 if (!NT_STATUS_IS_OK(status)) {
6134 reply_nterror(req, status);
6135 goto out;
6138 status = filename_convert(ctx, conn,
6139 req->flags2 & FLAGS2_DFS_PATHNAMES,
6140 directory,
6141 ucf_flags,
6142 NULL,
6143 &smb_dname);
6144 if (!NT_STATUS_IS_OK(status)) {
6145 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6146 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6147 ERRSRV, ERRbadpath);
6148 goto out;
6150 reply_nterror(req, status);
6151 goto out;
6154 status = create_directory(conn, req, smb_dname);
6156 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6158 if (!NT_STATUS_IS_OK(status)) {
6160 if (!use_nt_status()
6161 && NT_STATUS_EQUAL(status,
6162 NT_STATUS_OBJECT_NAME_COLLISION)) {
6164 * Yes, in the DOS error code case we get a
6165 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6166 * samba4 torture test.
6168 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6171 reply_nterror(req, status);
6172 goto out;
6175 reply_outbuf(req, 0, 0);
6177 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6178 out:
6179 TALLOC_FREE(smb_dname);
6180 END_PROFILE(SMBmkdir);
6181 return;
6184 /****************************************************************************
6185 Reply to a rmdir.
6186 ****************************************************************************/
6188 void reply_rmdir(struct smb_request *req)
6190 connection_struct *conn = req->conn;
6191 struct smb_filename *smb_dname = NULL;
6192 char *directory = NULL;
6193 NTSTATUS status;
6194 TALLOC_CTX *ctx = talloc_tos();
6195 files_struct *fsp = NULL;
6196 int info = 0;
6197 uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
6198 struct smbd_server_connection *sconn = req->sconn;
6200 START_PROFILE(SMBrmdir);
6202 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6203 STR_TERMINATE, &status);
6204 if (!NT_STATUS_IS_OK(status)) {
6205 reply_nterror(req, status);
6206 goto out;
6209 status = filename_convert(ctx, conn,
6210 req->flags2 & FLAGS2_DFS_PATHNAMES,
6211 directory,
6212 ucf_flags,
6213 NULL,
6214 &smb_dname);
6215 if (!NT_STATUS_IS_OK(status)) {
6216 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6217 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6218 ERRSRV, ERRbadpath);
6219 goto out;
6221 reply_nterror(req, status);
6222 goto out;
6225 if (is_ntfs_stream_smb_fname(smb_dname)) {
6226 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6227 goto out;
6230 status = SMB_VFS_CREATE_FILE(
6231 conn, /* conn */
6232 req, /* req */
6233 0, /* root_dir_fid */
6234 smb_dname, /* fname */
6235 DELETE_ACCESS, /* access_mask */
6236 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6237 FILE_SHARE_DELETE),
6238 FILE_OPEN, /* create_disposition*/
6239 FILE_DIRECTORY_FILE, /* create_options */
6240 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6241 0, /* oplock_request */
6242 NULL, /* lease */
6243 0, /* allocation_size */
6244 0, /* private_flags */
6245 NULL, /* sd */
6246 NULL, /* ea_list */
6247 &fsp, /* result */
6248 &info, /* pinfo */
6249 NULL, NULL); /* create context */
6251 if (!NT_STATUS_IS_OK(status)) {
6252 if (open_was_deferred(req->xconn, req->mid)) {
6253 /* We have re-scheduled this call. */
6254 goto out;
6256 reply_nterror(req, status);
6257 goto out;
6260 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6261 if (!NT_STATUS_IS_OK(status)) {
6262 close_file(req, fsp, ERROR_CLOSE);
6263 reply_nterror(req, status);
6264 goto out;
6267 if (!set_delete_on_close(fsp, true,
6268 conn->session_info->security_token,
6269 conn->session_info->unix_token)) {
6270 close_file(req, fsp, ERROR_CLOSE);
6271 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6272 goto out;
6275 status = close_file(req, fsp, NORMAL_CLOSE);
6276 if (!NT_STATUS_IS_OK(status)) {
6277 reply_nterror(req, status);
6278 } else {
6279 reply_outbuf(req, 0, 0);
6282 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6284 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6285 out:
6286 TALLOC_FREE(smb_dname);
6287 END_PROFILE(SMBrmdir);
6288 return;
6291 /*******************************************************************
6292 Resolve wildcards in a filename rename.
6293 ********************************************************************/
6295 static bool resolve_wildcards(TALLOC_CTX *ctx,
6296 const char *name1,
6297 const char *name2,
6298 char **pp_newname)
6300 char *name2_copy = NULL;
6301 char *root1 = NULL;
6302 char *root2 = NULL;
6303 char *ext1 = NULL;
6304 char *ext2 = NULL;
6305 char *p,*p2, *pname1, *pname2;
6307 name2_copy = talloc_strdup(ctx, name2);
6308 if (!name2_copy) {
6309 return False;
6312 pname1 = strrchr_m(name1,'/');
6313 pname2 = strrchr_m(name2_copy,'/');
6315 if (!pname1 || !pname2) {
6316 return False;
6319 /* Truncate the copy of name2 at the last '/' */
6320 *pname2 = '\0';
6322 /* Now go past the '/' */
6323 pname1++;
6324 pname2++;
6326 root1 = talloc_strdup(ctx, pname1);
6327 root2 = talloc_strdup(ctx, pname2);
6329 if (!root1 || !root2) {
6330 return False;
6333 p = strrchr_m(root1,'.');
6334 if (p) {
6335 *p = 0;
6336 ext1 = talloc_strdup(ctx, p+1);
6337 } else {
6338 ext1 = talloc_strdup(ctx, "");
6340 p = strrchr_m(root2,'.');
6341 if (p) {
6342 *p = 0;
6343 ext2 = talloc_strdup(ctx, p+1);
6344 } else {
6345 ext2 = talloc_strdup(ctx, "");
6348 if (!ext1 || !ext2) {
6349 return False;
6352 p = root1;
6353 p2 = root2;
6354 while (*p2) {
6355 if (*p2 == '?') {
6356 /* Hmmm. Should this be mb-aware ? */
6357 *p2 = *p;
6358 p2++;
6359 } else if (*p2 == '*') {
6360 *p2 = '\0';
6361 root2 = talloc_asprintf(ctx, "%s%s",
6362 root2,
6364 if (!root2) {
6365 return False;
6367 break;
6368 } else {
6369 p2++;
6371 if (*p) {
6372 p++;
6376 p = ext1;
6377 p2 = ext2;
6378 while (*p2) {
6379 if (*p2 == '?') {
6380 /* Hmmm. Should this be mb-aware ? */
6381 *p2 = *p;
6382 p2++;
6383 } else if (*p2 == '*') {
6384 *p2 = '\0';
6385 ext2 = talloc_asprintf(ctx, "%s%s",
6386 ext2,
6388 if (!ext2) {
6389 return False;
6391 break;
6392 } else {
6393 p2++;
6395 if (*p) {
6396 p++;
6400 if (*ext2) {
6401 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6402 name2_copy,
6403 root2,
6404 ext2);
6405 } else {
6406 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6407 name2_copy,
6408 root2);
6411 if (!*pp_newname) {
6412 return False;
6415 return True;
6418 /****************************************************************************
6419 Ensure open files have their names updated. Updated to notify other smbd's
6420 asynchronously.
6421 ****************************************************************************/
6423 static void rename_open_files(connection_struct *conn,
6424 struct share_mode_lock *lck,
6425 struct file_id id,
6426 uint32_t orig_name_hash,
6427 const struct smb_filename *smb_fname_dst)
6429 files_struct *fsp;
6430 bool did_rename = False;
6431 NTSTATUS status;
6432 uint32_t new_name_hash = 0;
6434 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6435 fsp = file_find_di_next(fsp)) {
6436 /* fsp_name is a relative path under the fsp. To change this for other
6437 sharepaths we need to manipulate relative paths. */
6438 /* TODO - create the absolute path and manipulate the newname
6439 relative to the sharepath. */
6440 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6441 continue;
6443 if (fsp->name_hash != orig_name_hash) {
6444 continue;
6446 DEBUG(10, ("rename_open_files: renaming file %s "
6447 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6448 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6449 smb_fname_str_dbg(smb_fname_dst)));
6451 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6452 if (NT_STATUS_IS_OK(status)) {
6453 did_rename = True;
6454 new_name_hash = fsp->name_hash;
6458 if (!did_rename) {
6459 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6460 "for %s\n", file_id_string_tos(&id),
6461 smb_fname_str_dbg(smb_fname_dst)));
6464 /* Send messages to all smbd's (not ourself) that the name has changed. */
6465 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6466 orig_name_hash, new_name_hash,
6467 smb_fname_dst);
6471 /****************************************************************************
6472 We need to check if the source path is a parent directory of the destination
6473 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6474 refuse the rename with a sharing violation. Under UNIX the above call can
6475 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6476 probably need to check that the client is a Windows one before disallowing
6477 this as a UNIX client (one with UNIX extensions) can know the source is a
6478 symlink and make this decision intelligently. Found by an excellent bug
6479 report from <AndyLiebman@aol.com>.
6480 ****************************************************************************/
6482 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6483 const struct smb_filename *smb_fname_dst)
6485 const char *psrc = smb_fname_src->base_name;
6486 const char *pdst = smb_fname_dst->base_name;
6487 size_t slen;
6489 if (psrc[0] == '.' && psrc[1] == '/') {
6490 psrc += 2;
6492 if (pdst[0] == '.' && pdst[1] == '/') {
6493 pdst += 2;
6495 if ((slen = strlen(psrc)) > strlen(pdst)) {
6496 return False;
6498 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6502 * Do the notify calls from a rename
6505 static void notify_rename(connection_struct *conn, bool is_dir,
6506 const struct smb_filename *smb_fname_src,
6507 const struct smb_filename *smb_fname_dst)
6509 char *parent_dir_src = NULL;
6510 char *parent_dir_dst = NULL;
6511 uint32_t mask;
6513 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6514 : FILE_NOTIFY_CHANGE_FILE_NAME;
6516 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6517 &parent_dir_src, NULL) ||
6518 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6519 &parent_dir_dst, NULL)) {
6520 goto out;
6523 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6524 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6525 smb_fname_src->base_name);
6526 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6527 smb_fname_dst->base_name);
6529 else {
6530 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6531 smb_fname_src->base_name);
6532 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6533 smb_fname_dst->base_name);
6536 /* this is a strange one. w2k3 gives an additional event for
6537 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6538 files, but not directories */
6539 if (!is_dir) {
6540 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6541 FILE_NOTIFY_CHANGE_ATTRIBUTES
6542 |FILE_NOTIFY_CHANGE_CREATION,
6543 smb_fname_dst->base_name);
6545 out:
6546 TALLOC_FREE(parent_dir_src);
6547 TALLOC_FREE(parent_dir_dst);
6550 /****************************************************************************
6551 Returns an error if the parent directory for a filename is open in an
6552 incompatible way.
6553 ****************************************************************************/
6555 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6556 const struct smb_filename *smb_fname_dst_in)
6558 char *parent_dir = NULL;
6559 struct smb_filename smb_fname_parent;
6560 struct file_id id;
6561 files_struct *fsp = NULL;
6562 int ret;
6564 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6565 &parent_dir, NULL)) {
6566 return NT_STATUS_NO_MEMORY;
6568 ZERO_STRUCT(smb_fname_parent);
6569 smb_fname_parent.base_name = parent_dir;
6571 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6572 if (ret == -1) {
6573 return map_nt_error_from_unix(errno);
6577 * We're only checking on this smbd here, mostly good
6578 * enough.. and will pass tests.
6581 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6582 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6583 fsp = file_find_di_next(fsp)) {
6584 if (fsp->access_mask & DELETE_ACCESS) {
6585 return NT_STATUS_SHARING_VIOLATION;
6588 return NT_STATUS_OK;
6591 /****************************************************************************
6592 Rename an open file - given an fsp.
6593 ****************************************************************************/
6595 NTSTATUS rename_internals_fsp(connection_struct *conn,
6596 files_struct *fsp,
6597 const struct smb_filename *smb_fname_dst_in,
6598 uint32_t attrs,
6599 bool replace_if_exists)
6601 TALLOC_CTX *ctx = talloc_tos();
6602 struct smb_filename *smb_fname_dst = NULL;
6603 NTSTATUS status = NT_STATUS_OK;
6604 struct share_mode_lock *lck = NULL;
6605 bool dst_exists, old_is_stream, new_is_stream;
6607 status = check_name(conn, smb_fname_dst_in->base_name);
6608 if (!NT_STATUS_IS_OK(status)) {
6609 return status;
6612 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6613 if (!NT_STATUS_IS_OK(status)) {
6614 return status;
6617 /* Make a copy of the dst smb_fname structs */
6619 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6620 if (smb_fname_dst == NULL) {
6621 status = NT_STATUS_NO_MEMORY;
6622 goto out;
6626 * Check for special case with case preserving and not
6627 * case sensitive. If the new last component differs from the original
6628 * last component only by case, then we should allow
6629 * the rename (user is trying to change the case of the
6630 * filename).
6632 if (!conn->case_sensitive && conn->case_preserve &&
6633 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6634 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6635 char *fname_dst_parent = NULL;
6636 const char *fname_dst_lcomp = NULL;
6637 char *orig_lcomp_path = NULL;
6638 char *orig_lcomp_stream = NULL;
6639 bool ok = true;
6642 * Split off the last component of the processed
6643 * destination name. We will compare this to
6644 * the split components of smb_fname_dst->original_lcomp.
6646 if (!parent_dirname(ctx,
6647 smb_fname_dst->base_name,
6648 &fname_dst_parent,
6649 &fname_dst_lcomp)) {
6650 status = NT_STATUS_NO_MEMORY;
6651 goto out;
6655 * The original_lcomp component contains
6656 * the last_component of the path + stream
6657 * name (if a stream exists).
6659 * Split off the stream name so we
6660 * can check them separately.
6663 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6664 /* POSIX - no stream component. */
6665 orig_lcomp_path = talloc_strdup(ctx,
6666 smb_fname_dst->original_lcomp);
6667 if (orig_lcomp_path == NULL) {
6668 ok = false;
6670 } else {
6671 ok = split_stream_filename(ctx,
6672 smb_fname_dst->original_lcomp,
6673 &orig_lcomp_path,
6674 &orig_lcomp_stream);
6677 if (!ok) {
6678 TALLOC_FREE(fname_dst_parent);
6679 status = NT_STATUS_NO_MEMORY;
6680 goto out;
6683 /* If the base names only differ by case, use original. */
6684 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6685 char *tmp;
6687 * Replace the modified last component with the
6688 * original.
6690 if (!ISDOT(fname_dst_parent)) {
6691 tmp = talloc_asprintf(smb_fname_dst,
6692 "%s/%s",
6693 fname_dst_parent,
6694 orig_lcomp_path);
6695 } else {
6696 tmp = talloc_strdup(smb_fname_dst,
6697 orig_lcomp_path);
6699 if (tmp == NULL) {
6700 status = NT_STATUS_NO_MEMORY;
6701 TALLOC_FREE(fname_dst_parent);
6702 TALLOC_FREE(orig_lcomp_path);
6703 TALLOC_FREE(orig_lcomp_stream);
6704 goto out;
6706 TALLOC_FREE(smb_fname_dst->base_name);
6707 smb_fname_dst->base_name = tmp;
6710 /* If the stream_names only differ by case, use original. */
6711 if(!strcsequal(smb_fname_dst->stream_name,
6712 orig_lcomp_stream)) {
6713 /* Use the original stream. */
6714 char *tmp = talloc_strdup(smb_fname_dst,
6715 orig_lcomp_stream);
6716 if (tmp == NULL) {
6717 status = NT_STATUS_NO_MEMORY;
6718 TALLOC_FREE(fname_dst_parent);
6719 TALLOC_FREE(orig_lcomp_path);
6720 TALLOC_FREE(orig_lcomp_stream);
6721 goto out;
6723 TALLOC_FREE(smb_fname_dst->stream_name);
6724 smb_fname_dst->stream_name = tmp;
6726 TALLOC_FREE(fname_dst_parent);
6727 TALLOC_FREE(orig_lcomp_path);
6728 TALLOC_FREE(orig_lcomp_stream);
6732 * If the src and dest names are identical - including case,
6733 * don't do the rename, just return success.
6736 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6737 strcsequal(fsp->fsp_name->stream_name,
6738 smb_fname_dst->stream_name)) {
6739 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6740 "- returning success\n",
6741 smb_fname_str_dbg(smb_fname_dst)));
6742 status = NT_STATUS_OK;
6743 goto out;
6746 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6747 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6749 /* Return the correct error code if both names aren't streams. */
6750 if (!old_is_stream && new_is_stream) {
6751 status = NT_STATUS_OBJECT_NAME_INVALID;
6752 goto out;
6755 if (old_is_stream && !new_is_stream) {
6756 status = NT_STATUS_INVALID_PARAMETER;
6757 goto out;
6760 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6762 if(!replace_if_exists && dst_exists) {
6763 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6764 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6765 smb_fname_str_dbg(smb_fname_dst)));
6766 status = NT_STATUS_OBJECT_NAME_COLLISION;
6767 goto out;
6770 if (dst_exists) {
6771 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6772 &smb_fname_dst->st);
6773 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6774 fileid);
6775 /* The file can be open when renaming a stream */
6776 if (dst_fsp && !new_is_stream) {
6777 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6778 status = NT_STATUS_ACCESS_DENIED;
6779 goto out;
6783 /* Ensure we have a valid stat struct for the source. */
6784 status = vfs_stat_fsp(fsp);
6785 if (!NT_STATUS_IS_OK(status)) {
6786 goto out;
6789 status = can_rename(conn, fsp, attrs);
6791 if (!NT_STATUS_IS_OK(status)) {
6792 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6793 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6794 smb_fname_str_dbg(smb_fname_dst)));
6795 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6796 status = NT_STATUS_ACCESS_DENIED;
6797 goto out;
6800 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6801 status = NT_STATUS_ACCESS_DENIED;
6804 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6807 * We have the file open ourselves, so not being able to get the
6808 * corresponding share mode lock is a fatal error.
6811 SMB_ASSERT(lck != NULL);
6813 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6814 uint32_t create_options = fsp->fh->private_options;
6816 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6817 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6818 smb_fname_str_dbg(smb_fname_dst)));
6820 if (!fsp->is_directory &&
6821 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6822 (lp_map_archive(SNUM(conn)) ||
6823 lp_store_dos_attributes(SNUM(conn)))) {
6824 /* We must set the archive bit on the newly
6825 renamed file. */
6826 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6827 uint32_t old_dosmode = dos_mode(conn,
6828 smb_fname_dst);
6829 file_set_dosmode(conn,
6830 smb_fname_dst,
6831 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6832 NULL,
6833 true);
6837 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6838 smb_fname_dst);
6840 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6841 smb_fname_dst);
6844 * A rename acts as a new file create w.r.t. allowing an initial delete
6845 * on close, probably because in Windows there is a new handle to the
6846 * new file. If initial delete on close was requested but not
6847 * originally set, we need to set it here. This is probably not 100% correct,
6848 * but will work for the CIFSFS client which in non-posix mode
6849 * depends on these semantics. JRA.
6852 if (create_options & FILE_DELETE_ON_CLOSE) {
6853 status = can_set_delete_on_close(fsp, 0);
6855 if (NT_STATUS_IS_OK(status)) {
6856 /* Note that here we set the *inital* delete on close flag,
6857 * not the regular one. The magic gets handled in close. */
6858 fsp->initial_delete_on_close = True;
6861 TALLOC_FREE(lck);
6862 status = NT_STATUS_OK;
6863 goto out;
6866 TALLOC_FREE(lck);
6868 if (errno == ENOTDIR || errno == EISDIR) {
6869 status = NT_STATUS_OBJECT_NAME_COLLISION;
6870 } else {
6871 status = map_nt_error_from_unix(errno);
6874 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6875 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6876 smb_fname_str_dbg(smb_fname_dst)));
6878 out:
6879 TALLOC_FREE(smb_fname_dst);
6881 return status;
6884 /****************************************************************************
6885 The guts of the rename command, split out so it may be called by the NT SMB
6886 code.
6887 ****************************************************************************/
6889 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6890 connection_struct *conn,
6891 struct smb_request *req,
6892 struct smb_filename *smb_fname_src,
6893 struct smb_filename *smb_fname_dst,
6894 uint32_t attrs,
6895 bool replace_if_exists,
6896 bool src_has_wild,
6897 bool dest_has_wild,
6898 uint32_t access_mask)
6900 char *fname_src_dir = NULL;
6901 struct smb_filename *smb_fname_src_dir = NULL;
6902 char *fname_src_mask = NULL;
6903 int count=0;
6904 NTSTATUS status = NT_STATUS_OK;
6905 struct smb_Dir *dir_hnd = NULL;
6906 const char *dname = NULL;
6907 char *talloced = NULL;
6908 long offset = 0;
6909 int create_options = 0;
6910 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6911 int rc;
6914 * Split the old name into directory and last component
6915 * strings. Note that unix_convert may have stripped off a
6916 * leading ./ from both name and newname if the rename is
6917 * at the root of the share. We need to make sure either both
6918 * name and newname contain a / character or neither of them do
6919 * as this is checked in resolve_wildcards().
6922 /* Split up the directory from the filename/mask. */
6923 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6924 &fname_src_dir, &fname_src_mask);
6925 if (!NT_STATUS_IS_OK(status)) {
6926 status = NT_STATUS_NO_MEMORY;
6927 goto out;
6931 * We should only check the mangled cache
6932 * here if unix_convert failed. This means
6933 * that the path in 'mask' doesn't exist
6934 * on the file system and so we need to look
6935 * for a possible mangle. This patch from
6936 * Tine Smukavec <valentin.smukavec@hermes.si>.
6939 if (!VALID_STAT(smb_fname_src->st) &&
6940 mangle_is_mangled(fname_src_mask, conn->params)) {
6941 char *new_mask = NULL;
6942 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6943 conn->params);
6944 if (new_mask) {
6945 TALLOC_FREE(fname_src_mask);
6946 fname_src_mask = new_mask;
6950 if (!src_has_wild) {
6951 files_struct *fsp;
6954 * Only one file needs to be renamed. Append the mask back
6955 * onto the directory.
6957 TALLOC_FREE(smb_fname_src->base_name);
6958 if (ISDOT(fname_src_dir)) {
6959 /* Ensure we use canonical names on open. */
6960 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6961 "%s",
6962 fname_src_mask);
6963 } else {
6964 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6965 "%s/%s",
6966 fname_src_dir,
6967 fname_src_mask);
6969 if (!smb_fname_src->base_name) {
6970 status = NT_STATUS_NO_MEMORY;
6971 goto out;
6974 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6975 "case_preserve = %d, short case preserve = %d, "
6976 "directory = %s, newname = %s, "
6977 "last_component_dest = %s\n",
6978 conn->case_sensitive, conn->case_preserve,
6979 conn->short_case_preserve,
6980 smb_fname_str_dbg(smb_fname_src),
6981 smb_fname_str_dbg(smb_fname_dst),
6982 smb_fname_dst->original_lcomp));
6984 /* The dest name still may have wildcards. */
6985 if (dest_has_wild) {
6986 char *fname_dst_mod = NULL;
6987 if (!resolve_wildcards(smb_fname_dst,
6988 smb_fname_src->base_name,
6989 smb_fname_dst->base_name,
6990 &fname_dst_mod)) {
6991 DEBUG(6, ("rename_internals: resolve_wildcards "
6992 "%s %s failed\n",
6993 smb_fname_src->base_name,
6994 smb_fname_dst->base_name));
6995 status = NT_STATUS_NO_MEMORY;
6996 goto out;
6998 TALLOC_FREE(smb_fname_dst->base_name);
6999 smb_fname_dst->base_name = fname_dst_mod;
7002 ZERO_STRUCT(smb_fname_src->st);
7003 if (posix_pathnames) {
7004 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7005 } else {
7006 rc = SMB_VFS_STAT(conn, smb_fname_src);
7008 if (rc == -1) {
7009 status = map_nt_error_from_unix_common(errno);
7010 goto out;
7013 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7014 create_options |= FILE_DIRECTORY_FILE;
7017 status = SMB_VFS_CREATE_FILE(
7018 conn, /* conn */
7019 req, /* req */
7020 0, /* root_dir_fid */
7021 smb_fname_src, /* fname */
7022 access_mask, /* access_mask */
7023 (FILE_SHARE_READ | /* share_access */
7024 FILE_SHARE_WRITE),
7025 FILE_OPEN, /* create_disposition*/
7026 create_options, /* create_options */
7027 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7028 0, /* oplock_request */
7029 NULL, /* lease */
7030 0, /* allocation_size */
7031 0, /* private_flags */
7032 NULL, /* sd */
7033 NULL, /* ea_list */
7034 &fsp, /* result */
7035 NULL, /* pinfo */
7036 NULL, NULL); /* create context */
7038 if (!NT_STATUS_IS_OK(status)) {
7039 DEBUG(3, ("Could not open rename source %s: %s\n",
7040 smb_fname_str_dbg(smb_fname_src),
7041 nt_errstr(status)));
7042 goto out;
7045 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7046 attrs, replace_if_exists);
7048 close_file(req, fsp, NORMAL_CLOSE);
7050 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7051 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7052 smb_fname_str_dbg(smb_fname_dst)));
7054 goto out;
7058 * Wildcards - process each file that matches.
7060 if (strequal(fname_src_mask, "????????.???")) {
7061 TALLOC_FREE(fname_src_mask);
7062 fname_src_mask = talloc_strdup(ctx, "*");
7063 if (!fname_src_mask) {
7064 status = NT_STATUS_NO_MEMORY;
7065 goto out;
7069 status = check_name(conn, fname_src_dir);
7070 if (!NT_STATUS_IS_OK(status)) {
7071 goto out;
7074 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7075 fname_src_dir,
7076 NULL,
7077 NULL,
7078 smb_fname_src->flags);
7079 if (smb_fname_src_dir == NULL) {
7080 status = NT_STATUS_NO_MEMORY;
7081 goto out;
7084 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7085 attrs);
7086 if (dir_hnd == NULL) {
7087 status = map_nt_error_from_unix(errno);
7088 goto out;
7091 status = NT_STATUS_NO_SUCH_FILE;
7093 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7094 * - gentest fix. JRA
7097 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7098 &talloced))) {
7099 files_struct *fsp = NULL;
7100 char *destname = NULL;
7101 bool sysdir_entry = False;
7103 /* Quick check for "." and ".." */
7104 if (ISDOT(dname) || ISDOTDOT(dname)) {
7105 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7106 sysdir_entry = True;
7107 } else {
7108 TALLOC_FREE(talloced);
7109 continue;
7113 if (!is_visible_file(conn, fname_src_dir, dname,
7114 &smb_fname_src->st, false)) {
7115 TALLOC_FREE(talloced);
7116 continue;
7119 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7120 TALLOC_FREE(talloced);
7121 continue;
7124 if (sysdir_entry) {
7125 status = NT_STATUS_OBJECT_NAME_INVALID;
7126 break;
7129 TALLOC_FREE(smb_fname_src->base_name);
7130 if (ISDOT(fname_src_dir)) {
7131 /* Ensure we use canonical names on open. */
7132 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7133 "%s",
7134 dname);
7135 } else {
7136 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7137 "%s/%s",
7138 fname_src_dir,
7139 dname);
7141 if (!smb_fname_src->base_name) {
7142 status = NT_STATUS_NO_MEMORY;
7143 goto out;
7146 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7147 smb_fname_dst->base_name,
7148 &destname)) {
7149 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7150 smb_fname_src->base_name, destname));
7151 TALLOC_FREE(talloced);
7152 continue;
7154 if (!destname) {
7155 status = NT_STATUS_NO_MEMORY;
7156 goto out;
7159 TALLOC_FREE(smb_fname_dst->base_name);
7160 smb_fname_dst->base_name = destname;
7162 ZERO_STRUCT(smb_fname_src->st);
7163 if (posix_pathnames) {
7164 SMB_VFS_LSTAT(conn, smb_fname_src);
7165 } else {
7166 SMB_VFS_STAT(conn, smb_fname_src);
7169 create_options = 0;
7171 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7172 create_options |= FILE_DIRECTORY_FILE;
7175 status = SMB_VFS_CREATE_FILE(
7176 conn, /* conn */
7177 req, /* req */
7178 0, /* root_dir_fid */
7179 smb_fname_src, /* fname */
7180 access_mask, /* access_mask */
7181 (FILE_SHARE_READ | /* share_access */
7182 FILE_SHARE_WRITE),
7183 FILE_OPEN, /* create_disposition*/
7184 create_options, /* create_options */
7185 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7186 0, /* oplock_request */
7187 NULL, /* lease */
7188 0, /* allocation_size */
7189 0, /* private_flags */
7190 NULL, /* sd */
7191 NULL, /* ea_list */
7192 &fsp, /* result */
7193 NULL, /* pinfo */
7194 NULL, NULL); /* create context */
7196 if (!NT_STATUS_IS_OK(status)) {
7197 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7198 "returned %s rename %s -> %s\n",
7199 nt_errstr(status),
7200 smb_fname_str_dbg(smb_fname_src),
7201 smb_fname_str_dbg(smb_fname_dst)));
7202 break;
7205 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7206 dname);
7207 if (!smb_fname_dst->original_lcomp) {
7208 status = NT_STATUS_NO_MEMORY;
7209 goto out;
7212 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7213 attrs, replace_if_exists);
7215 close_file(req, fsp, NORMAL_CLOSE);
7217 if (!NT_STATUS_IS_OK(status)) {
7218 DEBUG(3, ("rename_internals_fsp returned %s for "
7219 "rename %s -> %s\n", nt_errstr(status),
7220 smb_fname_str_dbg(smb_fname_src),
7221 smb_fname_str_dbg(smb_fname_dst)));
7222 break;
7225 count++;
7227 DEBUG(3,("rename_internals: doing rename on %s -> "
7228 "%s\n", smb_fname_str_dbg(smb_fname_src),
7229 smb_fname_str_dbg(smb_fname_src)));
7230 TALLOC_FREE(talloced);
7232 TALLOC_FREE(dir_hnd);
7234 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7235 status = map_nt_error_from_unix(errno);
7238 out:
7239 TALLOC_FREE(talloced);
7240 TALLOC_FREE(smb_fname_src_dir);
7241 TALLOC_FREE(fname_src_dir);
7242 TALLOC_FREE(fname_src_mask);
7243 return status;
7246 /****************************************************************************
7247 Reply to a mv.
7248 ****************************************************************************/
7250 void reply_mv(struct smb_request *req)
7252 connection_struct *conn = req->conn;
7253 char *name = NULL;
7254 char *newname = NULL;
7255 const char *p;
7256 uint32_t attrs;
7257 NTSTATUS status;
7258 bool src_has_wcard = False;
7259 bool dest_has_wcard = False;
7260 TALLOC_CTX *ctx = talloc_tos();
7261 struct smb_filename *smb_fname_src = NULL;
7262 struct smb_filename *smb_fname_dst = NULL;
7263 uint32_t src_ucf_flags = (req->posix_pathnames ?
7264 (UCF_UNIX_NAME_LOOKUP|UCF_POSIX_PATHNAMES) :
7265 UCF_COND_ALLOW_WCARD_LCOMP);
7266 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP |
7267 (req->posix_pathnames ? UCF_POSIX_PATHNAMES :
7268 UCF_COND_ALLOW_WCARD_LCOMP);
7269 bool stream_rename = false;
7271 START_PROFILE(SMBmv);
7273 if (req->wct < 1) {
7274 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7275 goto out;
7278 attrs = SVAL(req->vwv+0, 0);
7280 p = (const char *)req->buf + 1;
7281 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7282 &status, &src_has_wcard);
7283 if (!NT_STATUS_IS_OK(status)) {
7284 reply_nterror(req, status);
7285 goto out;
7287 p++;
7288 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7289 &status, &dest_has_wcard);
7290 if (!NT_STATUS_IS_OK(status)) {
7291 reply_nterror(req, status);
7292 goto out;
7295 if (!req->posix_pathnames) {
7296 /* The newname must begin with a ':' if the
7297 name contains a ':'. */
7298 if (strchr_m(name, ':')) {
7299 if (newname[0] != ':') {
7300 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7301 goto out;
7303 stream_rename = true;
7307 status = filename_convert(ctx,
7308 conn,
7309 req->flags2 & FLAGS2_DFS_PATHNAMES,
7310 name,
7311 src_ucf_flags,
7312 &src_has_wcard,
7313 &smb_fname_src);
7315 if (!NT_STATUS_IS_OK(status)) {
7316 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7317 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7318 ERRSRV, ERRbadpath);
7319 goto out;
7321 reply_nterror(req, status);
7322 goto out;
7325 status = filename_convert(ctx,
7326 conn,
7327 req->flags2 & FLAGS2_DFS_PATHNAMES,
7328 newname,
7329 dst_ucf_flags,
7330 &dest_has_wcard,
7331 &smb_fname_dst);
7333 if (!NT_STATUS_IS_OK(status)) {
7334 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7335 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7336 ERRSRV, ERRbadpath);
7337 goto out;
7339 reply_nterror(req, status);
7340 goto out;
7343 if (stream_rename) {
7344 /* smb_fname_dst->base_name must be the same as
7345 smb_fname_src->base_name. */
7346 TALLOC_FREE(smb_fname_dst->base_name);
7347 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7348 smb_fname_src->base_name);
7349 if (!smb_fname_dst->base_name) {
7350 reply_nterror(req, NT_STATUS_NO_MEMORY);
7351 goto out;
7355 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7356 smb_fname_str_dbg(smb_fname_dst)));
7358 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7359 attrs, False, src_has_wcard, dest_has_wcard,
7360 DELETE_ACCESS);
7361 if (!NT_STATUS_IS_OK(status)) {
7362 if (open_was_deferred(req->xconn, req->mid)) {
7363 /* We have re-scheduled this call. */
7364 goto out;
7366 reply_nterror(req, status);
7367 goto out;
7370 reply_outbuf(req, 0, 0);
7371 out:
7372 TALLOC_FREE(smb_fname_src);
7373 TALLOC_FREE(smb_fname_dst);
7374 END_PROFILE(SMBmv);
7375 return;
7378 /*******************************************************************
7379 Copy a file as part of a reply_copy.
7380 ******************************************************************/
7383 * TODO: check error codes on all callers
7386 NTSTATUS copy_file(TALLOC_CTX *ctx,
7387 connection_struct *conn,
7388 struct smb_filename *smb_fname_src,
7389 struct smb_filename *smb_fname_dst,
7390 int ofun,
7391 int count,
7392 bool target_is_directory)
7394 struct smb_filename *smb_fname_dst_tmp = NULL;
7395 off_t ret=-1;
7396 files_struct *fsp1,*fsp2;
7397 uint32_t dosattrs;
7398 uint32_t new_create_disposition;
7399 NTSTATUS status;
7402 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7403 if (smb_fname_dst_tmp == NULL) {
7404 return NT_STATUS_NO_MEMORY;
7408 * If the target is a directory, extract the last component from the
7409 * src filename and append it to the dst filename
7411 if (target_is_directory) {
7412 const char *p;
7414 /* dest/target can't be a stream if it's a directory. */
7415 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7417 p = strrchr_m(smb_fname_src->base_name,'/');
7418 if (p) {
7419 p++;
7420 } else {
7421 p = smb_fname_src->base_name;
7423 smb_fname_dst_tmp->base_name =
7424 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7426 if (!smb_fname_dst_tmp->base_name) {
7427 status = NT_STATUS_NO_MEMORY;
7428 goto out;
7432 status = vfs_file_exist(conn, smb_fname_src);
7433 if (!NT_STATUS_IS_OK(status)) {
7434 goto out;
7437 if (!target_is_directory && count) {
7438 new_create_disposition = FILE_OPEN;
7439 } else {
7440 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7441 0, ofun,
7442 NULL, NULL,
7443 &new_create_disposition,
7444 NULL,
7445 NULL)) {
7446 status = NT_STATUS_INVALID_PARAMETER;
7447 goto out;
7451 /* Open the src file for reading. */
7452 status = SMB_VFS_CREATE_FILE(
7453 conn, /* conn */
7454 NULL, /* req */
7455 0, /* root_dir_fid */
7456 smb_fname_src, /* fname */
7457 FILE_GENERIC_READ, /* access_mask */
7458 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7459 FILE_OPEN, /* create_disposition*/
7460 0, /* create_options */
7461 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7462 INTERNAL_OPEN_ONLY, /* oplock_request */
7463 NULL, /* lease */
7464 0, /* allocation_size */
7465 0, /* private_flags */
7466 NULL, /* sd */
7467 NULL, /* ea_list */
7468 &fsp1, /* result */
7469 NULL, /* psbuf */
7470 NULL, NULL); /* create context */
7472 if (!NT_STATUS_IS_OK(status)) {
7473 goto out;
7476 dosattrs = dos_mode(conn, smb_fname_src);
7478 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7479 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7482 /* Open the dst file for writing. */
7483 status = SMB_VFS_CREATE_FILE(
7484 conn, /* conn */
7485 NULL, /* req */
7486 0, /* root_dir_fid */
7487 smb_fname_dst, /* fname */
7488 FILE_GENERIC_WRITE, /* access_mask */
7489 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7490 new_create_disposition, /* create_disposition*/
7491 0, /* create_options */
7492 dosattrs, /* file_attributes */
7493 INTERNAL_OPEN_ONLY, /* oplock_request */
7494 NULL, /* lease */
7495 0, /* allocation_size */
7496 0, /* private_flags */
7497 NULL, /* sd */
7498 NULL, /* ea_list */
7499 &fsp2, /* result */
7500 NULL, /* psbuf */
7501 NULL, NULL); /* create context */
7503 if (!NT_STATUS_IS_OK(status)) {
7504 close_file(NULL, fsp1, ERROR_CLOSE);
7505 goto out;
7508 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7509 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7510 if (ret == -1) {
7511 DEBUG(0, ("error - vfs lseek returned error %s\n",
7512 strerror(errno)));
7513 status = map_nt_error_from_unix(errno);
7514 close_file(NULL, fsp1, ERROR_CLOSE);
7515 close_file(NULL, fsp2, ERROR_CLOSE);
7516 goto out;
7520 /* Do the actual copy. */
7521 if (smb_fname_src->st.st_ex_size) {
7522 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7523 } else {
7524 ret = 0;
7527 close_file(NULL, fsp1, NORMAL_CLOSE);
7529 /* Ensure the modtime is set correctly on the destination file. */
7530 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7533 * As we are opening fsp1 read-only we only expect
7534 * an error on close on fsp2 if we are out of space.
7535 * Thus we don't look at the error return from the
7536 * close of fsp1.
7538 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7540 if (!NT_STATUS_IS_OK(status)) {
7541 goto out;
7544 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7545 status = NT_STATUS_DISK_FULL;
7546 goto out;
7549 status = NT_STATUS_OK;
7551 out:
7552 TALLOC_FREE(smb_fname_dst_tmp);
7553 return status;
7556 /****************************************************************************
7557 Reply to a file copy.
7558 ****************************************************************************/
7560 void reply_copy(struct smb_request *req)
7562 connection_struct *conn = req->conn;
7563 struct smb_filename *smb_fname_src = NULL;
7564 struct smb_filename *smb_fname_src_dir = NULL;
7565 struct smb_filename *smb_fname_dst = NULL;
7566 char *fname_src = NULL;
7567 char *fname_dst = NULL;
7568 char *fname_src_mask = NULL;
7569 char *fname_src_dir = NULL;
7570 const char *p;
7571 int count=0;
7572 int error = ERRnoaccess;
7573 int tid2;
7574 int ofun;
7575 int flags;
7576 bool target_is_directory=False;
7577 bool source_has_wild = False;
7578 bool dest_has_wild = False;
7579 NTSTATUS status;
7580 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7581 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
7582 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7583 (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
7584 TALLOC_CTX *ctx = talloc_tos();
7586 START_PROFILE(SMBcopy);
7588 if (req->wct < 3) {
7589 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7590 goto out;
7593 tid2 = SVAL(req->vwv+0, 0);
7594 ofun = SVAL(req->vwv+1, 0);
7595 flags = SVAL(req->vwv+2, 0);
7597 p = (const char *)req->buf;
7598 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7599 &status, &source_has_wild);
7600 if (!NT_STATUS_IS_OK(status)) {
7601 reply_nterror(req, status);
7602 goto out;
7604 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7605 &status, &dest_has_wild);
7606 if (!NT_STATUS_IS_OK(status)) {
7607 reply_nterror(req, status);
7608 goto out;
7611 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7613 if (tid2 != conn->cnum) {
7614 /* can't currently handle inter share copies XXXX */
7615 DEBUG(3,("Rejecting inter-share copy\n"));
7616 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7617 goto out;
7620 status = filename_convert(ctx, conn,
7621 req->flags2 & FLAGS2_DFS_PATHNAMES,
7622 fname_src,
7623 ucf_flags_src,
7624 &source_has_wild,
7625 &smb_fname_src);
7626 if (!NT_STATUS_IS_OK(status)) {
7627 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7628 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7629 ERRSRV, ERRbadpath);
7630 goto out;
7632 reply_nterror(req, status);
7633 goto out;
7636 status = filename_convert(ctx, conn,
7637 req->flags2 & FLAGS2_DFS_PATHNAMES,
7638 fname_dst,
7639 ucf_flags_dst,
7640 &dest_has_wild,
7641 &smb_fname_dst);
7642 if (!NT_STATUS_IS_OK(status)) {
7643 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7644 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7645 ERRSRV, ERRbadpath);
7646 goto out;
7648 reply_nterror(req, status);
7649 goto out;
7652 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7654 if ((flags&1) && target_is_directory) {
7655 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7656 goto out;
7659 if ((flags&2) && !target_is_directory) {
7660 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7661 goto out;
7664 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7665 /* wants a tree copy! XXXX */
7666 DEBUG(3,("Rejecting tree copy\n"));
7667 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7668 goto out;
7671 /* Split up the directory from the filename/mask. */
7672 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7673 &fname_src_dir, &fname_src_mask);
7674 if (!NT_STATUS_IS_OK(status)) {
7675 reply_nterror(req, NT_STATUS_NO_MEMORY);
7676 goto out;
7680 * We should only check the mangled cache
7681 * here if unix_convert failed. This means
7682 * that the path in 'mask' doesn't exist
7683 * on the file system and so we need to look
7684 * for a possible mangle. This patch from
7685 * Tine Smukavec <valentin.smukavec@hermes.si>.
7687 if (!VALID_STAT(smb_fname_src->st) &&
7688 mangle_is_mangled(fname_src_mask, conn->params)) {
7689 char *new_mask = NULL;
7690 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7691 &new_mask, conn->params);
7693 /* Use demangled name if one was successfully found. */
7694 if (new_mask) {
7695 TALLOC_FREE(fname_src_mask);
7696 fname_src_mask = new_mask;
7700 if (!source_has_wild) {
7703 * Only one file needs to be copied. Append the mask back onto
7704 * the directory.
7706 TALLOC_FREE(smb_fname_src->base_name);
7707 if (ISDOT(fname_src_dir)) {
7708 /* Ensure we use canonical names on open. */
7709 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7710 "%s",
7711 fname_src_mask);
7712 } else {
7713 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7714 "%s/%s",
7715 fname_src_dir,
7716 fname_src_mask);
7718 if (!smb_fname_src->base_name) {
7719 reply_nterror(req, NT_STATUS_NO_MEMORY);
7720 goto out;
7723 if (dest_has_wild) {
7724 char *fname_dst_mod = NULL;
7725 if (!resolve_wildcards(smb_fname_dst,
7726 smb_fname_src->base_name,
7727 smb_fname_dst->base_name,
7728 &fname_dst_mod)) {
7729 reply_nterror(req, NT_STATUS_NO_MEMORY);
7730 goto out;
7732 TALLOC_FREE(smb_fname_dst->base_name);
7733 smb_fname_dst->base_name = fname_dst_mod;
7736 status = check_name(conn, smb_fname_src->base_name);
7737 if (!NT_STATUS_IS_OK(status)) {
7738 reply_nterror(req, status);
7739 goto out;
7742 status = check_name(conn, smb_fname_dst->base_name);
7743 if (!NT_STATUS_IS_OK(status)) {
7744 reply_nterror(req, status);
7745 goto out;
7748 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7749 ofun, count, target_is_directory);
7751 if(!NT_STATUS_IS_OK(status)) {
7752 reply_nterror(req, status);
7753 goto out;
7754 } else {
7755 count++;
7757 } else {
7758 struct smb_Dir *dir_hnd = NULL;
7759 const char *dname = NULL;
7760 char *talloced = NULL;
7761 long offset = 0;
7764 * There is a wildcard that requires us to actually read the
7765 * src dir and copy each file matching the mask to the dst.
7766 * Right now streams won't be copied, but this could
7767 * presumably be added with a nested loop for reach dir entry.
7769 SMB_ASSERT(!smb_fname_src->stream_name);
7770 SMB_ASSERT(!smb_fname_dst->stream_name);
7772 smb_fname_src->stream_name = NULL;
7773 smb_fname_dst->stream_name = NULL;
7775 if (strequal(fname_src_mask,"????????.???")) {
7776 TALLOC_FREE(fname_src_mask);
7777 fname_src_mask = talloc_strdup(ctx, "*");
7778 if (!fname_src_mask) {
7779 reply_nterror(req, NT_STATUS_NO_MEMORY);
7780 goto out;
7784 status = check_name(conn, fname_src_dir);
7785 if (!NT_STATUS_IS_OK(status)) {
7786 reply_nterror(req, status);
7787 goto out;
7790 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7791 fname_src_dir,
7792 NULL,
7793 NULL,
7794 smb_fname_src->flags);
7795 if (smb_fname_src_dir == NULL) {
7796 reply_nterror(req, NT_STATUS_NO_MEMORY);
7797 goto out;
7800 dir_hnd = OpenDir(ctx,
7801 conn,
7802 smb_fname_src_dir,
7803 fname_src_mask,
7805 if (dir_hnd == NULL) {
7806 status = map_nt_error_from_unix(errno);
7807 reply_nterror(req, status);
7808 goto out;
7811 error = ERRbadfile;
7813 /* Iterate over the src dir copying each entry to the dst. */
7814 while ((dname = ReadDirName(dir_hnd, &offset,
7815 &smb_fname_src->st, &talloced))) {
7816 char *destname = NULL;
7818 if (ISDOT(dname) || ISDOTDOT(dname)) {
7819 TALLOC_FREE(talloced);
7820 continue;
7823 if (!is_visible_file(conn, fname_src_dir, dname,
7824 &smb_fname_src->st, false)) {
7825 TALLOC_FREE(talloced);
7826 continue;
7829 if(!mask_match(dname, fname_src_mask,
7830 conn->case_sensitive)) {
7831 TALLOC_FREE(talloced);
7832 continue;
7835 error = ERRnoaccess;
7837 /* Get the src smb_fname struct setup. */
7838 TALLOC_FREE(smb_fname_src->base_name);
7839 if (ISDOT(fname_src_dir)) {
7840 /* Ensure we use canonical names on open. */
7841 smb_fname_src->base_name =
7842 talloc_asprintf(smb_fname_src, "%s",
7843 dname);
7844 } else {
7845 smb_fname_src->base_name =
7846 talloc_asprintf(smb_fname_src, "%s/%s",
7847 fname_src_dir, dname);
7850 if (!smb_fname_src->base_name) {
7851 TALLOC_FREE(dir_hnd);
7852 TALLOC_FREE(talloced);
7853 reply_nterror(req, NT_STATUS_NO_MEMORY);
7854 goto out;
7857 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7858 smb_fname_dst->base_name,
7859 &destname)) {
7860 TALLOC_FREE(talloced);
7861 continue;
7863 if (!destname) {
7864 TALLOC_FREE(dir_hnd);
7865 TALLOC_FREE(talloced);
7866 reply_nterror(req, NT_STATUS_NO_MEMORY);
7867 goto out;
7870 TALLOC_FREE(smb_fname_dst->base_name);
7871 smb_fname_dst->base_name = destname;
7873 status = check_name(conn, smb_fname_src->base_name);
7874 if (!NT_STATUS_IS_OK(status)) {
7875 TALLOC_FREE(dir_hnd);
7876 TALLOC_FREE(talloced);
7877 reply_nterror(req, status);
7878 goto out;
7881 status = check_name(conn, smb_fname_dst->base_name);
7882 if (!NT_STATUS_IS_OK(status)) {
7883 TALLOC_FREE(dir_hnd);
7884 TALLOC_FREE(talloced);
7885 reply_nterror(req, status);
7886 goto out;
7889 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7890 smb_fname_src->base_name,
7891 smb_fname_dst->base_name));
7893 status = copy_file(ctx, conn, smb_fname_src,
7894 smb_fname_dst, ofun, count,
7895 target_is_directory);
7896 if (NT_STATUS_IS_OK(status)) {
7897 count++;
7900 TALLOC_FREE(talloced);
7902 TALLOC_FREE(dir_hnd);
7905 if (count == 0) {
7906 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7907 goto out;
7910 reply_outbuf(req, 1, 0);
7911 SSVAL(req->outbuf,smb_vwv0,count);
7912 out:
7913 TALLOC_FREE(smb_fname_src);
7914 TALLOC_FREE(smb_fname_src_dir);
7915 TALLOC_FREE(smb_fname_dst);
7916 TALLOC_FREE(fname_src);
7917 TALLOC_FREE(fname_dst);
7918 TALLOC_FREE(fname_src_mask);
7919 TALLOC_FREE(fname_src_dir);
7921 END_PROFILE(SMBcopy);
7922 return;
7925 #undef DBGC_CLASS
7926 #define DBGC_CLASS DBGC_LOCKING
7928 /****************************************************************************
7929 Get a lock pid, dealing with large count requests.
7930 ****************************************************************************/
7932 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7933 bool large_file_format)
7935 if(!large_file_format)
7936 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7937 else
7938 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7941 /****************************************************************************
7942 Get a lock count, dealing with large count requests.
7943 ****************************************************************************/
7945 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7946 bool large_file_format)
7948 uint64_t count = 0;
7950 if(!large_file_format) {
7951 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7952 } else {
7954 * No BVAL, this is reversed!
7956 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7957 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7960 return count;
7963 /****************************************************************************
7964 Get a lock offset, dealing with large offset requests.
7965 ****************************************************************************/
7967 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7968 bool large_file_format)
7970 uint64_t offset = 0;
7972 if(!large_file_format) {
7973 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7974 } else {
7976 * No BVAL, this is reversed!
7978 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7979 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7982 return offset;
7985 NTSTATUS smbd_do_locking(struct smb_request *req,
7986 files_struct *fsp,
7987 uint8_t type,
7988 int32_t timeout,
7989 uint16_t num_locks,
7990 struct smbd_lock_element *locks,
7991 bool *async)
7993 connection_struct *conn = req->conn;
7994 int i;
7995 NTSTATUS status = NT_STATUS_OK;
7997 *async = false;
7999 /* Setup the timeout in seconds. */
8001 if (!lp_blocking_locks(SNUM(conn))) {
8002 timeout = 0;
8005 for(i = 0; i < (int)num_locks; i++) {
8006 struct smbd_lock_element *e = &locks[i];
8008 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8009 "%llu, file %s timeout = %d\n",
8010 (double)e->offset,
8011 (double)e->count,
8012 (unsigned long long)e->smblctx,
8013 fsp_str_dbg(fsp),
8014 (int)timeout));
8016 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8017 struct blocking_lock_record *blr = NULL;
8019 if (num_locks > 1) {
8021 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8022 * if the lock vector contains one entry. When given multiple cancel
8023 * requests in a single PDU we expect the server to return an
8024 * error. Windows servers seem to accept the request but only
8025 * cancel the first lock.
8026 * JRA - Do what Windows does (tm) :-).
8029 #if 0
8030 /* MS-CIFS (2.2.4.32.1) behavior. */
8031 return NT_STATUS_DOS(ERRDOS,
8032 ERRcancelviolation);
8033 #else
8034 /* Windows behavior. */
8035 if (i != 0) {
8036 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8037 "cancel request\n"));
8038 continue;
8040 #endif
8043 if (lp_blocking_locks(SNUM(conn))) {
8045 /* Schedule a message to ourselves to
8046 remove the blocking lock record and
8047 return the right error. */
8049 blr = blocking_lock_cancel_smb1(fsp,
8050 e->smblctx,
8051 e->offset,
8052 e->count,
8053 WINDOWS_LOCK,
8054 type,
8055 NT_STATUS_FILE_LOCK_CONFLICT);
8056 if (blr == NULL) {
8057 return NT_STATUS_DOS(
8058 ERRDOS,
8059 ERRcancelviolation);
8062 /* Remove a matching pending lock. */
8063 status = do_lock_cancel(fsp,
8064 e->smblctx,
8065 e->count,
8066 e->offset,
8067 WINDOWS_LOCK);
8068 } else {
8069 bool blocking_lock = timeout ? true : false;
8070 bool defer_lock = false;
8071 struct byte_range_lock *br_lck;
8072 uint64_t block_smblctx;
8074 br_lck = do_lock(req->sconn->msg_ctx,
8075 fsp,
8076 e->smblctx,
8077 e->count,
8078 e->offset,
8079 e->brltype,
8080 WINDOWS_LOCK,
8081 blocking_lock,
8082 &status,
8083 &block_smblctx);
8085 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8086 /* Windows internal resolution for blocking locks seems
8087 to be about 200ms... Don't wait for less than that. JRA. */
8088 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8089 timeout = lp_lock_spin_time();
8091 defer_lock = true;
8094 /* If a lock sent with timeout of zero would fail, and
8095 * this lock has been requested multiple times,
8096 * according to brl_lock_failed() we convert this
8097 * request to a blocking lock with a timeout of between
8098 * 150 - 300 milliseconds.
8100 * If lp_lock_spin_time() has been set to 0, we skip
8101 * this blocking retry and fail immediately.
8103 * Replacement for do_lock_spin(). JRA. */
8105 if (!req->sconn->using_smb2 &&
8106 br_lck && lp_blocking_locks(SNUM(conn)) &&
8107 lp_lock_spin_time() && !blocking_lock &&
8108 NT_STATUS_EQUAL((status),
8109 NT_STATUS_FILE_LOCK_CONFLICT))
8111 defer_lock = true;
8112 timeout = lp_lock_spin_time();
8115 if (br_lck && defer_lock) {
8117 * A blocking lock was requested. Package up
8118 * this smb into a queued request and push it
8119 * onto the blocking lock queue.
8121 if(push_blocking_lock_request(br_lck,
8122 req,
8123 fsp,
8124 timeout,
8126 e->smblctx,
8127 e->brltype,
8128 WINDOWS_LOCK,
8129 e->offset,
8130 e->count,
8131 block_smblctx)) {
8132 TALLOC_FREE(br_lck);
8133 *async = true;
8134 return NT_STATUS_OK;
8138 TALLOC_FREE(br_lck);
8141 if (!NT_STATUS_IS_OK(status)) {
8142 break;
8146 /* If any of the above locks failed, then we must unlock
8147 all of the previous locks (X/Open spec). */
8149 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8151 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8152 i = -1; /* we want to skip the for loop */
8156 * Ensure we don't do a remove on the lock that just failed,
8157 * as under POSIX rules, if we have a lock already there, we
8158 * will delete it (and we shouldn't) .....
8160 for(i--; i >= 0; i--) {
8161 struct smbd_lock_element *e = &locks[i];
8163 do_unlock(req->sconn->msg_ctx,
8164 fsp,
8165 e->smblctx,
8166 e->count,
8167 e->offset,
8168 WINDOWS_LOCK);
8170 return status;
8173 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8174 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8176 return NT_STATUS_OK;
8179 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8180 files_struct *fsp,
8181 uint16_t num_ulocks,
8182 struct smbd_lock_element *ulocks)
8184 int i;
8186 for(i = 0; i < (int)num_ulocks; i++) {
8187 struct smbd_lock_element *e = &ulocks[i];
8188 NTSTATUS status;
8190 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8191 "pid %u, file %s\n", __func__,
8192 (double)e->offset,
8193 (double)e->count,
8194 (unsigned int)e->smblctx,
8195 fsp_str_dbg(fsp)));
8197 if (e->brltype != UNLOCK_LOCK) {
8198 /* this can only happen with SMB2 */
8199 return NT_STATUS_INVALID_PARAMETER;
8202 status = do_unlock(req->sconn->msg_ctx,
8203 fsp,
8204 e->smblctx,
8205 e->count,
8206 e->offset,
8207 WINDOWS_LOCK);
8209 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8210 nt_errstr(status)));
8212 if (!NT_STATUS_IS_OK(status)) {
8213 return status;
8217 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8218 num_ulocks));
8220 return NT_STATUS_OK;
8223 /****************************************************************************
8224 Reply to a lockingX request.
8225 ****************************************************************************/
8227 void reply_lockingX(struct smb_request *req)
8229 connection_struct *conn = req->conn;
8230 files_struct *fsp;
8231 unsigned char locktype;
8232 unsigned char oplocklevel;
8233 uint16_t num_ulocks;
8234 uint16_t num_locks;
8235 int32_t lock_timeout;
8236 int i;
8237 const uint8_t *data;
8238 bool large_file_format;
8239 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8240 struct smbd_lock_element *ulocks;
8241 struct smbd_lock_element *locks;
8242 bool async = false;
8244 START_PROFILE(SMBlockingX);
8246 if (req->wct < 8) {
8247 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8248 END_PROFILE(SMBlockingX);
8249 return;
8252 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8253 locktype = CVAL(req->vwv+3, 0);
8254 oplocklevel = CVAL(req->vwv+3, 1);
8255 num_ulocks = SVAL(req->vwv+6, 0);
8256 num_locks = SVAL(req->vwv+7, 0);
8257 lock_timeout = IVAL(req->vwv+4, 0);
8258 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8260 if (!check_fsp(conn, req, fsp)) {
8261 END_PROFILE(SMBlockingX);
8262 return;
8265 data = req->buf;
8267 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8268 /* we don't support these - and CANCEL_LOCK makes w2k
8269 and XP reboot so I don't really want to be
8270 compatible! (tridge) */
8271 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8272 END_PROFILE(SMBlockingX);
8273 return;
8276 /* Check if this is an oplock break on a file
8277 we have granted an oplock on.
8279 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8280 /* Client can insist on breaking to none. */
8281 bool break_to_none = (oplocklevel == 0);
8282 bool result;
8284 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8285 "for %s\n", (unsigned int)oplocklevel,
8286 fsp_fnum_dbg(fsp)));
8289 * Make sure we have granted an exclusive or batch oplock on
8290 * this file.
8293 if (fsp->oplock_type == 0) {
8295 /* The Samba4 nbench simulator doesn't understand
8296 the difference between break to level2 and break
8297 to none from level2 - it sends oplock break
8298 replies in both cases. Don't keep logging an error
8299 message here - just ignore it. JRA. */
8301 DEBUG(5,("reply_lockingX: Error : oplock break from "
8302 "client for %s (oplock=%d) and no "
8303 "oplock granted on this file (%s).\n",
8304 fsp_fnum_dbg(fsp), fsp->oplock_type,
8305 fsp_str_dbg(fsp)));
8307 /* if this is a pure oplock break request then don't
8308 * send a reply */
8309 if (num_locks == 0 && num_ulocks == 0) {
8310 END_PROFILE(SMBlockingX);
8311 return;
8312 } else {
8313 END_PROFILE(SMBlockingX);
8314 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8315 return;
8319 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8320 (break_to_none)) {
8321 result = remove_oplock(fsp);
8322 } else {
8323 result = downgrade_oplock(fsp);
8326 if (!result) {
8327 DEBUG(0, ("reply_lockingX: error in removing "
8328 "oplock on file %s\n", fsp_str_dbg(fsp)));
8329 /* Hmmm. Is this panic justified? */
8330 smb_panic("internal tdb error");
8333 /* if this is a pure oplock break request then don't send a
8334 * reply */
8335 if (num_locks == 0 && num_ulocks == 0) {
8336 /* Sanity check - ensure a pure oplock break is not a
8337 chained request. */
8338 if (CVAL(req->vwv+0, 0) != 0xff) {
8339 DEBUG(0,("reply_lockingX: Error : pure oplock "
8340 "break is a chained %d request !\n",
8341 (unsigned int)CVAL(req->vwv+0, 0)));
8343 END_PROFILE(SMBlockingX);
8344 return;
8348 if (req->buflen <
8349 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8350 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8351 END_PROFILE(SMBlockingX);
8352 return;
8355 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8356 if (ulocks == NULL) {
8357 reply_nterror(req, NT_STATUS_NO_MEMORY);
8358 END_PROFILE(SMBlockingX);
8359 return;
8362 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8363 if (locks == NULL) {
8364 reply_nterror(req, NT_STATUS_NO_MEMORY);
8365 END_PROFILE(SMBlockingX);
8366 return;
8369 /* Data now points at the beginning of the list
8370 of smb_unlkrng structs */
8371 for(i = 0; i < (int)num_ulocks; i++) {
8372 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8373 ulocks[i].count = get_lock_count(data, i, large_file_format);
8374 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8375 ulocks[i].brltype = UNLOCK_LOCK;
8378 /* Now do any requested locks */
8379 data += ((large_file_format ? 20 : 10)*num_ulocks);
8381 /* Data now points at the beginning of the list
8382 of smb_lkrng structs */
8384 for(i = 0; i < (int)num_locks; i++) {
8385 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8386 locks[i].count = get_lock_count(data, i, large_file_format);
8387 locks[i].offset = get_lock_offset(data, i, large_file_format);
8389 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8390 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8391 locks[i].brltype = PENDING_READ_LOCK;
8392 } else {
8393 locks[i].brltype = READ_LOCK;
8395 } else {
8396 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8397 locks[i].brltype = PENDING_WRITE_LOCK;
8398 } else {
8399 locks[i].brltype = WRITE_LOCK;
8404 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8405 if (!NT_STATUS_IS_OK(status)) {
8406 END_PROFILE(SMBlockingX);
8407 reply_nterror(req, status);
8408 return;
8411 status = smbd_do_locking(req, fsp,
8412 locktype, lock_timeout,
8413 num_locks, locks,
8414 &async);
8415 if (!NT_STATUS_IS_OK(status)) {
8416 END_PROFILE(SMBlockingX);
8417 reply_nterror(req, status);
8418 return;
8420 if (async) {
8421 END_PROFILE(SMBlockingX);
8422 return;
8425 reply_outbuf(req, 2, 0);
8426 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8427 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8429 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8430 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8432 END_PROFILE(SMBlockingX);
8435 #undef DBGC_CLASS
8436 #define DBGC_CLASS DBGC_ALL
8438 /****************************************************************************
8439 Reply to a SMBreadbmpx (read block multiplex) request.
8440 Always reply with an error, if someone has a platform really needs this,
8441 please contact vl@samba.org
8442 ****************************************************************************/
8444 void reply_readbmpx(struct smb_request *req)
8446 START_PROFILE(SMBreadBmpx);
8447 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8448 END_PROFILE(SMBreadBmpx);
8449 return;
8452 /****************************************************************************
8453 Reply to a SMBreadbs (read block multiplex secondary) request.
8454 Always reply with an error, if someone has a platform really needs this,
8455 please contact vl@samba.org
8456 ****************************************************************************/
8458 void reply_readbs(struct smb_request *req)
8460 START_PROFILE(SMBreadBs);
8461 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8462 END_PROFILE(SMBreadBs);
8463 return;
8466 /****************************************************************************
8467 Reply to a SMBsetattrE.
8468 ****************************************************************************/
8470 void reply_setattrE(struct smb_request *req)
8472 connection_struct *conn = req->conn;
8473 struct smb_file_time ft;
8474 files_struct *fsp;
8475 NTSTATUS status;
8477 START_PROFILE(SMBsetattrE);
8478 ZERO_STRUCT(ft);
8480 if (req->wct < 7) {
8481 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8482 goto out;
8485 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8487 if(!fsp || (fsp->conn != conn)) {
8488 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8489 goto out;
8493 * Convert the DOS times into unix times.
8496 ft.atime = convert_time_t_to_timespec(
8497 srv_make_unix_date2(req->vwv+3));
8498 ft.mtime = convert_time_t_to_timespec(
8499 srv_make_unix_date2(req->vwv+5));
8500 ft.create_time = convert_time_t_to_timespec(
8501 srv_make_unix_date2(req->vwv+1));
8503 reply_outbuf(req, 0, 0);
8506 * Patch from Ray Frush <frush@engr.colostate.edu>
8507 * Sometimes times are sent as zero - ignore them.
8510 /* Ensure we have a valid stat struct for the source. */
8511 status = vfs_stat_fsp(fsp);
8512 if (!NT_STATUS_IS_OK(status)) {
8513 reply_nterror(req, status);
8514 goto out;
8517 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8518 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8519 goto out;
8522 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8523 if (!NT_STATUS_IS_OK(status)) {
8524 reply_nterror(req, status);
8525 goto out;
8528 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8529 " createtime=%u\n",
8530 fsp_fnum_dbg(fsp),
8531 (unsigned int)ft.atime.tv_sec,
8532 (unsigned int)ft.mtime.tv_sec,
8533 (unsigned int)ft.create_time.tv_sec
8535 out:
8536 END_PROFILE(SMBsetattrE);
8537 return;
8541 /* Back from the dead for OS/2..... JRA. */
8543 /****************************************************************************
8544 Reply to a SMBwritebmpx (write block multiplex primary) 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_writebmpx(struct smb_request *req)
8551 START_PROFILE(SMBwriteBmpx);
8552 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8553 END_PROFILE(SMBwriteBmpx);
8554 return;
8557 /****************************************************************************
8558 Reply to a SMBwritebs (write block multiplex secondary) request.
8559 Always reply with an error, if someone has a platform really needs this,
8560 please contact vl@samba.org
8561 ****************************************************************************/
8563 void reply_writebs(struct smb_request *req)
8565 START_PROFILE(SMBwriteBs);
8566 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8567 END_PROFILE(SMBwriteBs);
8568 return;
8571 /****************************************************************************
8572 Reply to a SMBgetattrE.
8573 ****************************************************************************/
8575 void reply_getattrE(struct smb_request *req)
8577 connection_struct *conn = req->conn;
8578 int mode;
8579 files_struct *fsp;
8580 struct timespec create_ts;
8582 START_PROFILE(SMBgetattrE);
8584 if (req->wct < 1) {
8585 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8586 END_PROFILE(SMBgetattrE);
8587 return;
8590 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8592 if(!fsp || (fsp->conn != conn)) {
8593 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8594 END_PROFILE(SMBgetattrE);
8595 return;
8598 /* Do an fstat on this file */
8599 if(fsp_stat(fsp)) {
8600 reply_nterror(req, map_nt_error_from_unix(errno));
8601 END_PROFILE(SMBgetattrE);
8602 return;
8605 mode = dos_mode(conn, fsp->fsp_name);
8608 * Convert the times into dos times. Set create
8609 * date to be last modify date as UNIX doesn't save
8610 * this.
8613 reply_outbuf(req, 11, 0);
8615 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8616 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8617 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8618 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8619 /* Should we check pending modtime here ? JRA */
8620 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8621 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8623 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8624 SIVAL(req->outbuf, smb_vwv6, 0);
8625 SIVAL(req->outbuf, smb_vwv8, 0);
8626 } else {
8627 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8628 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8629 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8631 SSVAL(req->outbuf,smb_vwv10, mode);
8633 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8635 END_PROFILE(SMBgetattrE);
8636 return;