ldb:tests: Extend api.py testsuite to show transaction_commit() blocks against the...
[Samba.git] / source3 / smbd / reply.c
blobe430a8e2d0f00e181ac6c3a6e617253bb3780d53
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
46 #include "lib/util/sys_rw_data.h"
48 /****************************************************************************
49 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
50 path or anything including wildcards.
51 We're assuming here that '/' is not the second byte in any multibyte char
52 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
53 set.
54 ****************************************************************************/
56 /* Custom version for processing POSIX paths. */
57 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
59 static NTSTATUS check_path_syntax_internal(char *path,
60 bool posix_path,
61 bool *p_last_component_contains_wcard)
63 char *d = path;
64 const char *s = path;
65 NTSTATUS ret = NT_STATUS_OK;
66 bool start_of_name_component = True;
67 bool stream_started = false;
69 *p_last_component_contains_wcard = False;
71 while (*s) {
72 if (stream_started) {
73 switch (*s) {
74 case '/':
75 case '\\':
76 return NT_STATUS_OBJECT_NAME_INVALID;
77 case ':':
78 if (s[1] == '\0') {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 if (strchr_m(&s[1], ':')) {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 break;
88 if ((*s == ':') && !posix_path && !stream_started) {
89 if (*p_last_component_contains_wcard) {
90 return NT_STATUS_OBJECT_NAME_INVALID;
92 /* Stream names allow more characters than file names.
93 We're overloading posix_path here to allow a wider
94 range of characters. If stream_started is true this
95 is still a Windows path even if posix_path is true.
96 JRA.
98 stream_started = true;
99 start_of_name_component = false;
100 posix_path = true;
102 if (s[1] == '\0') {
103 return NT_STATUS_OBJECT_NAME_INVALID;
107 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
109 * Safe to assume is not the second part of a mb char
110 * as this is handled below.
112 /* Eat multiple '/' or '\\' */
113 while (IS_PATH_SEP(*s,posix_path)) {
114 s++;
116 if ((d != path) && (*s != '\0')) {
117 /* We only care about non-leading or trailing '/' or '\\' */
118 *d++ = '/';
121 start_of_name_component = True;
122 /* New component. */
123 *p_last_component_contains_wcard = False;
124 continue;
127 if (start_of_name_component) {
128 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
129 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
132 * No mb char starts with '.' so we're safe checking the directory separator here.
135 /* If we just added a '/' - delete it */
136 if ((d > path) && (*(d-1) == '/')) {
137 *(d-1) = '\0';
138 d--;
141 /* Are we at the start ? Can't go back further if so. */
142 if (d <= path) {
143 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
144 break;
146 /* Go back one level... */
147 /* We know this is safe as '/' cannot be part of a mb sequence. */
148 /* NOTE - if this assumption is invalid we are not in good shape... */
149 /* Decrement d first as d points to the *next* char to write into. */
150 for (d--; d > path; d--) {
151 if (*d == '/')
152 break;
154 s += 2; /* Else go past the .. */
155 /* We're still at the start of a name component, just the previous one. */
156 continue;
158 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
159 if (posix_path) {
160 /* Eat the '.' */
161 s++;
162 continue;
168 if (!(*s & 0x80)) {
169 if (!posix_path) {
170 if (*s <= 0x1f || *s == '|') {
171 return NT_STATUS_OBJECT_NAME_INVALID;
173 switch (*s) {
174 case '*':
175 case '?':
176 case '<':
177 case '>':
178 case '"':
179 *p_last_component_contains_wcard = True;
180 break;
181 default:
182 break;
185 *d++ = *s++;
186 } else {
187 size_t siz;
188 /* Get the size of the next MB character. */
189 next_codepoint(s,&siz);
190 switch(siz) {
191 case 5:
192 *d++ = *s++;
193 /*fall through*/
194 case 4:
195 *d++ = *s++;
196 /*fall through*/
197 case 3:
198 *d++ = *s++;
199 /*fall through*/
200 case 2:
201 *d++ = *s++;
202 /*fall through*/
203 case 1:
204 *d++ = *s++;
205 break;
206 default:
207 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
208 *d = '\0';
209 return NT_STATUS_INVALID_PARAMETER;
212 start_of_name_component = False;
215 *d = '\0';
217 return ret;
220 /****************************************************************************
221 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
222 No wildcards allowed.
223 ****************************************************************************/
225 NTSTATUS check_path_syntax(char *path)
227 bool ignore;
228 return check_path_syntax_internal(path, False, &ignore);
231 /****************************************************************************
232 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
233 Wildcards allowed - p_contains_wcard returns true if the last component contained
234 a wildcard.
235 ****************************************************************************/
237 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
239 return check_path_syntax_internal(path, False, p_contains_wcard);
242 /****************************************************************************
243 Check the path for a POSIX client.
244 We're assuming here that '/' is not the second byte in any multibyte char
245 set (a safe assumption).
246 ****************************************************************************/
248 NTSTATUS check_path_syntax_posix(char *path)
250 bool ignore;
251 return check_path_syntax_internal(path, True, &ignore);
254 /****************************************************************************
255 Pull a string and check the path allowing a wilcard - provide for error return.
256 Passes in posix flag.
257 ****************************************************************************/
259 static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
260 const char *base_ptr,
261 uint16_t smb_flags2,
262 char **pp_dest,
263 const char *src,
264 size_t src_len,
265 int flags,
266 bool posix_pathnames,
267 NTSTATUS *err,
268 bool *contains_wcard)
270 size_t ret;
272 *pp_dest = NULL;
274 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
275 src_len, flags);
277 if (!*pp_dest) {
278 *err = NT_STATUS_INVALID_PARAMETER;
279 return ret;
282 *contains_wcard = False;
284 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
286 * For a DFS path the function parse_dfs_path()
287 * will do the path processing, just make a copy.
289 *err = NT_STATUS_OK;
290 return ret;
293 if (posix_pathnames) {
294 *err = check_path_syntax_posix(*pp_dest);
295 } else {
296 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
299 return ret;
302 /****************************************************************************
303 Pull a string and check the path allowing a wilcard - provide for error return.
304 ****************************************************************************/
306 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
307 const char *base_ptr,
308 uint16_t smb_flags2,
309 char **pp_dest,
310 const char *src,
311 size_t src_len,
312 int flags,
313 NTSTATUS *err,
314 bool *contains_wcard)
316 return srvstr_get_path_wcard_internal(ctx,
317 base_ptr,
318 smb_flags2,
319 pp_dest,
320 src,
321 src_len,
322 flags,
323 false,
324 err,
325 contains_wcard);
328 /****************************************************************************
329 Pull a string and check the path allowing a wilcard - provide for error return.
330 posix_pathnames version.
331 ****************************************************************************/
333 size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
334 const char *base_ptr,
335 uint16_t smb_flags2,
336 char **pp_dest,
337 const char *src,
338 size_t src_len,
339 int flags,
340 NTSTATUS *err,
341 bool *contains_wcard)
343 return srvstr_get_path_wcard_internal(ctx,
344 base_ptr,
345 smb_flags2,
346 pp_dest,
347 src,
348 src_len,
349 flags,
350 true,
351 err,
352 contains_wcard);
355 /****************************************************************************
356 Pull a string and check the path - provide for error return.
357 ****************************************************************************/
359 size_t srvstr_get_path(TALLOC_CTX *ctx,
360 const char *base_ptr,
361 uint16_t smb_flags2,
362 char **pp_dest,
363 const char *src,
364 size_t src_len,
365 int flags,
366 NTSTATUS *err)
368 bool ignore;
369 return srvstr_get_path_wcard_internal(ctx,
370 base_ptr,
371 smb_flags2,
372 pp_dest,
373 src,
374 src_len,
375 flags,
376 false,
377 err,
378 &ignore);
381 /****************************************************************************
382 Pull a string and check the path - provide for error return.
383 posix_pathnames version.
384 ****************************************************************************/
386 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
387 const char *base_ptr,
388 uint16_t smb_flags2,
389 char **pp_dest,
390 const char *src,
391 size_t src_len,
392 int flags,
393 NTSTATUS *err)
395 bool ignore;
396 return srvstr_get_path_wcard_internal(ctx,
397 base_ptr,
398 smb_flags2,
399 pp_dest,
400 src,
401 src_len,
402 flags,
403 true,
404 err,
405 &ignore);
409 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
410 char **pp_dest, const char *src, int flags,
411 NTSTATUS *err, bool *contains_wcard)
413 ssize_t bufrem = smbreq_bufrem(req, src);
415 if (bufrem < 0) {
416 *err = NT_STATUS_INVALID_PARAMETER;
417 return 0;
420 if (req->posix_pathnames) {
421 return srvstr_get_path_wcard_internal(mem_ctx,
422 (const char *)req->inbuf,
423 req->flags2,
424 pp_dest,
425 src,
426 bufrem,
427 flags,
428 true,
429 err,
430 contains_wcard);
431 } else {
432 return srvstr_get_path_wcard_internal(mem_ctx,
433 (const char *)req->inbuf,
434 req->flags2,
435 pp_dest,
436 src,
437 bufrem,
438 flags,
439 false,
440 err,
441 contains_wcard);
445 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
446 char **pp_dest, const char *src, int flags,
447 NTSTATUS *err)
449 bool ignore;
450 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
451 flags, err, &ignore);
455 * pull a string from the smb_buf part of a packet. In this case the
456 * string can either be null terminated or it can be terminated by the
457 * end of the smbbuf area
459 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
460 char **dest, const uint8_t *src, int flags)
462 ssize_t bufrem = smbreq_bufrem(req, src);
464 if (bufrem < 0) {
465 return 0;
468 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
469 bufrem, flags);
472 /****************************************************************************
473 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
474 ****************************************************************************/
476 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
477 files_struct *fsp)
479 if ((fsp == NULL) || (conn == NULL)) {
480 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
481 return False;
483 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
484 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
485 return False;
487 return True;
490 /****************************************************************************
491 Check if we have a correct fsp pointing to a file.
492 ****************************************************************************/
494 bool check_fsp(connection_struct *conn, struct smb_request *req,
495 files_struct *fsp)
497 if (!check_fsp_open(conn, req, fsp)) {
498 return False;
500 if (fsp->is_directory) {
501 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
502 return False;
504 if (fsp->fh->fd == -1) {
505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
506 return False;
508 fsp->num_smb_operations++;
509 return True;
512 /****************************************************************************
513 Check if we have a correct fsp pointing to a quota fake file. Replacement for
514 the CHECK_NTQUOTA_HANDLE_OK macro.
515 ****************************************************************************/
517 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
518 files_struct *fsp)
520 if (!check_fsp_open(conn, req, fsp)) {
521 return false;
524 if (fsp->is_directory) {
525 return false;
528 if (fsp->fake_file_handle == NULL) {
529 return false;
532 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
533 return false;
536 if (fsp->fake_file_handle->private_data == NULL) {
537 return false;
540 return true;
543 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
544 const char *name, int name_type)
546 char *trim_name;
547 char *trim_name_type;
548 const char *retarget_parm;
549 char *retarget;
550 char *p;
551 int retarget_type = 0x20;
552 int retarget_port = NBT_SMB_PORT;
553 struct sockaddr_storage retarget_addr;
554 struct sockaddr_in *in_addr;
555 bool ret = false;
556 uint8_t outbuf[10];
558 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
559 return false;
562 trim_name = talloc_strdup(talloc_tos(), name);
563 if (trim_name == NULL) {
564 goto fail;
566 trim_char(trim_name, ' ', ' ');
568 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
569 name_type);
570 if (trim_name_type == NULL) {
571 goto fail;
574 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
575 trim_name_type, NULL);
576 if (retarget_parm == NULL) {
577 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
578 trim_name, NULL);
580 if (retarget_parm == NULL) {
581 goto fail;
584 retarget = talloc_strdup(trim_name, retarget_parm);
585 if (retarget == NULL) {
586 goto fail;
589 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
591 p = strchr(retarget, ':');
592 if (p != NULL) {
593 *p++ = '\0';
594 retarget_port = atoi(p);
597 p = strchr_m(retarget, '#');
598 if (p != NULL) {
599 *p++ = '\0';
600 if (sscanf(p, "%x", &retarget_type) != 1) {
601 goto fail;
605 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
606 if (!ret) {
607 DEBUG(10, ("could not resolve %s\n", retarget));
608 goto fail;
611 if (retarget_addr.ss_family != AF_INET) {
612 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
613 goto fail;
616 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
618 _smb_setlen(outbuf, 6);
619 SCVAL(outbuf, 0, 0x84);
620 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
621 *(uint16_t *)(outbuf+8) = htons(retarget_port);
623 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
624 NULL)) {
625 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
626 "failed.");
629 ret = true;
630 fail:
631 TALLOC_FREE(trim_name);
632 return ret;
635 static void reply_called_name_not_present(char *outbuf)
637 smb_setlen(outbuf, 1);
638 SCVAL(outbuf, 0, 0x83);
639 SCVAL(outbuf, 4, 0x82);
642 /****************************************************************************
643 Reply to a (netbios-level) special message.
644 ****************************************************************************/
646 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
648 struct smbd_server_connection *sconn = xconn->client->sconn;
649 int msg_type = CVAL(inbuf,0);
650 int msg_flags = CVAL(inbuf,1);
652 * We only really use 4 bytes of the outbuf, but for the smb_setlen
653 * calculation & friends (srv_send_smb uses that) we need the full smb
654 * header.
656 char outbuf[smb_size];
658 memset(outbuf, '\0', sizeof(outbuf));
660 smb_setlen(outbuf,0);
662 switch (msg_type) {
663 case NBSSrequest: /* session request */
665 /* inbuf_size is guarenteed to be at least 4. */
666 fstring name1,name2;
667 int name_type1, name_type2;
668 int name_len1, name_len2;
670 *name1 = *name2 = 0;
672 if (xconn->transport.nbt.got_session) {
673 exit_server_cleanly("multiple session request not permitted");
676 SCVAL(outbuf,0,NBSSpositive);
677 SCVAL(outbuf,3,0);
679 /* inbuf_size is guaranteed to be at least 4. */
680 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
681 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
682 DEBUG(0,("Invalid name length in session request\n"));
683 reply_called_name_not_present(outbuf);
684 break;
686 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
687 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
688 DEBUG(0,("Invalid name length in session request\n"));
689 reply_called_name_not_present(outbuf);
690 break;
693 name_type1 = name_extract((unsigned char *)inbuf,
694 inbuf_size,(unsigned int)4,name1);
695 name_type2 = name_extract((unsigned char *)inbuf,
696 inbuf_size,(unsigned int)(4 + name_len1),name2);
698 if (name_type1 == -1 || name_type2 == -1) {
699 DEBUG(0,("Invalid name type in session request\n"));
700 reply_called_name_not_present(outbuf);
701 break;
704 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
705 name1, name_type1, name2, name_type2));
707 if (netbios_session_retarget(xconn, name1, name_type1)) {
708 exit_server_cleanly("retargeted client");
712 * Windows NT/2k uses "*SMBSERVER" and XP uses
713 * "*SMBSERV" arrggg!!!
715 if (strequal(name1, "*SMBSERVER ")
716 || strequal(name1, "*SMBSERV ")) {
717 char *raddr;
719 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
720 talloc_tos());
721 if (raddr == NULL) {
722 exit_server_cleanly("could not allocate raddr");
725 fstrcpy(name1, raddr);
728 set_local_machine_name(name1, True);
729 set_remote_machine_name(name2, True);
731 if (is_ipaddress(sconn->remote_hostname)) {
732 char *p = discard_const_p(char, sconn->remote_hostname);
734 talloc_free(p);
736 sconn->remote_hostname = talloc_strdup(sconn,
737 get_remote_machine_name());
738 if (sconn->remote_hostname == NULL) {
739 exit_server_cleanly("could not copy remote name");
741 xconn->remote_hostname = sconn->remote_hostname;
744 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
745 get_local_machine_name(), get_remote_machine_name(),
746 name_type2));
748 if (name_type2 == 'R') {
749 /* We are being asked for a pathworks session ---
750 no thanks! */
751 reply_called_name_not_present(outbuf);
752 break;
755 reload_services(sconn, conn_snum_used, true);
756 reopen_logs();
758 xconn->transport.nbt.got_session = true;
759 break;
762 case 0x89: /* session keepalive request
763 (some old clients produce this?) */
764 SCVAL(outbuf,0,NBSSkeepalive);
765 SCVAL(outbuf,3,0);
766 break;
768 case NBSSpositive: /* positive session response */
769 case NBSSnegative: /* negative session response */
770 case NBSSretarget: /* retarget session response */
771 DEBUG(0,("Unexpected session response\n"));
772 break;
774 case NBSSkeepalive: /* session keepalive */
775 default:
776 return;
779 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
780 msg_type, msg_flags));
782 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
783 exit_server_cleanly("reply_special: srv_send_smb failed.");
786 if (CVAL(outbuf, 0) != 0x82) {
787 exit_server_cleanly("invalid netbios session");
789 return;
792 /****************************************************************************
793 Reply to a tcon.
794 conn POINTER CAN BE NULL HERE !
795 ****************************************************************************/
797 void reply_tcon(struct smb_request *req)
799 connection_struct *conn = req->conn;
800 const char *service;
801 char *service_buf = NULL;
802 char *password = NULL;
803 char *dev = NULL;
804 int pwlen=0;
805 NTSTATUS nt_status;
806 const uint8_t *p;
807 const char *p2;
808 TALLOC_CTX *ctx = talloc_tos();
809 struct smbXsrv_connection *xconn = req->xconn;
810 NTTIME now = timeval_to_nttime(&req->request_time);
812 START_PROFILE(SMBtcon);
814 if (req->buflen < 4) {
815 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
816 END_PROFILE(SMBtcon);
817 return;
820 p = req->buf + 1;
821 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
822 p += 1;
823 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
824 p += pwlen+1;
825 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
826 p += 1;
828 if (service_buf == NULL || password == NULL || dev == NULL) {
829 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
830 END_PROFILE(SMBtcon);
831 return;
833 p2 = strrchr_m(service_buf,'\\');
834 if (p2) {
835 service = p2+1;
836 } else {
837 service = service_buf;
840 conn = make_connection(req, now, service, dev,
841 req->vuid,&nt_status);
842 req->conn = conn;
844 if (!conn) {
845 reply_nterror(req, nt_status);
846 END_PROFILE(SMBtcon);
847 return;
850 reply_outbuf(req, 2, 0);
851 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
852 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
853 SSVAL(req->outbuf,smb_tid,conn->cnum);
855 DEBUG(3,("tcon service=%s cnum=%d\n",
856 service, conn->cnum));
858 END_PROFILE(SMBtcon);
859 return;
862 /****************************************************************************
863 Reply to a tcon and X.
864 conn POINTER CAN BE NULL HERE !
865 ****************************************************************************/
867 void reply_tcon_and_X(struct smb_request *req)
869 connection_struct *conn = req->conn;
870 const char *service = NULL;
871 TALLOC_CTX *ctx = talloc_tos();
872 /* what the client thinks the device is */
873 char *client_devicetype = NULL;
874 /* what the server tells the client the share represents */
875 const char *server_devicetype;
876 NTSTATUS nt_status;
877 int passlen;
878 char *path = NULL;
879 const uint8_t *p;
880 const char *q;
881 uint16_t tcon_flags;
882 struct smbXsrv_session *session = NULL;
883 NTTIME now = timeval_to_nttime(&req->request_time);
884 bool session_key_updated = false;
885 uint16_t optional_support = 0;
886 struct smbXsrv_connection *xconn = req->xconn;
888 START_PROFILE(SMBtconX);
890 if (req->wct < 4) {
891 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
892 END_PROFILE(SMBtconX);
893 return;
896 passlen = SVAL(req->vwv+3, 0);
897 tcon_flags = SVAL(req->vwv+2, 0);
899 /* we might have to close an old one */
900 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
901 struct smbXsrv_tcon *tcon;
902 NTSTATUS status;
904 tcon = conn->tcon;
905 req->conn = NULL;
906 conn = NULL;
909 * TODO: cancel all outstanding requests on the tcon
911 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
912 if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(0, ("reply_tcon_and_X: "
914 "smbXsrv_tcon_disconnect() failed: %s\n",
915 nt_errstr(status)));
917 * If we hit this case, there is something completely
918 * wrong, so we better disconnect the transport connection.
920 END_PROFILE(SMBtconX);
921 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
922 return;
925 TALLOC_FREE(tcon);
928 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
929 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
930 END_PROFILE(SMBtconX);
931 return;
934 if (xconn->smb1.negprot.encrypted_passwords) {
935 p = req->buf + passlen;
936 } else {
937 p = req->buf + passlen + 1;
940 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
942 if (path == NULL) {
943 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
944 END_PROFILE(SMBtconX);
945 return;
949 * the service name can be either: \\server\share
950 * or share directly like on the DELL PowerVault 705
952 if (*path=='\\') {
953 q = strchr_m(path+2,'\\');
954 if (!q) {
955 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
956 END_PROFILE(SMBtconX);
957 return;
959 service = q+1;
960 } else {
961 service = path;
964 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
965 &client_devicetype, p,
966 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
968 if (client_devicetype == NULL) {
969 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
970 END_PROFILE(SMBtconX);
971 return;
974 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
976 nt_status = smb1srv_session_lookup(xconn,
977 req->vuid, now, &session);
978 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
979 reply_force_doserror(req, ERRSRV, ERRbaduid);
980 END_PROFILE(SMBtconX);
981 return;
983 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
984 reply_nterror(req, nt_status);
985 END_PROFILE(SMBtconX);
986 return;
988 if (!NT_STATUS_IS_OK(nt_status)) {
989 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
990 END_PROFILE(SMBtconX);
991 return;
994 if (session->global->auth_session_info == NULL) {
995 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
996 END_PROFILE(SMBtconX);
997 return;
1001 * If there is no application key defined yet
1002 * we create one.
1004 * This means we setup the application key on the
1005 * first tcon that happens via the given session.
1007 * Once the application key is defined, it does not
1008 * change any more.
1010 if (session->global->application_key.length == 0 &&
1011 session->global->signing_key.length > 0)
1013 struct smbXsrv_session *x = session;
1014 struct auth_session_info *session_info =
1015 session->global->auth_session_info;
1016 uint8_t session_key[16];
1018 ZERO_STRUCT(session_key);
1019 memcpy(session_key, x->global->signing_key.data,
1020 MIN(x->global->signing_key.length, sizeof(session_key)));
1023 * The application key is truncated/padded to 16 bytes
1025 x->global->application_key = data_blob_talloc(x->global,
1026 session_key,
1027 sizeof(session_key));
1028 ZERO_STRUCT(session_key);
1029 if (x->global->application_key.data == NULL) {
1030 reply_nterror(req, NT_STATUS_NO_MEMORY);
1031 END_PROFILE(SMBtconX);
1032 return;
1035 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1036 smb_key_derivation(x->global->application_key.data,
1037 x->global->application_key.length,
1038 x->global->application_key.data);
1039 optional_support |= SMB_EXTENDED_SIGNATURES;
1043 * Place the application key into the session_info
1045 data_blob_clear_free(&session_info->session_key);
1046 session_info->session_key = data_blob_dup_talloc(session_info,
1047 x->global->application_key);
1048 if (session_info->session_key.data == NULL) {
1049 data_blob_clear_free(&x->global->application_key);
1050 reply_nterror(req, NT_STATUS_NO_MEMORY);
1051 END_PROFILE(SMBtconX);
1052 return;
1054 session_key_updated = true;
1057 conn = make_connection(req, now, service, client_devicetype,
1058 req->vuid, &nt_status);
1059 req->conn =conn;
1061 if (!conn) {
1062 if (session_key_updated) {
1063 struct smbXsrv_session *x = session;
1064 struct auth_session_info *session_info =
1065 session->global->auth_session_info;
1066 data_blob_clear_free(&x->global->application_key);
1067 data_blob_clear_free(&session_info->session_key);
1069 reply_nterror(req, nt_status);
1070 END_PROFILE(SMBtconX);
1071 return;
1074 if ( IS_IPC(conn) )
1075 server_devicetype = "IPC";
1076 else if ( IS_PRINT(conn) )
1077 server_devicetype = "LPT1:";
1078 else
1079 server_devicetype = "A:";
1081 if (get_Protocol() < PROTOCOL_NT1) {
1082 reply_outbuf(req, 2, 0);
1083 if (message_push_string(&req->outbuf, server_devicetype,
1084 STR_TERMINATE|STR_ASCII) == -1) {
1085 reply_nterror(req, NT_STATUS_NO_MEMORY);
1086 END_PROFILE(SMBtconX);
1087 return;
1089 } else {
1090 /* NT sets the fstype of IPC$ to the null string */
1091 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1093 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1094 /* Return permissions. */
1095 uint32_t perm1 = 0;
1096 uint32_t perm2 = 0;
1098 reply_outbuf(req, 7, 0);
1100 if (IS_IPC(conn)) {
1101 perm1 = FILE_ALL_ACCESS;
1102 perm2 = FILE_ALL_ACCESS;
1103 } else {
1104 perm1 = conn->share_access;
1107 SIVAL(req->outbuf, smb_vwv3, perm1);
1108 SIVAL(req->outbuf, smb_vwv5, perm2);
1109 } else {
1110 reply_outbuf(req, 3, 0);
1113 if ((message_push_string(&req->outbuf, server_devicetype,
1114 STR_TERMINATE|STR_ASCII) == -1)
1115 || (message_push_string(&req->outbuf, fstype,
1116 STR_TERMINATE) == -1)) {
1117 reply_nterror(req, NT_STATUS_NO_MEMORY);
1118 END_PROFILE(SMBtconX);
1119 return;
1122 /* what does setting this bit do? It is set by NT4 and
1123 may affect the ability to autorun mounted cdroms */
1124 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1125 optional_support |=
1126 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1128 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1129 DEBUG(2,("Serving %s as a Dfs root\n",
1130 lp_servicename(ctx, SNUM(conn)) ));
1131 optional_support |= SMB_SHARE_IN_DFS;
1134 SSVAL(req->outbuf, smb_vwv2, optional_support);
1137 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1138 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1140 DEBUG(3,("tconX service=%s \n",
1141 service));
1143 /* set the incoming and outgoing tid to the just created one */
1144 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1145 SSVAL(req->outbuf,smb_tid,conn->cnum);
1147 END_PROFILE(SMBtconX);
1149 req->tid = conn->cnum;
1152 /****************************************************************************
1153 Reply to an unknown type.
1154 ****************************************************************************/
1156 void reply_unknown_new(struct smb_request *req, uint8_t type)
1158 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1159 smb_fn_name(type), type, type));
1160 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1161 return;
1164 /****************************************************************************
1165 Reply to an ioctl.
1166 conn POINTER CAN BE NULL HERE !
1167 ****************************************************************************/
1169 void reply_ioctl(struct smb_request *req)
1171 connection_struct *conn = req->conn;
1172 uint16_t device;
1173 uint16_t function;
1174 uint32_t ioctl_code;
1175 int replysize;
1176 char *p;
1178 START_PROFILE(SMBioctl);
1180 if (req->wct < 3) {
1181 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1182 END_PROFILE(SMBioctl);
1183 return;
1186 device = SVAL(req->vwv+1, 0);
1187 function = SVAL(req->vwv+2, 0);
1188 ioctl_code = (device << 16) + function;
1190 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1192 switch (ioctl_code) {
1193 case IOCTL_QUERY_JOB_INFO:
1194 replysize = 32;
1195 break;
1196 default:
1197 reply_force_doserror(req, ERRSRV, ERRnosupport);
1198 END_PROFILE(SMBioctl);
1199 return;
1202 reply_outbuf(req, 8, replysize+1);
1203 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1204 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1205 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1206 p = smb_buf(req->outbuf);
1207 memset(p, '\0', replysize+1); /* valgrind-safe. */
1208 p += 1; /* Allow for alignment */
1210 switch (ioctl_code) {
1211 case IOCTL_QUERY_JOB_INFO:
1213 NTSTATUS status;
1214 size_t len = 0;
1215 files_struct *fsp = file_fsp(
1216 req, SVAL(req->vwv+0, 0));
1217 if (!fsp) {
1218 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1219 END_PROFILE(SMBioctl);
1220 return;
1222 /* Job number */
1223 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1225 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1226 lp_netbios_name(), 15,
1227 STR_TERMINATE|STR_ASCII, &len);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 reply_nterror(req, status);
1230 END_PROFILE(SMBioctl);
1231 return;
1233 if (conn) {
1234 status = srvstr_push((char *)req->outbuf, req->flags2,
1235 p+18,
1236 lp_servicename(talloc_tos(),
1237 SNUM(conn)),
1238 13, STR_TERMINATE|STR_ASCII, &len);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 reply_nterror(req, status);
1241 END_PROFILE(SMBioctl);
1242 return;
1244 } else {
1245 memset(p+18, 0, 13);
1247 break;
1251 END_PROFILE(SMBioctl);
1252 return;
1255 /****************************************************************************
1256 Strange checkpath NTSTATUS mapping.
1257 ****************************************************************************/
1259 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1261 /* Strange DOS error code semantics only for checkpath... */
1262 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1263 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1264 /* We need to map to ERRbadpath */
1265 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1268 return status;
1271 /****************************************************************************
1272 Reply to a checkpath.
1273 ****************************************************************************/
1275 void reply_checkpath(struct smb_request *req)
1277 connection_struct *conn = req->conn;
1278 struct smb_filename *smb_fname = NULL;
1279 char *name = NULL;
1280 NTSTATUS status;
1281 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1282 TALLOC_CTX *ctx = talloc_tos();
1284 START_PROFILE(SMBcheckpath);
1286 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1287 STR_TERMINATE, &status);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 status = map_checkpath_error(req->flags2, status);
1291 reply_nterror(req, status);
1292 END_PROFILE(SMBcheckpath);
1293 return;
1296 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1298 status = filename_convert(ctx,
1299 conn,
1300 name,
1301 ucf_flags,
1302 NULL,
1303 &smb_fname);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1307 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1308 ERRSRV, ERRbadpath);
1309 END_PROFILE(SMBcheckpath);
1310 return;
1312 goto path_err;
1315 if (!VALID_STAT(smb_fname->st) &&
1316 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1317 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1318 smb_fname_str_dbg(smb_fname), strerror(errno)));
1319 status = map_nt_error_from_unix(errno);
1320 goto path_err;
1323 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1324 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1325 ERRDOS, ERRbadpath);
1326 goto out;
1329 reply_outbuf(req, 0, 0);
1331 path_err:
1332 /* We special case this - as when a Windows machine
1333 is parsing a path is steps through the components
1334 one at a time - if a component fails it expects
1335 ERRbadpath, not ERRbadfile.
1337 status = map_checkpath_error(req->flags2, status);
1338 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1340 * Windows returns different error codes if
1341 * the parent directory is valid but not the
1342 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1343 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1344 * if the path is invalid.
1346 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1347 ERRDOS, ERRbadpath);
1348 goto out;
1351 reply_nterror(req, status);
1353 out:
1354 TALLOC_FREE(smb_fname);
1355 END_PROFILE(SMBcheckpath);
1356 return;
1359 /****************************************************************************
1360 Reply to a getatr.
1361 ****************************************************************************/
1363 void reply_getatr(struct smb_request *req)
1365 connection_struct *conn = req->conn;
1366 struct smb_filename *smb_fname = NULL;
1367 char *fname = NULL;
1368 int mode=0;
1369 off_t size=0;
1370 time_t mtime=0;
1371 const char *p;
1372 NTSTATUS status;
1373 TALLOC_CTX *ctx = talloc_tos();
1374 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1376 START_PROFILE(SMBgetatr);
1378 p = (const char *)req->buf + 1;
1379 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 reply_nterror(req, status);
1382 goto out;
1385 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1386 under WfWg - weird! */
1387 if (*fname == '\0') {
1388 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1389 if (!CAN_WRITE(conn)) {
1390 mode |= FILE_ATTRIBUTE_READONLY;
1392 size = 0;
1393 mtime = 0;
1394 } else {
1395 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1396 status = filename_convert(ctx,
1397 conn,
1398 fname,
1399 ucf_flags,
1400 NULL,
1401 &smb_fname);
1402 if (!NT_STATUS_IS_OK(status)) {
1403 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1404 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1405 ERRSRV, ERRbadpath);
1406 goto out;
1408 reply_nterror(req, status);
1409 goto out;
1411 if (!VALID_STAT(smb_fname->st) &&
1412 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1413 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1414 smb_fname_str_dbg(smb_fname),
1415 strerror(errno)));
1416 reply_nterror(req, map_nt_error_from_unix(errno));
1417 goto out;
1420 mode = dos_mode(conn, smb_fname);
1421 size = smb_fname->st.st_ex_size;
1423 if (ask_sharemode) {
1424 struct timespec write_time_ts;
1425 struct file_id fileid;
1427 ZERO_STRUCT(write_time_ts);
1428 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1429 get_file_infos(fileid, 0, NULL, &write_time_ts);
1430 if (!null_timespec(write_time_ts)) {
1431 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1435 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1436 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1437 size = 0;
1441 reply_outbuf(req, 10, 0);
1443 SSVAL(req->outbuf,smb_vwv0,mode);
1444 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1445 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1446 } else {
1447 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1449 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1451 if (get_Protocol() >= PROTOCOL_NT1) {
1452 SSVAL(req->outbuf, smb_flg2,
1453 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1456 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1457 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1459 out:
1460 TALLOC_FREE(smb_fname);
1461 TALLOC_FREE(fname);
1462 END_PROFILE(SMBgetatr);
1463 return;
1466 /****************************************************************************
1467 Reply to a setatr.
1468 ****************************************************************************/
1470 void reply_setatr(struct smb_request *req)
1472 struct smb_file_time ft;
1473 connection_struct *conn = req->conn;
1474 struct smb_filename *smb_fname = NULL;
1475 char *fname = NULL;
1476 int mode;
1477 time_t mtime;
1478 const char *p;
1479 NTSTATUS status;
1480 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1481 TALLOC_CTX *ctx = talloc_tos();
1483 START_PROFILE(SMBsetatr);
1485 ZERO_STRUCT(ft);
1487 if (req->wct < 2) {
1488 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1489 goto out;
1492 p = (const char *)req->buf + 1;
1493 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 reply_nterror(req, status);
1496 goto out;
1499 status = filename_convert(ctx,
1500 conn,
1501 fname,
1502 ucf_flags,
1503 NULL,
1504 &smb_fname);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1507 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1508 ERRSRV, ERRbadpath);
1509 goto out;
1511 reply_nterror(req, status);
1512 goto out;
1515 if (smb_fname->base_name[0] == '.' &&
1516 smb_fname->base_name[1] == '\0') {
1518 * Not sure here is the right place to catch this
1519 * condition. Might be moved to somewhere else later -- vl
1521 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1522 goto out;
1525 mode = SVAL(req->vwv+0, 0);
1526 mtime = srv_make_unix_date3(req->vwv+1);
1528 if (mode != FILE_ATTRIBUTE_NORMAL) {
1529 if (VALID_STAT_OF_DIR(smb_fname->st))
1530 mode |= FILE_ATTRIBUTE_DIRECTORY;
1531 else
1532 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1534 status = check_access(conn, NULL, smb_fname,
1535 FILE_WRITE_ATTRIBUTES);
1536 if (!NT_STATUS_IS_OK(status)) {
1537 reply_nterror(req, status);
1538 goto out;
1541 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1542 false) != 0) {
1543 reply_nterror(req, map_nt_error_from_unix(errno));
1544 goto out;
1548 ft.mtime = convert_time_t_to_timespec(mtime);
1549 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1550 if (!NT_STATUS_IS_OK(status)) {
1551 reply_nterror(req, status);
1552 goto out;
1555 reply_outbuf(req, 0, 0);
1557 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1558 mode));
1559 out:
1560 TALLOC_FREE(smb_fname);
1561 END_PROFILE(SMBsetatr);
1562 return;
1565 /****************************************************************************
1566 Reply to a dskattr.
1567 ****************************************************************************/
1569 void reply_dskattr(struct smb_request *req)
1571 connection_struct *conn = req->conn;
1572 uint64_t ret;
1573 uint64_t dfree,dsize,bsize;
1574 struct smb_filename smb_fname;
1575 START_PROFILE(SMBdskattr);
1577 ZERO_STRUCT(smb_fname);
1578 smb_fname.base_name = discard_const_p(char, ".");
1580 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1581 reply_nterror(req, map_nt_error_from_unix(errno));
1582 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1583 END_PROFILE(SMBdskattr);
1584 return;
1587 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1588 if (ret == (uint64_t)-1) {
1589 reply_nterror(req, map_nt_error_from_unix(errno));
1590 END_PROFILE(SMBdskattr);
1591 return;
1595 * Force max to fit in 16 bit fields.
1597 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1598 dfree /= 2;
1599 dsize /= 2;
1600 bsize *= 2;
1601 if (bsize > (WORDMAX*512)) {
1602 bsize = (WORDMAX*512);
1603 if (dsize > WORDMAX)
1604 dsize = WORDMAX;
1605 if (dfree > WORDMAX)
1606 dfree = WORDMAX;
1607 break;
1611 reply_outbuf(req, 5, 0);
1613 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1614 double total_space, free_space;
1615 /* we need to scale this to a number that DOS6 can handle. We
1616 use floating point so we can handle large drives on systems
1617 that don't have 64 bit integers
1619 we end up displaying a maximum of 2G to DOS systems
1621 total_space = dsize * (double)bsize;
1622 free_space = dfree * (double)bsize;
1624 dsize = (uint64_t)((total_space+63*512) / (64*512));
1625 dfree = (uint64_t)((free_space+63*512) / (64*512));
1627 if (dsize > 0xFFFF) dsize = 0xFFFF;
1628 if (dfree > 0xFFFF) dfree = 0xFFFF;
1630 SSVAL(req->outbuf,smb_vwv0,dsize);
1631 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1632 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1633 SSVAL(req->outbuf,smb_vwv3,dfree);
1634 } else {
1635 SSVAL(req->outbuf,smb_vwv0,dsize);
1636 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1637 SSVAL(req->outbuf,smb_vwv2,512);
1638 SSVAL(req->outbuf,smb_vwv3,dfree);
1641 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1643 END_PROFILE(SMBdskattr);
1644 return;
1648 * Utility function to split the filename from the directory.
1650 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1651 char **fname_dir_out,
1652 char **fname_mask_out)
1654 const char *p = NULL;
1655 char *fname_dir = NULL;
1656 char *fname_mask = NULL;
1658 p = strrchr_m(fname_in, '/');
1659 if (!p) {
1660 fname_dir = talloc_strdup(ctx, ".");
1661 fname_mask = talloc_strdup(ctx, fname_in);
1662 } else {
1663 fname_dir = talloc_strndup(ctx, fname_in,
1664 PTR_DIFF(p, fname_in));
1665 fname_mask = talloc_strdup(ctx, p+1);
1668 if (!fname_dir || !fname_mask) {
1669 TALLOC_FREE(fname_dir);
1670 TALLOC_FREE(fname_mask);
1671 return NT_STATUS_NO_MEMORY;
1674 *fname_dir_out = fname_dir;
1675 *fname_mask_out = fname_mask;
1676 return NT_STATUS_OK;
1679 /****************************************************************************
1680 Make a dir struct.
1681 ****************************************************************************/
1683 static bool make_dir_struct(TALLOC_CTX *ctx,
1684 char *buf,
1685 const char *mask,
1686 const char *fname,
1687 off_t size,
1688 uint32_t mode,
1689 time_t date,
1690 bool uc)
1692 char *p;
1693 char *mask2 = talloc_strdup(ctx, mask);
1695 if (!mask2) {
1696 return False;
1699 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1700 size = 0;
1703 memset(buf+1,' ',11);
1704 if ((p = strchr_m(mask2,'.')) != NULL) {
1705 *p = 0;
1706 push_ascii(buf+1,mask2,8, 0);
1707 push_ascii(buf+9,p+1,3, 0);
1708 *p = '.';
1709 } else {
1710 push_ascii(buf+1,mask2,11, 0);
1713 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1714 SCVAL(buf,21,mode);
1715 srv_put_dos_date(buf,22,date);
1716 SSVAL(buf,26,size & 0xFFFF);
1717 SSVAL(buf,28,(size >> 16)&0xFFFF);
1718 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1719 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1720 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1721 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1722 return True;
1725 /****************************************************************************
1726 Reply to a search.
1727 Can be called from SMBsearch, SMBffirst or SMBfunique.
1728 ****************************************************************************/
1730 void reply_search(struct smb_request *req)
1732 connection_struct *conn = req->conn;
1733 char *path = NULL;
1734 char *mask = NULL;
1735 char *directory = NULL;
1736 struct smb_filename *smb_fname = NULL;
1737 char *fname = NULL;
1738 off_t size;
1739 uint32_t mode;
1740 struct timespec date;
1741 uint32_t dirtype;
1742 unsigned int numentries = 0;
1743 unsigned int maxentries = 0;
1744 bool finished = False;
1745 const char *p;
1746 int status_len;
1747 char status[21];
1748 int dptr_num= -1;
1749 bool check_descend = False;
1750 bool expect_close = False;
1751 NTSTATUS nt_status;
1752 bool mask_contains_wcard = False;
1753 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1754 TALLOC_CTX *ctx = talloc_tos();
1755 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1756 struct dptr_struct *dirptr = NULL;
1757 struct smbXsrv_connection *xconn = req->xconn;
1758 struct smbd_server_connection *sconn = req->sconn;
1760 START_PROFILE(SMBsearch);
1762 if (req->wct < 2) {
1763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1764 goto out;
1767 if (req->posix_pathnames) {
1768 reply_unknown_new(req, req->cmd);
1769 goto out;
1772 /* If we were called as SMBffirst then we must expect close. */
1773 if(req->cmd == SMBffirst) {
1774 expect_close = True;
1777 reply_outbuf(req, 1, 3);
1778 maxentries = SVAL(req->vwv+0, 0);
1779 dirtype = SVAL(req->vwv+1, 0);
1780 p = (const char *)req->buf + 1;
1781 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1782 &nt_status, &mask_contains_wcard);
1783 if (!NT_STATUS_IS_OK(nt_status)) {
1784 reply_nterror(req, nt_status);
1785 goto out;
1788 p++;
1789 status_len = SVAL(p, 0);
1790 p += 2;
1792 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1794 if (status_len == 0) {
1795 struct smb_filename *smb_dname = NULL;
1796 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1797 ucf_flags_from_smb_request(req);
1798 nt_status = filename_convert(ctx, conn,
1799 path,
1800 ucf_flags,
1801 &mask_contains_wcard,
1802 &smb_fname);
1803 if (!NT_STATUS_IS_OK(nt_status)) {
1804 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1805 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1806 ERRSRV, ERRbadpath);
1807 goto out;
1809 reply_nterror(req, nt_status);
1810 goto out;
1813 directory = smb_fname->base_name;
1815 p = strrchr_m(directory,'/');
1816 if ((p != NULL) && (*directory != '/')) {
1817 mask = talloc_strdup(ctx, p + 1);
1818 directory = talloc_strndup(ctx, directory,
1819 PTR_DIFF(p, directory));
1820 } else {
1821 mask = talloc_strdup(ctx, directory);
1822 directory = talloc_strdup(ctx,".");
1825 if (!directory) {
1826 reply_nterror(req, NT_STATUS_NO_MEMORY);
1827 goto out;
1830 memset((char *)status,'\0',21);
1831 SCVAL(status,0,(dirtype & 0x1F));
1833 smb_dname = synthetic_smb_fname(talloc_tos(),
1834 directory,
1835 NULL,
1836 NULL,
1837 smb_fname->flags);
1838 if (smb_dname == NULL) {
1839 reply_nterror(req, NT_STATUS_NO_MEMORY);
1840 goto out;
1843 nt_status = dptr_create(conn,
1844 NULL, /* req */
1845 NULL, /* fsp */
1846 smb_dname,
1847 True,
1848 expect_close,
1849 req->smbpid,
1850 mask,
1851 mask_contains_wcard,
1852 dirtype,
1853 &dirptr);
1855 TALLOC_FREE(smb_dname);
1857 if (!NT_STATUS_IS_OK(nt_status)) {
1858 reply_nterror(req, nt_status);
1859 goto out;
1861 dptr_num = dptr_dnum(dirptr);
1862 } else {
1863 int status_dirtype;
1864 const char *dirpath;
1866 memcpy(status,p,21);
1867 status_dirtype = CVAL(status,0) & 0x1F;
1868 if (status_dirtype != (dirtype & 0x1F)) {
1869 dirtype = status_dirtype;
1872 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1873 if (!dirptr) {
1874 goto SearchEmpty;
1876 dirpath = dptr_path(sconn, dptr_num);
1877 directory = talloc_strdup(ctx, dirpath);
1878 if (!directory) {
1879 reply_nterror(req, NT_STATUS_NO_MEMORY);
1880 goto out;
1883 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1884 if (!mask) {
1885 goto SearchEmpty;
1888 * For a 'continue' search we have no string. So
1889 * check from the initial saved string.
1891 if (!req->posix_pathnames) {
1892 mask_contains_wcard = ms_has_wild(mask);
1894 dirtype = dptr_attr(sconn, dptr_num);
1897 DEBUG(4,("dptr_num is %d\n",dptr_num));
1899 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1900 dptr_init_search_op(dirptr);
1902 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1903 char buf[DIR_STRUCT_SIZE];
1904 memcpy(buf,status,21);
1905 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1906 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1907 reply_nterror(req, NT_STATUS_NO_MEMORY);
1908 goto out;
1910 dptr_fill(sconn, buf+12,dptr_num);
1911 if (dptr_zero(buf+12) && (status_len==0)) {
1912 numentries = 1;
1913 } else {
1914 numentries = 0;
1916 if (message_push_blob(&req->outbuf,
1917 data_blob_const(buf, sizeof(buf)))
1918 == -1) {
1919 reply_nterror(req, NT_STATUS_NO_MEMORY);
1920 goto out;
1922 } else {
1923 unsigned int i;
1924 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1925 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1927 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1929 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1930 directory,lp_dont_descend(ctx, SNUM(conn))));
1931 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1932 check_descend = True;
1935 for (i=numentries;(i<maxentries) && !finished;i++) {
1936 finished = !get_dir_entry(ctx,
1937 dirptr,
1938 mask,
1939 dirtype,
1940 &fname,
1941 &size,
1942 &mode,
1943 &date,
1944 check_descend,
1945 ask_sharemode);
1946 if (!finished) {
1947 char buf[DIR_STRUCT_SIZE];
1948 memcpy(buf,status,21);
1949 if (!make_dir_struct(ctx,
1950 buf,
1951 mask,
1952 fname,
1953 size,
1954 mode,
1955 convert_timespec_to_time_t(date),
1956 !allow_long_path_components)) {
1957 reply_nterror(req, NT_STATUS_NO_MEMORY);
1958 goto out;
1960 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1961 break;
1963 if (message_push_blob(&req->outbuf,
1964 data_blob_const(buf, sizeof(buf)))
1965 == -1) {
1966 reply_nterror(req, NT_STATUS_NO_MEMORY);
1967 goto out;
1969 numentries++;
1974 SearchEmpty:
1976 /* If we were called as SMBffirst with smb_search_id == NULL
1977 and no entries were found then return error and close dirptr
1978 (X/Open spec) */
1980 if (numentries == 0) {
1981 dptr_close(sconn, &dptr_num);
1982 } else if(expect_close && status_len == 0) {
1983 /* Close the dptr - we know it's gone */
1984 dptr_close(sconn, &dptr_num);
1987 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1988 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1989 dptr_close(sconn, &dptr_num);
1992 if ((numentries == 0) && !mask_contains_wcard) {
1993 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1994 goto out;
1997 SSVAL(req->outbuf,smb_vwv0,numentries);
1998 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1999 SCVAL(smb_buf(req->outbuf),0,5);
2000 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2002 /* The replies here are never long name. */
2003 SSVAL(req->outbuf, smb_flg2,
2004 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2005 if (!allow_long_path_components) {
2006 SSVAL(req->outbuf, smb_flg2,
2007 SVAL(req->outbuf, smb_flg2)
2008 & (~FLAGS2_LONG_PATH_COMPONENTS));
2011 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2012 SSVAL(req->outbuf, smb_flg2,
2013 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2015 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2016 smb_fn_name(req->cmd),
2017 mask,
2018 directory,
2019 dirtype,
2020 numentries,
2021 maxentries ));
2022 out:
2023 TALLOC_FREE(directory);
2024 TALLOC_FREE(mask);
2025 TALLOC_FREE(smb_fname);
2026 END_PROFILE(SMBsearch);
2027 return;
2030 /****************************************************************************
2031 Reply to a fclose (stop directory search).
2032 ****************************************************************************/
2034 void reply_fclose(struct smb_request *req)
2036 int status_len;
2037 char status[21];
2038 int dptr_num= -2;
2039 const char *p;
2040 char *path = NULL;
2041 NTSTATUS err;
2042 bool path_contains_wcard = False;
2043 TALLOC_CTX *ctx = talloc_tos();
2044 struct smbd_server_connection *sconn = req->sconn;
2046 START_PROFILE(SMBfclose);
2048 if (req->posix_pathnames) {
2049 reply_unknown_new(req, req->cmd);
2050 END_PROFILE(SMBfclose);
2051 return;
2054 p = (const char *)req->buf + 1;
2055 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2056 &err, &path_contains_wcard);
2057 if (!NT_STATUS_IS_OK(err)) {
2058 reply_nterror(req, err);
2059 END_PROFILE(SMBfclose);
2060 return;
2062 p++;
2063 status_len = SVAL(p,0);
2064 p += 2;
2066 if (status_len == 0) {
2067 reply_force_doserror(req, ERRSRV, ERRsrverror);
2068 END_PROFILE(SMBfclose);
2069 return;
2072 memcpy(status,p,21);
2074 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2075 /* Close the dptr - we know it's gone */
2076 dptr_close(sconn, &dptr_num);
2079 reply_outbuf(req, 1, 0);
2080 SSVAL(req->outbuf,smb_vwv0,0);
2082 DEBUG(3,("search close\n"));
2084 END_PROFILE(SMBfclose);
2085 return;
2088 /****************************************************************************
2089 Reply to an open.
2090 ****************************************************************************/
2092 void reply_open(struct smb_request *req)
2094 connection_struct *conn = req->conn;
2095 struct smb_filename *smb_fname = NULL;
2096 char *fname = NULL;
2097 uint32_t fattr=0;
2098 off_t size = 0;
2099 time_t mtime=0;
2100 int info;
2101 files_struct *fsp;
2102 int oplock_request;
2103 int deny_mode;
2104 uint32_t dos_attr;
2105 uint32_t access_mask;
2106 uint32_t share_mode;
2107 uint32_t create_disposition;
2108 uint32_t create_options = 0;
2109 uint32_t private_flags = 0;
2110 NTSTATUS status;
2111 uint32_t ucf_flags;
2112 TALLOC_CTX *ctx = talloc_tos();
2114 START_PROFILE(SMBopen);
2116 if (req->wct < 2) {
2117 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2118 goto out;
2121 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2122 deny_mode = SVAL(req->vwv+0, 0);
2123 dos_attr = SVAL(req->vwv+1, 0);
2125 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2126 STR_TERMINATE, &status);
2127 if (!NT_STATUS_IS_OK(status)) {
2128 reply_nterror(req, status);
2129 goto out;
2132 if (!map_open_params_to_ntcreate(fname, deny_mode,
2133 OPENX_FILE_EXISTS_OPEN, &access_mask,
2134 &share_mode, &create_disposition,
2135 &create_options, &private_flags)) {
2136 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2137 goto out;
2140 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2142 status = filename_convert(ctx,
2143 conn,
2144 fname,
2145 ucf_flags,
2146 NULL,
2147 &smb_fname);
2148 if (!NT_STATUS_IS_OK(status)) {
2149 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2150 reply_botherror(req,
2151 NT_STATUS_PATH_NOT_COVERED,
2152 ERRSRV, ERRbadpath);
2153 goto out;
2155 reply_nterror(req, status);
2156 goto out;
2159 status = SMB_VFS_CREATE_FILE(
2160 conn, /* conn */
2161 req, /* req */
2162 0, /* root_dir_fid */
2163 smb_fname, /* fname */
2164 access_mask, /* access_mask */
2165 share_mode, /* share_access */
2166 create_disposition, /* create_disposition*/
2167 create_options, /* create_options */
2168 dos_attr, /* file_attributes */
2169 oplock_request, /* oplock_request */
2170 NULL, /* lease */
2171 0, /* allocation_size */
2172 private_flags,
2173 NULL, /* sd */
2174 NULL, /* ea_list */
2175 &fsp, /* result */
2176 &info, /* pinfo */
2177 NULL, NULL); /* create context */
2179 if (!NT_STATUS_IS_OK(status)) {
2180 if (open_was_deferred(req->xconn, req->mid)) {
2181 /* We have re-scheduled this call. */
2182 goto out;
2184 reply_openerror(req, status);
2185 goto out;
2188 /* Ensure we're pointing at the correct stat struct. */
2189 TALLOC_FREE(smb_fname);
2190 smb_fname = fsp->fsp_name;
2192 size = smb_fname->st.st_ex_size;
2193 fattr = dos_mode(conn, smb_fname);
2195 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2197 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2198 DEBUG(3,("attempt to open a directory %s\n",
2199 fsp_str_dbg(fsp)));
2200 close_file(req, fsp, ERROR_CLOSE);
2201 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2202 ERRDOS, ERRnoaccess);
2203 goto out;
2206 reply_outbuf(req, 7, 0);
2207 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2208 SSVAL(req->outbuf,smb_vwv1,fattr);
2209 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2210 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2211 } else {
2212 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2214 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2215 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2217 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2218 SCVAL(req->outbuf,smb_flg,
2219 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2222 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2223 SCVAL(req->outbuf,smb_flg,
2224 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2226 out:
2227 END_PROFILE(SMBopen);
2228 return;
2231 /****************************************************************************
2232 Reply to an open and X.
2233 ****************************************************************************/
2235 void reply_open_and_X(struct smb_request *req)
2237 connection_struct *conn = req->conn;
2238 struct smb_filename *smb_fname = NULL;
2239 char *fname = NULL;
2240 uint16_t open_flags;
2241 int deny_mode;
2242 uint32_t smb_attr;
2243 /* Breakout the oplock request bits so we can set the
2244 reply bits separately. */
2245 int ex_oplock_request;
2246 int core_oplock_request;
2247 int oplock_request;
2248 #if 0
2249 int smb_sattr = SVAL(req->vwv+4, 0);
2250 uint32_t smb_time = make_unix_date3(req->vwv+6);
2251 #endif
2252 int smb_ofun;
2253 uint32_t fattr=0;
2254 int mtime=0;
2255 int smb_action = 0;
2256 files_struct *fsp;
2257 NTSTATUS status;
2258 uint64_t allocation_size;
2259 ssize_t retval = -1;
2260 uint32_t access_mask;
2261 uint32_t share_mode;
2262 uint32_t create_disposition;
2263 uint32_t create_options = 0;
2264 uint32_t private_flags = 0;
2265 uint32_t ucf_flags;
2266 TALLOC_CTX *ctx = talloc_tos();
2268 START_PROFILE(SMBopenX);
2270 if (req->wct < 15) {
2271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2272 goto out;
2275 open_flags = SVAL(req->vwv+2, 0);
2276 deny_mode = SVAL(req->vwv+3, 0);
2277 smb_attr = SVAL(req->vwv+5, 0);
2278 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2279 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2280 oplock_request = ex_oplock_request | core_oplock_request;
2281 smb_ofun = SVAL(req->vwv+8, 0);
2282 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2284 /* If it's an IPC, pass off the pipe handler. */
2285 if (IS_IPC(conn)) {
2286 if (lp_nt_pipe_support()) {
2287 reply_open_pipe_and_X(conn, req);
2288 } else {
2289 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2291 goto out;
2294 /* XXXX we need to handle passed times, sattr and flags */
2295 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2296 STR_TERMINATE, &status);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 reply_nterror(req, status);
2299 goto out;
2302 if (!map_open_params_to_ntcreate(fname, deny_mode,
2303 smb_ofun,
2304 &access_mask, &share_mode,
2305 &create_disposition,
2306 &create_options,
2307 &private_flags)) {
2308 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2309 goto out;
2312 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2314 status = filename_convert(ctx,
2315 conn,
2316 fname,
2317 ucf_flags,
2318 NULL,
2319 &smb_fname);
2320 if (!NT_STATUS_IS_OK(status)) {
2321 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2322 reply_botherror(req,
2323 NT_STATUS_PATH_NOT_COVERED,
2324 ERRSRV, ERRbadpath);
2325 goto out;
2327 reply_nterror(req, status);
2328 goto out;
2331 status = SMB_VFS_CREATE_FILE(
2332 conn, /* conn */
2333 req, /* req */
2334 0, /* root_dir_fid */
2335 smb_fname, /* fname */
2336 access_mask, /* access_mask */
2337 share_mode, /* share_access */
2338 create_disposition, /* create_disposition*/
2339 create_options, /* create_options */
2340 smb_attr, /* file_attributes */
2341 oplock_request, /* oplock_request */
2342 NULL, /* lease */
2343 0, /* allocation_size */
2344 private_flags,
2345 NULL, /* sd */
2346 NULL, /* ea_list */
2347 &fsp, /* result */
2348 &smb_action, /* pinfo */
2349 NULL, NULL); /* create context */
2351 if (!NT_STATUS_IS_OK(status)) {
2352 if (open_was_deferred(req->xconn, req->mid)) {
2353 /* We have re-scheduled this call. */
2354 goto out;
2356 reply_openerror(req, status);
2357 goto out;
2360 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2361 if the file is truncated or created. */
2362 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2363 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2364 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2365 close_file(req, fsp, ERROR_CLOSE);
2366 reply_nterror(req, NT_STATUS_DISK_FULL);
2367 goto out;
2369 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2370 if (retval < 0) {
2371 close_file(req, fsp, ERROR_CLOSE);
2372 reply_nterror(req, NT_STATUS_DISK_FULL);
2373 goto out;
2375 status = vfs_stat_fsp(fsp);
2376 if (!NT_STATUS_IS_OK(status)) {
2377 close_file(req, fsp, ERROR_CLOSE);
2378 reply_nterror(req, status);
2379 goto out;
2383 fattr = dos_mode(conn, fsp->fsp_name);
2384 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2385 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2386 close_file(req, fsp, ERROR_CLOSE);
2387 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2388 goto out;
2391 /* If the caller set the extended oplock request bit
2392 and we granted one (by whatever means) - set the
2393 correct bit for extended oplock reply.
2396 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2397 smb_action |= EXTENDED_OPLOCK_GRANTED;
2400 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2401 smb_action |= EXTENDED_OPLOCK_GRANTED;
2404 /* If the caller set the core oplock request bit
2405 and we granted one (by whatever means) - set the
2406 correct bit for core oplock reply.
2409 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2410 reply_outbuf(req, 19, 0);
2411 } else {
2412 reply_outbuf(req, 15, 0);
2415 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2416 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2418 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2419 SCVAL(req->outbuf, smb_flg,
2420 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2423 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2424 SCVAL(req->outbuf, smb_flg,
2425 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2428 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2429 SSVAL(req->outbuf,smb_vwv3,fattr);
2430 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2431 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2432 } else {
2433 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2435 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2436 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2437 SSVAL(req->outbuf,smb_vwv11,smb_action);
2439 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2440 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2443 out:
2444 TALLOC_FREE(smb_fname);
2445 END_PROFILE(SMBopenX);
2446 return;
2449 /****************************************************************************
2450 Reply to a SMBulogoffX.
2451 ****************************************************************************/
2453 void reply_ulogoffX(struct smb_request *req)
2455 struct smbd_server_connection *sconn = req->sconn;
2456 struct user_struct *vuser;
2457 struct smbXsrv_session *session = NULL;
2458 NTSTATUS status;
2460 START_PROFILE(SMBulogoffX);
2462 vuser = get_valid_user_struct(sconn, req->vuid);
2464 if(vuser == NULL) {
2465 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2466 (unsigned long long)req->vuid));
2468 req->vuid = UID_FIELD_INVALID;
2469 reply_force_doserror(req, ERRSRV, ERRbaduid);
2470 END_PROFILE(SMBulogoffX);
2471 return;
2474 session = vuser->session;
2475 vuser = NULL;
2478 * TODO: cancel all outstanding requests on the session
2480 status = smbXsrv_session_logoff(session);
2481 if (!NT_STATUS_IS_OK(status)) {
2482 DEBUG(0, ("reply_ulogoff: "
2483 "smbXsrv_session_logoff() failed: %s\n",
2484 nt_errstr(status)));
2486 * If we hit this case, there is something completely
2487 * wrong, so we better disconnect the transport connection.
2489 END_PROFILE(SMBulogoffX);
2490 exit_server(__location__ ": smbXsrv_session_logoff failed");
2491 return;
2494 TALLOC_FREE(session);
2496 reply_outbuf(req, 2, 0);
2497 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2498 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2500 DEBUG(3, ("ulogoffX vuid=%llu\n",
2501 (unsigned long long)req->vuid));
2503 END_PROFILE(SMBulogoffX);
2504 req->vuid = UID_FIELD_INVALID;
2507 /****************************************************************************
2508 Reply to a mknew or a create.
2509 ****************************************************************************/
2511 void reply_mknew(struct smb_request *req)
2513 connection_struct *conn = req->conn;
2514 struct smb_filename *smb_fname = NULL;
2515 char *fname = NULL;
2516 uint32_t fattr = 0;
2517 struct smb_file_time ft;
2518 files_struct *fsp;
2519 int oplock_request = 0;
2520 NTSTATUS status;
2521 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2522 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2523 uint32_t create_disposition;
2524 uint32_t create_options = 0;
2525 uint32_t ucf_flags;
2526 TALLOC_CTX *ctx = talloc_tos();
2528 START_PROFILE(SMBcreate);
2529 ZERO_STRUCT(ft);
2531 if (req->wct < 3) {
2532 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2533 goto out;
2536 fattr = SVAL(req->vwv+0, 0);
2537 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2539 if (req->cmd == SMBmknew) {
2540 /* We should fail if file exists. */
2541 create_disposition = FILE_CREATE;
2542 } else {
2543 /* Create if file doesn't exist, truncate if it does. */
2544 create_disposition = FILE_OVERWRITE_IF;
2547 /* mtime. */
2548 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2550 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2551 STR_TERMINATE, &status);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 reply_nterror(req, status);
2554 goto out;
2557 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2558 status = filename_convert(ctx,
2559 conn,
2560 fname,
2561 ucf_flags,
2562 NULL,
2563 &smb_fname);
2564 if (!NT_STATUS_IS_OK(status)) {
2565 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2566 reply_botherror(req,
2567 NT_STATUS_PATH_NOT_COVERED,
2568 ERRSRV, ERRbadpath);
2569 goto out;
2571 reply_nterror(req, status);
2572 goto out;
2575 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2576 DEBUG(0,("Attempt to create file (%s) with volid set - "
2577 "please report this\n",
2578 smb_fname_str_dbg(smb_fname)));
2581 status = SMB_VFS_CREATE_FILE(
2582 conn, /* conn */
2583 req, /* req */
2584 0, /* root_dir_fid */
2585 smb_fname, /* fname */
2586 access_mask, /* access_mask */
2587 share_mode, /* share_access */
2588 create_disposition, /* create_disposition*/
2589 create_options, /* create_options */
2590 fattr, /* file_attributes */
2591 oplock_request, /* oplock_request */
2592 NULL, /* lease */
2593 0, /* allocation_size */
2594 0, /* private_flags */
2595 NULL, /* sd */
2596 NULL, /* ea_list */
2597 &fsp, /* result */
2598 NULL, /* pinfo */
2599 NULL, NULL); /* create context */
2601 if (!NT_STATUS_IS_OK(status)) {
2602 if (open_was_deferred(req->xconn, req->mid)) {
2603 /* We have re-scheduled this call. */
2604 goto out;
2606 reply_openerror(req, status);
2607 goto out;
2610 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2611 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 END_PROFILE(SMBcreate);
2614 goto out;
2617 reply_outbuf(req, 1, 0);
2618 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2620 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2621 SCVAL(req->outbuf,smb_flg,
2622 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2625 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2626 SCVAL(req->outbuf,smb_flg,
2627 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2630 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2631 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2632 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2633 (unsigned int)fattr));
2635 out:
2636 TALLOC_FREE(smb_fname);
2637 END_PROFILE(SMBcreate);
2638 return;
2641 /****************************************************************************
2642 Reply to a create temporary file.
2643 ****************************************************************************/
2645 void reply_ctemp(struct smb_request *req)
2647 connection_struct *conn = req->conn;
2648 struct smb_filename *smb_fname = NULL;
2649 char *wire_name = NULL;
2650 char *fname = NULL;
2651 uint32_t fattr;
2652 files_struct *fsp;
2653 int oplock_request;
2654 char *s;
2655 NTSTATUS status;
2656 int i;
2657 uint32_t ucf_flags;
2658 TALLOC_CTX *ctx = talloc_tos();
2660 START_PROFILE(SMBctemp);
2662 if (req->wct < 3) {
2663 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2664 goto out;
2667 fattr = SVAL(req->vwv+0, 0);
2668 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2670 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2671 STR_TERMINATE, &status);
2672 if (!NT_STATUS_IS_OK(status)) {
2673 reply_nterror(req, status);
2674 goto out;
2677 for (i = 0; i < 10; i++) {
2678 if (*wire_name) {
2679 fname = talloc_asprintf(ctx,
2680 "%s/TMP%s",
2681 wire_name,
2682 generate_random_str_list(ctx, 5, "0123456789"));
2683 } else {
2684 fname = talloc_asprintf(ctx,
2685 "TMP%s",
2686 generate_random_str_list(ctx, 5, "0123456789"));
2689 if (!fname) {
2690 reply_nterror(req, NT_STATUS_NO_MEMORY);
2691 goto out;
2694 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2695 status = filename_convert(ctx, conn,
2696 fname,
2697 ucf_flags,
2698 NULL,
2699 &smb_fname);
2700 if (!NT_STATUS_IS_OK(status)) {
2701 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2702 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2703 ERRSRV, ERRbadpath);
2704 goto out;
2706 reply_nterror(req, status);
2707 goto out;
2710 /* Create the file. */
2711 status = SMB_VFS_CREATE_FILE(
2712 conn, /* conn */
2713 req, /* req */
2714 0, /* root_dir_fid */
2715 smb_fname, /* fname */
2716 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2717 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2718 FILE_CREATE, /* create_disposition*/
2719 0, /* create_options */
2720 fattr, /* file_attributes */
2721 oplock_request, /* oplock_request */
2722 NULL, /* lease */
2723 0, /* allocation_size */
2724 0, /* private_flags */
2725 NULL, /* sd */
2726 NULL, /* ea_list */
2727 &fsp, /* result */
2728 NULL, /* pinfo */
2729 NULL, NULL); /* create context */
2731 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2732 TALLOC_FREE(fname);
2733 TALLOC_FREE(smb_fname);
2734 continue;
2737 if (!NT_STATUS_IS_OK(status)) {
2738 if (open_was_deferred(req->xconn, req->mid)) {
2739 /* We have re-scheduled this call. */
2740 goto out;
2742 reply_openerror(req, status);
2743 goto out;
2746 break;
2749 if (i == 10) {
2750 /* Collision after 10 times... */
2751 reply_nterror(req, status);
2752 goto out;
2755 reply_outbuf(req, 1, 0);
2756 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2758 /* the returned filename is relative to the directory */
2759 s = strrchr_m(fsp->fsp_name->base_name, '/');
2760 if (!s) {
2761 s = fsp->fsp_name->base_name;
2762 } else {
2763 s++;
2766 #if 0
2767 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2768 thing in the byte section. JRA */
2769 SSVALS(p, 0, -1); /* what is this? not in spec */
2770 #endif
2771 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2772 == -1) {
2773 reply_nterror(req, NT_STATUS_NO_MEMORY);
2774 goto out;
2777 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2778 SCVAL(req->outbuf, smb_flg,
2779 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2782 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2783 SCVAL(req->outbuf, smb_flg,
2784 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2787 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2788 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2789 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2790 out:
2791 TALLOC_FREE(smb_fname);
2792 TALLOC_FREE(wire_name);
2793 END_PROFILE(SMBctemp);
2794 return;
2797 /*******************************************************************
2798 Check if a user is allowed to rename a file.
2799 ********************************************************************/
2801 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2802 uint16_t dirtype)
2804 if (!CAN_WRITE(conn)) {
2805 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2808 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2809 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2810 /* Only bother to read the DOS attribute if we might deny the
2811 rename on the grounds of attribute mismatch. */
2812 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2813 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2814 return NT_STATUS_NO_SUCH_FILE;
2818 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2819 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2820 return NT_STATUS_OK;
2823 /* If no pathnames are open below this
2824 directory, allow the rename. */
2826 if (lp_strict_rename(SNUM(conn))) {
2828 * Strict rename, check open file db.
2830 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2831 return NT_STATUS_ACCESS_DENIED;
2833 } else if (file_find_subpath(fsp)) {
2835 * No strict rename, just look in local process.
2837 return NT_STATUS_ACCESS_DENIED;
2839 return NT_STATUS_OK;
2842 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2843 return NT_STATUS_OK;
2846 return NT_STATUS_ACCESS_DENIED;
2849 /*******************************************************************
2850 * unlink a file with all relevant access checks
2851 *******************************************************************/
2853 static NTSTATUS do_unlink(connection_struct *conn,
2854 struct smb_request *req,
2855 struct smb_filename *smb_fname,
2856 uint32_t dirtype)
2858 uint32_t fattr;
2859 files_struct *fsp;
2860 uint32_t dirtype_orig = dirtype;
2861 NTSTATUS status;
2862 int ret;
2863 bool posix_paths = (req != NULL && req->posix_pathnames);
2865 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2866 smb_fname_str_dbg(smb_fname),
2867 dirtype));
2869 if (!CAN_WRITE(conn)) {
2870 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2873 if (posix_paths) {
2874 ret = SMB_VFS_LSTAT(conn, smb_fname);
2875 } else {
2876 ret = SMB_VFS_STAT(conn, smb_fname);
2878 if (ret != 0) {
2879 return map_nt_error_from_unix(errno);
2882 fattr = dos_mode(conn, smb_fname);
2884 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2885 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2888 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2889 if (!dirtype) {
2890 return NT_STATUS_NO_SUCH_FILE;
2893 if (!dir_check_ftype(fattr, dirtype)) {
2894 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2895 return NT_STATUS_FILE_IS_A_DIRECTORY;
2897 return NT_STATUS_NO_SUCH_FILE;
2900 if (dirtype_orig & 0x8000) {
2901 /* These will never be set for POSIX. */
2902 return NT_STATUS_NO_SUCH_FILE;
2905 #if 0
2906 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2907 return NT_STATUS_FILE_IS_A_DIRECTORY;
2910 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2911 return NT_STATUS_NO_SUCH_FILE;
2914 if (dirtype & 0xFF00) {
2915 /* These will never be set for POSIX. */
2916 return NT_STATUS_NO_SUCH_FILE;
2919 dirtype &= 0xFF;
2920 if (!dirtype) {
2921 return NT_STATUS_NO_SUCH_FILE;
2924 /* Can't delete a directory. */
2925 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2926 return NT_STATUS_FILE_IS_A_DIRECTORY;
2928 #endif
2930 #if 0 /* JRATEST */
2931 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2932 return NT_STATUS_OBJECT_NAME_INVALID;
2933 #endif /* JRATEST */
2935 /* On open checks the open itself will check the share mode, so
2936 don't do it here as we'll get it wrong. */
2938 status = SMB_VFS_CREATE_FILE
2939 (conn, /* conn */
2940 req, /* req */
2941 0, /* root_dir_fid */
2942 smb_fname, /* fname */
2943 DELETE_ACCESS, /* access_mask */
2944 FILE_SHARE_NONE, /* share_access */
2945 FILE_OPEN, /* create_disposition*/
2946 FILE_NON_DIRECTORY_FILE, /* create_options */
2947 /* file_attributes */
2948 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2949 FILE_ATTRIBUTE_NORMAL,
2950 0, /* oplock_request */
2951 NULL, /* lease */
2952 0, /* allocation_size */
2953 0, /* private_flags */
2954 NULL, /* sd */
2955 NULL, /* ea_list */
2956 &fsp, /* result */
2957 NULL, /* pinfo */
2958 NULL, NULL); /* create context */
2960 if (!NT_STATUS_IS_OK(status)) {
2961 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2962 nt_errstr(status)));
2963 return status;
2966 status = can_set_delete_on_close(fsp, fattr);
2967 if (!NT_STATUS_IS_OK(status)) {
2968 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2969 "(%s)\n",
2970 smb_fname_str_dbg(smb_fname),
2971 nt_errstr(status)));
2972 close_file(req, fsp, NORMAL_CLOSE);
2973 return status;
2976 /* The set is across all open files on this dev/inode pair. */
2977 if (!set_delete_on_close(fsp, True,
2978 conn->session_info->security_token,
2979 conn->session_info->unix_token)) {
2980 close_file(req, fsp, NORMAL_CLOSE);
2981 return NT_STATUS_ACCESS_DENIED;
2984 return close_file(req, fsp, NORMAL_CLOSE);
2987 /****************************************************************************
2988 The guts of the unlink command, split out so it may be called by the NT SMB
2989 code.
2990 ****************************************************************************/
2992 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2993 uint32_t dirtype, struct smb_filename *smb_fname,
2994 bool has_wild)
2996 char *fname_dir = NULL;
2997 char *fname_mask = NULL;
2998 int count=0;
2999 NTSTATUS status = NT_STATUS_OK;
3000 struct smb_filename *smb_fname_dir = NULL;
3001 TALLOC_CTX *ctx = talloc_tos();
3003 /* Split up the directory from the filename/mask. */
3004 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3005 &fname_dir, &fname_mask);
3006 if (!NT_STATUS_IS_OK(status)) {
3007 goto out;
3011 * We should only check the mangled cache
3012 * here if unix_convert failed. This means
3013 * that the path in 'mask' doesn't exist
3014 * on the file system and so we need to look
3015 * for a possible mangle. This patch from
3016 * Tine Smukavec <valentin.smukavec@hermes.si>.
3019 if (!VALID_STAT(smb_fname->st) &&
3020 mangle_is_mangled(fname_mask, conn->params)) {
3021 char *new_mask = NULL;
3022 mangle_lookup_name_from_8_3(ctx, fname_mask,
3023 &new_mask, conn->params);
3024 if (new_mask) {
3025 TALLOC_FREE(fname_mask);
3026 fname_mask = new_mask;
3030 if (!has_wild) {
3033 * Only one file needs to be unlinked. Append the mask back
3034 * onto the directory.
3036 TALLOC_FREE(smb_fname->base_name);
3037 if (ISDOT(fname_dir)) {
3038 /* Ensure we use canonical names on open. */
3039 smb_fname->base_name = talloc_asprintf(smb_fname,
3040 "%s",
3041 fname_mask);
3042 } else {
3043 smb_fname->base_name = talloc_asprintf(smb_fname,
3044 "%s/%s",
3045 fname_dir,
3046 fname_mask);
3048 if (!smb_fname->base_name) {
3049 status = NT_STATUS_NO_MEMORY;
3050 goto out;
3052 if (dirtype == 0) {
3053 dirtype = FILE_ATTRIBUTE_NORMAL;
3056 status = check_name(conn, smb_fname);
3057 if (!NT_STATUS_IS_OK(status)) {
3058 goto out;
3061 status = do_unlink(conn, req, smb_fname, dirtype);
3062 if (!NT_STATUS_IS_OK(status)) {
3063 goto out;
3066 count++;
3067 } else {
3068 struct smb_Dir *dir_hnd = NULL;
3069 long offset = 0;
3070 const char *dname = NULL;
3071 char *talloced = NULL;
3073 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3074 status = NT_STATUS_OBJECT_NAME_INVALID;
3075 goto out;
3077 if (dirtype == 0) {
3078 dirtype = FILE_ATTRIBUTE_NORMAL;
3081 if (strequal(fname_mask,"????????.???")) {
3082 TALLOC_FREE(fname_mask);
3083 fname_mask = talloc_strdup(ctx, "*");
3084 if (!fname_mask) {
3085 status = NT_STATUS_NO_MEMORY;
3086 goto out;
3090 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3091 fname_dir,
3092 NULL,
3093 NULL,
3094 smb_fname->flags);
3095 if (smb_fname_dir == NULL) {
3096 status = NT_STATUS_NO_MEMORY;
3097 goto out;
3100 status = check_name(conn, smb_fname_dir);
3101 if (!NT_STATUS_IS_OK(status)) {
3102 goto out;
3105 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3106 dirtype);
3107 if (dir_hnd == NULL) {
3108 status = map_nt_error_from_unix(errno);
3109 goto out;
3112 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3113 the pattern matches against the long name, otherwise the short name
3114 We don't implement this yet XXXX
3117 status = NT_STATUS_NO_SUCH_FILE;
3119 while ((dname = ReadDirName(dir_hnd, &offset,
3120 &smb_fname->st, &talloced))) {
3121 TALLOC_CTX *frame = talloc_stackframe();
3123 if (!is_visible_file(conn, fname_dir, dname,
3124 &smb_fname->st, true)) {
3125 TALLOC_FREE(frame);
3126 TALLOC_FREE(talloced);
3127 continue;
3130 /* Quick check for "." and ".." */
3131 if (ISDOT(dname) || ISDOTDOT(dname)) {
3132 TALLOC_FREE(frame);
3133 TALLOC_FREE(talloced);
3134 continue;
3137 if(!mask_match(dname, fname_mask,
3138 conn->case_sensitive)) {
3139 TALLOC_FREE(frame);
3140 TALLOC_FREE(talloced);
3141 continue;
3144 TALLOC_FREE(smb_fname->base_name);
3145 if (ISDOT(fname_dir)) {
3146 /* Ensure we use canonical names on open. */
3147 smb_fname->base_name =
3148 talloc_asprintf(smb_fname, "%s",
3149 dname);
3150 } else {
3151 smb_fname->base_name =
3152 talloc_asprintf(smb_fname, "%s/%s",
3153 fname_dir, dname);
3156 if (!smb_fname->base_name) {
3157 TALLOC_FREE(dir_hnd);
3158 status = NT_STATUS_NO_MEMORY;
3159 TALLOC_FREE(frame);
3160 TALLOC_FREE(talloced);
3161 goto out;
3164 status = check_name(conn, smb_fname);
3165 if (!NT_STATUS_IS_OK(status)) {
3166 TALLOC_FREE(dir_hnd);
3167 TALLOC_FREE(frame);
3168 TALLOC_FREE(talloced);
3169 goto out;
3172 status = do_unlink(conn, req, smb_fname, dirtype);
3173 if (!NT_STATUS_IS_OK(status)) {
3174 TALLOC_FREE(dir_hnd);
3175 TALLOC_FREE(frame);
3176 TALLOC_FREE(talloced);
3177 goto out;
3180 count++;
3181 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3182 smb_fname->base_name));
3184 TALLOC_FREE(frame);
3185 TALLOC_FREE(talloced);
3187 TALLOC_FREE(dir_hnd);
3190 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3191 status = map_nt_error_from_unix(errno);
3194 out:
3195 TALLOC_FREE(smb_fname_dir);
3196 TALLOC_FREE(fname_dir);
3197 TALLOC_FREE(fname_mask);
3198 return status;
3201 /****************************************************************************
3202 Reply to a unlink
3203 ****************************************************************************/
3205 void reply_unlink(struct smb_request *req)
3207 connection_struct *conn = req->conn;
3208 char *name = NULL;
3209 struct smb_filename *smb_fname = NULL;
3210 uint32_t dirtype;
3211 NTSTATUS status;
3212 bool path_contains_wcard = False;
3213 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3214 ucf_flags_from_smb_request(req);
3215 TALLOC_CTX *ctx = talloc_tos();
3217 START_PROFILE(SMBunlink);
3219 if (req->wct < 1) {
3220 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3221 goto out;
3224 dirtype = SVAL(req->vwv+0, 0);
3226 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3227 STR_TERMINATE, &status,
3228 &path_contains_wcard);
3229 if (!NT_STATUS_IS_OK(status)) {
3230 reply_nterror(req, status);
3231 goto out;
3234 status = filename_convert(ctx, conn,
3235 name,
3236 ucf_flags,
3237 &path_contains_wcard,
3238 &smb_fname);
3239 if (!NT_STATUS_IS_OK(status)) {
3240 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3241 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3242 ERRSRV, ERRbadpath);
3243 goto out;
3245 reply_nterror(req, status);
3246 goto out;
3249 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3251 status = unlink_internals(conn, req, dirtype, smb_fname,
3252 path_contains_wcard);
3253 if (!NT_STATUS_IS_OK(status)) {
3254 if (open_was_deferred(req->xconn, req->mid)) {
3255 /* We have re-scheduled this call. */
3256 goto out;
3258 reply_nterror(req, status);
3259 goto out;
3262 reply_outbuf(req, 0, 0);
3263 out:
3264 TALLOC_FREE(smb_fname);
3265 END_PROFILE(SMBunlink);
3266 return;
3269 /****************************************************************************
3270 Fail for readbraw.
3271 ****************************************************************************/
3273 static void fail_readraw(void)
3275 const char *errstr = talloc_asprintf(talloc_tos(),
3276 "FAIL ! reply_readbraw: socket write fail (%s)",
3277 strerror(errno));
3278 if (!errstr) {
3279 errstr = "";
3281 exit_server_cleanly(errstr);
3284 /****************************************************************************
3285 Fake (read/write) sendfile. Returns -1 on read or write fail.
3286 ****************************************************************************/
3288 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3289 off_t startpos, size_t nread)
3291 size_t bufsize;
3292 size_t tosend = nread;
3293 char *buf;
3295 if (nread == 0) {
3296 return 0;
3299 bufsize = MIN(nread, 65536);
3301 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3302 return -1;
3305 while (tosend > 0) {
3306 ssize_t ret;
3307 size_t cur_read;
3309 cur_read = MIN(tosend, bufsize);
3310 ret = read_file(fsp,buf,startpos,cur_read);
3311 if (ret == -1) {
3312 SAFE_FREE(buf);
3313 return -1;
3316 /* If we had a short read, fill with zeros. */
3317 if (ret < cur_read) {
3318 memset(buf + ret, '\0', cur_read - ret);
3321 ret = write_data(xconn->transport.sock, buf, cur_read);
3322 if (ret != cur_read) {
3323 int saved_errno = errno;
3325 * Try and give an error message saying what
3326 * client failed.
3328 DEBUG(0, ("write_data failed for client %s. "
3329 "Error %s\n",
3330 smbXsrv_connection_dbg(xconn),
3331 strerror(saved_errno)));
3332 SAFE_FREE(buf);
3333 errno = saved_errno;
3334 return -1;
3336 tosend -= cur_read;
3337 startpos += cur_read;
3340 SAFE_FREE(buf);
3341 return (ssize_t)nread;
3344 /****************************************************************************
3345 Deal with the case of sendfile reading less bytes from the file than
3346 requested. Fill with zeros (all we can do). Returns 0 on success
3347 ****************************************************************************/
3349 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3350 files_struct *fsp,
3351 ssize_t nread,
3352 size_t headersize,
3353 size_t smb_maxcnt)
3355 #define SHORT_SEND_BUFSIZE 1024
3356 if (nread < headersize) {
3357 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3358 "header for file %s (%s). Terminating\n",
3359 fsp_str_dbg(fsp), strerror(errno)));
3360 return -1;
3363 nread -= headersize;
3365 if (nread < smb_maxcnt) {
3366 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3367 if (!buf) {
3368 DEBUG(0,("sendfile_short_send: malloc failed "
3369 "for file %s (%s). Terminating\n",
3370 fsp_str_dbg(fsp), strerror(errno)));
3371 return -1;
3374 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3375 "with zeros !\n", fsp_str_dbg(fsp)));
3377 while (nread < smb_maxcnt) {
3379 * We asked for the real file size and told sendfile
3380 * to not go beyond the end of the file. But it can
3381 * happen that in between our fstat call and the
3382 * sendfile call the file was truncated. This is very
3383 * bad because we have already announced the larger
3384 * number of bytes to the client.
3386 * The best we can do now is to send 0-bytes, just as
3387 * a read from a hole in a sparse file would do.
3389 * This should happen rarely enough that I don't care
3390 * about efficiency here :-)
3392 size_t to_write;
3393 ssize_t ret;
3395 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3396 ret = write_data(xconn->transport.sock, buf, to_write);
3397 if (ret != to_write) {
3398 int saved_errno = errno;
3400 * Try and give an error message saying what
3401 * client failed.
3403 DEBUG(0, ("write_data failed for client %s. "
3404 "Error %s\n",
3405 smbXsrv_connection_dbg(xconn),
3406 strerror(saved_errno)));
3407 errno = saved_errno;
3408 return -1;
3410 nread += to_write;
3412 SAFE_FREE(buf);
3415 return 0;
3418 /****************************************************************************
3419 Return a readbraw error (4 bytes of zero).
3420 ****************************************************************************/
3422 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3424 char header[4];
3426 SIVAL(header,0,0);
3428 smbd_lock_socket(xconn);
3429 if (write_data(xconn->transport.sock,header,4) != 4) {
3430 int saved_errno = errno;
3432 * Try and give an error message saying what
3433 * client failed.
3435 DEBUG(0, ("write_data failed for client %s. "
3436 "Error %s\n",
3437 smbXsrv_connection_dbg(xconn),
3438 strerror(saved_errno)));
3439 errno = saved_errno;
3441 fail_readraw();
3443 smbd_unlock_socket(xconn);
3446 /****************************************************************************
3447 Use sendfile in readbraw.
3448 ****************************************************************************/
3450 static void send_file_readbraw(connection_struct *conn,
3451 struct smb_request *req,
3452 files_struct *fsp,
3453 off_t startpos,
3454 size_t nread,
3455 ssize_t mincount)
3457 struct smbXsrv_connection *xconn = req->xconn;
3458 char *outbuf = NULL;
3459 ssize_t ret=0;
3462 * We can only use sendfile on a non-chained packet
3463 * but we can use on a non-oplocked file. tridge proved this
3464 * on a train in Germany :-). JRA.
3465 * reply_readbraw has already checked the length.
3468 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3469 (fsp->wcp == NULL) &&
3470 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3471 ssize_t sendfile_read = -1;
3472 char header[4];
3473 DATA_BLOB header_blob;
3475 _smb_setlen(header,nread);
3476 header_blob = data_blob_const(header, 4);
3478 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3479 &header_blob, startpos,
3480 nread);
3481 if (sendfile_read == -1) {
3482 /* Returning ENOSYS means no data at all was sent.
3483 * Do this as a normal read. */
3484 if (errno == ENOSYS) {
3485 goto normal_readbraw;
3489 * Special hack for broken Linux with no working sendfile. If we
3490 * return EINTR we sent the header but not the rest of the data.
3491 * Fake this up by doing read/write calls.
3493 if (errno == EINTR) {
3494 /* Ensure we don't do this again. */
3495 set_use_sendfile(SNUM(conn), False);
3496 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3498 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3499 DEBUG(0,("send_file_readbraw: "
3500 "fake_sendfile failed for "
3501 "file %s (%s).\n",
3502 fsp_str_dbg(fsp),
3503 strerror(errno)));
3504 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3506 return;
3509 DEBUG(0,("send_file_readbraw: sendfile failed for "
3510 "file %s (%s). Terminating\n",
3511 fsp_str_dbg(fsp), strerror(errno)));
3512 exit_server_cleanly("send_file_readbraw sendfile failed");
3513 } else if (sendfile_read == 0) {
3515 * Some sendfile implementations return 0 to indicate
3516 * that there was a short read, but nothing was
3517 * actually written to the socket. In this case,
3518 * fallback to the normal read path so the header gets
3519 * the correct byte count.
3521 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3522 "bytes falling back to the normal read: "
3523 "%s\n", fsp_str_dbg(fsp)));
3524 goto normal_readbraw;
3527 /* Deal with possible short send. */
3528 if (sendfile_read != 4+nread) {
3529 ret = sendfile_short_send(xconn, fsp,
3530 sendfile_read, 4, nread);
3531 if (ret == -1) {
3532 fail_readraw();
3535 return;
3538 normal_readbraw:
3540 outbuf = talloc_array(NULL, char, nread+4);
3541 if (!outbuf) {
3542 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3543 (unsigned)(nread+4)));
3544 reply_readbraw_error(xconn);
3545 return;
3548 if (nread > 0) {
3549 ret = read_file(fsp,outbuf+4,startpos,nread);
3550 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3551 if (ret < mincount)
3552 ret = 0;
3553 #else
3554 if (ret < nread)
3555 ret = 0;
3556 #endif
3559 _smb_setlen(outbuf,ret);
3560 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3561 int saved_errno = errno;
3563 * Try and give an error message saying what
3564 * client failed.
3566 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3567 smbXsrv_connection_dbg(xconn),
3568 strerror(saved_errno)));
3569 errno = saved_errno;
3571 fail_readraw();
3574 TALLOC_FREE(outbuf);
3577 /****************************************************************************
3578 Reply to a readbraw (core+ protocol).
3579 ****************************************************************************/
3581 void reply_readbraw(struct smb_request *req)
3583 connection_struct *conn = req->conn;
3584 struct smbXsrv_connection *xconn = req->xconn;
3585 ssize_t maxcount,mincount;
3586 size_t nread = 0;
3587 off_t startpos;
3588 files_struct *fsp;
3589 struct lock_struct lock;
3590 off_t size = 0;
3592 START_PROFILE(SMBreadbraw);
3594 if (srv_is_signing_active(xconn) || req->encrypted) {
3595 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3596 "raw reads/writes are disallowed.");
3599 if (req->wct < 8) {
3600 reply_readbraw_error(xconn);
3601 END_PROFILE(SMBreadbraw);
3602 return;
3605 if (xconn->smb1.echo_handler.trusted_fde) {
3606 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3607 "'async smb echo handler = yes'\n"));
3608 reply_readbraw_error(xconn);
3609 END_PROFILE(SMBreadbraw);
3610 return;
3614 * Special check if an oplock break has been issued
3615 * and the readraw request croses on the wire, we must
3616 * return a zero length response here.
3619 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3622 * We have to do a check_fsp by hand here, as
3623 * we must always return 4 zero bytes on error,
3624 * not a NTSTATUS.
3627 if (!fsp || !conn || conn != fsp->conn ||
3628 req->vuid != fsp->vuid ||
3629 fsp->is_directory || fsp->fh->fd == -1) {
3631 * fsp could be NULL here so use the value from the packet. JRA.
3633 DEBUG(3,("reply_readbraw: fnum %d not valid "
3634 "- cache prime?\n",
3635 (int)SVAL(req->vwv+0, 0)));
3636 reply_readbraw_error(xconn);
3637 END_PROFILE(SMBreadbraw);
3638 return;
3641 /* Do a "by hand" version of CHECK_READ. */
3642 if (!(fsp->can_read ||
3643 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3644 (fsp->access_mask & FILE_EXECUTE)))) {
3645 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3646 (int)SVAL(req->vwv+0, 0)));
3647 reply_readbraw_error(xconn);
3648 END_PROFILE(SMBreadbraw);
3649 return;
3652 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3654 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3655 if(req->wct == 10) {
3657 * This is a large offset (64 bit) read.
3660 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3662 if(startpos < 0) {
3663 DEBUG(0,("reply_readbraw: negative 64 bit "
3664 "readraw offset (%.0f) !\n",
3665 (double)startpos ));
3666 reply_readbraw_error(xconn);
3667 END_PROFILE(SMBreadbraw);
3668 return;
3672 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3673 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3675 /* ensure we don't overrun the packet size */
3676 maxcount = MIN(65535,maxcount);
3678 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3679 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3680 &lock);
3682 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3683 reply_readbraw_error(xconn);
3684 END_PROFILE(SMBreadbraw);
3685 return;
3688 if (fsp_stat(fsp) == 0) {
3689 size = fsp->fsp_name->st.st_ex_size;
3692 if (startpos >= size) {
3693 nread = 0;
3694 } else {
3695 nread = MIN(maxcount,(size - startpos));
3698 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3699 if (nread < mincount)
3700 nread = 0;
3701 #endif
3703 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3704 "min=%lu nread=%lu\n",
3705 fsp_fnum_dbg(fsp), (double)startpos,
3706 (unsigned long)maxcount,
3707 (unsigned long)mincount,
3708 (unsigned long)nread ) );
3710 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3712 DEBUG(5,("reply_readbraw finished\n"));
3714 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3716 END_PROFILE(SMBreadbraw);
3717 return;
3720 #undef DBGC_CLASS
3721 #define DBGC_CLASS DBGC_LOCKING
3723 /****************************************************************************
3724 Reply to a lockread (core+ protocol).
3725 ****************************************************************************/
3727 void reply_lockread(struct smb_request *req)
3729 connection_struct *conn = req->conn;
3730 ssize_t nread = -1;
3731 char *data;
3732 off_t startpos;
3733 size_t numtoread;
3734 size_t maxtoread;
3735 NTSTATUS status;
3736 files_struct *fsp;
3737 struct byte_range_lock *br_lck = NULL;
3738 char *p = NULL;
3739 struct smbXsrv_connection *xconn = req->xconn;
3741 START_PROFILE(SMBlockread);
3743 if (req->wct < 5) {
3744 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3745 END_PROFILE(SMBlockread);
3746 return;
3749 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3751 if (!check_fsp(conn, req, fsp)) {
3752 END_PROFILE(SMBlockread);
3753 return;
3756 if (!CHECK_READ(fsp,req)) {
3757 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3758 END_PROFILE(SMBlockread);
3759 return;
3762 numtoread = SVAL(req->vwv+1, 0);
3763 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3766 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3767 * protocol request that predates the read/write lock concept.
3768 * Thus instead of asking for a read lock here we need to ask
3769 * for a write lock. JRA.
3770 * Note that the requested lock size is unaffected by max_send.
3773 br_lck = do_lock(req->sconn->msg_ctx,
3774 fsp,
3775 (uint64_t)req->smbpid,
3776 (uint64_t)numtoread,
3777 (uint64_t)startpos,
3778 WRITE_LOCK,
3779 WINDOWS_LOCK,
3780 False, /* Non-blocking lock. */
3781 &status,
3782 NULL);
3783 TALLOC_FREE(br_lck);
3785 if (NT_STATUS_V(status)) {
3786 reply_nterror(req, status);
3787 END_PROFILE(SMBlockread);
3788 return;
3792 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3794 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3796 if (numtoread > maxtoread) {
3797 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3798 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3799 (unsigned int)numtoread, (unsigned int)maxtoread,
3800 (unsigned int)xconn->smb1.sessions.max_send));
3801 numtoread = maxtoread;
3804 reply_outbuf(req, 5, numtoread + 3);
3806 data = smb_buf(req->outbuf) + 3;
3808 nread = read_file(fsp,data,startpos,numtoread);
3810 if (nread < 0) {
3811 reply_nterror(req, map_nt_error_from_unix(errno));
3812 END_PROFILE(SMBlockread);
3813 return;
3816 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3818 SSVAL(req->outbuf,smb_vwv0,nread);
3819 SSVAL(req->outbuf,smb_vwv5,nread+3);
3820 p = smb_buf(req->outbuf);
3821 SCVAL(p,0,0); /* pad byte. */
3822 SSVAL(p,1,nread);
3824 DEBUG(3,("lockread %s num=%d nread=%d\n",
3825 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3827 END_PROFILE(SMBlockread);
3828 return;
3831 #undef DBGC_CLASS
3832 #define DBGC_CLASS DBGC_ALL
3834 /****************************************************************************
3835 Reply to a read.
3836 ****************************************************************************/
3838 void reply_read(struct smb_request *req)
3840 connection_struct *conn = req->conn;
3841 size_t numtoread;
3842 size_t maxtoread;
3843 ssize_t nread = 0;
3844 char *data;
3845 off_t startpos;
3846 files_struct *fsp;
3847 struct lock_struct lock;
3848 struct smbXsrv_connection *xconn = req->xconn;
3850 START_PROFILE(SMBread);
3852 if (req->wct < 3) {
3853 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3854 END_PROFILE(SMBread);
3855 return;
3858 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3860 if (!check_fsp(conn, req, fsp)) {
3861 END_PROFILE(SMBread);
3862 return;
3865 if (!CHECK_READ(fsp,req)) {
3866 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3867 END_PROFILE(SMBread);
3868 return;
3871 numtoread = SVAL(req->vwv+1, 0);
3872 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3875 * The requested read size cannot be greater than max_send. JRA.
3877 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3879 if (numtoread > maxtoread) {
3880 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3881 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3882 (unsigned int)numtoread, (unsigned int)maxtoread,
3883 (unsigned int)xconn->smb1.sessions.max_send));
3884 numtoread = maxtoread;
3887 reply_outbuf(req, 5, numtoread+3);
3889 data = smb_buf(req->outbuf) + 3;
3891 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3892 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3893 &lock);
3895 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3896 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3897 END_PROFILE(SMBread);
3898 return;
3901 if (numtoread > 0)
3902 nread = read_file(fsp,data,startpos,numtoread);
3904 if (nread < 0) {
3905 reply_nterror(req, map_nt_error_from_unix(errno));
3906 goto strict_unlock;
3909 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3911 SSVAL(req->outbuf,smb_vwv0,nread);
3912 SSVAL(req->outbuf,smb_vwv5,nread+3);
3913 SCVAL(smb_buf(req->outbuf),0,1);
3914 SSVAL(smb_buf(req->outbuf),1,nread);
3916 DEBUG(3, ("read %s num=%d nread=%d\n",
3917 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3919 strict_unlock:
3920 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3922 END_PROFILE(SMBread);
3923 return;
3926 /****************************************************************************
3927 Setup readX header.
3928 ****************************************************************************/
3930 int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3932 int outsize;
3934 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3935 False);
3937 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3939 SCVAL(outbuf,smb_vwv0,0xFF);
3940 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3941 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3942 SSVAL(outbuf,smb_vwv6,
3943 (smb_wct - 4) /* offset from smb header to wct */
3944 + 1 /* the wct field */
3945 + 12 * sizeof(uint16_t) /* vwv */
3946 + 2 /* the buflen field */
3947 + 1); /* padding byte */
3948 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3949 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3950 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3951 _smb_setlen_large(outbuf,
3952 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3953 return outsize;
3956 /****************************************************************************
3957 Reply to a read and X - possibly using sendfile.
3958 ****************************************************************************/
3960 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3961 files_struct *fsp, off_t startpos,
3962 size_t smb_maxcnt)
3964 struct smbXsrv_connection *xconn = req->xconn;
3965 ssize_t nread = -1;
3966 struct lock_struct lock;
3967 int saved_errno = 0;
3969 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3970 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3971 &lock);
3973 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3974 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3975 return;
3979 * We can only use sendfile on a non-chained packet
3980 * but we can use on a non-oplocked file. tridge proved this
3981 * on a train in Germany :-). JRA.
3984 if (!req_is_in_chain(req) &&
3985 !req->encrypted &&
3986 (fsp->base_fsp == NULL) &&
3987 (fsp->wcp == NULL) &&
3988 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3989 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3990 DATA_BLOB header;
3992 if(fsp_stat(fsp) == -1) {
3993 reply_nterror(req, map_nt_error_from_unix(errno));
3994 goto strict_unlock;
3997 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3998 (startpos > fsp->fsp_name->st.st_ex_size) ||
3999 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4001 * We already know that we would do a short read, so don't
4002 * try the sendfile() path.
4004 goto nosendfile_read;
4008 * Set up the packet header before send. We
4009 * assume here the sendfile will work (get the
4010 * correct amount of data).
4013 header = data_blob_const(headerbuf, sizeof(headerbuf));
4015 construct_reply_common_req(req, (char *)headerbuf);
4016 setup_readX_header((char *)headerbuf, smb_maxcnt);
4018 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4019 startpos, smb_maxcnt);
4020 if (nread == -1) {
4021 saved_errno = errno;
4023 /* Returning ENOSYS means no data at all was sent.
4024 Do this as a normal read. */
4025 if (errno == ENOSYS) {
4026 goto normal_read;
4030 * Special hack for broken Linux with no working sendfile. If we
4031 * return EINTR we sent the header but not the rest of the data.
4032 * Fake this up by doing read/write calls.
4035 if (errno == EINTR) {
4036 /* Ensure we don't do this again. */
4037 set_use_sendfile(SNUM(conn), False);
4038 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4039 nread = fake_sendfile(xconn, fsp, startpos,
4040 smb_maxcnt);
4041 if (nread == -1) {
4042 saved_errno = errno;
4043 DEBUG(0,("send_file_readX: "
4044 "fake_sendfile failed for "
4045 "file %s (%s) for client %s. "
4046 "Terminating\n",
4047 fsp_str_dbg(fsp),
4048 smbXsrv_connection_dbg(xconn),
4049 strerror(saved_errno)));
4050 errno = saved_errno;
4051 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4053 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4054 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4055 /* No outbuf here means successful sendfile. */
4056 goto strict_unlock;
4059 DEBUG(0,("send_file_readX: sendfile failed for file "
4060 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4061 strerror(errno)));
4062 exit_server_cleanly("send_file_readX sendfile failed");
4063 } else if (nread == 0) {
4065 * Some sendfile implementations return 0 to indicate
4066 * that there was a short read, but nothing was
4067 * actually written to the socket. In this case,
4068 * fallback to the normal read path so the header gets
4069 * the correct byte count.
4071 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4072 "falling back to the normal read: %s\n",
4073 fsp_str_dbg(fsp)));
4074 goto normal_read;
4077 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4078 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4080 /* Deal with possible short send. */
4081 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4082 ssize_t ret;
4084 ret = sendfile_short_send(xconn, fsp, nread,
4085 sizeof(headerbuf), smb_maxcnt);
4086 if (ret == -1) {
4087 const char *r;
4088 r = "send_file_readX: sendfile_short_send failed";
4089 DEBUG(0,("%s for file %s (%s).\n",
4090 r, fsp_str_dbg(fsp), strerror(errno)));
4091 exit_server_cleanly(r);
4094 /* No outbuf here means successful sendfile. */
4095 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4096 SMB_PERFCOUNT_END(&req->pcd);
4097 goto strict_unlock;
4100 normal_read:
4102 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4103 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4104 ssize_t ret;
4106 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4107 (startpos > fsp->fsp_name->st.st_ex_size) ||
4108 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4110 * We already know that we would do a short
4111 * read, so don't try the sendfile() path.
4113 goto nosendfile_read;
4116 construct_reply_common_req(req, (char *)headerbuf);
4117 setup_readX_header((char *)headerbuf, smb_maxcnt);
4119 /* Send out the header. */
4120 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4121 sizeof(headerbuf));
4122 if (ret != sizeof(headerbuf)) {
4123 saved_errno = errno;
4125 * Try and give an error message saying what
4126 * client failed.
4128 DEBUG(0,("send_file_readX: write_data failed for file "
4129 "%s (%s) for client %s. Terminating\n",
4130 fsp_str_dbg(fsp),
4131 smbXsrv_connection_dbg(xconn),
4132 strerror(saved_errno)));
4133 errno = saved_errno;
4134 exit_server_cleanly("send_file_readX sendfile failed");
4136 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4137 if (nread == -1) {
4138 saved_errno = errno;
4139 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4140 "%s (%s) for client %s. Terminating\n",
4141 fsp_str_dbg(fsp),
4142 smbXsrv_connection_dbg(xconn),
4143 strerror(saved_errno)));
4144 errno = saved_errno;
4145 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4147 goto strict_unlock;
4150 nosendfile_read:
4152 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4153 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4154 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4156 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4157 startpos, smb_maxcnt);
4158 saved_errno = errno;
4160 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4162 if (nread < 0) {
4163 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4164 return;
4167 setup_readX_header((char *)req->outbuf, nread);
4169 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4170 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4171 return;
4173 strict_unlock:
4174 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4175 TALLOC_FREE(req->outbuf);
4176 return;
4179 /****************************************************************************
4180 Work out how much space we have for a read return.
4181 ****************************************************************************/
4183 static size_t calc_max_read_pdu(const struct smb_request *req)
4185 struct smbXsrv_connection *xconn = req->xconn;
4187 if (xconn->protocol < PROTOCOL_NT1) {
4188 return xconn->smb1.sessions.max_send;
4191 if (!lp_large_readwrite()) {
4192 return xconn->smb1.sessions.max_send;
4195 if (req_is_in_chain(req)) {
4196 return xconn->smb1.sessions.max_send;
4199 if (req->encrypted) {
4201 * Don't take encrypted traffic up to the
4202 * limit. There are padding considerations
4203 * that make that tricky.
4205 return xconn->smb1.sessions.max_send;
4208 if (srv_is_signing_active(xconn)) {
4209 return 0x1FFFF;
4212 if (!lp_unix_extensions()) {
4213 return 0x1FFFF;
4217 * We can do ultra-large POSIX reads.
4219 return 0xFFFFFF;
4222 /****************************************************************************
4223 Calculate how big a read can be. Copes with all clients. It's always
4224 safe to return a short read - Windows does this.
4225 ****************************************************************************/
4227 static size_t calc_read_size(const struct smb_request *req,
4228 size_t upper_size,
4229 size_t lower_size)
4231 struct smbXsrv_connection *xconn = req->xconn;
4232 size_t max_pdu = calc_max_read_pdu(req);
4233 size_t total_size = 0;
4234 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4235 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4238 * Windows explicitly ignores upper size of 0xFFFF.
4239 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4240 * We must do the same as these will never fit even in
4241 * an extended size NetBIOS packet.
4243 if (upper_size == 0xFFFF) {
4244 upper_size = 0;
4247 if (xconn->protocol < PROTOCOL_NT1) {
4248 upper_size = 0;
4251 total_size = ((upper_size<<16) | lower_size);
4254 * LARGE_READX test shows it's always safe to return
4255 * a short read. Windows does so.
4257 return MIN(total_size, max_len);
4260 /****************************************************************************
4261 Reply to a read and X.
4262 ****************************************************************************/
4264 void reply_read_and_X(struct smb_request *req)
4266 connection_struct *conn = req->conn;
4267 files_struct *fsp;
4268 off_t startpos;
4269 size_t smb_maxcnt;
4270 size_t upper_size;
4271 bool big_readX = False;
4272 #if 0
4273 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4274 #endif
4276 START_PROFILE(SMBreadX);
4278 if ((req->wct != 10) && (req->wct != 12)) {
4279 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4280 return;
4283 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4284 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4285 smb_maxcnt = SVAL(req->vwv+5, 0);
4287 /* If it's an IPC, pass off the pipe handler. */
4288 if (IS_IPC(conn)) {
4289 reply_pipe_read_and_X(req);
4290 END_PROFILE(SMBreadX);
4291 return;
4294 if (!check_fsp(conn, req, fsp)) {
4295 END_PROFILE(SMBreadX);
4296 return;
4299 if (!CHECK_READ(fsp,req)) {
4300 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4301 END_PROFILE(SMBreadX);
4302 return;
4305 upper_size = SVAL(req->vwv+7, 0);
4306 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4307 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4309 * This is a heuristic to avoid keeping large
4310 * outgoing buffers around over long-lived aio
4311 * requests.
4313 big_readX = True;
4316 if (req->wct == 12) {
4318 * This is a large offset (64 bit) read.
4320 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4324 if (!big_readX) {
4325 NTSTATUS status = schedule_aio_read_and_X(conn,
4326 req,
4327 fsp,
4328 startpos,
4329 smb_maxcnt);
4330 if (NT_STATUS_IS_OK(status)) {
4331 /* Read scheduled - we're done. */
4332 goto out;
4334 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4335 /* Real error - report to client. */
4336 END_PROFILE(SMBreadX);
4337 reply_nterror(req, status);
4338 return;
4340 /* NT_STATUS_RETRY - fall back to sync read. */
4343 smbd_lock_socket(req->xconn);
4344 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4345 smbd_unlock_socket(req->xconn);
4347 out:
4348 END_PROFILE(SMBreadX);
4349 return;
4352 /****************************************************************************
4353 Error replies to writebraw must have smb_wct == 1. Fix this up.
4354 ****************************************************************************/
4356 void error_to_writebrawerr(struct smb_request *req)
4358 uint8_t *old_outbuf = req->outbuf;
4360 reply_outbuf(req, 1, 0);
4362 memcpy(req->outbuf, old_outbuf, smb_size);
4363 TALLOC_FREE(old_outbuf);
4366 /****************************************************************************
4367 Read 4 bytes of a smb packet and return the smb length of the packet.
4368 Store the result in the buffer. This version of the function will
4369 never return a session keepalive (length of zero).
4370 Timeout is in milliseconds.
4371 ****************************************************************************/
4373 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4374 size_t *len)
4376 uint8_t msgtype = NBSSkeepalive;
4378 while (msgtype == NBSSkeepalive) {
4379 NTSTATUS status;
4381 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4382 len);
4383 if (!NT_STATUS_IS_OK(status)) {
4384 char addr[INET6_ADDRSTRLEN];
4385 /* Try and give an error message
4386 * saying what client failed. */
4387 DEBUG(0, ("read_fd_with_timeout failed for "
4388 "client %s read error = %s.\n",
4389 get_peer_addr(fd,addr,sizeof(addr)),
4390 nt_errstr(status)));
4391 return status;
4394 msgtype = CVAL(inbuf, 0);
4397 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4398 (unsigned long)len));
4400 return NT_STATUS_OK;
4403 /****************************************************************************
4404 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4405 ****************************************************************************/
4407 void reply_writebraw(struct smb_request *req)
4409 connection_struct *conn = req->conn;
4410 struct smbXsrv_connection *xconn = req->xconn;
4411 char *buf = NULL;
4412 ssize_t nwritten=0;
4413 ssize_t total_written=0;
4414 size_t numtowrite=0;
4415 size_t tcount;
4416 off_t startpos;
4417 const char *data=NULL;
4418 bool write_through;
4419 files_struct *fsp;
4420 struct lock_struct lock;
4421 NTSTATUS status;
4423 START_PROFILE(SMBwritebraw);
4426 * If we ever reply with an error, it must have the SMB command
4427 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4428 * we're finished.
4430 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4432 if (srv_is_signing_active(xconn)) {
4433 END_PROFILE(SMBwritebraw);
4434 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4435 "raw reads/writes are disallowed.");
4438 if (req->wct < 12) {
4439 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4440 error_to_writebrawerr(req);
4441 END_PROFILE(SMBwritebraw);
4442 return;
4445 if (xconn->smb1.echo_handler.trusted_fde) {
4446 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4447 "'async smb echo handler = yes'\n"));
4448 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4449 error_to_writebrawerr(req);
4450 END_PROFILE(SMBwritebraw);
4451 return;
4454 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4455 if (!check_fsp(conn, req, fsp)) {
4456 error_to_writebrawerr(req);
4457 END_PROFILE(SMBwritebraw);
4458 return;
4461 if (!CHECK_WRITE(fsp)) {
4462 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4463 error_to_writebrawerr(req);
4464 END_PROFILE(SMBwritebraw);
4465 return;
4468 tcount = IVAL(req->vwv+1, 0);
4469 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4470 write_through = BITSETW(req->vwv+7,0);
4472 /* We have to deal with slightly different formats depending
4473 on whether we are using the core+ or lanman1.0 protocol */
4475 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4476 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4477 data = smb_buf_const(req->inbuf);
4478 } else {
4479 numtowrite = SVAL(req->vwv+10, 0);
4480 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4483 /* Ensure we don't write bytes past the end of this packet. */
4484 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4485 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4486 error_to_writebrawerr(req);
4487 END_PROFILE(SMBwritebraw);
4488 return;
4491 if (!fsp->print_file) {
4492 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4493 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4494 &lock);
4496 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4497 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4498 error_to_writebrawerr(req);
4499 END_PROFILE(SMBwritebraw);
4500 return;
4504 if (numtowrite>0) {
4505 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4508 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4509 "wrote=%d sync=%d\n",
4510 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4511 (int)nwritten, (int)write_through));
4513 if (nwritten < (ssize_t)numtowrite) {
4514 reply_nterror(req, NT_STATUS_DISK_FULL);
4515 error_to_writebrawerr(req);
4516 goto strict_unlock;
4519 total_written = nwritten;
4521 /* Allocate a buffer of 64k + length. */
4522 buf = talloc_array(NULL, char, 65540);
4523 if (!buf) {
4524 reply_nterror(req, NT_STATUS_NO_MEMORY);
4525 error_to_writebrawerr(req);
4526 goto strict_unlock;
4529 /* Return a SMBwritebraw message to the redirector to tell
4530 * it to send more bytes */
4532 memcpy(buf, req->inbuf, smb_size);
4533 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4534 SCVAL(buf,smb_com,SMBwritebraw);
4535 SSVALS(buf,smb_vwv0,0xFFFF);
4536 show_msg(buf);
4537 if (!srv_send_smb(req->xconn,
4538 buf,
4539 false, 0, /* no signing */
4540 IS_CONN_ENCRYPTED(conn),
4541 &req->pcd)) {
4542 exit_server_cleanly("reply_writebraw: srv_send_smb "
4543 "failed.");
4546 /* Now read the raw data into the buffer and write it */
4547 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4548 &numtowrite);
4549 if (!NT_STATUS_IS_OK(status)) {
4550 exit_server_cleanly("secondary writebraw failed");
4553 /* Set up outbuf to return the correct size */
4554 reply_outbuf(req, 1, 0);
4556 if (numtowrite != 0) {
4558 if (numtowrite > 0xFFFF) {
4559 DEBUG(0,("reply_writebraw: Oversize secondary write "
4560 "raw requested (%u). Terminating\n",
4561 (unsigned int)numtowrite ));
4562 exit_server_cleanly("secondary writebraw failed");
4565 if (tcount > nwritten+numtowrite) {
4566 DEBUG(3,("reply_writebraw: Client overestimated the "
4567 "write %d %d %d\n",
4568 (int)tcount,(int)nwritten,(int)numtowrite));
4571 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4572 numtowrite);
4574 if (!NT_STATUS_IS_OK(status)) {
4575 /* Try and give an error message
4576 * saying what client failed. */
4577 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4578 "raw read failed (%s) for client %s. "
4579 "Terminating\n", nt_errstr(status),
4580 smbXsrv_connection_dbg(xconn)));
4581 exit_server_cleanly("secondary writebraw failed");
4584 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4585 if (nwritten == -1) {
4586 TALLOC_FREE(buf);
4587 reply_nterror(req, map_nt_error_from_unix(errno));
4588 error_to_writebrawerr(req);
4589 goto strict_unlock;
4592 if (nwritten < (ssize_t)numtowrite) {
4593 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4594 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4597 if (nwritten > 0) {
4598 total_written += nwritten;
4602 TALLOC_FREE(buf);
4603 SSVAL(req->outbuf,smb_vwv0,total_written);
4605 status = sync_file(conn, fsp, write_through);
4606 if (!NT_STATUS_IS_OK(status)) {
4607 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4608 fsp_str_dbg(fsp), nt_errstr(status)));
4609 reply_nterror(req, status);
4610 error_to_writebrawerr(req);
4611 goto strict_unlock;
4614 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4615 "wrote=%d\n",
4616 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4617 (int)total_written));
4619 if (!fsp->print_file) {
4620 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4623 /* We won't return a status if write through is not selected - this
4624 * follows what WfWg does */
4625 END_PROFILE(SMBwritebraw);
4627 if (!write_through && total_written==tcount) {
4629 #if RABBIT_PELLET_FIX
4631 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4632 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4633 * JRA.
4635 if (!send_keepalive(xconn->transport.sock)) {
4636 exit_server_cleanly("reply_writebraw: send of "
4637 "keepalive failed");
4639 #endif
4640 TALLOC_FREE(req->outbuf);
4642 return;
4644 strict_unlock:
4645 if (!fsp->print_file) {
4646 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4649 END_PROFILE(SMBwritebraw);
4650 return;
4653 #undef DBGC_CLASS
4654 #define DBGC_CLASS DBGC_LOCKING
4656 /****************************************************************************
4657 Reply to a writeunlock (core+).
4658 ****************************************************************************/
4660 void reply_writeunlock(struct smb_request *req)
4662 connection_struct *conn = req->conn;
4663 ssize_t nwritten = -1;
4664 size_t numtowrite;
4665 off_t startpos;
4666 const char *data;
4667 NTSTATUS status = NT_STATUS_OK;
4668 files_struct *fsp;
4669 struct lock_struct lock;
4670 int saved_errno = 0;
4672 START_PROFILE(SMBwriteunlock);
4674 if (req->wct < 5) {
4675 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4676 END_PROFILE(SMBwriteunlock);
4677 return;
4680 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4682 if (!check_fsp(conn, req, fsp)) {
4683 END_PROFILE(SMBwriteunlock);
4684 return;
4687 if (!CHECK_WRITE(fsp)) {
4688 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4689 END_PROFILE(SMBwriteunlock);
4690 return;
4693 numtowrite = SVAL(req->vwv+1, 0);
4694 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4695 data = (const char *)req->buf + 3;
4697 if (!fsp->print_file && numtowrite > 0) {
4698 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4699 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4700 &lock);
4702 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4703 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4704 END_PROFILE(SMBwriteunlock);
4705 return;
4709 /* The special X/Open SMB protocol handling of
4710 zero length writes is *NOT* done for
4711 this call */
4712 if(numtowrite == 0) {
4713 nwritten = 0;
4714 } else {
4715 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4716 saved_errno = errno;
4719 status = sync_file(conn, fsp, False /* write through */);
4720 if (!NT_STATUS_IS_OK(status)) {
4721 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4722 fsp_str_dbg(fsp), nt_errstr(status)));
4723 reply_nterror(req, status);
4724 goto strict_unlock;
4727 if(nwritten < 0) {
4728 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4729 goto strict_unlock;
4732 if((nwritten < numtowrite) && (numtowrite != 0)) {
4733 reply_nterror(req, NT_STATUS_DISK_FULL);
4734 goto strict_unlock;
4737 if (numtowrite && !fsp->print_file) {
4738 status = do_unlock(req->sconn->msg_ctx,
4739 fsp,
4740 (uint64_t)req->smbpid,
4741 (uint64_t)numtowrite,
4742 (uint64_t)startpos,
4743 WINDOWS_LOCK);
4745 if (NT_STATUS_V(status)) {
4746 reply_nterror(req, status);
4747 goto strict_unlock;
4751 reply_outbuf(req, 1, 0);
4753 SSVAL(req->outbuf,smb_vwv0,nwritten);
4755 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4756 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4758 strict_unlock:
4759 if (numtowrite && !fsp->print_file) {
4760 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4763 END_PROFILE(SMBwriteunlock);
4764 return;
4767 #undef DBGC_CLASS
4768 #define DBGC_CLASS DBGC_ALL
4770 /****************************************************************************
4771 Reply to a write.
4772 ****************************************************************************/
4774 void reply_write(struct smb_request *req)
4776 connection_struct *conn = req->conn;
4777 size_t numtowrite;
4778 ssize_t nwritten = -1;
4779 off_t startpos;
4780 const char *data;
4781 files_struct *fsp;
4782 struct lock_struct lock;
4783 NTSTATUS status;
4784 int saved_errno = 0;
4786 START_PROFILE(SMBwrite);
4788 if (req->wct < 5) {
4789 END_PROFILE(SMBwrite);
4790 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4791 return;
4794 /* If it's an IPC, pass off the pipe handler. */
4795 if (IS_IPC(conn)) {
4796 reply_pipe_write(req);
4797 END_PROFILE(SMBwrite);
4798 return;
4801 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4803 if (!check_fsp(conn, req, fsp)) {
4804 END_PROFILE(SMBwrite);
4805 return;
4808 if (!CHECK_WRITE(fsp)) {
4809 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4810 END_PROFILE(SMBwrite);
4811 return;
4814 numtowrite = SVAL(req->vwv+1, 0);
4815 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4816 data = (const char *)req->buf + 3;
4818 if (!fsp->print_file) {
4819 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4820 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4821 &lock);
4823 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4824 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4825 END_PROFILE(SMBwrite);
4826 return;
4831 * X/Open SMB protocol says that if smb_vwv1 is
4832 * zero then the file size should be extended or
4833 * truncated to the size given in smb_vwv[2-3].
4836 if(numtowrite == 0) {
4838 * This is actually an allocate call, and set EOF. JRA.
4840 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4841 if (nwritten < 0) {
4842 reply_nterror(req, NT_STATUS_DISK_FULL);
4843 goto strict_unlock;
4845 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4846 if (nwritten < 0) {
4847 reply_nterror(req, NT_STATUS_DISK_FULL);
4848 goto strict_unlock;
4850 trigger_write_time_update_immediate(fsp);
4851 } else {
4852 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4855 status = sync_file(conn, fsp, False);
4856 if (!NT_STATUS_IS_OK(status)) {
4857 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4858 fsp_str_dbg(fsp), nt_errstr(status)));
4859 reply_nterror(req, status);
4860 goto strict_unlock;
4863 if(nwritten < 0) {
4864 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4865 goto strict_unlock;
4868 if((nwritten == 0) && (numtowrite != 0)) {
4869 reply_nterror(req, NT_STATUS_DISK_FULL);
4870 goto strict_unlock;
4873 reply_outbuf(req, 1, 0);
4875 SSVAL(req->outbuf,smb_vwv0,nwritten);
4877 if (nwritten < (ssize_t)numtowrite) {
4878 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4879 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4882 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4884 strict_unlock:
4885 if (!fsp->print_file) {
4886 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4889 END_PROFILE(SMBwrite);
4890 return;
4893 /****************************************************************************
4894 Ensure a buffer is a valid writeX for recvfile purposes.
4895 ****************************************************************************/
4897 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4898 (2*14) + /* word count (including bcc) */ \
4899 1 /* pad byte */)
4901 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4902 const uint8_t *inbuf)
4904 size_t numtowrite;
4905 unsigned int doff = 0;
4906 size_t len = smb_len_large(inbuf);
4907 uint16_t fnum;
4908 struct smbXsrv_open *op = NULL;
4909 struct files_struct *fsp = NULL;
4910 NTSTATUS status;
4912 if (is_encrypted_packet(inbuf)) {
4913 /* Can't do this on encrypted
4914 * connections. */
4915 return false;
4918 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4919 return false;
4922 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4923 CVAL(inbuf,smb_wct) != 14) {
4924 DEBUG(10,("is_valid_writeX_buffer: chained or "
4925 "invalid word length.\n"));
4926 return false;
4929 fnum = SVAL(inbuf, smb_vwv2);
4930 status = smb1srv_open_lookup(xconn,
4931 fnum,
4932 0, /* now */
4933 &op);
4934 if (!NT_STATUS_IS_OK(status)) {
4935 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4936 return false;
4938 fsp = op->compat;
4939 if (fsp == NULL) {
4940 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4941 return false;
4943 if (fsp->conn == NULL) {
4944 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4945 return false;
4948 if (IS_IPC(fsp->conn)) {
4949 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4950 return false;
4952 if (IS_PRINT(fsp->conn)) {
4953 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4954 return false;
4956 doff = SVAL(inbuf,smb_vwv11);
4958 numtowrite = SVAL(inbuf,smb_vwv10);
4960 if (len > doff && len - doff > 0xFFFF) {
4961 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4964 if (numtowrite == 0) {
4965 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4966 return false;
4969 /* Ensure the sizes match up. */
4970 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4971 /* no pad byte...old smbclient :-( */
4972 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4973 (unsigned int)doff,
4974 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4975 return false;
4978 if (len - doff != numtowrite) {
4979 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4980 "len = %u, doff = %u, numtowrite = %u\n",
4981 (unsigned int)len,
4982 (unsigned int)doff,
4983 (unsigned int)numtowrite ));
4984 return false;
4987 DEBUG(10,("is_valid_writeX_buffer: true "
4988 "len = %u, doff = %u, numtowrite = %u\n",
4989 (unsigned int)len,
4990 (unsigned int)doff,
4991 (unsigned int)numtowrite ));
4993 return true;
4996 /****************************************************************************
4997 Reply to a write and X.
4998 ****************************************************************************/
5000 void reply_write_and_X(struct smb_request *req)
5002 connection_struct *conn = req->conn;
5003 struct smbXsrv_connection *xconn = req->xconn;
5004 files_struct *fsp;
5005 struct lock_struct lock;
5006 off_t startpos;
5007 size_t numtowrite;
5008 bool write_through;
5009 ssize_t nwritten;
5010 unsigned int smb_doff;
5011 unsigned int smblen;
5012 const char *data;
5013 NTSTATUS status;
5014 int saved_errno = 0;
5016 START_PROFILE(SMBwriteX);
5018 if ((req->wct != 12) && (req->wct != 14)) {
5019 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5020 goto out;
5023 numtowrite = SVAL(req->vwv+10, 0);
5024 smb_doff = SVAL(req->vwv+11, 0);
5025 smblen = smb_len(req->inbuf);
5027 if (req->unread_bytes > 0xFFFF ||
5028 (smblen > smb_doff &&
5029 smblen - smb_doff > 0xFFFF)) {
5030 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5033 if (req->unread_bytes) {
5034 /* Can't do a recvfile write on IPC$ */
5035 if (IS_IPC(conn)) {
5036 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5037 goto out;
5039 if (numtowrite != req->unread_bytes) {
5040 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5041 goto out;
5043 } else {
5044 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5045 smb_doff + numtowrite > smblen) {
5046 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5047 goto out;
5051 /* If it's an IPC, pass off the pipe handler. */
5052 if (IS_IPC(conn)) {
5053 if (req->unread_bytes) {
5054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5055 goto out;
5057 reply_pipe_write_and_X(req);
5058 goto out;
5061 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5062 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5063 write_through = BITSETW(req->vwv+7,0);
5065 if (!check_fsp(conn, req, fsp)) {
5066 goto out;
5069 if (!CHECK_WRITE(fsp)) {
5070 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5071 goto out;
5074 data = smb_base(req->inbuf) + smb_doff;
5076 if(req->wct == 14) {
5078 * This is a large offset (64 bit) write.
5080 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5084 /* X/Open SMB protocol says that, unlike SMBwrite
5085 if the length is zero then NO truncation is
5086 done, just a write of zero. To truncate a file,
5087 use SMBwrite. */
5089 if(numtowrite == 0) {
5090 nwritten = 0;
5091 } else {
5092 if (req->unread_bytes == 0) {
5093 status = schedule_aio_write_and_X(conn,
5094 req,
5095 fsp,
5096 data,
5097 startpos,
5098 numtowrite);
5100 if (NT_STATUS_IS_OK(status)) {
5101 /* write scheduled - we're done. */
5102 goto out;
5104 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5105 /* Real error - report to client. */
5106 reply_nterror(req, status);
5107 goto out;
5109 /* NT_STATUS_RETRY - fall through to sync write. */
5112 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5113 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5114 &lock);
5116 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5117 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5118 goto out;
5121 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5122 saved_errno = errno;
5124 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5127 if(nwritten < 0) {
5128 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5129 goto out;
5132 if((nwritten == 0) && (numtowrite != 0)) {
5133 reply_nterror(req, NT_STATUS_DISK_FULL);
5134 goto out;
5137 reply_outbuf(req, 6, 0);
5138 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5139 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5140 SSVAL(req->outbuf,smb_vwv2,nwritten);
5141 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5143 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5144 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5146 status = sync_file(conn, fsp, write_through);
5147 if (!NT_STATUS_IS_OK(status)) {
5148 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5149 fsp_str_dbg(fsp), nt_errstr(status)));
5150 reply_nterror(req, status);
5151 goto out;
5154 END_PROFILE(SMBwriteX);
5155 return;
5157 out:
5158 if (req->unread_bytes) {
5159 /* writeX failed. drain socket. */
5160 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5161 req->unread_bytes) {
5162 smb_panic("failed to drain pending bytes");
5164 req->unread_bytes = 0;
5167 END_PROFILE(SMBwriteX);
5168 return;
5171 /****************************************************************************
5172 Reply to a lseek.
5173 ****************************************************************************/
5175 void reply_lseek(struct smb_request *req)
5177 connection_struct *conn = req->conn;
5178 off_t startpos;
5179 off_t res= -1;
5180 int mode,umode;
5181 files_struct *fsp;
5183 START_PROFILE(SMBlseek);
5185 if (req->wct < 4) {
5186 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5187 END_PROFILE(SMBlseek);
5188 return;
5191 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5193 if (!check_fsp(conn, req, fsp)) {
5194 return;
5197 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5199 mode = SVAL(req->vwv+1, 0) & 3;
5200 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5201 startpos = (off_t)IVALS(req->vwv+2, 0);
5203 switch (mode) {
5204 case 0:
5205 umode = SEEK_SET;
5206 res = startpos;
5207 break;
5208 case 1:
5209 umode = SEEK_CUR;
5210 res = fsp->fh->pos + startpos;
5211 break;
5212 case 2:
5213 umode = SEEK_END;
5214 break;
5215 default:
5216 umode = SEEK_SET;
5217 res = startpos;
5218 break;
5221 if (umode == SEEK_END) {
5222 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5223 if(errno == EINVAL) {
5224 off_t current_pos = startpos;
5226 if(fsp_stat(fsp) == -1) {
5227 reply_nterror(req,
5228 map_nt_error_from_unix(errno));
5229 END_PROFILE(SMBlseek);
5230 return;
5233 current_pos += fsp->fsp_name->st.st_ex_size;
5234 if(current_pos < 0)
5235 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5239 if(res == -1) {
5240 reply_nterror(req, map_nt_error_from_unix(errno));
5241 END_PROFILE(SMBlseek);
5242 return;
5246 fsp->fh->pos = res;
5248 reply_outbuf(req, 2, 0);
5249 SIVAL(req->outbuf,smb_vwv0,res);
5251 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5252 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5254 END_PROFILE(SMBlseek);
5255 return;
5258 /****************************************************************************
5259 Reply to a flush.
5260 ****************************************************************************/
5262 void reply_flush(struct smb_request *req)
5264 connection_struct *conn = req->conn;
5265 uint16_t fnum;
5266 files_struct *fsp;
5268 START_PROFILE(SMBflush);
5270 if (req->wct < 1) {
5271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5272 return;
5275 fnum = SVAL(req->vwv+0, 0);
5276 fsp = file_fsp(req, fnum);
5278 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5279 return;
5282 if (!fsp) {
5283 file_sync_all(conn);
5284 } else {
5285 NTSTATUS status = sync_file(conn, fsp, True);
5286 if (!NT_STATUS_IS_OK(status)) {
5287 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5288 fsp_str_dbg(fsp), nt_errstr(status)));
5289 reply_nterror(req, status);
5290 END_PROFILE(SMBflush);
5291 return;
5295 reply_outbuf(req, 0, 0);
5297 DEBUG(3,("flush\n"));
5298 END_PROFILE(SMBflush);
5299 return;
5302 /****************************************************************************
5303 Reply to a exit.
5304 conn POINTER CAN BE NULL HERE !
5305 ****************************************************************************/
5307 void reply_exit(struct smb_request *req)
5309 START_PROFILE(SMBexit);
5311 file_close_pid(req->sconn, req->smbpid, req->vuid);
5313 reply_outbuf(req, 0, 0);
5315 DEBUG(3,("exit\n"));
5317 END_PROFILE(SMBexit);
5318 return;
5321 struct reply_close_state {
5322 files_struct *fsp;
5323 struct smb_request *smbreq;
5326 static void do_smb1_close(struct tevent_req *req);
5328 void reply_close(struct smb_request *req)
5330 connection_struct *conn = req->conn;
5331 NTSTATUS status = NT_STATUS_OK;
5332 files_struct *fsp = NULL;
5333 START_PROFILE(SMBclose);
5335 if (req->wct < 3) {
5336 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5337 END_PROFILE(SMBclose);
5338 return;
5341 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5344 * We can only use check_fsp if we know it's not a directory.
5347 if (!check_fsp_open(conn, req, fsp)) {
5348 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5349 END_PROFILE(SMBclose);
5350 return;
5353 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5354 fsp->is_directory ? "directory" : "file",
5355 fsp->fh->fd, fsp_fnum_dbg(fsp),
5356 conn->num_files_open));
5358 if (!fsp->is_directory) {
5359 time_t t;
5362 * Take care of any time sent in the close.
5365 t = srv_make_unix_date3(req->vwv+1);
5366 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5369 if (fsp->num_aio_requests != 0) {
5371 struct reply_close_state *state;
5373 DEBUG(10, ("closing with aio %u requests pending\n",
5374 fsp->num_aio_requests));
5377 * We depend on the aio_extra destructor to take care of this
5378 * close request once fsp->num_aio_request drops to 0.
5381 fsp->deferred_close = tevent_wait_send(
5382 fsp, fsp->conn->sconn->ev_ctx);
5383 if (fsp->deferred_close == NULL) {
5384 status = NT_STATUS_NO_MEMORY;
5385 goto done;
5388 state = talloc(fsp, struct reply_close_state);
5389 if (state == NULL) {
5390 TALLOC_FREE(fsp->deferred_close);
5391 status = NT_STATUS_NO_MEMORY;
5392 goto done;
5394 state->fsp = fsp;
5395 state->smbreq = talloc_move(fsp, &req);
5396 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5397 state);
5398 END_PROFILE(SMBclose);
5399 return;
5403 * close_file() returns the unix errno if an error was detected on
5404 * close - normally this is due to a disk full error. If not then it
5405 * was probably an I/O error.
5408 status = close_file(req, fsp, NORMAL_CLOSE);
5409 done:
5410 if (!NT_STATUS_IS_OK(status)) {
5411 reply_nterror(req, status);
5412 END_PROFILE(SMBclose);
5413 return;
5416 reply_outbuf(req, 0, 0);
5417 END_PROFILE(SMBclose);
5418 return;
5421 static void do_smb1_close(struct tevent_req *req)
5423 struct reply_close_state *state = tevent_req_callback_data(
5424 req, struct reply_close_state);
5425 struct smb_request *smbreq;
5426 NTSTATUS status;
5427 int ret;
5429 ret = tevent_wait_recv(req);
5430 TALLOC_FREE(req);
5431 if (ret != 0) {
5432 DEBUG(10, ("tevent_wait_recv returned %s\n",
5433 strerror(ret)));
5435 * Continue anyway, this should never happen
5440 * fsp->smb2_close_request right now is a talloc grandchild of
5441 * fsp. When we close_file(fsp), it would go with it. No chance to
5442 * reply...
5444 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5446 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5447 if (NT_STATUS_IS_OK(status)) {
5448 reply_outbuf(smbreq, 0, 0);
5449 } else {
5450 reply_nterror(smbreq, status);
5452 if (!srv_send_smb(smbreq->xconn,
5453 (char *)smbreq->outbuf,
5454 true,
5455 smbreq->seqnum+1,
5456 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5457 NULL)) {
5458 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5459 "failed.");
5461 TALLOC_FREE(smbreq);
5464 /****************************************************************************
5465 Reply to a writeclose (Core+ protocol).
5466 ****************************************************************************/
5468 void reply_writeclose(struct smb_request *req)
5470 connection_struct *conn = req->conn;
5471 size_t numtowrite;
5472 ssize_t nwritten = -1;
5473 NTSTATUS close_status = NT_STATUS_OK;
5474 off_t startpos;
5475 const char *data;
5476 struct timespec mtime;
5477 files_struct *fsp;
5478 struct lock_struct lock;
5480 START_PROFILE(SMBwriteclose);
5482 if (req->wct < 6) {
5483 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5484 END_PROFILE(SMBwriteclose);
5485 return;
5488 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5490 if (!check_fsp(conn, req, fsp)) {
5491 END_PROFILE(SMBwriteclose);
5492 return;
5494 if (!CHECK_WRITE(fsp)) {
5495 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5496 END_PROFILE(SMBwriteclose);
5497 return;
5500 numtowrite = SVAL(req->vwv+1, 0);
5501 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5502 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5503 data = (const char *)req->buf + 1;
5505 if (fsp->print_file == NULL) {
5506 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5507 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5508 &lock);
5510 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5511 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5512 END_PROFILE(SMBwriteclose);
5513 return;
5517 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5519 if (fsp->print_file == NULL) {
5520 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5523 set_close_write_time(fsp, mtime);
5526 * More insanity. W2K only closes the file if writelen > 0.
5527 * JRA.
5530 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5531 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5532 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5534 if (numtowrite) {
5535 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5536 "file %s\n", fsp_str_dbg(fsp)));
5537 close_status = close_file(req, fsp, NORMAL_CLOSE);
5538 fsp = NULL;
5541 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5542 reply_nterror(req, NT_STATUS_DISK_FULL);
5543 goto out;
5546 if(!NT_STATUS_IS_OK(close_status)) {
5547 reply_nterror(req, close_status);
5548 goto out;
5551 reply_outbuf(req, 1, 0);
5553 SSVAL(req->outbuf,smb_vwv0,nwritten);
5555 out:
5557 END_PROFILE(SMBwriteclose);
5558 return;
5561 #undef DBGC_CLASS
5562 #define DBGC_CLASS DBGC_LOCKING
5564 /****************************************************************************
5565 Reply to a lock.
5566 ****************************************************************************/
5568 void reply_lock(struct smb_request *req)
5570 connection_struct *conn = req->conn;
5571 uint64_t count,offset;
5572 NTSTATUS status;
5573 files_struct *fsp;
5574 struct byte_range_lock *br_lck = NULL;
5576 START_PROFILE(SMBlock);
5578 if (req->wct < 5) {
5579 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5580 END_PROFILE(SMBlock);
5581 return;
5584 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5586 if (!check_fsp(conn, req, fsp)) {
5587 END_PROFILE(SMBlock);
5588 return;
5591 count = (uint64_t)IVAL(req->vwv+1, 0);
5592 offset = (uint64_t)IVAL(req->vwv+3, 0);
5594 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5595 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5597 br_lck = do_lock(req->sconn->msg_ctx,
5598 fsp,
5599 (uint64_t)req->smbpid,
5600 count,
5601 offset,
5602 WRITE_LOCK,
5603 WINDOWS_LOCK,
5604 False, /* Non-blocking lock. */
5605 &status,
5606 NULL);
5608 TALLOC_FREE(br_lck);
5610 if (NT_STATUS_V(status)) {
5611 reply_nterror(req, status);
5612 END_PROFILE(SMBlock);
5613 return;
5616 reply_outbuf(req, 0, 0);
5618 END_PROFILE(SMBlock);
5619 return;
5622 /****************************************************************************
5623 Reply to a unlock.
5624 ****************************************************************************/
5626 void reply_unlock(struct smb_request *req)
5628 connection_struct *conn = req->conn;
5629 uint64_t count,offset;
5630 NTSTATUS status;
5631 files_struct *fsp;
5633 START_PROFILE(SMBunlock);
5635 if (req->wct < 5) {
5636 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5637 END_PROFILE(SMBunlock);
5638 return;
5641 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5643 if (!check_fsp(conn, req, fsp)) {
5644 END_PROFILE(SMBunlock);
5645 return;
5648 count = (uint64_t)IVAL(req->vwv+1, 0);
5649 offset = (uint64_t)IVAL(req->vwv+3, 0);
5651 status = do_unlock(req->sconn->msg_ctx,
5652 fsp,
5653 (uint64_t)req->smbpid,
5654 count,
5655 offset,
5656 WINDOWS_LOCK);
5658 if (NT_STATUS_V(status)) {
5659 reply_nterror(req, status);
5660 END_PROFILE(SMBunlock);
5661 return;
5664 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5665 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5667 reply_outbuf(req, 0, 0);
5669 END_PROFILE(SMBunlock);
5670 return;
5673 #undef DBGC_CLASS
5674 #define DBGC_CLASS DBGC_ALL
5676 /****************************************************************************
5677 Reply to a tdis.
5678 conn POINTER CAN BE NULL HERE !
5679 ****************************************************************************/
5681 void reply_tdis(struct smb_request *req)
5683 NTSTATUS status;
5684 connection_struct *conn = req->conn;
5685 struct smbXsrv_tcon *tcon;
5687 START_PROFILE(SMBtdis);
5689 if (!conn) {
5690 DEBUG(4,("Invalid connection in tdis\n"));
5691 reply_force_doserror(req, ERRSRV, ERRinvnid);
5692 END_PROFILE(SMBtdis);
5693 return;
5696 tcon = conn->tcon;
5697 req->conn = NULL;
5700 * TODO: cancel all outstanding requests on the tcon
5702 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5703 if (!NT_STATUS_IS_OK(status)) {
5704 DEBUG(0, ("reply_tdis: "
5705 "smbXsrv_tcon_disconnect() failed: %s\n",
5706 nt_errstr(status)));
5708 * If we hit this case, there is something completely
5709 * wrong, so we better disconnect the transport connection.
5711 END_PROFILE(SMBtdis);
5712 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5713 return;
5716 TALLOC_FREE(tcon);
5718 reply_outbuf(req, 0, 0);
5719 END_PROFILE(SMBtdis);
5720 return;
5723 /****************************************************************************
5724 Reply to a echo.
5725 conn POINTER CAN BE NULL HERE !
5726 ****************************************************************************/
5728 void reply_echo(struct smb_request *req)
5730 connection_struct *conn = req->conn;
5731 struct smb_perfcount_data local_pcd;
5732 struct smb_perfcount_data *cur_pcd;
5733 int smb_reverb;
5734 int seq_num;
5736 START_PROFILE(SMBecho);
5738 smb_init_perfcount_data(&local_pcd);
5740 if (req->wct < 1) {
5741 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5742 END_PROFILE(SMBecho);
5743 return;
5746 smb_reverb = SVAL(req->vwv+0, 0);
5748 reply_outbuf(req, 1, req->buflen);
5750 /* copy any incoming data back out */
5751 if (req->buflen > 0) {
5752 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5755 if (smb_reverb > 100) {
5756 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5757 smb_reverb = 100;
5760 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5762 /* this makes sure we catch the request pcd */
5763 if (seq_num == smb_reverb) {
5764 cur_pcd = &req->pcd;
5765 } else {
5766 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5767 cur_pcd = &local_pcd;
5770 SSVAL(req->outbuf,smb_vwv0,seq_num);
5772 show_msg((char *)req->outbuf);
5773 if (!srv_send_smb(req->xconn,
5774 (char *)req->outbuf,
5775 true, req->seqnum+1,
5776 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5777 cur_pcd))
5778 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5781 DEBUG(3,("echo %d times\n", smb_reverb));
5783 TALLOC_FREE(req->outbuf);
5785 END_PROFILE(SMBecho);
5786 return;
5789 /****************************************************************************
5790 Reply to a printopen.
5791 ****************************************************************************/
5793 void reply_printopen(struct smb_request *req)
5795 connection_struct *conn = req->conn;
5796 files_struct *fsp;
5797 NTSTATUS status;
5799 START_PROFILE(SMBsplopen);
5801 if (req->wct < 2) {
5802 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5803 END_PROFILE(SMBsplopen);
5804 return;
5807 if (!CAN_PRINT(conn)) {
5808 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5809 END_PROFILE(SMBsplopen);
5810 return;
5813 status = file_new(req, conn, &fsp);
5814 if(!NT_STATUS_IS_OK(status)) {
5815 reply_nterror(req, status);
5816 END_PROFILE(SMBsplopen);
5817 return;
5820 /* Open for exclusive use, write only. */
5821 status = print_spool_open(fsp, NULL, req->vuid);
5823 if (!NT_STATUS_IS_OK(status)) {
5824 file_free(req, fsp);
5825 reply_nterror(req, status);
5826 END_PROFILE(SMBsplopen);
5827 return;
5830 reply_outbuf(req, 1, 0);
5831 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5833 DEBUG(3,("openprint fd=%d %s\n",
5834 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5836 END_PROFILE(SMBsplopen);
5837 return;
5840 /****************************************************************************
5841 Reply to a printclose.
5842 ****************************************************************************/
5844 void reply_printclose(struct smb_request *req)
5846 connection_struct *conn = req->conn;
5847 files_struct *fsp;
5848 NTSTATUS status;
5850 START_PROFILE(SMBsplclose);
5852 if (req->wct < 1) {
5853 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5854 END_PROFILE(SMBsplclose);
5855 return;
5858 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5860 if (!check_fsp(conn, req, fsp)) {
5861 END_PROFILE(SMBsplclose);
5862 return;
5865 if (!CAN_PRINT(conn)) {
5866 reply_force_doserror(req, ERRSRV, ERRerror);
5867 END_PROFILE(SMBsplclose);
5868 return;
5871 DEBUG(3,("printclose fd=%d %s\n",
5872 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5874 status = close_file(req, fsp, NORMAL_CLOSE);
5876 if(!NT_STATUS_IS_OK(status)) {
5877 reply_nterror(req, status);
5878 END_PROFILE(SMBsplclose);
5879 return;
5882 reply_outbuf(req, 0, 0);
5884 END_PROFILE(SMBsplclose);
5885 return;
5888 /****************************************************************************
5889 Reply to a printqueue.
5890 ****************************************************************************/
5892 void reply_printqueue(struct smb_request *req)
5894 connection_struct *conn = req->conn;
5895 int max_count;
5896 int start_index;
5898 START_PROFILE(SMBsplretq);
5900 if (req->wct < 2) {
5901 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5902 END_PROFILE(SMBsplretq);
5903 return;
5906 max_count = SVAL(req->vwv+0, 0);
5907 start_index = SVAL(req->vwv+1, 0);
5909 /* we used to allow the client to get the cnum wrong, but that
5910 is really quite gross and only worked when there was only
5911 one printer - I think we should now only accept it if they
5912 get it right (tridge) */
5913 if (!CAN_PRINT(conn)) {
5914 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5915 END_PROFILE(SMBsplretq);
5916 return;
5919 reply_outbuf(req, 2, 3);
5920 SSVAL(req->outbuf,smb_vwv0,0);
5921 SSVAL(req->outbuf,smb_vwv1,0);
5922 SCVAL(smb_buf(req->outbuf),0,1);
5923 SSVAL(smb_buf(req->outbuf),1,0);
5925 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5926 start_index, max_count));
5929 TALLOC_CTX *mem_ctx = talloc_tos();
5930 NTSTATUS status;
5931 WERROR werr;
5932 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5933 struct rpc_pipe_client *cli = NULL;
5934 struct dcerpc_binding_handle *b = NULL;
5935 struct policy_handle handle;
5936 struct spoolss_DevmodeContainer devmode_ctr;
5937 union spoolss_JobInfo *info;
5938 uint32_t count;
5939 uint32_t num_to_get;
5940 uint32_t first;
5941 uint32_t i;
5943 ZERO_STRUCT(handle);
5945 status = rpc_pipe_open_interface(conn,
5946 &ndr_table_spoolss,
5947 conn->session_info,
5948 conn->sconn->remote_address,
5949 conn->sconn->local_address,
5950 conn->sconn->msg_ctx,
5951 &cli);
5952 if (!NT_STATUS_IS_OK(status)) {
5953 DEBUG(0, ("reply_printqueue: "
5954 "could not connect to spoolss: %s\n",
5955 nt_errstr(status)));
5956 reply_nterror(req, status);
5957 goto out;
5959 b = cli->binding_handle;
5961 ZERO_STRUCT(devmode_ctr);
5963 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5964 sharename,
5965 NULL, devmode_ctr,
5966 SEC_FLAG_MAXIMUM_ALLOWED,
5967 &handle,
5968 &werr);
5969 if (!NT_STATUS_IS_OK(status)) {
5970 reply_nterror(req, status);
5971 goto out;
5973 if (!W_ERROR_IS_OK(werr)) {
5974 reply_nterror(req, werror_to_ntstatus(werr));
5975 goto out;
5978 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5979 &handle,
5980 0, /* firstjob */
5981 0xff, /* numjobs */
5982 2, /* level */
5983 0, /* offered */
5984 &count,
5985 &info);
5986 if (!W_ERROR_IS_OK(werr)) {
5987 reply_nterror(req, werror_to_ntstatus(werr));
5988 goto out;
5991 if (max_count > 0) {
5992 first = start_index;
5993 } else {
5994 first = start_index + max_count + 1;
5997 if (first >= count) {
5998 num_to_get = first;
5999 } else {
6000 num_to_get = first + MIN(ABS(max_count), count - first);
6003 for (i = first; i < num_to_get; i++) {
6004 char blob[28];
6005 char *p = blob;
6006 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
6007 int qstatus;
6008 size_t len = 0;
6009 uint16_t qrapjobid = pjobid_to_rap(sharename,
6010 info[i].info2.job_id);
6012 if (info[i].info2.status == JOB_STATUS_PRINTING) {
6013 qstatus = 2;
6014 } else {
6015 qstatus = 3;
6018 srv_put_dos_date2(p, 0, qtime);
6019 SCVAL(p, 4, qstatus);
6020 SSVAL(p, 5, qrapjobid);
6021 SIVAL(p, 7, info[i].info2.size);
6022 SCVAL(p, 11, 0);
6023 status = srvstr_push(blob, req->flags2, p+12,
6024 info[i].info2.notify_name, 16, STR_ASCII, &len);
6025 if (!NT_STATUS_IS_OK(status)) {
6026 reply_nterror(req, status);
6027 goto out;
6029 if (message_push_blob(
6030 &req->outbuf,
6031 data_blob_const(
6032 blob, sizeof(blob))) == -1) {
6033 reply_nterror(req, NT_STATUS_NO_MEMORY);
6034 goto out;
6038 if (count > 0) {
6039 SSVAL(req->outbuf,smb_vwv0,count);
6040 SSVAL(req->outbuf,smb_vwv1,
6041 (max_count>0?first+count:first-1));
6042 SCVAL(smb_buf(req->outbuf),0,1);
6043 SSVAL(smb_buf(req->outbuf),1,28*count);
6047 DEBUG(3, ("%u entries returned in queue\n",
6048 (unsigned)count));
6050 out:
6051 if (b && is_valid_policy_hnd(&handle)) {
6052 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6057 END_PROFILE(SMBsplretq);
6058 return;
6061 /****************************************************************************
6062 Reply to a printwrite.
6063 ****************************************************************************/
6065 void reply_printwrite(struct smb_request *req)
6067 connection_struct *conn = req->conn;
6068 int numtowrite;
6069 const char *data;
6070 files_struct *fsp;
6072 START_PROFILE(SMBsplwr);
6074 if (req->wct < 1) {
6075 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6076 END_PROFILE(SMBsplwr);
6077 return;
6080 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6082 if (!check_fsp(conn, req, fsp)) {
6083 END_PROFILE(SMBsplwr);
6084 return;
6087 if (!fsp->print_file) {
6088 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6089 END_PROFILE(SMBsplwr);
6090 return;
6093 if (!CHECK_WRITE(fsp)) {
6094 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6095 END_PROFILE(SMBsplwr);
6096 return;
6099 numtowrite = SVAL(req->buf, 1);
6101 if (req->buflen < numtowrite + 3) {
6102 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6103 END_PROFILE(SMBsplwr);
6104 return;
6107 data = (const char *)req->buf + 3;
6109 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6110 reply_nterror(req, map_nt_error_from_unix(errno));
6111 END_PROFILE(SMBsplwr);
6112 return;
6115 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6117 END_PROFILE(SMBsplwr);
6118 return;
6121 /****************************************************************************
6122 Reply to a mkdir.
6123 ****************************************************************************/
6125 void reply_mkdir(struct smb_request *req)
6127 connection_struct *conn = req->conn;
6128 struct smb_filename *smb_dname = NULL;
6129 char *directory = NULL;
6130 NTSTATUS status;
6131 uint32_t ucf_flags;
6132 TALLOC_CTX *ctx = talloc_tos();
6134 START_PROFILE(SMBmkdir);
6136 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6137 STR_TERMINATE, &status);
6138 if (!NT_STATUS_IS_OK(status)) {
6139 reply_nterror(req, status);
6140 goto out;
6143 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6144 status = filename_convert(ctx, conn,
6145 directory,
6146 ucf_flags,
6147 NULL,
6148 &smb_dname);
6149 if (!NT_STATUS_IS_OK(status)) {
6150 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6151 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6152 ERRSRV, ERRbadpath);
6153 goto out;
6155 reply_nterror(req, status);
6156 goto out;
6159 status = create_directory(conn, req, smb_dname);
6161 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6163 if (!NT_STATUS_IS_OK(status)) {
6165 if (!use_nt_status()
6166 && NT_STATUS_EQUAL(status,
6167 NT_STATUS_OBJECT_NAME_COLLISION)) {
6169 * Yes, in the DOS error code case we get a
6170 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6171 * samba4 torture test.
6173 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6176 reply_nterror(req, status);
6177 goto out;
6180 reply_outbuf(req, 0, 0);
6182 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6183 out:
6184 TALLOC_FREE(smb_dname);
6185 END_PROFILE(SMBmkdir);
6186 return;
6189 /****************************************************************************
6190 Reply to a rmdir.
6191 ****************************************************************************/
6193 void reply_rmdir(struct smb_request *req)
6195 connection_struct *conn = req->conn;
6196 struct smb_filename *smb_dname = NULL;
6197 char *directory = NULL;
6198 NTSTATUS status;
6199 TALLOC_CTX *ctx = talloc_tos();
6200 files_struct *fsp = NULL;
6201 int info = 0;
6202 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6203 struct smbd_server_connection *sconn = req->sconn;
6205 START_PROFILE(SMBrmdir);
6207 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6208 STR_TERMINATE, &status);
6209 if (!NT_STATUS_IS_OK(status)) {
6210 reply_nterror(req, status);
6211 goto out;
6214 status = filename_convert(ctx, conn,
6215 directory,
6216 ucf_flags,
6217 NULL,
6218 &smb_dname);
6219 if (!NT_STATUS_IS_OK(status)) {
6220 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6221 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6222 ERRSRV, ERRbadpath);
6223 goto out;
6225 reply_nterror(req, status);
6226 goto out;
6229 if (is_ntfs_stream_smb_fname(smb_dname)) {
6230 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6231 goto out;
6234 status = SMB_VFS_CREATE_FILE(
6235 conn, /* conn */
6236 req, /* req */
6237 0, /* root_dir_fid */
6238 smb_dname, /* fname */
6239 DELETE_ACCESS, /* access_mask */
6240 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6241 FILE_SHARE_DELETE),
6242 FILE_OPEN, /* create_disposition*/
6243 FILE_DIRECTORY_FILE, /* create_options */
6244 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6245 0, /* oplock_request */
6246 NULL, /* lease */
6247 0, /* allocation_size */
6248 0, /* private_flags */
6249 NULL, /* sd */
6250 NULL, /* ea_list */
6251 &fsp, /* result */
6252 &info, /* pinfo */
6253 NULL, NULL); /* create context */
6255 if (!NT_STATUS_IS_OK(status)) {
6256 if (open_was_deferred(req->xconn, req->mid)) {
6257 /* We have re-scheduled this call. */
6258 goto out;
6260 reply_nterror(req, status);
6261 goto out;
6264 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6265 if (!NT_STATUS_IS_OK(status)) {
6266 close_file(req, fsp, ERROR_CLOSE);
6267 reply_nterror(req, status);
6268 goto out;
6271 if (!set_delete_on_close(fsp, true,
6272 conn->session_info->security_token,
6273 conn->session_info->unix_token)) {
6274 close_file(req, fsp, ERROR_CLOSE);
6275 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6276 goto out;
6279 status = close_file(req, fsp, NORMAL_CLOSE);
6280 if (!NT_STATUS_IS_OK(status)) {
6281 reply_nterror(req, status);
6282 } else {
6283 reply_outbuf(req, 0, 0);
6286 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6288 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6289 out:
6290 TALLOC_FREE(smb_dname);
6291 END_PROFILE(SMBrmdir);
6292 return;
6295 /*******************************************************************
6296 Resolve wildcards in a filename rename.
6297 ********************************************************************/
6299 static bool resolve_wildcards(TALLOC_CTX *ctx,
6300 const char *name1,
6301 const char *name2,
6302 char **pp_newname)
6304 char *name2_copy = NULL;
6305 char *root1 = NULL;
6306 char *root2 = NULL;
6307 char *ext1 = NULL;
6308 char *ext2 = NULL;
6309 char *p,*p2, *pname1, *pname2;
6311 name2_copy = talloc_strdup(ctx, name2);
6312 if (!name2_copy) {
6313 return False;
6316 pname1 = strrchr_m(name1,'/');
6317 pname2 = strrchr_m(name2_copy,'/');
6319 if (!pname1 || !pname2) {
6320 return False;
6323 /* Truncate the copy of name2 at the last '/' */
6324 *pname2 = '\0';
6326 /* Now go past the '/' */
6327 pname1++;
6328 pname2++;
6330 root1 = talloc_strdup(ctx, pname1);
6331 root2 = talloc_strdup(ctx, pname2);
6333 if (!root1 || !root2) {
6334 return False;
6337 p = strrchr_m(root1,'.');
6338 if (p) {
6339 *p = 0;
6340 ext1 = talloc_strdup(ctx, p+1);
6341 } else {
6342 ext1 = talloc_strdup(ctx, "");
6344 p = strrchr_m(root2,'.');
6345 if (p) {
6346 *p = 0;
6347 ext2 = talloc_strdup(ctx, p+1);
6348 } else {
6349 ext2 = talloc_strdup(ctx, "");
6352 if (!ext1 || !ext2) {
6353 return False;
6356 p = root1;
6357 p2 = root2;
6358 while (*p2) {
6359 if (*p2 == '?') {
6360 /* Hmmm. Should this be mb-aware ? */
6361 *p2 = *p;
6362 p2++;
6363 } else if (*p2 == '*') {
6364 *p2 = '\0';
6365 root2 = talloc_asprintf(ctx, "%s%s",
6366 root2,
6368 if (!root2) {
6369 return False;
6371 break;
6372 } else {
6373 p2++;
6375 if (*p) {
6376 p++;
6380 p = ext1;
6381 p2 = ext2;
6382 while (*p2) {
6383 if (*p2 == '?') {
6384 /* Hmmm. Should this be mb-aware ? */
6385 *p2 = *p;
6386 p2++;
6387 } else if (*p2 == '*') {
6388 *p2 = '\0';
6389 ext2 = talloc_asprintf(ctx, "%s%s",
6390 ext2,
6392 if (!ext2) {
6393 return False;
6395 break;
6396 } else {
6397 p2++;
6399 if (*p) {
6400 p++;
6404 if (*ext2) {
6405 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6406 name2_copy,
6407 root2,
6408 ext2);
6409 } else {
6410 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6411 name2_copy,
6412 root2);
6415 if (!*pp_newname) {
6416 return False;
6419 return True;
6422 /****************************************************************************
6423 Ensure open files have their names updated. Updated to notify other smbd's
6424 asynchronously.
6425 ****************************************************************************/
6427 static void rename_open_files(connection_struct *conn,
6428 struct share_mode_lock *lck,
6429 struct file_id id,
6430 uint32_t orig_name_hash,
6431 const struct smb_filename *smb_fname_dst)
6433 files_struct *fsp;
6434 bool did_rename = False;
6435 NTSTATUS status;
6436 uint32_t new_name_hash = 0;
6438 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6439 fsp = file_find_di_next(fsp)) {
6440 /* fsp_name is a relative path under the fsp. To change this for other
6441 sharepaths we need to manipulate relative paths. */
6442 /* TODO - create the absolute path and manipulate the newname
6443 relative to the sharepath. */
6444 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6445 continue;
6447 if (fsp->name_hash != orig_name_hash) {
6448 continue;
6450 DEBUG(10, ("rename_open_files: renaming file %s "
6451 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6452 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6453 smb_fname_str_dbg(smb_fname_dst)));
6455 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6456 if (NT_STATUS_IS_OK(status)) {
6457 did_rename = True;
6458 new_name_hash = fsp->name_hash;
6462 if (!did_rename) {
6463 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6464 "for %s\n", file_id_string_tos(&id),
6465 smb_fname_str_dbg(smb_fname_dst)));
6468 /* Send messages to all smbd's (not ourself) that the name has changed. */
6469 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6470 orig_name_hash, new_name_hash,
6471 smb_fname_dst);
6475 /****************************************************************************
6476 We need to check if the source path is a parent directory of the destination
6477 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6478 refuse the rename with a sharing violation. Under UNIX the above call can
6479 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6480 probably need to check that the client is a Windows one before disallowing
6481 this as a UNIX client (one with UNIX extensions) can know the source is a
6482 symlink and make this decision intelligently. Found by an excellent bug
6483 report from <AndyLiebman@aol.com>.
6484 ****************************************************************************/
6486 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6487 const struct smb_filename *smb_fname_dst)
6489 const char *psrc = smb_fname_src->base_name;
6490 const char *pdst = smb_fname_dst->base_name;
6491 size_t slen;
6493 if (psrc[0] == '.' && psrc[1] == '/') {
6494 psrc += 2;
6496 if (pdst[0] == '.' && pdst[1] == '/') {
6497 pdst += 2;
6499 if ((slen = strlen(psrc)) > strlen(pdst)) {
6500 return False;
6502 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6506 * Do the notify calls from a rename
6509 static void notify_rename(connection_struct *conn, bool is_dir,
6510 const struct smb_filename *smb_fname_src,
6511 const struct smb_filename *smb_fname_dst)
6513 char *parent_dir_src = NULL;
6514 char *parent_dir_dst = NULL;
6515 uint32_t mask;
6517 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6518 : FILE_NOTIFY_CHANGE_FILE_NAME;
6520 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6521 &parent_dir_src, NULL) ||
6522 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6523 &parent_dir_dst, NULL)) {
6524 goto out;
6527 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6528 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6529 smb_fname_src->base_name);
6530 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6531 smb_fname_dst->base_name);
6533 else {
6534 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6535 smb_fname_src->base_name);
6536 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6537 smb_fname_dst->base_name);
6540 /* this is a strange one. w2k3 gives an additional event for
6541 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6542 files, but not directories */
6543 if (!is_dir) {
6544 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6545 FILE_NOTIFY_CHANGE_ATTRIBUTES
6546 |FILE_NOTIFY_CHANGE_CREATION,
6547 smb_fname_dst->base_name);
6549 out:
6550 TALLOC_FREE(parent_dir_src);
6551 TALLOC_FREE(parent_dir_dst);
6554 /****************************************************************************
6555 Returns an error if the parent directory for a filename is open in an
6556 incompatible way.
6557 ****************************************************************************/
6559 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6560 const struct smb_filename *smb_fname_dst_in)
6562 char *parent_dir = NULL;
6563 struct smb_filename smb_fname_parent;
6564 struct file_id id;
6565 files_struct *fsp = NULL;
6566 int ret;
6568 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6569 &parent_dir, NULL)) {
6570 return NT_STATUS_NO_MEMORY;
6572 ZERO_STRUCT(smb_fname_parent);
6573 smb_fname_parent.base_name = parent_dir;
6575 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6576 if (ret == -1) {
6577 return map_nt_error_from_unix(errno);
6581 * We're only checking on this smbd here, mostly good
6582 * enough.. and will pass tests.
6585 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6586 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6587 fsp = file_find_di_next(fsp)) {
6588 if (fsp->access_mask & DELETE_ACCESS) {
6589 return NT_STATUS_SHARING_VIOLATION;
6592 return NT_STATUS_OK;
6595 /****************************************************************************
6596 Rename an open file - given an fsp.
6597 ****************************************************************************/
6599 NTSTATUS rename_internals_fsp(connection_struct *conn,
6600 files_struct *fsp,
6601 const struct smb_filename *smb_fname_dst_in,
6602 uint32_t attrs,
6603 bool replace_if_exists)
6605 TALLOC_CTX *ctx = talloc_tos();
6606 struct smb_filename *smb_fname_dst = NULL;
6607 NTSTATUS status = NT_STATUS_OK;
6608 struct share_mode_lock *lck = NULL;
6609 uint32_t access_mask = SEC_DIR_ADD_FILE;
6610 bool dst_exists, old_is_stream, new_is_stream;
6612 status = check_name(conn, smb_fname_dst_in);
6613 if (!NT_STATUS_IS_OK(status)) {
6614 return status;
6617 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6618 if (!NT_STATUS_IS_OK(status)) {
6619 return status;
6622 /* Make a copy of the dst smb_fname structs */
6624 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6625 if (smb_fname_dst == NULL) {
6626 status = NT_STATUS_NO_MEMORY;
6627 goto out;
6631 * Check for special case with case preserving and not
6632 * case sensitive. If the new last component differs from the original
6633 * last component only by case, then we should allow
6634 * the rename (user is trying to change the case of the
6635 * filename).
6637 if (!conn->case_sensitive && conn->case_preserve &&
6638 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6639 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6640 char *fname_dst_parent = NULL;
6641 const char *fname_dst_lcomp = NULL;
6642 char *orig_lcomp_path = NULL;
6643 char *orig_lcomp_stream = NULL;
6644 bool ok = true;
6647 * Split off the last component of the processed
6648 * destination name. We will compare this to
6649 * the split components of smb_fname_dst->original_lcomp.
6651 if (!parent_dirname(ctx,
6652 smb_fname_dst->base_name,
6653 &fname_dst_parent,
6654 &fname_dst_lcomp)) {
6655 status = NT_STATUS_NO_MEMORY;
6656 goto out;
6660 * The original_lcomp component contains
6661 * the last_component of the path + stream
6662 * name (if a stream exists).
6664 * Split off the stream name so we
6665 * can check them separately.
6668 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6669 /* POSIX - no stream component. */
6670 orig_lcomp_path = talloc_strdup(ctx,
6671 smb_fname_dst->original_lcomp);
6672 if (orig_lcomp_path == NULL) {
6673 ok = false;
6675 } else {
6676 ok = split_stream_filename(ctx,
6677 smb_fname_dst->original_lcomp,
6678 &orig_lcomp_path,
6679 &orig_lcomp_stream);
6682 if (!ok) {
6683 TALLOC_FREE(fname_dst_parent);
6684 status = NT_STATUS_NO_MEMORY;
6685 goto out;
6688 /* If the base names only differ by case, use original. */
6689 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6690 char *tmp;
6692 * Replace the modified last component with the
6693 * original.
6695 if (!ISDOT(fname_dst_parent)) {
6696 tmp = talloc_asprintf(smb_fname_dst,
6697 "%s/%s",
6698 fname_dst_parent,
6699 orig_lcomp_path);
6700 } else {
6701 tmp = talloc_strdup(smb_fname_dst,
6702 orig_lcomp_path);
6704 if (tmp == NULL) {
6705 status = NT_STATUS_NO_MEMORY;
6706 TALLOC_FREE(fname_dst_parent);
6707 TALLOC_FREE(orig_lcomp_path);
6708 TALLOC_FREE(orig_lcomp_stream);
6709 goto out;
6711 TALLOC_FREE(smb_fname_dst->base_name);
6712 smb_fname_dst->base_name = tmp;
6715 /* If the stream_names only differ by case, use original. */
6716 if(!strcsequal(smb_fname_dst->stream_name,
6717 orig_lcomp_stream)) {
6718 /* Use the original stream. */
6719 char *tmp = talloc_strdup(smb_fname_dst,
6720 orig_lcomp_stream);
6721 if (tmp == NULL) {
6722 status = NT_STATUS_NO_MEMORY;
6723 TALLOC_FREE(fname_dst_parent);
6724 TALLOC_FREE(orig_lcomp_path);
6725 TALLOC_FREE(orig_lcomp_stream);
6726 goto out;
6728 TALLOC_FREE(smb_fname_dst->stream_name);
6729 smb_fname_dst->stream_name = tmp;
6731 TALLOC_FREE(fname_dst_parent);
6732 TALLOC_FREE(orig_lcomp_path);
6733 TALLOC_FREE(orig_lcomp_stream);
6737 * If the src and dest names are identical - including case,
6738 * don't do the rename, just return success.
6741 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6742 strcsequal(fsp->fsp_name->stream_name,
6743 smb_fname_dst->stream_name)) {
6744 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6745 "- returning success\n",
6746 smb_fname_str_dbg(smb_fname_dst)));
6747 status = NT_STATUS_OK;
6748 goto out;
6751 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6752 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6754 /* Return the correct error code if both names aren't streams. */
6755 if (!old_is_stream && new_is_stream) {
6756 status = NT_STATUS_OBJECT_NAME_INVALID;
6757 goto out;
6760 if (old_is_stream && !new_is_stream) {
6761 status = NT_STATUS_INVALID_PARAMETER;
6762 goto out;
6765 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6767 if(!replace_if_exists && dst_exists) {
6768 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6769 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6770 smb_fname_str_dbg(smb_fname_dst)));
6771 status = NT_STATUS_OBJECT_NAME_COLLISION;
6772 goto out;
6775 if (dst_exists) {
6776 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6777 &smb_fname_dst->st);
6778 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6779 fileid);
6780 /* The file can be open when renaming a stream */
6781 if (dst_fsp && !new_is_stream) {
6782 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6783 status = NT_STATUS_ACCESS_DENIED;
6784 goto out;
6788 /* Ensure we have a valid stat struct for the source. */
6789 status = vfs_stat_fsp(fsp);
6790 if (!NT_STATUS_IS_OK(status)) {
6791 goto out;
6794 status = can_rename(conn, fsp, attrs);
6796 if (!NT_STATUS_IS_OK(status)) {
6797 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6798 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6799 smb_fname_str_dbg(smb_fname_dst)));
6800 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6801 status = NT_STATUS_ACCESS_DENIED;
6802 goto out;
6805 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6806 status = NT_STATUS_ACCESS_DENIED;
6807 goto out;
6810 /* Do we have rights to move into the destination ? */
6811 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
6812 /* We're moving a directory. */
6813 access_mask = SEC_DIR_ADD_SUBDIR;
6815 status = check_parent_access(conn,
6816 smb_fname_dst,
6817 access_mask);
6818 if (!NT_STATUS_IS_OK(status)) {
6819 DBG_INFO("check_parent_access on "
6820 "dst %s returned %s\n",
6821 smb_fname_str_dbg(smb_fname_dst),
6822 nt_errstr(status));
6823 goto out;
6826 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6829 * We have the file open ourselves, so not being able to get the
6830 * corresponding share mode lock is a fatal error.
6833 SMB_ASSERT(lck != NULL);
6835 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6836 uint32_t create_options = fsp->fh->private_options;
6838 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6839 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6840 smb_fname_str_dbg(smb_fname_dst)));
6842 if (!fsp->is_directory &&
6843 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6844 (lp_map_archive(SNUM(conn)) ||
6845 lp_store_dos_attributes(SNUM(conn)))) {
6846 /* We must set the archive bit on the newly
6847 renamed file. */
6848 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6849 uint32_t old_dosmode = dos_mode(conn,
6850 smb_fname_dst);
6851 file_set_dosmode(conn,
6852 smb_fname_dst,
6853 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6854 NULL,
6855 true);
6859 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6860 smb_fname_dst);
6862 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6863 smb_fname_dst);
6866 * A rename acts as a new file create w.r.t. allowing an initial delete
6867 * on close, probably because in Windows there is a new handle to the
6868 * new file. If initial delete on close was requested but not
6869 * originally set, we need to set it here. This is probably not 100% correct,
6870 * but will work for the CIFSFS client which in non-posix mode
6871 * depends on these semantics. JRA.
6874 if (create_options & FILE_DELETE_ON_CLOSE) {
6875 status = can_set_delete_on_close(fsp, 0);
6877 if (NT_STATUS_IS_OK(status)) {
6878 /* Note that here we set the *inital* delete on close flag,
6879 * not the regular one. The magic gets handled in close. */
6880 fsp->initial_delete_on_close = True;
6883 TALLOC_FREE(lck);
6884 status = NT_STATUS_OK;
6885 goto out;
6888 TALLOC_FREE(lck);
6890 if (errno == ENOTDIR || errno == EISDIR) {
6891 status = NT_STATUS_OBJECT_NAME_COLLISION;
6892 } else {
6893 status = map_nt_error_from_unix(errno);
6896 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6897 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6898 smb_fname_str_dbg(smb_fname_dst)));
6900 out:
6901 TALLOC_FREE(smb_fname_dst);
6903 return status;
6906 /****************************************************************************
6907 The guts of the rename command, split out so it may be called by the NT SMB
6908 code.
6909 ****************************************************************************/
6911 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6912 connection_struct *conn,
6913 struct smb_request *req,
6914 struct smb_filename *smb_fname_src,
6915 struct smb_filename *smb_fname_dst,
6916 uint32_t attrs,
6917 bool replace_if_exists,
6918 bool src_has_wild,
6919 bool dest_has_wild,
6920 uint32_t access_mask)
6922 char *fname_src_dir = NULL;
6923 struct smb_filename *smb_fname_src_dir = NULL;
6924 char *fname_src_mask = NULL;
6925 int count=0;
6926 NTSTATUS status = NT_STATUS_OK;
6927 struct smb_Dir *dir_hnd = NULL;
6928 const char *dname = NULL;
6929 char *talloced = NULL;
6930 long offset = 0;
6931 int create_options = 0;
6932 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6933 int rc;
6936 * Split the old name into directory and last component
6937 * strings. Note that unix_convert may have stripped off a
6938 * leading ./ from both name and newname if the rename is
6939 * at the root of the share. We need to make sure either both
6940 * name and newname contain a / character or neither of them do
6941 * as this is checked in resolve_wildcards().
6944 /* Split up the directory from the filename/mask. */
6945 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6946 &fname_src_dir, &fname_src_mask);
6947 if (!NT_STATUS_IS_OK(status)) {
6948 status = NT_STATUS_NO_MEMORY;
6949 goto out;
6953 * We should only check the mangled cache
6954 * here if unix_convert failed. This means
6955 * that the path in 'mask' doesn't exist
6956 * on the file system and so we need to look
6957 * for a possible mangle. This patch from
6958 * Tine Smukavec <valentin.smukavec@hermes.si>.
6961 if (!VALID_STAT(smb_fname_src->st) &&
6962 mangle_is_mangled(fname_src_mask, conn->params)) {
6963 char *new_mask = NULL;
6964 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6965 conn->params);
6966 if (new_mask) {
6967 TALLOC_FREE(fname_src_mask);
6968 fname_src_mask = new_mask;
6972 if (!src_has_wild) {
6973 files_struct *fsp;
6976 * Only one file needs to be renamed. Append the mask back
6977 * onto the directory.
6979 TALLOC_FREE(smb_fname_src->base_name);
6980 if (ISDOT(fname_src_dir)) {
6981 /* Ensure we use canonical names on open. */
6982 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6983 "%s",
6984 fname_src_mask);
6985 } else {
6986 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6987 "%s/%s",
6988 fname_src_dir,
6989 fname_src_mask);
6991 if (!smb_fname_src->base_name) {
6992 status = NT_STATUS_NO_MEMORY;
6993 goto out;
6996 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6997 "case_preserve = %d, short case preserve = %d, "
6998 "directory = %s, newname = %s, "
6999 "last_component_dest = %s\n",
7000 conn->case_sensitive, conn->case_preserve,
7001 conn->short_case_preserve,
7002 smb_fname_str_dbg(smb_fname_src),
7003 smb_fname_str_dbg(smb_fname_dst),
7004 smb_fname_dst->original_lcomp));
7006 /* The dest name still may have wildcards. */
7007 if (dest_has_wild) {
7008 char *fname_dst_mod = NULL;
7009 if (!resolve_wildcards(smb_fname_dst,
7010 smb_fname_src->base_name,
7011 smb_fname_dst->base_name,
7012 &fname_dst_mod)) {
7013 DEBUG(6, ("rename_internals: resolve_wildcards "
7014 "%s %s failed\n",
7015 smb_fname_src->base_name,
7016 smb_fname_dst->base_name));
7017 status = NT_STATUS_NO_MEMORY;
7018 goto out;
7020 TALLOC_FREE(smb_fname_dst->base_name);
7021 smb_fname_dst->base_name = fname_dst_mod;
7024 ZERO_STRUCT(smb_fname_src->st);
7025 if (posix_pathnames) {
7026 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
7027 } else {
7028 rc = SMB_VFS_STAT(conn, smb_fname_src);
7030 if (rc == -1) {
7031 status = map_nt_error_from_unix_common(errno);
7032 goto out;
7035 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7036 create_options |= FILE_DIRECTORY_FILE;
7039 status = SMB_VFS_CREATE_FILE(
7040 conn, /* conn */
7041 req, /* req */
7042 0, /* root_dir_fid */
7043 smb_fname_src, /* fname */
7044 access_mask, /* access_mask */
7045 (FILE_SHARE_READ | /* share_access */
7046 FILE_SHARE_WRITE),
7047 FILE_OPEN, /* create_disposition*/
7048 create_options, /* create_options */
7049 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7050 0, /* oplock_request */
7051 NULL, /* lease */
7052 0, /* allocation_size */
7053 0, /* private_flags */
7054 NULL, /* sd */
7055 NULL, /* ea_list */
7056 &fsp, /* result */
7057 NULL, /* pinfo */
7058 NULL, NULL); /* create context */
7060 if (!NT_STATUS_IS_OK(status)) {
7061 DEBUG(3, ("Could not open rename source %s: %s\n",
7062 smb_fname_str_dbg(smb_fname_src),
7063 nt_errstr(status)));
7064 goto out;
7067 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7068 attrs, replace_if_exists);
7070 close_file(req, fsp, NORMAL_CLOSE);
7072 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7073 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7074 smb_fname_str_dbg(smb_fname_dst)));
7076 goto out;
7080 * Wildcards - process each file that matches.
7082 if (strequal(fname_src_mask, "????????.???")) {
7083 TALLOC_FREE(fname_src_mask);
7084 fname_src_mask = talloc_strdup(ctx, "*");
7085 if (!fname_src_mask) {
7086 status = NT_STATUS_NO_MEMORY;
7087 goto out;
7091 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7092 fname_src_dir,
7093 NULL,
7094 NULL,
7095 smb_fname_src->flags);
7096 if (smb_fname_src_dir == NULL) {
7097 status = NT_STATUS_NO_MEMORY;
7098 goto out;
7101 status = check_name(conn, smb_fname_src_dir);
7102 if (!NT_STATUS_IS_OK(status)) {
7103 goto out;
7106 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7107 attrs);
7108 if (dir_hnd == NULL) {
7109 status = map_nt_error_from_unix(errno);
7110 goto out;
7113 status = NT_STATUS_NO_SUCH_FILE;
7115 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7116 * - gentest fix. JRA
7119 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7120 &talloced))) {
7121 files_struct *fsp = NULL;
7122 char *destname = NULL;
7123 bool sysdir_entry = False;
7125 /* Quick check for "." and ".." */
7126 if (ISDOT(dname) || ISDOTDOT(dname)) {
7127 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7128 sysdir_entry = True;
7129 } else {
7130 TALLOC_FREE(talloced);
7131 continue;
7135 if (!is_visible_file(conn, fname_src_dir, dname,
7136 &smb_fname_src->st, false)) {
7137 TALLOC_FREE(talloced);
7138 continue;
7141 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7142 TALLOC_FREE(talloced);
7143 continue;
7146 if (sysdir_entry) {
7147 status = NT_STATUS_OBJECT_NAME_INVALID;
7148 break;
7151 TALLOC_FREE(smb_fname_src->base_name);
7152 if (ISDOT(fname_src_dir)) {
7153 /* Ensure we use canonical names on open. */
7154 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7155 "%s",
7156 dname);
7157 } else {
7158 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7159 "%s/%s",
7160 fname_src_dir,
7161 dname);
7163 if (!smb_fname_src->base_name) {
7164 status = NT_STATUS_NO_MEMORY;
7165 goto out;
7168 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7169 smb_fname_dst->base_name,
7170 &destname)) {
7171 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7172 smb_fname_src->base_name, destname));
7173 TALLOC_FREE(talloced);
7174 continue;
7176 if (!destname) {
7177 status = NT_STATUS_NO_MEMORY;
7178 goto out;
7181 TALLOC_FREE(smb_fname_dst->base_name);
7182 smb_fname_dst->base_name = destname;
7184 ZERO_STRUCT(smb_fname_src->st);
7185 if (posix_pathnames) {
7186 SMB_VFS_LSTAT(conn, smb_fname_src);
7187 } else {
7188 SMB_VFS_STAT(conn, smb_fname_src);
7191 create_options = 0;
7193 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7194 create_options |= FILE_DIRECTORY_FILE;
7197 status = SMB_VFS_CREATE_FILE(
7198 conn, /* conn */
7199 req, /* req */
7200 0, /* root_dir_fid */
7201 smb_fname_src, /* fname */
7202 access_mask, /* access_mask */
7203 (FILE_SHARE_READ | /* share_access */
7204 FILE_SHARE_WRITE),
7205 FILE_OPEN, /* create_disposition*/
7206 create_options, /* create_options */
7207 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7208 0, /* oplock_request */
7209 NULL, /* lease */
7210 0, /* allocation_size */
7211 0, /* private_flags */
7212 NULL, /* sd */
7213 NULL, /* ea_list */
7214 &fsp, /* result */
7215 NULL, /* pinfo */
7216 NULL, NULL); /* create context */
7218 if (!NT_STATUS_IS_OK(status)) {
7219 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7220 "returned %s rename %s -> %s\n",
7221 nt_errstr(status),
7222 smb_fname_str_dbg(smb_fname_src),
7223 smb_fname_str_dbg(smb_fname_dst)));
7224 break;
7227 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7228 dname);
7229 if (!smb_fname_dst->original_lcomp) {
7230 status = NT_STATUS_NO_MEMORY;
7231 goto out;
7234 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7235 attrs, replace_if_exists);
7237 close_file(req, fsp, NORMAL_CLOSE);
7239 if (!NT_STATUS_IS_OK(status)) {
7240 DEBUG(3, ("rename_internals_fsp returned %s for "
7241 "rename %s -> %s\n", nt_errstr(status),
7242 smb_fname_str_dbg(smb_fname_src),
7243 smb_fname_str_dbg(smb_fname_dst)));
7244 break;
7247 count++;
7249 DEBUG(3,("rename_internals: doing rename on %s -> "
7250 "%s\n", smb_fname_str_dbg(smb_fname_src),
7251 smb_fname_str_dbg(smb_fname_src)));
7252 TALLOC_FREE(talloced);
7254 TALLOC_FREE(dir_hnd);
7256 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7257 status = map_nt_error_from_unix(errno);
7260 out:
7261 TALLOC_FREE(talloced);
7262 TALLOC_FREE(smb_fname_src_dir);
7263 TALLOC_FREE(fname_src_dir);
7264 TALLOC_FREE(fname_src_mask);
7265 return status;
7268 /****************************************************************************
7269 Reply to a mv.
7270 ****************************************************************************/
7272 void reply_mv(struct smb_request *req)
7274 connection_struct *conn = req->conn;
7275 char *name = NULL;
7276 char *newname = NULL;
7277 const char *p;
7278 uint32_t attrs;
7279 NTSTATUS status;
7280 bool src_has_wcard = False;
7281 bool dest_has_wcard = False;
7282 TALLOC_CTX *ctx = talloc_tos();
7283 struct smb_filename *smb_fname_src = NULL;
7284 struct smb_filename *smb_fname_dst = NULL;
7285 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
7286 (req->posix_pathnames ?
7287 UCF_UNIX_NAME_LOOKUP :
7288 UCF_COND_ALLOW_WCARD_LCOMP);
7289 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
7290 UCF_SAVE_LCOMP |
7291 (req->posix_pathnames ?
7293 UCF_COND_ALLOW_WCARD_LCOMP);
7294 bool stream_rename = false;
7296 START_PROFILE(SMBmv);
7298 if (req->wct < 1) {
7299 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7300 goto out;
7303 attrs = SVAL(req->vwv+0, 0);
7305 p = (const char *)req->buf + 1;
7306 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7307 &status, &src_has_wcard);
7308 if (!NT_STATUS_IS_OK(status)) {
7309 reply_nterror(req, status);
7310 goto out;
7312 p++;
7313 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7314 &status, &dest_has_wcard);
7315 if (!NT_STATUS_IS_OK(status)) {
7316 reply_nterror(req, status);
7317 goto out;
7320 if (!req->posix_pathnames) {
7321 /* The newname must begin with a ':' if the
7322 name contains a ':'. */
7323 if (strchr_m(name, ':')) {
7324 if (newname[0] != ':') {
7325 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7326 goto out;
7328 stream_rename = true;
7332 status = filename_convert(ctx,
7333 conn,
7334 name,
7335 src_ucf_flags,
7336 &src_has_wcard,
7337 &smb_fname_src);
7339 if (!NT_STATUS_IS_OK(status)) {
7340 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7341 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7342 ERRSRV, ERRbadpath);
7343 goto out;
7345 reply_nterror(req, status);
7346 goto out;
7349 status = filename_convert(ctx,
7350 conn,
7351 newname,
7352 dst_ucf_flags,
7353 &dest_has_wcard,
7354 &smb_fname_dst);
7356 if (!NT_STATUS_IS_OK(status)) {
7357 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7358 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7359 ERRSRV, ERRbadpath);
7360 goto out;
7362 reply_nterror(req, status);
7363 goto out;
7366 if (stream_rename) {
7367 /* smb_fname_dst->base_name must be the same as
7368 smb_fname_src->base_name. */
7369 TALLOC_FREE(smb_fname_dst->base_name);
7370 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7371 smb_fname_src->base_name);
7372 if (!smb_fname_dst->base_name) {
7373 reply_nterror(req, NT_STATUS_NO_MEMORY);
7374 goto out;
7378 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7379 smb_fname_str_dbg(smb_fname_dst)));
7381 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7382 attrs, False, src_has_wcard, dest_has_wcard,
7383 DELETE_ACCESS);
7384 if (!NT_STATUS_IS_OK(status)) {
7385 if (open_was_deferred(req->xconn, req->mid)) {
7386 /* We have re-scheduled this call. */
7387 goto out;
7389 reply_nterror(req, status);
7390 goto out;
7393 reply_outbuf(req, 0, 0);
7394 out:
7395 TALLOC_FREE(smb_fname_src);
7396 TALLOC_FREE(smb_fname_dst);
7397 END_PROFILE(SMBmv);
7398 return;
7401 /*******************************************************************
7402 Copy a file as part of a reply_copy.
7403 ******************************************************************/
7406 * TODO: check error codes on all callers
7409 NTSTATUS copy_file(TALLOC_CTX *ctx,
7410 connection_struct *conn,
7411 struct smb_filename *smb_fname_src,
7412 struct smb_filename *smb_fname_dst,
7413 int ofun,
7414 int count,
7415 bool target_is_directory)
7417 struct smb_filename *smb_fname_dst_tmp = NULL;
7418 off_t ret=-1;
7419 files_struct *fsp1,*fsp2;
7420 uint32_t dosattrs;
7421 uint32_t new_create_disposition;
7422 NTSTATUS status;
7425 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7426 if (smb_fname_dst_tmp == NULL) {
7427 return NT_STATUS_NO_MEMORY;
7431 * If the target is a directory, extract the last component from the
7432 * src filename and append it to the dst filename
7434 if (target_is_directory) {
7435 const char *p;
7437 /* dest/target can't be a stream if it's a directory. */
7438 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7440 p = strrchr_m(smb_fname_src->base_name,'/');
7441 if (p) {
7442 p++;
7443 } else {
7444 p = smb_fname_src->base_name;
7446 smb_fname_dst_tmp->base_name =
7447 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7449 if (!smb_fname_dst_tmp->base_name) {
7450 status = NT_STATUS_NO_MEMORY;
7451 goto out;
7455 status = vfs_file_exist(conn, smb_fname_src);
7456 if (!NT_STATUS_IS_OK(status)) {
7457 goto out;
7460 if (!target_is_directory && count) {
7461 new_create_disposition = FILE_OPEN;
7462 } else {
7463 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7464 0, ofun,
7465 NULL, NULL,
7466 &new_create_disposition,
7467 NULL,
7468 NULL)) {
7469 status = NT_STATUS_INVALID_PARAMETER;
7470 goto out;
7474 /* Open the src file for reading. */
7475 status = SMB_VFS_CREATE_FILE(
7476 conn, /* conn */
7477 NULL, /* req */
7478 0, /* root_dir_fid */
7479 smb_fname_src, /* fname */
7480 FILE_GENERIC_READ, /* access_mask */
7481 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7482 FILE_OPEN, /* create_disposition*/
7483 0, /* create_options */
7484 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7485 INTERNAL_OPEN_ONLY, /* oplock_request */
7486 NULL, /* lease */
7487 0, /* allocation_size */
7488 0, /* private_flags */
7489 NULL, /* sd */
7490 NULL, /* ea_list */
7491 &fsp1, /* result */
7492 NULL, /* psbuf */
7493 NULL, NULL); /* create context */
7495 if (!NT_STATUS_IS_OK(status)) {
7496 goto out;
7499 dosattrs = dos_mode(conn, smb_fname_src);
7501 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7502 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7505 /* Open the dst file for writing. */
7506 status = SMB_VFS_CREATE_FILE(
7507 conn, /* conn */
7508 NULL, /* req */
7509 0, /* root_dir_fid */
7510 smb_fname_dst, /* fname */
7511 FILE_GENERIC_WRITE, /* access_mask */
7512 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7513 new_create_disposition, /* create_disposition*/
7514 0, /* create_options */
7515 dosattrs, /* file_attributes */
7516 INTERNAL_OPEN_ONLY, /* oplock_request */
7517 NULL, /* lease */
7518 0, /* allocation_size */
7519 0, /* private_flags */
7520 NULL, /* sd */
7521 NULL, /* ea_list */
7522 &fsp2, /* result */
7523 NULL, /* psbuf */
7524 NULL, NULL); /* create context */
7526 if (!NT_STATUS_IS_OK(status)) {
7527 close_file(NULL, fsp1, ERROR_CLOSE);
7528 goto out;
7531 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7532 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7533 if (ret == -1) {
7534 DEBUG(0, ("error - vfs lseek returned error %s\n",
7535 strerror(errno)));
7536 status = map_nt_error_from_unix(errno);
7537 close_file(NULL, fsp1, ERROR_CLOSE);
7538 close_file(NULL, fsp2, ERROR_CLOSE);
7539 goto out;
7543 /* Do the actual copy. */
7544 if (smb_fname_src->st.st_ex_size) {
7545 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7546 } else {
7547 ret = 0;
7550 close_file(NULL, fsp1, NORMAL_CLOSE);
7552 /* Ensure the modtime is set correctly on the destination file. */
7553 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7556 * As we are opening fsp1 read-only we only expect
7557 * an error on close on fsp2 if we are out of space.
7558 * Thus we don't look at the error return from the
7559 * close of fsp1.
7561 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7563 if (!NT_STATUS_IS_OK(status)) {
7564 goto out;
7567 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7568 status = NT_STATUS_DISK_FULL;
7569 goto out;
7572 status = NT_STATUS_OK;
7574 out:
7575 TALLOC_FREE(smb_fname_dst_tmp);
7576 return status;
7579 /****************************************************************************
7580 Reply to a file copy.
7581 ****************************************************************************/
7583 void reply_copy(struct smb_request *req)
7585 connection_struct *conn = req->conn;
7586 struct smb_filename *smb_fname_src = NULL;
7587 struct smb_filename *smb_fname_src_dir = NULL;
7588 struct smb_filename *smb_fname_dst = NULL;
7589 char *fname_src = NULL;
7590 char *fname_dst = NULL;
7591 char *fname_src_mask = NULL;
7592 char *fname_src_dir = NULL;
7593 const char *p;
7594 int count=0;
7595 int error = ERRnoaccess;
7596 int tid2;
7597 int ofun;
7598 int flags;
7599 bool target_is_directory=False;
7600 bool source_has_wild = False;
7601 bool dest_has_wild = False;
7602 NTSTATUS status;
7603 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7604 ucf_flags_from_smb_request(req);
7605 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7606 ucf_flags_from_smb_request(req);
7607 TALLOC_CTX *ctx = talloc_tos();
7609 START_PROFILE(SMBcopy);
7611 if (req->wct < 3) {
7612 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7613 goto out;
7616 tid2 = SVAL(req->vwv+0, 0);
7617 ofun = SVAL(req->vwv+1, 0);
7618 flags = SVAL(req->vwv+2, 0);
7620 p = (const char *)req->buf;
7621 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7622 &status, &source_has_wild);
7623 if (!NT_STATUS_IS_OK(status)) {
7624 reply_nterror(req, status);
7625 goto out;
7627 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7628 &status, &dest_has_wild);
7629 if (!NT_STATUS_IS_OK(status)) {
7630 reply_nterror(req, status);
7631 goto out;
7634 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7636 if (tid2 != conn->cnum) {
7637 /* can't currently handle inter share copies XXXX */
7638 DEBUG(3,("Rejecting inter-share copy\n"));
7639 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7640 goto out;
7643 status = filename_convert(ctx, conn,
7644 fname_src,
7645 ucf_flags_src,
7646 &source_has_wild,
7647 &smb_fname_src);
7648 if (!NT_STATUS_IS_OK(status)) {
7649 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7650 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7651 ERRSRV, ERRbadpath);
7652 goto out;
7654 reply_nterror(req, status);
7655 goto out;
7658 status = filename_convert(ctx, conn,
7659 fname_dst,
7660 ucf_flags_dst,
7661 &dest_has_wild,
7662 &smb_fname_dst);
7663 if (!NT_STATUS_IS_OK(status)) {
7664 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7665 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7666 ERRSRV, ERRbadpath);
7667 goto out;
7669 reply_nterror(req, status);
7670 goto out;
7673 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7675 if ((flags&1) && target_is_directory) {
7676 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7677 goto out;
7680 if ((flags&2) && !target_is_directory) {
7681 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7682 goto out;
7685 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7686 /* wants a tree copy! XXXX */
7687 DEBUG(3,("Rejecting tree copy\n"));
7688 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7689 goto out;
7692 /* Split up the directory from the filename/mask. */
7693 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7694 &fname_src_dir, &fname_src_mask);
7695 if (!NT_STATUS_IS_OK(status)) {
7696 reply_nterror(req, NT_STATUS_NO_MEMORY);
7697 goto out;
7701 * We should only check the mangled cache
7702 * here if unix_convert failed. This means
7703 * that the path in 'mask' doesn't exist
7704 * on the file system and so we need to look
7705 * for a possible mangle. This patch from
7706 * Tine Smukavec <valentin.smukavec@hermes.si>.
7708 if (!VALID_STAT(smb_fname_src->st) &&
7709 mangle_is_mangled(fname_src_mask, conn->params)) {
7710 char *new_mask = NULL;
7711 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7712 &new_mask, conn->params);
7714 /* Use demangled name if one was successfully found. */
7715 if (new_mask) {
7716 TALLOC_FREE(fname_src_mask);
7717 fname_src_mask = new_mask;
7721 if (!source_has_wild) {
7724 * Only one file needs to be copied. Append the mask back onto
7725 * the directory.
7727 TALLOC_FREE(smb_fname_src->base_name);
7728 if (ISDOT(fname_src_dir)) {
7729 /* Ensure we use canonical names on open. */
7730 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7731 "%s",
7732 fname_src_mask);
7733 } else {
7734 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7735 "%s/%s",
7736 fname_src_dir,
7737 fname_src_mask);
7739 if (!smb_fname_src->base_name) {
7740 reply_nterror(req, NT_STATUS_NO_MEMORY);
7741 goto out;
7744 if (dest_has_wild) {
7745 char *fname_dst_mod = NULL;
7746 if (!resolve_wildcards(smb_fname_dst,
7747 smb_fname_src->base_name,
7748 smb_fname_dst->base_name,
7749 &fname_dst_mod)) {
7750 reply_nterror(req, NT_STATUS_NO_MEMORY);
7751 goto out;
7753 TALLOC_FREE(smb_fname_dst->base_name);
7754 smb_fname_dst->base_name = fname_dst_mod;
7757 status = check_name(conn, smb_fname_src);
7758 if (!NT_STATUS_IS_OK(status)) {
7759 reply_nterror(req, status);
7760 goto out;
7763 status = check_name(conn, smb_fname_dst);
7764 if (!NT_STATUS_IS_OK(status)) {
7765 reply_nterror(req, status);
7766 goto out;
7769 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7770 ofun, count, target_is_directory);
7772 if(!NT_STATUS_IS_OK(status)) {
7773 reply_nterror(req, status);
7774 goto out;
7775 } else {
7776 count++;
7778 } else {
7779 struct smb_Dir *dir_hnd = NULL;
7780 const char *dname = NULL;
7781 char *talloced = NULL;
7782 long offset = 0;
7785 * There is a wildcard that requires us to actually read the
7786 * src dir and copy each file matching the mask to the dst.
7787 * Right now streams won't be copied, but this could
7788 * presumably be added with a nested loop for reach dir entry.
7790 SMB_ASSERT(!smb_fname_src->stream_name);
7791 SMB_ASSERT(!smb_fname_dst->stream_name);
7793 smb_fname_src->stream_name = NULL;
7794 smb_fname_dst->stream_name = NULL;
7796 if (strequal(fname_src_mask,"????????.???")) {
7797 TALLOC_FREE(fname_src_mask);
7798 fname_src_mask = talloc_strdup(ctx, "*");
7799 if (!fname_src_mask) {
7800 reply_nterror(req, NT_STATUS_NO_MEMORY);
7801 goto out;
7805 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7806 fname_src_dir,
7807 NULL,
7808 NULL,
7809 smb_fname_src->flags);
7810 if (smb_fname_src_dir == NULL) {
7811 reply_nterror(req, NT_STATUS_NO_MEMORY);
7812 goto out;
7815 status = check_name(conn, smb_fname_src_dir);
7816 if (!NT_STATUS_IS_OK(status)) {
7817 reply_nterror(req, status);
7818 goto out;
7821 dir_hnd = OpenDir(ctx,
7822 conn,
7823 smb_fname_src_dir,
7824 fname_src_mask,
7826 if (dir_hnd == NULL) {
7827 status = map_nt_error_from_unix(errno);
7828 reply_nterror(req, status);
7829 goto out;
7832 error = ERRbadfile;
7834 /* Iterate over the src dir copying each entry to the dst. */
7835 while ((dname = ReadDirName(dir_hnd, &offset,
7836 &smb_fname_src->st, &talloced))) {
7837 char *destname = NULL;
7839 if (ISDOT(dname) || ISDOTDOT(dname)) {
7840 TALLOC_FREE(talloced);
7841 continue;
7844 if (!is_visible_file(conn, fname_src_dir, dname,
7845 &smb_fname_src->st, false)) {
7846 TALLOC_FREE(talloced);
7847 continue;
7850 if(!mask_match(dname, fname_src_mask,
7851 conn->case_sensitive)) {
7852 TALLOC_FREE(talloced);
7853 continue;
7856 error = ERRnoaccess;
7858 /* Get the src smb_fname struct setup. */
7859 TALLOC_FREE(smb_fname_src->base_name);
7860 if (ISDOT(fname_src_dir)) {
7861 /* Ensure we use canonical names on open. */
7862 smb_fname_src->base_name =
7863 talloc_asprintf(smb_fname_src, "%s",
7864 dname);
7865 } else {
7866 smb_fname_src->base_name =
7867 talloc_asprintf(smb_fname_src, "%s/%s",
7868 fname_src_dir, dname);
7871 if (!smb_fname_src->base_name) {
7872 TALLOC_FREE(dir_hnd);
7873 TALLOC_FREE(talloced);
7874 reply_nterror(req, NT_STATUS_NO_MEMORY);
7875 goto out;
7878 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7879 smb_fname_dst->base_name,
7880 &destname)) {
7881 TALLOC_FREE(talloced);
7882 continue;
7884 if (!destname) {
7885 TALLOC_FREE(dir_hnd);
7886 TALLOC_FREE(talloced);
7887 reply_nterror(req, NT_STATUS_NO_MEMORY);
7888 goto out;
7891 TALLOC_FREE(smb_fname_dst->base_name);
7892 smb_fname_dst->base_name = destname;
7894 status = check_name(conn, smb_fname_src);
7895 if (!NT_STATUS_IS_OK(status)) {
7896 TALLOC_FREE(dir_hnd);
7897 TALLOC_FREE(talloced);
7898 reply_nterror(req, status);
7899 goto out;
7902 status = check_name(conn, smb_fname_dst);
7903 if (!NT_STATUS_IS_OK(status)) {
7904 TALLOC_FREE(dir_hnd);
7905 TALLOC_FREE(talloced);
7906 reply_nterror(req, status);
7907 goto out;
7910 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7911 smb_fname_src->base_name,
7912 smb_fname_dst->base_name));
7914 status = copy_file(ctx, conn, smb_fname_src,
7915 smb_fname_dst, ofun, count,
7916 target_is_directory);
7917 if (NT_STATUS_IS_OK(status)) {
7918 count++;
7921 TALLOC_FREE(talloced);
7923 TALLOC_FREE(dir_hnd);
7926 if (count == 0) {
7927 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7928 goto out;
7931 reply_outbuf(req, 1, 0);
7932 SSVAL(req->outbuf,smb_vwv0,count);
7933 out:
7934 TALLOC_FREE(smb_fname_src);
7935 TALLOC_FREE(smb_fname_src_dir);
7936 TALLOC_FREE(smb_fname_dst);
7937 TALLOC_FREE(fname_src);
7938 TALLOC_FREE(fname_dst);
7939 TALLOC_FREE(fname_src_mask);
7940 TALLOC_FREE(fname_src_dir);
7942 END_PROFILE(SMBcopy);
7943 return;
7946 #undef DBGC_CLASS
7947 #define DBGC_CLASS DBGC_LOCKING
7949 /****************************************************************************
7950 Get a lock pid, dealing with large count requests.
7951 ****************************************************************************/
7953 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7954 bool large_file_format)
7956 if(!large_file_format)
7957 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7958 else
7959 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7962 /****************************************************************************
7963 Get a lock count, dealing with large count requests.
7964 ****************************************************************************/
7966 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7967 bool large_file_format)
7969 uint64_t count = 0;
7971 if(!large_file_format) {
7972 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7973 } else {
7975 * No BVAL, this is reversed!
7977 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7978 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7981 return count;
7984 /****************************************************************************
7985 Get a lock offset, dealing with large offset requests.
7986 ****************************************************************************/
7988 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7989 bool large_file_format)
7991 uint64_t offset = 0;
7993 if(!large_file_format) {
7994 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7995 } else {
7997 * No BVAL, this is reversed!
7999 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
8000 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
8003 return offset;
8006 NTSTATUS smbd_do_locking(struct smb_request *req,
8007 files_struct *fsp,
8008 uint8_t type,
8009 int32_t timeout,
8010 uint16_t num_locks,
8011 struct smbd_lock_element *locks,
8012 bool *async)
8014 connection_struct *conn = req->conn;
8015 int i;
8016 NTSTATUS status = NT_STATUS_OK;
8018 *async = false;
8020 /* Setup the timeout in seconds. */
8022 if (!lp_blocking_locks(SNUM(conn))) {
8023 timeout = 0;
8026 for(i = 0; i < (int)num_locks; i++) {
8027 struct smbd_lock_element *e = &locks[i];
8029 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8030 "%llu, file %s timeout = %d\n",
8031 (double)e->offset,
8032 (double)e->count,
8033 (unsigned long long)e->smblctx,
8034 fsp_str_dbg(fsp),
8035 (int)timeout));
8037 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8038 struct blocking_lock_record *blr = NULL;
8040 if (num_locks > 1) {
8042 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8043 * if the lock vector contains one entry. When given multiple cancel
8044 * requests in a single PDU we expect the server to return an
8045 * error. Windows servers seem to accept the request but only
8046 * cancel the first lock.
8047 * JRA - Do what Windows does (tm) :-).
8050 #if 0
8051 /* MS-CIFS (2.2.4.32.1) behavior. */
8052 return NT_STATUS_DOS(ERRDOS,
8053 ERRcancelviolation);
8054 #else
8055 /* Windows behavior. */
8056 if (i != 0) {
8057 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8058 "cancel request\n"));
8059 continue;
8061 #endif
8064 if (lp_blocking_locks(SNUM(conn))) {
8066 /* Schedule a message to ourselves to
8067 remove the blocking lock record and
8068 return the right error. */
8070 blr = blocking_lock_cancel_smb1(fsp,
8071 e->smblctx,
8072 e->offset,
8073 e->count,
8074 WINDOWS_LOCK,
8075 type,
8076 NT_STATUS_FILE_LOCK_CONFLICT);
8077 if (blr == NULL) {
8078 return NT_STATUS_DOS(
8079 ERRDOS,
8080 ERRcancelviolation);
8083 /* Remove a matching pending lock. */
8084 status = do_lock_cancel(fsp,
8085 e->smblctx,
8086 e->count,
8087 e->offset,
8088 WINDOWS_LOCK);
8089 } else {
8090 bool blocking_lock = timeout ? true : false;
8091 bool defer_lock = false;
8092 struct byte_range_lock *br_lck;
8093 uint64_t block_smblctx;
8095 br_lck = do_lock(req->sconn->msg_ctx,
8096 fsp,
8097 e->smblctx,
8098 e->count,
8099 e->offset,
8100 e->brltype,
8101 WINDOWS_LOCK,
8102 blocking_lock,
8103 &status,
8104 &block_smblctx);
8106 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8107 /* Windows internal resolution for blocking locks seems
8108 to be about 200ms... Don't wait for less than that. JRA. */
8109 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8110 timeout = lp_lock_spin_time();
8112 defer_lock = true;
8115 /* If a lock sent with timeout of zero would fail, and
8116 * this lock has been requested multiple times,
8117 * according to brl_lock_failed() we convert this
8118 * request to a blocking lock with a timeout of between
8119 * 150 - 300 milliseconds.
8121 * If lp_lock_spin_time() has been set to 0, we skip
8122 * this blocking retry and fail immediately.
8124 * Replacement for do_lock_spin(). JRA. */
8126 if (!req->sconn->using_smb2 &&
8127 br_lck && lp_blocking_locks(SNUM(conn)) &&
8128 lp_lock_spin_time() && !blocking_lock &&
8129 NT_STATUS_EQUAL((status),
8130 NT_STATUS_FILE_LOCK_CONFLICT))
8132 defer_lock = true;
8133 timeout = lp_lock_spin_time();
8136 if (br_lck && defer_lock) {
8138 * A blocking lock was requested. Package up
8139 * this smb into a queued request and push it
8140 * onto the blocking lock queue.
8142 if(push_blocking_lock_request(br_lck,
8143 req,
8144 fsp,
8145 timeout,
8147 e->smblctx,
8148 e->brltype,
8149 WINDOWS_LOCK,
8150 e->offset,
8151 e->count,
8152 block_smblctx)) {
8153 TALLOC_FREE(br_lck);
8154 *async = true;
8155 return NT_STATUS_OK;
8159 TALLOC_FREE(br_lck);
8162 if (!NT_STATUS_IS_OK(status)) {
8163 break;
8167 /* If any of the above locks failed, then we must unlock
8168 all of the previous locks (X/Open spec). */
8170 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8172 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8173 i = -1; /* we want to skip the for loop */
8177 * Ensure we don't do a remove on the lock that just failed,
8178 * as under POSIX rules, if we have a lock already there, we
8179 * will delete it (and we shouldn't) .....
8181 for(i--; i >= 0; i--) {
8182 struct smbd_lock_element *e = &locks[i];
8184 do_unlock(req->sconn->msg_ctx,
8185 fsp,
8186 e->smblctx,
8187 e->count,
8188 e->offset,
8189 WINDOWS_LOCK);
8191 return status;
8194 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8195 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8197 return NT_STATUS_OK;
8200 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8201 files_struct *fsp,
8202 uint16_t num_ulocks,
8203 struct smbd_lock_element *ulocks)
8205 int i;
8207 for(i = 0; i < (int)num_ulocks; i++) {
8208 struct smbd_lock_element *e = &ulocks[i];
8209 NTSTATUS status;
8211 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8212 "pid %u, file %s\n", __func__,
8213 (double)e->offset,
8214 (double)e->count,
8215 (unsigned int)e->smblctx,
8216 fsp_str_dbg(fsp)));
8218 if (e->brltype != UNLOCK_LOCK) {
8219 /* this can only happen with SMB2 */
8220 return NT_STATUS_INVALID_PARAMETER;
8223 status = do_unlock(req->sconn->msg_ctx,
8224 fsp,
8225 e->smblctx,
8226 e->count,
8227 e->offset,
8228 WINDOWS_LOCK);
8230 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8231 nt_errstr(status)));
8233 if (!NT_STATUS_IS_OK(status)) {
8234 return status;
8238 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8239 num_ulocks));
8241 return NT_STATUS_OK;
8244 /****************************************************************************
8245 Reply to a lockingX request.
8246 ****************************************************************************/
8248 void reply_lockingX(struct smb_request *req)
8250 connection_struct *conn = req->conn;
8251 files_struct *fsp;
8252 unsigned char locktype;
8253 unsigned char oplocklevel;
8254 uint16_t num_ulocks;
8255 uint16_t num_locks;
8256 int32_t lock_timeout;
8257 int i;
8258 const uint8_t *data;
8259 bool large_file_format;
8260 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8261 struct smbd_lock_element *ulocks;
8262 struct smbd_lock_element *locks;
8263 bool async = false;
8265 START_PROFILE(SMBlockingX);
8267 if (req->wct < 8) {
8268 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8269 END_PROFILE(SMBlockingX);
8270 return;
8273 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8274 locktype = CVAL(req->vwv+3, 0);
8275 oplocklevel = CVAL(req->vwv+3, 1);
8276 num_ulocks = SVAL(req->vwv+6, 0);
8277 num_locks = SVAL(req->vwv+7, 0);
8278 lock_timeout = IVAL(req->vwv+4, 0);
8279 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8281 if (!check_fsp(conn, req, fsp)) {
8282 END_PROFILE(SMBlockingX);
8283 return;
8286 data = req->buf;
8288 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8289 /* we don't support these - and CANCEL_LOCK makes w2k
8290 and XP reboot so I don't really want to be
8291 compatible! (tridge) */
8292 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8293 END_PROFILE(SMBlockingX);
8294 return;
8297 /* Check if this is an oplock break on a file
8298 we have granted an oplock on.
8300 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8301 /* Client can insist on breaking to none. */
8302 bool break_to_none = (oplocklevel == 0);
8303 bool result;
8305 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8306 "for %s\n", (unsigned int)oplocklevel,
8307 fsp_fnum_dbg(fsp)));
8310 * Make sure we have granted an exclusive or batch oplock on
8311 * this file.
8314 if (fsp->oplock_type == 0) {
8316 /* The Samba4 nbench simulator doesn't understand
8317 the difference between break to level2 and break
8318 to none from level2 - it sends oplock break
8319 replies in both cases. Don't keep logging an error
8320 message here - just ignore it. JRA. */
8322 DEBUG(5,("reply_lockingX: Error : oplock break from "
8323 "client for %s (oplock=%d) and no "
8324 "oplock granted on this file (%s).\n",
8325 fsp_fnum_dbg(fsp), fsp->oplock_type,
8326 fsp_str_dbg(fsp)));
8328 /* if this is a pure oplock break request then don't
8329 * send a reply */
8330 if (num_locks == 0 && num_ulocks == 0) {
8331 END_PROFILE(SMBlockingX);
8332 return;
8333 } else {
8334 END_PROFILE(SMBlockingX);
8335 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8336 return;
8340 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8341 (break_to_none)) {
8342 result = remove_oplock(fsp);
8343 } else {
8344 result = downgrade_oplock(fsp);
8347 if (!result) {
8348 DEBUG(0, ("reply_lockingX: error in removing "
8349 "oplock on file %s\n", fsp_str_dbg(fsp)));
8350 /* Hmmm. Is this panic justified? */
8351 smb_panic("internal tdb error");
8354 /* if this is a pure oplock break request then don't send a
8355 * reply */
8356 if (num_locks == 0 && num_ulocks == 0) {
8357 /* Sanity check - ensure a pure oplock break is not a
8358 chained request. */
8359 if (CVAL(req->vwv+0, 0) != 0xff) {
8360 DEBUG(0,("reply_lockingX: Error : pure oplock "
8361 "break is a chained %d request !\n",
8362 (unsigned int)CVAL(req->vwv+0, 0)));
8364 END_PROFILE(SMBlockingX);
8365 return;
8369 if (req->buflen <
8370 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8371 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8372 END_PROFILE(SMBlockingX);
8373 return;
8376 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8377 if (ulocks == NULL) {
8378 reply_nterror(req, NT_STATUS_NO_MEMORY);
8379 END_PROFILE(SMBlockingX);
8380 return;
8383 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8384 if (locks == NULL) {
8385 reply_nterror(req, NT_STATUS_NO_MEMORY);
8386 END_PROFILE(SMBlockingX);
8387 return;
8390 /* Data now points at the beginning of the list
8391 of smb_unlkrng structs */
8392 for(i = 0; i < (int)num_ulocks; i++) {
8393 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8394 ulocks[i].count = get_lock_count(data, i, large_file_format);
8395 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8396 ulocks[i].brltype = UNLOCK_LOCK;
8399 /* Now do any requested locks */
8400 data += ((large_file_format ? 20 : 10)*num_ulocks);
8402 /* Data now points at the beginning of the list
8403 of smb_lkrng structs */
8405 for(i = 0; i < (int)num_locks; i++) {
8406 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8407 locks[i].count = get_lock_count(data, i, large_file_format);
8408 locks[i].offset = get_lock_offset(data, i, large_file_format);
8410 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8411 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8412 locks[i].brltype = PENDING_READ_LOCK;
8413 } else {
8414 locks[i].brltype = READ_LOCK;
8416 } else {
8417 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8418 locks[i].brltype = PENDING_WRITE_LOCK;
8419 } else {
8420 locks[i].brltype = WRITE_LOCK;
8425 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8426 if (!NT_STATUS_IS_OK(status)) {
8427 END_PROFILE(SMBlockingX);
8428 reply_nterror(req, status);
8429 return;
8432 status = smbd_do_locking(req, fsp,
8433 locktype, lock_timeout,
8434 num_locks, locks,
8435 &async);
8436 if (!NT_STATUS_IS_OK(status)) {
8437 END_PROFILE(SMBlockingX);
8438 reply_nterror(req, status);
8439 return;
8441 if (async) {
8442 END_PROFILE(SMBlockingX);
8443 return;
8446 reply_outbuf(req, 2, 0);
8447 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8448 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8450 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8451 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8453 END_PROFILE(SMBlockingX);
8456 #undef DBGC_CLASS
8457 #define DBGC_CLASS DBGC_ALL
8459 /****************************************************************************
8460 Reply to a SMBreadbmpx (read block multiplex) request.
8461 Always reply with an error, if someone has a platform really needs this,
8462 please contact vl@samba.org
8463 ****************************************************************************/
8465 void reply_readbmpx(struct smb_request *req)
8467 START_PROFILE(SMBreadBmpx);
8468 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8469 END_PROFILE(SMBreadBmpx);
8470 return;
8473 /****************************************************************************
8474 Reply to a SMBreadbs (read block multiplex secondary) request.
8475 Always reply with an error, if someone has a platform really needs this,
8476 please contact vl@samba.org
8477 ****************************************************************************/
8479 void reply_readbs(struct smb_request *req)
8481 START_PROFILE(SMBreadBs);
8482 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8483 END_PROFILE(SMBreadBs);
8484 return;
8487 /****************************************************************************
8488 Reply to a SMBsetattrE.
8489 ****************************************************************************/
8491 void reply_setattrE(struct smb_request *req)
8493 connection_struct *conn = req->conn;
8494 struct smb_file_time ft;
8495 files_struct *fsp;
8496 NTSTATUS status;
8498 START_PROFILE(SMBsetattrE);
8499 ZERO_STRUCT(ft);
8501 if (req->wct < 7) {
8502 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8503 goto out;
8506 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8508 if(!fsp || (fsp->conn != conn)) {
8509 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8510 goto out;
8514 * Convert the DOS times into unix times.
8517 ft.atime = convert_time_t_to_timespec(
8518 srv_make_unix_date2(req->vwv+3));
8519 ft.mtime = convert_time_t_to_timespec(
8520 srv_make_unix_date2(req->vwv+5));
8521 ft.create_time = convert_time_t_to_timespec(
8522 srv_make_unix_date2(req->vwv+1));
8524 reply_outbuf(req, 0, 0);
8527 * Patch from Ray Frush <frush@engr.colostate.edu>
8528 * Sometimes times are sent as zero - ignore them.
8531 /* Ensure we have a valid stat struct for the source. */
8532 status = vfs_stat_fsp(fsp);
8533 if (!NT_STATUS_IS_OK(status)) {
8534 reply_nterror(req, status);
8535 goto out;
8538 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8539 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8540 goto out;
8543 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8544 if (!NT_STATUS_IS_OK(status)) {
8545 reply_nterror(req, status);
8546 goto out;
8549 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8550 " createtime=%u\n",
8551 fsp_fnum_dbg(fsp),
8552 (unsigned int)ft.atime.tv_sec,
8553 (unsigned int)ft.mtime.tv_sec,
8554 (unsigned int)ft.create_time.tv_sec
8556 out:
8557 END_PROFILE(SMBsetattrE);
8558 return;
8562 /* Back from the dead for OS/2..... JRA. */
8564 /****************************************************************************
8565 Reply to a SMBwritebmpx (write block multiplex primary) request.
8566 Always reply with an error, if someone has a platform really needs this,
8567 please contact vl@samba.org
8568 ****************************************************************************/
8570 void reply_writebmpx(struct smb_request *req)
8572 START_PROFILE(SMBwriteBmpx);
8573 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8574 END_PROFILE(SMBwriteBmpx);
8575 return;
8578 /****************************************************************************
8579 Reply to a SMBwritebs (write block multiplex secondary) request.
8580 Always reply with an error, if someone has a platform really needs this,
8581 please contact vl@samba.org
8582 ****************************************************************************/
8584 void reply_writebs(struct smb_request *req)
8586 START_PROFILE(SMBwriteBs);
8587 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8588 END_PROFILE(SMBwriteBs);
8589 return;
8592 /****************************************************************************
8593 Reply to a SMBgetattrE.
8594 ****************************************************************************/
8596 void reply_getattrE(struct smb_request *req)
8598 connection_struct *conn = req->conn;
8599 int mode;
8600 files_struct *fsp;
8601 struct timespec create_ts;
8603 START_PROFILE(SMBgetattrE);
8605 if (req->wct < 1) {
8606 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8607 END_PROFILE(SMBgetattrE);
8608 return;
8611 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8613 if(!fsp || (fsp->conn != conn)) {
8614 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8615 END_PROFILE(SMBgetattrE);
8616 return;
8619 /* Do an fstat on this file */
8620 if(fsp_stat(fsp)) {
8621 reply_nterror(req, map_nt_error_from_unix(errno));
8622 END_PROFILE(SMBgetattrE);
8623 return;
8626 mode = dos_mode(conn, fsp->fsp_name);
8629 * Convert the times into dos times. Set create
8630 * date to be last modify date as UNIX doesn't save
8631 * this.
8634 reply_outbuf(req, 11, 0);
8636 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8637 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8638 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8639 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8640 /* Should we check pending modtime here ? JRA */
8641 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8642 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8644 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8645 SIVAL(req->outbuf, smb_vwv6, 0);
8646 SIVAL(req->outbuf, smb_vwv8, 0);
8647 } else {
8648 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8649 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8650 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8652 SSVAL(req->outbuf,smb_vwv10, mode);
8654 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8656 END_PROFILE(SMBgetattrE);
8657 return;