s3: smbd : Fix wildcard unlink to fail if we get an error rather than trying to continue.
[Samba.git] / source3 / smbd / reply.c
blob8b16a0c79c2b3df565c3f03cecedf3169a3aed17
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"
47 /****************************************************************************
48 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
49 path or anything including wildcards.
50 We're assuming here that '/' is not the second byte in any multibyte char
51 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
52 set.
53 ****************************************************************************/
55 /* Custom version for processing POSIX paths. */
56 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
58 static NTSTATUS check_path_syntax_internal(char *path,
59 bool posix_path,
60 bool *p_last_component_contains_wcard)
62 char *d = path;
63 const char *s = path;
64 NTSTATUS ret = NT_STATUS_OK;
65 bool start_of_name_component = True;
66 bool stream_started = false;
68 *p_last_component_contains_wcard = False;
70 while (*s) {
71 if (stream_started) {
72 switch (*s) {
73 case '/':
74 case '\\':
75 return NT_STATUS_OBJECT_NAME_INVALID;
76 case ':':
77 if (s[1] == '\0') {
78 return NT_STATUS_OBJECT_NAME_INVALID;
80 if (strchr_m(&s[1], ':')) {
81 return NT_STATUS_OBJECT_NAME_INVALID;
83 break;
87 if ((*s == ':') && !posix_path && !stream_started) {
88 if (*p_last_component_contains_wcard) {
89 return NT_STATUS_OBJECT_NAME_INVALID;
91 /* Stream names allow more characters than file names.
92 We're overloading posix_path here to allow a wider
93 range of characters. If stream_started is true this
94 is still a Windows path even if posix_path is true.
95 JRA.
97 stream_started = true;
98 start_of_name_component = false;
99 posix_path = true;
101 if (s[1] == '\0') {
102 return NT_STATUS_OBJECT_NAME_INVALID;
106 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
108 * Safe to assume is not the second part of a mb char
109 * as this is handled below.
111 /* Eat multiple '/' or '\\' */
112 while (IS_PATH_SEP(*s,posix_path)) {
113 s++;
115 if ((d != path) && (*s != '\0')) {
116 /* We only care about non-leading or trailing '/' or '\\' */
117 *d++ = '/';
120 start_of_name_component = True;
121 /* New component. */
122 *p_last_component_contains_wcard = False;
123 continue;
126 if (start_of_name_component) {
127 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
128 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
131 * No mb char starts with '.' so we're safe checking the directory separator here.
134 /* If we just added a '/' - delete it */
135 if ((d > path) && (*(d-1) == '/')) {
136 *(d-1) = '\0';
137 d--;
140 /* Are we at the start ? Can't go back further if so. */
141 if (d <= path) {
142 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
143 break;
145 /* Go back one level... */
146 /* We know this is safe as '/' cannot be part of a mb sequence. */
147 /* NOTE - if this assumption is invalid we are not in good shape... */
148 /* Decrement d first as d points to the *next* char to write into. */
149 for (d--; d > path; d--) {
150 if (*d == '/')
151 break;
153 s += 2; /* Else go past the .. */
154 /* We're still at the start of a name component, just the previous one. */
155 continue;
157 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
158 if (posix_path) {
159 /* Eat the '.' */
160 s++;
161 continue;
167 if (!(*s & 0x80)) {
168 if (!posix_path) {
169 if (*s <= 0x1f || *s == '|') {
170 return NT_STATUS_OBJECT_NAME_INVALID;
172 switch (*s) {
173 case '*':
174 case '?':
175 case '<':
176 case '>':
177 case '"':
178 *p_last_component_contains_wcard = True;
179 break;
180 default:
181 break;
184 *d++ = *s++;
185 } else {
186 size_t siz;
187 /* Get the size of the next MB character. */
188 next_codepoint(s,&siz);
189 switch(siz) {
190 case 5:
191 *d++ = *s++;
192 /*fall through*/
193 case 4:
194 *d++ = *s++;
195 /*fall through*/
196 case 3:
197 *d++ = *s++;
198 /*fall through*/
199 case 2:
200 *d++ = *s++;
201 /*fall through*/
202 case 1:
203 *d++ = *s++;
204 break;
205 default:
206 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
207 *d = '\0';
208 return NT_STATUS_INVALID_PARAMETER;
211 start_of_name_component = False;
214 *d = '\0';
216 return ret;
219 /****************************************************************************
220 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
221 No wildcards allowed.
222 ****************************************************************************/
224 NTSTATUS check_path_syntax(char *path)
226 bool ignore;
227 return check_path_syntax_internal(path, False, &ignore);
230 /****************************************************************************
231 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
232 Wildcards allowed - p_contains_wcard returns true if the last component contained
233 a wildcard.
234 ****************************************************************************/
236 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
238 return check_path_syntax_internal(path, False, p_contains_wcard);
241 /****************************************************************************
242 Check the path for a POSIX client.
243 We're assuming here that '/' is not the second byte in any multibyte char
244 set (a safe assumption).
245 ****************************************************************************/
247 NTSTATUS check_path_syntax_posix(char *path)
249 bool ignore;
250 return check_path_syntax_internal(path, True, &ignore);
253 /****************************************************************************
254 Pull a string and check the path allowing a wilcard - provide for error return.
255 ****************************************************************************/
257 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
258 const char *base_ptr,
259 uint16 smb_flags2,
260 char **pp_dest,
261 const char *src,
262 size_t src_len,
263 int flags,
264 NTSTATUS *err,
265 bool *contains_wcard)
267 size_t ret;
269 *pp_dest = NULL;
271 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
272 src_len, flags);
274 if (!*pp_dest) {
275 *err = NT_STATUS_INVALID_PARAMETER;
276 return ret;
279 *contains_wcard = False;
281 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
283 * For a DFS path the function parse_dfs_path()
284 * will do the path processing, just make a copy.
286 *err = NT_STATUS_OK;
287 return ret;
290 if (lp_posix_pathnames()) {
291 *err = check_path_syntax_posix(*pp_dest);
292 } else {
293 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
296 return ret;
299 /****************************************************************************
300 Pull a string and check the path - provide for error return.
301 ****************************************************************************/
303 size_t srvstr_get_path(TALLOC_CTX *ctx,
304 const char *base_ptr,
305 uint16 smb_flags2,
306 char **pp_dest,
307 const char *src,
308 size_t src_len,
309 int flags,
310 NTSTATUS *err)
312 bool ignore;
313 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
314 src_len, flags, err, &ignore);
317 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
318 char **pp_dest, const char *src, int flags,
319 NTSTATUS *err, bool *contains_wcard)
321 ssize_t bufrem = smbreq_bufrem(req, src);
323 if (bufrem < 0) {
324 *err = NT_STATUS_INVALID_PARAMETER;
325 return 0;
328 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
329 req->flags2, pp_dest, src, bufrem, flags,
330 err, contains_wcard);
333 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
334 char **pp_dest, const char *src, int flags,
335 NTSTATUS *err)
337 bool ignore;
338 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
339 flags, err, &ignore);
342 /* pull a string from the smb_buf part of a packet. In this case the
343 string can either be null terminated or it can be terminated by the
344 end of the smbbuf area
346 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
347 char **dest, const char *src, int flags)
349 ssize_t bufrem = smbreq_bufrem(req, src);
351 if (bufrem < 0) {
352 return 0;
355 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
356 bufrem, flags);
359 /****************************************************************************
360 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
361 ****************************************************************************/
363 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
364 files_struct *fsp)
366 if ((fsp == NULL) || (conn == NULL)) {
367 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
368 return False;
370 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
371 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
372 return False;
374 return True;
377 /****************************************************************************
378 Check if we have a correct fsp pointing to a file.
379 ****************************************************************************/
381 bool check_fsp(connection_struct *conn, struct smb_request *req,
382 files_struct *fsp)
384 if (!check_fsp_open(conn, req, fsp)) {
385 return False;
387 if (fsp->is_directory) {
388 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
389 return False;
391 if (fsp->fh->fd == -1) {
392 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
393 return False;
395 fsp->num_smb_operations++;
396 return True;
399 /****************************************************************************
400 Check if we have a correct fsp pointing to a quota fake file. Replacement for
401 the CHECK_NTQUOTA_HANDLE_OK macro.
402 ****************************************************************************/
404 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
405 files_struct *fsp)
407 if (!check_fsp_open(conn, req, fsp)) {
408 return false;
411 if (fsp->is_directory) {
412 return false;
415 if (fsp->fake_file_handle == NULL) {
416 return false;
419 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
420 return false;
423 if (fsp->fake_file_handle->private_data == NULL) {
424 return false;
427 return true;
430 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
431 const char *name, int name_type)
433 char *trim_name;
434 char *trim_name_type;
435 const char *retarget_parm;
436 char *retarget;
437 char *p;
438 int retarget_type = 0x20;
439 int retarget_port = NBT_SMB_PORT;
440 struct sockaddr_storage retarget_addr;
441 struct sockaddr_in *in_addr;
442 bool ret = false;
443 uint8_t outbuf[10];
445 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
446 return false;
449 trim_name = talloc_strdup(talloc_tos(), name);
450 if (trim_name == NULL) {
451 goto fail;
453 trim_char(trim_name, ' ', ' ');
455 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
456 name_type);
457 if (trim_name_type == NULL) {
458 goto fail;
461 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
462 trim_name_type, NULL);
463 if (retarget_parm == NULL) {
464 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
465 trim_name, NULL);
467 if (retarget_parm == NULL) {
468 goto fail;
471 retarget = talloc_strdup(trim_name, retarget_parm);
472 if (retarget == NULL) {
473 goto fail;
476 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
478 p = strchr(retarget, ':');
479 if (p != NULL) {
480 *p++ = '\0';
481 retarget_port = atoi(p);
484 p = strchr_m(retarget, '#');
485 if (p != NULL) {
486 *p++ = '\0';
487 if (sscanf(p, "%x", &retarget_type) != 1) {
488 goto fail;
492 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
493 if (!ret) {
494 DEBUG(10, ("could not resolve %s\n", retarget));
495 goto fail;
498 if (retarget_addr.ss_family != AF_INET) {
499 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
500 goto fail;
503 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
505 _smb_setlen(outbuf, 6);
506 SCVAL(outbuf, 0, 0x84);
507 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
508 *(uint16_t *)(outbuf+8) = htons(retarget_port);
510 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
511 NULL)) {
512 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
513 "failed.");
516 ret = true;
517 fail:
518 TALLOC_FREE(trim_name);
519 return ret;
522 static void reply_called_name_not_present(char *outbuf)
524 smb_setlen(outbuf, 1);
525 SCVAL(outbuf, 0, 0x83);
526 SCVAL(outbuf, 4, 0x82);
529 /****************************************************************************
530 Reply to a (netbios-level) special message.
531 ****************************************************************************/
533 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
535 int msg_type = CVAL(inbuf,0);
536 int msg_flags = CVAL(inbuf,1);
538 * We only really use 4 bytes of the outbuf, but for the smb_setlen
539 * calculation & friends (srv_send_smb uses that) we need the full smb
540 * header.
542 char outbuf[smb_size];
544 memset(outbuf, '\0', sizeof(outbuf));
546 smb_setlen(outbuf,0);
548 switch (msg_type) {
549 case NBSSrequest: /* session request */
551 /* inbuf_size is guarenteed to be at least 4. */
552 fstring name1,name2;
553 int name_type1, name_type2;
554 int name_len1, name_len2;
556 *name1 = *name2 = 0;
558 if (sconn->nbt.got_session) {
559 exit_server_cleanly("multiple session request not permitted");
562 SCVAL(outbuf,0,NBSSpositive);
563 SCVAL(outbuf,3,0);
565 /* inbuf_size is guaranteed to be at least 4. */
566 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
567 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
568 DEBUG(0,("Invalid name length in session request\n"));
569 reply_called_name_not_present(outbuf);
570 break;
572 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
573 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
574 DEBUG(0,("Invalid name length in session request\n"));
575 reply_called_name_not_present(outbuf);
576 break;
579 name_type1 = name_extract((unsigned char *)inbuf,
580 inbuf_size,(unsigned int)4,name1);
581 name_type2 = name_extract((unsigned char *)inbuf,
582 inbuf_size,(unsigned int)(4 + name_len1),name2);
584 if (name_type1 == -1 || name_type2 == -1) {
585 DEBUG(0,("Invalid name type in session request\n"));
586 reply_called_name_not_present(outbuf);
587 break;
590 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
591 name1, name_type1, name2, name_type2));
593 if (netbios_session_retarget(sconn, name1, name_type1)) {
594 exit_server_cleanly("retargeted client");
598 * Windows NT/2k uses "*SMBSERVER" and XP uses
599 * "*SMBSERV" arrggg!!!
601 if (strequal(name1, "*SMBSERVER ")
602 || strequal(name1, "*SMBSERV ")) {
603 char *raddr;
605 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
606 talloc_tos());
607 if (raddr == NULL) {
608 exit_server_cleanly("could not allocate raddr");
611 fstrcpy(name1, raddr);
614 set_local_machine_name(name1, True);
615 set_remote_machine_name(name2, True);
617 if (is_ipaddress(sconn->remote_hostname)) {
618 char *p = discard_const_p(char, sconn->remote_hostname);
620 talloc_free(p);
622 sconn->remote_hostname = talloc_strdup(sconn,
623 get_remote_machine_name());
624 if (sconn->remote_hostname == NULL) {
625 exit_server_cleanly("could not copy remote name");
627 sconn->conn->remote_hostname = sconn->remote_hostname;
630 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
631 get_local_machine_name(), get_remote_machine_name(),
632 name_type2));
634 if (name_type2 == 'R') {
635 /* We are being asked for a pathworks session ---
636 no thanks! */
637 reply_called_name_not_present(outbuf);
638 break;
641 reload_services(sconn, conn_snum_used, true);
642 reopen_logs();
644 sconn->nbt.got_session = true;
645 break;
648 case 0x89: /* session keepalive request
649 (some old clients produce this?) */
650 SCVAL(outbuf,0,NBSSkeepalive);
651 SCVAL(outbuf,3,0);
652 break;
654 case NBSSpositive: /* positive session response */
655 case NBSSnegative: /* negative session response */
656 case NBSSretarget: /* retarget session response */
657 DEBUG(0,("Unexpected session response\n"));
658 break;
660 case NBSSkeepalive: /* session keepalive */
661 default:
662 return;
665 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
666 msg_type, msg_flags));
668 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
670 if (CVAL(outbuf, 0) != 0x82) {
671 exit_server_cleanly("invalid netbios session");
673 return;
676 /****************************************************************************
677 Reply to a tcon.
678 conn POINTER CAN BE NULL HERE !
679 ****************************************************************************/
681 void reply_tcon(struct smb_request *req)
683 connection_struct *conn = req->conn;
684 const char *service;
685 char *service_buf = NULL;
686 char *password = NULL;
687 char *dev = NULL;
688 int pwlen=0;
689 NTSTATUS nt_status;
690 const char *p;
691 TALLOC_CTX *ctx = talloc_tos();
692 struct smbd_server_connection *sconn = req->sconn;
693 NTTIME now = timeval_to_nttime(&req->request_time);
695 START_PROFILE(SMBtcon);
697 if (req->buflen < 4) {
698 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
699 END_PROFILE(SMBtcon);
700 return;
703 p = (const char *)req->buf + 1;
704 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
705 p += 1;
706 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
707 p += pwlen+1;
708 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
709 p += 1;
711 if (service_buf == NULL || password == NULL || dev == NULL) {
712 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
713 END_PROFILE(SMBtcon);
714 return;
716 p = strrchr_m(service_buf,'\\');
717 if (p) {
718 service = p+1;
719 } else {
720 service = service_buf;
723 conn = make_connection(sconn, now, service, dev,
724 req->vuid,&nt_status);
725 req->conn = conn;
727 if (!conn) {
728 reply_nterror(req, nt_status);
729 END_PROFILE(SMBtcon);
730 return;
733 reply_outbuf(req, 2, 0);
734 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
735 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
736 SSVAL(req->outbuf,smb_tid,conn->cnum);
738 DEBUG(3,("tcon service=%s cnum=%d\n",
739 service, conn->cnum));
741 END_PROFILE(SMBtcon);
742 return;
745 /****************************************************************************
746 Reply to a tcon and X.
747 conn POINTER CAN BE NULL HERE !
748 ****************************************************************************/
750 void reply_tcon_and_X(struct smb_request *req)
752 connection_struct *conn = req->conn;
753 const char *service = NULL;
754 TALLOC_CTX *ctx = talloc_tos();
755 /* what the cleint thinks the device is */
756 char *client_devicetype = NULL;
757 /* what the server tells the client the share represents */
758 const char *server_devicetype;
759 NTSTATUS nt_status;
760 int passlen;
761 char *path = NULL;
762 const char *p, *q;
763 uint16_t tcon_flags;
764 struct smbXsrv_session *session = NULL;
765 NTTIME now = timeval_to_nttime(&req->request_time);
766 bool session_key_updated = false;
767 uint16_t optional_support = 0;
768 struct smbd_server_connection *sconn = req->sconn;
770 START_PROFILE(SMBtconX);
772 if (req->wct < 4) {
773 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
774 END_PROFILE(SMBtconX);
775 return;
778 passlen = SVAL(req->vwv+3, 0);
779 tcon_flags = SVAL(req->vwv+2, 0);
781 /* we might have to close an old one */
782 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
783 struct smbXsrv_tcon *tcon;
784 NTSTATUS status;
786 tcon = conn->tcon;
787 req->conn = NULL;
788 conn = NULL;
791 * TODO: cancel all outstanding requests on the tcon
793 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
794 if (!NT_STATUS_IS_OK(status)) {
795 DEBUG(0, ("reply_tcon_and_X: "
796 "smbXsrv_tcon_disconnect() failed: %s\n",
797 nt_errstr(status)));
799 * If we hit this case, there is something completely
800 * wrong, so we better disconnect the transport connection.
802 END_PROFILE(SMBtconX);
803 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
804 return;
807 TALLOC_FREE(tcon);
810 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
811 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
812 END_PROFILE(SMBtconX);
813 return;
816 if (sconn->smb1.negprot.encrypted_passwords) {
817 p = (const char *)req->buf + passlen;
818 } else {
819 p = (const char *)req->buf + passlen + 1;
822 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
824 if (path == NULL) {
825 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
826 END_PROFILE(SMBtconX);
827 return;
831 * the service name can be either: \\server\share
832 * or share directly like on the DELL PowerVault 705
834 if (*path=='\\') {
835 q = strchr_m(path+2,'\\');
836 if (!q) {
837 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
838 END_PROFILE(SMBtconX);
839 return;
841 service = q+1;
842 } else {
843 service = path;
846 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
847 &client_devicetype, p,
848 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
850 if (client_devicetype == NULL) {
851 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
852 END_PROFILE(SMBtconX);
853 return;
856 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
858 nt_status = smb1srv_session_lookup(req->sconn->conn,
859 req->vuid, now, &session);
860 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
861 reply_force_doserror(req, ERRSRV, ERRbaduid);
862 END_PROFILE(SMBtconX);
863 return;
865 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
866 reply_nterror(req, nt_status);
867 END_PROFILE(SMBtconX);
868 return;
870 if (!NT_STATUS_IS_OK(nt_status)) {
871 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
872 END_PROFILE(SMBtconX);
873 return;
876 if (session->global->auth_session_info == NULL) {
877 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
878 END_PROFILE(SMBtconX);
879 return;
883 * If there is no application key defined yet
884 * we create one.
886 * This means we setup the application key on the
887 * first tcon that happens via the given session.
889 * Once the application key is defined, it does not
890 * change any more.
892 if (session->global->application_key.length == 0 &&
893 session->global->signing_key.length > 0)
895 struct smbXsrv_session *x = session;
896 struct auth_session_info *session_info =
897 session->global->auth_session_info;
898 uint8_t session_key[16];
900 ZERO_STRUCT(session_key);
901 memcpy(session_key, x->global->signing_key.data,
902 MIN(x->global->signing_key.length, sizeof(session_key)));
905 * The application key is truncated/padded to 16 bytes
907 x->global->application_key = data_blob_talloc(x->global,
908 session_key,
909 sizeof(session_key));
910 ZERO_STRUCT(session_key);
911 if (x->global->application_key.data == NULL) {
912 reply_nterror(req, NT_STATUS_NO_MEMORY);
913 END_PROFILE(SMBtconX);
914 return;
917 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
918 smb_key_derivation(x->global->application_key.data,
919 x->global->application_key.length,
920 x->global->application_key.data);
921 optional_support |= SMB_EXTENDED_SIGNATURES;
925 * Place the application key into the session_info
927 data_blob_clear_free(&session_info->session_key);
928 session_info->session_key = data_blob_dup_talloc(session_info,
929 x->global->application_key);
930 if (session_info->session_key.data == NULL) {
931 data_blob_clear_free(&x->global->application_key);
932 reply_nterror(req, NT_STATUS_NO_MEMORY);
933 END_PROFILE(SMBtconX);
934 return;
936 session_key_updated = true;
939 conn = make_connection(sconn, now, service, client_devicetype,
940 req->vuid, &nt_status);
941 req->conn =conn;
943 if (!conn) {
944 if (session_key_updated) {
945 struct smbXsrv_session *x = session;
946 struct auth_session_info *session_info =
947 session->global->auth_session_info;
948 data_blob_clear_free(&x->global->application_key);
949 data_blob_clear_free(&session_info->session_key);
951 reply_nterror(req, nt_status);
952 END_PROFILE(SMBtconX);
953 return;
956 if ( IS_IPC(conn) )
957 server_devicetype = "IPC";
958 else if ( IS_PRINT(conn) )
959 server_devicetype = "LPT1:";
960 else
961 server_devicetype = "A:";
963 if (get_Protocol() < PROTOCOL_NT1) {
964 reply_outbuf(req, 2, 0);
965 if (message_push_string(&req->outbuf, server_devicetype,
966 STR_TERMINATE|STR_ASCII) == -1) {
967 reply_nterror(req, NT_STATUS_NO_MEMORY);
968 END_PROFILE(SMBtconX);
969 return;
971 } else {
972 /* NT sets the fstype of IPC$ to the null string */
973 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
975 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
976 /* Return permissions. */
977 uint32 perm1 = 0;
978 uint32 perm2 = 0;
980 reply_outbuf(req, 7, 0);
982 if (IS_IPC(conn)) {
983 perm1 = FILE_ALL_ACCESS;
984 perm2 = FILE_ALL_ACCESS;
985 } else {
986 perm1 = conn->share_access;
989 SIVAL(req->outbuf, smb_vwv3, perm1);
990 SIVAL(req->outbuf, smb_vwv5, perm2);
991 } else {
992 reply_outbuf(req, 3, 0);
995 if ((message_push_string(&req->outbuf, server_devicetype,
996 STR_TERMINATE|STR_ASCII) == -1)
997 || (message_push_string(&req->outbuf, fstype,
998 STR_TERMINATE) == -1)) {
999 reply_nterror(req, NT_STATUS_NO_MEMORY);
1000 END_PROFILE(SMBtconX);
1001 return;
1004 /* what does setting this bit do? It is set by NT4 and
1005 may affect the ability to autorun mounted cdroms */
1006 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1007 optional_support |=
1008 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1010 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1011 DEBUG(2,("Serving %s as a Dfs root\n",
1012 lp_servicename(ctx, SNUM(conn)) ));
1013 optional_support |= SMB_SHARE_IN_DFS;
1016 SSVAL(req->outbuf, smb_vwv2, optional_support);
1019 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1020 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1022 DEBUG(3,("tconX service=%s \n",
1023 service));
1025 /* set the incoming and outgoing tid to the just created one */
1026 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1027 SSVAL(req->outbuf,smb_tid,conn->cnum);
1029 END_PROFILE(SMBtconX);
1031 req->tid = conn->cnum;
1034 /****************************************************************************
1035 Reply to an unknown type.
1036 ****************************************************************************/
1038 void reply_unknown_new(struct smb_request *req, uint8 type)
1040 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1041 smb_fn_name(type), type, type));
1042 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1043 return;
1046 /****************************************************************************
1047 Reply to an ioctl.
1048 conn POINTER CAN BE NULL HERE !
1049 ****************************************************************************/
1051 void reply_ioctl(struct smb_request *req)
1053 connection_struct *conn = req->conn;
1054 uint16 device;
1055 uint16 function;
1056 uint32 ioctl_code;
1057 int replysize;
1058 char *p;
1060 START_PROFILE(SMBioctl);
1062 if (req->wct < 3) {
1063 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1064 END_PROFILE(SMBioctl);
1065 return;
1068 device = SVAL(req->vwv+1, 0);
1069 function = SVAL(req->vwv+2, 0);
1070 ioctl_code = (device << 16) + function;
1072 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1074 switch (ioctl_code) {
1075 case IOCTL_QUERY_JOB_INFO:
1076 replysize = 32;
1077 break;
1078 default:
1079 reply_force_doserror(req, ERRSRV, ERRnosupport);
1080 END_PROFILE(SMBioctl);
1081 return;
1084 reply_outbuf(req, 8, replysize+1);
1085 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1086 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1087 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1088 p = smb_buf(req->outbuf);
1089 memset(p, '\0', replysize+1); /* valgrind-safe. */
1090 p += 1; /* Allow for alignment */
1092 switch (ioctl_code) {
1093 case IOCTL_QUERY_JOB_INFO:
1095 files_struct *fsp = file_fsp(
1096 req, SVAL(req->vwv+0, 0));
1097 if (!fsp) {
1098 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1099 END_PROFILE(SMBioctl);
1100 return;
1102 /* Job number */
1103 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1105 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1106 lp_netbios_name(), 15,
1107 STR_TERMINATE|STR_ASCII);
1108 if (conn) {
1109 srvstr_push((char *)req->outbuf, req->flags2,
1110 p+18,
1111 lp_servicename(talloc_tos(),
1112 SNUM(conn)),
1113 13, STR_TERMINATE|STR_ASCII);
1114 } else {
1115 memset(p+18, 0, 13);
1117 break;
1121 END_PROFILE(SMBioctl);
1122 return;
1125 /****************************************************************************
1126 Strange checkpath NTSTATUS mapping.
1127 ****************************************************************************/
1129 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1131 /* Strange DOS error code semantics only for checkpath... */
1132 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1133 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1134 /* We need to map to ERRbadpath */
1135 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1138 return status;
1141 /****************************************************************************
1142 Reply to a checkpath.
1143 ****************************************************************************/
1145 void reply_checkpath(struct smb_request *req)
1147 connection_struct *conn = req->conn;
1148 struct smb_filename *smb_fname = NULL;
1149 char *name = NULL;
1150 NTSTATUS status;
1151 TALLOC_CTX *ctx = talloc_tos();
1153 START_PROFILE(SMBcheckpath);
1155 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1156 STR_TERMINATE, &status);
1158 if (!NT_STATUS_IS_OK(status)) {
1159 status = map_checkpath_error(req->flags2, status);
1160 reply_nterror(req, status);
1161 END_PROFILE(SMBcheckpath);
1162 return;
1165 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1167 status = filename_convert(ctx,
1168 conn,
1169 req->flags2 & FLAGS2_DFS_PATHNAMES,
1170 name,
1172 NULL,
1173 &smb_fname);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1177 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1178 ERRSRV, ERRbadpath);
1179 END_PROFILE(SMBcheckpath);
1180 return;
1182 goto path_err;
1185 if (!VALID_STAT(smb_fname->st) &&
1186 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1187 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1188 smb_fname_str_dbg(smb_fname), strerror(errno)));
1189 status = map_nt_error_from_unix(errno);
1190 goto path_err;
1193 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1194 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1195 ERRDOS, ERRbadpath);
1196 goto out;
1199 reply_outbuf(req, 0, 0);
1201 path_err:
1202 /* We special case this - as when a Windows machine
1203 is parsing a path is steps through the components
1204 one at a time - if a component fails it expects
1205 ERRbadpath, not ERRbadfile.
1207 status = map_checkpath_error(req->flags2, status);
1208 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1210 * Windows returns different error codes if
1211 * the parent directory is valid but not the
1212 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1213 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1214 * if the path is invalid.
1216 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1217 ERRDOS, ERRbadpath);
1218 goto out;
1221 reply_nterror(req, status);
1223 out:
1224 TALLOC_FREE(smb_fname);
1225 END_PROFILE(SMBcheckpath);
1226 return;
1229 /****************************************************************************
1230 Reply to a getatr.
1231 ****************************************************************************/
1233 void reply_getatr(struct smb_request *req)
1235 connection_struct *conn = req->conn;
1236 struct smb_filename *smb_fname = NULL;
1237 char *fname = NULL;
1238 int mode=0;
1239 off_t size=0;
1240 time_t mtime=0;
1241 const char *p;
1242 NTSTATUS status;
1243 TALLOC_CTX *ctx = talloc_tos();
1244 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1246 START_PROFILE(SMBgetatr);
1248 p = (const char *)req->buf + 1;
1249 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 reply_nterror(req, status);
1252 goto out;
1255 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1256 under WfWg - weird! */
1257 if (*fname == '\0') {
1258 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1259 if (!CAN_WRITE(conn)) {
1260 mode |= FILE_ATTRIBUTE_READONLY;
1262 size = 0;
1263 mtime = 0;
1264 } else {
1265 status = filename_convert(ctx,
1266 conn,
1267 req->flags2 & FLAGS2_DFS_PATHNAMES,
1268 fname,
1270 NULL,
1271 &smb_fname);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1274 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1275 ERRSRV, ERRbadpath);
1276 goto out;
1278 reply_nterror(req, status);
1279 goto out;
1281 if (!VALID_STAT(smb_fname->st) &&
1282 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1283 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1284 smb_fname_str_dbg(smb_fname),
1285 strerror(errno)));
1286 reply_nterror(req, map_nt_error_from_unix(errno));
1287 goto out;
1290 mode = dos_mode(conn, smb_fname);
1291 size = smb_fname->st.st_ex_size;
1293 if (ask_sharemode) {
1294 struct timespec write_time_ts;
1295 struct file_id fileid;
1297 ZERO_STRUCT(write_time_ts);
1298 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1299 get_file_infos(fileid, 0, NULL, &write_time_ts);
1300 if (!null_timespec(write_time_ts)) {
1301 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1305 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1306 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1307 size = 0;
1311 reply_outbuf(req, 10, 0);
1313 SSVAL(req->outbuf,smb_vwv0,mode);
1314 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1315 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1316 } else {
1317 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1319 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1321 if (get_Protocol() >= PROTOCOL_NT1) {
1322 SSVAL(req->outbuf, smb_flg2,
1323 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1326 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1327 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1329 out:
1330 TALLOC_FREE(smb_fname);
1331 TALLOC_FREE(fname);
1332 END_PROFILE(SMBgetatr);
1333 return;
1336 /****************************************************************************
1337 Reply to a setatr.
1338 ****************************************************************************/
1340 void reply_setatr(struct smb_request *req)
1342 struct smb_file_time ft;
1343 connection_struct *conn = req->conn;
1344 struct smb_filename *smb_fname = NULL;
1345 char *fname = NULL;
1346 int mode;
1347 time_t mtime;
1348 const char *p;
1349 NTSTATUS status;
1350 TALLOC_CTX *ctx = talloc_tos();
1352 START_PROFILE(SMBsetatr);
1354 ZERO_STRUCT(ft);
1356 if (req->wct < 2) {
1357 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1358 goto out;
1361 p = (const char *)req->buf + 1;
1362 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1363 if (!NT_STATUS_IS_OK(status)) {
1364 reply_nterror(req, status);
1365 goto out;
1368 status = filename_convert(ctx,
1369 conn,
1370 req->flags2 & FLAGS2_DFS_PATHNAMES,
1371 fname,
1373 NULL,
1374 &smb_fname);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1377 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1378 ERRSRV, ERRbadpath);
1379 goto out;
1381 reply_nterror(req, status);
1382 goto out;
1385 if (smb_fname->base_name[0] == '.' &&
1386 smb_fname->base_name[1] == '\0') {
1388 * Not sure here is the right place to catch this
1389 * condition. Might be moved to somewhere else later -- vl
1391 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1392 goto out;
1395 mode = SVAL(req->vwv+0, 0);
1396 mtime = srv_make_unix_date3(req->vwv+1);
1398 if (mode != FILE_ATTRIBUTE_NORMAL) {
1399 if (VALID_STAT_OF_DIR(smb_fname->st))
1400 mode |= FILE_ATTRIBUTE_DIRECTORY;
1401 else
1402 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1404 status = check_access(conn, NULL, smb_fname,
1405 FILE_WRITE_ATTRIBUTES);
1406 if (!NT_STATUS_IS_OK(status)) {
1407 reply_nterror(req, status);
1408 goto out;
1411 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1412 false) != 0) {
1413 reply_nterror(req, map_nt_error_from_unix(errno));
1414 goto out;
1418 ft.mtime = convert_time_t_to_timespec(mtime);
1419 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 reply_nterror(req, status);
1422 goto out;
1425 reply_outbuf(req, 0, 0);
1427 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1428 mode));
1429 out:
1430 TALLOC_FREE(smb_fname);
1431 END_PROFILE(SMBsetatr);
1432 return;
1435 /****************************************************************************
1436 Reply to a dskattr.
1437 ****************************************************************************/
1439 void reply_dskattr(struct smb_request *req)
1441 connection_struct *conn = req->conn;
1442 uint64_t dfree,dsize,bsize;
1443 START_PROFILE(SMBdskattr);
1445 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1446 reply_nterror(req, map_nt_error_from_unix(errno));
1447 END_PROFILE(SMBdskattr);
1448 return;
1451 reply_outbuf(req, 5, 0);
1453 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1454 double total_space, free_space;
1455 /* we need to scale this to a number that DOS6 can handle. We
1456 use floating point so we can handle large drives on systems
1457 that don't have 64 bit integers
1459 we end up displaying a maximum of 2G to DOS systems
1461 total_space = dsize * (double)bsize;
1462 free_space = dfree * (double)bsize;
1464 dsize = (uint64_t)((total_space+63*512) / (64*512));
1465 dfree = (uint64_t)((free_space+63*512) / (64*512));
1467 if (dsize > 0xFFFF) dsize = 0xFFFF;
1468 if (dfree > 0xFFFF) dfree = 0xFFFF;
1470 SSVAL(req->outbuf,smb_vwv0,dsize);
1471 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1472 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1473 SSVAL(req->outbuf,smb_vwv3,dfree);
1474 } else {
1475 SSVAL(req->outbuf,smb_vwv0,dsize);
1476 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1477 SSVAL(req->outbuf,smb_vwv2,512);
1478 SSVAL(req->outbuf,smb_vwv3,dfree);
1481 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1483 END_PROFILE(SMBdskattr);
1484 return;
1488 * Utility function to split the filename from the directory.
1490 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1491 char **fname_dir_out,
1492 char **fname_mask_out)
1494 const char *p = NULL;
1495 char *fname_dir = NULL;
1496 char *fname_mask = NULL;
1498 p = strrchr_m(fname_in, '/');
1499 if (!p) {
1500 fname_dir = talloc_strdup(ctx, ".");
1501 fname_mask = talloc_strdup(ctx, fname_in);
1502 } else {
1503 fname_dir = talloc_strndup(ctx, fname_in,
1504 PTR_DIFF(p, fname_in));
1505 fname_mask = talloc_strdup(ctx, p+1);
1508 if (!fname_dir || !fname_mask) {
1509 TALLOC_FREE(fname_dir);
1510 TALLOC_FREE(fname_mask);
1511 return NT_STATUS_NO_MEMORY;
1514 *fname_dir_out = fname_dir;
1515 *fname_mask_out = fname_mask;
1516 return NT_STATUS_OK;
1519 /****************************************************************************
1520 Reply to a search.
1521 Can be called from SMBsearch, SMBffirst or SMBfunique.
1522 ****************************************************************************/
1524 void reply_search(struct smb_request *req)
1526 connection_struct *conn = req->conn;
1527 char *path = NULL;
1528 const char *mask = NULL;
1529 char *directory = NULL;
1530 struct smb_filename *smb_fname = NULL;
1531 char *fname = NULL;
1532 off_t size;
1533 uint32 mode;
1534 struct timespec date;
1535 uint32 dirtype;
1536 unsigned int numentries = 0;
1537 unsigned int maxentries = 0;
1538 bool finished = False;
1539 const char *p;
1540 int status_len;
1541 char status[21];
1542 int dptr_num= -1;
1543 bool check_descend = False;
1544 bool expect_close = False;
1545 NTSTATUS nt_status;
1546 bool mask_contains_wcard = False;
1547 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1548 TALLOC_CTX *ctx = talloc_tos();
1549 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1550 struct dptr_struct *dirptr = NULL;
1551 struct smbd_server_connection *sconn = req->sconn;
1553 START_PROFILE(SMBsearch);
1555 if (req->wct < 2) {
1556 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1557 goto out;
1560 if (lp_posix_pathnames()) {
1561 reply_unknown_new(req, req->cmd);
1562 goto out;
1565 /* If we were called as SMBffirst then we must expect close. */
1566 if(req->cmd == SMBffirst) {
1567 expect_close = True;
1570 reply_outbuf(req, 1, 3);
1571 maxentries = SVAL(req->vwv+0, 0);
1572 dirtype = SVAL(req->vwv+1, 0);
1573 p = (const char *)req->buf + 1;
1574 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1575 &nt_status, &mask_contains_wcard);
1576 if (!NT_STATUS_IS_OK(nt_status)) {
1577 reply_nterror(req, nt_status);
1578 goto out;
1581 p++;
1582 status_len = SVAL(p, 0);
1583 p += 2;
1585 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1587 if (status_len == 0) {
1588 nt_status = filename_convert(ctx, conn,
1589 req->flags2 & FLAGS2_DFS_PATHNAMES,
1590 path,
1591 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1592 &mask_contains_wcard,
1593 &smb_fname);
1594 if (!NT_STATUS_IS_OK(nt_status)) {
1595 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1596 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1597 ERRSRV, ERRbadpath);
1598 goto out;
1600 reply_nterror(req, nt_status);
1601 goto out;
1604 directory = smb_fname->base_name;
1606 p = strrchr_m(directory,'/');
1607 if ((p != NULL) && (*directory != '/')) {
1608 mask = p + 1;
1609 directory = talloc_strndup(ctx, directory,
1610 PTR_DIFF(p, directory));
1611 } else {
1612 mask = directory;
1613 directory = talloc_strdup(ctx,".");
1616 if (!directory) {
1617 reply_nterror(req, NT_STATUS_NO_MEMORY);
1618 goto out;
1621 memset((char *)status,'\0',21);
1622 SCVAL(status,0,(dirtype & 0x1F));
1624 nt_status = dptr_create(conn,
1625 NULL, /* req */
1626 NULL, /* fsp */
1627 directory,
1628 True,
1629 expect_close,
1630 req->smbpid,
1631 mask,
1632 mask_contains_wcard,
1633 dirtype,
1634 &dirptr);
1635 if (!NT_STATUS_IS_OK(nt_status)) {
1636 reply_nterror(req, nt_status);
1637 goto out;
1639 dptr_num = dptr_dnum(dirptr);
1640 } else {
1641 int status_dirtype;
1642 const char *dirpath;
1644 memcpy(status,p,21);
1645 status_dirtype = CVAL(status,0) & 0x1F;
1646 if (status_dirtype != (dirtype & 0x1F)) {
1647 dirtype = status_dirtype;
1650 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1651 if (!dirptr) {
1652 goto SearchEmpty;
1654 dirpath = dptr_path(sconn, dptr_num);
1655 directory = talloc_strdup(ctx, dirpath);
1656 if (!directory) {
1657 reply_nterror(req, NT_STATUS_NO_MEMORY);
1658 goto out;
1661 mask = dptr_wcard(sconn, dptr_num);
1662 if (!mask) {
1663 goto SearchEmpty;
1666 * For a 'continue' search we have no string. So
1667 * check from the initial saved string.
1669 mask_contains_wcard = ms_has_wild(mask);
1670 dirtype = dptr_attr(sconn, dptr_num);
1673 DEBUG(4,("dptr_num is %d\n",dptr_num));
1675 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1676 dptr_init_search_op(dirptr);
1678 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1679 char buf[DIR_STRUCT_SIZE];
1680 memcpy(buf,status,21);
1681 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1682 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1683 reply_nterror(req, NT_STATUS_NO_MEMORY);
1684 goto out;
1686 dptr_fill(sconn, buf+12,dptr_num);
1687 if (dptr_zero(buf+12) && (status_len==0)) {
1688 numentries = 1;
1689 } else {
1690 numentries = 0;
1692 if (message_push_blob(&req->outbuf,
1693 data_blob_const(buf, sizeof(buf)))
1694 == -1) {
1695 reply_nterror(req, NT_STATUS_NO_MEMORY);
1696 goto out;
1698 } else {
1699 unsigned int i;
1700 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1701 size_t available_space = sconn->smb1.sessions.max_send - hdr_size;
1703 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1705 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1706 directory,lp_dontdescend(ctx, SNUM(conn))));
1707 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1708 check_descend = True;
1711 for (i=numentries;(i<maxentries) && !finished;i++) {
1712 finished = !get_dir_entry(ctx,
1713 dirptr,
1714 mask,
1715 dirtype,
1716 &fname,
1717 &size,
1718 &mode,
1719 &date,
1720 check_descend,
1721 ask_sharemode);
1722 if (!finished) {
1723 char buf[DIR_STRUCT_SIZE];
1724 memcpy(buf,status,21);
1725 if (!make_dir_struct(ctx,
1726 buf,
1727 mask,
1728 fname,
1729 size,
1730 mode,
1731 convert_timespec_to_time_t(date),
1732 !allow_long_path_components)) {
1733 reply_nterror(req, NT_STATUS_NO_MEMORY);
1734 goto out;
1736 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1737 break;
1739 if (message_push_blob(&req->outbuf,
1740 data_blob_const(buf, sizeof(buf)))
1741 == -1) {
1742 reply_nterror(req, NT_STATUS_NO_MEMORY);
1743 goto out;
1745 numentries++;
1750 SearchEmpty:
1752 /* If we were called as SMBffirst with smb_search_id == NULL
1753 and no entries were found then return error and close dirptr
1754 (X/Open spec) */
1756 if (numentries == 0) {
1757 dptr_close(sconn, &dptr_num);
1758 } else if(expect_close && status_len == 0) {
1759 /* Close the dptr - we know it's gone */
1760 dptr_close(sconn, &dptr_num);
1763 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1764 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1765 dptr_close(sconn, &dptr_num);
1768 if ((numentries == 0) && !mask_contains_wcard) {
1769 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1770 goto out;
1773 SSVAL(req->outbuf,smb_vwv0,numentries);
1774 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1775 SCVAL(smb_buf(req->outbuf),0,5);
1776 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1778 /* The replies here are never long name. */
1779 SSVAL(req->outbuf, smb_flg2,
1780 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1781 if (!allow_long_path_components) {
1782 SSVAL(req->outbuf, smb_flg2,
1783 SVAL(req->outbuf, smb_flg2)
1784 & (~FLAGS2_LONG_PATH_COMPONENTS));
1787 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1788 SSVAL(req->outbuf, smb_flg2,
1789 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1791 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1792 smb_fn_name(req->cmd),
1793 mask,
1794 directory,
1795 dirtype,
1796 numentries,
1797 maxentries ));
1798 out:
1799 TALLOC_FREE(directory);
1800 TALLOC_FREE(smb_fname);
1801 END_PROFILE(SMBsearch);
1802 return;
1805 /****************************************************************************
1806 Reply to a fclose (stop directory search).
1807 ****************************************************************************/
1809 void reply_fclose(struct smb_request *req)
1811 int status_len;
1812 char status[21];
1813 int dptr_num= -2;
1814 const char *p;
1815 char *path = NULL;
1816 NTSTATUS err;
1817 bool path_contains_wcard = False;
1818 TALLOC_CTX *ctx = talloc_tos();
1819 struct smbd_server_connection *sconn = req->sconn;
1821 START_PROFILE(SMBfclose);
1823 if (lp_posix_pathnames()) {
1824 reply_unknown_new(req, req->cmd);
1825 END_PROFILE(SMBfclose);
1826 return;
1829 p = (const char *)req->buf + 1;
1830 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1831 &err, &path_contains_wcard);
1832 if (!NT_STATUS_IS_OK(err)) {
1833 reply_nterror(req, err);
1834 END_PROFILE(SMBfclose);
1835 return;
1837 p++;
1838 status_len = SVAL(p,0);
1839 p += 2;
1841 if (status_len == 0) {
1842 reply_force_doserror(req, ERRSRV, ERRsrverror);
1843 END_PROFILE(SMBfclose);
1844 return;
1847 memcpy(status,p,21);
1849 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1850 /* Close the dptr - we know it's gone */
1851 dptr_close(sconn, &dptr_num);
1854 reply_outbuf(req, 1, 0);
1855 SSVAL(req->outbuf,smb_vwv0,0);
1857 DEBUG(3,("search close\n"));
1859 END_PROFILE(SMBfclose);
1860 return;
1863 /****************************************************************************
1864 Reply to an open.
1865 ****************************************************************************/
1867 void reply_open(struct smb_request *req)
1869 connection_struct *conn = req->conn;
1870 struct smb_filename *smb_fname = NULL;
1871 char *fname = NULL;
1872 uint32 fattr=0;
1873 off_t size = 0;
1874 time_t mtime=0;
1875 int info;
1876 files_struct *fsp;
1877 int oplock_request;
1878 int deny_mode;
1879 uint32 dos_attr;
1880 uint32 access_mask;
1881 uint32 share_mode;
1882 uint32 create_disposition;
1883 uint32 create_options = 0;
1884 uint32_t private_flags = 0;
1885 NTSTATUS status;
1886 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1887 TALLOC_CTX *ctx = talloc_tos();
1889 START_PROFILE(SMBopen);
1891 if (req->wct < 2) {
1892 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1893 goto out;
1896 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1897 deny_mode = SVAL(req->vwv+0, 0);
1898 dos_attr = SVAL(req->vwv+1, 0);
1900 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1901 STR_TERMINATE, &status);
1902 if (!NT_STATUS_IS_OK(status)) {
1903 reply_nterror(req, status);
1904 goto out;
1907 if (!map_open_params_to_ntcreate(fname, deny_mode,
1908 OPENX_FILE_EXISTS_OPEN, &access_mask,
1909 &share_mode, &create_disposition,
1910 &create_options, &private_flags)) {
1911 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1912 goto out;
1915 status = filename_convert(ctx,
1916 conn,
1917 req->flags2 & FLAGS2_DFS_PATHNAMES,
1918 fname,
1919 UCF_PREP_CREATEFILE,
1920 NULL,
1921 &smb_fname);
1922 if (!NT_STATUS_IS_OK(status)) {
1923 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1924 reply_botherror(req,
1925 NT_STATUS_PATH_NOT_COVERED,
1926 ERRSRV, ERRbadpath);
1927 goto out;
1929 reply_nterror(req, status);
1930 goto out;
1933 status = SMB_VFS_CREATE_FILE(
1934 conn, /* conn */
1935 req, /* req */
1936 0, /* root_dir_fid */
1937 smb_fname, /* fname */
1938 access_mask, /* access_mask */
1939 share_mode, /* share_access */
1940 create_disposition, /* create_disposition*/
1941 create_options, /* create_options */
1942 dos_attr, /* file_attributes */
1943 oplock_request, /* oplock_request */
1944 0, /* allocation_size */
1945 private_flags,
1946 NULL, /* sd */
1947 NULL, /* ea_list */
1948 &fsp, /* result */
1949 &info); /* pinfo */
1951 if (!NT_STATUS_IS_OK(status)) {
1952 if (open_was_deferred(req->sconn, req->mid)) {
1953 /* We have re-scheduled this call. */
1954 goto out;
1956 reply_openerror(req, status);
1957 goto out;
1960 size = smb_fname->st.st_ex_size;
1961 fattr = dos_mode(conn, smb_fname);
1963 /* Deal with other possible opens having a modified
1964 write time. JRA. */
1965 if (ask_sharemode) {
1966 struct timespec write_time_ts;
1968 ZERO_STRUCT(write_time_ts);
1969 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1970 if (!null_timespec(write_time_ts)) {
1971 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1975 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1977 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1978 DEBUG(3,("attempt to open a directory %s\n",
1979 fsp_str_dbg(fsp)));
1980 close_file(req, fsp, ERROR_CLOSE);
1981 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1982 ERRDOS, ERRnoaccess);
1983 goto out;
1986 reply_outbuf(req, 7, 0);
1987 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1988 SSVAL(req->outbuf,smb_vwv1,fattr);
1989 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1990 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1991 } else {
1992 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1994 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1995 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1997 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1998 SCVAL(req->outbuf,smb_flg,
1999 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2002 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2003 SCVAL(req->outbuf,smb_flg,
2004 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2006 out:
2007 TALLOC_FREE(smb_fname);
2008 END_PROFILE(SMBopen);
2009 return;
2012 /****************************************************************************
2013 Reply to an open and X.
2014 ****************************************************************************/
2016 void reply_open_and_X(struct smb_request *req)
2018 connection_struct *conn = req->conn;
2019 struct smb_filename *smb_fname = NULL;
2020 char *fname = NULL;
2021 uint16 open_flags;
2022 int deny_mode;
2023 uint32 smb_attr;
2024 /* Breakout the oplock request bits so we can set the
2025 reply bits separately. */
2026 int ex_oplock_request;
2027 int core_oplock_request;
2028 int oplock_request;
2029 #if 0
2030 int smb_sattr = SVAL(req->vwv+4, 0);
2031 uint32 smb_time = make_unix_date3(req->vwv+6);
2032 #endif
2033 int smb_ofun;
2034 uint32 fattr=0;
2035 int mtime=0;
2036 int smb_action = 0;
2037 files_struct *fsp;
2038 NTSTATUS status;
2039 uint64_t allocation_size;
2040 ssize_t retval = -1;
2041 uint32 access_mask;
2042 uint32 share_mode;
2043 uint32 create_disposition;
2044 uint32 create_options = 0;
2045 uint32_t private_flags = 0;
2046 TALLOC_CTX *ctx = talloc_tos();
2048 START_PROFILE(SMBopenX);
2050 if (req->wct < 15) {
2051 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2052 goto out;
2055 open_flags = SVAL(req->vwv+2, 0);
2056 deny_mode = SVAL(req->vwv+3, 0);
2057 smb_attr = SVAL(req->vwv+5, 0);
2058 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2059 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2060 oplock_request = ex_oplock_request | core_oplock_request;
2061 smb_ofun = SVAL(req->vwv+8, 0);
2062 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2064 /* If it's an IPC, pass off the pipe handler. */
2065 if (IS_IPC(conn)) {
2066 if (lp_nt_pipe_support()) {
2067 reply_open_pipe_and_X(conn, req);
2068 } else {
2069 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2071 goto out;
2074 /* XXXX we need to handle passed times, sattr and flags */
2075 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2076 STR_TERMINATE, &status);
2077 if (!NT_STATUS_IS_OK(status)) {
2078 reply_nterror(req, status);
2079 goto out;
2082 if (!map_open_params_to_ntcreate(fname, deny_mode,
2083 smb_ofun,
2084 &access_mask, &share_mode,
2085 &create_disposition,
2086 &create_options,
2087 &private_flags)) {
2088 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2089 goto out;
2092 status = filename_convert(ctx,
2093 conn,
2094 req->flags2 & FLAGS2_DFS_PATHNAMES,
2095 fname,
2096 UCF_PREP_CREATEFILE,
2097 NULL,
2098 &smb_fname);
2099 if (!NT_STATUS_IS_OK(status)) {
2100 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2101 reply_botherror(req,
2102 NT_STATUS_PATH_NOT_COVERED,
2103 ERRSRV, ERRbadpath);
2104 goto out;
2106 reply_nterror(req, status);
2107 goto out;
2110 status = SMB_VFS_CREATE_FILE(
2111 conn, /* conn */
2112 req, /* req */
2113 0, /* root_dir_fid */
2114 smb_fname, /* fname */
2115 access_mask, /* access_mask */
2116 share_mode, /* share_access */
2117 create_disposition, /* create_disposition*/
2118 create_options, /* create_options */
2119 smb_attr, /* file_attributes */
2120 oplock_request, /* oplock_request */
2121 0, /* allocation_size */
2122 private_flags,
2123 NULL, /* sd */
2124 NULL, /* ea_list */
2125 &fsp, /* result */
2126 &smb_action); /* pinfo */
2128 if (!NT_STATUS_IS_OK(status)) {
2129 if (open_was_deferred(req->sconn, req->mid)) {
2130 /* We have re-scheduled this call. */
2131 goto out;
2133 reply_openerror(req, status);
2134 goto out;
2137 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2138 if the file is truncated or created. */
2139 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2140 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2141 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2142 close_file(req, fsp, ERROR_CLOSE);
2143 reply_nterror(req, NT_STATUS_DISK_FULL);
2144 goto out;
2146 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2147 if (retval < 0) {
2148 close_file(req, fsp, ERROR_CLOSE);
2149 reply_nterror(req, NT_STATUS_DISK_FULL);
2150 goto out;
2152 status = vfs_stat_fsp(fsp);
2153 if (!NT_STATUS_IS_OK(status)) {
2154 close_file(req, fsp, ERROR_CLOSE);
2155 reply_nterror(req, status);
2156 goto out;
2160 fattr = dos_mode(conn, fsp->fsp_name);
2161 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2162 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2163 close_file(req, fsp, ERROR_CLOSE);
2164 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2165 goto out;
2168 /* If the caller set the extended oplock request bit
2169 and we granted one (by whatever means) - set the
2170 correct bit for extended oplock reply.
2173 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2174 smb_action |= EXTENDED_OPLOCK_GRANTED;
2177 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2178 smb_action |= EXTENDED_OPLOCK_GRANTED;
2181 /* If the caller set the core oplock request bit
2182 and we granted one (by whatever means) - set the
2183 correct bit for core oplock reply.
2186 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2187 reply_outbuf(req, 19, 0);
2188 } else {
2189 reply_outbuf(req, 15, 0);
2192 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2193 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2195 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2196 SCVAL(req->outbuf, smb_flg,
2197 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2200 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2201 SCVAL(req->outbuf, smb_flg,
2202 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2205 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2206 SSVAL(req->outbuf,smb_vwv3,fattr);
2207 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2208 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2209 } else {
2210 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2212 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2213 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2214 SSVAL(req->outbuf,smb_vwv11,smb_action);
2216 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2217 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2220 out:
2221 TALLOC_FREE(smb_fname);
2222 END_PROFILE(SMBopenX);
2223 return;
2226 /****************************************************************************
2227 Reply to a SMBulogoffX.
2228 ****************************************************************************/
2230 void reply_ulogoffX(struct smb_request *req)
2232 struct smbd_server_connection *sconn = req->sconn;
2233 struct user_struct *vuser;
2234 struct smbXsrv_session *session = NULL;
2235 NTSTATUS status;
2237 START_PROFILE(SMBulogoffX);
2239 vuser = get_valid_user_struct(sconn, req->vuid);
2241 if(vuser == NULL) {
2242 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2243 (unsigned long long)req->vuid));
2245 req->vuid = UID_FIELD_INVALID;
2246 reply_force_doserror(req, ERRSRV, ERRbaduid);
2247 END_PROFILE(SMBulogoffX);
2248 return;
2251 session = vuser->session;
2252 vuser = NULL;
2255 * TODO: cancel all outstanding requests on the session
2257 status = smbXsrv_session_logoff(session);
2258 if (!NT_STATUS_IS_OK(status)) {
2259 DEBUG(0, ("reply_ulogoff: "
2260 "smbXsrv_session_logoff() failed: %s\n",
2261 nt_errstr(status)));
2263 * If we hit this case, there is something completely
2264 * wrong, so we better disconnect the transport connection.
2266 END_PROFILE(SMBulogoffX);
2267 exit_server(__location__ ": smbXsrv_session_logoff failed");
2268 return;
2271 TALLOC_FREE(session);
2273 reply_outbuf(req, 2, 0);
2274 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2275 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2277 DEBUG(3, ("ulogoffX vuid=%llu\n",
2278 (unsigned long long)req->vuid));
2280 END_PROFILE(SMBulogoffX);
2281 req->vuid = UID_FIELD_INVALID;
2284 /****************************************************************************
2285 Reply to a mknew or a create.
2286 ****************************************************************************/
2288 void reply_mknew(struct smb_request *req)
2290 connection_struct *conn = req->conn;
2291 struct smb_filename *smb_fname = NULL;
2292 char *fname = NULL;
2293 uint32 fattr = 0;
2294 struct smb_file_time ft;
2295 files_struct *fsp;
2296 int oplock_request = 0;
2297 NTSTATUS status;
2298 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2299 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2300 uint32 create_disposition;
2301 uint32 create_options = 0;
2302 TALLOC_CTX *ctx = talloc_tos();
2304 START_PROFILE(SMBcreate);
2305 ZERO_STRUCT(ft);
2307 if (req->wct < 3) {
2308 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2309 goto out;
2312 fattr = SVAL(req->vwv+0, 0);
2313 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2315 /* mtime. */
2316 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2318 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2319 STR_TERMINATE, &status);
2320 if (!NT_STATUS_IS_OK(status)) {
2321 reply_nterror(req, status);
2322 goto out;
2325 status = filename_convert(ctx,
2326 conn,
2327 req->flags2 & FLAGS2_DFS_PATHNAMES,
2328 fname,
2329 UCF_PREP_CREATEFILE,
2330 NULL,
2331 &smb_fname);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2334 reply_botherror(req,
2335 NT_STATUS_PATH_NOT_COVERED,
2336 ERRSRV, ERRbadpath);
2337 goto out;
2339 reply_nterror(req, status);
2340 goto out;
2343 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2344 DEBUG(0,("Attempt to create file (%s) with volid set - "
2345 "please report this\n",
2346 smb_fname_str_dbg(smb_fname)));
2349 if(req->cmd == SMBmknew) {
2350 /* We should fail if file exists. */
2351 create_disposition = FILE_CREATE;
2352 } else {
2353 /* Create if file doesn't exist, truncate if it does. */
2354 create_disposition = FILE_OVERWRITE_IF;
2357 status = SMB_VFS_CREATE_FILE(
2358 conn, /* conn */
2359 req, /* req */
2360 0, /* root_dir_fid */
2361 smb_fname, /* fname */
2362 access_mask, /* access_mask */
2363 share_mode, /* share_access */
2364 create_disposition, /* create_disposition*/
2365 create_options, /* create_options */
2366 fattr, /* file_attributes */
2367 oplock_request, /* oplock_request */
2368 0, /* allocation_size */
2369 0, /* private_flags */
2370 NULL, /* sd */
2371 NULL, /* ea_list */
2372 &fsp, /* result */
2373 NULL); /* pinfo */
2375 if (!NT_STATUS_IS_OK(status)) {
2376 if (open_was_deferred(req->sconn, req->mid)) {
2377 /* We have re-scheduled this call. */
2378 goto out;
2380 reply_openerror(req, status);
2381 goto out;
2384 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2385 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2386 if (!NT_STATUS_IS_OK(status)) {
2387 END_PROFILE(SMBcreate);
2388 goto out;
2391 reply_outbuf(req, 1, 0);
2392 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2394 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2395 SCVAL(req->outbuf,smb_flg,
2396 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2399 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2400 SCVAL(req->outbuf,smb_flg,
2401 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2404 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2405 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2406 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2407 (unsigned int)fattr));
2409 out:
2410 TALLOC_FREE(smb_fname);
2411 END_PROFILE(SMBcreate);
2412 return;
2415 /****************************************************************************
2416 Reply to a create temporary file.
2417 ****************************************************************************/
2419 void reply_ctemp(struct smb_request *req)
2421 connection_struct *conn = req->conn;
2422 struct smb_filename *smb_fname = NULL;
2423 char *wire_name = NULL;
2424 char *fname = NULL;
2425 uint32 fattr;
2426 files_struct *fsp;
2427 int oplock_request;
2428 char *s;
2429 NTSTATUS status;
2430 int i;
2431 TALLOC_CTX *ctx = talloc_tos();
2433 START_PROFILE(SMBctemp);
2435 if (req->wct < 3) {
2436 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2437 goto out;
2440 fattr = SVAL(req->vwv+0, 0);
2441 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2443 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2444 STR_TERMINATE, &status);
2445 if (!NT_STATUS_IS_OK(status)) {
2446 reply_nterror(req, status);
2447 goto out;
2450 for (i = 0; i < 10; i++) {
2451 if (*wire_name) {
2452 fname = talloc_asprintf(ctx,
2453 "%s/TMP%s",
2454 wire_name,
2455 generate_random_str_list(ctx, 5, "0123456789"));
2456 } else {
2457 fname = talloc_asprintf(ctx,
2458 "TMP%s",
2459 generate_random_str_list(ctx, 5, "0123456789"));
2462 if (!fname) {
2463 reply_nterror(req, NT_STATUS_NO_MEMORY);
2464 goto out;
2467 status = filename_convert(ctx, conn,
2468 req->flags2 & FLAGS2_DFS_PATHNAMES,
2469 fname,
2470 UCF_PREP_CREATEFILE,
2471 NULL,
2472 &smb_fname);
2473 if (!NT_STATUS_IS_OK(status)) {
2474 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2475 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2476 ERRSRV, ERRbadpath);
2477 goto out;
2479 reply_nterror(req, status);
2480 goto out;
2483 /* Create the file. */
2484 status = SMB_VFS_CREATE_FILE(
2485 conn, /* conn */
2486 req, /* req */
2487 0, /* root_dir_fid */
2488 smb_fname, /* fname */
2489 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2490 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2491 FILE_CREATE, /* create_disposition*/
2492 0, /* create_options */
2493 fattr, /* file_attributes */
2494 oplock_request, /* oplock_request */
2495 0, /* allocation_size */
2496 0, /* private_flags */
2497 NULL, /* sd */
2498 NULL, /* ea_list */
2499 &fsp, /* result */
2500 NULL); /* pinfo */
2502 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2503 TALLOC_FREE(fname);
2504 TALLOC_FREE(smb_fname);
2505 continue;
2508 if (!NT_STATUS_IS_OK(status)) {
2509 if (open_was_deferred(req->sconn, req->mid)) {
2510 /* We have re-scheduled this call. */
2511 goto out;
2513 reply_openerror(req, status);
2514 goto out;
2517 break;
2520 if (i == 10) {
2521 /* Collision after 10 times... */
2522 reply_nterror(req, status);
2523 goto out;
2526 reply_outbuf(req, 1, 0);
2527 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2529 /* the returned filename is relative to the directory */
2530 s = strrchr_m(fsp->fsp_name->base_name, '/');
2531 if (!s) {
2532 s = fsp->fsp_name->base_name;
2533 } else {
2534 s++;
2537 #if 0
2538 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2539 thing in the byte section. JRA */
2540 SSVALS(p, 0, -1); /* what is this? not in spec */
2541 #endif
2542 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2543 == -1) {
2544 reply_nterror(req, NT_STATUS_NO_MEMORY);
2545 goto out;
2548 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2549 SCVAL(req->outbuf, smb_flg,
2550 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2553 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2554 SCVAL(req->outbuf, smb_flg,
2555 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2558 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2559 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2560 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2561 out:
2562 TALLOC_FREE(smb_fname);
2563 TALLOC_FREE(wire_name);
2564 END_PROFILE(SMBctemp);
2565 return;
2568 /*******************************************************************
2569 Check if a user is allowed to rename a file.
2570 ********************************************************************/
2572 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2573 uint16 dirtype)
2575 if (!CAN_WRITE(conn)) {
2576 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2579 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2580 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2581 /* Only bother to read the DOS attribute if we might deny the
2582 rename on the grounds of attribute missmatch. */
2583 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2584 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2585 return NT_STATUS_NO_SUCH_FILE;
2589 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2590 if (fsp->posix_open) {
2591 return NT_STATUS_OK;
2594 /* If no pathnames are open below this
2595 directory, allow the rename. */
2597 if (file_find_subpath(fsp)) {
2598 return NT_STATUS_ACCESS_DENIED;
2600 return NT_STATUS_OK;
2603 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2604 return NT_STATUS_OK;
2607 return NT_STATUS_ACCESS_DENIED;
2610 /*******************************************************************
2611 * unlink a file with all relevant access checks
2612 *******************************************************************/
2614 static NTSTATUS do_unlink(connection_struct *conn,
2615 struct smb_request *req,
2616 struct smb_filename *smb_fname,
2617 uint32 dirtype)
2619 uint32 fattr;
2620 files_struct *fsp;
2621 uint32 dirtype_orig = dirtype;
2622 NTSTATUS status;
2623 int ret;
2624 bool posix_paths = lp_posix_pathnames();
2626 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2627 smb_fname_str_dbg(smb_fname),
2628 dirtype));
2630 if (!CAN_WRITE(conn)) {
2631 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2634 if (posix_paths) {
2635 ret = SMB_VFS_LSTAT(conn, smb_fname);
2636 } else {
2637 ret = SMB_VFS_STAT(conn, smb_fname);
2639 if (ret != 0) {
2640 return map_nt_error_from_unix(errno);
2643 fattr = dos_mode(conn, smb_fname);
2645 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2646 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2649 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2650 if (!dirtype) {
2651 return NT_STATUS_NO_SUCH_FILE;
2654 if (!dir_check_ftype(conn, fattr, dirtype)) {
2655 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2656 return NT_STATUS_FILE_IS_A_DIRECTORY;
2658 return NT_STATUS_NO_SUCH_FILE;
2661 if (dirtype_orig & 0x8000) {
2662 /* These will never be set for POSIX. */
2663 return NT_STATUS_NO_SUCH_FILE;
2666 #if 0
2667 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2668 return NT_STATUS_FILE_IS_A_DIRECTORY;
2671 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2672 return NT_STATUS_NO_SUCH_FILE;
2675 if (dirtype & 0xFF00) {
2676 /* These will never be set for POSIX. */
2677 return NT_STATUS_NO_SUCH_FILE;
2680 dirtype &= 0xFF;
2681 if (!dirtype) {
2682 return NT_STATUS_NO_SUCH_FILE;
2685 /* Can't delete a directory. */
2686 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2687 return NT_STATUS_FILE_IS_A_DIRECTORY;
2689 #endif
2691 #if 0 /* JRATEST */
2692 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2693 return NT_STATUS_OBJECT_NAME_INVALID;
2694 #endif /* JRATEST */
2696 /* On open checks the open itself will check the share mode, so
2697 don't do it here as we'll get it wrong. */
2699 status = SMB_VFS_CREATE_FILE
2700 (conn, /* conn */
2701 req, /* req */
2702 0, /* root_dir_fid */
2703 smb_fname, /* fname */
2704 DELETE_ACCESS, /* access_mask */
2705 FILE_SHARE_NONE, /* share_access */
2706 FILE_OPEN, /* create_disposition*/
2707 FILE_NON_DIRECTORY_FILE, /* create_options */
2708 /* file_attributes */
2709 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2710 FILE_ATTRIBUTE_NORMAL,
2711 0, /* oplock_request */
2712 0, /* allocation_size */
2713 0, /* private_flags */
2714 NULL, /* sd */
2715 NULL, /* ea_list */
2716 &fsp, /* result */
2717 NULL); /* pinfo */
2719 if (!NT_STATUS_IS_OK(status)) {
2720 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2721 nt_errstr(status)));
2722 return status;
2725 status = can_set_delete_on_close(fsp, fattr);
2726 if (!NT_STATUS_IS_OK(status)) {
2727 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2728 "(%s)\n",
2729 smb_fname_str_dbg(smb_fname),
2730 nt_errstr(status)));
2731 close_file(req, fsp, NORMAL_CLOSE);
2732 return status;
2735 /* The set is across all open files on this dev/inode pair. */
2736 if (!set_delete_on_close(fsp, True,
2737 conn->session_info->security_token,
2738 conn->session_info->unix_token)) {
2739 close_file(req, fsp, NORMAL_CLOSE);
2740 return NT_STATUS_ACCESS_DENIED;
2743 return close_file(req, fsp, NORMAL_CLOSE);
2746 /****************************************************************************
2747 The guts of the unlink command, split out so it may be called by the NT SMB
2748 code.
2749 ****************************************************************************/
2751 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2752 uint32 dirtype, struct smb_filename *smb_fname,
2753 bool has_wild)
2755 char *fname_dir = NULL;
2756 char *fname_mask = NULL;
2757 int count=0;
2758 NTSTATUS status = NT_STATUS_OK;
2759 TALLOC_CTX *ctx = talloc_tos();
2761 /* Split up the directory from the filename/mask. */
2762 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2763 &fname_dir, &fname_mask);
2764 if (!NT_STATUS_IS_OK(status)) {
2765 goto out;
2769 * We should only check the mangled cache
2770 * here if unix_convert failed. This means
2771 * that the path in 'mask' doesn't exist
2772 * on the file system and so we need to look
2773 * for a possible mangle. This patch from
2774 * Tine Smukavec <valentin.smukavec@hermes.si>.
2777 if (!VALID_STAT(smb_fname->st) &&
2778 mangle_is_mangled(fname_mask, conn->params)) {
2779 char *new_mask = NULL;
2780 mangle_lookup_name_from_8_3(ctx, fname_mask,
2781 &new_mask, conn->params);
2782 if (new_mask) {
2783 TALLOC_FREE(fname_mask);
2784 fname_mask = new_mask;
2788 if (!has_wild) {
2791 * Only one file needs to be unlinked. Append the mask back
2792 * onto the directory.
2794 TALLOC_FREE(smb_fname->base_name);
2795 if (ISDOT(fname_dir)) {
2796 /* Ensure we use canonical names on open. */
2797 smb_fname->base_name = talloc_asprintf(smb_fname,
2798 "%s",
2799 fname_mask);
2800 } else {
2801 smb_fname->base_name = talloc_asprintf(smb_fname,
2802 "%s/%s",
2803 fname_dir,
2804 fname_mask);
2806 if (!smb_fname->base_name) {
2807 status = NT_STATUS_NO_MEMORY;
2808 goto out;
2810 if (dirtype == 0) {
2811 dirtype = FILE_ATTRIBUTE_NORMAL;
2814 status = check_name(conn, smb_fname->base_name);
2815 if (!NT_STATUS_IS_OK(status)) {
2816 goto out;
2819 status = do_unlink(conn, req, smb_fname, dirtype);
2820 if (!NT_STATUS_IS_OK(status)) {
2821 goto out;
2824 count++;
2825 } else {
2826 struct smb_Dir *dir_hnd = NULL;
2827 long offset = 0;
2828 const char *dname = NULL;
2829 char *talloced = NULL;
2831 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2832 status = NT_STATUS_OBJECT_NAME_INVALID;
2833 goto out;
2836 if (strequal(fname_mask,"????????.???")) {
2837 TALLOC_FREE(fname_mask);
2838 fname_mask = talloc_strdup(ctx, "*");
2839 if (!fname_mask) {
2840 status = NT_STATUS_NO_MEMORY;
2841 goto out;
2845 status = check_name(conn, fname_dir);
2846 if (!NT_STATUS_IS_OK(status)) {
2847 goto out;
2850 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2851 dirtype);
2852 if (dir_hnd == NULL) {
2853 status = map_nt_error_from_unix(errno);
2854 goto out;
2857 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2858 the pattern matches against the long name, otherwise the short name
2859 We don't implement this yet XXXX
2862 status = NT_STATUS_NO_SUCH_FILE;
2864 while ((dname = ReadDirName(dir_hnd, &offset,
2865 &smb_fname->st, &talloced))) {
2866 TALLOC_CTX *frame = talloc_stackframe();
2868 if (!is_visible_file(conn, fname_dir, dname,
2869 &smb_fname->st, true)) {
2870 TALLOC_FREE(frame);
2871 TALLOC_FREE(talloced);
2872 continue;
2875 /* Quick check for "." and ".." */
2876 if (ISDOT(dname) || ISDOTDOT(dname)) {
2877 TALLOC_FREE(frame);
2878 TALLOC_FREE(talloced);
2879 continue;
2882 if(!mask_match(dname, fname_mask,
2883 conn->case_sensitive)) {
2884 TALLOC_FREE(frame);
2885 TALLOC_FREE(talloced);
2886 continue;
2889 TALLOC_FREE(smb_fname->base_name);
2890 if (ISDOT(fname_dir)) {
2891 /* Ensure we use canonical names on open. */
2892 smb_fname->base_name =
2893 talloc_asprintf(smb_fname, "%s",
2894 dname);
2895 } else {
2896 smb_fname->base_name =
2897 talloc_asprintf(smb_fname, "%s/%s",
2898 fname_dir, dname);
2901 if (!smb_fname->base_name) {
2902 TALLOC_FREE(dir_hnd);
2903 status = NT_STATUS_NO_MEMORY;
2904 TALLOC_FREE(frame);
2905 TALLOC_FREE(talloced);
2906 goto out;
2909 status = check_name(conn, smb_fname->base_name);
2910 if (!NT_STATUS_IS_OK(status)) {
2911 TALLOC_FREE(dir_hnd);
2912 TALLOC_FREE(frame);
2913 TALLOC_FREE(talloced);
2914 goto out;
2917 status = do_unlink(conn, req, smb_fname, dirtype);
2918 if (!NT_STATUS_IS_OK(status)) {
2919 TALLOC_FREE(dir_hnd);
2920 TALLOC_FREE(frame);
2921 TALLOC_FREE(talloced);
2922 goto out;
2925 count++;
2926 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2927 smb_fname->base_name));
2929 TALLOC_FREE(frame);
2930 TALLOC_FREE(talloced);
2932 TALLOC_FREE(dir_hnd);
2935 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2936 status = map_nt_error_from_unix(errno);
2939 out:
2940 TALLOC_FREE(fname_dir);
2941 TALLOC_FREE(fname_mask);
2942 return status;
2945 /****************************************************************************
2946 Reply to a unlink
2947 ****************************************************************************/
2949 void reply_unlink(struct smb_request *req)
2951 connection_struct *conn = req->conn;
2952 char *name = NULL;
2953 struct smb_filename *smb_fname = NULL;
2954 uint32 dirtype;
2955 NTSTATUS status;
2956 bool path_contains_wcard = False;
2957 TALLOC_CTX *ctx = talloc_tos();
2959 START_PROFILE(SMBunlink);
2961 if (req->wct < 1) {
2962 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2963 goto out;
2966 dirtype = SVAL(req->vwv+0, 0);
2968 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2969 STR_TERMINATE, &status,
2970 &path_contains_wcard);
2971 if (!NT_STATUS_IS_OK(status)) {
2972 reply_nterror(req, status);
2973 goto out;
2976 status = filename_convert(ctx, conn,
2977 req->flags2 & FLAGS2_DFS_PATHNAMES,
2978 name,
2979 UCF_COND_ALLOW_WCARD_LCOMP,
2980 &path_contains_wcard,
2981 &smb_fname);
2982 if (!NT_STATUS_IS_OK(status)) {
2983 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2984 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2985 ERRSRV, ERRbadpath);
2986 goto out;
2988 reply_nterror(req, status);
2989 goto out;
2992 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2994 status = unlink_internals(conn, req, dirtype, smb_fname,
2995 path_contains_wcard);
2996 if (!NT_STATUS_IS_OK(status)) {
2997 if (open_was_deferred(req->sconn, req->mid)) {
2998 /* We have re-scheduled this call. */
2999 goto out;
3001 reply_nterror(req, status);
3002 goto out;
3005 reply_outbuf(req, 0, 0);
3006 out:
3007 TALLOC_FREE(smb_fname);
3008 END_PROFILE(SMBunlink);
3009 return;
3012 /****************************************************************************
3013 Fail for readbraw.
3014 ****************************************************************************/
3016 static void fail_readraw(void)
3018 const char *errstr = talloc_asprintf(talloc_tos(),
3019 "FAIL ! reply_readbraw: socket write fail (%s)",
3020 strerror(errno));
3021 if (!errstr) {
3022 errstr = "";
3024 exit_server_cleanly(errstr);
3027 /****************************************************************************
3028 Fake (read/write) sendfile. Returns -1 on read or write fail.
3029 ****************************************************************************/
3031 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
3033 size_t bufsize;
3034 size_t tosend = nread;
3035 char *buf;
3037 if (nread == 0) {
3038 return 0;
3041 bufsize = MIN(nread, 65536);
3043 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3044 return -1;
3047 while (tosend > 0) {
3048 ssize_t ret;
3049 size_t cur_read;
3051 if (tosend > bufsize) {
3052 cur_read = bufsize;
3053 } else {
3054 cur_read = tosend;
3056 ret = read_file(fsp,buf,startpos,cur_read);
3057 if (ret == -1) {
3058 SAFE_FREE(buf);
3059 return -1;
3062 /* If we had a short read, fill with zeros. */
3063 if (ret < cur_read) {
3064 memset(buf + ret, '\0', cur_read - ret);
3067 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3068 != cur_read) {
3069 char addr[INET6_ADDRSTRLEN];
3071 * Try and give an error message saying what
3072 * client failed.
3074 DEBUG(0, ("write_data failed for client %s. "
3075 "Error %s\n",
3076 get_peer_addr(fsp->conn->sconn->sock, addr,
3077 sizeof(addr)),
3078 strerror(errno)));
3079 SAFE_FREE(buf);
3080 return -1;
3082 tosend -= cur_read;
3083 startpos += cur_read;
3086 SAFE_FREE(buf);
3087 return (ssize_t)nread;
3090 /****************************************************************************
3091 Deal with the case of sendfile reading less bytes from the file than
3092 requested. Fill with zeros (all we can do).
3093 ****************************************************************************/
3095 void sendfile_short_send(files_struct *fsp,
3096 ssize_t nread,
3097 size_t headersize,
3098 size_t smb_maxcnt)
3100 #define SHORT_SEND_BUFSIZE 1024
3101 if (nread < headersize) {
3102 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3103 "header for file %s (%s). Terminating\n",
3104 fsp_str_dbg(fsp), strerror(errno)));
3105 exit_server_cleanly("sendfile_short_send failed");
3108 nread -= headersize;
3110 if (nread < smb_maxcnt) {
3111 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3112 if (!buf) {
3113 exit_server_cleanly("sendfile_short_send: "
3114 "malloc failed");
3117 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3118 "with zeros !\n", fsp_str_dbg(fsp)));
3120 while (nread < smb_maxcnt) {
3122 * We asked for the real file size and told sendfile
3123 * to not go beyond the end of the file. But it can
3124 * happen that in between our fstat call and the
3125 * sendfile call the file was truncated. This is very
3126 * bad because we have already announced the larger
3127 * number of bytes to the client.
3129 * The best we can do now is to send 0-bytes, just as
3130 * a read from a hole in a sparse file would do.
3132 * This should happen rarely enough that I don't care
3133 * about efficiency here :-)
3135 size_t to_write;
3137 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3138 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3139 != to_write) {
3140 char addr[INET6_ADDRSTRLEN];
3142 * Try and give an error message saying what
3143 * client failed.
3145 DEBUG(0, ("write_data failed for client %s. "
3146 "Error %s\n",
3147 get_peer_addr(
3148 fsp->conn->sconn->sock, addr,
3149 sizeof(addr)),
3150 strerror(errno)));
3151 exit_server_cleanly("sendfile_short_send: "
3152 "write_data failed");
3154 nread += to_write;
3156 SAFE_FREE(buf);
3160 /****************************************************************************
3161 Return a readbraw error (4 bytes of zero).
3162 ****************************************************************************/
3164 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3166 char header[4];
3168 SIVAL(header,0,0);
3170 smbd_lock_socket(sconn);
3171 if (write_data(sconn->sock,header,4) != 4) {
3172 char addr[INET6_ADDRSTRLEN];
3174 * Try and give an error message saying what
3175 * client failed.
3177 DEBUG(0, ("write_data failed for client %s. "
3178 "Error %s\n",
3179 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3180 strerror(errno)));
3182 fail_readraw();
3184 smbd_unlock_socket(sconn);
3187 /****************************************************************************
3188 Use sendfile in readbraw.
3189 ****************************************************************************/
3191 static void send_file_readbraw(connection_struct *conn,
3192 struct smb_request *req,
3193 files_struct *fsp,
3194 off_t startpos,
3195 size_t nread,
3196 ssize_t mincount)
3198 struct smbd_server_connection *sconn = req->sconn;
3199 char *outbuf = NULL;
3200 ssize_t ret=0;
3203 * We can only use sendfile on a non-chained packet
3204 * but we can use on a non-oplocked file. tridge proved this
3205 * on a train in Germany :-). JRA.
3206 * reply_readbraw has already checked the length.
3209 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3210 (fsp->wcp == NULL) &&
3211 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3212 ssize_t sendfile_read = -1;
3213 char header[4];
3214 DATA_BLOB header_blob;
3216 _smb_setlen(header,nread);
3217 header_blob = data_blob_const(header, 4);
3219 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3220 &header_blob, startpos,
3221 nread);
3222 if (sendfile_read == -1) {
3223 /* Returning ENOSYS means no data at all was sent.
3224 * Do this as a normal read. */
3225 if (errno == ENOSYS) {
3226 goto normal_readbraw;
3230 * Special hack for broken Linux with no working sendfile. If we
3231 * return EINTR we sent the header but not the rest of the data.
3232 * Fake this up by doing read/write calls.
3234 if (errno == EINTR) {
3235 /* Ensure we don't do this again. */
3236 set_use_sendfile(SNUM(conn), False);
3237 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3239 if (fake_sendfile(fsp, startpos, nread) == -1) {
3240 DEBUG(0,("send_file_readbraw: "
3241 "fake_sendfile failed for "
3242 "file %s (%s).\n",
3243 fsp_str_dbg(fsp),
3244 strerror(errno)));
3245 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3247 return;
3250 DEBUG(0,("send_file_readbraw: sendfile failed for "
3251 "file %s (%s). Terminating\n",
3252 fsp_str_dbg(fsp), strerror(errno)));
3253 exit_server_cleanly("send_file_readbraw sendfile failed");
3254 } else if (sendfile_read == 0) {
3256 * Some sendfile implementations return 0 to indicate
3257 * that there was a short read, but nothing was
3258 * actually written to the socket. In this case,
3259 * fallback to the normal read path so the header gets
3260 * the correct byte count.
3262 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3263 "bytes falling back to the normal read: "
3264 "%s\n", fsp_str_dbg(fsp)));
3265 goto normal_readbraw;
3268 /* Deal with possible short send. */
3269 if (sendfile_read != 4+nread) {
3270 sendfile_short_send(fsp, sendfile_read, 4, nread);
3272 return;
3275 normal_readbraw:
3277 outbuf = talloc_array(NULL, char, nread+4);
3278 if (!outbuf) {
3279 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3280 (unsigned)(nread+4)));
3281 reply_readbraw_error(sconn);
3282 return;
3285 if (nread > 0) {
3286 ret = read_file(fsp,outbuf+4,startpos,nread);
3287 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3288 if (ret < mincount)
3289 ret = 0;
3290 #else
3291 if (ret < nread)
3292 ret = 0;
3293 #endif
3296 _smb_setlen(outbuf,ret);
3297 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3298 char addr[INET6_ADDRSTRLEN];
3300 * Try and give an error message saying what
3301 * client failed.
3303 DEBUG(0, ("write_data failed for client %s. "
3304 "Error %s\n",
3305 get_peer_addr(fsp->conn->sconn->sock, addr,
3306 sizeof(addr)),
3307 strerror(errno)));
3309 fail_readraw();
3312 TALLOC_FREE(outbuf);
3315 /****************************************************************************
3316 Reply to a readbraw (core+ protocol).
3317 ****************************************************************************/
3319 void reply_readbraw(struct smb_request *req)
3321 connection_struct *conn = req->conn;
3322 struct smbd_server_connection *sconn = req->sconn;
3323 ssize_t maxcount,mincount;
3324 size_t nread = 0;
3325 off_t startpos;
3326 files_struct *fsp;
3327 struct lock_struct lock;
3328 off_t size = 0;
3330 START_PROFILE(SMBreadbraw);
3332 if (srv_is_signing_active(sconn) || req->encrypted) {
3333 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3334 "raw reads/writes are disallowed.");
3337 if (req->wct < 8) {
3338 reply_readbraw_error(sconn);
3339 END_PROFILE(SMBreadbraw);
3340 return;
3343 if (sconn->smb1.echo_handler.trusted_fde) {
3344 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3345 "'async smb echo handler = yes'\n"));
3346 reply_readbraw_error(sconn);
3347 END_PROFILE(SMBreadbraw);
3348 return;
3352 * Special check if an oplock break has been issued
3353 * and the readraw request croses on the wire, we must
3354 * return a zero length response here.
3357 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3360 * We have to do a check_fsp by hand here, as
3361 * we must always return 4 zero bytes on error,
3362 * not a NTSTATUS.
3365 if (!fsp || !conn || conn != fsp->conn ||
3366 req->vuid != fsp->vuid ||
3367 fsp->is_directory || fsp->fh->fd == -1) {
3369 * fsp could be NULL here so use the value from the packet. JRA.
3371 DEBUG(3,("reply_readbraw: fnum %d not valid "
3372 "- cache prime?\n",
3373 (int)SVAL(req->vwv+0, 0)));
3374 reply_readbraw_error(sconn);
3375 END_PROFILE(SMBreadbraw);
3376 return;
3379 /* Do a "by hand" version of CHECK_READ. */
3380 if (!(fsp->can_read ||
3381 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3382 (fsp->access_mask & FILE_EXECUTE)))) {
3383 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3384 (int)SVAL(req->vwv+0, 0)));
3385 reply_readbraw_error(sconn);
3386 END_PROFILE(SMBreadbraw);
3387 return;
3390 flush_write_cache(fsp, READRAW_FLUSH);
3392 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3393 if(req->wct == 10) {
3395 * This is a large offset (64 bit) read.
3398 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3400 if(startpos < 0) {
3401 DEBUG(0,("reply_readbraw: negative 64 bit "
3402 "readraw offset (%.0f) !\n",
3403 (double)startpos ));
3404 reply_readbraw_error(sconn);
3405 END_PROFILE(SMBreadbraw);
3406 return;
3410 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3411 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3413 /* ensure we don't overrun the packet size */
3414 maxcount = MIN(65535,maxcount);
3416 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3417 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3418 &lock);
3420 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3421 reply_readbraw_error(sconn);
3422 END_PROFILE(SMBreadbraw);
3423 return;
3426 if (fsp_stat(fsp) == 0) {
3427 size = fsp->fsp_name->st.st_ex_size;
3430 if (startpos >= size) {
3431 nread = 0;
3432 } else {
3433 nread = MIN(maxcount,(size - startpos));
3436 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3437 if (nread < mincount)
3438 nread = 0;
3439 #endif
3441 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3442 "min=%lu nread=%lu\n",
3443 fsp_fnum_dbg(fsp), (double)startpos,
3444 (unsigned long)maxcount,
3445 (unsigned long)mincount,
3446 (unsigned long)nread ) );
3448 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3450 DEBUG(5,("reply_readbraw finished\n"));
3452 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3454 END_PROFILE(SMBreadbraw);
3455 return;
3458 #undef DBGC_CLASS
3459 #define DBGC_CLASS DBGC_LOCKING
3461 /****************************************************************************
3462 Reply to a lockread (core+ protocol).
3463 ****************************************************************************/
3465 void reply_lockread(struct smb_request *req)
3467 connection_struct *conn = req->conn;
3468 ssize_t nread = -1;
3469 char *data;
3470 off_t startpos;
3471 size_t numtoread;
3472 size_t maxtoread;
3473 NTSTATUS status;
3474 files_struct *fsp;
3475 struct byte_range_lock *br_lck = NULL;
3476 char *p = NULL;
3477 struct smbd_server_connection *sconn = req->sconn;
3479 START_PROFILE(SMBlockread);
3481 if (req->wct < 5) {
3482 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3483 END_PROFILE(SMBlockread);
3484 return;
3487 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3489 if (!check_fsp(conn, req, fsp)) {
3490 END_PROFILE(SMBlockread);
3491 return;
3494 if (!CHECK_READ(fsp,req)) {
3495 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3496 END_PROFILE(SMBlockread);
3497 return;
3500 numtoread = SVAL(req->vwv+1, 0);
3501 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3504 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3505 * protocol request that predates the read/write lock concept.
3506 * Thus instead of asking for a read lock here we need to ask
3507 * for a write lock. JRA.
3508 * Note that the requested lock size is unaffected by max_send.
3511 br_lck = do_lock(req->sconn->msg_ctx,
3512 fsp,
3513 (uint64_t)req->smbpid,
3514 (uint64_t)numtoread,
3515 (uint64_t)startpos,
3516 WRITE_LOCK,
3517 WINDOWS_LOCK,
3518 False, /* Non-blocking lock. */
3519 &status,
3520 NULL,
3521 NULL);
3522 TALLOC_FREE(br_lck);
3524 if (NT_STATUS_V(status)) {
3525 reply_nterror(req, status);
3526 END_PROFILE(SMBlockread);
3527 return;
3531 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3533 maxtoread = sconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3535 if (numtoread > maxtoread) {
3536 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3537 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3538 (unsigned int)numtoread, (unsigned int)maxtoread,
3539 (unsigned int)sconn->smb1.sessions.max_send));
3540 numtoread = maxtoread;
3543 reply_outbuf(req, 5, numtoread + 3);
3545 data = smb_buf(req->outbuf) + 3;
3547 nread = read_file(fsp,data,startpos,numtoread);
3549 if (nread < 0) {
3550 reply_nterror(req, map_nt_error_from_unix(errno));
3551 END_PROFILE(SMBlockread);
3552 return;
3555 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3557 SSVAL(req->outbuf,smb_vwv0,nread);
3558 SSVAL(req->outbuf,smb_vwv5,nread+3);
3559 p = smb_buf(req->outbuf);
3560 SCVAL(p,0,0); /* pad byte. */
3561 SSVAL(p,1,nread);
3563 DEBUG(3,("lockread %s num=%d nread=%d\n",
3564 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3566 END_PROFILE(SMBlockread);
3567 return;
3570 #undef DBGC_CLASS
3571 #define DBGC_CLASS DBGC_ALL
3573 /****************************************************************************
3574 Reply to a read.
3575 ****************************************************************************/
3577 void reply_read(struct smb_request *req)
3579 connection_struct *conn = req->conn;
3580 size_t numtoread;
3581 size_t maxtoread;
3582 ssize_t nread = 0;
3583 char *data;
3584 off_t startpos;
3585 files_struct *fsp;
3586 struct lock_struct lock;
3587 struct smbd_server_connection *sconn = req->sconn;
3589 START_PROFILE(SMBread);
3591 if (req->wct < 3) {
3592 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3593 END_PROFILE(SMBread);
3594 return;
3597 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3599 if (!check_fsp(conn, req, fsp)) {
3600 END_PROFILE(SMBread);
3601 return;
3604 if (!CHECK_READ(fsp,req)) {
3605 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3606 END_PROFILE(SMBread);
3607 return;
3610 numtoread = SVAL(req->vwv+1, 0);
3611 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3614 * The requested read size cannot be greater than max_send. JRA.
3616 maxtoread = sconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3618 if (numtoread > maxtoread) {
3619 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3620 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3621 (unsigned int)numtoread, (unsigned int)maxtoread,
3622 (unsigned int)sconn->smb1.sessions.max_send));
3623 numtoread = maxtoread;
3626 reply_outbuf(req, 5, numtoread+3);
3628 data = smb_buf(req->outbuf) + 3;
3630 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3631 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3632 &lock);
3634 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3635 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3636 END_PROFILE(SMBread);
3637 return;
3640 if (numtoread > 0)
3641 nread = read_file(fsp,data,startpos,numtoread);
3643 if (nread < 0) {
3644 reply_nterror(req, map_nt_error_from_unix(errno));
3645 goto strict_unlock;
3648 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3650 SSVAL(req->outbuf,smb_vwv0,nread);
3651 SSVAL(req->outbuf,smb_vwv5,nread+3);
3652 SCVAL(smb_buf(req->outbuf),0,1);
3653 SSVAL(smb_buf(req->outbuf),1,nread);
3655 DEBUG(3, ("read %s num=%d nread=%d\n",
3656 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3658 strict_unlock:
3659 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3661 END_PROFILE(SMBread);
3662 return;
3665 /****************************************************************************
3666 Setup readX header.
3667 ****************************************************************************/
3669 static int setup_readX_header(struct smb_request *req, char *outbuf,
3670 size_t smb_maxcnt)
3672 int outsize;
3674 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3676 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3678 SCVAL(outbuf,smb_vwv0,0xFF);
3679 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3680 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3681 SSVAL(outbuf,smb_vwv6,
3682 (smb_wct - 4) /* offset from smb header to wct */
3683 + 1 /* the wct field */
3684 + 12 * sizeof(uint16_t) /* vwv */
3685 + 2); /* the buflen field */
3686 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3687 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3688 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3689 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3690 return outsize;
3693 /****************************************************************************
3694 Reply to a read and X - possibly using sendfile.
3695 ****************************************************************************/
3697 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3698 files_struct *fsp, off_t startpos,
3699 size_t smb_maxcnt)
3701 ssize_t nread = -1;
3702 struct lock_struct lock;
3703 int saved_errno = 0;
3705 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3706 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3707 &lock);
3709 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3710 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3711 return;
3715 * We can only use sendfile on a non-chained packet
3716 * but we can use on a non-oplocked file. tridge proved this
3717 * on a train in Germany :-). JRA.
3720 if (!req_is_in_chain(req) &&
3721 !req->encrypted &&
3722 (fsp->base_fsp == NULL) &&
3723 (fsp->wcp == NULL) &&
3724 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3725 uint8 headerbuf[smb_size + 12 * 2];
3726 DATA_BLOB header;
3728 if(fsp_stat(fsp) == -1) {
3729 reply_nterror(req, map_nt_error_from_unix(errno));
3730 goto strict_unlock;
3733 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3734 (startpos > fsp->fsp_name->st.st_ex_size) ||
3735 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3737 * We already know that we would do a short read, so don't
3738 * try the sendfile() path.
3740 goto nosendfile_read;
3744 * Set up the packet header before send. We
3745 * assume here the sendfile will work (get the
3746 * correct amount of data).
3749 header = data_blob_const(headerbuf, sizeof(headerbuf));
3751 construct_reply_common_req(req, (char *)headerbuf);
3752 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3754 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3755 startpos, smb_maxcnt);
3756 if (nread == -1) {
3757 /* Returning ENOSYS means no data at all was sent.
3758 Do this as a normal read. */
3759 if (errno == ENOSYS) {
3760 goto normal_read;
3764 * Special hack for broken Linux with no working sendfile. If we
3765 * return EINTR we sent the header but not the rest of the data.
3766 * Fake this up by doing read/write calls.
3769 if (errno == EINTR) {
3770 /* Ensure we don't do this again. */
3771 set_use_sendfile(SNUM(conn), False);
3772 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3773 nread = fake_sendfile(fsp, startpos,
3774 smb_maxcnt);
3775 if (nread == -1) {
3776 DEBUG(0,("send_file_readX: "
3777 "fake_sendfile failed for "
3778 "file %s (%s).\n",
3779 fsp_str_dbg(fsp),
3780 strerror(errno)));
3781 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3783 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3784 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3785 /* No outbuf here means successful sendfile. */
3786 goto strict_unlock;
3789 DEBUG(0,("send_file_readX: sendfile failed for file "
3790 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3791 strerror(errno)));
3792 exit_server_cleanly("send_file_readX sendfile failed");
3793 } else if (nread == 0) {
3795 * Some sendfile implementations return 0 to indicate
3796 * that there was a short read, but nothing was
3797 * actually written to the socket. In this case,
3798 * fallback to the normal read path so the header gets
3799 * the correct byte count.
3801 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3802 "falling back to the normal read: %s\n",
3803 fsp_str_dbg(fsp)));
3804 goto normal_read;
3807 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3808 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3810 /* Deal with possible short send. */
3811 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3812 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3814 /* No outbuf here means successful sendfile. */
3815 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3816 SMB_PERFCOUNT_END(&req->pcd);
3817 goto strict_unlock;
3820 normal_read:
3822 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3823 uint8 headerbuf[smb_size + 2*12];
3825 construct_reply_common_req(req, (char *)headerbuf);
3826 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3828 /* Send out the header. */
3829 if (write_data(req->sconn->sock, (char *)headerbuf,
3830 sizeof(headerbuf)) != sizeof(headerbuf)) {
3832 char addr[INET6_ADDRSTRLEN];
3834 * Try and give an error message saying what
3835 * client failed.
3837 DEBUG(0, ("write_data failed for client %s. "
3838 "Error %s\n",
3839 get_peer_addr(req->sconn->sock, addr,
3840 sizeof(addr)),
3841 strerror(errno)));
3843 DEBUG(0,("send_file_readX: write_data failed for file "
3844 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3845 strerror(errno)));
3846 exit_server_cleanly("send_file_readX sendfile failed");
3848 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3849 if (nread == -1) {
3850 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3851 "file %s (%s).\n", fsp_str_dbg(fsp),
3852 strerror(errno)));
3853 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3855 goto strict_unlock;
3858 nosendfile_read:
3860 reply_outbuf(req, 12, smb_maxcnt);
3861 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3862 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3864 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3865 saved_errno = errno;
3867 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3869 if (nread < 0) {
3870 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3871 return;
3874 setup_readX_header(req, (char *)req->outbuf, nread);
3876 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3877 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3878 return;
3880 strict_unlock:
3881 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3882 TALLOC_FREE(req->outbuf);
3883 return;
3886 /****************************************************************************
3887 Work out how much space we have for a read return.
3888 ****************************************************************************/
3890 static size_t calc_max_read_pdu(const struct smb_request *req)
3892 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3893 return req->sconn->smb1.sessions.max_send;
3896 if (!lp_large_readwrite()) {
3897 return req->sconn->smb1.sessions.max_send;
3900 if (req_is_in_chain(req)) {
3901 return req->sconn->smb1.sessions.max_send;
3904 if (req->encrypted) {
3906 * Don't take encrypted traffic up to the
3907 * limit. There are padding considerations
3908 * that make that tricky.
3910 return req->sconn->smb1.sessions.max_send;
3913 if (srv_is_signing_active(req->sconn)) {
3914 return 0x1FFFF;
3917 if (!lp_unix_extensions()) {
3918 return 0x1FFFF;
3922 * We can do ultra-large POSIX reads.
3924 return 0xFFFFFF;
3927 /****************************************************************************
3928 Calculate how big a read can be. Copes with all clients. It's always
3929 safe to return a short read - Windows does this.
3930 ****************************************************************************/
3932 static size_t calc_read_size(const struct smb_request *req,
3933 size_t upper_size,
3934 size_t lower_size)
3936 size_t max_pdu = calc_max_read_pdu(req);
3937 size_t total_size = 0;
3938 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3939 size_t max_len = max_pdu - hdr_len;
3942 * Windows explicitly ignores upper size of 0xFFFF.
3943 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3944 * We must do the same as these will never fit even in
3945 * an extended size NetBIOS packet.
3947 if (upper_size == 0xFFFF) {
3948 upper_size = 0;
3951 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3952 upper_size = 0;
3955 total_size = ((upper_size<<16) | lower_size);
3958 * LARGE_READX test shows it's always safe to return
3959 * a short read. Windows does so.
3961 return MIN(total_size, max_len);
3964 /****************************************************************************
3965 Reply to a read and X.
3966 ****************************************************************************/
3968 void reply_read_and_X(struct smb_request *req)
3970 connection_struct *conn = req->conn;
3971 files_struct *fsp;
3972 off_t startpos;
3973 size_t smb_maxcnt;
3974 size_t upper_size;
3975 bool big_readX = False;
3976 #if 0
3977 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3978 #endif
3980 START_PROFILE(SMBreadX);
3982 if ((req->wct != 10) && (req->wct != 12)) {
3983 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3984 return;
3987 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3988 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3989 smb_maxcnt = SVAL(req->vwv+5, 0);
3991 /* If it's an IPC, pass off the pipe handler. */
3992 if (IS_IPC(conn)) {
3993 reply_pipe_read_and_X(req);
3994 END_PROFILE(SMBreadX);
3995 return;
3998 if (!check_fsp(conn, req, fsp)) {
3999 END_PROFILE(SMBreadX);
4000 return;
4003 if (!CHECK_READ(fsp,req)) {
4004 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4005 END_PROFILE(SMBreadX);
4006 return;
4009 upper_size = SVAL(req->vwv+7, 0);
4010 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4011 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4013 * This is a heuristic to avoid keeping large
4014 * outgoing buffers around over long-lived aio
4015 * requests.
4017 big_readX = True;
4020 if (req->wct == 12) {
4022 * This is a large offset (64 bit) read.
4024 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4028 if (!big_readX) {
4029 NTSTATUS status = schedule_aio_read_and_X(conn,
4030 req,
4031 fsp,
4032 startpos,
4033 smb_maxcnt);
4034 if (NT_STATUS_IS_OK(status)) {
4035 /* Read scheduled - we're done. */
4036 goto out;
4038 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4039 /* Real error - report to client. */
4040 END_PROFILE(SMBreadX);
4041 reply_nterror(req, status);
4042 return;
4044 /* NT_STATUS_RETRY - fall back to sync read. */
4047 smbd_lock_socket(req->sconn);
4048 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4049 smbd_unlock_socket(req->sconn);
4051 out:
4052 END_PROFILE(SMBreadX);
4053 return;
4056 /****************************************************************************
4057 Error replies to writebraw must have smb_wct == 1. Fix this up.
4058 ****************************************************************************/
4060 void error_to_writebrawerr(struct smb_request *req)
4062 uint8 *old_outbuf = req->outbuf;
4064 reply_outbuf(req, 1, 0);
4066 memcpy(req->outbuf, old_outbuf, smb_size);
4067 TALLOC_FREE(old_outbuf);
4070 /****************************************************************************
4071 Read 4 bytes of a smb packet and return the smb length of the packet.
4072 Store the result in the buffer. This version of the function will
4073 never return a session keepalive (length of zero).
4074 Timeout is in milliseconds.
4075 ****************************************************************************/
4077 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4078 size_t *len)
4080 uint8_t msgtype = NBSSkeepalive;
4082 while (msgtype == NBSSkeepalive) {
4083 NTSTATUS status;
4085 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4086 len);
4087 if (!NT_STATUS_IS_OK(status)) {
4088 char addr[INET6_ADDRSTRLEN];
4089 /* Try and give an error message
4090 * saying what client failed. */
4091 DEBUG(0, ("read_fd_with_timeout failed for "
4092 "client %s read error = %s.\n",
4093 get_peer_addr(fd,addr,sizeof(addr)),
4094 nt_errstr(status)));
4095 return status;
4098 msgtype = CVAL(inbuf, 0);
4101 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4102 (unsigned long)len));
4104 return NT_STATUS_OK;
4107 /****************************************************************************
4108 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4109 ****************************************************************************/
4111 void reply_writebraw(struct smb_request *req)
4113 connection_struct *conn = req->conn;
4114 char *buf = NULL;
4115 ssize_t nwritten=0;
4116 ssize_t total_written=0;
4117 size_t numtowrite=0;
4118 size_t tcount;
4119 off_t startpos;
4120 const char *data=NULL;
4121 bool write_through;
4122 files_struct *fsp;
4123 struct lock_struct lock;
4124 NTSTATUS status;
4126 START_PROFILE(SMBwritebraw);
4129 * If we ever reply with an error, it must have the SMB command
4130 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4131 * we're finished.
4133 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4135 if (srv_is_signing_active(req->sconn)) {
4136 END_PROFILE(SMBwritebraw);
4137 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4138 "raw reads/writes are disallowed.");
4141 if (req->wct < 12) {
4142 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4143 error_to_writebrawerr(req);
4144 END_PROFILE(SMBwritebraw);
4145 return;
4148 if (req->sconn->smb1.echo_handler.trusted_fde) {
4149 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4150 "'async smb echo handler = yes'\n"));
4151 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4152 error_to_writebrawerr(req);
4153 END_PROFILE(SMBwritebraw);
4154 return;
4157 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4158 if (!check_fsp(conn, req, fsp)) {
4159 error_to_writebrawerr(req);
4160 END_PROFILE(SMBwritebraw);
4161 return;
4164 if (!CHECK_WRITE(fsp)) {
4165 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4166 error_to_writebrawerr(req);
4167 END_PROFILE(SMBwritebraw);
4168 return;
4171 tcount = IVAL(req->vwv+1, 0);
4172 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4173 write_through = BITSETW(req->vwv+7,0);
4175 /* We have to deal with slightly different formats depending
4176 on whether we are using the core+ or lanman1.0 protocol */
4178 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4179 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4180 data = smb_buf_const(req->inbuf);
4181 } else {
4182 numtowrite = SVAL(req->vwv+10, 0);
4183 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4186 /* Ensure we don't write bytes past the end of this packet. */
4187 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4188 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4189 error_to_writebrawerr(req);
4190 END_PROFILE(SMBwritebraw);
4191 return;
4194 if (!fsp->print_file) {
4195 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4196 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4197 &lock);
4199 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4200 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4201 error_to_writebrawerr(req);
4202 END_PROFILE(SMBwritebraw);
4203 return;
4207 if (numtowrite>0) {
4208 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4211 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4212 "wrote=%d sync=%d\n",
4213 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4214 (int)nwritten, (int)write_through));
4216 if (nwritten < (ssize_t)numtowrite) {
4217 reply_nterror(req, NT_STATUS_DISK_FULL);
4218 error_to_writebrawerr(req);
4219 goto strict_unlock;
4222 total_written = nwritten;
4224 /* Allocate a buffer of 64k + length. */
4225 buf = talloc_array(NULL, char, 65540);
4226 if (!buf) {
4227 reply_nterror(req, NT_STATUS_NO_MEMORY);
4228 error_to_writebrawerr(req);
4229 goto strict_unlock;
4232 /* Return a SMBwritebraw message to the redirector to tell
4233 * it to send more bytes */
4235 memcpy(buf, req->inbuf, smb_size);
4236 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4237 SCVAL(buf,smb_com,SMBwritebraw);
4238 SSVALS(buf,smb_vwv0,0xFFFF);
4239 show_msg(buf);
4240 if (!srv_send_smb(req->sconn,
4241 buf,
4242 false, 0, /* no signing */
4243 IS_CONN_ENCRYPTED(conn),
4244 &req->pcd)) {
4245 exit_server_cleanly("reply_writebraw: srv_send_smb "
4246 "failed.");
4249 /* Now read the raw data into the buffer and write it */
4250 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4251 &numtowrite);
4252 if (!NT_STATUS_IS_OK(status)) {
4253 exit_server_cleanly("secondary writebraw failed");
4256 /* Set up outbuf to return the correct size */
4257 reply_outbuf(req, 1, 0);
4259 if (numtowrite != 0) {
4261 if (numtowrite > 0xFFFF) {
4262 DEBUG(0,("reply_writebraw: Oversize secondary write "
4263 "raw requested (%u). Terminating\n",
4264 (unsigned int)numtowrite ));
4265 exit_server_cleanly("secondary writebraw failed");
4268 if (tcount > nwritten+numtowrite) {
4269 DEBUG(3,("reply_writebraw: Client overestimated the "
4270 "write %d %d %d\n",
4271 (int)tcount,(int)nwritten,(int)numtowrite));
4274 status = read_data(req->sconn->sock, buf+4, numtowrite);
4276 if (!NT_STATUS_IS_OK(status)) {
4277 char addr[INET6_ADDRSTRLEN];
4278 /* Try and give an error message
4279 * saying what client failed. */
4280 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4281 "raw read failed (%s) for client %s. "
4282 "Terminating\n", nt_errstr(status),
4283 get_peer_addr(req->sconn->sock, addr,
4284 sizeof(addr))));
4285 exit_server_cleanly("secondary writebraw failed");
4288 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4289 if (nwritten == -1) {
4290 TALLOC_FREE(buf);
4291 reply_nterror(req, map_nt_error_from_unix(errno));
4292 error_to_writebrawerr(req);
4293 goto strict_unlock;
4296 if (nwritten < (ssize_t)numtowrite) {
4297 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4298 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4301 if (nwritten > 0) {
4302 total_written += nwritten;
4306 TALLOC_FREE(buf);
4307 SSVAL(req->outbuf,smb_vwv0,total_written);
4309 status = sync_file(conn, fsp, write_through);
4310 if (!NT_STATUS_IS_OK(status)) {
4311 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4312 fsp_str_dbg(fsp), nt_errstr(status)));
4313 reply_nterror(req, status);
4314 error_to_writebrawerr(req);
4315 goto strict_unlock;
4318 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4319 "wrote=%d\n",
4320 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4321 (int)total_written));
4323 if (!fsp->print_file) {
4324 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4327 /* We won't return a status if write through is not selected - this
4328 * follows what WfWg does */
4329 END_PROFILE(SMBwritebraw);
4331 if (!write_through && total_written==tcount) {
4333 #if RABBIT_PELLET_FIX
4335 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4336 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4337 * JRA.
4339 if (!send_keepalive(req->sconn->sock)) {
4340 exit_server_cleanly("reply_writebraw: send of "
4341 "keepalive failed");
4343 #endif
4344 TALLOC_FREE(req->outbuf);
4346 return;
4348 strict_unlock:
4349 if (!fsp->print_file) {
4350 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4353 END_PROFILE(SMBwritebraw);
4354 return;
4357 #undef DBGC_CLASS
4358 #define DBGC_CLASS DBGC_LOCKING
4360 /****************************************************************************
4361 Reply to a writeunlock (core+).
4362 ****************************************************************************/
4364 void reply_writeunlock(struct smb_request *req)
4366 connection_struct *conn = req->conn;
4367 ssize_t nwritten = -1;
4368 size_t numtowrite;
4369 off_t startpos;
4370 const char *data;
4371 NTSTATUS status = NT_STATUS_OK;
4372 files_struct *fsp;
4373 struct lock_struct lock;
4374 int saved_errno = 0;
4376 START_PROFILE(SMBwriteunlock);
4378 if (req->wct < 5) {
4379 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4380 END_PROFILE(SMBwriteunlock);
4381 return;
4384 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4386 if (!check_fsp(conn, req, fsp)) {
4387 END_PROFILE(SMBwriteunlock);
4388 return;
4391 if (!CHECK_WRITE(fsp)) {
4392 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4393 END_PROFILE(SMBwriteunlock);
4394 return;
4397 numtowrite = SVAL(req->vwv+1, 0);
4398 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4399 data = (const char *)req->buf + 3;
4401 if (!fsp->print_file && numtowrite > 0) {
4402 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4403 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4404 &lock);
4406 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4407 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4408 END_PROFILE(SMBwriteunlock);
4409 return;
4413 /* The special X/Open SMB protocol handling of
4414 zero length writes is *NOT* done for
4415 this call */
4416 if(numtowrite == 0) {
4417 nwritten = 0;
4418 } else {
4419 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4420 saved_errno = errno;
4423 status = sync_file(conn, fsp, False /* write through */);
4424 if (!NT_STATUS_IS_OK(status)) {
4425 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4426 fsp_str_dbg(fsp), nt_errstr(status)));
4427 reply_nterror(req, status);
4428 goto strict_unlock;
4431 if(nwritten < 0) {
4432 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4433 goto strict_unlock;
4436 if((nwritten < numtowrite) && (numtowrite != 0)) {
4437 reply_nterror(req, NT_STATUS_DISK_FULL);
4438 goto strict_unlock;
4441 if (numtowrite && !fsp->print_file) {
4442 status = do_unlock(req->sconn->msg_ctx,
4443 fsp,
4444 (uint64_t)req->smbpid,
4445 (uint64_t)numtowrite,
4446 (uint64_t)startpos,
4447 WINDOWS_LOCK);
4449 if (NT_STATUS_V(status)) {
4450 reply_nterror(req, status);
4451 goto strict_unlock;
4455 reply_outbuf(req, 1, 0);
4457 SSVAL(req->outbuf,smb_vwv0,nwritten);
4459 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4460 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4462 strict_unlock:
4463 if (numtowrite && !fsp->print_file) {
4464 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4467 END_PROFILE(SMBwriteunlock);
4468 return;
4471 #undef DBGC_CLASS
4472 #define DBGC_CLASS DBGC_ALL
4474 /****************************************************************************
4475 Reply to a write.
4476 ****************************************************************************/
4478 void reply_write(struct smb_request *req)
4480 connection_struct *conn = req->conn;
4481 size_t numtowrite;
4482 ssize_t nwritten = -1;
4483 off_t startpos;
4484 const char *data;
4485 files_struct *fsp;
4486 struct lock_struct lock;
4487 NTSTATUS status;
4488 int saved_errno = 0;
4490 START_PROFILE(SMBwrite);
4492 if (req->wct < 5) {
4493 END_PROFILE(SMBwrite);
4494 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4495 return;
4498 /* If it's an IPC, pass off the pipe handler. */
4499 if (IS_IPC(conn)) {
4500 reply_pipe_write(req);
4501 END_PROFILE(SMBwrite);
4502 return;
4505 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4507 if (!check_fsp(conn, req, fsp)) {
4508 END_PROFILE(SMBwrite);
4509 return;
4512 if (!CHECK_WRITE(fsp)) {
4513 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4514 END_PROFILE(SMBwrite);
4515 return;
4518 numtowrite = SVAL(req->vwv+1, 0);
4519 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4520 data = (const char *)req->buf + 3;
4522 if (!fsp->print_file) {
4523 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4524 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4525 &lock);
4527 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4528 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4529 END_PROFILE(SMBwrite);
4530 return;
4535 * X/Open SMB protocol says that if smb_vwv1 is
4536 * zero then the file size should be extended or
4537 * truncated to the size given in smb_vwv[2-3].
4540 if(numtowrite == 0) {
4542 * This is actually an allocate call, and set EOF. JRA.
4544 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4545 if (nwritten < 0) {
4546 reply_nterror(req, NT_STATUS_DISK_FULL);
4547 goto strict_unlock;
4549 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4550 if (nwritten < 0) {
4551 reply_nterror(req, NT_STATUS_DISK_FULL);
4552 goto strict_unlock;
4554 trigger_write_time_update_immediate(fsp);
4555 } else {
4556 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4559 status = sync_file(conn, fsp, False);
4560 if (!NT_STATUS_IS_OK(status)) {
4561 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4562 fsp_str_dbg(fsp), nt_errstr(status)));
4563 reply_nterror(req, status);
4564 goto strict_unlock;
4567 if(nwritten < 0) {
4568 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4569 goto strict_unlock;
4572 if((nwritten == 0) && (numtowrite != 0)) {
4573 reply_nterror(req, NT_STATUS_DISK_FULL);
4574 goto strict_unlock;
4577 reply_outbuf(req, 1, 0);
4579 SSVAL(req->outbuf,smb_vwv0,nwritten);
4581 if (nwritten < (ssize_t)numtowrite) {
4582 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4583 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4586 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4588 strict_unlock:
4589 if (!fsp->print_file) {
4590 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4593 END_PROFILE(SMBwrite);
4594 return;
4597 /****************************************************************************
4598 Ensure a buffer is a valid writeX for recvfile purposes.
4599 ****************************************************************************/
4601 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4602 (2*14) + /* word count (including bcc) */ \
4603 1 /* pad byte */)
4605 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4606 const uint8_t *inbuf)
4608 size_t numtowrite;
4609 connection_struct *conn = NULL;
4610 unsigned int doff = 0;
4611 size_t len = smb_len_large(inbuf);
4612 struct smbXsrv_tcon *tcon;
4613 NTSTATUS status;
4614 NTTIME now = 0;
4616 if (is_encrypted_packet(sconn, inbuf)) {
4617 /* Can't do this on encrypted
4618 * connections. */
4619 return false;
4622 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4623 return false;
4626 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4627 CVAL(inbuf,smb_wct) != 14) {
4628 DEBUG(10,("is_valid_writeX_buffer: chained or "
4629 "invalid word length.\n"));
4630 return false;
4633 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4634 now, &tcon);
4635 if (!NT_STATUS_IS_OK(status)) {
4636 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4637 return false;
4639 conn = tcon->compat;
4641 if (IS_IPC(conn)) {
4642 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4643 return false;
4645 if (IS_PRINT(conn)) {
4646 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4647 return false;
4649 doff = SVAL(inbuf,smb_vwv11);
4651 numtowrite = SVAL(inbuf,smb_vwv10);
4653 if (len > doff && len - doff > 0xFFFF) {
4654 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4657 if (numtowrite == 0) {
4658 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4659 return false;
4662 /* Ensure the sizes match up. */
4663 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4664 /* no pad byte...old smbclient :-( */
4665 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4666 (unsigned int)doff,
4667 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4668 return false;
4671 if (len - doff != numtowrite) {
4672 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4673 "len = %u, doff = %u, numtowrite = %u\n",
4674 (unsigned int)len,
4675 (unsigned int)doff,
4676 (unsigned int)numtowrite ));
4677 return false;
4680 DEBUG(10,("is_valid_writeX_buffer: true "
4681 "len = %u, doff = %u, numtowrite = %u\n",
4682 (unsigned int)len,
4683 (unsigned int)doff,
4684 (unsigned int)numtowrite ));
4686 return true;
4689 /****************************************************************************
4690 Reply to a write and X.
4691 ****************************************************************************/
4693 void reply_write_and_X(struct smb_request *req)
4695 connection_struct *conn = req->conn;
4696 files_struct *fsp;
4697 struct lock_struct lock;
4698 off_t startpos;
4699 size_t numtowrite;
4700 bool write_through;
4701 ssize_t nwritten;
4702 unsigned int smb_doff;
4703 unsigned int smblen;
4704 const char *data;
4705 NTSTATUS status;
4706 int saved_errno = 0;
4708 START_PROFILE(SMBwriteX);
4710 if ((req->wct != 12) && (req->wct != 14)) {
4711 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4712 goto out;
4715 numtowrite = SVAL(req->vwv+10, 0);
4716 smb_doff = SVAL(req->vwv+11, 0);
4717 smblen = smb_len(req->inbuf);
4719 if (req->unread_bytes > 0xFFFF ||
4720 (smblen > smb_doff &&
4721 smblen - smb_doff > 0xFFFF)) {
4722 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4725 if (req->unread_bytes) {
4726 /* Can't do a recvfile write on IPC$ */
4727 if (IS_IPC(conn)) {
4728 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4729 goto out;
4731 if (numtowrite != req->unread_bytes) {
4732 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4733 goto out;
4735 } else {
4736 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4737 smb_doff + numtowrite > smblen) {
4738 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4739 goto out;
4743 /* If it's an IPC, pass off the pipe handler. */
4744 if (IS_IPC(conn)) {
4745 if (req->unread_bytes) {
4746 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4747 goto out;
4749 reply_pipe_write_and_X(req);
4750 goto out;
4753 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4754 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4755 write_through = BITSETW(req->vwv+7,0);
4757 if (!check_fsp(conn, req, fsp)) {
4758 goto out;
4761 if (!CHECK_WRITE(fsp)) {
4762 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4763 goto out;
4766 data = smb_base(req->inbuf) + smb_doff;
4768 if(req->wct == 14) {
4770 * This is a large offset (64 bit) write.
4772 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4776 /* X/Open SMB protocol says that, unlike SMBwrite
4777 if the length is zero then NO truncation is
4778 done, just a write of zero. To truncate a file,
4779 use SMBwrite. */
4781 if(numtowrite == 0) {
4782 nwritten = 0;
4783 } else {
4784 if (req->unread_bytes == 0) {
4785 status = schedule_aio_write_and_X(conn,
4786 req,
4787 fsp,
4788 data,
4789 startpos,
4790 numtowrite);
4792 if (NT_STATUS_IS_OK(status)) {
4793 /* write scheduled - we're done. */
4794 goto out;
4796 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4797 /* Real error - report to client. */
4798 reply_nterror(req, status);
4799 goto out;
4801 /* NT_STATUS_RETRY - fall through to sync write. */
4804 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4805 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4806 &lock);
4808 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4809 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4810 goto out;
4813 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4814 saved_errno = errno;
4816 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4819 if(nwritten < 0) {
4820 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4821 goto out;
4824 if((nwritten == 0) && (numtowrite != 0)) {
4825 reply_nterror(req, NT_STATUS_DISK_FULL);
4826 goto out;
4829 reply_outbuf(req, 6, 0);
4830 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4831 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4832 SSVAL(req->outbuf,smb_vwv2,nwritten);
4833 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4835 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4836 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4838 status = sync_file(conn, fsp, write_through);
4839 if (!NT_STATUS_IS_OK(status)) {
4840 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4841 fsp_str_dbg(fsp), nt_errstr(status)));
4842 reply_nterror(req, status);
4843 goto out;
4846 END_PROFILE(SMBwriteX);
4847 return;
4849 out:
4850 if (req->unread_bytes) {
4851 /* writeX failed. drain socket. */
4852 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4853 req->unread_bytes) {
4854 smb_panic("failed to drain pending bytes");
4856 req->unread_bytes = 0;
4859 END_PROFILE(SMBwriteX);
4860 return;
4863 /****************************************************************************
4864 Reply to a lseek.
4865 ****************************************************************************/
4867 void reply_lseek(struct smb_request *req)
4869 connection_struct *conn = req->conn;
4870 off_t startpos;
4871 off_t res= -1;
4872 int mode,umode;
4873 files_struct *fsp;
4875 START_PROFILE(SMBlseek);
4877 if (req->wct < 4) {
4878 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4879 END_PROFILE(SMBlseek);
4880 return;
4883 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4885 if (!check_fsp(conn, req, fsp)) {
4886 return;
4889 flush_write_cache(fsp, SEEK_FLUSH);
4891 mode = SVAL(req->vwv+1, 0) & 3;
4892 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4893 startpos = (off_t)IVALS(req->vwv+2, 0);
4895 switch (mode) {
4896 case 0:
4897 umode = SEEK_SET;
4898 res = startpos;
4899 break;
4900 case 1:
4901 umode = SEEK_CUR;
4902 res = fsp->fh->pos + startpos;
4903 break;
4904 case 2:
4905 umode = SEEK_END;
4906 break;
4907 default:
4908 umode = SEEK_SET;
4909 res = startpos;
4910 break;
4913 if (umode == SEEK_END) {
4914 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4915 if(errno == EINVAL) {
4916 off_t current_pos = startpos;
4918 if(fsp_stat(fsp) == -1) {
4919 reply_nterror(req,
4920 map_nt_error_from_unix(errno));
4921 END_PROFILE(SMBlseek);
4922 return;
4925 current_pos += fsp->fsp_name->st.st_ex_size;
4926 if(current_pos < 0)
4927 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4931 if(res == -1) {
4932 reply_nterror(req, map_nt_error_from_unix(errno));
4933 END_PROFILE(SMBlseek);
4934 return;
4938 fsp->fh->pos = res;
4940 reply_outbuf(req, 2, 0);
4941 SIVAL(req->outbuf,smb_vwv0,res);
4943 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4944 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4946 END_PROFILE(SMBlseek);
4947 return;
4950 /****************************************************************************
4951 Reply to a flush.
4952 ****************************************************************************/
4954 void reply_flush(struct smb_request *req)
4956 connection_struct *conn = req->conn;
4957 uint16 fnum;
4958 files_struct *fsp;
4960 START_PROFILE(SMBflush);
4962 if (req->wct < 1) {
4963 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4964 return;
4967 fnum = SVAL(req->vwv+0, 0);
4968 fsp = file_fsp(req, fnum);
4970 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4971 return;
4974 if (!fsp) {
4975 file_sync_all(conn);
4976 } else {
4977 NTSTATUS status = sync_file(conn, fsp, True);
4978 if (!NT_STATUS_IS_OK(status)) {
4979 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4980 fsp_str_dbg(fsp), nt_errstr(status)));
4981 reply_nterror(req, status);
4982 END_PROFILE(SMBflush);
4983 return;
4987 reply_outbuf(req, 0, 0);
4989 DEBUG(3,("flush\n"));
4990 END_PROFILE(SMBflush);
4991 return;
4994 /****************************************************************************
4995 Reply to a exit.
4996 conn POINTER CAN BE NULL HERE !
4997 ****************************************************************************/
4999 void reply_exit(struct smb_request *req)
5001 START_PROFILE(SMBexit);
5003 file_close_pid(req->sconn, req->smbpid, req->vuid);
5005 reply_outbuf(req, 0, 0);
5007 DEBUG(3,("exit\n"));
5009 END_PROFILE(SMBexit);
5010 return;
5013 struct reply_close_state {
5014 files_struct *fsp;
5015 struct smb_request *smbreq;
5018 static void do_smb1_close(struct tevent_req *req);
5020 void reply_close(struct smb_request *req)
5022 connection_struct *conn = req->conn;
5023 NTSTATUS status = NT_STATUS_OK;
5024 files_struct *fsp = NULL;
5025 START_PROFILE(SMBclose);
5027 if (req->wct < 3) {
5028 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5029 END_PROFILE(SMBclose);
5030 return;
5033 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5036 * We can only use check_fsp if we know it's not a directory.
5039 if (!check_fsp_open(conn, req, fsp)) {
5040 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5041 END_PROFILE(SMBclose);
5042 return;
5045 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5046 fsp->is_directory ? "directory" : "file",
5047 fsp->fh->fd, fsp_fnum_dbg(fsp),
5048 conn->num_files_open));
5050 if (!fsp->is_directory) {
5051 time_t t;
5054 * Take care of any time sent in the close.
5057 t = srv_make_unix_date3(req->vwv+1);
5058 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5061 if (fsp->num_aio_requests != 0) {
5063 struct reply_close_state *state;
5065 DEBUG(10, ("closing with aio %u requests pending\n",
5066 fsp->num_aio_requests));
5069 * We depend on the aio_extra destructor to take care of this
5070 * close request once fsp->num_aio_request drops to 0.
5073 fsp->deferred_close = tevent_wait_send(
5074 fsp, fsp->conn->sconn->ev_ctx);
5075 if (fsp->deferred_close == NULL) {
5076 status = NT_STATUS_NO_MEMORY;
5077 goto done;
5080 state = talloc(fsp, struct reply_close_state);
5081 if (state == NULL) {
5082 TALLOC_FREE(fsp->deferred_close);
5083 status = NT_STATUS_NO_MEMORY;
5084 goto done;
5086 state->fsp = fsp;
5087 state->smbreq = talloc_move(fsp, &req);
5088 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5089 state);
5090 END_PROFILE(SMBclose);
5091 return;
5095 * close_file() returns the unix errno if an error was detected on
5096 * close - normally this is due to a disk full error. If not then it
5097 * was probably an I/O error.
5100 status = close_file(req, fsp, NORMAL_CLOSE);
5101 done:
5102 if (!NT_STATUS_IS_OK(status)) {
5103 reply_nterror(req, status);
5104 END_PROFILE(SMBclose);
5105 return;
5108 reply_outbuf(req, 0, 0);
5109 END_PROFILE(SMBclose);
5110 return;
5113 static void do_smb1_close(struct tevent_req *req)
5115 struct reply_close_state *state = tevent_req_callback_data(
5116 req, struct reply_close_state);
5117 struct smb_request *smbreq;
5118 NTSTATUS status;
5119 int ret;
5121 ret = tevent_wait_recv(req);
5122 TALLOC_FREE(req);
5123 if (ret != 0) {
5124 DEBUG(10, ("tevent_wait_recv returned %s\n",
5125 strerror(ret)));
5127 * Continue anyway, this should never happen
5132 * fsp->smb2_close_request right now is a talloc grandchild of
5133 * fsp. When we close_file(fsp), it would go with it. No chance to
5134 * reply...
5136 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5138 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5139 if (NT_STATUS_IS_OK(status)) {
5140 reply_outbuf(smbreq, 0, 0);
5141 } else {
5142 reply_nterror(smbreq, status);
5144 if (!srv_send_smb(smbreq->sconn,
5145 (char *)smbreq->outbuf,
5146 true,
5147 smbreq->seqnum+1,
5148 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5149 NULL)) {
5150 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5151 "failed.");
5153 TALLOC_FREE(smbreq);
5156 /****************************************************************************
5157 Reply to a writeclose (Core+ protocol).
5158 ****************************************************************************/
5160 void reply_writeclose(struct smb_request *req)
5162 connection_struct *conn = req->conn;
5163 size_t numtowrite;
5164 ssize_t nwritten = -1;
5165 NTSTATUS close_status = NT_STATUS_OK;
5166 off_t startpos;
5167 const char *data;
5168 struct timespec mtime;
5169 files_struct *fsp;
5170 struct lock_struct lock;
5172 START_PROFILE(SMBwriteclose);
5174 if (req->wct < 6) {
5175 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5176 END_PROFILE(SMBwriteclose);
5177 return;
5180 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5182 if (!check_fsp(conn, req, fsp)) {
5183 END_PROFILE(SMBwriteclose);
5184 return;
5186 if (!CHECK_WRITE(fsp)) {
5187 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5188 END_PROFILE(SMBwriteclose);
5189 return;
5192 numtowrite = SVAL(req->vwv+1, 0);
5193 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5194 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5195 data = (const char *)req->buf + 1;
5197 if (fsp->print_file == NULL) {
5198 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5199 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5200 &lock);
5202 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5203 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5204 END_PROFILE(SMBwriteclose);
5205 return;
5209 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5211 if (fsp->print_file == NULL) {
5212 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5215 set_close_write_time(fsp, mtime);
5218 * More insanity. W2K only closes the file if writelen > 0.
5219 * JRA.
5222 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5223 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5224 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5226 if (numtowrite) {
5227 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5228 "file %s\n", fsp_str_dbg(fsp)));
5229 close_status = close_file(req, fsp, NORMAL_CLOSE);
5230 fsp = NULL;
5233 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5234 reply_nterror(req, NT_STATUS_DISK_FULL);
5235 goto out;
5238 if(!NT_STATUS_IS_OK(close_status)) {
5239 reply_nterror(req, close_status);
5240 goto out;
5243 reply_outbuf(req, 1, 0);
5245 SSVAL(req->outbuf,smb_vwv0,nwritten);
5247 out:
5249 END_PROFILE(SMBwriteclose);
5250 return;
5253 #undef DBGC_CLASS
5254 #define DBGC_CLASS DBGC_LOCKING
5256 /****************************************************************************
5257 Reply to a lock.
5258 ****************************************************************************/
5260 void reply_lock(struct smb_request *req)
5262 connection_struct *conn = req->conn;
5263 uint64_t count,offset;
5264 NTSTATUS status;
5265 files_struct *fsp;
5266 struct byte_range_lock *br_lck = NULL;
5268 START_PROFILE(SMBlock);
5270 if (req->wct < 5) {
5271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5272 END_PROFILE(SMBlock);
5273 return;
5276 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5278 if (!check_fsp(conn, req, fsp)) {
5279 END_PROFILE(SMBlock);
5280 return;
5283 count = (uint64_t)IVAL(req->vwv+1, 0);
5284 offset = (uint64_t)IVAL(req->vwv+3, 0);
5286 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5287 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5289 br_lck = do_lock(req->sconn->msg_ctx,
5290 fsp,
5291 (uint64_t)req->smbpid,
5292 count,
5293 offset,
5294 WRITE_LOCK,
5295 WINDOWS_LOCK,
5296 False, /* Non-blocking lock. */
5297 &status,
5298 NULL,
5299 NULL);
5301 TALLOC_FREE(br_lck);
5303 if (NT_STATUS_V(status)) {
5304 reply_nterror(req, status);
5305 END_PROFILE(SMBlock);
5306 return;
5309 reply_outbuf(req, 0, 0);
5311 END_PROFILE(SMBlock);
5312 return;
5315 /****************************************************************************
5316 Reply to a unlock.
5317 ****************************************************************************/
5319 void reply_unlock(struct smb_request *req)
5321 connection_struct *conn = req->conn;
5322 uint64_t count,offset;
5323 NTSTATUS status;
5324 files_struct *fsp;
5326 START_PROFILE(SMBunlock);
5328 if (req->wct < 5) {
5329 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5330 END_PROFILE(SMBunlock);
5331 return;
5334 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5336 if (!check_fsp(conn, req, fsp)) {
5337 END_PROFILE(SMBunlock);
5338 return;
5341 count = (uint64_t)IVAL(req->vwv+1, 0);
5342 offset = (uint64_t)IVAL(req->vwv+3, 0);
5344 status = do_unlock(req->sconn->msg_ctx,
5345 fsp,
5346 (uint64_t)req->smbpid,
5347 count,
5348 offset,
5349 WINDOWS_LOCK);
5351 if (NT_STATUS_V(status)) {
5352 reply_nterror(req, status);
5353 END_PROFILE(SMBunlock);
5354 return;
5357 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5358 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5360 reply_outbuf(req, 0, 0);
5362 END_PROFILE(SMBunlock);
5363 return;
5366 #undef DBGC_CLASS
5367 #define DBGC_CLASS DBGC_ALL
5369 /****************************************************************************
5370 Reply to a tdis.
5371 conn POINTER CAN BE NULL HERE !
5372 ****************************************************************************/
5374 void reply_tdis(struct smb_request *req)
5376 NTSTATUS status;
5377 connection_struct *conn = req->conn;
5378 struct smbXsrv_tcon *tcon;
5380 START_PROFILE(SMBtdis);
5382 if (!conn) {
5383 DEBUG(4,("Invalid connection in tdis\n"));
5384 reply_force_doserror(req, ERRSRV, ERRinvnid);
5385 END_PROFILE(SMBtdis);
5386 return;
5389 tcon = conn->tcon;
5390 req->conn = NULL;
5393 * TODO: cancel all outstanding requests on the tcon
5395 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5396 if (!NT_STATUS_IS_OK(status)) {
5397 DEBUG(0, ("reply_tdis: "
5398 "smbXsrv_tcon_disconnect() failed: %s\n",
5399 nt_errstr(status)));
5401 * If we hit this case, there is something completely
5402 * wrong, so we better disconnect the transport connection.
5404 END_PROFILE(SMBtdis);
5405 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5406 return;
5409 TALLOC_FREE(tcon);
5411 reply_outbuf(req, 0, 0);
5412 END_PROFILE(SMBtdis);
5413 return;
5416 /****************************************************************************
5417 Reply to a echo.
5418 conn POINTER CAN BE NULL HERE !
5419 ****************************************************************************/
5421 void reply_echo(struct smb_request *req)
5423 connection_struct *conn = req->conn;
5424 struct smb_perfcount_data local_pcd;
5425 struct smb_perfcount_data *cur_pcd;
5426 int smb_reverb;
5427 int seq_num;
5429 START_PROFILE(SMBecho);
5431 smb_init_perfcount_data(&local_pcd);
5433 if (req->wct < 1) {
5434 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5435 END_PROFILE(SMBecho);
5436 return;
5439 smb_reverb = SVAL(req->vwv+0, 0);
5441 reply_outbuf(req, 1, req->buflen);
5443 /* copy any incoming data back out */
5444 if (req->buflen > 0) {
5445 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5448 if (smb_reverb > 100) {
5449 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5450 smb_reverb = 100;
5453 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5455 /* this makes sure we catch the request pcd */
5456 if (seq_num == smb_reverb) {
5457 cur_pcd = &req->pcd;
5458 } else {
5459 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5460 cur_pcd = &local_pcd;
5463 SSVAL(req->outbuf,smb_vwv0,seq_num);
5465 show_msg((char *)req->outbuf);
5466 if (!srv_send_smb(req->sconn,
5467 (char *)req->outbuf,
5468 true, req->seqnum+1,
5469 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5470 cur_pcd))
5471 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5474 DEBUG(3,("echo %d times\n", smb_reverb));
5476 TALLOC_FREE(req->outbuf);
5478 END_PROFILE(SMBecho);
5479 return;
5482 /****************************************************************************
5483 Reply to a printopen.
5484 ****************************************************************************/
5486 void reply_printopen(struct smb_request *req)
5488 connection_struct *conn = req->conn;
5489 files_struct *fsp;
5490 NTSTATUS status;
5492 START_PROFILE(SMBsplopen);
5494 if (req->wct < 2) {
5495 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5496 END_PROFILE(SMBsplopen);
5497 return;
5500 if (!CAN_PRINT(conn)) {
5501 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5502 END_PROFILE(SMBsplopen);
5503 return;
5506 status = file_new(req, conn, &fsp);
5507 if(!NT_STATUS_IS_OK(status)) {
5508 reply_nterror(req, status);
5509 END_PROFILE(SMBsplopen);
5510 return;
5513 /* Open for exclusive use, write only. */
5514 status = print_spool_open(fsp, NULL, req->vuid);
5516 if (!NT_STATUS_IS_OK(status)) {
5517 file_free(req, fsp);
5518 reply_nterror(req, status);
5519 END_PROFILE(SMBsplopen);
5520 return;
5523 reply_outbuf(req, 1, 0);
5524 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5526 DEBUG(3,("openprint fd=%d %s\n",
5527 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5529 END_PROFILE(SMBsplopen);
5530 return;
5533 /****************************************************************************
5534 Reply to a printclose.
5535 ****************************************************************************/
5537 void reply_printclose(struct smb_request *req)
5539 connection_struct *conn = req->conn;
5540 files_struct *fsp;
5541 NTSTATUS status;
5543 START_PROFILE(SMBsplclose);
5545 if (req->wct < 1) {
5546 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5547 END_PROFILE(SMBsplclose);
5548 return;
5551 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5553 if (!check_fsp(conn, req, fsp)) {
5554 END_PROFILE(SMBsplclose);
5555 return;
5558 if (!CAN_PRINT(conn)) {
5559 reply_force_doserror(req, ERRSRV, ERRerror);
5560 END_PROFILE(SMBsplclose);
5561 return;
5564 DEBUG(3,("printclose fd=%d %s\n",
5565 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5567 status = close_file(req, fsp, NORMAL_CLOSE);
5569 if(!NT_STATUS_IS_OK(status)) {
5570 reply_nterror(req, status);
5571 END_PROFILE(SMBsplclose);
5572 return;
5575 reply_outbuf(req, 0, 0);
5577 END_PROFILE(SMBsplclose);
5578 return;
5581 /****************************************************************************
5582 Reply to a printqueue.
5583 ****************************************************************************/
5585 void reply_printqueue(struct smb_request *req)
5587 connection_struct *conn = req->conn;
5588 int max_count;
5589 int start_index;
5591 START_PROFILE(SMBsplretq);
5593 if (req->wct < 2) {
5594 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5595 END_PROFILE(SMBsplretq);
5596 return;
5599 max_count = SVAL(req->vwv+0, 0);
5600 start_index = SVAL(req->vwv+1, 0);
5602 /* we used to allow the client to get the cnum wrong, but that
5603 is really quite gross and only worked when there was only
5604 one printer - I think we should now only accept it if they
5605 get it right (tridge) */
5606 if (!CAN_PRINT(conn)) {
5607 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5608 END_PROFILE(SMBsplretq);
5609 return;
5612 reply_outbuf(req, 2, 3);
5613 SSVAL(req->outbuf,smb_vwv0,0);
5614 SSVAL(req->outbuf,smb_vwv1,0);
5615 SCVAL(smb_buf(req->outbuf),0,1);
5616 SSVAL(smb_buf(req->outbuf),1,0);
5618 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5619 start_index, max_count));
5622 TALLOC_CTX *mem_ctx = talloc_tos();
5623 NTSTATUS status;
5624 WERROR werr;
5625 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5626 struct rpc_pipe_client *cli = NULL;
5627 struct dcerpc_binding_handle *b = NULL;
5628 struct policy_handle handle;
5629 struct spoolss_DevmodeContainer devmode_ctr;
5630 union spoolss_JobInfo *info;
5631 uint32_t count;
5632 uint32_t num_to_get;
5633 uint32_t first;
5634 uint32_t i;
5636 ZERO_STRUCT(handle);
5638 status = rpc_pipe_open_interface(conn,
5639 &ndr_table_spoolss.syntax_id,
5640 conn->session_info,
5641 conn->sconn->remote_address,
5642 conn->sconn->msg_ctx,
5643 &cli);
5644 if (!NT_STATUS_IS_OK(status)) {
5645 DEBUG(0, ("reply_printqueue: "
5646 "could not connect to spoolss: %s\n",
5647 nt_errstr(status)));
5648 reply_nterror(req, status);
5649 goto out;
5651 b = cli->binding_handle;
5653 ZERO_STRUCT(devmode_ctr);
5655 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5656 sharename,
5657 NULL, devmode_ctr,
5658 SEC_FLAG_MAXIMUM_ALLOWED,
5659 &handle,
5660 &werr);
5661 if (!NT_STATUS_IS_OK(status)) {
5662 reply_nterror(req, status);
5663 goto out;
5665 if (!W_ERROR_IS_OK(werr)) {
5666 reply_nterror(req, werror_to_ntstatus(werr));
5667 goto out;
5670 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5671 &handle,
5672 0, /* firstjob */
5673 0xff, /* numjobs */
5674 2, /* level */
5675 0, /* offered */
5676 &count,
5677 &info);
5678 if (!W_ERROR_IS_OK(werr)) {
5679 reply_nterror(req, werror_to_ntstatus(werr));
5680 goto out;
5683 if (max_count > 0) {
5684 first = start_index;
5685 } else {
5686 first = start_index + max_count + 1;
5689 if (first >= count) {
5690 num_to_get = first;
5691 } else {
5692 num_to_get = first + MIN(ABS(max_count), count - first);
5695 for (i = first; i < num_to_get; i++) {
5696 char blob[28];
5697 char *p = blob;
5698 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5699 int qstatus;
5700 uint16_t qrapjobid = pjobid_to_rap(sharename,
5701 info[i].info2.job_id);
5703 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5704 qstatus = 2;
5705 } else {
5706 qstatus = 3;
5709 srv_put_dos_date2(p, 0, qtime);
5710 SCVAL(p, 4, qstatus);
5711 SSVAL(p, 5, qrapjobid);
5712 SIVAL(p, 7, info[i].info2.size);
5713 SCVAL(p, 11, 0);
5714 srvstr_push(blob, req->flags2, p+12,
5715 info[i].info2.notify_name, 16, STR_ASCII);
5717 if (message_push_blob(
5718 &req->outbuf,
5719 data_blob_const(
5720 blob, sizeof(blob))) == -1) {
5721 reply_nterror(req, NT_STATUS_NO_MEMORY);
5722 goto out;
5726 if (count > 0) {
5727 SSVAL(req->outbuf,smb_vwv0,count);
5728 SSVAL(req->outbuf,smb_vwv1,
5729 (max_count>0?first+count:first-1));
5730 SCVAL(smb_buf(req->outbuf),0,1);
5731 SSVAL(smb_buf(req->outbuf),1,28*count);
5735 DEBUG(3, ("%u entries returned in queue\n",
5736 (unsigned)count));
5738 out:
5739 if (b && is_valid_policy_hnd(&handle)) {
5740 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5745 END_PROFILE(SMBsplretq);
5746 return;
5749 /****************************************************************************
5750 Reply to a printwrite.
5751 ****************************************************************************/
5753 void reply_printwrite(struct smb_request *req)
5755 connection_struct *conn = req->conn;
5756 int numtowrite;
5757 const char *data;
5758 files_struct *fsp;
5760 START_PROFILE(SMBsplwr);
5762 if (req->wct < 1) {
5763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5764 END_PROFILE(SMBsplwr);
5765 return;
5768 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5770 if (!check_fsp(conn, req, fsp)) {
5771 END_PROFILE(SMBsplwr);
5772 return;
5775 if (!fsp->print_file) {
5776 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5777 END_PROFILE(SMBsplwr);
5778 return;
5781 if (!CHECK_WRITE(fsp)) {
5782 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5783 END_PROFILE(SMBsplwr);
5784 return;
5787 numtowrite = SVAL(req->buf, 1);
5789 if (req->buflen < numtowrite + 3) {
5790 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5791 END_PROFILE(SMBsplwr);
5792 return;
5795 data = (const char *)req->buf + 3;
5797 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5798 reply_nterror(req, map_nt_error_from_unix(errno));
5799 END_PROFILE(SMBsplwr);
5800 return;
5803 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5805 END_PROFILE(SMBsplwr);
5806 return;
5809 /****************************************************************************
5810 Reply to a mkdir.
5811 ****************************************************************************/
5813 void reply_mkdir(struct smb_request *req)
5815 connection_struct *conn = req->conn;
5816 struct smb_filename *smb_dname = NULL;
5817 char *directory = NULL;
5818 NTSTATUS status;
5819 TALLOC_CTX *ctx = talloc_tos();
5821 START_PROFILE(SMBmkdir);
5823 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5824 STR_TERMINATE, &status);
5825 if (!NT_STATUS_IS_OK(status)) {
5826 reply_nterror(req, status);
5827 goto out;
5830 status = filename_convert(ctx, conn,
5831 req->flags2 & FLAGS2_DFS_PATHNAMES,
5832 directory,
5833 UCF_PREP_CREATEFILE,
5834 NULL,
5835 &smb_dname);
5836 if (!NT_STATUS_IS_OK(status)) {
5837 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5838 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5839 ERRSRV, ERRbadpath);
5840 goto out;
5842 reply_nterror(req, status);
5843 goto out;
5846 status = create_directory(conn, req, smb_dname);
5848 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5850 if (!NT_STATUS_IS_OK(status)) {
5852 if (!use_nt_status()
5853 && NT_STATUS_EQUAL(status,
5854 NT_STATUS_OBJECT_NAME_COLLISION)) {
5856 * Yes, in the DOS error code case we get a
5857 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5858 * samba4 torture test.
5860 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5863 reply_nterror(req, status);
5864 goto out;
5867 reply_outbuf(req, 0, 0);
5869 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5870 out:
5871 TALLOC_FREE(smb_dname);
5872 END_PROFILE(SMBmkdir);
5873 return;
5876 /****************************************************************************
5877 Reply to a rmdir.
5878 ****************************************************************************/
5880 void reply_rmdir(struct smb_request *req)
5882 connection_struct *conn = req->conn;
5883 struct smb_filename *smb_dname = NULL;
5884 char *directory = NULL;
5885 NTSTATUS status;
5886 TALLOC_CTX *ctx = talloc_tos();
5887 files_struct *fsp = NULL;
5888 int info = 0;
5889 struct smbd_server_connection *sconn = req->sconn;
5891 START_PROFILE(SMBrmdir);
5893 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5894 STR_TERMINATE, &status);
5895 if (!NT_STATUS_IS_OK(status)) {
5896 reply_nterror(req, status);
5897 goto out;
5900 status = filename_convert(ctx, conn,
5901 req->flags2 & FLAGS2_DFS_PATHNAMES,
5902 directory,
5904 NULL,
5905 &smb_dname);
5906 if (!NT_STATUS_IS_OK(status)) {
5907 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5908 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5909 ERRSRV, ERRbadpath);
5910 goto out;
5912 reply_nterror(req, status);
5913 goto out;
5916 if (is_ntfs_stream_smb_fname(smb_dname)) {
5917 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5918 goto out;
5921 status = SMB_VFS_CREATE_FILE(
5922 conn, /* conn */
5923 req, /* req */
5924 0, /* root_dir_fid */
5925 smb_dname, /* fname */
5926 DELETE_ACCESS, /* access_mask */
5927 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5928 FILE_SHARE_DELETE),
5929 FILE_OPEN, /* create_disposition*/
5930 FILE_DIRECTORY_FILE, /* create_options */
5931 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5932 0, /* oplock_request */
5933 0, /* allocation_size */
5934 0, /* private_flags */
5935 NULL, /* sd */
5936 NULL, /* ea_list */
5937 &fsp, /* result */
5938 &info); /* pinfo */
5940 if (!NT_STATUS_IS_OK(status)) {
5941 if (open_was_deferred(req->sconn, req->mid)) {
5942 /* We have re-scheduled this call. */
5943 goto out;
5945 reply_nterror(req, status);
5946 goto out;
5949 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5950 if (!NT_STATUS_IS_OK(status)) {
5951 close_file(req, fsp, ERROR_CLOSE);
5952 reply_nterror(req, status);
5953 goto out;
5956 if (!set_delete_on_close(fsp, true,
5957 conn->session_info->security_token,
5958 conn->session_info->unix_token)) {
5959 close_file(req, fsp, ERROR_CLOSE);
5960 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5961 goto out;
5964 status = close_file(req, fsp, NORMAL_CLOSE);
5965 if (!NT_STATUS_IS_OK(status)) {
5966 reply_nterror(req, status);
5967 } else {
5968 reply_outbuf(req, 0, 0);
5971 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5973 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5974 out:
5975 TALLOC_FREE(smb_dname);
5976 END_PROFILE(SMBrmdir);
5977 return;
5980 /*******************************************************************
5981 Resolve wildcards in a filename rename.
5982 ********************************************************************/
5984 static bool resolve_wildcards(TALLOC_CTX *ctx,
5985 const char *name1,
5986 const char *name2,
5987 char **pp_newname)
5989 char *name2_copy = NULL;
5990 char *root1 = NULL;
5991 char *root2 = NULL;
5992 char *ext1 = NULL;
5993 char *ext2 = NULL;
5994 char *p,*p2, *pname1, *pname2;
5996 name2_copy = talloc_strdup(ctx, name2);
5997 if (!name2_copy) {
5998 return False;
6001 pname1 = strrchr_m(name1,'/');
6002 pname2 = strrchr_m(name2_copy,'/');
6004 if (!pname1 || !pname2) {
6005 return False;
6008 /* Truncate the copy of name2 at the last '/' */
6009 *pname2 = '\0';
6011 /* Now go past the '/' */
6012 pname1++;
6013 pname2++;
6015 root1 = talloc_strdup(ctx, pname1);
6016 root2 = talloc_strdup(ctx, pname2);
6018 if (!root1 || !root2) {
6019 return False;
6022 p = strrchr_m(root1,'.');
6023 if (p) {
6024 *p = 0;
6025 ext1 = talloc_strdup(ctx, p+1);
6026 } else {
6027 ext1 = talloc_strdup(ctx, "");
6029 p = strrchr_m(root2,'.');
6030 if (p) {
6031 *p = 0;
6032 ext2 = talloc_strdup(ctx, p+1);
6033 } else {
6034 ext2 = talloc_strdup(ctx, "");
6037 if (!ext1 || !ext2) {
6038 return False;
6041 p = root1;
6042 p2 = root2;
6043 while (*p2) {
6044 if (*p2 == '?') {
6045 /* Hmmm. Should this be mb-aware ? */
6046 *p2 = *p;
6047 p2++;
6048 } else if (*p2 == '*') {
6049 *p2 = '\0';
6050 root2 = talloc_asprintf(ctx, "%s%s",
6051 root2,
6053 if (!root2) {
6054 return False;
6056 break;
6057 } else {
6058 p2++;
6060 if (*p) {
6061 p++;
6065 p = ext1;
6066 p2 = ext2;
6067 while (*p2) {
6068 if (*p2 == '?') {
6069 /* Hmmm. Should this be mb-aware ? */
6070 *p2 = *p;
6071 p2++;
6072 } else if (*p2 == '*') {
6073 *p2 = '\0';
6074 ext2 = talloc_asprintf(ctx, "%s%s",
6075 ext2,
6077 if (!ext2) {
6078 return False;
6080 break;
6081 } else {
6082 p2++;
6084 if (*p) {
6085 p++;
6089 if (*ext2) {
6090 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6091 name2_copy,
6092 root2,
6093 ext2);
6094 } else {
6095 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6096 name2_copy,
6097 root2);
6100 if (!*pp_newname) {
6101 return False;
6104 return True;
6107 /****************************************************************************
6108 Ensure open files have their names updated. Updated to notify other smbd's
6109 asynchronously.
6110 ****************************************************************************/
6112 static void rename_open_files(connection_struct *conn,
6113 struct share_mode_lock *lck,
6114 uint32_t orig_name_hash,
6115 const struct smb_filename *smb_fname_dst)
6117 files_struct *fsp;
6118 bool did_rename = False;
6119 NTSTATUS status;
6120 uint32_t new_name_hash = 0;
6122 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6123 fsp = file_find_di_next(fsp)) {
6124 /* fsp_name is a relative path under the fsp. To change this for other
6125 sharepaths we need to manipulate relative paths. */
6126 /* TODO - create the absolute path and manipulate the newname
6127 relative to the sharepath. */
6128 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6129 continue;
6131 if (fsp->name_hash != orig_name_hash) {
6132 continue;
6134 DEBUG(10, ("rename_open_files: renaming file %s "
6135 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6136 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6137 smb_fname_str_dbg(smb_fname_dst)));
6139 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6140 if (NT_STATUS_IS_OK(status)) {
6141 did_rename = True;
6142 new_name_hash = fsp->name_hash;
6146 if (!did_rename) {
6147 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6148 "for %s\n", file_id_string_tos(&lck->data->id),
6149 smb_fname_str_dbg(smb_fname_dst)));
6152 /* Send messages to all smbd's (not ourself) that the name has changed. */
6153 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6154 orig_name_hash, new_name_hash,
6155 smb_fname_dst);
6159 /****************************************************************************
6160 We need to check if the source path is a parent directory of the destination
6161 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6162 refuse the rename with a sharing violation. Under UNIX the above call can
6163 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6164 probably need to check that the client is a Windows one before disallowing
6165 this as a UNIX client (one with UNIX extensions) can know the source is a
6166 symlink and make this decision intelligently. Found by an excellent bug
6167 report from <AndyLiebman@aol.com>.
6168 ****************************************************************************/
6170 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6171 const struct smb_filename *smb_fname_dst)
6173 const char *psrc = smb_fname_src->base_name;
6174 const char *pdst = smb_fname_dst->base_name;
6175 size_t slen;
6177 if (psrc[0] == '.' && psrc[1] == '/') {
6178 psrc += 2;
6180 if (pdst[0] == '.' && pdst[1] == '/') {
6181 pdst += 2;
6183 if ((slen = strlen(psrc)) > strlen(pdst)) {
6184 return False;
6186 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6190 * Do the notify calls from a rename
6193 static void notify_rename(connection_struct *conn, bool is_dir,
6194 const struct smb_filename *smb_fname_src,
6195 const struct smb_filename *smb_fname_dst)
6197 char *parent_dir_src = NULL;
6198 char *parent_dir_dst = NULL;
6199 uint32 mask;
6201 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6202 : FILE_NOTIFY_CHANGE_FILE_NAME;
6204 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6205 &parent_dir_src, NULL) ||
6206 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6207 &parent_dir_dst, NULL)) {
6208 goto out;
6211 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6212 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6213 smb_fname_src->base_name);
6214 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6215 smb_fname_dst->base_name);
6217 else {
6218 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6219 smb_fname_src->base_name);
6220 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6221 smb_fname_dst->base_name);
6224 /* this is a strange one. w2k3 gives an additional event for
6225 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6226 files, but not directories */
6227 if (!is_dir) {
6228 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6229 FILE_NOTIFY_CHANGE_ATTRIBUTES
6230 |FILE_NOTIFY_CHANGE_CREATION,
6231 smb_fname_dst->base_name);
6233 out:
6234 TALLOC_FREE(parent_dir_src);
6235 TALLOC_FREE(parent_dir_dst);
6238 /****************************************************************************
6239 Returns an error if the parent directory for a filename is open in an
6240 incompatible way.
6241 ****************************************************************************/
6243 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6244 const struct smb_filename *smb_fname_dst_in)
6246 char *parent_dir = NULL;
6247 struct smb_filename smb_fname_parent;
6248 struct file_id id;
6249 files_struct *fsp = NULL;
6250 int ret;
6252 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6253 &parent_dir, NULL)) {
6254 return NT_STATUS_NO_MEMORY;
6256 ZERO_STRUCT(smb_fname_parent);
6257 smb_fname_parent.base_name = parent_dir;
6259 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6260 if (ret == -1) {
6261 return map_nt_error_from_unix(errno);
6265 * We're only checking on this smbd here, mostly good
6266 * enough.. and will pass tests.
6269 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6270 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6271 fsp = file_find_di_next(fsp)) {
6272 if (fsp->access_mask & DELETE_ACCESS) {
6273 return NT_STATUS_SHARING_VIOLATION;
6276 return NT_STATUS_OK;
6279 /****************************************************************************
6280 Rename an open file - given an fsp.
6281 ****************************************************************************/
6283 NTSTATUS rename_internals_fsp(connection_struct *conn,
6284 files_struct *fsp,
6285 const struct smb_filename *smb_fname_dst_in,
6286 uint32 attrs,
6287 bool replace_if_exists)
6289 TALLOC_CTX *ctx = talloc_tos();
6290 struct smb_filename *smb_fname_dst = NULL;
6291 NTSTATUS status = NT_STATUS_OK;
6292 struct share_mode_lock *lck = NULL;
6293 bool dst_exists, old_is_stream, new_is_stream;
6295 status = check_name(conn, smb_fname_dst_in->base_name);
6296 if (!NT_STATUS_IS_OK(status)) {
6297 return status;
6300 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6301 if (!NT_STATUS_IS_OK(status)) {
6302 return status;
6305 /* Make a copy of the dst smb_fname structs */
6307 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6308 if (!NT_STATUS_IS_OK(status)) {
6309 goto out;
6313 * Check for special case with case preserving and not
6314 * case sensitive. If the old last component differs from the original
6315 * last component only by case, then we should allow
6316 * the rename (user is trying to change the case of the
6317 * filename).
6319 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6320 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6321 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6322 char *last_slash;
6323 char *fname_dst_lcomp_base_mod = NULL;
6324 struct smb_filename *smb_fname_orig_lcomp = NULL;
6327 * Get the last component of the destination name.
6329 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6330 if (last_slash) {
6331 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6332 } else {
6333 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6335 if (!fname_dst_lcomp_base_mod) {
6336 status = NT_STATUS_NO_MEMORY;
6337 goto out;
6341 * Create an smb_filename struct using the original last
6342 * component of the destination.
6344 status = create_synthetic_smb_fname_split(ctx,
6345 smb_fname_dst->original_lcomp, NULL,
6346 &smb_fname_orig_lcomp);
6347 if (!NT_STATUS_IS_OK(status)) {
6348 TALLOC_FREE(fname_dst_lcomp_base_mod);
6349 goto out;
6352 /* If the base names only differ by case, use original. */
6353 if(!strcsequal(fname_dst_lcomp_base_mod,
6354 smb_fname_orig_lcomp->base_name)) {
6355 char *tmp;
6357 * Replace the modified last component with the
6358 * original.
6360 if (last_slash) {
6361 *last_slash = '\0'; /* Truncate at the '/' */
6362 tmp = talloc_asprintf(smb_fname_dst,
6363 "%s/%s",
6364 smb_fname_dst->base_name,
6365 smb_fname_orig_lcomp->base_name);
6366 } else {
6367 tmp = talloc_asprintf(smb_fname_dst,
6368 "%s",
6369 smb_fname_orig_lcomp->base_name);
6371 if (tmp == NULL) {
6372 status = NT_STATUS_NO_MEMORY;
6373 TALLOC_FREE(fname_dst_lcomp_base_mod);
6374 TALLOC_FREE(smb_fname_orig_lcomp);
6375 goto out;
6377 TALLOC_FREE(smb_fname_dst->base_name);
6378 smb_fname_dst->base_name = tmp;
6381 /* If the stream_names only differ by case, use original. */
6382 if(!strcsequal(smb_fname_dst->stream_name,
6383 smb_fname_orig_lcomp->stream_name)) {
6384 char *tmp = NULL;
6385 /* Use the original stream. */
6386 tmp = talloc_strdup(smb_fname_dst,
6387 smb_fname_orig_lcomp->stream_name);
6388 if (tmp == NULL) {
6389 status = NT_STATUS_NO_MEMORY;
6390 TALLOC_FREE(fname_dst_lcomp_base_mod);
6391 TALLOC_FREE(smb_fname_orig_lcomp);
6392 goto out;
6394 TALLOC_FREE(smb_fname_dst->stream_name);
6395 smb_fname_dst->stream_name = tmp;
6397 TALLOC_FREE(fname_dst_lcomp_base_mod);
6398 TALLOC_FREE(smb_fname_orig_lcomp);
6402 * If the src and dest names are identical - including case,
6403 * don't do the rename, just return success.
6406 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6407 strcsequal(fsp->fsp_name->stream_name,
6408 smb_fname_dst->stream_name)) {
6409 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6410 "- returning success\n",
6411 smb_fname_str_dbg(smb_fname_dst)));
6412 status = NT_STATUS_OK;
6413 goto out;
6416 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6417 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6419 /* Return the correct error code if both names aren't streams. */
6420 if (!old_is_stream && new_is_stream) {
6421 status = NT_STATUS_OBJECT_NAME_INVALID;
6422 goto out;
6425 if (old_is_stream && !new_is_stream) {
6426 status = NT_STATUS_INVALID_PARAMETER;
6427 goto out;
6430 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6432 if(!replace_if_exists && dst_exists) {
6433 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6434 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6435 smb_fname_str_dbg(smb_fname_dst)));
6436 status = NT_STATUS_OBJECT_NAME_COLLISION;
6437 goto out;
6440 if (dst_exists) {
6441 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6442 &smb_fname_dst->st);
6443 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6444 fileid);
6445 /* The file can be open when renaming a stream */
6446 if (dst_fsp && !new_is_stream) {
6447 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6448 status = NT_STATUS_ACCESS_DENIED;
6449 goto out;
6453 /* Ensure we have a valid stat struct for the source. */
6454 status = vfs_stat_fsp(fsp);
6455 if (!NT_STATUS_IS_OK(status)) {
6456 goto out;
6459 status = can_rename(conn, fsp, attrs);
6461 if (!NT_STATUS_IS_OK(status)) {
6462 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6463 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6464 smb_fname_str_dbg(smb_fname_dst)));
6465 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6466 status = NT_STATUS_ACCESS_DENIED;
6467 goto out;
6470 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6471 status = NT_STATUS_ACCESS_DENIED;
6474 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6477 * We have the file open ourselves, so not being able to get the
6478 * corresponding share mode lock is a fatal error.
6481 SMB_ASSERT(lck != NULL);
6483 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6484 uint32 create_options = fsp->fh->private_options;
6486 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6487 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6488 smb_fname_str_dbg(smb_fname_dst)));
6490 if (!fsp->is_directory &&
6491 !lp_posix_pathnames() &&
6492 (lp_map_archive(SNUM(conn)) ||
6493 lp_store_dos_attributes(SNUM(conn)))) {
6494 /* We must set the archive bit on the newly
6495 renamed file. */
6496 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6497 uint32_t old_dosmode = dos_mode(conn,
6498 smb_fname_dst);
6499 file_set_dosmode(conn,
6500 smb_fname_dst,
6501 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6502 NULL,
6503 true);
6507 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6508 smb_fname_dst);
6510 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6513 * A rename acts as a new file create w.r.t. allowing an initial delete
6514 * on close, probably because in Windows there is a new handle to the
6515 * new file. If initial delete on close was requested but not
6516 * originally set, we need to set it here. This is probably not 100% correct,
6517 * but will work for the CIFSFS client which in non-posix mode
6518 * depends on these semantics. JRA.
6521 if (create_options & FILE_DELETE_ON_CLOSE) {
6522 status = can_set_delete_on_close(fsp, 0);
6524 if (NT_STATUS_IS_OK(status)) {
6525 /* Note that here we set the *inital* delete on close flag,
6526 * not the regular one. The magic gets handled in close. */
6527 fsp->initial_delete_on_close = True;
6530 TALLOC_FREE(lck);
6531 status = NT_STATUS_OK;
6532 goto out;
6535 TALLOC_FREE(lck);
6537 if (errno == ENOTDIR || errno == EISDIR) {
6538 status = NT_STATUS_OBJECT_NAME_COLLISION;
6539 } else {
6540 status = map_nt_error_from_unix(errno);
6543 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6544 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6545 smb_fname_str_dbg(smb_fname_dst)));
6547 out:
6548 TALLOC_FREE(smb_fname_dst);
6550 return status;
6553 /****************************************************************************
6554 The guts of the rename command, split out so it may be called by the NT SMB
6555 code.
6556 ****************************************************************************/
6558 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6559 connection_struct *conn,
6560 struct smb_request *req,
6561 struct smb_filename *smb_fname_src,
6562 struct smb_filename *smb_fname_dst,
6563 uint32 attrs,
6564 bool replace_if_exists,
6565 bool src_has_wild,
6566 bool dest_has_wild,
6567 uint32_t access_mask)
6569 char *fname_src_dir = NULL;
6570 char *fname_src_mask = NULL;
6571 int count=0;
6572 NTSTATUS status = NT_STATUS_OK;
6573 struct smb_Dir *dir_hnd = NULL;
6574 const char *dname = NULL;
6575 char *talloced = NULL;
6576 long offset = 0;
6577 int create_options = 0;
6578 bool posix_pathnames = lp_posix_pathnames();
6581 * Split the old name into directory and last component
6582 * strings. Note that unix_convert may have stripped off a
6583 * leading ./ from both name and newname if the rename is
6584 * at the root of the share. We need to make sure either both
6585 * name and newname contain a / character or neither of them do
6586 * as this is checked in resolve_wildcards().
6589 /* Split up the directory from the filename/mask. */
6590 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6591 &fname_src_dir, &fname_src_mask);
6592 if (!NT_STATUS_IS_OK(status)) {
6593 status = NT_STATUS_NO_MEMORY;
6594 goto out;
6598 * We should only check the mangled cache
6599 * here if unix_convert failed. This means
6600 * that the path in 'mask' doesn't exist
6601 * on the file system and so we need to look
6602 * for a possible mangle. This patch from
6603 * Tine Smukavec <valentin.smukavec@hermes.si>.
6606 if (!VALID_STAT(smb_fname_src->st) &&
6607 mangle_is_mangled(fname_src_mask, conn->params)) {
6608 char *new_mask = NULL;
6609 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6610 conn->params);
6611 if (new_mask) {
6612 TALLOC_FREE(fname_src_mask);
6613 fname_src_mask = new_mask;
6617 if (!src_has_wild) {
6618 files_struct *fsp;
6621 * Only one file needs to be renamed. Append the mask back
6622 * onto the directory.
6624 TALLOC_FREE(smb_fname_src->base_name);
6625 if (ISDOT(fname_src_dir)) {
6626 /* Ensure we use canonical names on open. */
6627 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6628 "%s",
6629 fname_src_mask);
6630 } else {
6631 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6632 "%s/%s",
6633 fname_src_dir,
6634 fname_src_mask);
6636 if (!smb_fname_src->base_name) {
6637 status = NT_STATUS_NO_MEMORY;
6638 goto out;
6641 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6642 "case_preserve = %d, short case preserve = %d, "
6643 "directory = %s, newname = %s, "
6644 "last_component_dest = %s\n",
6645 conn->case_sensitive, conn->case_preserve,
6646 conn->short_case_preserve,
6647 smb_fname_str_dbg(smb_fname_src),
6648 smb_fname_str_dbg(smb_fname_dst),
6649 smb_fname_dst->original_lcomp));
6651 /* The dest name still may have wildcards. */
6652 if (dest_has_wild) {
6653 char *fname_dst_mod = NULL;
6654 if (!resolve_wildcards(smb_fname_dst,
6655 smb_fname_src->base_name,
6656 smb_fname_dst->base_name,
6657 &fname_dst_mod)) {
6658 DEBUG(6, ("rename_internals: resolve_wildcards "
6659 "%s %s failed\n",
6660 smb_fname_src->base_name,
6661 smb_fname_dst->base_name));
6662 status = NT_STATUS_NO_MEMORY;
6663 goto out;
6665 TALLOC_FREE(smb_fname_dst->base_name);
6666 smb_fname_dst->base_name = fname_dst_mod;
6669 ZERO_STRUCT(smb_fname_src->st);
6670 if (posix_pathnames) {
6671 SMB_VFS_LSTAT(conn, smb_fname_src);
6672 } else {
6673 SMB_VFS_STAT(conn, smb_fname_src);
6676 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6677 create_options |= FILE_DIRECTORY_FILE;
6680 status = SMB_VFS_CREATE_FILE(
6681 conn, /* conn */
6682 req, /* req */
6683 0, /* root_dir_fid */
6684 smb_fname_src, /* fname */
6685 access_mask, /* access_mask */
6686 (FILE_SHARE_READ | /* share_access */
6687 FILE_SHARE_WRITE),
6688 FILE_OPEN, /* create_disposition*/
6689 create_options, /* create_options */
6690 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6691 0, /* oplock_request */
6692 0, /* allocation_size */
6693 0, /* private_flags */
6694 NULL, /* sd */
6695 NULL, /* ea_list */
6696 &fsp, /* result */
6697 NULL); /* pinfo */
6699 if (!NT_STATUS_IS_OK(status)) {
6700 DEBUG(3, ("Could not open rename source %s: %s\n",
6701 smb_fname_str_dbg(smb_fname_src),
6702 nt_errstr(status)));
6703 goto out;
6706 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6707 attrs, replace_if_exists);
6709 close_file(req, fsp, NORMAL_CLOSE);
6711 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6712 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6713 smb_fname_str_dbg(smb_fname_dst)));
6715 goto out;
6719 * Wildcards - process each file that matches.
6721 if (strequal(fname_src_mask, "????????.???")) {
6722 TALLOC_FREE(fname_src_mask);
6723 fname_src_mask = talloc_strdup(ctx, "*");
6724 if (!fname_src_mask) {
6725 status = NT_STATUS_NO_MEMORY;
6726 goto out;
6730 status = check_name(conn, fname_src_dir);
6731 if (!NT_STATUS_IS_OK(status)) {
6732 goto out;
6735 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6736 attrs);
6737 if (dir_hnd == NULL) {
6738 status = map_nt_error_from_unix(errno);
6739 goto out;
6742 status = NT_STATUS_NO_SUCH_FILE;
6744 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6745 * - gentest fix. JRA
6748 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6749 &talloced))) {
6750 files_struct *fsp = NULL;
6751 char *destname = NULL;
6752 bool sysdir_entry = False;
6754 /* Quick check for "." and ".." */
6755 if (ISDOT(dname) || ISDOTDOT(dname)) {
6756 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6757 sysdir_entry = True;
6758 } else {
6759 TALLOC_FREE(talloced);
6760 continue;
6764 if (!is_visible_file(conn, fname_src_dir, dname,
6765 &smb_fname_src->st, false)) {
6766 TALLOC_FREE(talloced);
6767 continue;
6770 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6771 TALLOC_FREE(talloced);
6772 continue;
6775 if (sysdir_entry) {
6776 status = NT_STATUS_OBJECT_NAME_INVALID;
6777 break;
6780 TALLOC_FREE(smb_fname_src->base_name);
6781 if (ISDOT(fname_src_dir)) {
6782 /* Ensure we use canonical names on open. */
6783 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6784 "%s",
6785 dname);
6786 } else {
6787 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6788 "%s/%s",
6789 fname_src_dir,
6790 dname);
6792 if (!smb_fname_src->base_name) {
6793 status = NT_STATUS_NO_MEMORY;
6794 goto out;
6797 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6798 smb_fname_dst->base_name,
6799 &destname)) {
6800 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6801 smb_fname_src->base_name, destname));
6802 TALLOC_FREE(talloced);
6803 continue;
6805 if (!destname) {
6806 status = NT_STATUS_NO_MEMORY;
6807 goto out;
6810 TALLOC_FREE(smb_fname_dst->base_name);
6811 smb_fname_dst->base_name = destname;
6813 ZERO_STRUCT(smb_fname_src->st);
6814 if (posix_pathnames) {
6815 SMB_VFS_LSTAT(conn, smb_fname_src);
6816 } else {
6817 SMB_VFS_STAT(conn, smb_fname_src);
6820 create_options = 0;
6822 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6823 create_options |= FILE_DIRECTORY_FILE;
6826 status = SMB_VFS_CREATE_FILE(
6827 conn, /* conn */
6828 req, /* req */
6829 0, /* root_dir_fid */
6830 smb_fname_src, /* fname */
6831 access_mask, /* access_mask */
6832 (FILE_SHARE_READ | /* share_access */
6833 FILE_SHARE_WRITE),
6834 FILE_OPEN, /* create_disposition*/
6835 create_options, /* create_options */
6836 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6837 0, /* oplock_request */
6838 0, /* allocation_size */
6839 0, /* private_flags */
6840 NULL, /* sd */
6841 NULL, /* ea_list */
6842 &fsp, /* result */
6843 NULL); /* pinfo */
6845 if (!NT_STATUS_IS_OK(status)) {
6846 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6847 "returned %s rename %s -> %s\n",
6848 nt_errstr(status),
6849 smb_fname_str_dbg(smb_fname_src),
6850 smb_fname_str_dbg(smb_fname_dst)));
6851 break;
6854 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6855 dname);
6856 if (!smb_fname_dst->original_lcomp) {
6857 status = NT_STATUS_NO_MEMORY;
6858 goto out;
6861 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6862 attrs, replace_if_exists);
6864 close_file(req, fsp, NORMAL_CLOSE);
6866 if (!NT_STATUS_IS_OK(status)) {
6867 DEBUG(3, ("rename_internals_fsp returned %s for "
6868 "rename %s -> %s\n", nt_errstr(status),
6869 smb_fname_str_dbg(smb_fname_src),
6870 smb_fname_str_dbg(smb_fname_dst)));
6871 break;
6874 count++;
6876 DEBUG(3,("rename_internals: doing rename on %s -> "
6877 "%s\n", smb_fname_str_dbg(smb_fname_src),
6878 smb_fname_str_dbg(smb_fname_src)));
6879 TALLOC_FREE(talloced);
6881 TALLOC_FREE(dir_hnd);
6883 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6884 status = map_nt_error_from_unix(errno);
6887 out:
6888 TALLOC_FREE(talloced);
6889 TALLOC_FREE(fname_src_dir);
6890 TALLOC_FREE(fname_src_mask);
6891 return status;
6894 /****************************************************************************
6895 Reply to a mv.
6896 ****************************************************************************/
6898 void reply_mv(struct smb_request *req)
6900 connection_struct *conn = req->conn;
6901 char *name = NULL;
6902 char *newname = NULL;
6903 const char *p;
6904 uint32 attrs;
6905 NTSTATUS status;
6906 bool src_has_wcard = False;
6907 bool dest_has_wcard = False;
6908 TALLOC_CTX *ctx = talloc_tos();
6909 struct smb_filename *smb_fname_src = NULL;
6910 struct smb_filename *smb_fname_dst = NULL;
6911 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6912 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6913 bool stream_rename = false;
6915 START_PROFILE(SMBmv);
6917 if (req->wct < 1) {
6918 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6919 goto out;
6922 attrs = SVAL(req->vwv+0, 0);
6924 p = (const char *)req->buf + 1;
6925 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6926 &status, &src_has_wcard);
6927 if (!NT_STATUS_IS_OK(status)) {
6928 reply_nterror(req, status);
6929 goto out;
6931 p++;
6932 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6933 &status, &dest_has_wcard);
6934 if (!NT_STATUS_IS_OK(status)) {
6935 reply_nterror(req, status);
6936 goto out;
6939 if (!lp_posix_pathnames()) {
6940 /* The newname must begin with a ':' if the
6941 name contains a ':'. */
6942 if (strchr_m(name, ':')) {
6943 if (newname[0] != ':') {
6944 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6945 goto out;
6947 stream_rename = true;
6951 status = filename_convert(ctx,
6952 conn,
6953 req->flags2 & FLAGS2_DFS_PATHNAMES,
6954 name,
6955 src_ucf_flags,
6956 &src_has_wcard,
6957 &smb_fname_src);
6959 if (!NT_STATUS_IS_OK(status)) {
6960 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6961 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6962 ERRSRV, ERRbadpath);
6963 goto out;
6965 reply_nterror(req, status);
6966 goto out;
6969 status = filename_convert(ctx,
6970 conn,
6971 req->flags2 & FLAGS2_DFS_PATHNAMES,
6972 newname,
6973 dst_ucf_flags,
6974 &dest_has_wcard,
6975 &smb_fname_dst);
6977 if (!NT_STATUS_IS_OK(status)) {
6978 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6979 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6980 ERRSRV, ERRbadpath);
6981 goto out;
6983 reply_nterror(req, status);
6984 goto out;
6987 if (stream_rename) {
6988 /* smb_fname_dst->base_name must be the same as
6989 smb_fname_src->base_name. */
6990 TALLOC_FREE(smb_fname_dst->base_name);
6991 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6992 smb_fname_src->base_name);
6993 if (!smb_fname_dst->base_name) {
6994 reply_nterror(req, NT_STATUS_NO_MEMORY);
6995 goto out;
6999 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7000 smb_fname_str_dbg(smb_fname_dst)));
7002 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7003 attrs, False, src_has_wcard, dest_has_wcard,
7004 DELETE_ACCESS);
7005 if (!NT_STATUS_IS_OK(status)) {
7006 if (open_was_deferred(req->sconn, req->mid)) {
7007 /* We have re-scheduled this call. */
7008 goto out;
7010 reply_nterror(req, status);
7011 goto out;
7014 reply_outbuf(req, 0, 0);
7015 out:
7016 TALLOC_FREE(smb_fname_src);
7017 TALLOC_FREE(smb_fname_dst);
7018 END_PROFILE(SMBmv);
7019 return;
7022 /*******************************************************************
7023 Copy a file as part of a reply_copy.
7024 ******************************************************************/
7027 * TODO: check error codes on all callers
7030 NTSTATUS copy_file(TALLOC_CTX *ctx,
7031 connection_struct *conn,
7032 struct smb_filename *smb_fname_src,
7033 struct smb_filename *smb_fname_dst,
7034 int ofun,
7035 int count,
7036 bool target_is_directory)
7038 struct smb_filename *smb_fname_dst_tmp = NULL;
7039 off_t ret=-1;
7040 files_struct *fsp1,*fsp2;
7041 uint32 dosattrs;
7042 uint32 new_create_disposition;
7043 NTSTATUS status;
7046 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
7047 if (!NT_STATUS_IS_OK(status)) {
7048 return status;
7052 * If the target is a directory, extract the last component from the
7053 * src filename and append it to the dst filename
7055 if (target_is_directory) {
7056 const char *p;
7058 /* dest/target can't be a stream if it's a directory. */
7059 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7061 p = strrchr_m(smb_fname_src->base_name,'/');
7062 if (p) {
7063 p++;
7064 } else {
7065 p = smb_fname_src->base_name;
7067 smb_fname_dst_tmp->base_name =
7068 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7070 if (!smb_fname_dst_tmp->base_name) {
7071 status = NT_STATUS_NO_MEMORY;
7072 goto out;
7076 status = vfs_file_exist(conn, smb_fname_src);
7077 if (!NT_STATUS_IS_OK(status)) {
7078 goto out;
7081 if (!target_is_directory && count) {
7082 new_create_disposition = FILE_OPEN;
7083 } else {
7084 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7085 0, ofun,
7086 NULL, NULL,
7087 &new_create_disposition,
7088 NULL,
7089 NULL)) {
7090 status = NT_STATUS_INVALID_PARAMETER;
7091 goto out;
7095 /* Open the src file for reading. */
7096 status = SMB_VFS_CREATE_FILE(
7097 conn, /* conn */
7098 NULL, /* req */
7099 0, /* root_dir_fid */
7100 smb_fname_src, /* fname */
7101 FILE_GENERIC_READ, /* access_mask */
7102 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7103 FILE_OPEN, /* create_disposition*/
7104 0, /* create_options */
7105 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7106 INTERNAL_OPEN_ONLY, /* oplock_request */
7107 0, /* allocation_size */
7108 0, /* private_flags */
7109 NULL, /* sd */
7110 NULL, /* ea_list */
7111 &fsp1, /* result */
7112 NULL); /* psbuf */
7114 if (!NT_STATUS_IS_OK(status)) {
7115 goto out;
7118 dosattrs = dos_mode(conn, smb_fname_src);
7120 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7121 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7124 /* Open the dst file for writing. */
7125 status = SMB_VFS_CREATE_FILE(
7126 conn, /* conn */
7127 NULL, /* req */
7128 0, /* root_dir_fid */
7129 smb_fname_dst, /* fname */
7130 FILE_GENERIC_WRITE, /* access_mask */
7131 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7132 new_create_disposition, /* create_disposition*/
7133 0, /* create_options */
7134 dosattrs, /* file_attributes */
7135 INTERNAL_OPEN_ONLY, /* oplock_request */
7136 0, /* allocation_size */
7137 0, /* private_flags */
7138 NULL, /* sd */
7139 NULL, /* ea_list */
7140 &fsp2, /* result */
7141 NULL); /* psbuf */
7143 if (!NT_STATUS_IS_OK(status)) {
7144 close_file(NULL, fsp1, ERROR_CLOSE);
7145 goto out;
7148 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7149 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7150 if (ret == -1) {
7151 DEBUG(0, ("error - vfs lseek returned error %s\n",
7152 strerror(errno)));
7153 status = map_nt_error_from_unix(errno);
7154 close_file(NULL, fsp1, ERROR_CLOSE);
7155 close_file(NULL, fsp2, ERROR_CLOSE);
7156 goto out;
7160 /* Do the actual copy. */
7161 if (smb_fname_src->st.st_ex_size) {
7162 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7163 } else {
7164 ret = 0;
7167 close_file(NULL, fsp1, NORMAL_CLOSE);
7169 /* Ensure the modtime is set correctly on the destination file. */
7170 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7173 * As we are opening fsp1 read-only we only expect
7174 * an error on close on fsp2 if we are out of space.
7175 * Thus we don't look at the error return from the
7176 * close of fsp1.
7178 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7180 if (!NT_STATUS_IS_OK(status)) {
7181 goto out;
7184 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7185 status = NT_STATUS_DISK_FULL;
7186 goto out;
7189 status = NT_STATUS_OK;
7191 out:
7192 TALLOC_FREE(smb_fname_dst_tmp);
7193 return status;
7196 /****************************************************************************
7197 Reply to a file copy.
7198 ****************************************************************************/
7200 void reply_copy(struct smb_request *req)
7202 connection_struct *conn = req->conn;
7203 struct smb_filename *smb_fname_src = NULL;
7204 struct smb_filename *smb_fname_dst = NULL;
7205 char *fname_src = NULL;
7206 char *fname_dst = NULL;
7207 char *fname_src_mask = NULL;
7208 char *fname_src_dir = NULL;
7209 const char *p;
7210 int count=0;
7211 int error = ERRnoaccess;
7212 int tid2;
7213 int ofun;
7214 int flags;
7215 bool target_is_directory=False;
7216 bool source_has_wild = False;
7217 bool dest_has_wild = False;
7218 NTSTATUS status;
7219 TALLOC_CTX *ctx = talloc_tos();
7221 START_PROFILE(SMBcopy);
7223 if (req->wct < 3) {
7224 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7225 goto out;
7228 tid2 = SVAL(req->vwv+0, 0);
7229 ofun = SVAL(req->vwv+1, 0);
7230 flags = SVAL(req->vwv+2, 0);
7232 p = (const char *)req->buf;
7233 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7234 &status, &source_has_wild);
7235 if (!NT_STATUS_IS_OK(status)) {
7236 reply_nterror(req, status);
7237 goto out;
7239 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7240 &status, &dest_has_wild);
7241 if (!NT_STATUS_IS_OK(status)) {
7242 reply_nterror(req, status);
7243 goto out;
7246 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7248 if (tid2 != conn->cnum) {
7249 /* can't currently handle inter share copies XXXX */
7250 DEBUG(3,("Rejecting inter-share copy\n"));
7251 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7252 goto out;
7255 status = filename_convert(ctx, conn,
7256 req->flags2 & FLAGS2_DFS_PATHNAMES,
7257 fname_src,
7258 UCF_COND_ALLOW_WCARD_LCOMP,
7259 &source_has_wild,
7260 &smb_fname_src);
7261 if (!NT_STATUS_IS_OK(status)) {
7262 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7263 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7264 ERRSRV, ERRbadpath);
7265 goto out;
7267 reply_nterror(req, status);
7268 goto out;
7271 status = filename_convert(ctx, conn,
7272 req->flags2 & FLAGS2_DFS_PATHNAMES,
7273 fname_dst,
7274 UCF_COND_ALLOW_WCARD_LCOMP,
7275 &dest_has_wild,
7276 &smb_fname_dst);
7277 if (!NT_STATUS_IS_OK(status)) {
7278 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7279 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7280 ERRSRV, ERRbadpath);
7281 goto out;
7283 reply_nterror(req, status);
7284 goto out;
7287 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7289 if ((flags&1) && target_is_directory) {
7290 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7291 goto out;
7294 if ((flags&2) && !target_is_directory) {
7295 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7296 goto out;
7299 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7300 /* wants a tree copy! XXXX */
7301 DEBUG(3,("Rejecting tree copy\n"));
7302 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7303 goto out;
7306 /* Split up the directory from the filename/mask. */
7307 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7308 &fname_src_dir, &fname_src_mask);
7309 if (!NT_STATUS_IS_OK(status)) {
7310 reply_nterror(req, NT_STATUS_NO_MEMORY);
7311 goto out;
7315 * We should only check the mangled cache
7316 * here if unix_convert failed. This means
7317 * that the path in 'mask' doesn't exist
7318 * on the file system and so we need to look
7319 * for a possible mangle. This patch from
7320 * Tine Smukavec <valentin.smukavec@hermes.si>.
7322 if (!VALID_STAT(smb_fname_src->st) &&
7323 mangle_is_mangled(fname_src_mask, conn->params)) {
7324 char *new_mask = NULL;
7325 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7326 &new_mask, conn->params);
7328 /* Use demangled name if one was successfully found. */
7329 if (new_mask) {
7330 TALLOC_FREE(fname_src_mask);
7331 fname_src_mask = new_mask;
7335 if (!source_has_wild) {
7338 * Only one file needs to be copied. Append the mask back onto
7339 * the directory.
7341 TALLOC_FREE(smb_fname_src->base_name);
7342 if (ISDOT(fname_src_dir)) {
7343 /* Ensure we use canonical names on open. */
7344 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7345 "%s",
7346 fname_src_mask);
7347 } else {
7348 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7349 "%s/%s",
7350 fname_src_dir,
7351 fname_src_mask);
7353 if (!smb_fname_src->base_name) {
7354 reply_nterror(req, NT_STATUS_NO_MEMORY);
7355 goto out;
7358 if (dest_has_wild) {
7359 char *fname_dst_mod = NULL;
7360 if (!resolve_wildcards(smb_fname_dst,
7361 smb_fname_src->base_name,
7362 smb_fname_dst->base_name,
7363 &fname_dst_mod)) {
7364 reply_nterror(req, NT_STATUS_NO_MEMORY);
7365 goto out;
7367 TALLOC_FREE(smb_fname_dst->base_name);
7368 smb_fname_dst->base_name = fname_dst_mod;
7371 status = check_name(conn, smb_fname_src->base_name);
7372 if (!NT_STATUS_IS_OK(status)) {
7373 reply_nterror(req, status);
7374 goto out;
7377 status = check_name(conn, smb_fname_dst->base_name);
7378 if (!NT_STATUS_IS_OK(status)) {
7379 reply_nterror(req, status);
7380 goto out;
7383 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7384 ofun, count, target_is_directory);
7386 if(!NT_STATUS_IS_OK(status)) {
7387 reply_nterror(req, status);
7388 goto out;
7389 } else {
7390 count++;
7392 } else {
7393 struct smb_Dir *dir_hnd = NULL;
7394 const char *dname = NULL;
7395 char *talloced = NULL;
7396 long offset = 0;
7399 * There is a wildcard that requires us to actually read the
7400 * src dir and copy each file matching the mask to the dst.
7401 * Right now streams won't be copied, but this could
7402 * presumably be added with a nested loop for reach dir entry.
7404 SMB_ASSERT(!smb_fname_src->stream_name);
7405 SMB_ASSERT(!smb_fname_dst->stream_name);
7407 smb_fname_src->stream_name = NULL;
7408 smb_fname_dst->stream_name = NULL;
7410 if (strequal(fname_src_mask,"????????.???")) {
7411 TALLOC_FREE(fname_src_mask);
7412 fname_src_mask = talloc_strdup(ctx, "*");
7413 if (!fname_src_mask) {
7414 reply_nterror(req, NT_STATUS_NO_MEMORY);
7415 goto out;
7419 status = check_name(conn, fname_src_dir);
7420 if (!NT_STATUS_IS_OK(status)) {
7421 reply_nterror(req, status);
7422 goto out;
7425 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7426 if (dir_hnd == NULL) {
7427 status = map_nt_error_from_unix(errno);
7428 reply_nterror(req, status);
7429 goto out;
7432 error = ERRbadfile;
7434 /* Iterate over the src dir copying each entry to the dst. */
7435 while ((dname = ReadDirName(dir_hnd, &offset,
7436 &smb_fname_src->st, &talloced))) {
7437 char *destname = NULL;
7439 if (ISDOT(dname) || ISDOTDOT(dname)) {
7440 TALLOC_FREE(talloced);
7441 continue;
7444 if (!is_visible_file(conn, fname_src_dir, dname,
7445 &smb_fname_src->st, false)) {
7446 TALLOC_FREE(talloced);
7447 continue;
7450 if(!mask_match(dname, fname_src_mask,
7451 conn->case_sensitive)) {
7452 TALLOC_FREE(talloced);
7453 continue;
7456 error = ERRnoaccess;
7458 /* Get the src smb_fname struct setup. */
7459 TALLOC_FREE(smb_fname_src->base_name);
7460 if (ISDOT(fname_src_dir)) {
7461 /* Ensure we use canonical names on open. */
7462 smb_fname_src->base_name =
7463 talloc_asprintf(smb_fname_src, "%s",
7464 dname);
7465 } else {
7466 smb_fname_src->base_name =
7467 talloc_asprintf(smb_fname_src, "%s/%s",
7468 fname_src_dir, dname);
7471 if (!smb_fname_src->base_name) {
7472 TALLOC_FREE(dir_hnd);
7473 TALLOC_FREE(talloced);
7474 reply_nterror(req, NT_STATUS_NO_MEMORY);
7475 goto out;
7478 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7479 smb_fname_dst->base_name,
7480 &destname)) {
7481 TALLOC_FREE(talloced);
7482 continue;
7484 if (!destname) {
7485 TALLOC_FREE(dir_hnd);
7486 TALLOC_FREE(talloced);
7487 reply_nterror(req, NT_STATUS_NO_MEMORY);
7488 goto out;
7491 TALLOC_FREE(smb_fname_dst->base_name);
7492 smb_fname_dst->base_name = destname;
7494 status = check_name(conn, smb_fname_src->base_name);
7495 if (!NT_STATUS_IS_OK(status)) {
7496 TALLOC_FREE(dir_hnd);
7497 TALLOC_FREE(talloced);
7498 reply_nterror(req, status);
7499 goto out;
7502 status = check_name(conn, smb_fname_dst->base_name);
7503 if (!NT_STATUS_IS_OK(status)) {
7504 TALLOC_FREE(dir_hnd);
7505 TALLOC_FREE(talloced);
7506 reply_nterror(req, status);
7507 goto out;
7510 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7511 smb_fname_src->base_name,
7512 smb_fname_dst->base_name));
7514 status = copy_file(ctx, conn, smb_fname_src,
7515 smb_fname_dst, ofun, count,
7516 target_is_directory);
7517 if (NT_STATUS_IS_OK(status)) {
7518 count++;
7521 TALLOC_FREE(talloced);
7523 TALLOC_FREE(dir_hnd);
7526 if (count == 0) {
7527 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7528 goto out;
7531 reply_outbuf(req, 1, 0);
7532 SSVAL(req->outbuf,smb_vwv0,count);
7533 out:
7534 TALLOC_FREE(smb_fname_src);
7535 TALLOC_FREE(smb_fname_dst);
7536 TALLOC_FREE(fname_src);
7537 TALLOC_FREE(fname_dst);
7538 TALLOC_FREE(fname_src_mask);
7539 TALLOC_FREE(fname_src_dir);
7541 END_PROFILE(SMBcopy);
7542 return;
7545 #undef DBGC_CLASS
7546 #define DBGC_CLASS DBGC_LOCKING
7548 /****************************************************************************
7549 Get a lock pid, dealing with large count requests.
7550 ****************************************************************************/
7552 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7553 bool large_file_format)
7555 if(!large_file_format)
7556 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7557 else
7558 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7561 /****************************************************************************
7562 Get a lock count, dealing with large count requests.
7563 ****************************************************************************/
7565 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7566 bool large_file_format)
7568 uint64_t count = 0;
7570 if(!large_file_format) {
7571 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7572 } else {
7574 #if defined(HAVE_LONGLONG)
7575 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7576 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7577 #else /* HAVE_LONGLONG */
7580 * NT4.x seems to be broken in that it sends large file (64 bit)
7581 * lockingX calls even if the CAP_LARGE_FILES was *not*
7582 * negotiated. For boxes without large unsigned ints truncate the
7583 * lock count by dropping the top 32 bits.
7586 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7587 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7588 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7589 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7590 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7593 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7594 #endif /* HAVE_LONGLONG */
7597 return count;
7600 #if !defined(HAVE_LONGLONG)
7601 /****************************************************************************
7602 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7603 ****************************************************************************/
7605 static uint32 map_lock_offset(uint32 high, uint32 low)
7607 unsigned int i;
7608 uint32 mask = 0;
7609 uint32 highcopy = high;
7612 * Try and find out how many significant bits there are in high.
7615 for(i = 0; highcopy; i++)
7616 highcopy >>= 1;
7619 * We use 31 bits not 32 here as POSIX
7620 * lock offsets may not be negative.
7623 mask = (~0) << (31 - i);
7625 if(low & mask)
7626 return 0; /* Fail. */
7628 high <<= (31 - i);
7630 return (high|low);
7632 #endif /* !defined(HAVE_LONGLONG) */
7634 /****************************************************************************
7635 Get a lock offset, dealing with large offset requests.
7636 ****************************************************************************/
7638 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7639 bool large_file_format, bool *err)
7641 uint64_t offset = 0;
7643 *err = False;
7645 if(!large_file_format) {
7646 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7647 } else {
7649 #if defined(HAVE_LONGLONG)
7650 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7651 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7652 #else /* HAVE_LONGLONG */
7655 * NT4.x seems to be broken in that it sends large file (64 bit)
7656 * lockingX calls even if the CAP_LARGE_FILES was *not*
7657 * negotiated. For boxes without large unsigned ints mangle the
7658 * lock offset by mapping the top 32 bits onto the lower 32.
7661 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7662 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7663 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7664 uint32 new_low = 0;
7666 if((new_low = map_lock_offset(high, low)) == 0) {
7667 *err = True;
7668 return (uint64_t)-1;
7671 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7672 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7673 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7674 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7677 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7678 #endif /* HAVE_LONGLONG */
7681 return offset;
7684 NTSTATUS smbd_do_locking(struct smb_request *req,
7685 files_struct *fsp,
7686 uint8_t type,
7687 int32_t timeout,
7688 uint16_t num_ulocks,
7689 struct smbd_lock_element *ulocks,
7690 uint16_t num_locks,
7691 struct smbd_lock_element *locks,
7692 bool *async)
7694 connection_struct *conn = req->conn;
7695 int i;
7696 NTSTATUS status = NT_STATUS_OK;
7698 *async = false;
7700 /* Data now points at the beginning of the list
7701 of smb_unlkrng structs */
7702 for(i = 0; i < (int)num_ulocks; i++) {
7703 struct smbd_lock_element *e = &ulocks[i];
7705 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7706 "pid %u, file %s\n",
7707 (double)e->offset,
7708 (double)e->count,
7709 (unsigned int)e->smblctx,
7710 fsp_str_dbg(fsp)));
7712 if (e->brltype != UNLOCK_LOCK) {
7713 /* this can only happen with SMB2 */
7714 return NT_STATUS_INVALID_PARAMETER;
7717 status = do_unlock(req->sconn->msg_ctx,
7718 fsp,
7719 e->smblctx,
7720 e->count,
7721 e->offset,
7722 WINDOWS_LOCK);
7724 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7725 nt_errstr(status)));
7727 if (!NT_STATUS_IS_OK(status)) {
7728 return status;
7732 /* Setup the timeout in seconds. */
7734 if (!lp_blocking_locks(SNUM(conn))) {
7735 timeout = 0;
7738 /* Data now points at the beginning of the list
7739 of smb_lkrng structs */
7741 for(i = 0; i < (int)num_locks; i++) {
7742 struct smbd_lock_element *e = &locks[i];
7744 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7745 "%llu, file %s timeout = %d\n",
7746 (double)e->offset,
7747 (double)e->count,
7748 (unsigned long long)e->smblctx,
7749 fsp_str_dbg(fsp),
7750 (int)timeout));
7752 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7753 struct blocking_lock_record *blr = NULL;
7755 if (num_locks > 1) {
7757 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7758 * if the lock vector contains one entry. When given mutliple cancel
7759 * requests in a single PDU we expect the server to return an
7760 * error. Windows servers seem to accept the request but only
7761 * cancel the first lock.
7762 * JRA - Do what Windows does (tm) :-).
7765 #if 0
7766 /* MS-CIFS (2.2.4.32.1) behavior. */
7767 return NT_STATUS_DOS(ERRDOS,
7768 ERRcancelviolation);
7769 #else
7770 /* Windows behavior. */
7771 if (i != 0) {
7772 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7773 "cancel request\n"));
7774 continue;
7776 #endif
7779 if (lp_blocking_locks(SNUM(conn))) {
7781 /* Schedule a message to ourselves to
7782 remove the blocking lock record and
7783 return the right error. */
7785 blr = blocking_lock_cancel_smb1(fsp,
7786 e->smblctx,
7787 e->offset,
7788 e->count,
7789 WINDOWS_LOCK,
7790 type,
7791 NT_STATUS_FILE_LOCK_CONFLICT);
7792 if (blr == NULL) {
7793 return NT_STATUS_DOS(
7794 ERRDOS,
7795 ERRcancelviolation);
7798 /* Remove a matching pending lock. */
7799 status = do_lock_cancel(fsp,
7800 e->smblctx,
7801 e->count,
7802 e->offset,
7803 WINDOWS_LOCK,
7804 blr);
7805 } else {
7806 bool blocking_lock = timeout ? true : false;
7807 bool defer_lock = false;
7808 struct byte_range_lock *br_lck;
7809 uint64_t block_smblctx;
7811 br_lck = do_lock(req->sconn->msg_ctx,
7812 fsp,
7813 e->smblctx,
7814 e->count,
7815 e->offset,
7816 e->brltype,
7817 WINDOWS_LOCK,
7818 blocking_lock,
7819 &status,
7820 &block_smblctx,
7821 NULL);
7823 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7824 /* Windows internal resolution for blocking locks seems
7825 to be about 200ms... Don't wait for less than that. JRA. */
7826 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7827 timeout = lp_lock_spin_time();
7829 defer_lock = true;
7832 /* If a lock sent with timeout of zero would fail, and
7833 * this lock has been requested multiple times,
7834 * according to brl_lock_failed() we convert this
7835 * request to a blocking lock with a timeout of between
7836 * 150 - 300 milliseconds.
7838 * If lp_lock_spin_time() has been set to 0, we skip
7839 * this blocking retry and fail immediately.
7841 * Replacement for do_lock_spin(). JRA. */
7843 if (!req->sconn->using_smb2 &&
7844 br_lck && lp_blocking_locks(SNUM(conn)) &&
7845 lp_lock_spin_time() && !blocking_lock &&
7846 NT_STATUS_EQUAL((status),
7847 NT_STATUS_FILE_LOCK_CONFLICT))
7849 defer_lock = true;
7850 timeout = lp_lock_spin_time();
7853 if (br_lck && defer_lock) {
7855 * A blocking lock was requested. Package up
7856 * this smb into a queued request and push it
7857 * onto the blocking lock queue.
7859 if(push_blocking_lock_request(br_lck,
7860 req,
7861 fsp,
7862 timeout,
7864 e->smblctx,
7865 e->brltype,
7866 WINDOWS_LOCK,
7867 e->offset,
7868 e->count,
7869 block_smblctx)) {
7870 TALLOC_FREE(br_lck);
7871 *async = true;
7872 return NT_STATUS_OK;
7876 TALLOC_FREE(br_lck);
7879 if (!NT_STATUS_IS_OK(status)) {
7880 break;
7884 /* If any of the above locks failed, then we must unlock
7885 all of the previous locks (X/Open spec). */
7887 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7889 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7890 i = -1; /* we want to skip the for loop */
7894 * Ensure we don't do a remove on the lock that just failed,
7895 * as under POSIX rules, if we have a lock already there, we
7896 * will delete it (and we shouldn't) .....
7898 for(i--; i >= 0; i--) {
7899 struct smbd_lock_element *e = &locks[i];
7901 do_unlock(req->sconn->msg_ctx,
7902 fsp,
7903 e->smblctx,
7904 e->count,
7905 e->offset,
7906 WINDOWS_LOCK);
7908 return status;
7911 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7912 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7914 return NT_STATUS_OK;
7917 /****************************************************************************
7918 Reply to a lockingX request.
7919 ****************************************************************************/
7921 void reply_lockingX(struct smb_request *req)
7923 connection_struct *conn = req->conn;
7924 files_struct *fsp;
7925 unsigned char locktype;
7926 unsigned char oplocklevel;
7927 uint16 num_ulocks;
7928 uint16 num_locks;
7929 int32 lock_timeout;
7930 int i;
7931 const uint8_t *data;
7932 bool large_file_format;
7933 bool err;
7934 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7935 struct smbd_lock_element *ulocks;
7936 struct smbd_lock_element *locks;
7937 bool async = false;
7939 START_PROFILE(SMBlockingX);
7941 if (req->wct < 8) {
7942 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7943 END_PROFILE(SMBlockingX);
7944 return;
7947 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7948 locktype = CVAL(req->vwv+3, 0);
7949 oplocklevel = CVAL(req->vwv+3, 1);
7950 num_ulocks = SVAL(req->vwv+6, 0);
7951 num_locks = SVAL(req->vwv+7, 0);
7952 lock_timeout = IVAL(req->vwv+4, 0);
7953 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7955 if (!check_fsp(conn, req, fsp)) {
7956 END_PROFILE(SMBlockingX);
7957 return;
7960 data = req->buf;
7962 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7963 /* we don't support these - and CANCEL_LOCK makes w2k
7964 and XP reboot so I don't really want to be
7965 compatible! (tridge) */
7966 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7967 END_PROFILE(SMBlockingX);
7968 return;
7971 /* Check if this is an oplock break on a file
7972 we have granted an oplock on.
7974 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7975 /* Client can insist on breaking to none. */
7976 bool break_to_none = (oplocklevel == 0);
7977 bool result;
7979 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7980 "for %s\n", (unsigned int)oplocklevel,
7981 fsp_fnum_dbg(fsp)));
7984 * Make sure we have granted an exclusive or batch oplock on
7985 * this file.
7988 if (fsp->oplock_type == 0) {
7990 /* The Samba4 nbench simulator doesn't understand
7991 the difference between break to level2 and break
7992 to none from level2 - it sends oplock break
7993 replies in both cases. Don't keep logging an error
7994 message here - just ignore it. JRA. */
7996 DEBUG(5,("reply_lockingX: Error : oplock break from "
7997 "client for %s (oplock=%d) and no "
7998 "oplock granted on this file (%s).\n",
7999 fsp_fnum_dbg(fsp), fsp->oplock_type,
8000 fsp_str_dbg(fsp)));
8002 /* if this is a pure oplock break request then don't
8003 * send a reply */
8004 if (num_locks == 0 && num_ulocks == 0) {
8005 END_PROFILE(SMBlockingX);
8006 return;
8007 } else {
8008 END_PROFILE(SMBlockingX);
8009 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8010 return;
8014 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8015 (break_to_none)) {
8016 result = remove_oplock(fsp);
8017 } else {
8018 result = downgrade_oplock(fsp);
8021 if (!result) {
8022 DEBUG(0, ("reply_lockingX: error in removing "
8023 "oplock on file %s\n", fsp_str_dbg(fsp)));
8024 /* Hmmm. Is this panic justified? */
8025 smb_panic("internal tdb error");
8028 reply_to_oplock_break_requests(fsp);
8030 /* if this is a pure oplock break request then don't send a
8031 * reply */
8032 if (num_locks == 0 && num_ulocks == 0) {
8033 /* Sanity check - ensure a pure oplock break is not a
8034 chained request. */
8035 if(CVAL(req->vwv+0, 0) != 0xff)
8036 DEBUG(0,("reply_lockingX: Error : pure oplock "
8037 "break is a chained %d request !\n",
8038 (unsigned int)CVAL(req->vwv+0, 0)));
8039 END_PROFILE(SMBlockingX);
8040 return;
8044 if (req->buflen <
8045 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8046 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8047 END_PROFILE(SMBlockingX);
8048 return;
8051 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8052 if (ulocks == NULL) {
8053 reply_nterror(req, NT_STATUS_NO_MEMORY);
8054 END_PROFILE(SMBlockingX);
8055 return;
8058 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8059 if (locks == NULL) {
8060 reply_nterror(req, NT_STATUS_NO_MEMORY);
8061 END_PROFILE(SMBlockingX);
8062 return;
8065 /* Data now points at the beginning of the list
8066 of smb_unlkrng structs */
8067 for(i = 0; i < (int)num_ulocks; i++) {
8068 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8069 ulocks[i].count = get_lock_count(data, i, large_file_format);
8070 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8071 ulocks[i].brltype = UNLOCK_LOCK;
8074 * There is no error code marked "stupid client bug".... :-).
8076 if(err) {
8077 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8078 END_PROFILE(SMBlockingX);
8079 return;
8083 /* Now do any requested locks */
8084 data += ((large_file_format ? 20 : 10)*num_ulocks);
8086 /* Data now points at the beginning of the list
8087 of smb_lkrng structs */
8089 for(i = 0; i < (int)num_locks; i++) {
8090 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8091 locks[i].count = get_lock_count(data, i, large_file_format);
8092 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8094 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8095 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8096 locks[i].brltype = PENDING_READ_LOCK;
8097 } else {
8098 locks[i].brltype = READ_LOCK;
8100 } else {
8101 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8102 locks[i].brltype = PENDING_WRITE_LOCK;
8103 } else {
8104 locks[i].brltype = WRITE_LOCK;
8109 * There is no error code marked "stupid client bug".... :-).
8111 if(err) {
8112 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8113 END_PROFILE(SMBlockingX);
8114 return;
8118 status = smbd_do_locking(req, fsp,
8119 locktype, lock_timeout,
8120 num_ulocks, ulocks,
8121 num_locks, locks,
8122 &async);
8123 if (!NT_STATUS_IS_OK(status)) {
8124 END_PROFILE(SMBlockingX);
8125 reply_nterror(req, status);
8126 return;
8128 if (async) {
8129 END_PROFILE(SMBlockingX);
8130 return;
8133 reply_outbuf(req, 2, 0);
8134 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8135 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8137 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8138 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8140 END_PROFILE(SMBlockingX);
8143 #undef DBGC_CLASS
8144 #define DBGC_CLASS DBGC_ALL
8146 /****************************************************************************
8147 Reply to a SMBreadbmpx (read block multiplex) request.
8148 Always reply with an error, if someone has a platform really needs this,
8149 please contact vl@samba.org
8150 ****************************************************************************/
8152 void reply_readbmpx(struct smb_request *req)
8154 START_PROFILE(SMBreadBmpx);
8155 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8156 END_PROFILE(SMBreadBmpx);
8157 return;
8160 /****************************************************************************
8161 Reply to a SMBreadbs (read block multiplex secondary) request.
8162 Always reply with an error, if someone has a platform really needs this,
8163 please contact vl@samba.org
8164 ****************************************************************************/
8166 void reply_readbs(struct smb_request *req)
8168 START_PROFILE(SMBreadBs);
8169 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8170 END_PROFILE(SMBreadBs);
8171 return;
8174 /****************************************************************************
8175 Reply to a SMBsetattrE.
8176 ****************************************************************************/
8178 void reply_setattrE(struct smb_request *req)
8180 connection_struct *conn = req->conn;
8181 struct smb_file_time ft;
8182 files_struct *fsp;
8183 NTSTATUS status;
8185 START_PROFILE(SMBsetattrE);
8186 ZERO_STRUCT(ft);
8188 if (req->wct < 7) {
8189 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8190 goto out;
8193 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8195 if(!fsp || (fsp->conn != conn)) {
8196 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8197 goto out;
8201 * Convert the DOS times into unix times.
8204 ft.atime = convert_time_t_to_timespec(
8205 srv_make_unix_date2(req->vwv+3));
8206 ft.mtime = convert_time_t_to_timespec(
8207 srv_make_unix_date2(req->vwv+5));
8208 ft.create_time = convert_time_t_to_timespec(
8209 srv_make_unix_date2(req->vwv+1));
8211 reply_outbuf(req, 0, 0);
8214 * Patch from Ray Frush <frush@engr.colostate.edu>
8215 * Sometimes times are sent as zero - ignore them.
8218 /* Ensure we have a valid stat struct for the source. */
8219 status = vfs_stat_fsp(fsp);
8220 if (!NT_STATUS_IS_OK(status)) {
8221 reply_nterror(req, status);
8222 goto out;
8225 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8226 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8227 goto out;
8230 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8231 if (!NT_STATUS_IS_OK(status)) {
8232 reply_nterror(req, status);
8233 goto out;
8236 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8237 " createtime=%u\n",
8238 fsp_fnum_dbg(fsp),
8239 (unsigned int)ft.atime.tv_sec,
8240 (unsigned int)ft.mtime.tv_sec,
8241 (unsigned int)ft.create_time.tv_sec
8243 out:
8244 END_PROFILE(SMBsetattrE);
8245 return;
8249 /* Back from the dead for OS/2..... JRA. */
8251 /****************************************************************************
8252 Reply to a SMBwritebmpx (write block multiplex primary) request.
8253 Always reply with an error, if someone has a platform really needs this,
8254 please contact vl@samba.org
8255 ****************************************************************************/
8257 void reply_writebmpx(struct smb_request *req)
8259 START_PROFILE(SMBwriteBmpx);
8260 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8261 END_PROFILE(SMBwriteBmpx);
8262 return;
8265 /****************************************************************************
8266 Reply to a SMBwritebs (write block multiplex secondary) request.
8267 Always reply with an error, if someone has a platform really needs this,
8268 please contact vl@samba.org
8269 ****************************************************************************/
8271 void reply_writebs(struct smb_request *req)
8273 START_PROFILE(SMBwriteBs);
8274 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8275 END_PROFILE(SMBwriteBs);
8276 return;
8279 /****************************************************************************
8280 Reply to a SMBgetattrE.
8281 ****************************************************************************/
8283 void reply_getattrE(struct smb_request *req)
8285 connection_struct *conn = req->conn;
8286 int mode;
8287 files_struct *fsp;
8288 struct timespec create_ts;
8290 START_PROFILE(SMBgetattrE);
8292 if (req->wct < 1) {
8293 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8294 END_PROFILE(SMBgetattrE);
8295 return;
8298 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8300 if(!fsp || (fsp->conn != conn)) {
8301 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8302 END_PROFILE(SMBgetattrE);
8303 return;
8306 /* Do an fstat on this file */
8307 if(fsp_stat(fsp)) {
8308 reply_nterror(req, map_nt_error_from_unix(errno));
8309 END_PROFILE(SMBgetattrE);
8310 return;
8313 mode = dos_mode(conn, fsp->fsp_name);
8316 * Convert the times into dos times. Set create
8317 * date to be last modify date as UNIX doesn't save
8318 * this.
8321 reply_outbuf(req, 11, 0);
8323 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8324 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8325 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8326 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8327 /* Should we check pending modtime here ? JRA */
8328 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8329 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8331 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8332 SIVAL(req->outbuf, smb_vwv6, 0);
8333 SIVAL(req->outbuf, smb_vwv8, 0);
8334 } else {
8335 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8336 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8337 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8339 SSVAL(req->outbuf,smb_vwv10, mode);
8341 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8343 END_PROFILE(SMBgetattrE);
8344 return;