s3:smbd: fix lockread numtoread calculation to match reply_outbuf() arguments.
[Samba.git] / source3 / smbd / reply.c
blobe07b40bbe366e952e1f79e9b6f518bdea85d9c99
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 maxentries = MIN(
1701 maxentries,
1702 ((BUFFER_SIZE -
1703 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1704 /DIR_STRUCT_SIZE));
1706 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1707 directory,lp_dontdescend(ctx, SNUM(conn))));
1708 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1709 check_descend = True;
1712 for (i=numentries;(i<maxentries) && !finished;i++) {
1713 finished = !get_dir_entry(ctx,
1714 dirptr,
1715 mask,
1716 dirtype,
1717 &fname,
1718 &size,
1719 &mode,
1720 &date,
1721 check_descend,
1722 ask_sharemode);
1723 if (!finished) {
1724 char buf[DIR_STRUCT_SIZE];
1725 memcpy(buf,status,21);
1726 if (!make_dir_struct(ctx,
1727 buf,
1728 mask,
1729 fname,
1730 size,
1731 mode,
1732 convert_timespec_to_time_t(date),
1733 !allow_long_path_components)) {
1734 reply_nterror(req, NT_STATUS_NO_MEMORY);
1735 goto out;
1737 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1738 break;
1740 if (message_push_blob(&req->outbuf,
1741 data_blob_const(buf, sizeof(buf)))
1742 == -1) {
1743 reply_nterror(req, NT_STATUS_NO_MEMORY);
1744 goto out;
1746 numentries++;
1751 SearchEmpty:
1753 /* If we were called as SMBffirst with smb_search_id == NULL
1754 and no entries were found then return error and close dirptr
1755 (X/Open spec) */
1757 if (numentries == 0) {
1758 dptr_close(sconn, &dptr_num);
1759 } else if(expect_close && status_len == 0) {
1760 /* Close the dptr - we know it's gone */
1761 dptr_close(sconn, &dptr_num);
1764 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1765 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1766 dptr_close(sconn, &dptr_num);
1769 if ((numentries == 0) && !mask_contains_wcard) {
1770 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1771 goto out;
1774 SSVAL(req->outbuf,smb_vwv0,numentries);
1775 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1776 SCVAL(smb_buf(req->outbuf),0,5);
1777 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1779 /* The replies here are never long name. */
1780 SSVAL(req->outbuf, smb_flg2,
1781 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1782 if (!allow_long_path_components) {
1783 SSVAL(req->outbuf, smb_flg2,
1784 SVAL(req->outbuf, smb_flg2)
1785 & (~FLAGS2_LONG_PATH_COMPONENTS));
1788 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1789 SSVAL(req->outbuf, smb_flg2,
1790 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1792 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1793 smb_fn_name(req->cmd),
1794 mask,
1795 directory,
1796 dirtype,
1797 numentries,
1798 maxentries ));
1799 out:
1800 TALLOC_FREE(directory);
1801 TALLOC_FREE(smb_fname);
1802 END_PROFILE(SMBsearch);
1803 return;
1806 /****************************************************************************
1807 Reply to a fclose (stop directory search).
1808 ****************************************************************************/
1810 void reply_fclose(struct smb_request *req)
1812 int status_len;
1813 char status[21];
1814 int dptr_num= -2;
1815 const char *p;
1816 char *path = NULL;
1817 NTSTATUS err;
1818 bool path_contains_wcard = False;
1819 TALLOC_CTX *ctx = talloc_tos();
1820 struct smbd_server_connection *sconn = req->sconn;
1822 START_PROFILE(SMBfclose);
1824 if (lp_posix_pathnames()) {
1825 reply_unknown_new(req, req->cmd);
1826 END_PROFILE(SMBfclose);
1827 return;
1830 p = (const char *)req->buf + 1;
1831 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1832 &err, &path_contains_wcard);
1833 if (!NT_STATUS_IS_OK(err)) {
1834 reply_nterror(req, err);
1835 END_PROFILE(SMBfclose);
1836 return;
1838 p++;
1839 status_len = SVAL(p,0);
1840 p += 2;
1842 if (status_len == 0) {
1843 reply_force_doserror(req, ERRSRV, ERRsrverror);
1844 END_PROFILE(SMBfclose);
1845 return;
1848 memcpy(status,p,21);
1850 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1851 /* Close the dptr - we know it's gone */
1852 dptr_close(sconn, &dptr_num);
1855 reply_outbuf(req, 1, 0);
1856 SSVAL(req->outbuf,smb_vwv0,0);
1858 DEBUG(3,("search close\n"));
1860 END_PROFILE(SMBfclose);
1861 return;
1864 /****************************************************************************
1865 Reply to an open.
1866 ****************************************************************************/
1868 void reply_open(struct smb_request *req)
1870 connection_struct *conn = req->conn;
1871 struct smb_filename *smb_fname = NULL;
1872 char *fname = NULL;
1873 uint32 fattr=0;
1874 off_t size = 0;
1875 time_t mtime=0;
1876 int info;
1877 files_struct *fsp;
1878 int oplock_request;
1879 int deny_mode;
1880 uint32 dos_attr;
1881 uint32 access_mask;
1882 uint32 share_mode;
1883 uint32 create_disposition;
1884 uint32 create_options = 0;
1885 uint32_t private_flags = 0;
1886 NTSTATUS status;
1887 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1888 TALLOC_CTX *ctx = talloc_tos();
1890 START_PROFILE(SMBopen);
1892 if (req->wct < 2) {
1893 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1894 goto out;
1897 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1898 deny_mode = SVAL(req->vwv+0, 0);
1899 dos_attr = SVAL(req->vwv+1, 0);
1901 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1902 STR_TERMINATE, &status);
1903 if (!NT_STATUS_IS_OK(status)) {
1904 reply_nterror(req, status);
1905 goto out;
1908 if (!map_open_params_to_ntcreate(fname, deny_mode,
1909 OPENX_FILE_EXISTS_OPEN, &access_mask,
1910 &share_mode, &create_disposition,
1911 &create_options, &private_flags)) {
1912 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1913 goto out;
1916 status = filename_convert(ctx,
1917 conn,
1918 req->flags2 & FLAGS2_DFS_PATHNAMES,
1919 fname,
1920 UCF_PREP_CREATEFILE,
1921 NULL,
1922 &smb_fname);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1925 reply_botherror(req,
1926 NT_STATUS_PATH_NOT_COVERED,
1927 ERRSRV, ERRbadpath);
1928 goto out;
1930 reply_nterror(req, status);
1931 goto out;
1934 status = SMB_VFS_CREATE_FILE(
1935 conn, /* conn */
1936 req, /* req */
1937 0, /* root_dir_fid */
1938 smb_fname, /* fname */
1939 access_mask, /* access_mask */
1940 share_mode, /* share_access */
1941 create_disposition, /* create_disposition*/
1942 create_options, /* create_options */
1943 dos_attr, /* file_attributes */
1944 oplock_request, /* oplock_request */
1945 0, /* allocation_size */
1946 private_flags,
1947 NULL, /* sd */
1948 NULL, /* ea_list */
1949 &fsp, /* result */
1950 &info); /* pinfo */
1952 if (!NT_STATUS_IS_OK(status)) {
1953 if (open_was_deferred(req->sconn, req->mid)) {
1954 /* We have re-scheduled this call. */
1955 goto out;
1957 reply_openerror(req, status);
1958 goto out;
1961 size = smb_fname->st.st_ex_size;
1962 fattr = dos_mode(conn, smb_fname);
1964 /* Deal with other possible opens having a modified
1965 write time. JRA. */
1966 if (ask_sharemode) {
1967 struct timespec write_time_ts;
1969 ZERO_STRUCT(write_time_ts);
1970 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1971 if (!null_timespec(write_time_ts)) {
1972 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1976 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1978 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1979 DEBUG(3,("attempt to open a directory %s\n",
1980 fsp_str_dbg(fsp)));
1981 close_file(req, fsp, ERROR_CLOSE);
1982 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1983 ERRDOS, ERRnoaccess);
1984 goto out;
1987 reply_outbuf(req, 7, 0);
1988 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1989 SSVAL(req->outbuf,smb_vwv1,fattr);
1990 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1991 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1992 } else {
1993 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1995 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1996 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1998 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1999 SCVAL(req->outbuf,smb_flg,
2000 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2003 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2004 SCVAL(req->outbuf,smb_flg,
2005 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2007 out:
2008 TALLOC_FREE(smb_fname);
2009 END_PROFILE(SMBopen);
2010 return;
2013 /****************************************************************************
2014 Reply to an open and X.
2015 ****************************************************************************/
2017 void reply_open_and_X(struct smb_request *req)
2019 connection_struct *conn = req->conn;
2020 struct smb_filename *smb_fname = NULL;
2021 char *fname = NULL;
2022 uint16 open_flags;
2023 int deny_mode;
2024 uint32 smb_attr;
2025 /* Breakout the oplock request bits so we can set the
2026 reply bits separately. */
2027 int ex_oplock_request;
2028 int core_oplock_request;
2029 int oplock_request;
2030 #if 0
2031 int smb_sattr = SVAL(req->vwv+4, 0);
2032 uint32 smb_time = make_unix_date3(req->vwv+6);
2033 #endif
2034 int smb_ofun;
2035 uint32 fattr=0;
2036 int mtime=0;
2037 int smb_action = 0;
2038 files_struct *fsp;
2039 NTSTATUS status;
2040 uint64_t allocation_size;
2041 ssize_t retval = -1;
2042 uint32 access_mask;
2043 uint32 share_mode;
2044 uint32 create_disposition;
2045 uint32 create_options = 0;
2046 uint32_t private_flags = 0;
2047 TALLOC_CTX *ctx = talloc_tos();
2049 START_PROFILE(SMBopenX);
2051 if (req->wct < 15) {
2052 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2053 goto out;
2056 open_flags = SVAL(req->vwv+2, 0);
2057 deny_mode = SVAL(req->vwv+3, 0);
2058 smb_attr = SVAL(req->vwv+5, 0);
2059 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2060 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2061 oplock_request = ex_oplock_request | core_oplock_request;
2062 smb_ofun = SVAL(req->vwv+8, 0);
2063 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2065 /* If it's an IPC, pass off the pipe handler. */
2066 if (IS_IPC(conn)) {
2067 if (lp_nt_pipe_support()) {
2068 reply_open_pipe_and_X(conn, req);
2069 } else {
2070 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2072 goto out;
2075 /* XXXX we need to handle passed times, sattr and flags */
2076 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2077 STR_TERMINATE, &status);
2078 if (!NT_STATUS_IS_OK(status)) {
2079 reply_nterror(req, status);
2080 goto out;
2083 if (!map_open_params_to_ntcreate(fname, deny_mode,
2084 smb_ofun,
2085 &access_mask, &share_mode,
2086 &create_disposition,
2087 &create_options,
2088 &private_flags)) {
2089 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2090 goto out;
2093 status = filename_convert(ctx,
2094 conn,
2095 req->flags2 & FLAGS2_DFS_PATHNAMES,
2096 fname,
2097 UCF_PREP_CREATEFILE,
2098 NULL,
2099 &smb_fname);
2100 if (!NT_STATUS_IS_OK(status)) {
2101 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2102 reply_botherror(req,
2103 NT_STATUS_PATH_NOT_COVERED,
2104 ERRSRV, ERRbadpath);
2105 goto out;
2107 reply_nterror(req, status);
2108 goto out;
2111 status = SMB_VFS_CREATE_FILE(
2112 conn, /* conn */
2113 req, /* req */
2114 0, /* root_dir_fid */
2115 smb_fname, /* fname */
2116 access_mask, /* access_mask */
2117 share_mode, /* share_access */
2118 create_disposition, /* create_disposition*/
2119 create_options, /* create_options */
2120 smb_attr, /* file_attributes */
2121 oplock_request, /* oplock_request */
2122 0, /* allocation_size */
2123 private_flags,
2124 NULL, /* sd */
2125 NULL, /* ea_list */
2126 &fsp, /* result */
2127 &smb_action); /* pinfo */
2129 if (!NT_STATUS_IS_OK(status)) {
2130 if (open_was_deferred(req->sconn, req->mid)) {
2131 /* We have re-scheduled this call. */
2132 goto out;
2134 reply_openerror(req, status);
2135 goto out;
2138 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2139 if the file is truncated or created. */
2140 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2141 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2142 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2143 close_file(req, fsp, ERROR_CLOSE);
2144 reply_nterror(req, NT_STATUS_DISK_FULL);
2145 goto out;
2147 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2148 if (retval < 0) {
2149 close_file(req, fsp, ERROR_CLOSE);
2150 reply_nterror(req, NT_STATUS_DISK_FULL);
2151 goto out;
2153 status = vfs_stat_fsp(fsp);
2154 if (!NT_STATUS_IS_OK(status)) {
2155 close_file(req, fsp, ERROR_CLOSE);
2156 reply_nterror(req, status);
2157 goto out;
2161 fattr = dos_mode(conn, fsp->fsp_name);
2162 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2163 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2164 close_file(req, fsp, ERROR_CLOSE);
2165 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2166 goto out;
2169 /* If the caller set the extended oplock request bit
2170 and we granted one (by whatever means) - set the
2171 correct bit for extended oplock reply.
2174 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2175 smb_action |= EXTENDED_OPLOCK_GRANTED;
2178 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2179 smb_action |= EXTENDED_OPLOCK_GRANTED;
2182 /* If the caller set the core oplock request bit
2183 and we granted one (by whatever means) - set the
2184 correct bit for core oplock reply.
2187 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2188 reply_outbuf(req, 19, 0);
2189 } else {
2190 reply_outbuf(req, 15, 0);
2193 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2194 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2196 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2197 SCVAL(req->outbuf, smb_flg,
2198 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2201 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2202 SCVAL(req->outbuf, smb_flg,
2203 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2206 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2207 SSVAL(req->outbuf,smb_vwv3,fattr);
2208 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2209 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2210 } else {
2211 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2213 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2214 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2215 SSVAL(req->outbuf,smb_vwv11,smb_action);
2217 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2218 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2221 out:
2222 TALLOC_FREE(smb_fname);
2223 END_PROFILE(SMBopenX);
2224 return;
2227 /****************************************************************************
2228 Reply to a SMBulogoffX.
2229 ****************************************************************************/
2231 void reply_ulogoffX(struct smb_request *req)
2233 struct smbd_server_connection *sconn = req->sconn;
2234 struct user_struct *vuser;
2235 struct smbXsrv_session *session = NULL;
2236 NTSTATUS status;
2238 START_PROFILE(SMBulogoffX);
2240 vuser = get_valid_user_struct(sconn, req->vuid);
2242 if(vuser == NULL) {
2243 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2244 (unsigned long long)req->vuid));
2246 req->vuid = UID_FIELD_INVALID;
2247 reply_force_doserror(req, ERRSRV, ERRbaduid);
2248 END_PROFILE(SMBulogoffX);
2249 return;
2252 session = vuser->session;
2253 vuser = NULL;
2256 * TODO: cancel all outstanding requests on the session
2258 status = smbXsrv_session_logoff(session);
2259 if (!NT_STATUS_IS_OK(status)) {
2260 DEBUG(0, ("reply_ulogoff: "
2261 "smbXsrv_session_logoff() failed: %s\n",
2262 nt_errstr(status)));
2264 * If we hit this case, there is something completely
2265 * wrong, so we better disconnect the transport connection.
2267 END_PROFILE(SMBulogoffX);
2268 exit_server(__location__ ": smbXsrv_session_logoff failed");
2269 return;
2272 TALLOC_FREE(session);
2274 reply_outbuf(req, 2, 0);
2275 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2276 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2278 DEBUG(3, ("ulogoffX vuid=%llu\n",
2279 (unsigned long long)req->vuid));
2281 END_PROFILE(SMBulogoffX);
2282 req->vuid = UID_FIELD_INVALID;
2285 /****************************************************************************
2286 Reply to a mknew or a create.
2287 ****************************************************************************/
2289 void reply_mknew(struct smb_request *req)
2291 connection_struct *conn = req->conn;
2292 struct smb_filename *smb_fname = NULL;
2293 char *fname = NULL;
2294 uint32 fattr = 0;
2295 struct smb_file_time ft;
2296 files_struct *fsp;
2297 int oplock_request = 0;
2298 NTSTATUS status;
2299 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2300 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2301 uint32 create_disposition;
2302 uint32 create_options = 0;
2303 TALLOC_CTX *ctx = talloc_tos();
2305 START_PROFILE(SMBcreate);
2306 ZERO_STRUCT(ft);
2308 if (req->wct < 3) {
2309 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2310 goto out;
2313 fattr = SVAL(req->vwv+0, 0);
2314 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2316 /* mtime. */
2317 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2319 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2320 STR_TERMINATE, &status);
2321 if (!NT_STATUS_IS_OK(status)) {
2322 reply_nterror(req, status);
2323 goto out;
2326 status = filename_convert(ctx,
2327 conn,
2328 req->flags2 & FLAGS2_DFS_PATHNAMES,
2329 fname,
2330 UCF_PREP_CREATEFILE,
2331 NULL,
2332 &smb_fname);
2333 if (!NT_STATUS_IS_OK(status)) {
2334 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2335 reply_botherror(req,
2336 NT_STATUS_PATH_NOT_COVERED,
2337 ERRSRV, ERRbadpath);
2338 goto out;
2340 reply_nterror(req, status);
2341 goto out;
2344 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2345 DEBUG(0,("Attempt to create file (%s) with volid set - "
2346 "please report this\n",
2347 smb_fname_str_dbg(smb_fname)));
2350 if(req->cmd == SMBmknew) {
2351 /* We should fail if file exists. */
2352 create_disposition = FILE_CREATE;
2353 } else {
2354 /* Create if file doesn't exist, truncate if it does. */
2355 create_disposition = FILE_OVERWRITE_IF;
2358 status = SMB_VFS_CREATE_FILE(
2359 conn, /* conn */
2360 req, /* req */
2361 0, /* root_dir_fid */
2362 smb_fname, /* fname */
2363 access_mask, /* access_mask */
2364 share_mode, /* share_access */
2365 create_disposition, /* create_disposition*/
2366 create_options, /* create_options */
2367 fattr, /* file_attributes */
2368 oplock_request, /* oplock_request */
2369 0, /* allocation_size */
2370 0, /* private_flags */
2371 NULL, /* sd */
2372 NULL, /* ea_list */
2373 &fsp, /* result */
2374 NULL); /* pinfo */
2376 if (!NT_STATUS_IS_OK(status)) {
2377 if (open_was_deferred(req->sconn, req->mid)) {
2378 /* We have re-scheduled this call. */
2379 goto out;
2381 reply_openerror(req, status);
2382 goto out;
2385 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2386 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2387 if (!NT_STATUS_IS_OK(status)) {
2388 END_PROFILE(SMBcreate);
2389 goto out;
2392 reply_outbuf(req, 1, 0);
2393 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2395 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2396 SCVAL(req->outbuf,smb_flg,
2397 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2400 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2401 SCVAL(req->outbuf,smb_flg,
2402 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2405 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2406 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2407 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2408 (unsigned int)fattr));
2410 out:
2411 TALLOC_FREE(smb_fname);
2412 END_PROFILE(SMBcreate);
2413 return;
2416 /****************************************************************************
2417 Reply to a create temporary file.
2418 ****************************************************************************/
2420 void reply_ctemp(struct smb_request *req)
2422 connection_struct *conn = req->conn;
2423 struct smb_filename *smb_fname = NULL;
2424 char *wire_name = NULL;
2425 char *fname = NULL;
2426 uint32 fattr;
2427 files_struct *fsp;
2428 int oplock_request;
2429 char *s;
2430 NTSTATUS status;
2431 int i;
2432 TALLOC_CTX *ctx = talloc_tos();
2434 START_PROFILE(SMBctemp);
2436 if (req->wct < 3) {
2437 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2438 goto out;
2441 fattr = SVAL(req->vwv+0, 0);
2442 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2444 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2445 STR_TERMINATE, &status);
2446 if (!NT_STATUS_IS_OK(status)) {
2447 reply_nterror(req, status);
2448 goto out;
2451 for (i = 0; i < 10; i++) {
2452 if (*wire_name) {
2453 fname = talloc_asprintf(ctx,
2454 "%s/TMP%s",
2455 wire_name,
2456 generate_random_str_list(ctx, 5, "0123456789"));
2457 } else {
2458 fname = talloc_asprintf(ctx,
2459 "TMP%s",
2460 generate_random_str_list(ctx, 5, "0123456789"));
2463 if (!fname) {
2464 reply_nterror(req, NT_STATUS_NO_MEMORY);
2465 goto out;
2468 status = filename_convert(ctx, conn,
2469 req->flags2 & FLAGS2_DFS_PATHNAMES,
2470 fname,
2471 UCF_PREP_CREATEFILE,
2472 NULL,
2473 &smb_fname);
2474 if (!NT_STATUS_IS_OK(status)) {
2475 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2476 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2477 ERRSRV, ERRbadpath);
2478 goto out;
2480 reply_nterror(req, status);
2481 goto out;
2484 /* Create the file. */
2485 status = SMB_VFS_CREATE_FILE(
2486 conn, /* conn */
2487 req, /* req */
2488 0, /* root_dir_fid */
2489 smb_fname, /* fname */
2490 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2491 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2492 FILE_CREATE, /* create_disposition*/
2493 0, /* create_options */
2494 fattr, /* file_attributes */
2495 oplock_request, /* oplock_request */
2496 0, /* allocation_size */
2497 0, /* private_flags */
2498 NULL, /* sd */
2499 NULL, /* ea_list */
2500 &fsp, /* result */
2501 NULL); /* pinfo */
2503 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2504 TALLOC_FREE(fname);
2505 TALLOC_FREE(smb_fname);
2506 continue;
2509 if (!NT_STATUS_IS_OK(status)) {
2510 if (open_was_deferred(req->sconn, req->mid)) {
2511 /* We have re-scheduled this call. */
2512 goto out;
2514 reply_openerror(req, status);
2515 goto out;
2518 break;
2521 if (i == 10) {
2522 /* Collision after 10 times... */
2523 reply_nterror(req, status);
2524 goto out;
2527 reply_outbuf(req, 1, 0);
2528 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2530 /* the returned filename is relative to the directory */
2531 s = strrchr_m(fsp->fsp_name->base_name, '/');
2532 if (!s) {
2533 s = fsp->fsp_name->base_name;
2534 } else {
2535 s++;
2538 #if 0
2539 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2540 thing in the byte section. JRA */
2541 SSVALS(p, 0, -1); /* what is this? not in spec */
2542 #endif
2543 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2544 == -1) {
2545 reply_nterror(req, NT_STATUS_NO_MEMORY);
2546 goto out;
2549 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2550 SCVAL(req->outbuf, smb_flg,
2551 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2554 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2555 SCVAL(req->outbuf, smb_flg,
2556 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2559 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2560 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2561 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2562 out:
2563 TALLOC_FREE(smb_fname);
2564 TALLOC_FREE(wire_name);
2565 END_PROFILE(SMBctemp);
2566 return;
2569 /*******************************************************************
2570 Check if a user is allowed to rename a file.
2571 ********************************************************************/
2573 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2574 uint16 dirtype)
2576 if (!CAN_WRITE(conn)) {
2577 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2580 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2581 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2582 /* Only bother to read the DOS attribute if we might deny the
2583 rename on the grounds of attribute missmatch. */
2584 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2585 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2586 return NT_STATUS_NO_SUCH_FILE;
2590 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2591 if (fsp->posix_open) {
2592 return NT_STATUS_OK;
2595 /* If no pathnames are open below this
2596 directory, allow the rename. */
2598 if (file_find_subpath(fsp)) {
2599 return NT_STATUS_ACCESS_DENIED;
2601 return NT_STATUS_OK;
2604 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2605 return NT_STATUS_OK;
2608 return NT_STATUS_ACCESS_DENIED;
2611 /*******************************************************************
2612 * unlink a file with all relevant access checks
2613 *******************************************************************/
2615 static NTSTATUS do_unlink(connection_struct *conn,
2616 struct smb_request *req,
2617 struct smb_filename *smb_fname,
2618 uint32 dirtype)
2620 uint32 fattr;
2621 files_struct *fsp;
2622 uint32 dirtype_orig = dirtype;
2623 NTSTATUS status;
2624 int ret;
2625 bool posix_paths = lp_posix_pathnames();
2627 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2628 smb_fname_str_dbg(smb_fname),
2629 dirtype));
2631 if (!CAN_WRITE(conn)) {
2632 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2635 if (posix_paths) {
2636 ret = SMB_VFS_LSTAT(conn, smb_fname);
2637 } else {
2638 ret = SMB_VFS_STAT(conn, smb_fname);
2640 if (ret != 0) {
2641 return map_nt_error_from_unix(errno);
2644 fattr = dos_mode(conn, smb_fname);
2646 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2647 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2650 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2651 if (!dirtype) {
2652 return NT_STATUS_NO_SUCH_FILE;
2655 if (!dir_check_ftype(conn, fattr, dirtype)) {
2656 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2657 return NT_STATUS_FILE_IS_A_DIRECTORY;
2659 return NT_STATUS_NO_SUCH_FILE;
2662 if (dirtype_orig & 0x8000) {
2663 /* These will never be set for POSIX. */
2664 return NT_STATUS_NO_SUCH_FILE;
2667 #if 0
2668 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2669 return NT_STATUS_FILE_IS_A_DIRECTORY;
2672 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2673 return NT_STATUS_NO_SUCH_FILE;
2676 if (dirtype & 0xFF00) {
2677 /* These will never be set for POSIX. */
2678 return NT_STATUS_NO_SUCH_FILE;
2681 dirtype &= 0xFF;
2682 if (!dirtype) {
2683 return NT_STATUS_NO_SUCH_FILE;
2686 /* Can't delete a directory. */
2687 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2688 return NT_STATUS_FILE_IS_A_DIRECTORY;
2690 #endif
2692 #if 0 /* JRATEST */
2693 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2694 return NT_STATUS_OBJECT_NAME_INVALID;
2695 #endif /* JRATEST */
2697 /* On open checks the open itself will check the share mode, so
2698 don't do it here as we'll get it wrong. */
2700 status = SMB_VFS_CREATE_FILE
2701 (conn, /* conn */
2702 req, /* req */
2703 0, /* root_dir_fid */
2704 smb_fname, /* fname */
2705 DELETE_ACCESS, /* access_mask */
2706 FILE_SHARE_NONE, /* share_access */
2707 FILE_OPEN, /* create_disposition*/
2708 FILE_NON_DIRECTORY_FILE, /* create_options */
2709 /* file_attributes */
2710 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2711 FILE_ATTRIBUTE_NORMAL,
2712 0, /* oplock_request */
2713 0, /* allocation_size */
2714 0, /* private_flags */
2715 NULL, /* sd */
2716 NULL, /* ea_list */
2717 &fsp, /* result */
2718 NULL); /* pinfo */
2720 if (!NT_STATUS_IS_OK(status)) {
2721 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2722 nt_errstr(status)));
2723 return status;
2726 status = can_set_delete_on_close(fsp, fattr);
2727 if (!NT_STATUS_IS_OK(status)) {
2728 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2729 "(%s)\n",
2730 smb_fname_str_dbg(smb_fname),
2731 nt_errstr(status)));
2732 close_file(req, fsp, NORMAL_CLOSE);
2733 return status;
2736 /* The set is across all open files on this dev/inode pair. */
2737 if (!set_delete_on_close(fsp, True,
2738 conn->session_info->security_token,
2739 conn->session_info->unix_token)) {
2740 close_file(req, fsp, NORMAL_CLOSE);
2741 return NT_STATUS_ACCESS_DENIED;
2744 return close_file(req, fsp, NORMAL_CLOSE);
2747 /****************************************************************************
2748 The guts of the unlink command, split out so it may be called by the NT SMB
2749 code.
2750 ****************************************************************************/
2752 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2753 uint32 dirtype, struct smb_filename *smb_fname,
2754 bool has_wild)
2756 char *fname_dir = NULL;
2757 char *fname_mask = NULL;
2758 int count=0;
2759 NTSTATUS status = NT_STATUS_OK;
2760 TALLOC_CTX *ctx = talloc_tos();
2762 /* Split up the directory from the filename/mask. */
2763 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2764 &fname_dir, &fname_mask);
2765 if (!NT_STATUS_IS_OK(status)) {
2766 goto out;
2770 * We should only check the mangled cache
2771 * here if unix_convert failed. This means
2772 * that the path in 'mask' doesn't exist
2773 * on the file system and so we need to look
2774 * for a possible mangle. This patch from
2775 * Tine Smukavec <valentin.smukavec@hermes.si>.
2778 if (!VALID_STAT(smb_fname->st) &&
2779 mangle_is_mangled(fname_mask, conn->params)) {
2780 char *new_mask = NULL;
2781 mangle_lookup_name_from_8_3(ctx, fname_mask,
2782 &new_mask, conn->params);
2783 if (new_mask) {
2784 TALLOC_FREE(fname_mask);
2785 fname_mask = new_mask;
2789 if (!has_wild) {
2792 * Only one file needs to be unlinked. Append the mask back
2793 * onto the directory.
2795 TALLOC_FREE(smb_fname->base_name);
2796 if (ISDOT(fname_dir)) {
2797 /* Ensure we use canonical names on open. */
2798 smb_fname->base_name = talloc_asprintf(smb_fname,
2799 "%s",
2800 fname_mask);
2801 } else {
2802 smb_fname->base_name = talloc_asprintf(smb_fname,
2803 "%s/%s",
2804 fname_dir,
2805 fname_mask);
2807 if (!smb_fname->base_name) {
2808 status = NT_STATUS_NO_MEMORY;
2809 goto out;
2811 if (dirtype == 0) {
2812 dirtype = FILE_ATTRIBUTE_NORMAL;
2815 status = check_name(conn, smb_fname->base_name);
2816 if (!NT_STATUS_IS_OK(status)) {
2817 goto out;
2820 status = do_unlink(conn, req, smb_fname, dirtype);
2821 if (!NT_STATUS_IS_OK(status)) {
2822 goto out;
2825 count++;
2826 } else {
2827 struct smb_Dir *dir_hnd = NULL;
2828 long offset = 0;
2829 const char *dname = NULL;
2830 char *talloced = NULL;
2832 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2833 status = NT_STATUS_OBJECT_NAME_INVALID;
2834 goto out;
2837 if (strequal(fname_mask,"????????.???")) {
2838 TALLOC_FREE(fname_mask);
2839 fname_mask = talloc_strdup(ctx, "*");
2840 if (!fname_mask) {
2841 status = NT_STATUS_NO_MEMORY;
2842 goto out;
2846 status = check_name(conn, fname_dir);
2847 if (!NT_STATUS_IS_OK(status)) {
2848 goto out;
2851 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2852 dirtype);
2853 if (dir_hnd == NULL) {
2854 status = map_nt_error_from_unix(errno);
2855 goto out;
2858 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2859 the pattern matches against the long name, otherwise the short name
2860 We don't implement this yet XXXX
2863 status = NT_STATUS_NO_SUCH_FILE;
2865 while ((dname = ReadDirName(dir_hnd, &offset,
2866 &smb_fname->st, &talloced))) {
2867 TALLOC_CTX *frame = talloc_stackframe();
2869 if (!is_visible_file(conn, fname_dir, dname,
2870 &smb_fname->st, true)) {
2871 TALLOC_FREE(frame);
2872 TALLOC_FREE(talloced);
2873 continue;
2876 /* Quick check for "." and ".." */
2877 if (ISDOT(dname) || ISDOTDOT(dname)) {
2878 TALLOC_FREE(frame);
2879 TALLOC_FREE(talloced);
2880 continue;
2883 if(!mask_match(dname, fname_mask,
2884 conn->case_sensitive)) {
2885 TALLOC_FREE(frame);
2886 TALLOC_FREE(talloced);
2887 continue;
2890 TALLOC_FREE(smb_fname->base_name);
2891 if (ISDOT(fname_dir)) {
2892 /* Ensure we use canonical names on open. */
2893 smb_fname->base_name =
2894 talloc_asprintf(smb_fname, "%s",
2895 dname);
2896 } else {
2897 smb_fname->base_name =
2898 talloc_asprintf(smb_fname, "%s/%s",
2899 fname_dir, dname);
2902 if (!smb_fname->base_name) {
2903 TALLOC_FREE(dir_hnd);
2904 status = NT_STATUS_NO_MEMORY;
2905 TALLOC_FREE(frame);
2906 TALLOC_FREE(talloced);
2907 goto out;
2910 status = check_name(conn, smb_fname->base_name);
2911 if (!NT_STATUS_IS_OK(status)) {
2912 TALLOC_FREE(dir_hnd);
2913 TALLOC_FREE(frame);
2914 TALLOC_FREE(talloced);
2915 goto out;
2918 status = do_unlink(conn, req, smb_fname, dirtype);
2919 if (!NT_STATUS_IS_OK(status)) {
2920 TALLOC_FREE(frame);
2921 TALLOC_FREE(talloced);
2922 continue;
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 NTSTATUS status;
3473 files_struct *fsp;
3474 struct byte_range_lock *br_lck = NULL;
3475 char *p = NULL;
3476 struct smbd_server_connection *sconn = req->sconn;
3478 START_PROFILE(SMBlockread);
3480 if (req->wct < 5) {
3481 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3482 END_PROFILE(SMBlockread);
3483 return;
3486 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3488 if (!check_fsp(conn, req, fsp)) {
3489 END_PROFILE(SMBlockread);
3490 return;
3493 if (!CHECK_READ(fsp,req)) {
3494 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3495 END_PROFILE(SMBlockread);
3496 return;
3499 numtoread = SVAL(req->vwv+1, 0);
3500 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3502 numtoread = MIN(BUFFER_SIZE - (smb_size + 5*2 + 3), numtoread);
3504 reply_outbuf(req, 5, numtoread + 3);
3506 data = smb_buf(req->outbuf) + 3;
3509 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3510 * protocol request that predates the read/write lock concept.
3511 * Thus instead of asking for a read lock here we need to ask
3512 * for a write lock. JRA.
3513 * Note that the requested lock size is unaffected by max_recv.
3516 br_lck = do_lock(req->sconn->msg_ctx,
3517 fsp,
3518 (uint64_t)req->smbpid,
3519 (uint64_t)numtoread,
3520 (uint64_t)startpos,
3521 WRITE_LOCK,
3522 WINDOWS_LOCK,
3523 False, /* Non-blocking lock. */
3524 &status,
3525 NULL,
3526 NULL);
3527 TALLOC_FREE(br_lck);
3529 if (NT_STATUS_V(status)) {
3530 reply_nterror(req, status);
3531 END_PROFILE(SMBlockread);
3532 return;
3536 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3539 if (numtoread > sconn->smb1.negprot.max_recv) {
3540 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3541 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3542 (unsigned int)numtoread,
3543 (unsigned int)sconn->smb1.negprot.max_recv));
3544 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3546 nread = read_file(fsp,data,startpos,numtoread);
3548 if (nread < 0) {
3549 reply_nterror(req, map_nt_error_from_unix(errno));
3550 END_PROFILE(SMBlockread);
3551 return;
3554 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3556 SSVAL(req->outbuf,smb_vwv0,nread);
3557 SSVAL(req->outbuf,smb_vwv5,nread+3);
3558 p = smb_buf(req->outbuf);
3559 SCVAL(p,0,0); /* pad byte. */
3560 SSVAL(p,1,nread);
3562 DEBUG(3,("lockread %s num=%d nread=%d\n",
3563 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3565 END_PROFILE(SMBlockread);
3566 return;
3569 #undef DBGC_CLASS
3570 #define DBGC_CLASS DBGC_ALL
3572 /****************************************************************************
3573 Reply to a read.
3574 ****************************************************************************/
3576 void reply_read(struct smb_request *req)
3578 connection_struct *conn = req->conn;
3579 size_t numtoread;
3580 ssize_t nread = 0;
3581 char *data;
3582 off_t startpos;
3583 int outsize = 0;
3584 files_struct *fsp;
3585 struct lock_struct lock;
3586 struct smbd_server_connection *sconn = req->sconn;
3588 START_PROFILE(SMBread);
3590 if (req->wct < 3) {
3591 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3592 END_PROFILE(SMBread);
3593 return;
3596 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3598 if (!check_fsp(conn, req, fsp)) {
3599 END_PROFILE(SMBread);
3600 return;
3603 if (!CHECK_READ(fsp,req)) {
3604 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3605 END_PROFILE(SMBread);
3606 return;
3609 numtoread = SVAL(req->vwv+1, 0);
3610 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3612 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3615 * The requested read size cannot be greater than max_recv. JRA.
3617 if (numtoread > sconn->smb1.negprot.max_recv) {
3618 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3619 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3620 (unsigned int)numtoread,
3621 (unsigned int)sconn->smb1.negprot.max_recv));
3622 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3625 reply_outbuf(req, 5, numtoread+3);
3627 data = smb_buf(req->outbuf) + 3;
3629 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3630 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3631 &lock);
3633 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3634 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3635 END_PROFILE(SMBread);
3636 return;
3639 if (numtoread > 0)
3640 nread = read_file(fsp,data,startpos,numtoread);
3642 if (nread < 0) {
3643 reply_nterror(req, map_nt_error_from_unix(errno));
3644 goto strict_unlock;
3647 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3649 SSVAL(req->outbuf,smb_vwv0,nread);
3650 SSVAL(req->outbuf,smb_vwv5,nread+3);
3651 SCVAL(smb_buf(req->outbuf),0,1);
3652 SSVAL(smb_buf(req->outbuf),1,nread);
3654 DEBUG(3, ("read %s num=%d nread=%d\n",
3655 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3657 strict_unlock:
3658 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3660 END_PROFILE(SMBread);
3661 return;
3664 /****************************************************************************
3665 Setup readX header.
3666 ****************************************************************************/
3668 static int setup_readX_header(struct smb_request *req, char *outbuf,
3669 size_t smb_maxcnt)
3671 int outsize;
3673 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3675 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3677 SCVAL(outbuf,smb_vwv0,0xFF);
3678 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3679 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3680 SSVAL(outbuf,smb_vwv6,
3681 (smb_wct - 4) /* offset from smb header to wct */
3682 + 1 /* the wct field */
3683 + 12 * sizeof(uint16_t) /* vwv */
3684 + 2); /* the buflen field */
3685 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3686 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3687 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3688 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3689 return outsize;
3692 /****************************************************************************
3693 Reply to a read and X - possibly using sendfile.
3694 ****************************************************************************/
3696 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3697 files_struct *fsp, off_t startpos,
3698 size_t smb_maxcnt)
3700 ssize_t nread = -1;
3701 struct lock_struct lock;
3702 int saved_errno = 0;
3704 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3705 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3706 &lock);
3708 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3709 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3710 return;
3714 * We can only use sendfile on a non-chained packet
3715 * but we can use on a non-oplocked file. tridge proved this
3716 * on a train in Germany :-). JRA.
3719 if (!req_is_in_chain(req) &&
3720 !req->encrypted &&
3721 (fsp->base_fsp == NULL) &&
3722 (fsp->wcp == NULL) &&
3723 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3724 uint8 headerbuf[smb_size + 12 * 2];
3725 DATA_BLOB header;
3727 if(fsp_stat(fsp) == -1) {
3728 reply_nterror(req, map_nt_error_from_unix(errno));
3729 goto strict_unlock;
3732 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3733 (startpos > fsp->fsp_name->st.st_ex_size) ||
3734 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3736 * We already know that we would do a short read, so don't
3737 * try the sendfile() path.
3739 goto nosendfile_read;
3743 * Set up the packet header before send. We
3744 * assume here the sendfile will work (get the
3745 * correct amount of data).
3748 header = data_blob_const(headerbuf, sizeof(headerbuf));
3750 construct_reply_common_req(req, (char *)headerbuf);
3751 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3753 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3754 startpos, smb_maxcnt);
3755 if (nread == -1) {
3756 /* Returning ENOSYS means no data at all was sent.
3757 Do this as a normal read. */
3758 if (errno == ENOSYS) {
3759 goto normal_read;
3763 * Special hack for broken Linux with no working sendfile. If we
3764 * return EINTR we sent the header but not the rest of the data.
3765 * Fake this up by doing read/write calls.
3768 if (errno == EINTR) {
3769 /* Ensure we don't do this again. */
3770 set_use_sendfile(SNUM(conn), False);
3771 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3772 nread = fake_sendfile(fsp, startpos,
3773 smb_maxcnt);
3774 if (nread == -1) {
3775 DEBUG(0,("send_file_readX: "
3776 "fake_sendfile failed for "
3777 "file %s (%s).\n",
3778 fsp_str_dbg(fsp),
3779 strerror(errno)));
3780 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3782 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3783 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3784 /* No outbuf here means successful sendfile. */
3785 goto strict_unlock;
3788 DEBUG(0,("send_file_readX: sendfile failed for file "
3789 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3790 strerror(errno)));
3791 exit_server_cleanly("send_file_readX sendfile failed");
3792 } else if (nread == 0) {
3794 * Some sendfile implementations return 0 to indicate
3795 * that there was a short read, but nothing was
3796 * actually written to the socket. In this case,
3797 * fallback to the normal read path so the header gets
3798 * the correct byte count.
3800 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3801 "falling back to the normal read: %s\n",
3802 fsp_str_dbg(fsp)));
3803 goto normal_read;
3806 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3807 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3809 /* Deal with possible short send. */
3810 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3811 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3813 /* No outbuf here means successful sendfile. */
3814 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3815 SMB_PERFCOUNT_END(&req->pcd);
3816 goto strict_unlock;
3819 normal_read:
3821 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3822 uint8 headerbuf[smb_size + 2*12];
3824 construct_reply_common_req(req, (char *)headerbuf);
3825 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3827 /* Send out the header. */
3828 if (write_data(req->sconn->sock, (char *)headerbuf,
3829 sizeof(headerbuf)) != sizeof(headerbuf)) {
3831 char addr[INET6_ADDRSTRLEN];
3833 * Try and give an error message saying what
3834 * client failed.
3836 DEBUG(0, ("write_data failed for client %s. "
3837 "Error %s\n",
3838 get_peer_addr(req->sconn->sock, addr,
3839 sizeof(addr)),
3840 strerror(errno)));
3842 DEBUG(0,("send_file_readX: write_data failed for file "
3843 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3844 strerror(errno)));
3845 exit_server_cleanly("send_file_readX sendfile failed");
3847 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3848 if (nread == -1) {
3849 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3850 "file %s (%s).\n", fsp_str_dbg(fsp),
3851 strerror(errno)));
3852 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3854 goto strict_unlock;
3857 nosendfile_read:
3859 reply_outbuf(req, 12, smb_maxcnt);
3860 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3861 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3863 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3864 saved_errno = errno;
3866 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3868 if (nread < 0) {
3869 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3870 return;
3873 setup_readX_header(req, (char *)req->outbuf, nread);
3875 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3876 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3877 return;
3879 strict_unlock:
3880 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3881 TALLOC_FREE(req->outbuf);
3882 return;
3885 /****************************************************************************
3886 Work out how much space we have for a read return.
3887 ****************************************************************************/
3889 static size_t calc_max_read_pdu(const struct smb_request *req)
3891 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3892 return req->sconn->smb1.sessions.max_send;
3895 if (!lp_large_readwrite()) {
3896 return req->sconn->smb1.sessions.max_send;
3899 if (req_is_in_chain(req)) {
3900 return req->sconn->smb1.sessions.max_send;
3903 if (req->encrypted) {
3905 * Don't take encrypted traffic up to the
3906 * limit. There are padding considerations
3907 * that make that tricky.
3909 return req->sconn->smb1.sessions.max_send;
3912 if (srv_is_signing_active(req->sconn)) {
3913 return 0x1FFFF;
3916 if (!lp_unix_extensions()) {
3917 return 0x1FFFF;
3921 * We can do ultra-large POSIX reads.
3923 return 0xFFFFFF;
3926 /****************************************************************************
3927 Calculate how big a read can be. Copes with all clients. It's always
3928 safe to return a short read - Windows does this.
3929 ****************************************************************************/
3931 static size_t calc_read_size(const struct smb_request *req,
3932 size_t upper_size,
3933 size_t lower_size)
3935 size_t max_pdu = calc_max_read_pdu(req);
3936 size_t total_size = 0;
3937 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3938 size_t max_len = max_pdu - hdr_len;
3941 * Windows explicitly ignores upper size of 0xFFFF.
3942 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3943 * We must do the same as these will never fit even in
3944 * an extended size NetBIOS packet.
3946 if (upper_size == 0xFFFF) {
3947 upper_size = 0;
3950 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3951 upper_size = 0;
3954 total_size = ((upper_size<<16) | lower_size);
3957 * LARGE_READX test shows it's always safe to return
3958 * a short read. Windows does so.
3960 return MIN(total_size, max_len);
3963 /****************************************************************************
3964 Reply to a read and X.
3965 ****************************************************************************/
3967 void reply_read_and_X(struct smb_request *req)
3969 connection_struct *conn = req->conn;
3970 files_struct *fsp;
3971 off_t startpos;
3972 size_t smb_maxcnt;
3973 size_t upper_size;
3974 bool big_readX = False;
3975 #if 0
3976 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3977 #endif
3979 START_PROFILE(SMBreadX);
3981 if ((req->wct != 10) && (req->wct != 12)) {
3982 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3983 return;
3986 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3987 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3988 smb_maxcnt = SVAL(req->vwv+5, 0);
3990 /* If it's an IPC, pass off the pipe handler. */
3991 if (IS_IPC(conn)) {
3992 reply_pipe_read_and_X(req);
3993 END_PROFILE(SMBreadX);
3994 return;
3997 if (!check_fsp(conn, req, fsp)) {
3998 END_PROFILE(SMBreadX);
3999 return;
4002 if (!CHECK_READ(fsp,req)) {
4003 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4004 END_PROFILE(SMBreadX);
4005 return;
4008 upper_size = SVAL(req->vwv+7, 0);
4009 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4010 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4012 * This is a heuristic to avoid keeping large
4013 * outgoing buffers around over long-lived aio
4014 * requests.
4016 big_readX = True;
4019 if (req->wct == 12) {
4021 * This is a large offset (64 bit) read.
4023 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4027 if (!big_readX) {
4028 NTSTATUS status = schedule_aio_read_and_X(conn,
4029 req,
4030 fsp,
4031 startpos,
4032 smb_maxcnt);
4033 if (NT_STATUS_IS_OK(status)) {
4034 /* Read scheduled - we're done. */
4035 goto out;
4037 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4038 /* Real error - report to client. */
4039 END_PROFILE(SMBreadX);
4040 reply_nterror(req, status);
4041 return;
4043 /* NT_STATUS_RETRY - fall back to sync read. */
4046 smbd_lock_socket(req->sconn);
4047 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4048 smbd_unlock_socket(req->sconn);
4050 out:
4051 END_PROFILE(SMBreadX);
4052 return;
4055 /****************************************************************************
4056 Error replies to writebraw must have smb_wct == 1. Fix this up.
4057 ****************************************************************************/
4059 void error_to_writebrawerr(struct smb_request *req)
4061 uint8 *old_outbuf = req->outbuf;
4063 reply_outbuf(req, 1, 0);
4065 memcpy(req->outbuf, old_outbuf, smb_size);
4066 TALLOC_FREE(old_outbuf);
4069 /****************************************************************************
4070 Read 4 bytes of a smb packet and return the smb length of the packet.
4071 Store the result in the buffer. This version of the function will
4072 never return a session keepalive (length of zero).
4073 Timeout is in milliseconds.
4074 ****************************************************************************/
4076 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4077 size_t *len)
4079 uint8_t msgtype = NBSSkeepalive;
4081 while (msgtype == NBSSkeepalive) {
4082 NTSTATUS status;
4084 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4085 len);
4086 if (!NT_STATUS_IS_OK(status)) {
4087 char addr[INET6_ADDRSTRLEN];
4088 /* Try and give an error message
4089 * saying what client failed. */
4090 DEBUG(0, ("read_fd_with_timeout failed for "
4091 "client %s read error = %s.\n",
4092 get_peer_addr(fd,addr,sizeof(addr)),
4093 nt_errstr(status)));
4094 return status;
4097 msgtype = CVAL(inbuf, 0);
4100 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4101 (unsigned long)len));
4103 return NT_STATUS_OK;
4106 /****************************************************************************
4107 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4108 ****************************************************************************/
4110 void reply_writebraw(struct smb_request *req)
4112 connection_struct *conn = req->conn;
4113 char *buf = NULL;
4114 ssize_t nwritten=0;
4115 ssize_t total_written=0;
4116 size_t numtowrite=0;
4117 size_t tcount;
4118 off_t startpos;
4119 const char *data=NULL;
4120 bool write_through;
4121 files_struct *fsp;
4122 struct lock_struct lock;
4123 NTSTATUS status;
4125 START_PROFILE(SMBwritebraw);
4128 * If we ever reply with an error, it must have the SMB command
4129 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4130 * we're finished.
4132 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4134 if (srv_is_signing_active(req->sconn)) {
4135 END_PROFILE(SMBwritebraw);
4136 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4137 "raw reads/writes are disallowed.");
4140 if (req->wct < 12) {
4141 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4142 error_to_writebrawerr(req);
4143 END_PROFILE(SMBwritebraw);
4144 return;
4147 if (req->sconn->smb1.echo_handler.trusted_fde) {
4148 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4149 "'async smb echo handler = yes'\n"));
4150 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4151 error_to_writebrawerr(req);
4152 END_PROFILE(SMBwritebraw);
4153 return;
4156 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4157 if (!check_fsp(conn, req, fsp)) {
4158 error_to_writebrawerr(req);
4159 END_PROFILE(SMBwritebraw);
4160 return;
4163 if (!CHECK_WRITE(fsp)) {
4164 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4165 error_to_writebrawerr(req);
4166 END_PROFILE(SMBwritebraw);
4167 return;
4170 tcount = IVAL(req->vwv+1, 0);
4171 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4172 write_through = BITSETW(req->vwv+7,0);
4174 /* We have to deal with slightly different formats depending
4175 on whether we are using the core+ or lanman1.0 protocol */
4177 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4178 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4179 data = smb_buf_const(req->inbuf);
4180 } else {
4181 numtowrite = SVAL(req->vwv+10, 0);
4182 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4185 /* Ensure we don't write bytes past the end of this packet. */
4186 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4187 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4188 error_to_writebrawerr(req);
4189 END_PROFILE(SMBwritebraw);
4190 return;
4193 if (!fsp->print_file) {
4194 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4195 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4196 &lock);
4198 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4199 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4200 error_to_writebrawerr(req);
4201 END_PROFILE(SMBwritebraw);
4202 return;
4206 if (numtowrite>0) {
4207 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4210 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4211 "wrote=%d sync=%d\n",
4212 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4213 (int)nwritten, (int)write_through));
4215 if (nwritten < (ssize_t)numtowrite) {
4216 reply_nterror(req, NT_STATUS_DISK_FULL);
4217 error_to_writebrawerr(req);
4218 goto strict_unlock;
4221 total_written = nwritten;
4223 /* Allocate a buffer of 64k + length. */
4224 buf = talloc_array(NULL, char, 65540);
4225 if (!buf) {
4226 reply_nterror(req, NT_STATUS_NO_MEMORY);
4227 error_to_writebrawerr(req);
4228 goto strict_unlock;
4231 /* Return a SMBwritebraw message to the redirector to tell
4232 * it to send more bytes */
4234 memcpy(buf, req->inbuf, smb_size);
4235 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4236 SCVAL(buf,smb_com,SMBwritebraw);
4237 SSVALS(buf,smb_vwv0,0xFFFF);
4238 show_msg(buf);
4239 if (!srv_send_smb(req->sconn,
4240 buf,
4241 false, 0, /* no signing */
4242 IS_CONN_ENCRYPTED(conn),
4243 &req->pcd)) {
4244 exit_server_cleanly("reply_writebraw: srv_send_smb "
4245 "failed.");
4248 /* Now read the raw data into the buffer and write it */
4249 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4250 &numtowrite);
4251 if (!NT_STATUS_IS_OK(status)) {
4252 exit_server_cleanly("secondary writebraw failed");
4255 /* Set up outbuf to return the correct size */
4256 reply_outbuf(req, 1, 0);
4258 if (numtowrite != 0) {
4260 if (numtowrite > 0xFFFF) {
4261 DEBUG(0,("reply_writebraw: Oversize secondary write "
4262 "raw requested (%u). Terminating\n",
4263 (unsigned int)numtowrite ));
4264 exit_server_cleanly("secondary writebraw failed");
4267 if (tcount > nwritten+numtowrite) {
4268 DEBUG(3,("reply_writebraw: Client overestimated the "
4269 "write %d %d %d\n",
4270 (int)tcount,(int)nwritten,(int)numtowrite));
4273 status = read_data(req->sconn->sock, buf+4, numtowrite);
4275 if (!NT_STATUS_IS_OK(status)) {
4276 char addr[INET6_ADDRSTRLEN];
4277 /* Try and give an error message
4278 * saying what client failed. */
4279 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4280 "raw read failed (%s) for client %s. "
4281 "Terminating\n", nt_errstr(status),
4282 get_peer_addr(req->sconn->sock, addr,
4283 sizeof(addr))));
4284 exit_server_cleanly("secondary writebraw failed");
4287 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4288 if (nwritten == -1) {
4289 TALLOC_FREE(buf);
4290 reply_nterror(req, map_nt_error_from_unix(errno));
4291 error_to_writebrawerr(req);
4292 goto strict_unlock;
4295 if (nwritten < (ssize_t)numtowrite) {
4296 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4297 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4300 if (nwritten > 0) {
4301 total_written += nwritten;
4305 TALLOC_FREE(buf);
4306 SSVAL(req->outbuf,smb_vwv0,total_written);
4308 status = sync_file(conn, fsp, write_through);
4309 if (!NT_STATUS_IS_OK(status)) {
4310 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4311 fsp_str_dbg(fsp), nt_errstr(status)));
4312 reply_nterror(req, status);
4313 error_to_writebrawerr(req);
4314 goto strict_unlock;
4317 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4318 "wrote=%d\n",
4319 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4320 (int)total_written));
4322 if (!fsp->print_file) {
4323 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4326 /* We won't return a status if write through is not selected - this
4327 * follows what WfWg does */
4328 END_PROFILE(SMBwritebraw);
4330 if (!write_through && total_written==tcount) {
4332 #if RABBIT_PELLET_FIX
4334 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4335 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4336 * JRA.
4338 if (!send_keepalive(req->sconn->sock)) {
4339 exit_server_cleanly("reply_writebraw: send of "
4340 "keepalive failed");
4342 #endif
4343 TALLOC_FREE(req->outbuf);
4345 return;
4347 strict_unlock:
4348 if (!fsp->print_file) {
4349 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4352 END_PROFILE(SMBwritebraw);
4353 return;
4356 #undef DBGC_CLASS
4357 #define DBGC_CLASS DBGC_LOCKING
4359 /****************************************************************************
4360 Reply to a writeunlock (core+).
4361 ****************************************************************************/
4363 void reply_writeunlock(struct smb_request *req)
4365 connection_struct *conn = req->conn;
4366 ssize_t nwritten = -1;
4367 size_t numtowrite;
4368 off_t startpos;
4369 const char *data;
4370 NTSTATUS status = NT_STATUS_OK;
4371 files_struct *fsp;
4372 struct lock_struct lock;
4373 int saved_errno = 0;
4375 START_PROFILE(SMBwriteunlock);
4377 if (req->wct < 5) {
4378 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4379 END_PROFILE(SMBwriteunlock);
4380 return;
4383 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4385 if (!check_fsp(conn, req, fsp)) {
4386 END_PROFILE(SMBwriteunlock);
4387 return;
4390 if (!CHECK_WRITE(fsp)) {
4391 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4392 END_PROFILE(SMBwriteunlock);
4393 return;
4396 numtowrite = SVAL(req->vwv+1, 0);
4397 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4398 data = (const char *)req->buf + 3;
4400 if (!fsp->print_file && numtowrite > 0) {
4401 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4402 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4403 &lock);
4405 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4406 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4407 END_PROFILE(SMBwriteunlock);
4408 return;
4412 /* The special X/Open SMB protocol handling of
4413 zero length writes is *NOT* done for
4414 this call */
4415 if(numtowrite == 0) {
4416 nwritten = 0;
4417 } else {
4418 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4419 saved_errno = errno;
4422 status = sync_file(conn, fsp, False /* write through */);
4423 if (!NT_STATUS_IS_OK(status)) {
4424 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4425 fsp_str_dbg(fsp), nt_errstr(status)));
4426 reply_nterror(req, status);
4427 goto strict_unlock;
4430 if(nwritten < 0) {
4431 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4432 goto strict_unlock;
4435 if((nwritten < numtowrite) && (numtowrite != 0)) {
4436 reply_nterror(req, NT_STATUS_DISK_FULL);
4437 goto strict_unlock;
4440 if (numtowrite && !fsp->print_file) {
4441 status = do_unlock(req->sconn->msg_ctx,
4442 fsp,
4443 (uint64_t)req->smbpid,
4444 (uint64_t)numtowrite,
4445 (uint64_t)startpos,
4446 WINDOWS_LOCK);
4448 if (NT_STATUS_V(status)) {
4449 reply_nterror(req, status);
4450 goto strict_unlock;
4454 reply_outbuf(req, 1, 0);
4456 SSVAL(req->outbuf,smb_vwv0,nwritten);
4458 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4459 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4461 strict_unlock:
4462 if (numtowrite && !fsp->print_file) {
4463 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4466 END_PROFILE(SMBwriteunlock);
4467 return;
4470 #undef DBGC_CLASS
4471 #define DBGC_CLASS DBGC_ALL
4473 /****************************************************************************
4474 Reply to a write.
4475 ****************************************************************************/
4477 void reply_write(struct smb_request *req)
4479 connection_struct *conn = req->conn;
4480 size_t numtowrite;
4481 ssize_t nwritten = -1;
4482 off_t startpos;
4483 const char *data;
4484 files_struct *fsp;
4485 struct lock_struct lock;
4486 NTSTATUS status;
4487 int saved_errno = 0;
4489 START_PROFILE(SMBwrite);
4491 if (req->wct < 5) {
4492 END_PROFILE(SMBwrite);
4493 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4494 return;
4497 /* If it's an IPC, pass off the pipe handler. */
4498 if (IS_IPC(conn)) {
4499 reply_pipe_write(req);
4500 END_PROFILE(SMBwrite);
4501 return;
4504 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4506 if (!check_fsp(conn, req, fsp)) {
4507 END_PROFILE(SMBwrite);
4508 return;
4511 if (!CHECK_WRITE(fsp)) {
4512 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4513 END_PROFILE(SMBwrite);
4514 return;
4517 numtowrite = SVAL(req->vwv+1, 0);
4518 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4519 data = (const char *)req->buf + 3;
4521 if (!fsp->print_file) {
4522 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4523 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4524 &lock);
4526 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4527 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4528 END_PROFILE(SMBwrite);
4529 return;
4534 * X/Open SMB protocol says that if smb_vwv1 is
4535 * zero then the file size should be extended or
4536 * truncated to the size given in smb_vwv[2-3].
4539 if(numtowrite == 0) {
4541 * This is actually an allocate call, and set EOF. JRA.
4543 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4544 if (nwritten < 0) {
4545 reply_nterror(req, NT_STATUS_DISK_FULL);
4546 goto strict_unlock;
4548 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4549 if (nwritten < 0) {
4550 reply_nterror(req, NT_STATUS_DISK_FULL);
4551 goto strict_unlock;
4553 trigger_write_time_update_immediate(fsp);
4554 } else {
4555 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4558 status = sync_file(conn, fsp, False);
4559 if (!NT_STATUS_IS_OK(status)) {
4560 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4561 fsp_str_dbg(fsp), nt_errstr(status)));
4562 reply_nterror(req, status);
4563 goto strict_unlock;
4566 if(nwritten < 0) {
4567 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4568 goto strict_unlock;
4571 if((nwritten == 0) && (numtowrite != 0)) {
4572 reply_nterror(req, NT_STATUS_DISK_FULL);
4573 goto strict_unlock;
4576 reply_outbuf(req, 1, 0);
4578 SSVAL(req->outbuf,smb_vwv0,nwritten);
4580 if (nwritten < (ssize_t)numtowrite) {
4581 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4582 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4585 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4587 strict_unlock:
4588 if (!fsp->print_file) {
4589 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4592 END_PROFILE(SMBwrite);
4593 return;
4596 /****************************************************************************
4597 Ensure a buffer is a valid writeX for recvfile purposes.
4598 ****************************************************************************/
4600 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4601 (2*14) + /* word count (including bcc) */ \
4602 1 /* pad byte */)
4604 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4605 const uint8_t *inbuf)
4607 size_t numtowrite;
4608 connection_struct *conn = NULL;
4609 unsigned int doff = 0;
4610 size_t len = smb_len_large(inbuf);
4611 struct smbXsrv_tcon *tcon;
4612 NTSTATUS status;
4613 NTTIME now = 0;
4615 if (is_encrypted_packet(sconn, inbuf)) {
4616 /* Can't do this on encrypted
4617 * connections. */
4618 return false;
4621 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4622 return false;
4625 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4626 CVAL(inbuf,smb_wct) != 14) {
4627 DEBUG(10,("is_valid_writeX_buffer: chained or "
4628 "invalid word length.\n"));
4629 return false;
4632 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4633 now, &tcon);
4634 if (!NT_STATUS_IS_OK(status)) {
4635 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4636 return false;
4638 conn = tcon->compat;
4640 if (IS_IPC(conn)) {
4641 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4642 return false;
4644 if (IS_PRINT(conn)) {
4645 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4646 return false;
4648 doff = SVAL(inbuf,smb_vwv11);
4650 numtowrite = SVAL(inbuf,smb_vwv10);
4652 if (len > doff && len - doff > 0xFFFF) {
4653 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4656 if (numtowrite == 0) {
4657 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4658 return false;
4661 /* Ensure the sizes match up. */
4662 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4663 /* no pad byte...old smbclient :-( */
4664 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4665 (unsigned int)doff,
4666 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4667 return false;
4670 if (len - doff != numtowrite) {
4671 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4672 "len = %u, doff = %u, numtowrite = %u\n",
4673 (unsigned int)len,
4674 (unsigned int)doff,
4675 (unsigned int)numtowrite ));
4676 return false;
4679 DEBUG(10,("is_valid_writeX_buffer: true "
4680 "len = %u, doff = %u, numtowrite = %u\n",
4681 (unsigned int)len,
4682 (unsigned int)doff,
4683 (unsigned int)numtowrite ));
4685 return true;
4688 /****************************************************************************
4689 Reply to a write and X.
4690 ****************************************************************************/
4692 void reply_write_and_X(struct smb_request *req)
4694 connection_struct *conn = req->conn;
4695 files_struct *fsp;
4696 struct lock_struct lock;
4697 off_t startpos;
4698 size_t numtowrite;
4699 bool write_through;
4700 ssize_t nwritten;
4701 unsigned int smb_doff;
4702 unsigned int smblen;
4703 const char *data;
4704 NTSTATUS status;
4705 int saved_errno = 0;
4707 START_PROFILE(SMBwriteX);
4709 if ((req->wct != 12) && (req->wct != 14)) {
4710 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4711 goto out;
4714 numtowrite = SVAL(req->vwv+10, 0);
4715 smb_doff = SVAL(req->vwv+11, 0);
4716 smblen = smb_len(req->inbuf);
4718 if (req->unread_bytes > 0xFFFF ||
4719 (smblen > smb_doff &&
4720 smblen - smb_doff > 0xFFFF)) {
4721 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4724 if (req->unread_bytes) {
4725 /* Can't do a recvfile write on IPC$ */
4726 if (IS_IPC(conn)) {
4727 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4728 goto out;
4730 if (numtowrite != req->unread_bytes) {
4731 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4732 goto out;
4734 } else {
4735 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4736 smb_doff + numtowrite > smblen) {
4737 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4738 goto out;
4742 /* If it's an IPC, pass off the pipe handler. */
4743 if (IS_IPC(conn)) {
4744 if (req->unread_bytes) {
4745 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4746 goto out;
4748 reply_pipe_write_and_X(req);
4749 goto out;
4752 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4753 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4754 write_through = BITSETW(req->vwv+7,0);
4756 if (!check_fsp(conn, req, fsp)) {
4757 goto out;
4760 if (!CHECK_WRITE(fsp)) {
4761 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4762 goto out;
4765 data = smb_base(req->inbuf) + smb_doff;
4767 if(req->wct == 14) {
4769 * This is a large offset (64 bit) write.
4771 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4775 /* X/Open SMB protocol says that, unlike SMBwrite
4776 if the length is zero then NO truncation is
4777 done, just a write of zero. To truncate a file,
4778 use SMBwrite. */
4780 if(numtowrite == 0) {
4781 nwritten = 0;
4782 } else {
4783 if (req->unread_bytes == 0) {
4784 status = schedule_aio_write_and_X(conn,
4785 req,
4786 fsp,
4787 data,
4788 startpos,
4789 numtowrite);
4791 if (NT_STATUS_IS_OK(status)) {
4792 /* write scheduled - we're done. */
4793 goto out;
4795 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4796 /* Real error - report to client. */
4797 reply_nterror(req, status);
4798 goto out;
4800 /* NT_STATUS_RETRY - fall through to sync write. */
4803 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4804 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4805 &lock);
4807 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4808 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4809 goto out;
4812 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4813 saved_errno = errno;
4815 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4818 if(nwritten < 0) {
4819 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4820 goto out;
4823 if((nwritten == 0) && (numtowrite != 0)) {
4824 reply_nterror(req, NT_STATUS_DISK_FULL);
4825 goto out;
4828 reply_outbuf(req, 6, 0);
4829 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4830 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4831 SSVAL(req->outbuf,smb_vwv2,nwritten);
4832 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4834 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4835 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4837 status = sync_file(conn, fsp, write_through);
4838 if (!NT_STATUS_IS_OK(status)) {
4839 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4840 fsp_str_dbg(fsp), nt_errstr(status)));
4841 reply_nterror(req, status);
4842 goto out;
4845 END_PROFILE(SMBwriteX);
4846 return;
4848 out:
4849 if (req->unread_bytes) {
4850 /* writeX failed. drain socket. */
4851 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4852 req->unread_bytes) {
4853 smb_panic("failed to drain pending bytes");
4855 req->unread_bytes = 0;
4858 END_PROFILE(SMBwriteX);
4859 return;
4862 /****************************************************************************
4863 Reply to a lseek.
4864 ****************************************************************************/
4866 void reply_lseek(struct smb_request *req)
4868 connection_struct *conn = req->conn;
4869 off_t startpos;
4870 off_t res= -1;
4871 int mode,umode;
4872 files_struct *fsp;
4874 START_PROFILE(SMBlseek);
4876 if (req->wct < 4) {
4877 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4878 END_PROFILE(SMBlseek);
4879 return;
4882 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4884 if (!check_fsp(conn, req, fsp)) {
4885 return;
4888 flush_write_cache(fsp, SEEK_FLUSH);
4890 mode = SVAL(req->vwv+1, 0) & 3;
4891 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4892 startpos = (off_t)IVALS(req->vwv+2, 0);
4894 switch (mode) {
4895 case 0:
4896 umode = SEEK_SET;
4897 res = startpos;
4898 break;
4899 case 1:
4900 umode = SEEK_CUR;
4901 res = fsp->fh->pos + startpos;
4902 break;
4903 case 2:
4904 umode = SEEK_END;
4905 break;
4906 default:
4907 umode = SEEK_SET;
4908 res = startpos;
4909 break;
4912 if (umode == SEEK_END) {
4913 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4914 if(errno == EINVAL) {
4915 off_t current_pos = startpos;
4917 if(fsp_stat(fsp) == -1) {
4918 reply_nterror(req,
4919 map_nt_error_from_unix(errno));
4920 END_PROFILE(SMBlseek);
4921 return;
4924 current_pos += fsp->fsp_name->st.st_ex_size;
4925 if(current_pos < 0)
4926 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4930 if(res == -1) {
4931 reply_nterror(req, map_nt_error_from_unix(errno));
4932 END_PROFILE(SMBlseek);
4933 return;
4937 fsp->fh->pos = res;
4939 reply_outbuf(req, 2, 0);
4940 SIVAL(req->outbuf,smb_vwv0,res);
4942 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4943 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4945 END_PROFILE(SMBlseek);
4946 return;
4949 /****************************************************************************
4950 Reply to a flush.
4951 ****************************************************************************/
4953 void reply_flush(struct smb_request *req)
4955 connection_struct *conn = req->conn;
4956 uint16 fnum;
4957 files_struct *fsp;
4959 START_PROFILE(SMBflush);
4961 if (req->wct < 1) {
4962 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4963 return;
4966 fnum = SVAL(req->vwv+0, 0);
4967 fsp = file_fsp(req, fnum);
4969 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4970 return;
4973 if (!fsp) {
4974 file_sync_all(conn);
4975 } else {
4976 NTSTATUS status = sync_file(conn, fsp, True);
4977 if (!NT_STATUS_IS_OK(status)) {
4978 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4979 fsp_str_dbg(fsp), nt_errstr(status)));
4980 reply_nterror(req, status);
4981 END_PROFILE(SMBflush);
4982 return;
4986 reply_outbuf(req, 0, 0);
4988 DEBUG(3,("flush\n"));
4989 END_PROFILE(SMBflush);
4990 return;
4993 /****************************************************************************
4994 Reply to a exit.
4995 conn POINTER CAN BE NULL HERE !
4996 ****************************************************************************/
4998 void reply_exit(struct smb_request *req)
5000 START_PROFILE(SMBexit);
5002 file_close_pid(req->sconn, req->smbpid, req->vuid);
5004 reply_outbuf(req, 0, 0);
5006 DEBUG(3,("exit\n"));
5008 END_PROFILE(SMBexit);
5009 return;
5012 struct reply_close_state {
5013 files_struct *fsp;
5014 struct smb_request *smbreq;
5017 static void do_smb1_close(struct tevent_req *req);
5019 void reply_close(struct smb_request *req)
5021 connection_struct *conn = req->conn;
5022 NTSTATUS status = NT_STATUS_OK;
5023 files_struct *fsp = NULL;
5024 START_PROFILE(SMBclose);
5026 if (req->wct < 3) {
5027 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5028 END_PROFILE(SMBclose);
5029 return;
5032 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5035 * We can only use check_fsp if we know it's not a directory.
5038 if (!check_fsp_open(conn, req, fsp)) {
5039 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5040 END_PROFILE(SMBclose);
5041 return;
5044 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5045 fsp->is_directory ? "directory" : "file",
5046 fsp->fh->fd, fsp_fnum_dbg(fsp),
5047 conn->num_files_open));
5049 if (!fsp->is_directory) {
5050 time_t t;
5053 * Take care of any time sent in the close.
5056 t = srv_make_unix_date3(req->vwv+1);
5057 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5060 if (fsp->num_aio_requests != 0) {
5062 struct reply_close_state *state;
5064 DEBUG(10, ("closing with aio %u requests pending\n",
5065 fsp->num_aio_requests));
5068 * We depend on the aio_extra destructor to take care of this
5069 * close request once fsp->num_aio_request drops to 0.
5072 fsp->deferred_close = tevent_wait_send(
5073 fsp, fsp->conn->sconn->ev_ctx);
5074 if (fsp->deferred_close == NULL) {
5075 status = NT_STATUS_NO_MEMORY;
5076 goto done;
5079 state = talloc(fsp, struct reply_close_state);
5080 if (state == NULL) {
5081 TALLOC_FREE(fsp->deferred_close);
5082 status = NT_STATUS_NO_MEMORY;
5083 goto done;
5085 state->fsp = fsp;
5086 state->smbreq = talloc_move(fsp, &req);
5087 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5088 state);
5089 END_PROFILE(SMBclose);
5090 return;
5094 * close_file() returns the unix errno if an error was detected on
5095 * close - normally this is due to a disk full error. If not then it
5096 * was probably an I/O error.
5099 status = close_file(req, fsp, NORMAL_CLOSE);
5100 done:
5101 if (!NT_STATUS_IS_OK(status)) {
5102 reply_nterror(req, status);
5103 END_PROFILE(SMBclose);
5104 return;
5107 reply_outbuf(req, 0, 0);
5108 END_PROFILE(SMBclose);
5109 return;
5112 static void do_smb1_close(struct tevent_req *req)
5114 struct reply_close_state *state = tevent_req_callback_data(
5115 req, struct reply_close_state);
5116 struct smb_request *smbreq;
5117 NTSTATUS status;
5118 int ret;
5120 ret = tevent_wait_recv(req);
5121 TALLOC_FREE(req);
5122 if (ret != 0) {
5123 DEBUG(10, ("tevent_wait_recv returned %s\n",
5124 strerror(ret)));
5126 * Continue anyway, this should never happen
5131 * fsp->smb2_close_request right now is a talloc grandchild of
5132 * fsp. When we close_file(fsp), it would go with it. No chance to
5133 * reply...
5135 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5137 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5138 if (NT_STATUS_IS_OK(status)) {
5139 reply_outbuf(smbreq, 0, 0);
5140 } else {
5141 reply_nterror(smbreq, status);
5143 if (!srv_send_smb(smbreq->sconn,
5144 (char *)smbreq->outbuf,
5145 true,
5146 smbreq->seqnum+1,
5147 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5148 NULL)) {
5149 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5150 "failed.");
5152 TALLOC_FREE(smbreq);
5155 /****************************************************************************
5156 Reply to a writeclose (Core+ protocol).
5157 ****************************************************************************/
5159 void reply_writeclose(struct smb_request *req)
5161 connection_struct *conn = req->conn;
5162 size_t numtowrite;
5163 ssize_t nwritten = -1;
5164 NTSTATUS close_status = NT_STATUS_OK;
5165 off_t startpos;
5166 const char *data;
5167 struct timespec mtime;
5168 files_struct *fsp;
5169 struct lock_struct lock;
5171 START_PROFILE(SMBwriteclose);
5173 if (req->wct < 6) {
5174 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5175 END_PROFILE(SMBwriteclose);
5176 return;
5179 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5181 if (!check_fsp(conn, req, fsp)) {
5182 END_PROFILE(SMBwriteclose);
5183 return;
5185 if (!CHECK_WRITE(fsp)) {
5186 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5187 END_PROFILE(SMBwriteclose);
5188 return;
5191 numtowrite = SVAL(req->vwv+1, 0);
5192 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5193 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5194 data = (const char *)req->buf + 1;
5196 if (!fsp->print_file) {
5197 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5198 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5199 &lock);
5201 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5202 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5203 END_PROFILE(SMBwriteclose);
5204 return;
5208 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5210 set_close_write_time(fsp, mtime);
5213 * More insanity. W2K only closes the file if writelen > 0.
5214 * JRA.
5217 if (numtowrite) {
5218 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5219 "file %s\n", fsp_str_dbg(fsp)));
5220 close_status = close_file(req, fsp, NORMAL_CLOSE);
5223 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5224 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5225 conn->num_files_open));
5227 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5228 reply_nterror(req, NT_STATUS_DISK_FULL);
5229 goto strict_unlock;
5232 if(!NT_STATUS_IS_OK(close_status)) {
5233 reply_nterror(req, close_status);
5234 goto strict_unlock;
5237 reply_outbuf(req, 1, 0);
5239 SSVAL(req->outbuf,smb_vwv0,nwritten);
5241 strict_unlock:
5242 if (numtowrite && !fsp->print_file) {
5243 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5246 END_PROFILE(SMBwriteclose);
5247 return;
5250 #undef DBGC_CLASS
5251 #define DBGC_CLASS DBGC_LOCKING
5253 /****************************************************************************
5254 Reply to a lock.
5255 ****************************************************************************/
5257 void reply_lock(struct smb_request *req)
5259 connection_struct *conn = req->conn;
5260 uint64_t count,offset;
5261 NTSTATUS status;
5262 files_struct *fsp;
5263 struct byte_range_lock *br_lck = NULL;
5265 START_PROFILE(SMBlock);
5267 if (req->wct < 5) {
5268 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5269 END_PROFILE(SMBlock);
5270 return;
5273 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5275 if (!check_fsp(conn, req, fsp)) {
5276 END_PROFILE(SMBlock);
5277 return;
5280 count = (uint64_t)IVAL(req->vwv+1, 0);
5281 offset = (uint64_t)IVAL(req->vwv+3, 0);
5283 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5284 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5286 br_lck = do_lock(req->sconn->msg_ctx,
5287 fsp,
5288 (uint64_t)req->smbpid,
5289 count,
5290 offset,
5291 WRITE_LOCK,
5292 WINDOWS_LOCK,
5293 False, /* Non-blocking lock. */
5294 &status,
5295 NULL,
5296 NULL);
5298 TALLOC_FREE(br_lck);
5300 if (NT_STATUS_V(status)) {
5301 reply_nterror(req, status);
5302 END_PROFILE(SMBlock);
5303 return;
5306 reply_outbuf(req, 0, 0);
5308 END_PROFILE(SMBlock);
5309 return;
5312 /****************************************************************************
5313 Reply to a unlock.
5314 ****************************************************************************/
5316 void reply_unlock(struct smb_request *req)
5318 connection_struct *conn = req->conn;
5319 uint64_t count,offset;
5320 NTSTATUS status;
5321 files_struct *fsp;
5323 START_PROFILE(SMBunlock);
5325 if (req->wct < 5) {
5326 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5327 END_PROFILE(SMBunlock);
5328 return;
5331 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5333 if (!check_fsp(conn, req, fsp)) {
5334 END_PROFILE(SMBunlock);
5335 return;
5338 count = (uint64_t)IVAL(req->vwv+1, 0);
5339 offset = (uint64_t)IVAL(req->vwv+3, 0);
5341 status = do_unlock(req->sconn->msg_ctx,
5342 fsp,
5343 (uint64_t)req->smbpid,
5344 count,
5345 offset,
5346 WINDOWS_LOCK);
5348 if (NT_STATUS_V(status)) {
5349 reply_nterror(req, status);
5350 END_PROFILE(SMBunlock);
5351 return;
5354 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5355 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5357 reply_outbuf(req, 0, 0);
5359 END_PROFILE(SMBunlock);
5360 return;
5363 #undef DBGC_CLASS
5364 #define DBGC_CLASS DBGC_ALL
5366 /****************************************************************************
5367 Reply to a tdis.
5368 conn POINTER CAN BE NULL HERE !
5369 ****************************************************************************/
5371 void reply_tdis(struct smb_request *req)
5373 NTSTATUS status;
5374 connection_struct *conn = req->conn;
5375 struct smbXsrv_tcon *tcon;
5377 START_PROFILE(SMBtdis);
5379 if (!conn) {
5380 DEBUG(4,("Invalid connection in tdis\n"));
5381 reply_force_doserror(req, ERRSRV, ERRinvnid);
5382 END_PROFILE(SMBtdis);
5383 return;
5386 tcon = conn->tcon;
5387 req->conn = NULL;
5390 * TODO: cancel all outstanding requests on the tcon
5392 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5393 if (!NT_STATUS_IS_OK(status)) {
5394 DEBUG(0, ("reply_tdis: "
5395 "smbXsrv_tcon_disconnect() failed: %s\n",
5396 nt_errstr(status)));
5398 * If we hit this case, there is something completely
5399 * wrong, so we better disconnect the transport connection.
5401 END_PROFILE(SMBtdis);
5402 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5403 return;
5406 TALLOC_FREE(tcon);
5408 reply_outbuf(req, 0, 0);
5409 END_PROFILE(SMBtdis);
5410 return;
5413 /****************************************************************************
5414 Reply to a echo.
5415 conn POINTER CAN BE NULL HERE !
5416 ****************************************************************************/
5418 void reply_echo(struct smb_request *req)
5420 connection_struct *conn = req->conn;
5421 struct smb_perfcount_data local_pcd;
5422 struct smb_perfcount_data *cur_pcd;
5423 int smb_reverb;
5424 int seq_num;
5426 START_PROFILE(SMBecho);
5428 smb_init_perfcount_data(&local_pcd);
5430 if (req->wct < 1) {
5431 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5432 END_PROFILE(SMBecho);
5433 return;
5436 smb_reverb = SVAL(req->vwv+0, 0);
5438 reply_outbuf(req, 1, req->buflen);
5440 /* copy any incoming data back out */
5441 if (req->buflen > 0) {
5442 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5445 if (smb_reverb > 100) {
5446 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5447 smb_reverb = 100;
5450 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5452 /* this makes sure we catch the request pcd */
5453 if (seq_num == smb_reverb) {
5454 cur_pcd = &req->pcd;
5455 } else {
5456 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5457 cur_pcd = &local_pcd;
5460 SSVAL(req->outbuf,smb_vwv0,seq_num);
5462 show_msg((char *)req->outbuf);
5463 if (!srv_send_smb(req->sconn,
5464 (char *)req->outbuf,
5465 true, req->seqnum+1,
5466 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5467 cur_pcd))
5468 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5471 DEBUG(3,("echo %d times\n", smb_reverb));
5473 TALLOC_FREE(req->outbuf);
5475 END_PROFILE(SMBecho);
5476 return;
5479 /****************************************************************************
5480 Reply to a printopen.
5481 ****************************************************************************/
5483 void reply_printopen(struct smb_request *req)
5485 connection_struct *conn = req->conn;
5486 files_struct *fsp;
5487 NTSTATUS status;
5489 START_PROFILE(SMBsplopen);
5491 if (req->wct < 2) {
5492 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5493 END_PROFILE(SMBsplopen);
5494 return;
5497 if (!CAN_PRINT(conn)) {
5498 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5499 END_PROFILE(SMBsplopen);
5500 return;
5503 status = file_new(req, conn, &fsp);
5504 if(!NT_STATUS_IS_OK(status)) {
5505 reply_nterror(req, status);
5506 END_PROFILE(SMBsplopen);
5507 return;
5510 /* Open for exclusive use, write only. */
5511 status = print_spool_open(fsp, NULL, req->vuid);
5513 if (!NT_STATUS_IS_OK(status)) {
5514 file_free(req, fsp);
5515 reply_nterror(req, status);
5516 END_PROFILE(SMBsplopen);
5517 return;
5520 reply_outbuf(req, 1, 0);
5521 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5523 DEBUG(3,("openprint fd=%d %s\n",
5524 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5526 END_PROFILE(SMBsplopen);
5527 return;
5530 /****************************************************************************
5531 Reply to a printclose.
5532 ****************************************************************************/
5534 void reply_printclose(struct smb_request *req)
5536 connection_struct *conn = req->conn;
5537 files_struct *fsp;
5538 NTSTATUS status;
5540 START_PROFILE(SMBsplclose);
5542 if (req->wct < 1) {
5543 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5544 END_PROFILE(SMBsplclose);
5545 return;
5548 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5550 if (!check_fsp(conn, req, fsp)) {
5551 END_PROFILE(SMBsplclose);
5552 return;
5555 if (!CAN_PRINT(conn)) {
5556 reply_force_doserror(req, ERRSRV, ERRerror);
5557 END_PROFILE(SMBsplclose);
5558 return;
5561 DEBUG(3,("printclose fd=%d %s\n",
5562 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5564 status = close_file(req, fsp, NORMAL_CLOSE);
5566 if(!NT_STATUS_IS_OK(status)) {
5567 reply_nterror(req, status);
5568 END_PROFILE(SMBsplclose);
5569 return;
5572 reply_outbuf(req, 0, 0);
5574 END_PROFILE(SMBsplclose);
5575 return;
5578 /****************************************************************************
5579 Reply to a printqueue.
5580 ****************************************************************************/
5582 void reply_printqueue(struct smb_request *req)
5584 connection_struct *conn = req->conn;
5585 int max_count;
5586 int start_index;
5588 START_PROFILE(SMBsplretq);
5590 if (req->wct < 2) {
5591 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5592 END_PROFILE(SMBsplretq);
5593 return;
5596 max_count = SVAL(req->vwv+0, 0);
5597 start_index = SVAL(req->vwv+1, 0);
5599 /* we used to allow the client to get the cnum wrong, but that
5600 is really quite gross and only worked when there was only
5601 one printer - I think we should now only accept it if they
5602 get it right (tridge) */
5603 if (!CAN_PRINT(conn)) {
5604 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5605 END_PROFILE(SMBsplretq);
5606 return;
5609 reply_outbuf(req, 2, 3);
5610 SSVAL(req->outbuf,smb_vwv0,0);
5611 SSVAL(req->outbuf,smb_vwv1,0);
5612 SCVAL(smb_buf(req->outbuf),0,1);
5613 SSVAL(smb_buf(req->outbuf),1,0);
5615 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5616 start_index, max_count));
5619 TALLOC_CTX *mem_ctx = talloc_tos();
5620 NTSTATUS status;
5621 WERROR werr;
5622 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5623 struct rpc_pipe_client *cli = NULL;
5624 struct dcerpc_binding_handle *b = NULL;
5625 struct policy_handle handle;
5626 struct spoolss_DevmodeContainer devmode_ctr;
5627 union spoolss_JobInfo *info;
5628 uint32_t count;
5629 uint32_t num_to_get;
5630 uint32_t first;
5631 uint32_t i;
5633 ZERO_STRUCT(handle);
5635 status = rpc_pipe_open_interface(conn,
5636 &ndr_table_spoolss.syntax_id,
5637 conn->session_info,
5638 conn->sconn->remote_address,
5639 conn->sconn->msg_ctx,
5640 &cli);
5641 if (!NT_STATUS_IS_OK(status)) {
5642 DEBUG(0, ("reply_printqueue: "
5643 "could not connect to spoolss: %s\n",
5644 nt_errstr(status)));
5645 reply_nterror(req, status);
5646 goto out;
5648 b = cli->binding_handle;
5650 ZERO_STRUCT(devmode_ctr);
5652 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5653 sharename,
5654 NULL, devmode_ctr,
5655 SEC_FLAG_MAXIMUM_ALLOWED,
5656 &handle,
5657 &werr);
5658 if (!NT_STATUS_IS_OK(status)) {
5659 reply_nterror(req, status);
5660 goto out;
5662 if (!W_ERROR_IS_OK(werr)) {
5663 reply_nterror(req, werror_to_ntstatus(werr));
5664 goto out;
5667 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5668 &handle,
5669 0, /* firstjob */
5670 0xff, /* numjobs */
5671 2, /* level */
5672 0, /* offered */
5673 &count,
5674 &info);
5675 if (!W_ERROR_IS_OK(werr)) {
5676 reply_nterror(req, werror_to_ntstatus(werr));
5677 goto out;
5680 if (max_count > 0) {
5681 first = start_index;
5682 } else {
5683 first = start_index + max_count + 1;
5686 if (first >= count) {
5687 num_to_get = first;
5688 } else {
5689 num_to_get = first + MIN(ABS(max_count), count - first);
5692 for (i = first; i < num_to_get; i++) {
5693 char blob[28];
5694 char *p = blob;
5695 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5696 int qstatus;
5697 uint16_t qrapjobid = pjobid_to_rap(sharename,
5698 info[i].info2.job_id);
5700 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5701 qstatus = 2;
5702 } else {
5703 qstatus = 3;
5706 srv_put_dos_date2(p, 0, qtime);
5707 SCVAL(p, 4, qstatus);
5708 SSVAL(p, 5, qrapjobid);
5709 SIVAL(p, 7, info[i].info2.size);
5710 SCVAL(p, 11, 0);
5711 srvstr_push(blob, req->flags2, p+12,
5712 info[i].info2.notify_name, 16, STR_ASCII);
5714 if (message_push_blob(
5715 &req->outbuf,
5716 data_blob_const(
5717 blob, sizeof(blob))) == -1) {
5718 reply_nterror(req, NT_STATUS_NO_MEMORY);
5719 goto out;
5723 if (count > 0) {
5724 SSVAL(req->outbuf,smb_vwv0,count);
5725 SSVAL(req->outbuf,smb_vwv1,
5726 (max_count>0?first+count:first-1));
5727 SCVAL(smb_buf(req->outbuf),0,1);
5728 SSVAL(smb_buf(req->outbuf),1,28*count);
5732 DEBUG(3, ("%u entries returned in queue\n",
5733 (unsigned)count));
5735 out:
5736 if (b && is_valid_policy_hnd(&handle)) {
5737 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5742 END_PROFILE(SMBsplretq);
5743 return;
5746 /****************************************************************************
5747 Reply to a printwrite.
5748 ****************************************************************************/
5750 void reply_printwrite(struct smb_request *req)
5752 connection_struct *conn = req->conn;
5753 int numtowrite;
5754 const char *data;
5755 files_struct *fsp;
5757 START_PROFILE(SMBsplwr);
5759 if (req->wct < 1) {
5760 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5761 END_PROFILE(SMBsplwr);
5762 return;
5765 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5767 if (!check_fsp(conn, req, fsp)) {
5768 END_PROFILE(SMBsplwr);
5769 return;
5772 if (!fsp->print_file) {
5773 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5774 END_PROFILE(SMBsplwr);
5775 return;
5778 if (!CHECK_WRITE(fsp)) {
5779 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5780 END_PROFILE(SMBsplwr);
5781 return;
5784 numtowrite = SVAL(req->buf, 1);
5786 if (req->buflen < numtowrite + 3) {
5787 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5788 END_PROFILE(SMBsplwr);
5789 return;
5792 data = (const char *)req->buf + 3;
5794 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5795 reply_nterror(req, map_nt_error_from_unix(errno));
5796 END_PROFILE(SMBsplwr);
5797 return;
5800 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5802 END_PROFILE(SMBsplwr);
5803 return;
5806 /****************************************************************************
5807 Reply to a mkdir.
5808 ****************************************************************************/
5810 void reply_mkdir(struct smb_request *req)
5812 connection_struct *conn = req->conn;
5813 struct smb_filename *smb_dname = NULL;
5814 char *directory = NULL;
5815 NTSTATUS status;
5816 TALLOC_CTX *ctx = talloc_tos();
5818 START_PROFILE(SMBmkdir);
5820 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5821 STR_TERMINATE, &status);
5822 if (!NT_STATUS_IS_OK(status)) {
5823 reply_nterror(req, status);
5824 goto out;
5827 status = filename_convert(ctx, conn,
5828 req->flags2 & FLAGS2_DFS_PATHNAMES,
5829 directory,
5830 UCF_PREP_CREATEFILE,
5831 NULL,
5832 &smb_dname);
5833 if (!NT_STATUS_IS_OK(status)) {
5834 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5835 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5836 ERRSRV, ERRbadpath);
5837 goto out;
5839 reply_nterror(req, status);
5840 goto out;
5843 status = create_directory(conn, req, smb_dname);
5845 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5847 if (!NT_STATUS_IS_OK(status)) {
5849 if (!use_nt_status()
5850 && NT_STATUS_EQUAL(status,
5851 NT_STATUS_OBJECT_NAME_COLLISION)) {
5853 * Yes, in the DOS error code case we get a
5854 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5855 * samba4 torture test.
5857 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5860 reply_nterror(req, status);
5861 goto out;
5864 reply_outbuf(req, 0, 0);
5866 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5867 out:
5868 TALLOC_FREE(smb_dname);
5869 END_PROFILE(SMBmkdir);
5870 return;
5873 /****************************************************************************
5874 Reply to a rmdir.
5875 ****************************************************************************/
5877 void reply_rmdir(struct smb_request *req)
5879 connection_struct *conn = req->conn;
5880 struct smb_filename *smb_dname = NULL;
5881 char *directory = NULL;
5882 NTSTATUS status;
5883 TALLOC_CTX *ctx = talloc_tos();
5884 files_struct *fsp = NULL;
5885 int info = 0;
5886 struct smbd_server_connection *sconn = req->sconn;
5888 START_PROFILE(SMBrmdir);
5890 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5891 STR_TERMINATE, &status);
5892 if (!NT_STATUS_IS_OK(status)) {
5893 reply_nterror(req, status);
5894 goto out;
5897 status = filename_convert(ctx, conn,
5898 req->flags2 & FLAGS2_DFS_PATHNAMES,
5899 directory,
5901 NULL,
5902 &smb_dname);
5903 if (!NT_STATUS_IS_OK(status)) {
5904 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5905 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5906 ERRSRV, ERRbadpath);
5907 goto out;
5909 reply_nterror(req, status);
5910 goto out;
5913 if (is_ntfs_stream_smb_fname(smb_dname)) {
5914 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5915 goto out;
5918 status = SMB_VFS_CREATE_FILE(
5919 conn, /* conn */
5920 req, /* req */
5921 0, /* root_dir_fid */
5922 smb_dname, /* fname */
5923 DELETE_ACCESS, /* access_mask */
5924 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5925 FILE_SHARE_DELETE),
5926 FILE_OPEN, /* create_disposition*/
5927 FILE_DIRECTORY_FILE, /* create_options */
5928 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5929 0, /* oplock_request */
5930 0, /* allocation_size */
5931 0, /* private_flags */
5932 NULL, /* sd */
5933 NULL, /* ea_list */
5934 &fsp, /* result */
5935 &info); /* pinfo */
5937 if (!NT_STATUS_IS_OK(status)) {
5938 if (open_was_deferred(req->sconn, req->mid)) {
5939 /* We have re-scheduled this call. */
5940 goto out;
5942 reply_nterror(req, status);
5943 goto out;
5946 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5947 if (!NT_STATUS_IS_OK(status)) {
5948 close_file(req, fsp, ERROR_CLOSE);
5949 reply_nterror(req, status);
5950 goto out;
5953 if (!set_delete_on_close(fsp, true,
5954 conn->session_info->security_token,
5955 conn->session_info->unix_token)) {
5956 close_file(req, fsp, ERROR_CLOSE);
5957 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5958 goto out;
5961 status = close_file(req, fsp, NORMAL_CLOSE);
5962 if (!NT_STATUS_IS_OK(status)) {
5963 reply_nterror(req, status);
5964 } else {
5965 reply_outbuf(req, 0, 0);
5968 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5970 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5971 out:
5972 TALLOC_FREE(smb_dname);
5973 END_PROFILE(SMBrmdir);
5974 return;
5977 /*******************************************************************
5978 Resolve wildcards in a filename rename.
5979 ********************************************************************/
5981 static bool resolve_wildcards(TALLOC_CTX *ctx,
5982 const char *name1,
5983 const char *name2,
5984 char **pp_newname)
5986 char *name2_copy = NULL;
5987 char *root1 = NULL;
5988 char *root2 = NULL;
5989 char *ext1 = NULL;
5990 char *ext2 = NULL;
5991 char *p,*p2, *pname1, *pname2;
5993 name2_copy = talloc_strdup(ctx, name2);
5994 if (!name2_copy) {
5995 return False;
5998 pname1 = strrchr_m(name1,'/');
5999 pname2 = strrchr_m(name2_copy,'/');
6001 if (!pname1 || !pname2) {
6002 return False;
6005 /* Truncate the copy of name2 at the last '/' */
6006 *pname2 = '\0';
6008 /* Now go past the '/' */
6009 pname1++;
6010 pname2++;
6012 root1 = talloc_strdup(ctx, pname1);
6013 root2 = talloc_strdup(ctx, pname2);
6015 if (!root1 || !root2) {
6016 return False;
6019 p = strrchr_m(root1,'.');
6020 if (p) {
6021 *p = 0;
6022 ext1 = talloc_strdup(ctx, p+1);
6023 } else {
6024 ext1 = talloc_strdup(ctx, "");
6026 p = strrchr_m(root2,'.');
6027 if (p) {
6028 *p = 0;
6029 ext2 = talloc_strdup(ctx, p+1);
6030 } else {
6031 ext2 = talloc_strdup(ctx, "");
6034 if (!ext1 || !ext2) {
6035 return False;
6038 p = root1;
6039 p2 = root2;
6040 while (*p2) {
6041 if (*p2 == '?') {
6042 /* Hmmm. Should this be mb-aware ? */
6043 *p2 = *p;
6044 p2++;
6045 } else if (*p2 == '*') {
6046 *p2 = '\0';
6047 root2 = talloc_asprintf(ctx, "%s%s",
6048 root2,
6050 if (!root2) {
6051 return False;
6053 break;
6054 } else {
6055 p2++;
6057 if (*p) {
6058 p++;
6062 p = ext1;
6063 p2 = ext2;
6064 while (*p2) {
6065 if (*p2 == '?') {
6066 /* Hmmm. Should this be mb-aware ? */
6067 *p2 = *p;
6068 p2++;
6069 } else if (*p2 == '*') {
6070 *p2 = '\0';
6071 ext2 = talloc_asprintf(ctx, "%s%s",
6072 ext2,
6074 if (!ext2) {
6075 return False;
6077 break;
6078 } else {
6079 p2++;
6081 if (*p) {
6082 p++;
6086 if (*ext2) {
6087 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6088 name2_copy,
6089 root2,
6090 ext2);
6091 } else {
6092 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6093 name2_copy,
6094 root2);
6097 if (!*pp_newname) {
6098 return False;
6101 return True;
6104 /****************************************************************************
6105 Ensure open files have their names updated. Updated to notify other smbd's
6106 asynchronously.
6107 ****************************************************************************/
6109 static void rename_open_files(connection_struct *conn,
6110 struct share_mode_lock *lck,
6111 uint32_t orig_name_hash,
6112 const struct smb_filename *smb_fname_dst)
6114 files_struct *fsp;
6115 bool did_rename = False;
6116 NTSTATUS status;
6117 uint32_t new_name_hash = 0;
6119 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6120 fsp = file_find_di_next(fsp)) {
6121 /* fsp_name is a relative path under the fsp. To change this for other
6122 sharepaths we need to manipulate relative paths. */
6123 /* TODO - create the absolute path and manipulate the newname
6124 relative to the sharepath. */
6125 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6126 continue;
6128 if (fsp->name_hash != orig_name_hash) {
6129 continue;
6131 DEBUG(10, ("rename_open_files: renaming file %s "
6132 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6133 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6134 smb_fname_str_dbg(smb_fname_dst)));
6136 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6137 if (NT_STATUS_IS_OK(status)) {
6138 did_rename = True;
6139 new_name_hash = fsp->name_hash;
6143 if (!did_rename) {
6144 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6145 "for %s\n", file_id_string_tos(&lck->data->id),
6146 smb_fname_str_dbg(smb_fname_dst)));
6149 /* Send messages to all smbd's (not ourself) that the name has changed. */
6150 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6151 orig_name_hash, new_name_hash,
6152 smb_fname_dst);
6156 /****************************************************************************
6157 We need to check if the source path is a parent directory of the destination
6158 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6159 refuse the rename with a sharing violation. Under UNIX the above call can
6160 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6161 probably need to check that the client is a Windows one before disallowing
6162 this as a UNIX client (one with UNIX extensions) can know the source is a
6163 symlink and make this decision intelligently. Found by an excellent bug
6164 report from <AndyLiebman@aol.com>.
6165 ****************************************************************************/
6167 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6168 const struct smb_filename *smb_fname_dst)
6170 const char *psrc = smb_fname_src->base_name;
6171 const char *pdst = smb_fname_dst->base_name;
6172 size_t slen;
6174 if (psrc[0] == '.' && psrc[1] == '/') {
6175 psrc += 2;
6177 if (pdst[0] == '.' && pdst[1] == '/') {
6178 pdst += 2;
6180 if ((slen = strlen(psrc)) > strlen(pdst)) {
6181 return False;
6183 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6187 * Do the notify calls from a rename
6190 static void notify_rename(connection_struct *conn, bool is_dir,
6191 const struct smb_filename *smb_fname_src,
6192 const struct smb_filename *smb_fname_dst)
6194 char *parent_dir_src = NULL;
6195 char *parent_dir_dst = NULL;
6196 uint32 mask;
6198 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6199 : FILE_NOTIFY_CHANGE_FILE_NAME;
6201 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6202 &parent_dir_src, NULL) ||
6203 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6204 &parent_dir_dst, NULL)) {
6205 goto out;
6208 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6209 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6210 smb_fname_src->base_name);
6211 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6212 smb_fname_dst->base_name);
6214 else {
6215 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6216 smb_fname_src->base_name);
6217 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6218 smb_fname_dst->base_name);
6221 /* this is a strange one. w2k3 gives an additional event for
6222 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6223 files, but not directories */
6224 if (!is_dir) {
6225 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6226 FILE_NOTIFY_CHANGE_ATTRIBUTES
6227 |FILE_NOTIFY_CHANGE_CREATION,
6228 smb_fname_dst->base_name);
6230 out:
6231 TALLOC_FREE(parent_dir_src);
6232 TALLOC_FREE(parent_dir_dst);
6235 /****************************************************************************
6236 Returns an error if the parent directory for a filename is open in an
6237 incompatible way.
6238 ****************************************************************************/
6240 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6241 const struct smb_filename *smb_fname_dst_in)
6243 char *parent_dir = NULL;
6244 struct smb_filename smb_fname_parent;
6245 struct file_id id;
6246 files_struct *fsp = NULL;
6247 int ret;
6249 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6250 &parent_dir, NULL)) {
6251 return NT_STATUS_NO_MEMORY;
6253 ZERO_STRUCT(smb_fname_parent);
6254 smb_fname_parent.base_name = parent_dir;
6256 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6257 if (ret == -1) {
6258 return map_nt_error_from_unix(errno);
6262 * We're only checking on this smbd here, mostly good
6263 * enough.. and will pass tests.
6266 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6267 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6268 fsp = file_find_di_next(fsp)) {
6269 if (fsp->access_mask & DELETE_ACCESS) {
6270 return NT_STATUS_SHARING_VIOLATION;
6273 return NT_STATUS_OK;
6276 /****************************************************************************
6277 Rename an open file - given an fsp.
6278 ****************************************************************************/
6280 NTSTATUS rename_internals_fsp(connection_struct *conn,
6281 files_struct *fsp,
6282 const struct smb_filename *smb_fname_dst_in,
6283 uint32 attrs,
6284 bool replace_if_exists)
6286 TALLOC_CTX *ctx = talloc_tos();
6287 struct smb_filename *smb_fname_dst = NULL;
6288 NTSTATUS status = NT_STATUS_OK;
6289 struct share_mode_lock *lck = NULL;
6290 bool dst_exists, old_is_stream, new_is_stream;
6292 status = check_name(conn, smb_fname_dst_in->base_name);
6293 if (!NT_STATUS_IS_OK(status)) {
6294 return status;
6297 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6298 if (!NT_STATUS_IS_OK(status)) {
6299 return status;
6302 /* Make a copy of the dst smb_fname structs */
6304 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6305 if (!NT_STATUS_IS_OK(status)) {
6306 goto out;
6310 * Check for special case with case preserving and not
6311 * case sensitive. If the old last component differs from the original
6312 * last component only by case, then we should allow
6313 * the rename (user is trying to change the case of the
6314 * filename).
6316 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6317 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6318 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6319 char *last_slash;
6320 char *fname_dst_lcomp_base_mod = NULL;
6321 struct smb_filename *smb_fname_orig_lcomp = NULL;
6324 * Get the last component of the destination name.
6326 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6327 if (last_slash) {
6328 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6329 } else {
6330 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6332 if (!fname_dst_lcomp_base_mod) {
6333 status = NT_STATUS_NO_MEMORY;
6334 goto out;
6338 * Create an smb_filename struct using the original last
6339 * component of the destination.
6341 status = create_synthetic_smb_fname_split(ctx,
6342 smb_fname_dst->original_lcomp, NULL,
6343 &smb_fname_orig_lcomp);
6344 if (!NT_STATUS_IS_OK(status)) {
6345 TALLOC_FREE(fname_dst_lcomp_base_mod);
6346 goto out;
6349 /* If the base names only differ by case, use original. */
6350 if(!strcsequal(fname_dst_lcomp_base_mod,
6351 smb_fname_orig_lcomp->base_name)) {
6352 char *tmp;
6354 * Replace the modified last component with the
6355 * original.
6357 if (last_slash) {
6358 *last_slash = '\0'; /* Truncate at the '/' */
6359 tmp = talloc_asprintf(smb_fname_dst,
6360 "%s/%s",
6361 smb_fname_dst->base_name,
6362 smb_fname_orig_lcomp->base_name);
6363 } else {
6364 tmp = talloc_asprintf(smb_fname_dst,
6365 "%s",
6366 smb_fname_orig_lcomp->base_name);
6368 if (tmp == NULL) {
6369 status = NT_STATUS_NO_MEMORY;
6370 TALLOC_FREE(fname_dst_lcomp_base_mod);
6371 TALLOC_FREE(smb_fname_orig_lcomp);
6372 goto out;
6374 TALLOC_FREE(smb_fname_dst->base_name);
6375 smb_fname_dst->base_name = tmp;
6378 /* If the stream_names only differ by case, use original. */
6379 if(!strcsequal(smb_fname_dst->stream_name,
6380 smb_fname_orig_lcomp->stream_name)) {
6381 char *tmp = NULL;
6382 /* Use the original stream. */
6383 tmp = talloc_strdup(smb_fname_dst,
6384 smb_fname_orig_lcomp->stream_name);
6385 if (tmp == NULL) {
6386 status = NT_STATUS_NO_MEMORY;
6387 TALLOC_FREE(fname_dst_lcomp_base_mod);
6388 TALLOC_FREE(smb_fname_orig_lcomp);
6389 goto out;
6391 TALLOC_FREE(smb_fname_dst->stream_name);
6392 smb_fname_dst->stream_name = tmp;
6394 TALLOC_FREE(fname_dst_lcomp_base_mod);
6395 TALLOC_FREE(smb_fname_orig_lcomp);
6399 * If the src and dest names are identical - including case,
6400 * don't do the rename, just return success.
6403 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6404 strcsequal(fsp->fsp_name->stream_name,
6405 smb_fname_dst->stream_name)) {
6406 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6407 "- returning success\n",
6408 smb_fname_str_dbg(smb_fname_dst)));
6409 status = NT_STATUS_OK;
6410 goto out;
6413 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6414 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6416 /* Return the correct error code if both names aren't streams. */
6417 if (!old_is_stream && new_is_stream) {
6418 status = NT_STATUS_OBJECT_NAME_INVALID;
6419 goto out;
6422 if (old_is_stream && !new_is_stream) {
6423 status = NT_STATUS_INVALID_PARAMETER;
6424 goto out;
6427 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6429 if(!replace_if_exists && dst_exists) {
6430 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6431 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6432 smb_fname_str_dbg(smb_fname_dst)));
6433 status = NT_STATUS_OBJECT_NAME_COLLISION;
6434 goto out;
6437 if (dst_exists) {
6438 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6439 &smb_fname_dst->st);
6440 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6441 fileid);
6442 /* The file can be open when renaming a stream */
6443 if (dst_fsp && !new_is_stream) {
6444 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6445 status = NT_STATUS_ACCESS_DENIED;
6446 goto out;
6450 /* Ensure we have a valid stat struct for the source. */
6451 status = vfs_stat_fsp(fsp);
6452 if (!NT_STATUS_IS_OK(status)) {
6453 goto out;
6456 status = can_rename(conn, fsp, attrs);
6458 if (!NT_STATUS_IS_OK(status)) {
6459 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6460 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6461 smb_fname_str_dbg(smb_fname_dst)));
6462 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6463 status = NT_STATUS_ACCESS_DENIED;
6464 goto out;
6467 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6468 status = NT_STATUS_ACCESS_DENIED;
6471 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6474 * We have the file open ourselves, so not being able to get the
6475 * corresponding share mode lock is a fatal error.
6478 SMB_ASSERT(lck != NULL);
6480 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6481 uint32 create_options = fsp->fh->private_options;
6483 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6484 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6485 smb_fname_str_dbg(smb_fname_dst)));
6487 if (!fsp->is_directory &&
6488 !lp_posix_pathnames() &&
6489 (lp_map_archive(SNUM(conn)) ||
6490 lp_store_dos_attributes(SNUM(conn)))) {
6491 /* We must set the archive bit on the newly
6492 renamed file. */
6493 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6494 uint32_t old_dosmode = dos_mode(conn,
6495 smb_fname_dst);
6496 file_set_dosmode(conn,
6497 smb_fname_dst,
6498 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6499 NULL,
6500 true);
6504 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6505 smb_fname_dst);
6507 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6510 * A rename acts as a new file create w.r.t. allowing an initial delete
6511 * on close, probably because in Windows there is a new handle to the
6512 * new file. If initial delete on close was requested but not
6513 * originally set, we need to set it here. This is probably not 100% correct,
6514 * but will work for the CIFSFS client which in non-posix mode
6515 * depends on these semantics. JRA.
6518 if (create_options & FILE_DELETE_ON_CLOSE) {
6519 status = can_set_delete_on_close(fsp, 0);
6521 if (NT_STATUS_IS_OK(status)) {
6522 /* Note that here we set the *inital* delete on close flag,
6523 * not the regular one. The magic gets handled in close. */
6524 fsp->initial_delete_on_close = True;
6527 TALLOC_FREE(lck);
6528 status = NT_STATUS_OK;
6529 goto out;
6532 TALLOC_FREE(lck);
6534 if (errno == ENOTDIR || errno == EISDIR) {
6535 status = NT_STATUS_OBJECT_NAME_COLLISION;
6536 } else {
6537 status = map_nt_error_from_unix(errno);
6540 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6541 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6542 smb_fname_str_dbg(smb_fname_dst)));
6544 out:
6545 TALLOC_FREE(smb_fname_dst);
6547 return status;
6550 /****************************************************************************
6551 The guts of the rename command, split out so it may be called by the NT SMB
6552 code.
6553 ****************************************************************************/
6555 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6556 connection_struct *conn,
6557 struct smb_request *req,
6558 struct smb_filename *smb_fname_src,
6559 struct smb_filename *smb_fname_dst,
6560 uint32 attrs,
6561 bool replace_if_exists,
6562 bool src_has_wild,
6563 bool dest_has_wild,
6564 uint32_t access_mask)
6566 char *fname_src_dir = NULL;
6567 char *fname_src_mask = NULL;
6568 int count=0;
6569 NTSTATUS status = NT_STATUS_OK;
6570 struct smb_Dir *dir_hnd = NULL;
6571 const char *dname = NULL;
6572 char *talloced = NULL;
6573 long offset = 0;
6574 int create_options = 0;
6575 bool posix_pathnames = lp_posix_pathnames();
6578 * Split the old name into directory and last component
6579 * strings. Note that unix_convert may have stripped off a
6580 * leading ./ from both name and newname if the rename is
6581 * at the root of the share. We need to make sure either both
6582 * name and newname contain a / character or neither of them do
6583 * as this is checked in resolve_wildcards().
6586 /* Split up the directory from the filename/mask. */
6587 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6588 &fname_src_dir, &fname_src_mask);
6589 if (!NT_STATUS_IS_OK(status)) {
6590 status = NT_STATUS_NO_MEMORY;
6591 goto out;
6595 * We should only check the mangled cache
6596 * here if unix_convert failed. This means
6597 * that the path in 'mask' doesn't exist
6598 * on the file system and so we need to look
6599 * for a possible mangle. This patch from
6600 * Tine Smukavec <valentin.smukavec@hermes.si>.
6603 if (!VALID_STAT(smb_fname_src->st) &&
6604 mangle_is_mangled(fname_src_mask, conn->params)) {
6605 char *new_mask = NULL;
6606 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6607 conn->params);
6608 if (new_mask) {
6609 TALLOC_FREE(fname_src_mask);
6610 fname_src_mask = new_mask;
6614 if (!src_has_wild) {
6615 files_struct *fsp;
6618 * Only one file needs to be renamed. Append the mask back
6619 * onto the directory.
6621 TALLOC_FREE(smb_fname_src->base_name);
6622 if (ISDOT(fname_src_dir)) {
6623 /* Ensure we use canonical names on open. */
6624 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6625 "%s",
6626 fname_src_mask);
6627 } else {
6628 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6629 "%s/%s",
6630 fname_src_dir,
6631 fname_src_mask);
6633 if (!smb_fname_src->base_name) {
6634 status = NT_STATUS_NO_MEMORY;
6635 goto out;
6638 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6639 "case_preserve = %d, short case preserve = %d, "
6640 "directory = %s, newname = %s, "
6641 "last_component_dest = %s\n",
6642 conn->case_sensitive, conn->case_preserve,
6643 conn->short_case_preserve,
6644 smb_fname_str_dbg(smb_fname_src),
6645 smb_fname_str_dbg(smb_fname_dst),
6646 smb_fname_dst->original_lcomp));
6648 /* The dest name still may have wildcards. */
6649 if (dest_has_wild) {
6650 char *fname_dst_mod = NULL;
6651 if (!resolve_wildcards(smb_fname_dst,
6652 smb_fname_src->base_name,
6653 smb_fname_dst->base_name,
6654 &fname_dst_mod)) {
6655 DEBUG(6, ("rename_internals: resolve_wildcards "
6656 "%s %s failed\n",
6657 smb_fname_src->base_name,
6658 smb_fname_dst->base_name));
6659 status = NT_STATUS_NO_MEMORY;
6660 goto out;
6662 TALLOC_FREE(smb_fname_dst->base_name);
6663 smb_fname_dst->base_name = fname_dst_mod;
6666 ZERO_STRUCT(smb_fname_src->st);
6667 if (posix_pathnames) {
6668 SMB_VFS_LSTAT(conn, smb_fname_src);
6669 } else {
6670 SMB_VFS_STAT(conn, smb_fname_src);
6673 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6674 create_options |= FILE_DIRECTORY_FILE;
6677 status = SMB_VFS_CREATE_FILE(
6678 conn, /* conn */
6679 req, /* req */
6680 0, /* root_dir_fid */
6681 smb_fname_src, /* fname */
6682 access_mask, /* access_mask */
6683 (FILE_SHARE_READ | /* share_access */
6684 FILE_SHARE_WRITE),
6685 FILE_OPEN, /* create_disposition*/
6686 create_options, /* create_options */
6687 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6688 0, /* oplock_request */
6689 0, /* allocation_size */
6690 0, /* private_flags */
6691 NULL, /* sd */
6692 NULL, /* ea_list */
6693 &fsp, /* result */
6694 NULL); /* pinfo */
6696 if (!NT_STATUS_IS_OK(status)) {
6697 DEBUG(3, ("Could not open rename source %s: %s\n",
6698 smb_fname_str_dbg(smb_fname_src),
6699 nt_errstr(status)));
6700 goto out;
6703 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6704 attrs, replace_if_exists);
6706 close_file(req, fsp, NORMAL_CLOSE);
6708 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6709 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6710 smb_fname_str_dbg(smb_fname_dst)));
6712 goto out;
6716 * Wildcards - process each file that matches.
6718 if (strequal(fname_src_mask, "????????.???")) {
6719 TALLOC_FREE(fname_src_mask);
6720 fname_src_mask = talloc_strdup(ctx, "*");
6721 if (!fname_src_mask) {
6722 status = NT_STATUS_NO_MEMORY;
6723 goto out;
6727 status = check_name(conn, fname_src_dir);
6728 if (!NT_STATUS_IS_OK(status)) {
6729 goto out;
6732 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6733 attrs);
6734 if (dir_hnd == NULL) {
6735 status = map_nt_error_from_unix(errno);
6736 goto out;
6739 status = NT_STATUS_NO_SUCH_FILE;
6741 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6742 * - gentest fix. JRA
6745 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6746 &talloced))) {
6747 files_struct *fsp = NULL;
6748 char *destname = NULL;
6749 bool sysdir_entry = False;
6751 /* Quick check for "." and ".." */
6752 if (ISDOT(dname) || ISDOTDOT(dname)) {
6753 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6754 sysdir_entry = True;
6755 } else {
6756 TALLOC_FREE(talloced);
6757 continue;
6761 if (!is_visible_file(conn, fname_src_dir, dname,
6762 &smb_fname_src->st, false)) {
6763 TALLOC_FREE(talloced);
6764 continue;
6767 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6768 TALLOC_FREE(talloced);
6769 continue;
6772 if (sysdir_entry) {
6773 status = NT_STATUS_OBJECT_NAME_INVALID;
6774 break;
6777 TALLOC_FREE(smb_fname_src->base_name);
6778 if (ISDOT(fname_src_dir)) {
6779 /* Ensure we use canonical names on open. */
6780 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6781 "%s",
6782 dname);
6783 } else {
6784 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6785 "%s/%s",
6786 fname_src_dir,
6787 dname);
6789 if (!smb_fname_src->base_name) {
6790 status = NT_STATUS_NO_MEMORY;
6791 goto out;
6794 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6795 smb_fname_dst->base_name,
6796 &destname)) {
6797 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6798 smb_fname_src->base_name, destname));
6799 TALLOC_FREE(talloced);
6800 continue;
6802 if (!destname) {
6803 status = NT_STATUS_NO_MEMORY;
6804 goto out;
6807 TALLOC_FREE(smb_fname_dst->base_name);
6808 smb_fname_dst->base_name = destname;
6810 ZERO_STRUCT(smb_fname_src->st);
6811 if (posix_pathnames) {
6812 SMB_VFS_LSTAT(conn, smb_fname_src);
6813 } else {
6814 SMB_VFS_STAT(conn, smb_fname_src);
6817 create_options = 0;
6819 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6820 create_options |= FILE_DIRECTORY_FILE;
6823 status = SMB_VFS_CREATE_FILE(
6824 conn, /* conn */
6825 req, /* req */
6826 0, /* root_dir_fid */
6827 smb_fname_src, /* fname */
6828 access_mask, /* access_mask */
6829 (FILE_SHARE_READ | /* share_access */
6830 FILE_SHARE_WRITE),
6831 FILE_OPEN, /* create_disposition*/
6832 create_options, /* create_options */
6833 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6834 0, /* oplock_request */
6835 0, /* allocation_size */
6836 0, /* private_flags */
6837 NULL, /* sd */
6838 NULL, /* ea_list */
6839 &fsp, /* result */
6840 NULL); /* pinfo */
6842 if (!NT_STATUS_IS_OK(status)) {
6843 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6844 "returned %s rename %s -> %s\n",
6845 nt_errstr(status),
6846 smb_fname_str_dbg(smb_fname_src),
6847 smb_fname_str_dbg(smb_fname_dst)));
6848 break;
6851 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6852 dname);
6853 if (!smb_fname_dst->original_lcomp) {
6854 status = NT_STATUS_NO_MEMORY;
6855 goto out;
6858 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6859 attrs, replace_if_exists);
6861 close_file(req, fsp, NORMAL_CLOSE);
6863 if (!NT_STATUS_IS_OK(status)) {
6864 DEBUG(3, ("rename_internals_fsp returned %s for "
6865 "rename %s -> %s\n", nt_errstr(status),
6866 smb_fname_str_dbg(smb_fname_src),
6867 smb_fname_str_dbg(smb_fname_dst)));
6868 break;
6871 count++;
6873 DEBUG(3,("rename_internals: doing rename on %s -> "
6874 "%s\n", smb_fname_str_dbg(smb_fname_src),
6875 smb_fname_str_dbg(smb_fname_src)));
6876 TALLOC_FREE(talloced);
6878 TALLOC_FREE(dir_hnd);
6880 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6881 status = map_nt_error_from_unix(errno);
6884 out:
6885 TALLOC_FREE(talloced);
6886 TALLOC_FREE(fname_src_dir);
6887 TALLOC_FREE(fname_src_mask);
6888 return status;
6891 /****************************************************************************
6892 Reply to a mv.
6893 ****************************************************************************/
6895 void reply_mv(struct smb_request *req)
6897 connection_struct *conn = req->conn;
6898 char *name = NULL;
6899 char *newname = NULL;
6900 const char *p;
6901 uint32 attrs;
6902 NTSTATUS status;
6903 bool src_has_wcard = False;
6904 bool dest_has_wcard = False;
6905 TALLOC_CTX *ctx = talloc_tos();
6906 struct smb_filename *smb_fname_src = NULL;
6907 struct smb_filename *smb_fname_dst = NULL;
6908 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6909 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6910 bool stream_rename = false;
6912 START_PROFILE(SMBmv);
6914 if (req->wct < 1) {
6915 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6916 goto out;
6919 attrs = SVAL(req->vwv+0, 0);
6921 p = (const char *)req->buf + 1;
6922 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6923 &status, &src_has_wcard);
6924 if (!NT_STATUS_IS_OK(status)) {
6925 reply_nterror(req, status);
6926 goto out;
6928 p++;
6929 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6930 &status, &dest_has_wcard);
6931 if (!NT_STATUS_IS_OK(status)) {
6932 reply_nterror(req, status);
6933 goto out;
6936 if (!lp_posix_pathnames()) {
6937 /* The newname must begin with a ':' if the
6938 name contains a ':'. */
6939 if (strchr_m(name, ':')) {
6940 if (newname[0] != ':') {
6941 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6942 goto out;
6944 stream_rename = true;
6948 status = filename_convert(ctx,
6949 conn,
6950 req->flags2 & FLAGS2_DFS_PATHNAMES,
6951 name,
6952 src_ucf_flags,
6953 &src_has_wcard,
6954 &smb_fname_src);
6956 if (!NT_STATUS_IS_OK(status)) {
6957 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6958 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6959 ERRSRV, ERRbadpath);
6960 goto out;
6962 reply_nterror(req, status);
6963 goto out;
6966 status = filename_convert(ctx,
6967 conn,
6968 req->flags2 & FLAGS2_DFS_PATHNAMES,
6969 newname,
6970 dst_ucf_flags,
6971 &dest_has_wcard,
6972 &smb_fname_dst);
6974 if (!NT_STATUS_IS_OK(status)) {
6975 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6976 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6977 ERRSRV, ERRbadpath);
6978 goto out;
6980 reply_nterror(req, status);
6981 goto out;
6984 if (stream_rename) {
6985 /* smb_fname_dst->base_name must be the same as
6986 smb_fname_src->base_name. */
6987 TALLOC_FREE(smb_fname_dst->base_name);
6988 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6989 smb_fname_src->base_name);
6990 if (!smb_fname_dst->base_name) {
6991 reply_nterror(req, NT_STATUS_NO_MEMORY);
6992 goto out;
6996 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6997 smb_fname_str_dbg(smb_fname_dst)));
6999 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7000 attrs, False, src_has_wcard, dest_has_wcard,
7001 DELETE_ACCESS);
7002 if (!NT_STATUS_IS_OK(status)) {
7003 if (open_was_deferred(req->sconn, req->mid)) {
7004 /* We have re-scheduled this call. */
7005 goto out;
7007 reply_nterror(req, status);
7008 goto out;
7011 reply_outbuf(req, 0, 0);
7012 out:
7013 TALLOC_FREE(smb_fname_src);
7014 TALLOC_FREE(smb_fname_dst);
7015 END_PROFILE(SMBmv);
7016 return;
7019 /*******************************************************************
7020 Copy a file as part of a reply_copy.
7021 ******************************************************************/
7024 * TODO: check error codes on all callers
7027 NTSTATUS copy_file(TALLOC_CTX *ctx,
7028 connection_struct *conn,
7029 struct smb_filename *smb_fname_src,
7030 struct smb_filename *smb_fname_dst,
7031 int ofun,
7032 int count,
7033 bool target_is_directory)
7035 struct smb_filename *smb_fname_dst_tmp = NULL;
7036 off_t ret=-1;
7037 files_struct *fsp1,*fsp2;
7038 uint32 dosattrs;
7039 uint32 new_create_disposition;
7040 NTSTATUS status;
7043 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
7044 if (!NT_STATUS_IS_OK(status)) {
7045 return status;
7049 * If the target is a directory, extract the last component from the
7050 * src filename and append it to the dst filename
7052 if (target_is_directory) {
7053 const char *p;
7055 /* dest/target can't be a stream if it's a directory. */
7056 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7058 p = strrchr_m(smb_fname_src->base_name,'/');
7059 if (p) {
7060 p++;
7061 } else {
7062 p = smb_fname_src->base_name;
7064 smb_fname_dst_tmp->base_name =
7065 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7067 if (!smb_fname_dst_tmp->base_name) {
7068 status = NT_STATUS_NO_MEMORY;
7069 goto out;
7073 status = vfs_file_exist(conn, smb_fname_src);
7074 if (!NT_STATUS_IS_OK(status)) {
7075 goto out;
7078 if (!target_is_directory && count) {
7079 new_create_disposition = FILE_OPEN;
7080 } else {
7081 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7082 0, ofun,
7083 NULL, NULL,
7084 &new_create_disposition,
7085 NULL,
7086 NULL)) {
7087 status = NT_STATUS_INVALID_PARAMETER;
7088 goto out;
7092 /* Open the src file for reading. */
7093 status = SMB_VFS_CREATE_FILE(
7094 conn, /* conn */
7095 NULL, /* req */
7096 0, /* root_dir_fid */
7097 smb_fname_src, /* fname */
7098 FILE_GENERIC_READ, /* access_mask */
7099 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7100 FILE_OPEN, /* create_disposition*/
7101 0, /* create_options */
7102 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7103 INTERNAL_OPEN_ONLY, /* oplock_request */
7104 0, /* allocation_size */
7105 0, /* private_flags */
7106 NULL, /* sd */
7107 NULL, /* ea_list */
7108 &fsp1, /* result */
7109 NULL); /* psbuf */
7111 if (!NT_STATUS_IS_OK(status)) {
7112 goto out;
7115 dosattrs = dos_mode(conn, smb_fname_src);
7117 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7118 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7121 /* Open the dst file for writing. */
7122 status = SMB_VFS_CREATE_FILE(
7123 conn, /* conn */
7124 NULL, /* req */
7125 0, /* root_dir_fid */
7126 smb_fname_dst, /* fname */
7127 FILE_GENERIC_WRITE, /* access_mask */
7128 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7129 new_create_disposition, /* create_disposition*/
7130 0, /* create_options */
7131 dosattrs, /* file_attributes */
7132 INTERNAL_OPEN_ONLY, /* oplock_request */
7133 0, /* allocation_size */
7134 0, /* private_flags */
7135 NULL, /* sd */
7136 NULL, /* ea_list */
7137 &fsp2, /* result */
7138 NULL); /* psbuf */
7140 if (!NT_STATUS_IS_OK(status)) {
7141 close_file(NULL, fsp1, ERROR_CLOSE);
7142 goto out;
7145 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7146 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7147 if (ret == -1) {
7148 DEBUG(0, ("error - vfs lseek returned error %s\n",
7149 strerror(errno)));
7150 status = map_nt_error_from_unix(errno);
7151 close_file(NULL, fsp1, ERROR_CLOSE);
7152 close_file(NULL, fsp2, ERROR_CLOSE);
7153 goto out;
7157 /* Do the actual copy. */
7158 if (smb_fname_src->st.st_ex_size) {
7159 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7160 } else {
7161 ret = 0;
7164 close_file(NULL, fsp1, NORMAL_CLOSE);
7166 /* Ensure the modtime is set correctly on the destination file. */
7167 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7170 * As we are opening fsp1 read-only we only expect
7171 * an error on close on fsp2 if we are out of space.
7172 * Thus we don't look at the error return from the
7173 * close of fsp1.
7175 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7177 if (!NT_STATUS_IS_OK(status)) {
7178 goto out;
7181 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7182 status = NT_STATUS_DISK_FULL;
7183 goto out;
7186 status = NT_STATUS_OK;
7188 out:
7189 TALLOC_FREE(smb_fname_dst_tmp);
7190 return status;
7193 /****************************************************************************
7194 Reply to a file copy.
7195 ****************************************************************************/
7197 void reply_copy(struct smb_request *req)
7199 connection_struct *conn = req->conn;
7200 struct smb_filename *smb_fname_src = NULL;
7201 struct smb_filename *smb_fname_dst = NULL;
7202 char *fname_src = NULL;
7203 char *fname_dst = NULL;
7204 char *fname_src_mask = NULL;
7205 char *fname_src_dir = NULL;
7206 const char *p;
7207 int count=0;
7208 int error = ERRnoaccess;
7209 int tid2;
7210 int ofun;
7211 int flags;
7212 bool target_is_directory=False;
7213 bool source_has_wild = False;
7214 bool dest_has_wild = False;
7215 NTSTATUS status;
7216 TALLOC_CTX *ctx = talloc_tos();
7218 START_PROFILE(SMBcopy);
7220 if (req->wct < 3) {
7221 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7222 goto out;
7225 tid2 = SVAL(req->vwv+0, 0);
7226 ofun = SVAL(req->vwv+1, 0);
7227 flags = SVAL(req->vwv+2, 0);
7229 p = (const char *)req->buf;
7230 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7231 &status, &source_has_wild);
7232 if (!NT_STATUS_IS_OK(status)) {
7233 reply_nterror(req, status);
7234 goto out;
7236 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7237 &status, &dest_has_wild);
7238 if (!NT_STATUS_IS_OK(status)) {
7239 reply_nterror(req, status);
7240 goto out;
7243 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7245 if (tid2 != conn->cnum) {
7246 /* can't currently handle inter share copies XXXX */
7247 DEBUG(3,("Rejecting inter-share copy\n"));
7248 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7249 goto out;
7252 status = filename_convert(ctx, conn,
7253 req->flags2 & FLAGS2_DFS_PATHNAMES,
7254 fname_src,
7255 UCF_COND_ALLOW_WCARD_LCOMP,
7256 &source_has_wild,
7257 &smb_fname_src);
7258 if (!NT_STATUS_IS_OK(status)) {
7259 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7260 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7261 ERRSRV, ERRbadpath);
7262 goto out;
7264 reply_nterror(req, status);
7265 goto out;
7268 status = filename_convert(ctx, conn,
7269 req->flags2 & FLAGS2_DFS_PATHNAMES,
7270 fname_dst,
7271 UCF_COND_ALLOW_WCARD_LCOMP,
7272 &dest_has_wild,
7273 &smb_fname_dst);
7274 if (!NT_STATUS_IS_OK(status)) {
7275 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7276 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7277 ERRSRV, ERRbadpath);
7278 goto out;
7280 reply_nterror(req, status);
7281 goto out;
7284 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7286 if ((flags&1) && target_is_directory) {
7287 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7288 goto out;
7291 if ((flags&2) && !target_is_directory) {
7292 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7293 goto out;
7296 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7297 /* wants a tree copy! XXXX */
7298 DEBUG(3,("Rejecting tree copy\n"));
7299 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7300 goto out;
7303 /* Split up the directory from the filename/mask. */
7304 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7305 &fname_src_dir, &fname_src_mask);
7306 if (!NT_STATUS_IS_OK(status)) {
7307 reply_nterror(req, NT_STATUS_NO_MEMORY);
7308 goto out;
7312 * We should only check the mangled cache
7313 * here if unix_convert failed. This means
7314 * that the path in 'mask' doesn't exist
7315 * on the file system and so we need to look
7316 * for a possible mangle. This patch from
7317 * Tine Smukavec <valentin.smukavec@hermes.si>.
7319 if (!VALID_STAT(smb_fname_src->st) &&
7320 mangle_is_mangled(fname_src_mask, conn->params)) {
7321 char *new_mask = NULL;
7322 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7323 &new_mask, conn->params);
7325 /* Use demangled name if one was successfully found. */
7326 if (new_mask) {
7327 TALLOC_FREE(fname_src_mask);
7328 fname_src_mask = new_mask;
7332 if (!source_has_wild) {
7335 * Only one file needs to be copied. Append the mask back onto
7336 * the directory.
7338 TALLOC_FREE(smb_fname_src->base_name);
7339 if (ISDOT(fname_src_dir)) {
7340 /* Ensure we use canonical names on open. */
7341 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7342 "%s",
7343 fname_src_mask);
7344 } else {
7345 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7346 "%s/%s",
7347 fname_src_dir,
7348 fname_src_mask);
7350 if (!smb_fname_src->base_name) {
7351 reply_nterror(req, NT_STATUS_NO_MEMORY);
7352 goto out;
7355 if (dest_has_wild) {
7356 char *fname_dst_mod = NULL;
7357 if (!resolve_wildcards(smb_fname_dst,
7358 smb_fname_src->base_name,
7359 smb_fname_dst->base_name,
7360 &fname_dst_mod)) {
7361 reply_nterror(req, NT_STATUS_NO_MEMORY);
7362 goto out;
7364 TALLOC_FREE(smb_fname_dst->base_name);
7365 smb_fname_dst->base_name = fname_dst_mod;
7368 status = check_name(conn, smb_fname_src->base_name);
7369 if (!NT_STATUS_IS_OK(status)) {
7370 reply_nterror(req, status);
7371 goto out;
7374 status = check_name(conn, smb_fname_dst->base_name);
7375 if (!NT_STATUS_IS_OK(status)) {
7376 reply_nterror(req, status);
7377 goto out;
7380 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7381 ofun, count, target_is_directory);
7383 if(!NT_STATUS_IS_OK(status)) {
7384 reply_nterror(req, status);
7385 goto out;
7386 } else {
7387 count++;
7389 } else {
7390 struct smb_Dir *dir_hnd = NULL;
7391 const char *dname = NULL;
7392 char *talloced = NULL;
7393 long offset = 0;
7396 * There is a wildcard that requires us to actually read the
7397 * src dir and copy each file matching the mask to the dst.
7398 * Right now streams won't be copied, but this could
7399 * presumably be added with a nested loop for reach dir entry.
7401 SMB_ASSERT(!smb_fname_src->stream_name);
7402 SMB_ASSERT(!smb_fname_dst->stream_name);
7404 smb_fname_src->stream_name = NULL;
7405 smb_fname_dst->stream_name = NULL;
7407 if (strequal(fname_src_mask,"????????.???")) {
7408 TALLOC_FREE(fname_src_mask);
7409 fname_src_mask = talloc_strdup(ctx, "*");
7410 if (!fname_src_mask) {
7411 reply_nterror(req, NT_STATUS_NO_MEMORY);
7412 goto out;
7416 status = check_name(conn, fname_src_dir);
7417 if (!NT_STATUS_IS_OK(status)) {
7418 reply_nterror(req, status);
7419 goto out;
7422 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7423 if (dir_hnd == NULL) {
7424 status = map_nt_error_from_unix(errno);
7425 reply_nterror(req, status);
7426 goto out;
7429 error = ERRbadfile;
7431 /* Iterate over the src dir copying each entry to the dst. */
7432 while ((dname = ReadDirName(dir_hnd, &offset,
7433 &smb_fname_src->st, &talloced))) {
7434 char *destname = NULL;
7436 if (ISDOT(dname) || ISDOTDOT(dname)) {
7437 TALLOC_FREE(talloced);
7438 continue;
7441 if (!is_visible_file(conn, fname_src_dir, dname,
7442 &smb_fname_src->st, false)) {
7443 TALLOC_FREE(talloced);
7444 continue;
7447 if(!mask_match(dname, fname_src_mask,
7448 conn->case_sensitive)) {
7449 TALLOC_FREE(talloced);
7450 continue;
7453 error = ERRnoaccess;
7455 /* Get the src smb_fname struct setup. */
7456 TALLOC_FREE(smb_fname_src->base_name);
7457 if (ISDOT(fname_src_dir)) {
7458 /* Ensure we use canonical names on open. */
7459 smb_fname_src->base_name =
7460 talloc_asprintf(smb_fname_src, "%s",
7461 dname);
7462 } else {
7463 smb_fname_src->base_name =
7464 talloc_asprintf(smb_fname_src, "%s/%s",
7465 fname_src_dir, dname);
7468 if (!smb_fname_src->base_name) {
7469 TALLOC_FREE(dir_hnd);
7470 TALLOC_FREE(talloced);
7471 reply_nterror(req, NT_STATUS_NO_MEMORY);
7472 goto out;
7475 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7476 smb_fname_dst->base_name,
7477 &destname)) {
7478 TALLOC_FREE(talloced);
7479 continue;
7481 if (!destname) {
7482 TALLOC_FREE(dir_hnd);
7483 TALLOC_FREE(talloced);
7484 reply_nterror(req, NT_STATUS_NO_MEMORY);
7485 goto out;
7488 TALLOC_FREE(smb_fname_dst->base_name);
7489 smb_fname_dst->base_name = destname;
7491 status = check_name(conn, smb_fname_src->base_name);
7492 if (!NT_STATUS_IS_OK(status)) {
7493 TALLOC_FREE(dir_hnd);
7494 TALLOC_FREE(talloced);
7495 reply_nterror(req, status);
7496 goto out;
7499 status = check_name(conn, smb_fname_dst->base_name);
7500 if (!NT_STATUS_IS_OK(status)) {
7501 TALLOC_FREE(dir_hnd);
7502 TALLOC_FREE(talloced);
7503 reply_nterror(req, status);
7504 goto out;
7507 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7508 smb_fname_src->base_name,
7509 smb_fname_dst->base_name));
7511 status = copy_file(ctx, conn, smb_fname_src,
7512 smb_fname_dst, ofun, count,
7513 target_is_directory);
7514 if (NT_STATUS_IS_OK(status)) {
7515 count++;
7518 TALLOC_FREE(talloced);
7520 TALLOC_FREE(dir_hnd);
7523 if (count == 0) {
7524 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7525 goto out;
7528 reply_outbuf(req, 1, 0);
7529 SSVAL(req->outbuf,smb_vwv0,count);
7530 out:
7531 TALLOC_FREE(smb_fname_src);
7532 TALLOC_FREE(smb_fname_dst);
7533 TALLOC_FREE(fname_src);
7534 TALLOC_FREE(fname_dst);
7535 TALLOC_FREE(fname_src_mask);
7536 TALLOC_FREE(fname_src_dir);
7538 END_PROFILE(SMBcopy);
7539 return;
7542 #undef DBGC_CLASS
7543 #define DBGC_CLASS DBGC_LOCKING
7545 /****************************************************************************
7546 Get a lock pid, dealing with large count requests.
7547 ****************************************************************************/
7549 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7550 bool large_file_format)
7552 if(!large_file_format)
7553 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7554 else
7555 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7558 /****************************************************************************
7559 Get a lock count, dealing with large count requests.
7560 ****************************************************************************/
7562 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7563 bool large_file_format)
7565 uint64_t count = 0;
7567 if(!large_file_format) {
7568 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7569 } else {
7571 #if defined(HAVE_LONGLONG)
7572 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7573 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7574 #else /* HAVE_LONGLONG */
7577 * NT4.x seems to be broken in that it sends large file (64 bit)
7578 * lockingX calls even if the CAP_LARGE_FILES was *not*
7579 * negotiated. For boxes without large unsigned ints truncate the
7580 * lock count by dropping the top 32 bits.
7583 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7584 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7585 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7586 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7587 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7590 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7591 #endif /* HAVE_LONGLONG */
7594 return count;
7597 #if !defined(HAVE_LONGLONG)
7598 /****************************************************************************
7599 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7600 ****************************************************************************/
7602 static uint32 map_lock_offset(uint32 high, uint32 low)
7604 unsigned int i;
7605 uint32 mask = 0;
7606 uint32 highcopy = high;
7609 * Try and find out how many significant bits there are in high.
7612 for(i = 0; highcopy; i++)
7613 highcopy >>= 1;
7616 * We use 31 bits not 32 here as POSIX
7617 * lock offsets may not be negative.
7620 mask = (~0) << (31 - i);
7622 if(low & mask)
7623 return 0; /* Fail. */
7625 high <<= (31 - i);
7627 return (high|low);
7629 #endif /* !defined(HAVE_LONGLONG) */
7631 /****************************************************************************
7632 Get a lock offset, dealing with large offset requests.
7633 ****************************************************************************/
7635 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7636 bool large_file_format, bool *err)
7638 uint64_t offset = 0;
7640 *err = False;
7642 if(!large_file_format) {
7643 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7644 } else {
7646 #if defined(HAVE_LONGLONG)
7647 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7648 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7649 #else /* HAVE_LONGLONG */
7652 * NT4.x seems to be broken in that it sends large file (64 bit)
7653 * lockingX calls even if the CAP_LARGE_FILES was *not*
7654 * negotiated. For boxes without large unsigned ints mangle the
7655 * lock offset by mapping the top 32 bits onto the lower 32.
7658 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7659 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7660 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7661 uint32 new_low = 0;
7663 if((new_low = map_lock_offset(high, low)) == 0) {
7664 *err = True;
7665 return (uint64_t)-1;
7668 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7669 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7670 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7671 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7674 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7675 #endif /* HAVE_LONGLONG */
7678 return offset;
7681 NTSTATUS smbd_do_locking(struct smb_request *req,
7682 files_struct *fsp,
7683 uint8_t type,
7684 int32_t timeout,
7685 uint16_t num_ulocks,
7686 struct smbd_lock_element *ulocks,
7687 uint16_t num_locks,
7688 struct smbd_lock_element *locks,
7689 bool *async)
7691 connection_struct *conn = req->conn;
7692 int i;
7693 NTSTATUS status = NT_STATUS_OK;
7695 *async = false;
7697 /* Data now points at the beginning of the list
7698 of smb_unlkrng structs */
7699 for(i = 0; i < (int)num_ulocks; i++) {
7700 struct smbd_lock_element *e = &ulocks[i];
7702 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7703 "pid %u, file %s\n",
7704 (double)e->offset,
7705 (double)e->count,
7706 (unsigned int)e->smblctx,
7707 fsp_str_dbg(fsp)));
7709 if (e->brltype != UNLOCK_LOCK) {
7710 /* this can only happen with SMB2 */
7711 return NT_STATUS_INVALID_PARAMETER;
7714 status = do_unlock(req->sconn->msg_ctx,
7715 fsp,
7716 e->smblctx,
7717 e->count,
7718 e->offset,
7719 WINDOWS_LOCK);
7721 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7722 nt_errstr(status)));
7724 if (!NT_STATUS_IS_OK(status)) {
7725 return status;
7729 /* Setup the timeout in seconds. */
7731 if (!lp_blocking_locks(SNUM(conn))) {
7732 timeout = 0;
7735 /* Data now points at the beginning of the list
7736 of smb_lkrng structs */
7738 for(i = 0; i < (int)num_locks; i++) {
7739 struct smbd_lock_element *e = &locks[i];
7741 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7742 "%llu, file %s timeout = %d\n",
7743 (double)e->offset,
7744 (double)e->count,
7745 (unsigned long long)e->smblctx,
7746 fsp_str_dbg(fsp),
7747 (int)timeout));
7749 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7750 struct blocking_lock_record *blr = NULL;
7752 if (num_locks > 1) {
7754 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7755 * if the lock vector contains one entry. When given mutliple cancel
7756 * requests in a single PDU we expect the server to return an
7757 * error. Windows servers seem to accept the request but only
7758 * cancel the first lock.
7759 * JRA - Do what Windows does (tm) :-).
7762 #if 0
7763 /* MS-CIFS (2.2.4.32.1) behavior. */
7764 return NT_STATUS_DOS(ERRDOS,
7765 ERRcancelviolation);
7766 #else
7767 /* Windows behavior. */
7768 if (i != 0) {
7769 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7770 "cancel request\n"));
7771 continue;
7773 #endif
7776 if (lp_blocking_locks(SNUM(conn))) {
7778 /* Schedule a message to ourselves to
7779 remove the blocking lock record and
7780 return the right error. */
7782 blr = blocking_lock_cancel_smb1(fsp,
7783 e->smblctx,
7784 e->offset,
7785 e->count,
7786 WINDOWS_LOCK,
7787 type,
7788 NT_STATUS_FILE_LOCK_CONFLICT);
7789 if (blr == NULL) {
7790 return NT_STATUS_DOS(
7791 ERRDOS,
7792 ERRcancelviolation);
7795 /* Remove a matching pending lock. */
7796 status = do_lock_cancel(fsp,
7797 e->smblctx,
7798 e->count,
7799 e->offset,
7800 WINDOWS_LOCK,
7801 blr);
7802 } else {
7803 bool blocking_lock = timeout ? true : false;
7804 bool defer_lock = false;
7805 struct byte_range_lock *br_lck;
7806 uint64_t block_smblctx;
7808 br_lck = do_lock(req->sconn->msg_ctx,
7809 fsp,
7810 e->smblctx,
7811 e->count,
7812 e->offset,
7813 e->brltype,
7814 WINDOWS_LOCK,
7815 blocking_lock,
7816 &status,
7817 &block_smblctx,
7818 NULL);
7820 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7821 /* Windows internal resolution for blocking locks seems
7822 to be about 200ms... Don't wait for less than that. JRA. */
7823 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7824 timeout = lp_lock_spin_time();
7826 defer_lock = true;
7829 /* If a lock sent with timeout of zero would fail, and
7830 * this lock has been requested multiple times,
7831 * according to brl_lock_failed() we convert this
7832 * request to a blocking lock with a timeout of between
7833 * 150 - 300 milliseconds.
7835 * If lp_lock_spin_time() has been set to 0, we skip
7836 * this blocking retry and fail immediately.
7838 * Replacement for do_lock_spin(). JRA. */
7840 if (!req->sconn->using_smb2 &&
7841 br_lck && lp_blocking_locks(SNUM(conn)) &&
7842 lp_lock_spin_time() && !blocking_lock &&
7843 NT_STATUS_EQUAL((status),
7844 NT_STATUS_FILE_LOCK_CONFLICT))
7846 defer_lock = true;
7847 timeout = lp_lock_spin_time();
7850 if (br_lck && defer_lock) {
7852 * A blocking lock was requested. Package up
7853 * this smb into a queued request and push it
7854 * onto the blocking lock queue.
7856 if(push_blocking_lock_request(br_lck,
7857 req,
7858 fsp,
7859 timeout,
7861 e->smblctx,
7862 e->brltype,
7863 WINDOWS_LOCK,
7864 e->offset,
7865 e->count,
7866 block_smblctx)) {
7867 TALLOC_FREE(br_lck);
7868 *async = true;
7869 return NT_STATUS_OK;
7873 TALLOC_FREE(br_lck);
7876 if (!NT_STATUS_IS_OK(status)) {
7877 break;
7881 /* If any of the above locks failed, then we must unlock
7882 all of the previous locks (X/Open spec). */
7884 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7886 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7887 i = -1; /* we want to skip the for loop */
7891 * Ensure we don't do a remove on the lock that just failed,
7892 * as under POSIX rules, if we have a lock already there, we
7893 * will delete it (and we shouldn't) .....
7895 for(i--; i >= 0; i--) {
7896 struct smbd_lock_element *e = &locks[i];
7898 do_unlock(req->sconn->msg_ctx,
7899 fsp,
7900 e->smblctx,
7901 e->count,
7902 e->offset,
7903 WINDOWS_LOCK);
7905 return status;
7908 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7909 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7911 return NT_STATUS_OK;
7914 /****************************************************************************
7915 Reply to a lockingX request.
7916 ****************************************************************************/
7918 void reply_lockingX(struct smb_request *req)
7920 connection_struct *conn = req->conn;
7921 files_struct *fsp;
7922 unsigned char locktype;
7923 unsigned char oplocklevel;
7924 uint16 num_ulocks;
7925 uint16 num_locks;
7926 int32 lock_timeout;
7927 int i;
7928 const uint8_t *data;
7929 bool large_file_format;
7930 bool err;
7931 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7932 struct smbd_lock_element *ulocks;
7933 struct smbd_lock_element *locks;
7934 bool async = false;
7936 START_PROFILE(SMBlockingX);
7938 if (req->wct < 8) {
7939 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7940 END_PROFILE(SMBlockingX);
7941 return;
7944 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7945 locktype = CVAL(req->vwv+3, 0);
7946 oplocklevel = CVAL(req->vwv+3, 1);
7947 num_ulocks = SVAL(req->vwv+6, 0);
7948 num_locks = SVAL(req->vwv+7, 0);
7949 lock_timeout = IVAL(req->vwv+4, 0);
7950 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7952 if (!check_fsp(conn, req, fsp)) {
7953 END_PROFILE(SMBlockingX);
7954 return;
7957 data = req->buf;
7959 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7960 /* we don't support these - and CANCEL_LOCK makes w2k
7961 and XP reboot so I don't really want to be
7962 compatible! (tridge) */
7963 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7964 END_PROFILE(SMBlockingX);
7965 return;
7968 /* Check if this is an oplock break on a file
7969 we have granted an oplock on.
7971 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7972 /* Client can insist on breaking to none. */
7973 bool break_to_none = (oplocklevel == 0);
7974 bool result;
7976 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7977 "for %s\n", (unsigned int)oplocklevel,
7978 fsp_fnum_dbg(fsp)));
7981 * Make sure we have granted an exclusive or batch oplock on
7982 * this file.
7985 if (fsp->oplock_type == 0) {
7987 /* The Samba4 nbench simulator doesn't understand
7988 the difference between break to level2 and break
7989 to none from level2 - it sends oplock break
7990 replies in both cases. Don't keep logging an error
7991 message here - just ignore it. JRA. */
7993 DEBUG(5,("reply_lockingX: Error : oplock break from "
7994 "client for %s (oplock=%d) and no "
7995 "oplock granted on this file (%s).\n",
7996 fsp_fnum_dbg(fsp), fsp->oplock_type,
7997 fsp_str_dbg(fsp)));
7999 /* if this is a pure oplock break request then don't
8000 * send a reply */
8001 if (num_locks == 0 && num_ulocks == 0) {
8002 END_PROFILE(SMBlockingX);
8003 return;
8004 } else {
8005 END_PROFILE(SMBlockingX);
8006 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8007 return;
8011 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8012 (break_to_none)) {
8013 result = remove_oplock(fsp);
8014 } else {
8015 result = downgrade_oplock(fsp);
8018 if (!result) {
8019 DEBUG(0, ("reply_lockingX: error in removing "
8020 "oplock on file %s\n", fsp_str_dbg(fsp)));
8021 /* Hmmm. Is this panic justified? */
8022 smb_panic("internal tdb error");
8025 reply_to_oplock_break_requests(fsp);
8027 /* if this is a pure oplock break request then don't send a
8028 * reply */
8029 if (num_locks == 0 && num_ulocks == 0) {
8030 /* Sanity check - ensure a pure oplock break is not a
8031 chained request. */
8032 if(CVAL(req->vwv+0, 0) != 0xff)
8033 DEBUG(0,("reply_lockingX: Error : pure oplock "
8034 "break is a chained %d request !\n",
8035 (unsigned int)CVAL(req->vwv+0, 0)));
8036 END_PROFILE(SMBlockingX);
8037 return;
8041 if (req->buflen <
8042 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8043 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8044 END_PROFILE(SMBlockingX);
8045 return;
8048 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8049 if (ulocks == NULL) {
8050 reply_nterror(req, NT_STATUS_NO_MEMORY);
8051 END_PROFILE(SMBlockingX);
8052 return;
8055 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8056 if (locks == NULL) {
8057 reply_nterror(req, NT_STATUS_NO_MEMORY);
8058 END_PROFILE(SMBlockingX);
8059 return;
8062 /* Data now points at the beginning of the list
8063 of smb_unlkrng structs */
8064 for(i = 0; i < (int)num_ulocks; i++) {
8065 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8066 ulocks[i].count = get_lock_count(data, i, large_file_format);
8067 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8068 ulocks[i].brltype = UNLOCK_LOCK;
8071 * There is no error code marked "stupid client bug".... :-).
8073 if(err) {
8074 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8075 END_PROFILE(SMBlockingX);
8076 return;
8080 /* Now do any requested locks */
8081 data += ((large_file_format ? 20 : 10)*num_ulocks);
8083 /* Data now points at the beginning of the list
8084 of smb_lkrng structs */
8086 for(i = 0; i < (int)num_locks; i++) {
8087 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8088 locks[i].count = get_lock_count(data, i, large_file_format);
8089 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8091 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8092 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8093 locks[i].brltype = PENDING_READ_LOCK;
8094 } else {
8095 locks[i].brltype = READ_LOCK;
8097 } else {
8098 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8099 locks[i].brltype = PENDING_WRITE_LOCK;
8100 } else {
8101 locks[i].brltype = WRITE_LOCK;
8106 * There is no error code marked "stupid client bug".... :-).
8108 if(err) {
8109 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8110 END_PROFILE(SMBlockingX);
8111 return;
8115 status = smbd_do_locking(req, fsp,
8116 locktype, lock_timeout,
8117 num_ulocks, ulocks,
8118 num_locks, locks,
8119 &async);
8120 if (!NT_STATUS_IS_OK(status)) {
8121 END_PROFILE(SMBlockingX);
8122 reply_nterror(req, status);
8123 return;
8125 if (async) {
8126 END_PROFILE(SMBlockingX);
8127 return;
8130 reply_outbuf(req, 2, 0);
8131 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8132 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8134 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8135 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8137 END_PROFILE(SMBlockingX);
8140 #undef DBGC_CLASS
8141 #define DBGC_CLASS DBGC_ALL
8143 /****************************************************************************
8144 Reply to a SMBreadbmpx (read block multiplex) request.
8145 Always reply with an error, if someone has a platform really needs this,
8146 please contact vl@samba.org
8147 ****************************************************************************/
8149 void reply_readbmpx(struct smb_request *req)
8151 START_PROFILE(SMBreadBmpx);
8152 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8153 END_PROFILE(SMBreadBmpx);
8154 return;
8157 /****************************************************************************
8158 Reply to a SMBreadbs (read block multiplex secondary) request.
8159 Always reply with an error, if someone has a platform really needs this,
8160 please contact vl@samba.org
8161 ****************************************************************************/
8163 void reply_readbs(struct smb_request *req)
8165 START_PROFILE(SMBreadBs);
8166 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8167 END_PROFILE(SMBreadBs);
8168 return;
8171 /****************************************************************************
8172 Reply to a SMBsetattrE.
8173 ****************************************************************************/
8175 void reply_setattrE(struct smb_request *req)
8177 connection_struct *conn = req->conn;
8178 struct smb_file_time ft;
8179 files_struct *fsp;
8180 NTSTATUS status;
8182 START_PROFILE(SMBsetattrE);
8183 ZERO_STRUCT(ft);
8185 if (req->wct < 7) {
8186 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8187 goto out;
8190 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8192 if(!fsp || (fsp->conn != conn)) {
8193 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8194 goto out;
8198 * Convert the DOS times into unix times.
8201 ft.atime = convert_time_t_to_timespec(
8202 srv_make_unix_date2(req->vwv+3));
8203 ft.mtime = convert_time_t_to_timespec(
8204 srv_make_unix_date2(req->vwv+5));
8205 ft.create_time = convert_time_t_to_timespec(
8206 srv_make_unix_date2(req->vwv+1));
8208 reply_outbuf(req, 0, 0);
8211 * Patch from Ray Frush <frush@engr.colostate.edu>
8212 * Sometimes times are sent as zero - ignore them.
8215 /* Ensure we have a valid stat struct for the source. */
8216 status = vfs_stat_fsp(fsp);
8217 if (!NT_STATUS_IS_OK(status)) {
8218 reply_nterror(req, status);
8219 goto out;
8222 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8223 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8224 goto out;
8227 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8228 if (!NT_STATUS_IS_OK(status)) {
8229 reply_nterror(req, status);
8230 goto out;
8233 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8234 " createtime=%u\n",
8235 fsp_fnum_dbg(fsp),
8236 (unsigned int)ft.atime.tv_sec,
8237 (unsigned int)ft.mtime.tv_sec,
8238 (unsigned int)ft.create_time.tv_sec
8240 out:
8241 END_PROFILE(SMBsetattrE);
8242 return;
8246 /* Back from the dead for OS/2..... JRA. */
8248 /****************************************************************************
8249 Reply to a SMBwritebmpx (write block multiplex primary) request.
8250 Always reply with an error, if someone has a platform really needs this,
8251 please contact vl@samba.org
8252 ****************************************************************************/
8254 void reply_writebmpx(struct smb_request *req)
8256 START_PROFILE(SMBwriteBmpx);
8257 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8258 END_PROFILE(SMBwriteBmpx);
8259 return;
8262 /****************************************************************************
8263 Reply to a SMBwritebs (write block multiplex secondary) request.
8264 Always reply with an error, if someone has a platform really needs this,
8265 please contact vl@samba.org
8266 ****************************************************************************/
8268 void reply_writebs(struct smb_request *req)
8270 START_PROFILE(SMBwriteBs);
8271 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8272 END_PROFILE(SMBwriteBs);
8273 return;
8276 /****************************************************************************
8277 Reply to a SMBgetattrE.
8278 ****************************************************************************/
8280 void reply_getattrE(struct smb_request *req)
8282 connection_struct *conn = req->conn;
8283 int mode;
8284 files_struct *fsp;
8285 struct timespec create_ts;
8287 START_PROFILE(SMBgetattrE);
8289 if (req->wct < 1) {
8290 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8291 END_PROFILE(SMBgetattrE);
8292 return;
8295 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8297 if(!fsp || (fsp->conn != conn)) {
8298 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8299 END_PROFILE(SMBgetattrE);
8300 return;
8303 /* Do an fstat on this file */
8304 if(fsp_stat(fsp)) {
8305 reply_nterror(req, map_nt_error_from_unix(errno));
8306 END_PROFILE(SMBgetattrE);
8307 return;
8310 mode = dos_mode(conn, fsp->fsp_name);
8313 * Convert the times into dos times. Set create
8314 * date to be last modify date as UNIX doesn't save
8315 * this.
8318 reply_outbuf(req, 11, 0);
8320 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8321 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8322 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8323 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8324 /* Should we check pending modtime here ? JRA */
8325 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8326 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8328 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8329 SIVAL(req->outbuf, smb_vwv6, 0);
8330 SIVAL(req->outbuf, smb_vwv8, 0);
8331 } else {
8332 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8333 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8334 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8336 SSVAL(req->outbuf,smb_vwv10, mode);
8338 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8340 END_PROFILE(SMBgetattrE);
8341 return;