smbd: Rename parameter "i" to "idx"
[Samba.git] / source3 / smbd / reply.c
blob2d729ece3b12ebb217b286746027b21f618665fb
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 (create_disposition == FILE_CREATE)
1921 ? UCF_CREATING_FILE : 0,
1922 NULL,
1923 &smb_fname);
1924 if (!NT_STATUS_IS_OK(status)) {
1925 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1926 reply_botherror(req,
1927 NT_STATUS_PATH_NOT_COVERED,
1928 ERRSRV, ERRbadpath);
1929 goto out;
1931 reply_nterror(req, status);
1932 goto out;
1935 status = SMB_VFS_CREATE_FILE(
1936 conn, /* conn */
1937 req, /* req */
1938 0, /* root_dir_fid */
1939 smb_fname, /* fname */
1940 access_mask, /* access_mask */
1941 share_mode, /* share_access */
1942 create_disposition, /* create_disposition*/
1943 create_options, /* create_options */
1944 dos_attr, /* file_attributes */
1945 oplock_request, /* oplock_request */
1946 0, /* allocation_size */
1947 private_flags,
1948 NULL, /* sd */
1949 NULL, /* ea_list */
1950 &fsp, /* result */
1951 &info); /* pinfo */
1953 if (!NT_STATUS_IS_OK(status)) {
1954 if (open_was_deferred(req->sconn, req->mid)) {
1955 /* We have re-scheduled this call. */
1956 goto out;
1958 reply_openerror(req, status);
1959 goto out;
1962 size = smb_fname->st.st_ex_size;
1963 fattr = dos_mode(conn, smb_fname);
1965 /* Deal with other possible opens having a modified
1966 write time. JRA. */
1967 if (ask_sharemode) {
1968 struct timespec write_time_ts;
1970 ZERO_STRUCT(write_time_ts);
1971 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1972 if (!null_timespec(write_time_ts)) {
1973 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1977 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1979 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1980 DEBUG(3,("attempt to open a directory %s\n",
1981 fsp_str_dbg(fsp)));
1982 close_file(req, fsp, ERROR_CLOSE);
1983 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1984 ERRDOS, ERRnoaccess);
1985 goto out;
1988 reply_outbuf(req, 7, 0);
1989 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1990 SSVAL(req->outbuf,smb_vwv1,fattr);
1991 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1992 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1993 } else {
1994 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1996 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1997 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1999 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2000 SCVAL(req->outbuf,smb_flg,
2001 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2004 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2005 SCVAL(req->outbuf,smb_flg,
2006 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2008 out:
2009 TALLOC_FREE(smb_fname);
2010 END_PROFILE(SMBopen);
2011 return;
2014 /****************************************************************************
2015 Reply to an open and X.
2016 ****************************************************************************/
2018 void reply_open_and_X(struct smb_request *req)
2020 connection_struct *conn = req->conn;
2021 struct smb_filename *smb_fname = NULL;
2022 char *fname = NULL;
2023 uint16 open_flags;
2024 int deny_mode;
2025 uint32 smb_attr;
2026 /* Breakout the oplock request bits so we can set the
2027 reply bits separately. */
2028 int ex_oplock_request;
2029 int core_oplock_request;
2030 int oplock_request;
2031 #if 0
2032 int smb_sattr = SVAL(req->vwv+4, 0);
2033 uint32 smb_time = make_unix_date3(req->vwv+6);
2034 #endif
2035 int smb_ofun;
2036 uint32 fattr=0;
2037 int mtime=0;
2038 int smb_action = 0;
2039 files_struct *fsp;
2040 NTSTATUS status;
2041 uint64_t allocation_size;
2042 ssize_t retval = -1;
2043 uint32 access_mask;
2044 uint32 share_mode;
2045 uint32 create_disposition;
2046 uint32 create_options = 0;
2047 uint32_t private_flags = 0;
2048 TALLOC_CTX *ctx = talloc_tos();
2050 START_PROFILE(SMBopenX);
2052 if (req->wct < 15) {
2053 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2054 goto out;
2057 open_flags = SVAL(req->vwv+2, 0);
2058 deny_mode = SVAL(req->vwv+3, 0);
2059 smb_attr = SVAL(req->vwv+5, 0);
2060 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2061 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2062 oplock_request = ex_oplock_request | core_oplock_request;
2063 smb_ofun = SVAL(req->vwv+8, 0);
2064 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2066 /* If it's an IPC, pass off the pipe handler. */
2067 if (IS_IPC(conn)) {
2068 if (lp_nt_pipe_support()) {
2069 reply_open_pipe_and_X(conn, req);
2070 } else {
2071 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2073 goto out;
2076 /* XXXX we need to handle passed times, sattr and flags */
2077 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2078 STR_TERMINATE, &status);
2079 if (!NT_STATUS_IS_OK(status)) {
2080 reply_nterror(req, status);
2081 goto out;
2084 if (!map_open_params_to_ntcreate(fname, deny_mode,
2085 smb_ofun,
2086 &access_mask, &share_mode,
2087 &create_disposition,
2088 &create_options,
2089 &private_flags)) {
2090 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2091 goto out;
2094 status = filename_convert(ctx,
2095 conn,
2096 req->flags2 & FLAGS2_DFS_PATHNAMES,
2097 fname,
2098 (create_disposition == FILE_CREATE)
2099 ? UCF_CREATING_FILE : 0,
2100 NULL,
2101 &smb_fname);
2102 if (!NT_STATUS_IS_OK(status)) {
2103 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2104 reply_botherror(req,
2105 NT_STATUS_PATH_NOT_COVERED,
2106 ERRSRV, ERRbadpath);
2107 goto out;
2109 reply_nterror(req, status);
2110 goto out;
2113 status = SMB_VFS_CREATE_FILE(
2114 conn, /* conn */
2115 req, /* req */
2116 0, /* root_dir_fid */
2117 smb_fname, /* fname */
2118 access_mask, /* access_mask */
2119 share_mode, /* share_access */
2120 create_disposition, /* create_disposition*/
2121 create_options, /* create_options */
2122 smb_attr, /* file_attributes */
2123 oplock_request, /* oplock_request */
2124 0, /* allocation_size */
2125 private_flags,
2126 NULL, /* sd */
2127 NULL, /* ea_list */
2128 &fsp, /* result */
2129 &smb_action); /* pinfo */
2131 if (!NT_STATUS_IS_OK(status)) {
2132 if (open_was_deferred(req->sconn, req->mid)) {
2133 /* We have re-scheduled this call. */
2134 goto out;
2136 reply_openerror(req, status);
2137 goto out;
2140 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2141 if the file is truncated or created. */
2142 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2143 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2144 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2145 close_file(req, fsp, ERROR_CLOSE);
2146 reply_nterror(req, NT_STATUS_DISK_FULL);
2147 goto out;
2149 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2150 if (retval < 0) {
2151 close_file(req, fsp, ERROR_CLOSE);
2152 reply_nterror(req, NT_STATUS_DISK_FULL);
2153 goto out;
2155 status = vfs_stat_fsp(fsp);
2156 if (!NT_STATUS_IS_OK(status)) {
2157 close_file(req, fsp, ERROR_CLOSE);
2158 reply_nterror(req, status);
2159 goto out;
2163 fattr = dos_mode(conn, fsp->fsp_name);
2164 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2165 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2166 close_file(req, fsp, ERROR_CLOSE);
2167 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2168 goto out;
2171 /* If the caller set the extended oplock request bit
2172 and we granted one (by whatever means) - set the
2173 correct bit for extended oplock reply.
2176 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2177 smb_action |= EXTENDED_OPLOCK_GRANTED;
2180 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2181 smb_action |= EXTENDED_OPLOCK_GRANTED;
2184 /* If the caller set the core oplock request bit
2185 and we granted one (by whatever means) - set the
2186 correct bit for core oplock reply.
2189 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2190 reply_outbuf(req, 19, 0);
2191 } else {
2192 reply_outbuf(req, 15, 0);
2195 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2196 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2198 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2199 SCVAL(req->outbuf, smb_flg,
2200 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2203 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2204 SCVAL(req->outbuf, smb_flg,
2205 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2208 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2209 SSVAL(req->outbuf,smb_vwv3,fattr);
2210 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2211 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2212 } else {
2213 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2215 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2216 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2217 SSVAL(req->outbuf,smb_vwv11,smb_action);
2219 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2220 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2223 out:
2224 TALLOC_FREE(smb_fname);
2225 END_PROFILE(SMBopenX);
2226 return;
2229 /****************************************************************************
2230 Reply to a SMBulogoffX.
2231 ****************************************************************************/
2233 void reply_ulogoffX(struct smb_request *req)
2235 struct smbd_server_connection *sconn = req->sconn;
2236 struct user_struct *vuser;
2237 struct smbXsrv_session *session = NULL;
2238 NTSTATUS status;
2240 START_PROFILE(SMBulogoffX);
2242 vuser = get_valid_user_struct(sconn, req->vuid);
2244 if(vuser == NULL) {
2245 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2246 (unsigned long long)req->vuid));
2248 req->vuid = UID_FIELD_INVALID;
2249 reply_force_doserror(req, ERRSRV, ERRbaduid);
2250 END_PROFILE(SMBulogoffX);
2251 return;
2254 session = vuser->session;
2255 vuser = NULL;
2258 * TODO: cancel all outstanding requests on the session
2260 status = smbXsrv_session_logoff(session);
2261 if (!NT_STATUS_IS_OK(status)) {
2262 DEBUG(0, ("reply_ulogoff: "
2263 "smbXsrv_session_logoff() failed: %s\n",
2264 nt_errstr(status)));
2266 * If we hit this case, there is something completely
2267 * wrong, so we better disconnect the transport connection.
2269 END_PROFILE(SMBulogoffX);
2270 exit_server(__location__ ": smbXsrv_session_logoff failed");
2271 return;
2274 TALLOC_FREE(session);
2276 reply_outbuf(req, 2, 0);
2277 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2278 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2280 DEBUG(3, ("ulogoffX vuid=%llu\n",
2281 (unsigned long long)req->vuid));
2283 END_PROFILE(SMBulogoffX);
2284 req->vuid = UID_FIELD_INVALID;
2287 /****************************************************************************
2288 Reply to a mknew or a create.
2289 ****************************************************************************/
2291 void reply_mknew(struct smb_request *req)
2293 connection_struct *conn = req->conn;
2294 struct smb_filename *smb_fname = NULL;
2295 char *fname = NULL;
2296 uint32 fattr = 0;
2297 struct smb_file_time ft;
2298 files_struct *fsp;
2299 int oplock_request = 0;
2300 NTSTATUS status;
2301 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2302 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2303 uint32 create_disposition;
2304 uint32 create_options = 0;
2305 TALLOC_CTX *ctx = talloc_tos();
2307 START_PROFILE(SMBcreate);
2308 ZERO_STRUCT(ft);
2310 if (req->wct < 3) {
2311 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2312 goto out;
2315 fattr = SVAL(req->vwv+0, 0);
2316 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2318 /* mtime. */
2319 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2321 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2322 STR_TERMINATE, &status);
2323 if (!NT_STATUS_IS_OK(status)) {
2324 reply_nterror(req, status);
2325 goto out;
2328 status = filename_convert(ctx,
2329 conn,
2330 req->flags2 & FLAGS2_DFS_PATHNAMES,
2331 fname,
2332 UCF_CREATING_FILE,
2333 NULL,
2334 &smb_fname);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2337 reply_botherror(req,
2338 NT_STATUS_PATH_NOT_COVERED,
2339 ERRSRV, ERRbadpath);
2340 goto out;
2342 reply_nterror(req, status);
2343 goto out;
2346 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2347 DEBUG(0,("Attempt to create file (%s) with volid set - "
2348 "please report this\n",
2349 smb_fname_str_dbg(smb_fname)));
2352 if(req->cmd == SMBmknew) {
2353 /* We should fail if file exists. */
2354 create_disposition = FILE_CREATE;
2355 } else {
2356 /* Create if file doesn't exist, truncate if it does. */
2357 create_disposition = FILE_OVERWRITE_IF;
2360 status = SMB_VFS_CREATE_FILE(
2361 conn, /* conn */
2362 req, /* req */
2363 0, /* root_dir_fid */
2364 smb_fname, /* fname */
2365 access_mask, /* access_mask */
2366 share_mode, /* share_access */
2367 create_disposition, /* create_disposition*/
2368 create_options, /* create_options */
2369 fattr, /* file_attributes */
2370 oplock_request, /* oplock_request */
2371 0, /* allocation_size */
2372 0, /* private_flags */
2373 NULL, /* sd */
2374 NULL, /* ea_list */
2375 &fsp, /* result */
2376 NULL); /* pinfo */
2378 if (!NT_STATUS_IS_OK(status)) {
2379 if (open_was_deferred(req->sconn, req->mid)) {
2380 /* We have re-scheduled this call. */
2381 goto out;
2383 reply_openerror(req, status);
2384 goto out;
2387 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2388 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2389 if (!NT_STATUS_IS_OK(status)) {
2390 END_PROFILE(SMBcreate);
2391 goto out;
2394 reply_outbuf(req, 1, 0);
2395 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2397 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2398 SCVAL(req->outbuf,smb_flg,
2399 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2402 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2403 SCVAL(req->outbuf,smb_flg,
2404 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2407 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2408 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2409 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2410 (unsigned int)fattr));
2412 out:
2413 TALLOC_FREE(smb_fname);
2414 END_PROFILE(SMBcreate);
2415 return;
2418 /****************************************************************************
2419 Reply to a create temporary file.
2420 ****************************************************************************/
2422 void reply_ctemp(struct smb_request *req)
2424 connection_struct *conn = req->conn;
2425 struct smb_filename *smb_fname = NULL;
2426 char *wire_name = NULL;
2427 char *fname = NULL;
2428 uint32 fattr;
2429 files_struct *fsp;
2430 int oplock_request;
2431 char *s;
2432 NTSTATUS status;
2433 int i;
2434 TALLOC_CTX *ctx = talloc_tos();
2436 START_PROFILE(SMBctemp);
2438 if (req->wct < 3) {
2439 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2440 goto out;
2443 fattr = SVAL(req->vwv+0, 0);
2444 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2446 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2447 STR_TERMINATE, &status);
2448 if (!NT_STATUS_IS_OK(status)) {
2449 reply_nterror(req, status);
2450 goto out;
2453 for (i = 0; i < 10; i++) {
2454 if (*wire_name) {
2455 fname = talloc_asprintf(ctx,
2456 "%s/TMP%s",
2457 wire_name,
2458 generate_random_str_list(ctx, 5, "0123456789"));
2459 } else {
2460 fname = talloc_asprintf(ctx,
2461 "TMP%s",
2462 generate_random_str_list(ctx, 5, "0123456789"));
2465 if (!fname) {
2466 reply_nterror(req, NT_STATUS_NO_MEMORY);
2467 goto out;
2470 status = filename_convert(ctx, conn,
2471 req->flags2 & FLAGS2_DFS_PATHNAMES,
2472 fname,
2473 UCF_CREATING_FILE,
2474 NULL,
2475 &smb_fname);
2476 if (!NT_STATUS_IS_OK(status)) {
2477 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2478 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2479 ERRSRV, ERRbadpath);
2480 goto out;
2482 reply_nterror(req, status);
2483 goto out;
2486 /* Create the file. */
2487 status = SMB_VFS_CREATE_FILE(
2488 conn, /* conn */
2489 req, /* req */
2490 0, /* root_dir_fid */
2491 smb_fname, /* fname */
2492 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2493 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2494 FILE_CREATE, /* create_disposition*/
2495 0, /* create_options */
2496 fattr, /* file_attributes */
2497 oplock_request, /* oplock_request */
2498 0, /* allocation_size */
2499 0, /* private_flags */
2500 NULL, /* sd */
2501 NULL, /* ea_list */
2502 &fsp, /* result */
2503 NULL); /* pinfo */
2505 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2506 TALLOC_FREE(fname);
2507 TALLOC_FREE(smb_fname);
2508 continue;
2511 if (!NT_STATUS_IS_OK(status)) {
2512 if (open_was_deferred(req->sconn, req->mid)) {
2513 /* We have re-scheduled this call. */
2514 goto out;
2516 reply_openerror(req, status);
2517 goto out;
2520 break;
2523 if (i == 10) {
2524 /* Collision after 10 times... */
2525 reply_nterror(req, status);
2526 goto out;
2529 reply_outbuf(req, 1, 0);
2530 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2532 /* the returned filename is relative to the directory */
2533 s = strrchr_m(fsp->fsp_name->base_name, '/');
2534 if (!s) {
2535 s = fsp->fsp_name->base_name;
2536 } else {
2537 s++;
2540 #if 0
2541 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2542 thing in the byte section. JRA */
2543 SSVALS(p, 0, -1); /* what is this? not in spec */
2544 #endif
2545 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2546 == -1) {
2547 reply_nterror(req, NT_STATUS_NO_MEMORY);
2548 goto out;
2551 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2552 SCVAL(req->outbuf, smb_flg,
2553 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2556 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2557 SCVAL(req->outbuf, smb_flg,
2558 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2561 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2562 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2563 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2564 out:
2565 TALLOC_FREE(smb_fname);
2566 TALLOC_FREE(wire_name);
2567 END_PROFILE(SMBctemp);
2568 return;
2571 /*******************************************************************
2572 Check if a user is allowed to rename a file.
2573 ********************************************************************/
2575 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2576 uint16 dirtype)
2578 if (!CAN_WRITE(conn)) {
2579 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2582 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2583 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2584 /* Only bother to read the DOS attribute if we might deny the
2585 rename on the grounds of attribute missmatch. */
2586 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2587 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2588 return NT_STATUS_NO_SUCH_FILE;
2592 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2593 if (fsp->posix_open) {
2594 return NT_STATUS_OK;
2597 /* If no pathnames are open below this
2598 directory, allow the rename. */
2600 if (file_find_subpath(fsp)) {
2601 return NT_STATUS_ACCESS_DENIED;
2603 return NT_STATUS_OK;
2606 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2607 return NT_STATUS_OK;
2610 return NT_STATUS_ACCESS_DENIED;
2613 /*******************************************************************
2614 * unlink a file with all relevant access checks
2615 *******************************************************************/
2617 static NTSTATUS do_unlink(connection_struct *conn,
2618 struct smb_request *req,
2619 struct smb_filename *smb_fname,
2620 uint32 dirtype)
2622 uint32 fattr;
2623 files_struct *fsp;
2624 uint32 dirtype_orig = dirtype;
2625 NTSTATUS status;
2626 int ret;
2627 bool posix_paths = lp_posix_pathnames();
2629 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2630 smb_fname_str_dbg(smb_fname),
2631 dirtype));
2633 if (!CAN_WRITE(conn)) {
2634 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2637 if (posix_paths) {
2638 ret = SMB_VFS_LSTAT(conn, smb_fname);
2639 } else {
2640 ret = SMB_VFS_STAT(conn, smb_fname);
2642 if (ret != 0) {
2643 return map_nt_error_from_unix(errno);
2646 fattr = dos_mode(conn, smb_fname);
2648 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2649 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2652 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2653 if (!dirtype) {
2654 return NT_STATUS_NO_SUCH_FILE;
2657 if (!dir_check_ftype(conn, fattr, dirtype)) {
2658 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2659 return NT_STATUS_FILE_IS_A_DIRECTORY;
2661 return NT_STATUS_NO_SUCH_FILE;
2664 if (dirtype_orig & 0x8000) {
2665 /* These will never be set for POSIX. */
2666 return NT_STATUS_NO_SUCH_FILE;
2669 #if 0
2670 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2671 return NT_STATUS_FILE_IS_A_DIRECTORY;
2674 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2675 return NT_STATUS_NO_SUCH_FILE;
2678 if (dirtype & 0xFF00) {
2679 /* These will never be set for POSIX. */
2680 return NT_STATUS_NO_SUCH_FILE;
2683 dirtype &= 0xFF;
2684 if (!dirtype) {
2685 return NT_STATUS_NO_SUCH_FILE;
2688 /* Can't delete a directory. */
2689 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2690 return NT_STATUS_FILE_IS_A_DIRECTORY;
2692 #endif
2694 #if 0 /* JRATEST */
2695 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2696 return NT_STATUS_OBJECT_NAME_INVALID;
2697 #endif /* JRATEST */
2699 /* On open checks the open itself will check the share mode, so
2700 don't do it here as we'll get it wrong. */
2702 status = SMB_VFS_CREATE_FILE
2703 (conn, /* conn */
2704 req, /* req */
2705 0, /* root_dir_fid */
2706 smb_fname, /* fname */
2707 DELETE_ACCESS, /* access_mask */
2708 FILE_SHARE_NONE, /* share_access */
2709 FILE_OPEN, /* create_disposition*/
2710 FILE_NON_DIRECTORY_FILE, /* create_options */
2711 /* file_attributes */
2712 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2713 FILE_ATTRIBUTE_NORMAL,
2714 0, /* oplock_request */
2715 0, /* allocation_size */
2716 0, /* private_flags */
2717 NULL, /* sd */
2718 NULL, /* ea_list */
2719 &fsp, /* result */
2720 NULL); /* pinfo */
2722 if (!NT_STATUS_IS_OK(status)) {
2723 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2724 nt_errstr(status)));
2725 return status;
2728 status = can_set_delete_on_close(fsp, fattr);
2729 if (!NT_STATUS_IS_OK(status)) {
2730 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2731 "(%s)\n",
2732 smb_fname_str_dbg(smb_fname),
2733 nt_errstr(status)));
2734 close_file(req, fsp, NORMAL_CLOSE);
2735 return status;
2738 /* The set is across all open files on this dev/inode pair. */
2739 if (!set_delete_on_close(fsp, True,
2740 conn->session_info->security_token,
2741 conn->session_info->unix_token)) {
2742 close_file(req, fsp, NORMAL_CLOSE);
2743 return NT_STATUS_ACCESS_DENIED;
2746 return close_file(req, fsp, NORMAL_CLOSE);
2749 /****************************************************************************
2750 The guts of the unlink command, split out so it may be called by the NT SMB
2751 code.
2752 ****************************************************************************/
2754 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2755 uint32 dirtype, struct smb_filename *smb_fname,
2756 bool has_wild)
2758 char *fname_dir = NULL;
2759 char *fname_mask = NULL;
2760 int count=0;
2761 NTSTATUS status = NT_STATUS_OK;
2762 TALLOC_CTX *ctx = talloc_tos();
2764 /* Split up the directory from the filename/mask. */
2765 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2766 &fname_dir, &fname_mask);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 goto out;
2772 * We should only check the mangled cache
2773 * here if unix_convert failed. This means
2774 * that the path in 'mask' doesn't exist
2775 * on the file system and so we need to look
2776 * for a possible mangle. This patch from
2777 * Tine Smukavec <valentin.smukavec@hermes.si>.
2780 if (!VALID_STAT(smb_fname->st) &&
2781 mangle_is_mangled(fname_mask, conn->params)) {
2782 char *new_mask = NULL;
2783 mangle_lookup_name_from_8_3(ctx, fname_mask,
2784 &new_mask, conn->params);
2785 if (new_mask) {
2786 TALLOC_FREE(fname_mask);
2787 fname_mask = new_mask;
2791 if (!has_wild) {
2794 * Only one file needs to be unlinked. Append the mask back
2795 * onto the directory.
2797 TALLOC_FREE(smb_fname->base_name);
2798 if (ISDOT(fname_dir)) {
2799 /* Ensure we use canonical names on open. */
2800 smb_fname->base_name = talloc_asprintf(smb_fname,
2801 "%s",
2802 fname_mask);
2803 } else {
2804 smb_fname->base_name = talloc_asprintf(smb_fname,
2805 "%s/%s",
2806 fname_dir,
2807 fname_mask);
2809 if (!smb_fname->base_name) {
2810 status = NT_STATUS_NO_MEMORY;
2811 goto out;
2813 if (dirtype == 0) {
2814 dirtype = FILE_ATTRIBUTE_NORMAL;
2817 status = check_name(conn, smb_fname->base_name);
2818 if (!NT_STATUS_IS_OK(status)) {
2819 goto out;
2822 status = do_unlink(conn, req, smb_fname, dirtype);
2823 if (!NT_STATUS_IS_OK(status)) {
2824 goto out;
2827 count++;
2828 } else {
2829 struct smb_Dir *dir_hnd = NULL;
2830 long offset = 0;
2831 const char *dname = NULL;
2832 char *talloced = NULL;
2834 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2835 status = NT_STATUS_OBJECT_NAME_INVALID;
2836 goto out;
2839 if (strequal(fname_mask,"????????.???")) {
2840 TALLOC_FREE(fname_mask);
2841 fname_mask = talloc_strdup(ctx, "*");
2842 if (!fname_mask) {
2843 status = NT_STATUS_NO_MEMORY;
2844 goto out;
2848 status = check_name(conn, fname_dir);
2849 if (!NT_STATUS_IS_OK(status)) {
2850 goto out;
2853 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2854 dirtype);
2855 if (dir_hnd == NULL) {
2856 status = map_nt_error_from_unix(errno);
2857 goto out;
2860 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2861 the pattern matches against the long name, otherwise the short name
2862 We don't implement this yet XXXX
2865 status = NT_STATUS_NO_SUCH_FILE;
2867 while ((dname = ReadDirName(dir_hnd, &offset,
2868 &smb_fname->st, &talloced))) {
2869 TALLOC_CTX *frame = talloc_stackframe();
2871 if (!is_visible_file(conn, fname_dir, dname,
2872 &smb_fname->st, true)) {
2873 TALLOC_FREE(frame);
2874 TALLOC_FREE(talloced);
2875 continue;
2878 /* Quick check for "." and ".." */
2879 if (ISDOT(dname) || ISDOTDOT(dname)) {
2880 TALLOC_FREE(frame);
2881 TALLOC_FREE(talloced);
2882 continue;
2885 if(!mask_match(dname, fname_mask,
2886 conn->case_sensitive)) {
2887 TALLOC_FREE(frame);
2888 TALLOC_FREE(talloced);
2889 continue;
2892 TALLOC_FREE(smb_fname->base_name);
2893 if (ISDOT(fname_dir)) {
2894 /* Ensure we use canonical names on open. */
2895 smb_fname->base_name =
2896 talloc_asprintf(smb_fname, "%s",
2897 dname);
2898 } else {
2899 smb_fname->base_name =
2900 talloc_asprintf(smb_fname, "%s/%s",
2901 fname_dir, dname);
2904 if (!smb_fname->base_name) {
2905 TALLOC_FREE(dir_hnd);
2906 status = NT_STATUS_NO_MEMORY;
2907 TALLOC_FREE(frame);
2908 TALLOC_FREE(talloced);
2909 goto out;
2912 status = check_name(conn, smb_fname->base_name);
2913 if (!NT_STATUS_IS_OK(status)) {
2914 TALLOC_FREE(dir_hnd);
2915 TALLOC_FREE(frame);
2916 TALLOC_FREE(talloced);
2917 goto out;
2920 status = do_unlink(conn, req, smb_fname, dirtype);
2921 if (!NT_STATUS_IS_OK(status)) {
2922 TALLOC_FREE(frame);
2923 TALLOC_FREE(talloced);
2924 continue;
2927 count++;
2928 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2929 smb_fname->base_name));
2931 TALLOC_FREE(frame);
2932 TALLOC_FREE(talloced);
2934 TALLOC_FREE(dir_hnd);
2937 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2938 status = map_nt_error_from_unix(errno);
2941 out:
2942 TALLOC_FREE(fname_dir);
2943 TALLOC_FREE(fname_mask);
2944 return status;
2947 /****************************************************************************
2948 Reply to a unlink
2949 ****************************************************************************/
2951 void reply_unlink(struct smb_request *req)
2953 connection_struct *conn = req->conn;
2954 char *name = NULL;
2955 struct smb_filename *smb_fname = NULL;
2956 uint32 dirtype;
2957 NTSTATUS status;
2958 bool path_contains_wcard = False;
2959 TALLOC_CTX *ctx = talloc_tos();
2961 START_PROFILE(SMBunlink);
2963 if (req->wct < 1) {
2964 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2965 goto out;
2968 dirtype = SVAL(req->vwv+0, 0);
2970 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2971 STR_TERMINATE, &status,
2972 &path_contains_wcard);
2973 if (!NT_STATUS_IS_OK(status)) {
2974 reply_nterror(req, status);
2975 goto out;
2978 status = filename_convert(ctx, conn,
2979 req->flags2 & FLAGS2_DFS_PATHNAMES,
2980 name,
2981 UCF_COND_ALLOW_WCARD_LCOMP,
2982 &path_contains_wcard,
2983 &smb_fname);
2984 if (!NT_STATUS_IS_OK(status)) {
2985 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2986 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2987 ERRSRV, ERRbadpath);
2988 goto out;
2990 reply_nterror(req, status);
2991 goto out;
2994 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2996 status = unlink_internals(conn, req, dirtype, smb_fname,
2997 path_contains_wcard);
2998 if (!NT_STATUS_IS_OK(status)) {
2999 if (open_was_deferred(req->sconn, req->mid)) {
3000 /* We have re-scheduled this call. */
3001 goto out;
3003 reply_nterror(req, status);
3004 goto out;
3007 reply_outbuf(req, 0, 0);
3008 out:
3009 TALLOC_FREE(smb_fname);
3010 END_PROFILE(SMBunlink);
3011 return;
3014 /****************************************************************************
3015 Fail for readbraw.
3016 ****************************************************************************/
3018 static void fail_readraw(void)
3020 const char *errstr = talloc_asprintf(talloc_tos(),
3021 "FAIL ! reply_readbraw: socket write fail (%s)",
3022 strerror(errno));
3023 if (!errstr) {
3024 errstr = "";
3026 exit_server_cleanly(errstr);
3029 /****************************************************************************
3030 Fake (read/write) sendfile. Returns -1 on read or write fail.
3031 ****************************************************************************/
3033 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
3035 size_t bufsize;
3036 size_t tosend = nread;
3037 char *buf;
3039 if (nread == 0) {
3040 return 0;
3043 bufsize = MIN(nread, 65536);
3045 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3046 return -1;
3049 while (tosend > 0) {
3050 ssize_t ret;
3051 size_t cur_read;
3053 if (tosend > bufsize) {
3054 cur_read = bufsize;
3055 } else {
3056 cur_read = tosend;
3058 ret = read_file(fsp,buf,startpos,cur_read);
3059 if (ret == -1) {
3060 SAFE_FREE(buf);
3061 return -1;
3064 /* If we had a short read, fill with zeros. */
3065 if (ret < cur_read) {
3066 memset(buf + ret, '\0', cur_read - ret);
3069 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3070 != cur_read) {
3071 char addr[INET6_ADDRSTRLEN];
3073 * Try and give an error message saying what
3074 * client failed.
3076 DEBUG(0, ("write_data failed for client %s. "
3077 "Error %s\n",
3078 get_peer_addr(fsp->conn->sconn->sock, addr,
3079 sizeof(addr)),
3080 strerror(errno)));
3081 SAFE_FREE(buf);
3082 return -1;
3084 tosend -= cur_read;
3085 startpos += cur_read;
3088 SAFE_FREE(buf);
3089 return (ssize_t)nread;
3092 /****************************************************************************
3093 Deal with the case of sendfile reading less bytes from the file than
3094 requested. Fill with zeros (all we can do).
3095 ****************************************************************************/
3097 void sendfile_short_send(files_struct *fsp,
3098 ssize_t nread,
3099 size_t headersize,
3100 size_t smb_maxcnt)
3102 #define SHORT_SEND_BUFSIZE 1024
3103 if (nread < headersize) {
3104 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3105 "header for file %s (%s). Terminating\n",
3106 fsp_str_dbg(fsp), strerror(errno)));
3107 exit_server_cleanly("sendfile_short_send failed");
3110 nread -= headersize;
3112 if (nread < smb_maxcnt) {
3113 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3114 if (!buf) {
3115 exit_server_cleanly("sendfile_short_send: "
3116 "malloc failed");
3119 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3120 "with zeros !\n", fsp_str_dbg(fsp)));
3122 while (nread < smb_maxcnt) {
3124 * We asked for the real file size and told sendfile
3125 * to not go beyond the end of the file. But it can
3126 * happen that in between our fstat call and the
3127 * sendfile call the file was truncated. This is very
3128 * bad because we have already announced the larger
3129 * number of bytes to the client.
3131 * The best we can do now is to send 0-bytes, just as
3132 * a read from a hole in a sparse file would do.
3134 * This should happen rarely enough that I don't care
3135 * about efficiency here :-)
3137 size_t to_write;
3139 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3140 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3141 != to_write) {
3142 char addr[INET6_ADDRSTRLEN];
3144 * Try and give an error message saying what
3145 * client failed.
3147 DEBUG(0, ("write_data failed for client %s. "
3148 "Error %s\n",
3149 get_peer_addr(
3150 fsp->conn->sconn->sock, addr,
3151 sizeof(addr)),
3152 strerror(errno)));
3153 exit_server_cleanly("sendfile_short_send: "
3154 "write_data failed");
3156 nread += to_write;
3158 SAFE_FREE(buf);
3162 /****************************************************************************
3163 Return a readbraw error (4 bytes of zero).
3164 ****************************************************************************/
3166 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3168 char header[4];
3170 SIVAL(header,0,0);
3172 smbd_lock_socket(sconn);
3173 if (write_data(sconn->sock,header,4) != 4) {
3174 char addr[INET6_ADDRSTRLEN];
3176 * Try and give an error message saying what
3177 * client failed.
3179 DEBUG(0, ("write_data failed for client %s. "
3180 "Error %s\n",
3181 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3182 strerror(errno)));
3184 fail_readraw();
3186 smbd_unlock_socket(sconn);
3189 /****************************************************************************
3190 Use sendfile in readbraw.
3191 ****************************************************************************/
3193 static void send_file_readbraw(connection_struct *conn,
3194 struct smb_request *req,
3195 files_struct *fsp,
3196 off_t startpos,
3197 size_t nread,
3198 ssize_t mincount)
3200 struct smbd_server_connection *sconn = req->sconn;
3201 char *outbuf = NULL;
3202 ssize_t ret=0;
3205 * We can only use sendfile on a non-chained packet
3206 * but we can use on a non-oplocked file. tridge proved this
3207 * on a train in Germany :-). JRA.
3208 * reply_readbraw has already checked the length.
3211 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3212 (fsp->wcp == NULL) &&
3213 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3214 ssize_t sendfile_read = -1;
3215 char header[4];
3216 DATA_BLOB header_blob;
3218 _smb_setlen(header,nread);
3219 header_blob = data_blob_const(header, 4);
3221 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3222 &header_blob, startpos,
3223 nread);
3224 if (sendfile_read == -1) {
3225 /* Returning ENOSYS means no data at all was sent.
3226 * Do this as a normal read. */
3227 if (errno == ENOSYS) {
3228 goto normal_readbraw;
3232 * Special hack for broken Linux with no working sendfile. If we
3233 * return EINTR we sent the header but not the rest of the data.
3234 * Fake this up by doing read/write calls.
3236 if (errno == EINTR) {
3237 /* Ensure we don't do this again. */
3238 set_use_sendfile(SNUM(conn), False);
3239 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3241 if (fake_sendfile(fsp, startpos, nread) == -1) {
3242 DEBUG(0,("send_file_readbraw: "
3243 "fake_sendfile failed for "
3244 "file %s (%s).\n",
3245 fsp_str_dbg(fsp),
3246 strerror(errno)));
3247 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3249 return;
3252 DEBUG(0,("send_file_readbraw: sendfile failed for "
3253 "file %s (%s). Terminating\n",
3254 fsp_str_dbg(fsp), strerror(errno)));
3255 exit_server_cleanly("send_file_readbraw sendfile failed");
3256 } else if (sendfile_read == 0) {
3258 * Some sendfile implementations return 0 to indicate
3259 * that there was a short read, but nothing was
3260 * actually written to the socket. In this case,
3261 * fallback to the normal read path so the header gets
3262 * the correct byte count.
3264 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3265 "bytes falling back to the normal read: "
3266 "%s\n", fsp_str_dbg(fsp)));
3267 goto normal_readbraw;
3270 /* Deal with possible short send. */
3271 if (sendfile_read != 4+nread) {
3272 sendfile_short_send(fsp, sendfile_read, 4, nread);
3274 return;
3277 normal_readbraw:
3279 outbuf = talloc_array(NULL, char, nread+4);
3280 if (!outbuf) {
3281 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3282 (unsigned)(nread+4)));
3283 reply_readbraw_error(sconn);
3284 return;
3287 if (nread > 0) {
3288 ret = read_file(fsp,outbuf+4,startpos,nread);
3289 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3290 if (ret < mincount)
3291 ret = 0;
3292 #else
3293 if (ret < nread)
3294 ret = 0;
3295 #endif
3298 _smb_setlen(outbuf,ret);
3299 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3300 char addr[INET6_ADDRSTRLEN];
3302 * Try and give an error message saying what
3303 * client failed.
3305 DEBUG(0, ("write_data failed for client %s. "
3306 "Error %s\n",
3307 get_peer_addr(fsp->conn->sconn->sock, addr,
3308 sizeof(addr)),
3309 strerror(errno)));
3311 fail_readraw();
3314 TALLOC_FREE(outbuf);
3317 /****************************************************************************
3318 Reply to a readbraw (core+ protocol).
3319 ****************************************************************************/
3321 void reply_readbraw(struct smb_request *req)
3323 connection_struct *conn = req->conn;
3324 struct smbd_server_connection *sconn = req->sconn;
3325 ssize_t maxcount,mincount;
3326 size_t nread = 0;
3327 off_t startpos;
3328 files_struct *fsp;
3329 struct lock_struct lock;
3330 off_t size = 0;
3332 START_PROFILE(SMBreadbraw);
3334 if (srv_is_signing_active(sconn) || req->encrypted) {
3335 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3336 "raw reads/writes are disallowed.");
3339 if (req->wct < 8) {
3340 reply_readbraw_error(sconn);
3341 END_PROFILE(SMBreadbraw);
3342 return;
3345 if (sconn->smb1.echo_handler.trusted_fde) {
3346 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3347 "'async smb echo handler = yes'\n"));
3348 reply_readbraw_error(sconn);
3349 END_PROFILE(SMBreadbraw);
3350 return;
3354 * Special check if an oplock break has been issued
3355 * and the readraw request croses on the wire, we must
3356 * return a zero length response here.
3359 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3362 * We have to do a check_fsp by hand here, as
3363 * we must always return 4 zero bytes on error,
3364 * not a NTSTATUS.
3367 if (!fsp || !conn || conn != fsp->conn ||
3368 req->vuid != fsp->vuid ||
3369 fsp->is_directory || fsp->fh->fd == -1) {
3371 * fsp could be NULL here so use the value from the packet. JRA.
3373 DEBUG(3,("reply_readbraw: fnum %d not valid "
3374 "- cache prime?\n",
3375 (int)SVAL(req->vwv+0, 0)));
3376 reply_readbraw_error(sconn);
3377 END_PROFILE(SMBreadbraw);
3378 return;
3381 /* Do a "by hand" version of CHECK_READ. */
3382 if (!(fsp->can_read ||
3383 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3384 (fsp->access_mask & FILE_EXECUTE)))) {
3385 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3386 (int)SVAL(req->vwv+0, 0)));
3387 reply_readbraw_error(sconn);
3388 END_PROFILE(SMBreadbraw);
3389 return;
3392 flush_write_cache(fsp, READRAW_FLUSH);
3394 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3395 if(req->wct == 10) {
3397 * This is a large offset (64 bit) read.
3400 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3402 if(startpos < 0) {
3403 DEBUG(0,("reply_readbraw: negative 64 bit "
3404 "readraw offset (%.0f) !\n",
3405 (double)startpos ));
3406 reply_readbraw_error(sconn);
3407 END_PROFILE(SMBreadbraw);
3408 return;
3412 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3413 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3415 /* ensure we don't overrun the packet size */
3416 maxcount = MIN(65535,maxcount);
3418 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3419 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3420 &lock);
3422 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3423 reply_readbraw_error(sconn);
3424 END_PROFILE(SMBreadbraw);
3425 return;
3428 if (fsp_stat(fsp) == 0) {
3429 size = fsp->fsp_name->st.st_ex_size;
3432 if (startpos >= size) {
3433 nread = 0;
3434 } else {
3435 nread = MIN(maxcount,(size - startpos));
3438 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3439 if (nread < mincount)
3440 nread = 0;
3441 #endif
3443 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3444 "min=%lu nread=%lu\n",
3445 fsp_fnum_dbg(fsp), (double)startpos,
3446 (unsigned long)maxcount,
3447 (unsigned long)mincount,
3448 (unsigned long)nread ) );
3450 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3452 DEBUG(5,("reply_readbraw finished\n"));
3454 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3456 END_PROFILE(SMBreadbraw);
3457 return;
3460 #undef DBGC_CLASS
3461 #define DBGC_CLASS DBGC_LOCKING
3463 /****************************************************************************
3464 Reply to a lockread (core+ protocol).
3465 ****************************************************************************/
3467 void reply_lockread(struct smb_request *req)
3469 connection_struct *conn = req->conn;
3470 ssize_t nread = -1;
3471 char *data;
3472 off_t startpos;
3473 size_t numtoread;
3474 NTSTATUS status;
3475 files_struct *fsp;
3476 struct byte_range_lock *br_lck = NULL;
3477 char *p = NULL;
3478 struct smbd_server_connection *sconn = req->sconn;
3480 START_PROFILE(SMBlockread);
3482 if (req->wct < 5) {
3483 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3484 END_PROFILE(SMBlockread);
3485 return;
3488 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3490 if (!check_fsp(conn, req, fsp)) {
3491 END_PROFILE(SMBlockread);
3492 return;
3495 if (!CHECK_READ(fsp,req)) {
3496 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3497 END_PROFILE(SMBlockread);
3498 return;
3501 numtoread = SVAL(req->vwv+1, 0);
3502 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3504 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3506 reply_outbuf(req, 5, numtoread + 3);
3508 data = smb_buf(req->outbuf) + 3;
3511 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3512 * protocol request that predates the read/write lock concept.
3513 * Thus instead of asking for a read lock here we need to ask
3514 * for a write lock. JRA.
3515 * Note that the requested lock size is unaffected by max_recv.
3518 br_lck = do_lock(req->sconn->msg_ctx,
3519 fsp,
3520 (uint64_t)req->smbpid,
3521 (uint64_t)numtoread,
3522 (uint64_t)startpos,
3523 WRITE_LOCK,
3524 WINDOWS_LOCK,
3525 False, /* Non-blocking lock. */
3526 &status,
3527 NULL,
3528 NULL);
3529 TALLOC_FREE(br_lck);
3531 if (NT_STATUS_V(status)) {
3532 reply_nterror(req, status);
3533 END_PROFILE(SMBlockread);
3534 return;
3538 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3541 if (numtoread > sconn->smb1.negprot.max_recv) {
3542 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3543 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3544 (unsigned int)numtoread,
3545 (unsigned int)sconn->smb1.negprot.max_recv));
3546 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3548 nread = read_file(fsp,data,startpos,numtoread);
3550 if (nread < 0) {
3551 reply_nterror(req, map_nt_error_from_unix(errno));
3552 END_PROFILE(SMBlockread);
3553 return;
3556 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3558 SSVAL(req->outbuf,smb_vwv0,nread);
3559 SSVAL(req->outbuf,smb_vwv5,nread+3);
3560 p = smb_buf(req->outbuf);
3561 SCVAL(p,0,0); /* pad byte. */
3562 SSVAL(p,1,nread);
3564 DEBUG(3,("lockread %s num=%d nread=%d\n",
3565 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3567 END_PROFILE(SMBlockread);
3568 return;
3571 #undef DBGC_CLASS
3572 #define DBGC_CLASS DBGC_ALL
3574 /****************************************************************************
3575 Reply to a read.
3576 ****************************************************************************/
3578 void reply_read(struct smb_request *req)
3580 connection_struct *conn = req->conn;
3581 size_t numtoread;
3582 ssize_t nread = 0;
3583 char *data;
3584 off_t startpos;
3585 int outsize = 0;
3586 files_struct *fsp;
3587 struct lock_struct lock;
3588 struct smbd_server_connection *sconn = req->sconn;
3590 START_PROFILE(SMBread);
3592 if (req->wct < 3) {
3593 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3594 END_PROFILE(SMBread);
3595 return;
3598 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3600 if (!check_fsp(conn, req, fsp)) {
3601 END_PROFILE(SMBread);
3602 return;
3605 if (!CHECK_READ(fsp,req)) {
3606 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3607 END_PROFILE(SMBread);
3608 return;
3611 numtoread = SVAL(req->vwv+1, 0);
3612 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3614 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3617 * The requested read size cannot be greater than max_recv. JRA.
3619 if (numtoread > sconn->smb1.negprot.max_recv) {
3620 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3621 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3622 (unsigned int)numtoread,
3623 (unsigned int)sconn->smb1.negprot.max_recv));
3624 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3627 reply_outbuf(req, 5, numtoread+3);
3629 data = smb_buf(req->outbuf) + 3;
3631 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3632 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3633 &lock);
3635 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3636 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3637 END_PROFILE(SMBread);
3638 return;
3641 if (numtoread > 0)
3642 nread = read_file(fsp,data,startpos,numtoread);
3644 if (nread < 0) {
3645 reply_nterror(req, map_nt_error_from_unix(errno));
3646 goto strict_unlock;
3649 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3651 SSVAL(req->outbuf,smb_vwv0,nread);
3652 SSVAL(req->outbuf,smb_vwv5,nread+3);
3653 SCVAL(smb_buf(req->outbuf),0,1);
3654 SSVAL(smb_buf(req->outbuf),1,nread);
3656 DEBUG(3, ("read %s num=%d nread=%d\n",
3657 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3659 strict_unlock:
3660 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3662 END_PROFILE(SMBread);
3663 return;
3666 /****************************************************************************
3667 Setup readX header.
3668 ****************************************************************************/
3670 static int setup_readX_header(struct smb_request *req, char *outbuf,
3671 size_t smb_maxcnt)
3673 int outsize;
3675 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3677 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3679 SCVAL(outbuf,smb_vwv0,0xFF);
3680 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3681 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3682 SSVAL(outbuf,smb_vwv6,
3683 (smb_wct - 4) /* offset from smb header to wct */
3684 + 1 /* the wct field */
3685 + 12 * sizeof(uint16_t) /* vwv */
3686 + 2); /* the buflen field */
3687 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3688 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3689 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3690 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3691 return outsize;
3694 /****************************************************************************
3695 Reply to a read and X - possibly using sendfile.
3696 ****************************************************************************/
3698 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3699 files_struct *fsp, off_t startpos,
3700 size_t smb_maxcnt)
3702 ssize_t nread = -1;
3703 struct lock_struct lock;
3704 int saved_errno = 0;
3706 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3707 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3708 &lock);
3710 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3711 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3712 return;
3716 * We can only use sendfile on a non-chained packet
3717 * but we can use on a non-oplocked file. tridge proved this
3718 * on a train in Germany :-). JRA.
3721 if (!req_is_in_chain(req) &&
3722 !req->encrypted &&
3723 (fsp->base_fsp == NULL) &&
3724 (fsp->wcp == NULL) &&
3725 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3726 uint8 headerbuf[smb_size + 12 * 2];
3727 DATA_BLOB header;
3729 if(fsp_stat(fsp) == -1) {
3730 reply_nterror(req, map_nt_error_from_unix(errno));
3731 goto strict_unlock;
3734 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3735 (startpos > fsp->fsp_name->st.st_ex_size) ||
3736 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3738 * We already know that we would do a short read, so don't
3739 * try the sendfile() path.
3741 goto nosendfile_read;
3745 * Set up the packet header before send. We
3746 * assume here the sendfile will work (get the
3747 * correct amount of data).
3750 header = data_blob_const(headerbuf, sizeof(headerbuf));
3752 construct_reply_common_req(req, (char *)headerbuf);
3753 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3755 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3756 startpos, smb_maxcnt);
3757 if (nread == -1) {
3758 /* Returning ENOSYS means no data at all was sent.
3759 Do this as a normal read. */
3760 if (errno == ENOSYS) {
3761 goto normal_read;
3765 * Special hack for broken Linux with no working sendfile. If we
3766 * return EINTR we sent the header but not the rest of the data.
3767 * Fake this up by doing read/write calls.
3770 if (errno == EINTR) {
3771 /* Ensure we don't do this again. */
3772 set_use_sendfile(SNUM(conn), False);
3773 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3774 nread = fake_sendfile(fsp, startpos,
3775 smb_maxcnt);
3776 if (nread == -1) {
3777 DEBUG(0,("send_file_readX: "
3778 "fake_sendfile failed for "
3779 "file %s (%s).\n",
3780 fsp_str_dbg(fsp),
3781 strerror(errno)));
3782 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3784 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3785 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3786 /* No outbuf here means successful sendfile. */
3787 goto strict_unlock;
3790 DEBUG(0,("send_file_readX: sendfile failed for file "
3791 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3792 strerror(errno)));
3793 exit_server_cleanly("send_file_readX sendfile failed");
3794 } else if (nread == 0) {
3796 * Some sendfile implementations return 0 to indicate
3797 * that there was a short read, but nothing was
3798 * actually written to the socket. In this case,
3799 * fallback to the normal read path so the header gets
3800 * the correct byte count.
3802 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3803 "falling back to the normal read: %s\n",
3804 fsp_str_dbg(fsp)));
3805 goto normal_read;
3808 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3809 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3811 /* Deal with possible short send. */
3812 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3813 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3815 /* No outbuf here means successful sendfile. */
3816 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3817 SMB_PERFCOUNT_END(&req->pcd);
3818 goto strict_unlock;
3821 normal_read:
3823 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3824 uint8 headerbuf[smb_size + 2*12];
3826 construct_reply_common_req(req, (char *)headerbuf);
3827 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3829 /* Send out the header. */
3830 if (write_data(req->sconn->sock, (char *)headerbuf,
3831 sizeof(headerbuf)) != sizeof(headerbuf)) {
3833 char addr[INET6_ADDRSTRLEN];
3835 * Try and give an error message saying what
3836 * client failed.
3838 DEBUG(0, ("write_data failed for client %s. "
3839 "Error %s\n",
3840 get_peer_addr(req->sconn->sock, addr,
3841 sizeof(addr)),
3842 strerror(errno)));
3844 DEBUG(0,("send_file_readX: write_data failed for file "
3845 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3846 strerror(errno)));
3847 exit_server_cleanly("send_file_readX sendfile failed");
3849 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3850 if (nread == -1) {
3851 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3852 "file %s (%s).\n", fsp_str_dbg(fsp),
3853 strerror(errno)));
3854 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3856 goto strict_unlock;
3859 nosendfile_read:
3861 reply_outbuf(req, 12, smb_maxcnt);
3862 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3863 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3865 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3866 saved_errno = errno;
3868 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3870 if (nread < 0) {
3871 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3872 return;
3875 setup_readX_header(req, (char *)req->outbuf, nread);
3877 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3878 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3879 return;
3881 strict_unlock:
3882 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3883 TALLOC_FREE(req->outbuf);
3884 return;
3887 /****************************************************************************
3888 Work out how much space we have for a read return.
3889 ****************************************************************************/
3891 static size_t calc_max_read_pdu(const struct smb_request *req)
3893 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3894 return req->sconn->smb1.sessions.max_send;
3897 if (!lp_large_readwrite()) {
3898 return req->sconn->smb1.sessions.max_send;
3901 if (req_is_in_chain(req)) {
3902 return req->sconn->smb1.sessions.max_send;
3905 if (req->encrypted) {
3907 * Don't take encrypted traffic up to the
3908 * limit. There are padding considerations
3909 * that make that tricky.
3911 return req->sconn->smb1.sessions.max_send;
3914 if (srv_is_signing_active(req->sconn)) {
3915 return 0x1FFFF;
3918 if (!lp_unix_extensions()) {
3919 return 0x1FFFF;
3923 * We can do ultra-large POSIX reads.
3925 return 0xFFFFFF;
3928 /****************************************************************************
3929 Calculate how big a read can be. Copes with all clients. It's always
3930 safe to return a short read - Windows does this.
3931 ****************************************************************************/
3933 static size_t calc_read_size(const struct smb_request *req,
3934 size_t upper_size,
3935 size_t lower_size)
3937 size_t max_pdu = calc_max_read_pdu(req);
3938 size_t total_size = 0;
3939 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3940 size_t max_len = max_pdu - hdr_len;
3943 * Windows explicitly ignores upper size of 0xFFFF.
3944 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3945 * We must do the same as these will never fit even in
3946 * an extended size NetBIOS packet.
3948 if (upper_size == 0xFFFF) {
3949 upper_size = 0;
3952 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3953 upper_size = 0;
3956 total_size = ((upper_size<<16) | lower_size);
3959 * LARGE_READX test shows it's always safe to return
3960 * a short read. Windows does so.
3962 return MIN(total_size, max_len);
3965 /****************************************************************************
3966 Reply to a read and X.
3967 ****************************************************************************/
3969 void reply_read_and_X(struct smb_request *req)
3971 connection_struct *conn = req->conn;
3972 files_struct *fsp;
3973 off_t startpos;
3974 size_t smb_maxcnt;
3975 size_t upper_size;
3976 bool big_readX = False;
3977 #if 0
3978 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3979 #endif
3981 START_PROFILE(SMBreadX);
3983 if ((req->wct != 10) && (req->wct != 12)) {
3984 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3985 return;
3988 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3989 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3990 smb_maxcnt = SVAL(req->vwv+5, 0);
3992 /* If it's an IPC, pass off the pipe handler. */
3993 if (IS_IPC(conn)) {
3994 reply_pipe_read_and_X(req);
3995 END_PROFILE(SMBreadX);
3996 return;
3999 if (!check_fsp(conn, req, fsp)) {
4000 END_PROFILE(SMBreadX);
4001 return;
4004 if (!CHECK_READ(fsp,req)) {
4005 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4006 END_PROFILE(SMBreadX);
4007 return;
4010 upper_size = SVAL(req->vwv+7, 0);
4011 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4012 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4014 * This is a heuristic to avoid keeping large
4015 * outgoing buffers around over long-lived aio
4016 * requests.
4018 big_readX = True;
4021 if (req->wct == 12) {
4023 * This is a large offset (64 bit) read.
4025 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4029 if (!big_readX) {
4030 NTSTATUS status = schedule_aio_read_and_X(conn,
4031 req,
4032 fsp,
4033 startpos,
4034 smb_maxcnt);
4035 if (NT_STATUS_IS_OK(status)) {
4036 /* Read scheduled - we're done. */
4037 goto out;
4039 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4040 /* Real error - report to client. */
4041 END_PROFILE(SMBreadX);
4042 reply_nterror(req, status);
4043 return;
4045 /* NT_STATUS_RETRY - fall back to sync read. */
4048 smbd_lock_socket(req->sconn);
4049 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4050 smbd_unlock_socket(req->sconn);
4052 out:
4053 END_PROFILE(SMBreadX);
4054 return;
4057 /****************************************************************************
4058 Error replies to writebraw must have smb_wct == 1. Fix this up.
4059 ****************************************************************************/
4061 void error_to_writebrawerr(struct smb_request *req)
4063 uint8 *old_outbuf = req->outbuf;
4065 reply_outbuf(req, 1, 0);
4067 memcpy(req->outbuf, old_outbuf, smb_size);
4068 TALLOC_FREE(old_outbuf);
4071 /****************************************************************************
4072 Read 4 bytes of a smb packet and return the smb length of the packet.
4073 Store the result in the buffer. This version of the function will
4074 never return a session keepalive (length of zero).
4075 Timeout is in milliseconds.
4076 ****************************************************************************/
4078 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4079 size_t *len)
4081 uint8_t msgtype = NBSSkeepalive;
4083 while (msgtype == NBSSkeepalive) {
4084 NTSTATUS status;
4086 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4087 len);
4088 if (!NT_STATUS_IS_OK(status)) {
4089 char addr[INET6_ADDRSTRLEN];
4090 /* Try and give an error message
4091 * saying what client failed. */
4092 DEBUG(0, ("read_fd_with_timeout failed for "
4093 "client %s read error = %s.\n",
4094 get_peer_addr(fd,addr,sizeof(addr)),
4095 nt_errstr(status)));
4096 return status;
4099 msgtype = CVAL(inbuf, 0);
4102 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4103 (unsigned long)len));
4105 return NT_STATUS_OK;
4108 /****************************************************************************
4109 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4110 ****************************************************************************/
4112 void reply_writebraw(struct smb_request *req)
4114 connection_struct *conn = req->conn;
4115 char *buf = NULL;
4116 ssize_t nwritten=0;
4117 ssize_t total_written=0;
4118 size_t numtowrite=0;
4119 size_t tcount;
4120 off_t startpos;
4121 const char *data=NULL;
4122 bool write_through;
4123 files_struct *fsp;
4124 struct lock_struct lock;
4125 NTSTATUS status;
4127 START_PROFILE(SMBwritebraw);
4130 * If we ever reply with an error, it must have the SMB command
4131 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4132 * we're finished.
4134 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4136 if (srv_is_signing_active(req->sconn)) {
4137 END_PROFILE(SMBwritebraw);
4138 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4139 "raw reads/writes are disallowed.");
4142 if (req->wct < 12) {
4143 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4144 error_to_writebrawerr(req);
4145 END_PROFILE(SMBwritebraw);
4146 return;
4149 if (req->sconn->smb1.echo_handler.trusted_fde) {
4150 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4151 "'async smb echo handler = yes'\n"));
4152 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4153 error_to_writebrawerr(req);
4154 END_PROFILE(SMBwritebraw);
4155 return;
4158 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4159 if (!check_fsp(conn, req, fsp)) {
4160 error_to_writebrawerr(req);
4161 END_PROFILE(SMBwritebraw);
4162 return;
4165 if (!CHECK_WRITE(fsp)) {
4166 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4167 error_to_writebrawerr(req);
4168 END_PROFILE(SMBwritebraw);
4169 return;
4172 tcount = IVAL(req->vwv+1, 0);
4173 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4174 write_through = BITSETW(req->vwv+7,0);
4176 /* We have to deal with slightly different formats depending
4177 on whether we are using the core+ or lanman1.0 protocol */
4179 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4180 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4181 data = smb_buf_const(req->inbuf);
4182 } else {
4183 numtowrite = SVAL(req->vwv+10, 0);
4184 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4187 /* Ensure we don't write bytes past the end of this packet. */
4188 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4189 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4190 error_to_writebrawerr(req);
4191 END_PROFILE(SMBwritebraw);
4192 return;
4195 if (!fsp->print_file) {
4196 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4197 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4198 &lock);
4200 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4201 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4202 error_to_writebrawerr(req);
4203 END_PROFILE(SMBwritebraw);
4204 return;
4208 if (numtowrite>0) {
4209 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4212 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4213 "wrote=%d sync=%d\n",
4214 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4215 (int)nwritten, (int)write_through));
4217 if (nwritten < (ssize_t)numtowrite) {
4218 reply_nterror(req, NT_STATUS_DISK_FULL);
4219 error_to_writebrawerr(req);
4220 goto strict_unlock;
4223 total_written = nwritten;
4225 /* Allocate a buffer of 64k + length. */
4226 buf = talloc_array(NULL, char, 65540);
4227 if (!buf) {
4228 reply_nterror(req, NT_STATUS_NO_MEMORY);
4229 error_to_writebrawerr(req);
4230 goto strict_unlock;
4233 /* Return a SMBwritebraw message to the redirector to tell
4234 * it to send more bytes */
4236 memcpy(buf, req->inbuf, smb_size);
4237 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4238 SCVAL(buf,smb_com,SMBwritebraw);
4239 SSVALS(buf,smb_vwv0,0xFFFF);
4240 show_msg(buf);
4241 if (!srv_send_smb(req->sconn,
4242 buf,
4243 false, 0, /* no signing */
4244 IS_CONN_ENCRYPTED(conn),
4245 &req->pcd)) {
4246 exit_server_cleanly("reply_writebraw: srv_send_smb "
4247 "failed.");
4250 /* Now read the raw data into the buffer and write it */
4251 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4252 &numtowrite);
4253 if (!NT_STATUS_IS_OK(status)) {
4254 exit_server_cleanly("secondary writebraw failed");
4257 /* Set up outbuf to return the correct size */
4258 reply_outbuf(req, 1, 0);
4260 if (numtowrite != 0) {
4262 if (numtowrite > 0xFFFF) {
4263 DEBUG(0,("reply_writebraw: Oversize secondary write "
4264 "raw requested (%u). Terminating\n",
4265 (unsigned int)numtowrite ));
4266 exit_server_cleanly("secondary writebraw failed");
4269 if (tcount > nwritten+numtowrite) {
4270 DEBUG(3,("reply_writebraw: Client overestimated the "
4271 "write %d %d %d\n",
4272 (int)tcount,(int)nwritten,(int)numtowrite));
4275 status = read_data(req->sconn->sock, buf+4, numtowrite);
4277 if (!NT_STATUS_IS_OK(status)) {
4278 char addr[INET6_ADDRSTRLEN];
4279 /* Try and give an error message
4280 * saying what client failed. */
4281 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4282 "raw read failed (%s) for client %s. "
4283 "Terminating\n", nt_errstr(status),
4284 get_peer_addr(req->sconn->sock, addr,
4285 sizeof(addr))));
4286 exit_server_cleanly("secondary writebraw failed");
4289 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4290 if (nwritten == -1) {
4291 TALLOC_FREE(buf);
4292 reply_nterror(req, map_nt_error_from_unix(errno));
4293 error_to_writebrawerr(req);
4294 goto strict_unlock;
4297 if (nwritten < (ssize_t)numtowrite) {
4298 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4299 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4302 if (nwritten > 0) {
4303 total_written += nwritten;
4307 TALLOC_FREE(buf);
4308 SSVAL(req->outbuf,smb_vwv0,total_written);
4310 status = sync_file(conn, fsp, write_through);
4311 if (!NT_STATUS_IS_OK(status)) {
4312 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4313 fsp_str_dbg(fsp), nt_errstr(status)));
4314 reply_nterror(req, status);
4315 error_to_writebrawerr(req);
4316 goto strict_unlock;
4319 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4320 "wrote=%d\n",
4321 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4322 (int)total_written));
4324 if (!fsp->print_file) {
4325 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4328 /* We won't return a status if write through is not selected - this
4329 * follows what WfWg does */
4330 END_PROFILE(SMBwritebraw);
4332 if (!write_through && total_written==tcount) {
4334 #if RABBIT_PELLET_FIX
4336 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4337 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4338 * JRA.
4340 if (!send_keepalive(req->sconn->sock)) {
4341 exit_server_cleanly("reply_writebraw: send of "
4342 "keepalive failed");
4344 #endif
4345 TALLOC_FREE(req->outbuf);
4347 return;
4349 strict_unlock:
4350 if (!fsp->print_file) {
4351 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4354 END_PROFILE(SMBwritebraw);
4355 return;
4358 #undef DBGC_CLASS
4359 #define DBGC_CLASS DBGC_LOCKING
4361 /****************************************************************************
4362 Reply to a writeunlock (core+).
4363 ****************************************************************************/
4365 void reply_writeunlock(struct smb_request *req)
4367 connection_struct *conn = req->conn;
4368 ssize_t nwritten = -1;
4369 size_t numtowrite;
4370 off_t startpos;
4371 const char *data;
4372 NTSTATUS status = NT_STATUS_OK;
4373 files_struct *fsp;
4374 struct lock_struct lock;
4375 int saved_errno = 0;
4377 START_PROFILE(SMBwriteunlock);
4379 if (req->wct < 5) {
4380 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4381 END_PROFILE(SMBwriteunlock);
4382 return;
4385 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4387 if (!check_fsp(conn, req, fsp)) {
4388 END_PROFILE(SMBwriteunlock);
4389 return;
4392 if (!CHECK_WRITE(fsp)) {
4393 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4394 END_PROFILE(SMBwriteunlock);
4395 return;
4398 numtowrite = SVAL(req->vwv+1, 0);
4399 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4400 data = (const char *)req->buf + 3;
4402 if (!fsp->print_file && numtowrite > 0) {
4403 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4404 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4405 &lock);
4407 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4408 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4409 END_PROFILE(SMBwriteunlock);
4410 return;
4414 /* The special X/Open SMB protocol handling of
4415 zero length writes is *NOT* done for
4416 this call */
4417 if(numtowrite == 0) {
4418 nwritten = 0;
4419 } else {
4420 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4421 saved_errno = errno;
4424 status = sync_file(conn, fsp, False /* write through */);
4425 if (!NT_STATUS_IS_OK(status)) {
4426 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4427 fsp_str_dbg(fsp), nt_errstr(status)));
4428 reply_nterror(req, status);
4429 goto strict_unlock;
4432 if(nwritten < 0) {
4433 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4434 goto strict_unlock;
4437 if((nwritten < numtowrite) && (numtowrite != 0)) {
4438 reply_nterror(req, NT_STATUS_DISK_FULL);
4439 goto strict_unlock;
4442 if (numtowrite && !fsp->print_file) {
4443 status = do_unlock(req->sconn->msg_ctx,
4444 fsp,
4445 (uint64_t)req->smbpid,
4446 (uint64_t)numtowrite,
4447 (uint64_t)startpos,
4448 WINDOWS_LOCK);
4450 if (NT_STATUS_V(status)) {
4451 reply_nterror(req, status);
4452 goto strict_unlock;
4456 reply_outbuf(req, 1, 0);
4458 SSVAL(req->outbuf,smb_vwv0,nwritten);
4460 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4461 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4463 strict_unlock:
4464 if (numtowrite && !fsp->print_file) {
4465 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4468 END_PROFILE(SMBwriteunlock);
4469 return;
4472 #undef DBGC_CLASS
4473 #define DBGC_CLASS DBGC_ALL
4475 /****************************************************************************
4476 Reply to a write.
4477 ****************************************************************************/
4479 void reply_write(struct smb_request *req)
4481 connection_struct *conn = req->conn;
4482 size_t numtowrite;
4483 ssize_t nwritten = -1;
4484 off_t startpos;
4485 const char *data;
4486 files_struct *fsp;
4487 struct lock_struct lock;
4488 NTSTATUS status;
4489 int saved_errno = 0;
4491 START_PROFILE(SMBwrite);
4493 if (req->wct < 5) {
4494 END_PROFILE(SMBwrite);
4495 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4496 return;
4499 /* If it's an IPC, pass off the pipe handler. */
4500 if (IS_IPC(conn)) {
4501 reply_pipe_write(req);
4502 END_PROFILE(SMBwrite);
4503 return;
4506 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4508 if (!check_fsp(conn, req, fsp)) {
4509 END_PROFILE(SMBwrite);
4510 return;
4513 if (!CHECK_WRITE(fsp)) {
4514 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4515 END_PROFILE(SMBwrite);
4516 return;
4519 numtowrite = SVAL(req->vwv+1, 0);
4520 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4521 data = (const char *)req->buf + 3;
4523 if (!fsp->print_file) {
4524 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4525 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4526 &lock);
4528 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4529 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4530 END_PROFILE(SMBwrite);
4531 return;
4536 * X/Open SMB protocol says that if smb_vwv1 is
4537 * zero then the file size should be extended or
4538 * truncated to the size given in smb_vwv[2-3].
4541 if(numtowrite == 0) {
4543 * This is actually an allocate call, and set EOF. JRA.
4545 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4546 if (nwritten < 0) {
4547 reply_nterror(req, NT_STATUS_DISK_FULL);
4548 goto strict_unlock;
4550 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4551 if (nwritten < 0) {
4552 reply_nterror(req, NT_STATUS_DISK_FULL);
4553 goto strict_unlock;
4555 trigger_write_time_update_immediate(fsp);
4556 } else {
4557 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4560 status = sync_file(conn, fsp, False);
4561 if (!NT_STATUS_IS_OK(status)) {
4562 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4563 fsp_str_dbg(fsp), nt_errstr(status)));
4564 reply_nterror(req, status);
4565 goto strict_unlock;
4568 if(nwritten < 0) {
4569 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4570 goto strict_unlock;
4573 if((nwritten == 0) && (numtowrite != 0)) {
4574 reply_nterror(req, NT_STATUS_DISK_FULL);
4575 goto strict_unlock;
4578 reply_outbuf(req, 1, 0);
4580 SSVAL(req->outbuf,smb_vwv0,nwritten);
4582 if (nwritten < (ssize_t)numtowrite) {
4583 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4584 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4587 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4589 strict_unlock:
4590 if (!fsp->print_file) {
4591 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4594 END_PROFILE(SMBwrite);
4595 return;
4598 /****************************************************************************
4599 Ensure a buffer is a valid writeX for recvfile purposes.
4600 ****************************************************************************/
4602 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4603 (2*14) + /* word count (including bcc) */ \
4604 1 /* pad byte */)
4606 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4607 const uint8_t *inbuf)
4609 size_t numtowrite;
4610 connection_struct *conn = NULL;
4611 unsigned int doff = 0;
4612 size_t len = smb_len_large(inbuf);
4613 struct smbXsrv_tcon *tcon;
4614 NTSTATUS status;
4615 NTTIME now = 0;
4617 if (is_encrypted_packet(sconn, inbuf)) {
4618 /* Can't do this on encrypted
4619 * connections. */
4620 return false;
4623 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4624 return false;
4627 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4628 CVAL(inbuf,smb_wct) != 14) {
4629 DEBUG(10,("is_valid_writeX_buffer: chained or "
4630 "invalid word length.\n"));
4631 return false;
4634 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4635 now, &tcon);
4636 if (!NT_STATUS_IS_OK(status)) {
4637 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4638 return false;
4640 conn = tcon->compat;
4642 if (IS_IPC(conn)) {
4643 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4644 return false;
4646 if (IS_PRINT(conn)) {
4647 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4648 return false;
4650 doff = SVAL(inbuf,smb_vwv11);
4652 numtowrite = SVAL(inbuf,smb_vwv10);
4654 if (len > doff && len - doff > 0xFFFF) {
4655 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4658 if (numtowrite == 0) {
4659 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4660 return false;
4663 /* Ensure the sizes match up. */
4664 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4665 /* no pad byte...old smbclient :-( */
4666 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4667 (unsigned int)doff,
4668 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4669 return false;
4672 if (len - doff != numtowrite) {
4673 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4674 "len = %u, doff = %u, numtowrite = %u\n",
4675 (unsigned int)len,
4676 (unsigned int)doff,
4677 (unsigned int)numtowrite ));
4678 return false;
4681 DEBUG(10,("is_valid_writeX_buffer: true "
4682 "len = %u, doff = %u, numtowrite = %u\n",
4683 (unsigned int)len,
4684 (unsigned int)doff,
4685 (unsigned int)numtowrite ));
4687 return true;
4690 /****************************************************************************
4691 Reply to a write and X.
4692 ****************************************************************************/
4694 void reply_write_and_X(struct smb_request *req)
4696 connection_struct *conn = req->conn;
4697 files_struct *fsp;
4698 struct lock_struct lock;
4699 off_t startpos;
4700 size_t numtowrite;
4701 bool write_through;
4702 ssize_t nwritten;
4703 unsigned int smb_doff;
4704 unsigned int smblen;
4705 const char *data;
4706 NTSTATUS status;
4707 int saved_errno = 0;
4709 START_PROFILE(SMBwriteX);
4711 if ((req->wct != 12) && (req->wct != 14)) {
4712 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4713 goto out;
4716 numtowrite = SVAL(req->vwv+10, 0);
4717 smb_doff = SVAL(req->vwv+11, 0);
4718 smblen = smb_len(req->inbuf);
4720 if (req->unread_bytes > 0xFFFF ||
4721 (smblen > smb_doff &&
4722 smblen - smb_doff > 0xFFFF)) {
4723 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4726 if (req->unread_bytes) {
4727 /* Can't do a recvfile write on IPC$ */
4728 if (IS_IPC(conn)) {
4729 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4730 goto out;
4732 if (numtowrite != req->unread_bytes) {
4733 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4734 goto out;
4736 } else {
4737 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4738 smb_doff + numtowrite > smblen) {
4739 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4740 goto out;
4744 /* If it's an IPC, pass off the pipe handler. */
4745 if (IS_IPC(conn)) {
4746 if (req->unread_bytes) {
4747 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4748 goto out;
4750 reply_pipe_write_and_X(req);
4751 goto out;
4754 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4755 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4756 write_through = BITSETW(req->vwv+7,0);
4758 if (!check_fsp(conn, req, fsp)) {
4759 goto out;
4762 if (!CHECK_WRITE(fsp)) {
4763 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4764 goto out;
4767 data = smb_base(req->inbuf) + smb_doff;
4769 if(req->wct == 14) {
4771 * This is a large offset (64 bit) write.
4773 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4777 /* X/Open SMB protocol says that, unlike SMBwrite
4778 if the length is zero then NO truncation is
4779 done, just a write of zero. To truncate a file,
4780 use SMBwrite. */
4782 if(numtowrite == 0) {
4783 nwritten = 0;
4784 } else {
4785 if (req->unread_bytes == 0) {
4786 status = schedule_aio_write_and_X(conn,
4787 req,
4788 fsp,
4789 data,
4790 startpos,
4791 numtowrite);
4793 if (NT_STATUS_IS_OK(status)) {
4794 /* write scheduled - we're done. */
4795 goto out;
4797 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4798 /* Real error - report to client. */
4799 reply_nterror(req, status);
4800 goto out;
4802 /* NT_STATUS_RETRY - fall through to sync write. */
4805 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4806 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4807 &lock);
4809 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4810 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4811 goto out;
4814 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4815 saved_errno = errno;
4817 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4820 if(nwritten < 0) {
4821 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4822 goto out;
4825 if((nwritten == 0) && (numtowrite != 0)) {
4826 reply_nterror(req, NT_STATUS_DISK_FULL);
4827 goto out;
4830 reply_outbuf(req, 6, 0);
4831 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4832 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4833 SSVAL(req->outbuf,smb_vwv2,nwritten);
4834 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4836 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4837 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4839 status = sync_file(conn, fsp, write_through);
4840 if (!NT_STATUS_IS_OK(status)) {
4841 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4842 fsp_str_dbg(fsp), nt_errstr(status)));
4843 reply_nterror(req, status);
4844 goto out;
4847 END_PROFILE(SMBwriteX);
4848 return;
4850 out:
4851 if (req->unread_bytes) {
4852 /* writeX failed. drain socket. */
4853 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4854 req->unread_bytes) {
4855 smb_panic("failed to drain pending bytes");
4857 req->unread_bytes = 0;
4860 END_PROFILE(SMBwriteX);
4861 return;
4864 /****************************************************************************
4865 Reply to a lseek.
4866 ****************************************************************************/
4868 void reply_lseek(struct smb_request *req)
4870 connection_struct *conn = req->conn;
4871 off_t startpos;
4872 off_t res= -1;
4873 int mode,umode;
4874 files_struct *fsp;
4876 START_PROFILE(SMBlseek);
4878 if (req->wct < 4) {
4879 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4880 END_PROFILE(SMBlseek);
4881 return;
4884 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4886 if (!check_fsp(conn, req, fsp)) {
4887 return;
4890 flush_write_cache(fsp, SEEK_FLUSH);
4892 mode = SVAL(req->vwv+1, 0) & 3;
4893 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4894 startpos = (off_t)IVALS(req->vwv+2, 0);
4896 switch (mode) {
4897 case 0:
4898 umode = SEEK_SET;
4899 res = startpos;
4900 break;
4901 case 1:
4902 umode = SEEK_CUR;
4903 res = fsp->fh->pos + startpos;
4904 break;
4905 case 2:
4906 umode = SEEK_END;
4907 break;
4908 default:
4909 umode = SEEK_SET;
4910 res = startpos;
4911 break;
4914 if (umode == SEEK_END) {
4915 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4916 if(errno == EINVAL) {
4917 off_t current_pos = startpos;
4919 if(fsp_stat(fsp) == -1) {
4920 reply_nterror(req,
4921 map_nt_error_from_unix(errno));
4922 END_PROFILE(SMBlseek);
4923 return;
4926 current_pos += fsp->fsp_name->st.st_ex_size;
4927 if(current_pos < 0)
4928 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4932 if(res == -1) {
4933 reply_nterror(req, map_nt_error_from_unix(errno));
4934 END_PROFILE(SMBlseek);
4935 return;
4939 fsp->fh->pos = res;
4941 reply_outbuf(req, 2, 0);
4942 SIVAL(req->outbuf,smb_vwv0,res);
4944 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4945 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4947 END_PROFILE(SMBlseek);
4948 return;
4951 /****************************************************************************
4952 Reply to a flush.
4953 ****************************************************************************/
4955 void reply_flush(struct smb_request *req)
4957 connection_struct *conn = req->conn;
4958 uint16 fnum;
4959 files_struct *fsp;
4961 START_PROFILE(SMBflush);
4963 if (req->wct < 1) {
4964 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4965 return;
4968 fnum = SVAL(req->vwv+0, 0);
4969 fsp = file_fsp(req, fnum);
4971 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4972 return;
4975 if (!fsp) {
4976 file_sync_all(conn);
4977 } else {
4978 NTSTATUS status = sync_file(conn, fsp, True);
4979 if (!NT_STATUS_IS_OK(status)) {
4980 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4981 fsp_str_dbg(fsp), nt_errstr(status)));
4982 reply_nterror(req, status);
4983 END_PROFILE(SMBflush);
4984 return;
4988 reply_outbuf(req, 0, 0);
4990 DEBUG(3,("flush\n"));
4991 END_PROFILE(SMBflush);
4992 return;
4995 /****************************************************************************
4996 Reply to a exit.
4997 conn POINTER CAN BE NULL HERE !
4998 ****************************************************************************/
5000 void reply_exit(struct smb_request *req)
5002 START_PROFILE(SMBexit);
5004 file_close_pid(req->sconn, req->smbpid, req->vuid);
5006 reply_outbuf(req, 0, 0);
5008 DEBUG(3,("exit\n"));
5010 END_PROFILE(SMBexit);
5011 return;
5014 struct reply_close_state {
5015 files_struct *fsp;
5016 struct smb_request *smbreq;
5019 static void do_smb1_close(struct tevent_req *req);
5021 void reply_close(struct smb_request *req)
5023 connection_struct *conn = req->conn;
5024 NTSTATUS status = NT_STATUS_OK;
5025 files_struct *fsp = NULL;
5026 START_PROFILE(SMBclose);
5028 if (req->wct < 3) {
5029 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5030 END_PROFILE(SMBclose);
5031 return;
5034 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5037 * We can only use check_fsp if we know it's not a directory.
5040 if (!check_fsp_open(conn, req, fsp)) {
5041 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5042 END_PROFILE(SMBclose);
5043 return;
5046 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5047 fsp->is_directory ? "directory" : "file",
5048 fsp->fh->fd, fsp_fnum_dbg(fsp),
5049 conn->num_files_open));
5051 if (!fsp->is_directory) {
5052 time_t t;
5055 * Take care of any time sent in the close.
5058 t = srv_make_unix_date3(req->vwv+1);
5059 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5062 if (fsp->num_aio_requests != 0) {
5064 struct reply_close_state *state;
5066 DEBUG(10, ("closing with aio %u requests pending\n",
5067 fsp->num_aio_requests));
5070 * We depend on the aio_extra destructor to take care of this
5071 * close request once fsp->num_aio_request drops to 0.
5074 fsp->deferred_close = tevent_wait_send(
5075 fsp, fsp->conn->sconn->ev_ctx);
5076 if (fsp->deferred_close == NULL) {
5077 status = NT_STATUS_NO_MEMORY;
5078 goto done;
5081 state = talloc(fsp, struct reply_close_state);
5082 if (state == NULL) {
5083 TALLOC_FREE(fsp->deferred_close);
5084 status = NT_STATUS_NO_MEMORY;
5085 goto done;
5087 state->fsp = fsp;
5088 state->smbreq = talloc_move(fsp, &req);
5089 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5090 state);
5091 END_PROFILE(SMBclose);
5092 return;
5096 * close_file() returns the unix errno if an error was detected on
5097 * close - normally this is due to a disk full error. If not then it
5098 * was probably an I/O error.
5101 status = close_file(req, fsp, NORMAL_CLOSE);
5102 done:
5103 if (!NT_STATUS_IS_OK(status)) {
5104 reply_nterror(req, status);
5105 END_PROFILE(SMBclose);
5106 return;
5109 reply_outbuf(req, 0, 0);
5110 END_PROFILE(SMBclose);
5111 return;
5114 static void do_smb1_close(struct tevent_req *req)
5116 struct reply_close_state *state = tevent_req_callback_data(
5117 req, struct reply_close_state);
5118 struct smb_request *smbreq;
5119 NTSTATUS status;
5120 int ret;
5122 ret = tevent_wait_recv(req);
5123 TALLOC_FREE(req);
5124 if (ret != 0) {
5125 DEBUG(10, ("tevent_wait_recv returned %s\n",
5126 strerror(ret)));
5128 * Continue anyway, this should never happen
5133 * fsp->smb2_close_request right now is a talloc grandchild of
5134 * fsp. When we close_file(fsp), it would go with it. No chance to
5135 * reply...
5137 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5139 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5140 if (NT_STATUS_IS_OK(status)) {
5141 reply_outbuf(smbreq, 0, 0);
5142 } else {
5143 reply_nterror(smbreq, status);
5145 if (!srv_send_smb(smbreq->sconn,
5146 (char *)smbreq->outbuf,
5147 true,
5148 smbreq->seqnum+1,
5149 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5150 NULL)) {
5151 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5152 "failed.");
5154 TALLOC_FREE(smbreq);
5157 /****************************************************************************
5158 Reply to a writeclose (Core+ protocol).
5159 ****************************************************************************/
5161 void reply_writeclose(struct smb_request *req)
5163 connection_struct *conn = req->conn;
5164 size_t numtowrite;
5165 ssize_t nwritten = -1;
5166 NTSTATUS close_status = NT_STATUS_OK;
5167 off_t startpos;
5168 const char *data;
5169 struct timespec mtime;
5170 files_struct *fsp;
5171 struct lock_struct lock;
5173 START_PROFILE(SMBwriteclose);
5175 if (req->wct < 6) {
5176 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5177 END_PROFILE(SMBwriteclose);
5178 return;
5181 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5183 if (!check_fsp(conn, req, fsp)) {
5184 END_PROFILE(SMBwriteclose);
5185 return;
5187 if (!CHECK_WRITE(fsp)) {
5188 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5189 END_PROFILE(SMBwriteclose);
5190 return;
5193 numtowrite = SVAL(req->vwv+1, 0);
5194 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5195 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5196 data = (const char *)req->buf + 1;
5198 if (!fsp->print_file) {
5199 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5200 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5201 &lock);
5203 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5204 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5205 END_PROFILE(SMBwriteclose);
5206 return;
5210 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5212 set_close_write_time(fsp, mtime);
5215 * More insanity. W2K only closes the file if writelen > 0.
5216 * JRA.
5219 if (numtowrite) {
5220 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5221 "file %s\n", fsp_str_dbg(fsp)));
5222 close_status = close_file(req, fsp, NORMAL_CLOSE);
5225 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5226 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5227 conn->num_files_open));
5229 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5230 reply_nterror(req, NT_STATUS_DISK_FULL);
5231 goto strict_unlock;
5234 if(!NT_STATUS_IS_OK(close_status)) {
5235 reply_nterror(req, close_status);
5236 goto strict_unlock;
5239 reply_outbuf(req, 1, 0);
5241 SSVAL(req->outbuf,smb_vwv0,nwritten);
5243 strict_unlock:
5244 if (numtowrite && !fsp->print_file) {
5245 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5248 END_PROFILE(SMBwriteclose);
5249 return;
5252 #undef DBGC_CLASS
5253 #define DBGC_CLASS DBGC_LOCKING
5255 /****************************************************************************
5256 Reply to a lock.
5257 ****************************************************************************/
5259 void reply_lock(struct smb_request *req)
5261 connection_struct *conn = req->conn;
5262 uint64_t count,offset;
5263 NTSTATUS status;
5264 files_struct *fsp;
5265 struct byte_range_lock *br_lck = NULL;
5267 START_PROFILE(SMBlock);
5269 if (req->wct < 5) {
5270 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5271 END_PROFILE(SMBlock);
5272 return;
5275 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5277 if (!check_fsp(conn, req, fsp)) {
5278 END_PROFILE(SMBlock);
5279 return;
5282 count = (uint64_t)IVAL(req->vwv+1, 0);
5283 offset = (uint64_t)IVAL(req->vwv+3, 0);
5285 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5286 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5288 br_lck = do_lock(req->sconn->msg_ctx,
5289 fsp,
5290 (uint64_t)req->smbpid,
5291 count,
5292 offset,
5293 WRITE_LOCK,
5294 WINDOWS_LOCK,
5295 False, /* Non-blocking lock. */
5296 &status,
5297 NULL,
5298 NULL);
5300 TALLOC_FREE(br_lck);
5302 if (NT_STATUS_V(status)) {
5303 reply_nterror(req, status);
5304 END_PROFILE(SMBlock);
5305 return;
5308 reply_outbuf(req, 0, 0);
5310 END_PROFILE(SMBlock);
5311 return;
5314 /****************************************************************************
5315 Reply to a unlock.
5316 ****************************************************************************/
5318 void reply_unlock(struct smb_request *req)
5320 connection_struct *conn = req->conn;
5321 uint64_t count,offset;
5322 NTSTATUS status;
5323 files_struct *fsp;
5325 START_PROFILE(SMBunlock);
5327 if (req->wct < 5) {
5328 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5329 END_PROFILE(SMBunlock);
5330 return;
5333 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5335 if (!check_fsp(conn, req, fsp)) {
5336 END_PROFILE(SMBunlock);
5337 return;
5340 count = (uint64_t)IVAL(req->vwv+1, 0);
5341 offset = (uint64_t)IVAL(req->vwv+3, 0);
5343 status = do_unlock(req->sconn->msg_ctx,
5344 fsp,
5345 (uint64_t)req->smbpid,
5346 count,
5347 offset,
5348 WINDOWS_LOCK);
5350 if (NT_STATUS_V(status)) {
5351 reply_nterror(req, status);
5352 END_PROFILE(SMBunlock);
5353 return;
5356 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5357 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5359 reply_outbuf(req, 0, 0);
5361 END_PROFILE(SMBunlock);
5362 return;
5365 #undef DBGC_CLASS
5366 #define DBGC_CLASS DBGC_ALL
5368 /****************************************************************************
5369 Reply to a tdis.
5370 conn POINTER CAN BE NULL HERE !
5371 ****************************************************************************/
5373 void reply_tdis(struct smb_request *req)
5375 NTSTATUS status;
5376 connection_struct *conn = req->conn;
5377 struct smbXsrv_tcon *tcon;
5379 START_PROFILE(SMBtdis);
5381 if (!conn) {
5382 DEBUG(4,("Invalid connection in tdis\n"));
5383 reply_force_doserror(req, ERRSRV, ERRinvnid);
5384 END_PROFILE(SMBtdis);
5385 return;
5388 tcon = conn->tcon;
5389 req->conn = NULL;
5392 * TODO: cancel all outstanding requests on the tcon
5394 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5395 if (!NT_STATUS_IS_OK(status)) {
5396 DEBUG(0, ("reply_tdis: "
5397 "smbXsrv_tcon_disconnect() failed: %s\n",
5398 nt_errstr(status)));
5400 * If we hit this case, there is something completely
5401 * wrong, so we better disconnect the transport connection.
5403 END_PROFILE(SMBtdis);
5404 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5405 return;
5408 TALLOC_FREE(tcon);
5410 reply_outbuf(req, 0, 0);
5411 END_PROFILE(SMBtdis);
5412 return;
5415 /****************************************************************************
5416 Reply to a echo.
5417 conn POINTER CAN BE NULL HERE !
5418 ****************************************************************************/
5420 void reply_echo(struct smb_request *req)
5422 connection_struct *conn = req->conn;
5423 struct smb_perfcount_data local_pcd;
5424 struct smb_perfcount_data *cur_pcd;
5425 int smb_reverb;
5426 int seq_num;
5428 START_PROFILE(SMBecho);
5430 smb_init_perfcount_data(&local_pcd);
5432 if (req->wct < 1) {
5433 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5434 END_PROFILE(SMBecho);
5435 return;
5438 smb_reverb = SVAL(req->vwv+0, 0);
5440 reply_outbuf(req, 1, req->buflen);
5442 /* copy any incoming data back out */
5443 if (req->buflen > 0) {
5444 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5447 if (smb_reverb > 100) {
5448 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5449 smb_reverb = 100;
5452 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5454 /* this makes sure we catch the request pcd */
5455 if (seq_num == smb_reverb) {
5456 cur_pcd = &req->pcd;
5457 } else {
5458 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5459 cur_pcd = &local_pcd;
5462 SSVAL(req->outbuf,smb_vwv0,seq_num);
5464 show_msg((char *)req->outbuf);
5465 if (!srv_send_smb(req->sconn,
5466 (char *)req->outbuf,
5467 true, req->seqnum+1,
5468 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5469 cur_pcd))
5470 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5473 DEBUG(3,("echo %d times\n", smb_reverb));
5475 TALLOC_FREE(req->outbuf);
5477 END_PROFILE(SMBecho);
5478 return;
5481 /****************************************************************************
5482 Reply to a printopen.
5483 ****************************************************************************/
5485 void reply_printopen(struct smb_request *req)
5487 connection_struct *conn = req->conn;
5488 files_struct *fsp;
5489 NTSTATUS status;
5491 START_PROFILE(SMBsplopen);
5493 if (req->wct < 2) {
5494 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5495 END_PROFILE(SMBsplopen);
5496 return;
5499 if (!CAN_PRINT(conn)) {
5500 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5501 END_PROFILE(SMBsplopen);
5502 return;
5505 status = file_new(req, conn, &fsp);
5506 if(!NT_STATUS_IS_OK(status)) {
5507 reply_nterror(req, status);
5508 END_PROFILE(SMBsplopen);
5509 return;
5512 /* Open for exclusive use, write only. */
5513 status = print_spool_open(fsp, NULL, req->vuid);
5515 if (!NT_STATUS_IS_OK(status)) {
5516 file_free(req, fsp);
5517 reply_nterror(req, status);
5518 END_PROFILE(SMBsplopen);
5519 return;
5522 reply_outbuf(req, 1, 0);
5523 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5525 DEBUG(3,("openprint fd=%d %s\n",
5526 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5528 END_PROFILE(SMBsplopen);
5529 return;
5532 /****************************************************************************
5533 Reply to a printclose.
5534 ****************************************************************************/
5536 void reply_printclose(struct smb_request *req)
5538 connection_struct *conn = req->conn;
5539 files_struct *fsp;
5540 NTSTATUS status;
5542 START_PROFILE(SMBsplclose);
5544 if (req->wct < 1) {
5545 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5546 END_PROFILE(SMBsplclose);
5547 return;
5550 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5552 if (!check_fsp(conn, req, fsp)) {
5553 END_PROFILE(SMBsplclose);
5554 return;
5557 if (!CAN_PRINT(conn)) {
5558 reply_force_doserror(req, ERRSRV, ERRerror);
5559 END_PROFILE(SMBsplclose);
5560 return;
5563 DEBUG(3,("printclose fd=%d %s\n",
5564 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5566 status = close_file(req, fsp, NORMAL_CLOSE);
5568 if(!NT_STATUS_IS_OK(status)) {
5569 reply_nterror(req, status);
5570 END_PROFILE(SMBsplclose);
5571 return;
5574 reply_outbuf(req, 0, 0);
5576 END_PROFILE(SMBsplclose);
5577 return;
5580 /****************************************************************************
5581 Reply to a printqueue.
5582 ****************************************************************************/
5584 void reply_printqueue(struct smb_request *req)
5586 connection_struct *conn = req->conn;
5587 int max_count;
5588 int start_index;
5590 START_PROFILE(SMBsplretq);
5592 if (req->wct < 2) {
5593 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5594 END_PROFILE(SMBsplretq);
5595 return;
5598 max_count = SVAL(req->vwv+0, 0);
5599 start_index = SVAL(req->vwv+1, 0);
5601 /* we used to allow the client to get the cnum wrong, but that
5602 is really quite gross and only worked when there was only
5603 one printer - I think we should now only accept it if they
5604 get it right (tridge) */
5605 if (!CAN_PRINT(conn)) {
5606 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5607 END_PROFILE(SMBsplretq);
5608 return;
5611 reply_outbuf(req, 2, 3);
5612 SSVAL(req->outbuf,smb_vwv0,0);
5613 SSVAL(req->outbuf,smb_vwv1,0);
5614 SCVAL(smb_buf(req->outbuf),0,1);
5615 SSVAL(smb_buf(req->outbuf),1,0);
5617 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5618 start_index, max_count));
5621 TALLOC_CTX *mem_ctx = talloc_tos();
5622 NTSTATUS status;
5623 WERROR werr;
5624 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5625 struct rpc_pipe_client *cli = NULL;
5626 struct dcerpc_binding_handle *b = NULL;
5627 struct policy_handle handle;
5628 struct spoolss_DevmodeContainer devmode_ctr;
5629 union spoolss_JobInfo *info;
5630 uint32_t count;
5631 uint32_t num_to_get;
5632 uint32_t first;
5633 uint32_t i;
5635 ZERO_STRUCT(handle);
5637 status = rpc_pipe_open_interface(conn,
5638 &ndr_table_spoolss.syntax_id,
5639 conn->session_info,
5640 conn->sconn->remote_address,
5641 conn->sconn->msg_ctx,
5642 &cli);
5643 if (!NT_STATUS_IS_OK(status)) {
5644 DEBUG(0, ("reply_printqueue: "
5645 "could not connect to spoolss: %s\n",
5646 nt_errstr(status)));
5647 reply_nterror(req, status);
5648 goto out;
5650 b = cli->binding_handle;
5652 ZERO_STRUCT(devmode_ctr);
5654 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5655 sharename,
5656 NULL, devmode_ctr,
5657 SEC_FLAG_MAXIMUM_ALLOWED,
5658 &handle,
5659 &werr);
5660 if (!NT_STATUS_IS_OK(status)) {
5661 reply_nterror(req, status);
5662 goto out;
5664 if (!W_ERROR_IS_OK(werr)) {
5665 reply_nterror(req, werror_to_ntstatus(werr));
5666 goto out;
5669 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5670 &handle,
5671 0, /* firstjob */
5672 0xff, /* numjobs */
5673 2, /* level */
5674 0, /* offered */
5675 &count,
5676 &info);
5677 if (!W_ERROR_IS_OK(werr)) {
5678 reply_nterror(req, werror_to_ntstatus(werr));
5679 goto out;
5682 if (max_count > 0) {
5683 first = start_index;
5684 } else {
5685 first = start_index + max_count + 1;
5688 if (first >= count) {
5689 num_to_get = first;
5690 } else {
5691 num_to_get = first + MIN(ABS(max_count), count - first);
5694 for (i = first; i < num_to_get; i++) {
5695 char blob[28];
5696 char *p = blob;
5697 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5698 int qstatus;
5699 uint16_t qrapjobid = pjobid_to_rap(sharename,
5700 info[i].info2.job_id);
5702 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5703 qstatus = 2;
5704 } else {
5705 qstatus = 3;
5708 srv_put_dos_date2(p, 0, qtime);
5709 SCVAL(p, 4, qstatus);
5710 SSVAL(p, 5, qrapjobid);
5711 SIVAL(p, 7, info[i].info2.size);
5712 SCVAL(p, 11, 0);
5713 srvstr_push(blob, req->flags2, p+12,
5714 info[i].info2.notify_name, 16, STR_ASCII);
5716 if (message_push_blob(
5717 &req->outbuf,
5718 data_blob_const(
5719 blob, sizeof(blob))) == -1) {
5720 reply_nterror(req, NT_STATUS_NO_MEMORY);
5721 goto out;
5725 if (count > 0) {
5726 SSVAL(req->outbuf,smb_vwv0,count);
5727 SSVAL(req->outbuf,smb_vwv1,
5728 (max_count>0?first+count:first-1));
5729 SCVAL(smb_buf(req->outbuf),0,1);
5730 SSVAL(smb_buf(req->outbuf),1,28*count);
5734 DEBUG(3, ("%u entries returned in queue\n",
5735 (unsigned)count));
5737 out:
5738 if (b && is_valid_policy_hnd(&handle)) {
5739 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5744 END_PROFILE(SMBsplretq);
5745 return;
5748 /****************************************************************************
5749 Reply to a printwrite.
5750 ****************************************************************************/
5752 void reply_printwrite(struct smb_request *req)
5754 connection_struct *conn = req->conn;
5755 int numtowrite;
5756 const char *data;
5757 files_struct *fsp;
5759 START_PROFILE(SMBsplwr);
5761 if (req->wct < 1) {
5762 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5763 END_PROFILE(SMBsplwr);
5764 return;
5767 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5769 if (!check_fsp(conn, req, fsp)) {
5770 END_PROFILE(SMBsplwr);
5771 return;
5774 if (!fsp->print_file) {
5775 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5776 END_PROFILE(SMBsplwr);
5777 return;
5780 if (!CHECK_WRITE(fsp)) {
5781 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5782 END_PROFILE(SMBsplwr);
5783 return;
5786 numtowrite = SVAL(req->buf, 1);
5788 if (req->buflen < numtowrite + 3) {
5789 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5790 END_PROFILE(SMBsplwr);
5791 return;
5794 data = (const char *)req->buf + 3;
5796 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5797 reply_nterror(req, map_nt_error_from_unix(errno));
5798 END_PROFILE(SMBsplwr);
5799 return;
5802 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5804 END_PROFILE(SMBsplwr);
5805 return;
5808 /****************************************************************************
5809 Reply to a mkdir.
5810 ****************************************************************************/
5812 void reply_mkdir(struct smb_request *req)
5814 connection_struct *conn = req->conn;
5815 struct smb_filename *smb_dname = NULL;
5816 char *directory = NULL;
5817 NTSTATUS status;
5818 TALLOC_CTX *ctx = talloc_tos();
5820 START_PROFILE(SMBmkdir);
5822 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5823 STR_TERMINATE, &status);
5824 if (!NT_STATUS_IS_OK(status)) {
5825 reply_nterror(req, status);
5826 goto out;
5829 status = filename_convert(ctx, conn,
5830 req->flags2 & FLAGS2_DFS_PATHNAMES,
5831 directory,
5832 UCF_CREATING_FILE,
5833 NULL,
5834 &smb_dname);
5835 if (!NT_STATUS_IS_OK(status)) {
5836 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5837 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5838 ERRSRV, ERRbadpath);
5839 goto out;
5841 reply_nterror(req, status);
5842 goto out;
5845 status = create_directory(conn, req, smb_dname);
5847 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5849 if (!NT_STATUS_IS_OK(status)) {
5851 if (!use_nt_status()
5852 && NT_STATUS_EQUAL(status,
5853 NT_STATUS_OBJECT_NAME_COLLISION)) {
5855 * Yes, in the DOS error code case we get a
5856 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5857 * samba4 torture test.
5859 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5862 reply_nterror(req, status);
5863 goto out;
5866 reply_outbuf(req, 0, 0);
5868 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5869 out:
5870 TALLOC_FREE(smb_dname);
5871 END_PROFILE(SMBmkdir);
5872 return;
5875 /****************************************************************************
5876 Reply to a rmdir.
5877 ****************************************************************************/
5879 void reply_rmdir(struct smb_request *req)
5881 connection_struct *conn = req->conn;
5882 struct smb_filename *smb_dname = NULL;
5883 char *directory = NULL;
5884 NTSTATUS status;
5885 TALLOC_CTX *ctx = talloc_tos();
5886 files_struct *fsp = NULL;
5887 int info = 0;
5888 struct smbd_server_connection *sconn = req->sconn;
5890 START_PROFILE(SMBrmdir);
5892 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5893 STR_TERMINATE, &status);
5894 if (!NT_STATUS_IS_OK(status)) {
5895 reply_nterror(req, status);
5896 goto out;
5899 status = filename_convert(ctx, conn,
5900 req->flags2 & FLAGS2_DFS_PATHNAMES,
5901 directory,
5903 NULL,
5904 &smb_dname);
5905 if (!NT_STATUS_IS_OK(status)) {
5906 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5907 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5908 ERRSRV, ERRbadpath);
5909 goto out;
5911 reply_nterror(req, status);
5912 goto out;
5915 if (is_ntfs_stream_smb_fname(smb_dname)) {
5916 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5917 goto out;
5920 status = SMB_VFS_CREATE_FILE(
5921 conn, /* conn */
5922 req, /* req */
5923 0, /* root_dir_fid */
5924 smb_dname, /* fname */
5925 DELETE_ACCESS, /* access_mask */
5926 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5927 FILE_SHARE_DELETE),
5928 FILE_OPEN, /* create_disposition*/
5929 FILE_DIRECTORY_FILE, /* create_options */
5930 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5931 0, /* oplock_request */
5932 0, /* allocation_size */
5933 0, /* private_flags */
5934 NULL, /* sd */
5935 NULL, /* ea_list */
5936 &fsp, /* result */
5937 &info); /* pinfo */
5939 if (!NT_STATUS_IS_OK(status)) {
5940 if (open_was_deferred(req->sconn, req->mid)) {
5941 /* We have re-scheduled this call. */
5942 goto out;
5944 reply_nterror(req, status);
5945 goto out;
5948 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5949 if (!NT_STATUS_IS_OK(status)) {
5950 close_file(req, fsp, ERROR_CLOSE);
5951 reply_nterror(req, status);
5952 goto out;
5955 if (!set_delete_on_close(fsp, true,
5956 conn->session_info->security_token,
5957 conn->session_info->unix_token)) {
5958 close_file(req, fsp, ERROR_CLOSE);
5959 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5960 goto out;
5963 status = close_file(req, fsp, NORMAL_CLOSE);
5964 if (!NT_STATUS_IS_OK(status)) {
5965 reply_nterror(req, status);
5966 } else {
5967 reply_outbuf(req, 0, 0);
5970 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5972 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5973 out:
5974 TALLOC_FREE(smb_dname);
5975 END_PROFILE(SMBrmdir);
5976 return;
5979 /*******************************************************************
5980 Resolve wildcards in a filename rename.
5981 ********************************************************************/
5983 static bool resolve_wildcards(TALLOC_CTX *ctx,
5984 const char *name1,
5985 const char *name2,
5986 char **pp_newname)
5988 char *name2_copy = NULL;
5989 char *root1 = NULL;
5990 char *root2 = NULL;
5991 char *ext1 = NULL;
5992 char *ext2 = NULL;
5993 char *p,*p2, *pname1, *pname2;
5995 name2_copy = talloc_strdup(ctx, name2);
5996 if (!name2_copy) {
5997 return False;
6000 pname1 = strrchr_m(name1,'/');
6001 pname2 = strrchr_m(name2_copy,'/');
6003 if (!pname1 || !pname2) {
6004 return False;
6007 /* Truncate the copy of name2 at the last '/' */
6008 *pname2 = '\0';
6010 /* Now go past the '/' */
6011 pname1++;
6012 pname2++;
6014 root1 = talloc_strdup(ctx, pname1);
6015 root2 = talloc_strdup(ctx, pname2);
6017 if (!root1 || !root2) {
6018 return False;
6021 p = strrchr_m(root1,'.');
6022 if (p) {
6023 *p = 0;
6024 ext1 = talloc_strdup(ctx, p+1);
6025 } else {
6026 ext1 = talloc_strdup(ctx, "");
6028 p = strrchr_m(root2,'.');
6029 if (p) {
6030 *p = 0;
6031 ext2 = talloc_strdup(ctx, p+1);
6032 } else {
6033 ext2 = talloc_strdup(ctx, "");
6036 if (!ext1 || !ext2) {
6037 return False;
6040 p = root1;
6041 p2 = root2;
6042 while (*p2) {
6043 if (*p2 == '?') {
6044 /* Hmmm. Should this be mb-aware ? */
6045 *p2 = *p;
6046 p2++;
6047 } else if (*p2 == '*') {
6048 *p2 = '\0';
6049 root2 = talloc_asprintf(ctx, "%s%s",
6050 root2,
6052 if (!root2) {
6053 return False;
6055 break;
6056 } else {
6057 p2++;
6059 if (*p) {
6060 p++;
6064 p = ext1;
6065 p2 = ext2;
6066 while (*p2) {
6067 if (*p2 == '?') {
6068 /* Hmmm. Should this be mb-aware ? */
6069 *p2 = *p;
6070 p2++;
6071 } else if (*p2 == '*') {
6072 *p2 = '\0';
6073 ext2 = talloc_asprintf(ctx, "%s%s",
6074 ext2,
6076 if (!ext2) {
6077 return False;
6079 break;
6080 } else {
6081 p2++;
6083 if (*p) {
6084 p++;
6088 if (*ext2) {
6089 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6090 name2_copy,
6091 root2,
6092 ext2);
6093 } else {
6094 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6095 name2_copy,
6096 root2);
6099 if (!*pp_newname) {
6100 return False;
6103 return True;
6106 /****************************************************************************
6107 Ensure open files have their names updated. Updated to notify other smbd's
6108 asynchronously.
6109 ****************************************************************************/
6111 static void rename_open_files(connection_struct *conn,
6112 struct share_mode_lock *lck,
6113 uint32_t orig_name_hash,
6114 const struct smb_filename *smb_fname_dst)
6116 files_struct *fsp;
6117 bool did_rename = False;
6118 NTSTATUS status;
6119 uint32_t new_name_hash = 0;
6121 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6122 fsp = file_find_di_next(fsp)) {
6123 /* fsp_name is a relative path under the fsp. To change this for other
6124 sharepaths we need to manipulate relative paths. */
6125 /* TODO - create the absolute path and manipulate the newname
6126 relative to the sharepath. */
6127 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6128 continue;
6130 if (fsp->name_hash != orig_name_hash) {
6131 continue;
6133 DEBUG(10, ("rename_open_files: renaming file %s "
6134 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6135 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6136 smb_fname_str_dbg(smb_fname_dst)));
6138 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6139 if (NT_STATUS_IS_OK(status)) {
6140 did_rename = True;
6141 new_name_hash = fsp->name_hash;
6145 if (!did_rename) {
6146 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6147 "for %s\n", file_id_string_tos(&lck->data->id),
6148 smb_fname_str_dbg(smb_fname_dst)));
6151 /* Send messages to all smbd's (not ourself) that the name has changed. */
6152 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6153 orig_name_hash, new_name_hash,
6154 smb_fname_dst);
6158 /****************************************************************************
6159 We need to check if the source path is a parent directory of the destination
6160 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6161 refuse the rename with a sharing violation. Under UNIX the above call can
6162 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6163 probably need to check that the client is a Windows one before disallowing
6164 this as a UNIX client (one with UNIX extensions) can know the source is a
6165 symlink and make this decision intelligently. Found by an excellent bug
6166 report from <AndyLiebman@aol.com>.
6167 ****************************************************************************/
6169 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6170 const struct smb_filename *smb_fname_dst)
6172 const char *psrc = smb_fname_src->base_name;
6173 const char *pdst = smb_fname_dst->base_name;
6174 size_t slen;
6176 if (psrc[0] == '.' && psrc[1] == '/') {
6177 psrc += 2;
6179 if (pdst[0] == '.' && pdst[1] == '/') {
6180 pdst += 2;
6182 if ((slen = strlen(psrc)) > strlen(pdst)) {
6183 return False;
6185 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6189 * Do the notify calls from a rename
6192 static void notify_rename(connection_struct *conn, bool is_dir,
6193 const struct smb_filename *smb_fname_src,
6194 const struct smb_filename *smb_fname_dst)
6196 char *parent_dir_src = NULL;
6197 char *parent_dir_dst = NULL;
6198 uint32 mask;
6200 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6201 : FILE_NOTIFY_CHANGE_FILE_NAME;
6203 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6204 &parent_dir_src, NULL) ||
6205 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6206 &parent_dir_dst, NULL)) {
6207 goto out;
6210 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6211 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6212 smb_fname_src->base_name);
6213 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6214 smb_fname_dst->base_name);
6216 else {
6217 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6218 smb_fname_src->base_name);
6219 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6220 smb_fname_dst->base_name);
6223 /* this is a strange one. w2k3 gives an additional event for
6224 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6225 files, but not directories */
6226 if (!is_dir) {
6227 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6228 FILE_NOTIFY_CHANGE_ATTRIBUTES
6229 |FILE_NOTIFY_CHANGE_CREATION,
6230 smb_fname_dst->base_name);
6232 out:
6233 TALLOC_FREE(parent_dir_src);
6234 TALLOC_FREE(parent_dir_dst);
6237 /****************************************************************************
6238 Returns an error if the parent directory for a filename is open in an
6239 incompatible way.
6240 ****************************************************************************/
6242 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6243 const struct smb_filename *smb_fname_dst_in)
6245 char *parent_dir = NULL;
6246 struct smb_filename smb_fname_parent;
6247 struct file_id id;
6248 files_struct *fsp = NULL;
6249 int ret;
6251 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6252 &parent_dir, NULL)) {
6253 return NT_STATUS_NO_MEMORY;
6255 ZERO_STRUCT(smb_fname_parent);
6256 smb_fname_parent.base_name = parent_dir;
6258 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6259 if (ret == -1) {
6260 return map_nt_error_from_unix(errno);
6264 * We're only checking on this smbd here, mostly good
6265 * enough.. and will pass tests.
6268 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6269 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6270 fsp = file_find_di_next(fsp)) {
6271 if (fsp->access_mask & DELETE_ACCESS) {
6272 return NT_STATUS_SHARING_VIOLATION;
6275 return NT_STATUS_OK;
6278 /****************************************************************************
6279 Rename an open file - given an fsp.
6280 ****************************************************************************/
6282 NTSTATUS rename_internals_fsp(connection_struct *conn,
6283 files_struct *fsp,
6284 const struct smb_filename *smb_fname_dst_in,
6285 uint32 attrs,
6286 bool replace_if_exists)
6288 TALLOC_CTX *ctx = talloc_tos();
6289 struct smb_filename *smb_fname_dst = NULL;
6290 NTSTATUS status = NT_STATUS_OK;
6291 struct share_mode_lock *lck = NULL;
6292 bool dst_exists, old_is_stream, new_is_stream;
6294 status = check_name(conn, smb_fname_dst_in->base_name);
6295 if (!NT_STATUS_IS_OK(status)) {
6296 return status;
6299 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6300 if (!NT_STATUS_IS_OK(status)) {
6301 return status;
6304 /* Make a copy of the dst smb_fname structs */
6306 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6307 if (!NT_STATUS_IS_OK(status)) {
6308 goto out;
6312 * Check for special case with case preserving and not
6313 * case sensitive. If the old last component differs from the original
6314 * last component only by case, then we should allow
6315 * the rename (user is trying to change the case of the
6316 * filename).
6318 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6319 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6320 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6321 char *last_slash;
6322 char *fname_dst_lcomp_base_mod = NULL;
6323 struct smb_filename *smb_fname_orig_lcomp = NULL;
6326 * Get the last component of the destination name.
6328 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6329 if (last_slash) {
6330 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6331 } else {
6332 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6334 if (!fname_dst_lcomp_base_mod) {
6335 status = NT_STATUS_NO_MEMORY;
6336 goto out;
6340 * Create an smb_filename struct using the original last
6341 * component of the destination.
6343 status = create_synthetic_smb_fname_split(ctx,
6344 smb_fname_dst->original_lcomp, NULL,
6345 &smb_fname_orig_lcomp);
6346 if (!NT_STATUS_IS_OK(status)) {
6347 TALLOC_FREE(fname_dst_lcomp_base_mod);
6348 goto out;
6351 /* If the base names only differ by case, use original. */
6352 if(!strcsequal(fname_dst_lcomp_base_mod,
6353 smb_fname_orig_lcomp->base_name)) {
6354 char *tmp;
6356 * Replace the modified last component with the
6357 * original.
6359 if (last_slash) {
6360 *last_slash = '\0'; /* Truncate at the '/' */
6361 tmp = talloc_asprintf(smb_fname_dst,
6362 "%s/%s",
6363 smb_fname_dst->base_name,
6364 smb_fname_orig_lcomp->base_name);
6365 } else {
6366 tmp = talloc_asprintf(smb_fname_dst,
6367 "%s",
6368 smb_fname_orig_lcomp->base_name);
6370 if (tmp == NULL) {
6371 status = NT_STATUS_NO_MEMORY;
6372 TALLOC_FREE(fname_dst_lcomp_base_mod);
6373 TALLOC_FREE(smb_fname_orig_lcomp);
6374 goto out;
6376 TALLOC_FREE(smb_fname_dst->base_name);
6377 smb_fname_dst->base_name = tmp;
6380 /* If the stream_names only differ by case, use original. */
6381 if(!strcsequal(smb_fname_dst->stream_name,
6382 smb_fname_orig_lcomp->stream_name)) {
6383 char *tmp = NULL;
6384 /* Use the original stream. */
6385 tmp = talloc_strdup(smb_fname_dst,
6386 smb_fname_orig_lcomp->stream_name);
6387 if (tmp == NULL) {
6388 status = NT_STATUS_NO_MEMORY;
6389 TALLOC_FREE(fname_dst_lcomp_base_mod);
6390 TALLOC_FREE(smb_fname_orig_lcomp);
6391 goto out;
6393 TALLOC_FREE(smb_fname_dst->stream_name);
6394 smb_fname_dst->stream_name = tmp;
6396 TALLOC_FREE(fname_dst_lcomp_base_mod);
6397 TALLOC_FREE(smb_fname_orig_lcomp);
6401 * If the src and dest names are identical - including case,
6402 * don't do the rename, just return success.
6405 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6406 strcsequal(fsp->fsp_name->stream_name,
6407 smb_fname_dst->stream_name)) {
6408 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6409 "- returning success\n",
6410 smb_fname_str_dbg(smb_fname_dst)));
6411 status = NT_STATUS_OK;
6412 goto out;
6415 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6416 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6418 /* Return the correct error code if both names aren't streams. */
6419 if (!old_is_stream && new_is_stream) {
6420 status = NT_STATUS_OBJECT_NAME_INVALID;
6421 goto out;
6424 if (old_is_stream && !new_is_stream) {
6425 status = NT_STATUS_INVALID_PARAMETER;
6426 goto out;
6429 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6431 if(!replace_if_exists && dst_exists) {
6432 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6433 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6434 smb_fname_str_dbg(smb_fname_dst)));
6435 status = NT_STATUS_OBJECT_NAME_COLLISION;
6436 goto out;
6439 if (dst_exists) {
6440 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6441 &smb_fname_dst->st);
6442 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6443 fileid);
6444 /* The file can be open when renaming a stream */
6445 if (dst_fsp && !new_is_stream) {
6446 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6447 status = NT_STATUS_ACCESS_DENIED;
6448 goto out;
6452 /* Ensure we have a valid stat struct for the source. */
6453 status = vfs_stat_fsp(fsp);
6454 if (!NT_STATUS_IS_OK(status)) {
6455 goto out;
6458 status = can_rename(conn, fsp, attrs);
6460 if (!NT_STATUS_IS_OK(status)) {
6461 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6462 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6463 smb_fname_str_dbg(smb_fname_dst)));
6464 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6465 status = NT_STATUS_ACCESS_DENIED;
6466 goto out;
6469 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6470 status = NT_STATUS_ACCESS_DENIED;
6473 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6476 * We have the file open ourselves, so not being able to get the
6477 * corresponding share mode lock is a fatal error.
6480 SMB_ASSERT(lck != NULL);
6482 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6483 uint32 create_options = fsp->fh->private_options;
6485 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6486 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6487 smb_fname_str_dbg(smb_fname_dst)));
6489 if (!fsp->is_directory &&
6490 !lp_posix_pathnames() &&
6491 (lp_map_archive(SNUM(conn)) ||
6492 lp_store_dos_attributes(SNUM(conn)))) {
6493 /* We must set the archive bit on the newly
6494 renamed file. */
6495 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6496 uint32_t old_dosmode = dos_mode(conn,
6497 smb_fname_dst);
6498 file_set_dosmode(conn,
6499 smb_fname_dst,
6500 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6501 NULL,
6502 true);
6506 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6507 smb_fname_dst);
6509 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6512 * A rename acts as a new file create w.r.t. allowing an initial delete
6513 * on close, probably because in Windows there is a new handle to the
6514 * new file. If initial delete on close was requested but not
6515 * originally set, we need to set it here. This is probably not 100% correct,
6516 * but will work for the CIFSFS client which in non-posix mode
6517 * depends on these semantics. JRA.
6520 if (create_options & FILE_DELETE_ON_CLOSE) {
6521 status = can_set_delete_on_close(fsp, 0);
6523 if (NT_STATUS_IS_OK(status)) {
6524 /* Note that here we set the *inital* delete on close flag,
6525 * not the regular one. The magic gets handled in close. */
6526 fsp->initial_delete_on_close = True;
6529 TALLOC_FREE(lck);
6530 status = NT_STATUS_OK;
6531 goto out;
6534 TALLOC_FREE(lck);
6536 if (errno == ENOTDIR || errno == EISDIR) {
6537 status = NT_STATUS_OBJECT_NAME_COLLISION;
6538 } else {
6539 status = map_nt_error_from_unix(errno);
6542 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6543 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6544 smb_fname_str_dbg(smb_fname_dst)));
6546 out:
6547 TALLOC_FREE(smb_fname_dst);
6549 return status;
6552 /****************************************************************************
6553 The guts of the rename command, split out so it may be called by the NT SMB
6554 code.
6555 ****************************************************************************/
6557 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6558 connection_struct *conn,
6559 struct smb_request *req,
6560 struct smb_filename *smb_fname_src,
6561 struct smb_filename *smb_fname_dst,
6562 uint32 attrs,
6563 bool replace_if_exists,
6564 bool src_has_wild,
6565 bool dest_has_wild,
6566 uint32_t access_mask)
6568 char *fname_src_dir = NULL;
6569 char *fname_src_mask = NULL;
6570 int count=0;
6571 NTSTATUS status = NT_STATUS_OK;
6572 struct smb_Dir *dir_hnd = NULL;
6573 const char *dname = NULL;
6574 char *talloced = NULL;
6575 long offset = 0;
6576 int create_options = 0;
6577 bool posix_pathnames = lp_posix_pathnames();
6580 * Split the old name into directory and last component
6581 * strings. Note that unix_convert may have stripped off a
6582 * leading ./ from both name and newname if the rename is
6583 * at the root of the share. We need to make sure either both
6584 * name and newname contain a / character or neither of them do
6585 * as this is checked in resolve_wildcards().
6588 /* Split up the directory from the filename/mask. */
6589 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6590 &fname_src_dir, &fname_src_mask);
6591 if (!NT_STATUS_IS_OK(status)) {
6592 status = NT_STATUS_NO_MEMORY;
6593 goto out;
6597 * We should only check the mangled cache
6598 * here if unix_convert failed. This means
6599 * that the path in 'mask' doesn't exist
6600 * on the file system and so we need to look
6601 * for a possible mangle. This patch from
6602 * Tine Smukavec <valentin.smukavec@hermes.si>.
6605 if (!VALID_STAT(smb_fname_src->st) &&
6606 mangle_is_mangled(fname_src_mask, conn->params)) {
6607 char *new_mask = NULL;
6608 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6609 conn->params);
6610 if (new_mask) {
6611 TALLOC_FREE(fname_src_mask);
6612 fname_src_mask = new_mask;
6616 if (!src_has_wild) {
6617 files_struct *fsp;
6620 * Only one file needs to be renamed. Append the mask back
6621 * onto the directory.
6623 TALLOC_FREE(smb_fname_src->base_name);
6624 if (ISDOT(fname_src_dir)) {
6625 /* Ensure we use canonical names on open. */
6626 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6627 "%s",
6628 fname_src_mask);
6629 } else {
6630 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6631 "%s/%s",
6632 fname_src_dir,
6633 fname_src_mask);
6635 if (!smb_fname_src->base_name) {
6636 status = NT_STATUS_NO_MEMORY;
6637 goto out;
6640 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6641 "case_preserve = %d, short case preserve = %d, "
6642 "directory = %s, newname = %s, "
6643 "last_component_dest = %s\n",
6644 conn->case_sensitive, conn->case_preserve,
6645 conn->short_case_preserve,
6646 smb_fname_str_dbg(smb_fname_src),
6647 smb_fname_str_dbg(smb_fname_dst),
6648 smb_fname_dst->original_lcomp));
6650 /* The dest name still may have wildcards. */
6651 if (dest_has_wild) {
6652 char *fname_dst_mod = NULL;
6653 if (!resolve_wildcards(smb_fname_dst,
6654 smb_fname_src->base_name,
6655 smb_fname_dst->base_name,
6656 &fname_dst_mod)) {
6657 DEBUG(6, ("rename_internals: resolve_wildcards "
6658 "%s %s failed\n",
6659 smb_fname_src->base_name,
6660 smb_fname_dst->base_name));
6661 status = NT_STATUS_NO_MEMORY;
6662 goto out;
6664 TALLOC_FREE(smb_fname_dst->base_name);
6665 smb_fname_dst->base_name = fname_dst_mod;
6668 ZERO_STRUCT(smb_fname_src->st);
6669 if (posix_pathnames) {
6670 SMB_VFS_LSTAT(conn, smb_fname_src);
6671 } else {
6672 SMB_VFS_STAT(conn, smb_fname_src);
6675 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6676 create_options |= FILE_DIRECTORY_FILE;
6679 status = SMB_VFS_CREATE_FILE(
6680 conn, /* conn */
6681 req, /* req */
6682 0, /* root_dir_fid */
6683 smb_fname_src, /* fname */
6684 access_mask, /* access_mask */
6685 (FILE_SHARE_READ | /* share_access */
6686 FILE_SHARE_WRITE),
6687 FILE_OPEN, /* create_disposition*/
6688 create_options, /* create_options */
6689 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6690 0, /* oplock_request */
6691 0, /* allocation_size */
6692 0, /* private_flags */
6693 NULL, /* sd */
6694 NULL, /* ea_list */
6695 &fsp, /* result */
6696 NULL); /* pinfo */
6698 if (!NT_STATUS_IS_OK(status)) {
6699 DEBUG(3, ("Could not open rename source %s: %s\n",
6700 smb_fname_str_dbg(smb_fname_src),
6701 nt_errstr(status)));
6702 goto out;
6705 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6706 attrs, replace_if_exists);
6708 close_file(req, fsp, NORMAL_CLOSE);
6710 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6711 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6712 smb_fname_str_dbg(smb_fname_dst)));
6714 goto out;
6718 * Wildcards - process each file that matches.
6720 if (strequal(fname_src_mask, "????????.???")) {
6721 TALLOC_FREE(fname_src_mask);
6722 fname_src_mask = talloc_strdup(ctx, "*");
6723 if (!fname_src_mask) {
6724 status = NT_STATUS_NO_MEMORY;
6725 goto out;
6729 status = check_name(conn, fname_src_dir);
6730 if (!NT_STATUS_IS_OK(status)) {
6731 goto out;
6734 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6735 attrs);
6736 if (dir_hnd == NULL) {
6737 status = map_nt_error_from_unix(errno);
6738 goto out;
6741 status = NT_STATUS_NO_SUCH_FILE;
6743 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6744 * - gentest fix. JRA
6747 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6748 &talloced))) {
6749 files_struct *fsp = NULL;
6750 char *destname = NULL;
6751 bool sysdir_entry = False;
6753 /* Quick check for "." and ".." */
6754 if (ISDOT(dname) || ISDOTDOT(dname)) {
6755 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6756 sysdir_entry = True;
6757 } else {
6758 TALLOC_FREE(talloced);
6759 continue;
6763 if (!is_visible_file(conn, fname_src_dir, dname,
6764 &smb_fname_src->st, false)) {
6765 TALLOC_FREE(talloced);
6766 continue;
6769 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6770 TALLOC_FREE(talloced);
6771 continue;
6774 if (sysdir_entry) {
6775 status = NT_STATUS_OBJECT_NAME_INVALID;
6776 break;
6779 TALLOC_FREE(smb_fname_src->base_name);
6780 if (ISDOT(fname_src_dir)) {
6781 /* Ensure we use canonical names on open. */
6782 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6783 "%s",
6784 dname);
6785 } else {
6786 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6787 "%s/%s",
6788 fname_src_dir,
6789 dname);
6791 if (!smb_fname_src->base_name) {
6792 status = NT_STATUS_NO_MEMORY;
6793 goto out;
6796 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6797 smb_fname_dst->base_name,
6798 &destname)) {
6799 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6800 smb_fname_src->base_name, destname));
6801 TALLOC_FREE(talloced);
6802 continue;
6804 if (!destname) {
6805 status = NT_STATUS_NO_MEMORY;
6806 goto out;
6809 TALLOC_FREE(smb_fname_dst->base_name);
6810 smb_fname_dst->base_name = destname;
6812 ZERO_STRUCT(smb_fname_src->st);
6813 if (posix_pathnames) {
6814 SMB_VFS_LSTAT(conn, smb_fname_src);
6815 } else {
6816 SMB_VFS_STAT(conn, smb_fname_src);
6819 create_options = 0;
6821 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6822 create_options |= FILE_DIRECTORY_FILE;
6825 status = SMB_VFS_CREATE_FILE(
6826 conn, /* conn */
6827 req, /* req */
6828 0, /* root_dir_fid */
6829 smb_fname_src, /* fname */
6830 access_mask, /* access_mask */
6831 (FILE_SHARE_READ | /* share_access */
6832 FILE_SHARE_WRITE),
6833 FILE_OPEN, /* create_disposition*/
6834 create_options, /* create_options */
6835 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6836 0, /* oplock_request */
6837 0, /* allocation_size */
6838 0, /* private_flags */
6839 NULL, /* sd */
6840 NULL, /* ea_list */
6841 &fsp, /* result */
6842 NULL); /* pinfo */
6844 if (!NT_STATUS_IS_OK(status)) {
6845 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6846 "returned %s rename %s -> %s\n",
6847 nt_errstr(status),
6848 smb_fname_str_dbg(smb_fname_src),
6849 smb_fname_str_dbg(smb_fname_dst)));
6850 break;
6853 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6854 dname);
6855 if (!smb_fname_dst->original_lcomp) {
6856 status = NT_STATUS_NO_MEMORY;
6857 goto out;
6860 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6861 attrs, replace_if_exists);
6863 close_file(req, fsp, NORMAL_CLOSE);
6865 if (!NT_STATUS_IS_OK(status)) {
6866 DEBUG(3, ("rename_internals_fsp returned %s for "
6867 "rename %s -> %s\n", nt_errstr(status),
6868 smb_fname_str_dbg(smb_fname_src),
6869 smb_fname_str_dbg(smb_fname_dst)));
6870 break;
6873 count++;
6875 DEBUG(3,("rename_internals: doing rename on %s -> "
6876 "%s\n", smb_fname_str_dbg(smb_fname_src),
6877 smb_fname_str_dbg(smb_fname_src)));
6878 TALLOC_FREE(talloced);
6880 TALLOC_FREE(dir_hnd);
6882 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6883 status = map_nt_error_from_unix(errno);
6886 out:
6887 TALLOC_FREE(talloced);
6888 TALLOC_FREE(fname_src_dir);
6889 TALLOC_FREE(fname_src_mask);
6890 return status;
6893 /****************************************************************************
6894 Reply to a mv.
6895 ****************************************************************************/
6897 void reply_mv(struct smb_request *req)
6899 connection_struct *conn = req->conn;
6900 char *name = NULL;
6901 char *newname = NULL;
6902 const char *p;
6903 uint32 attrs;
6904 NTSTATUS status;
6905 bool src_has_wcard = False;
6906 bool dest_has_wcard = False;
6907 TALLOC_CTX *ctx = talloc_tos();
6908 struct smb_filename *smb_fname_src = NULL;
6909 struct smb_filename *smb_fname_dst = NULL;
6910 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6911 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6912 bool stream_rename = false;
6914 START_PROFILE(SMBmv);
6916 if (req->wct < 1) {
6917 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6918 goto out;
6921 attrs = SVAL(req->vwv+0, 0);
6923 p = (const char *)req->buf + 1;
6924 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6925 &status, &src_has_wcard);
6926 if (!NT_STATUS_IS_OK(status)) {
6927 reply_nterror(req, status);
6928 goto out;
6930 p++;
6931 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6932 &status, &dest_has_wcard);
6933 if (!NT_STATUS_IS_OK(status)) {
6934 reply_nterror(req, status);
6935 goto out;
6938 if (!lp_posix_pathnames()) {
6939 /* The newname must begin with a ':' if the
6940 name contains a ':'. */
6941 if (strchr_m(name, ':')) {
6942 if (newname[0] != ':') {
6943 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6944 goto out;
6946 stream_rename = true;
6950 status = filename_convert(ctx,
6951 conn,
6952 req->flags2 & FLAGS2_DFS_PATHNAMES,
6953 name,
6954 src_ucf_flags,
6955 &src_has_wcard,
6956 &smb_fname_src);
6958 if (!NT_STATUS_IS_OK(status)) {
6959 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6960 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6961 ERRSRV, ERRbadpath);
6962 goto out;
6964 reply_nterror(req, status);
6965 goto out;
6968 status = filename_convert(ctx,
6969 conn,
6970 req->flags2 & FLAGS2_DFS_PATHNAMES,
6971 newname,
6972 dst_ucf_flags,
6973 &dest_has_wcard,
6974 &smb_fname_dst);
6976 if (!NT_STATUS_IS_OK(status)) {
6977 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6978 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6979 ERRSRV, ERRbadpath);
6980 goto out;
6982 reply_nterror(req, status);
6983 goto out;
6986 if (stream_rename) {
6987 /* smb_fname_dst->base_name must be the same as
6988 smb_fname_src->base_name. */
6989 TALLOC_FREE(smb_fname_dst->base_name);
6990 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6991 smb_fname_src->base_name);
6992 if (!smb_fname_dst->base_name) {
6993 reply_nterror(req, NT_STATUS_NO_MEMORY);
6994 goto out;
6998 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6999 smb_fname_str_dbg(smb_fname_dst)));
7001 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7002 attrs, False, src_has_wcard, dest_has_wcard,
7003 DELETE_ACCESS);
7004 if (!NT_STATUS_IS_OK(status)) {
7005 if (open_was_deferred(req->sconn, req->mid)) {
7006 /* We have re-scheduled this call. */
7007 goto out;
7009 reply_nterror(req, status);
7010 goto out;
7013 reply_outbuf(req, 0, 0);
7014 out:
7015 TALLOC_FREE(smb_fname_src);
7016 TALLOC_FREE(smb_fname_dst);
7017 END_PROFILE(SMBmv);
7018 return;
7021 /*******************************************************************
7022 Copy a file as part of a reply_copy.
7023 ******************************************************************/
7026 * TODO: check error codes on all callers
7029 NTSTATUS copy_file(TALLOC_CTX *ctx,
7030 connection_struct *conn,
7031 struct smb_filename *smb_fname_src,
7032 struct smb_filename *smb_fname_dst,
7033 int ofun,
7034 int count,
7035 bool target_is_directory)
7037 struct smb_filename *smb_fname_dst_tmp = NULL;
7038 off_t ret=-1;
7039 files_struct *fsp1,*fsp2;
7040 uint32 dosattrs;
7041 uint32 new_create_disposition;
7042 NTSTATUS status;
7045 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
7046 if (!NT_STATUS_IS_OK(status)) {
7047 return status;
7051 * If the target is a directory, extract the last component from the
7052 * src filename and append it to the dst filename
7054 if (target_is_directory) {
7055 const char *p;
7057 /* dest/target can't be a stream if it's a directory. */
7058 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7060 p = strrchr_m(smb_fname_src->base_name,'/');
7061 if (p) {
7062 p++;
7063 } else {
7064 p = smb_fname_src->base_name;
7066 smb_fname_dst_tmp->base_name =
7067 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7069 if (!smb_fname_dst_tmp->base_name) {
7070 status = NT_STATUS_NO_MEMORY;
7071 goto out;
7075 status = vfs_file_exist(conn, smb_fname_src);
7076 if (!NT_STATUS_IS_OK(status)) {
7077 goto out;
7080 if (!target_is_directory && count) {
7081 new_create_disposition = FILE_OPEN;
7082 } else {
7083 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7084 0, ofun,
7085 NULL, NULL,
7086 &new_create_disposition,
7087 NULL,
7088 NULL)) {
7089 status = NT_STATUS_INVALID_PARAMETER;
7090 goto out;
7094 /* Open the src file for reading. */
7095 status = SMB_VFS_CREATE_FILE(
7096 conn, /* conn */
7097 NULL, /* req */
7098 0, /* root_dir_fid */
7099 smb_fname_src, /* fname */
7100 FILE_GENERIC_READ, /* access_mask */
7101 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7102 FILE_OPEN, /* create_disposition*/
7103 0, /* create_options */
7104 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7105 INTERNAL_OPEN_ONLY, /* oplock_request */
7106 0, /* allocation_size */
7107 0, /* private_flags */
7108 NULL, /* sd */
7109 NULL, /* ea_list */
7110 &fsp1, /* result */
7111 NULL); /* psbuf */
7113 if (!NT_STATUS_IS_OK(status)) {
7114 goto out;
7117 dosattrs = dos_mode(conn, smb_fname_src);
7119 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7120 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7123 /* Open the dst file for writing. */
7124 status = SMB_VFS_CREATE_FILE(
7125 conn, /* conn */
7126 NULL, /* req */
7127 0, /* root_dir_fid */
7128 smb_fname_dst, /* fname */
7129 FILE_GENERIC_WRITE, /* access_mask */
7130 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7131 new_create_disposition, /* create_disposition*/
7132 0, /* create_options */
7133 dosattrs, /* file_attributes */
7134 INTERNAL_OPEN_ONLY, /* oplock_request */
7135 0, /* allocation_size */
7136 0, /* private_flags */
7137 NULL, /* sd */
7138 NULL, /* ea_list */
7139 &fsp2, /* result */
7140 NULL); /* psbuf */
7142 if (!NT_STATUS_IS_OK(status)) {
7143 close_file(NULL, fsp1, ERROR_CLOSE);
7144 goto out;
7147 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7148 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7149 if (ret == -1) {
7150 DEBUG(0, ("error - vfs lseek returned error %s\n",
7151 strerror(errno)));
7152 status = map_nt_error_from_unix(errno);
7153 close_file(NULL, fsp1, ERROR_CLOSE);
7154 close_file(NULL, fsp2, ERROR_CLOSE);
7155 goto out;
7159 /* Do the actual copy. */
7160 if (smb_fname_src->st.st_ex_size) {
7161 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7162 } else {
7163 ret = 0;
7166 close_file(NULL, fsp1, NORMAL_CLOSE);
7168 /* Ensure the modtime is set correctly on the destination file. */
7169 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7172 * As we are opening fsp1 read-only we only expect
7173 * an error on close on fsp2 if we are out of space.
7174 * Thus we don't look at the error return from the
7175 * close of fsp1.
7177 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7179 if (!NT_STATUS_IS_OK(status)) {
7180 goto out;
7183 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7184 status = NT_STATUS_DISK_FULL;
7185 goto out;
7188 status = NT_STATUS_OK;
7190 out:
7191 TALLOC_FREE(smb_fname_dst_tmp);
7192 return status;
7195 /****************************************************************************
7196 Reply to a file copy.
7197 ****************************************************************************/
7199 void reply_copy(struct smb_request *req)
7201 connection_struct *conn = req->conn;
7202 struct smb_filename *smb_fname_src = NULL;
7203 struct smb_filename *smb_fname_dst = NULL;
7204 char *fname_src = NULL;
7205 char *fname_dst = NULL;
7206 char *fname_src_mask = NULL;
7207 char *fname_src_dir = NULL;
7208 const char *p;
7209 int count=0;
7210 int error = ERRnoaccess;
7211 int tid2;
7212 int ofun;
7213 int flags;
7214 bool target_is_directory=False;
7215 bool source_has_wild = False;
7216 bool dest_has_wild = False;
7217 NTSTATUS status;
7218 TALLOC_CTX *ctx = talloc_tos();
7220 START_PROFILE(SMBcopy);
7222 if (req->wct < 3) {
7223 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7224 goto out;
7227 tid2 = SVAL(req->vwv+0, 0);
7228 ofun = SVAL(req->vwv+1, 0);
7229 flags = SVAL(req->vwv+2, 0);
7231 p = (const char *)req->buf;
7232 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7233 &status, &source_has_wild);
7234 if (!NT_STATUS_IS_OK(status)) {
7235 reply_nterror(req, status);
7236 goto out;
7238 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7239 &status, &dest_has_wild);
7240 if (!NT_STATUS_IS_OK(status)) {
7241 reply_nterror(req, status);
7242 goto out;
7245 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7247 if (tid2 != conn->cnum) {
7248 /* can't currently handle inter share copies XXXX */
7249 DEBUG(3,("Rejecting inter-share copy\n"));
7250 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7251 goto out;
7254 status = filename_convert(ctx, conn,
7255 req->flags2 & FLAGS2_DFS_PATHNAMES,
7256 fname_src,
7257 UCF_COND_ALLOW_WCARD_LCOMP,
7258 &source_has_wild,
7259 &smb_fname_src);
7260 if (!NT_STATUS_IS_OK(status)) {
7261 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7262 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7263 ERRSRV, ERRbadpath);
7264 goto out;
7266 reply_nterror(req, status);
7267 goto out;
7270 status = filename_convert(ctx, conn,
7271 req->flags2 & FLAGS2_DFS_PATHNAMES,
7272 fname_dst,
7273 UCF_COND_ALLOW_WCARD_LCOMP,
7274 &dest_has_wild,
7275 &smb_fname_dst);
7276 if (!NT_STATUS_IS_OK(status)) {
7277 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7278 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7279 ERRSRV, ERRbadpath);
7280 goto out;
7282 reply_nterror(req, status);
7283 goto out;
7286 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7288 if ((flags&1) && target_is_directory) {
7289 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7290 goto out;
7293 if ((flags&2) && !target_is_directory) {
7294 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7295 goto out;
7298 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7299 /* wants a tree copy! XXXX */
7300 DEBUG(3,("Rejecting tree copy\n"));
7301 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7302 goto out;
7305 /* Split up the directory from the filename/mask. */
7306 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7307 &fname_src_dir, &fname_src_mask);
7308 if (!NT_STATUS_IS_OK(status)) {
7309 reply_nterror(req, NT_STATUS_NO_MEMORY);
7310 goto out;
7314 * We should only check the mangled cache
7315 * here if unix_convert failed. This means
7316 * that the path in 'mask' doesn't exist
7317 * on the file system and so we need to look
7318 * for a possible mangle. This patch from
7319 * Tine Smukavec <valentin.smukavec@hermes.si>.
7321 if (!VALID_STAT(smb_fname_src->st) &&
7322 mangle_is_mangled(fname_src_mask, conn->params)) {
7323 char *new_mask = NULL;
7324 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7325 &new_mask, conn->params);
7327 /* Use demangled name if one was successfully found. */
7328 if (new_mask) {
7329 TALLOC_FREE(fname_src_mask);
7330 fname_src_mask = new_mask;
7334 if (!source_has_wild) {
7337 * Only one file needs to be copied. Append the mask back onto
7338 * the directory.
7340 TALLOC_FREE(smb_fname_src->base_name);
7341 if (ISDOT(fname_src_dir)) {
7342 /* Ensure we use canonical names on open. */
7343 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7344 "%s",
7345 fname_src_mask);
7346 } else {
7347 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7348 "%s/%s",
7349 fname_src_dir,
7350 fname_src_mask);
7352 if (!smb_fname_src->base_name) {
7353 reply_nterror(req, NT_STATUS_NO_MEMORY);
7354 goto out;
7357 if (dest_has_wild) {
7358 char *fname_dst_mod = NULL;
7359 if (!resolve_wildcards(smb_fname_dst,
7360 smb_fname_src->base_name,
7361 smb_fname_dst->base_name,
7362 &fname_dst_mod)) {
7363 reply_nterror(req, NT_STATUS_NO_MEMORY);
7364 goto out;
7366 TALLOC_FREE(smb_fname_dst->base_name);
7367 smb_fname_dst->base_name = fname_dst_mod;
7370 status = check_name(conn, smb_fname_src->base_name);
7371 if (!NT_STATUS_IS_OK(status)) {
7372 reply_nterror(req, status);
7373 goto out;
7376 status = check_name(conn, smb_fname_dst->base_name);
7377 if (!NT_STATUS_IS_OK(status)) {
7378 reply_nterror(req, status);
7379 goto out;
7382 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7383 ofun, count, target_is_directory);
7385 if(!NT_STATUS_IS_OK(status)) {
7386 reply_nterror(req, status);
7387 goto out;
7388 } else {
7389 count++;
7391 } else {
7392 struct smb_Dir *dir_hnd = NULL;
7393 const char *dname = NULL;
7394 char *talloced = NULL;
7395 long offset = 0;
7398 * There is a wildcard that requires us to actually read the
7399 * src dir and copy each file matching the mask to the dst.
7400 * Right now streams won't be copied, but this could
7401 * presumably be added with a nested loop for reach dir entry.
7403 SMB_ASSERT(!smb_fname_src->stream_name);
7404 SMB_ASSERT(!smb_fname_dst->stream_name);
7406 smb_fname_src->stream_name = NULL;
7407 smb_fname_dst->stream_name = NULL;
7409 if (strequal(fname_src_mask,"????????.???")) {
7410 TALLOC_FREE(fname_src_mask);
7411 fname_src_mask = talloc_strdup(ctx, "*");
7412 if (!fname_src_mask) {
7413 reply_nterror(req, NT_STATUS_NO_MEMORY);
7414 goto out;
7418 status = check_name(conn, fname_src_dir);
7419 if (!NT_STATUS_IS_OK(status)) {
7420 reply_nterror(req, status);
7421 goto out;
7424 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7425 if (dir_hnd == NULL) {
7426 status = map_nt_error_from_unix(errno);
7427 reply_nterror(req, status);
7428 goto out;
7431 error = ERRbadfile;
7433 /* Iterate over the src dir copying each entry to the dst. */
7434 while ((dname = ReadDirName(dir_hnd, &offset,
7435 &smb_fname_src->st, &talloced))) {
7436 char *destname = NULL;
7438 if (ISDOT(dname) || ISDOTDOT(dname)) {
7439 TALLOC_FREE(talloced);
7440 continue;
7443 if (!is_visible_file(conn, fname_src_dir, dname,
7444 &smb_fname_src->st, false)) {
7445 TALLOC_FREE(talloced);
7446 continue;
7449 if(!mask_match(dname, fname_src_mask,
7450 conn->case_sensitive)) {
7451 TALLOC_FREE(talloced);
7452 continue;
7455 error = ERRnoaccess;
7457 /* Get the src smb_fname struct setup. */
7458 TALLOC_FREE(smb_fname_src->base_name);
7459 if (ISDOT(fname_src_dir)) {
7460 /* Ensure we use canonical names on open. */
7461 smb_fname_src->base_name =
7462 talloc_asprintf(smb_fname_src, "%s",
7463 dname);
7464 } else {
7465 smb_fname_src->base_name =
7466 talloc_asprintf(smb_fname_src, "%s/%s",
7467 fname_src_dir, dname);
7470 if (!smb_fname_src->base_name) {
7471 TALLOC_FREE(dir_hnd);
7472 TALLOC_FREE(talloced);
7473 reply_nterror(req, NT_STATUS_NO_MEMORY);
7474 goto out;
7477 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7478 smb_fname_dst->base_name,
7479 &destname)) {
7480 TALLOC_FREE(talloced);
7481 continue;
7483 if (!destname) {
7484 TALLOC_FREE(dir_hnd);
7485 TALLOC_FREE(talloced);
7486 reply_nterror(req, NT_STATUS_NO_MEMORY);
7487 goto out;
7490 TALLOC_FREE(smb_fname_dst->base_name);
7491 smb_fname_dst->base_name = destname;
7493 status = check_name(conn, smb_fname_src->base_name);
7494 if (!NT_STATUS_IS_OK(status)) {
7495 TALLOC_FREE(dir_hnd);
7496 TALLOC_FREE(talloced);
7497 reply_nterror(req, status);
7498 goto out;
7501 status = check_name(conn, smb_fname_dst->base_name);
7502 if (!NT_STATUS_IS_OK(status)) {
7503 TALLOC_FREE(dir_hnd);
7504 TALLOC_FREE(talloced);
7505 reply_nterror(req, status);
7506 goto out;
7509 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7510 smb_fname_src->base_name,
7511 smb_fname_dst->base_name));
7513 status = copy_file(ctx, conn, smb_fname_src,
7514 smb_fname_dst, ofun, count,
7515 target_is_directory);
7516 if (NT_STATUS_IS_OK(status)) {
7517 count++;
7520 TALLOC_FREE(talloced);
7522 TALLOC_FREE(dir_hnd);
7525 if (count == 0) {
7526 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7527 goto out;
7530 reply_outbuf(req, 1, 0);
7531 SSVAL(req->outbuf,smb_vwv0,count);
7532 out:
7533 TALLOC_FREE(smb_fname_src);
7534 TALLOC_FREE(smb_fname_dst);
7535 TALLOC_FREE(fname_src);
7536 TALLOC_FREE(fname_dst);
7537 TALLOC_FREE(fname_src_mask);
7538 TALLOC_FREE(fname_src_dir);
7540 END_PROFILE(SMBcopy);
7541 return;
7544 #undef DBGC_CLASS
7545 #define DBGC_CLASS DBGC_LOCKING
7547 /****************************************************************************
7548 Get a lock pid, dealing with large count requests.
7549 ****************************************************************************/
7551 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7552 bool large_file_format)
7554 if(!large_file_format)
7555 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7556 else
7557 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7560 /****************************************************************************
7561 Get a lock count, dealing with large count requests.
7562 ****************************************************************************/
7564 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7565 bool large_file_format)
7567 uint64_t count = 0;
7569 if(!large_file_format) {
7570 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7571 } else {
7573 #if defined(HAVE_LONGLONG)
7574 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7575 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7576 #else /* HAVE_LONGLONG */
7579 * NT4.x seems to be broken in that it sends large file (64 bit)
7580 * lockingX calls even if the CAP_LARGE_FILES was *not*
7581 * negotiated. For boxes without large unsigned ints truncate the
7582 * lock count by dropping the top 32 bits.
7585 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7586 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7587 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7588 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7589 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7592 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7593 #endif /* HAVE_LONGLONG */
7596 return count;
7599 #if !defined(HAVE_LONGLONG)
7600 /****************************************************************************
7601 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7602 ****************************************************************************/
7604 static uint32 map_lock_offset(uint32 high, uint32 low)
7606 unsigned int i;
7607 uint32 mask = 0;
7608 uint32 highcopy = high;
7611 * Try and find out how many significant bits there are in high.
7614 for(i = 0; highcopy; i++)
7615 highcopy >>= 1;
7618 * We use 31 bits not 32 here as POSIX
7619 * lock offsets may not be negative.
7622 mask = (~0) << (31 - i);
7624 if(low & mask)
7625 return 0; /* Fail. */
7627 high <<= (31 - i);
7629 return (high|low);
7631 #endif /* !defined(HAVE_LONGLONG) */
7633 /****************************************************************************
7634 Get a lock offset, dealing with large offset requests.
7635 ****************************************************************************/
7637 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7638 bool large_file_format, bool *err)
7640 uint64_t offset = 0;
7642 *err = False;
7644 if(!large_file_format) {
7645 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7646 } else {
7648 #if defined(HAVE_LONGLONG)
7649 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7650 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7651 #else /* HAVE_LONGLONG */
7654 * NT4.x seems to be broken in that it sends large file (64 bit)
7655 * lockingX calls even if the CAP_LARGE_FILES was *not*
7656 * negotiated. For boxes without large unsigned ints mangle the
7657 * lock offset by mapping the top 32 bits onto the lower 32.
7660 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7661 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7662 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7663 uint32 new_low = 0;
7665 if((new_low = map_lock_offset(high, low)) == 0) {
7666 *err = True;
7667 return (uint64_t)-1;
7670 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7671 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7672 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7673 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7676 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7677 #endif /* HAVE_LONGLONG */
7680 return offset;
7683 NTSTATUS smbd_do_locking(struct smb_request *req,
7684 files_struct *fsp,
7685 uint8_t type,
7686 int32_t timeout,
7687 uint16_t num_ulocks,
7688 struct smbd_lock_element *ulocks,
7689 uint16_t num_locks,
7690 struct smbd_lock_element *locks,
7691 bool *async)
7693 connection_struct *conn = req->conn;
7694 int i;
7695 NTSTATUS status = NT_STATUS_OK;
7697 *async = false;
7699 /* Data now points at the beginning of the list
7700 of smb_unlkrng structs */
7701 for(i = 0; i < (int)num_ulocks; i++) {
7702 struct smbd_lock_element *e = &ulocks[i];
7704 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7705 "pid %u, file %s\n",
7706 (double)e->offset,
7707 (double)e->count,
7708 (unsigned int)e->smblctx,
7709 fsp_str_dbg(fsp)));
7711 if (e->brltype != UNLOCK_LOCK) {
7712 /* this can only happen with SMB2 */
7713 return NT_STATUS_INVALID_PARAMETER;
7716 status = do_unlock(req->sconn->msg_ctx,
7717 fsp,
7718 e->smblctx,
7719 e->count,
7720 e->offset,
7721 WINDOWS_LOCK);
7723 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7724 nt_errstr(status)));
7726 if (!NT_STATUS_IS_OK(status)) {
7727 return status;
7731 /* Setup the timeout in seconds. */
7733 if (!lp_blocking_locks(SNUM(conn))) {
7734 timeout = 0;
7737 /* Data now points at the beginning of the list
7738 of smb_lkrng structs */
7740 for(i = 0; i < (int)num_locks; i++) {
7741 struct smbd_lock_element *e = &locks[i];
7743 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7744 "%llu, file %s timeout = %d\n",
7745 (double)e->offset,
7746 (double)e->count,
7747 (unsigned long long)e->smblctx,
7748 fsp_str_dbg(fsp),
7749 (int)timeout));
7751 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7752 struct blocking_lock_record *blr = NULL;
7754 if (num_locks > 1) {
7756 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7757 * if the lock vector contains one entry. When given mutliple cancel
7758 * requests in a single PDU we expect the server to return an
7759 * error. Windows servers seem to accept the request but only
7760 * cancel the first lock.
7761 * JRA - Do what Windows does (tm) :-).
7764 #if 0
7765 /* MS-CIFS (2.2.4.32.1) behavior. */
7766 return NT_STATUS_DOS(ERRDOS,
7767 ERRcancelviolation);
7768 #else
7769 /* Windows behavior. */
7770 if (i != 0) {
7771 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7772 "cancel request\n"));
7773 continue;
7775 #endif
7778 if (lp_blocking_locks(SNUM(conn))) {
7780 /* Schedule a message to ourselves to
7781 remove the blocking lock record and
7782 return the right error. */
7784 blr = blocking_lock_cancel_smb1(fsp,
7785 e->smblctx,
7786 e->offset,
7787 e->count,
7788 WINDOWS_LOCK,
7789 type,
7790 NT_STATUS_FILE_LOCK_CONFLICT);
7791 if (blr == NULL) {
7792 return NT_STATUS_DOS(
7793 ERRDOS,
7794 ERRcancelviolation);
7797 /* Remove a matching pending lock. */
7798 status = do_lock_cancel(fsp,
7799 e->smblctx,
7800 e->count,
7801 e->offset,
7802 WINDOWS_LOCK,
7803 blr);
7804 } else {
7805 bool blocking_lock = timeout ? true : false;
7806 bool defer_lock = false;
7807 struct byte_range_lock *br_lck;
7808 uint64_t block_smblctx;
7810 br_lck = do_lock(req->sconn->msg_ctx,
7811 fsp,
7812 e->smblctx,
7813 e->count,
7814 e->offset,
7815 e->brltype,
7816 WINDOWS_LOCK,
7817 blocking_lock,
7818 &status,
7819 &block_smblctx,
7820 NULL);
7822 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7823 /* Windows internal resolution for blocking locks seems
7824 to be about 200ms... Don't wait for less than that. JRA. */
7825 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7826 timeout = lp_lock_spin_time();
7828 defer_lock = true;
7831 /* If a lock sent with timeout of zero would fail, and
7832 * this lock has been requested multiple times,
7833 * according to brl_lock_failed() we convert this
7834 * request to a blocking lock with a timeout of between
7835 * 150 - 300 milliseconds.
7837 * If lp_lock_spin_time() has been set to 0, we skip
7838 * this blocking retry and fail immediately.
7840 * Replacement for do_lock_spin(). JRA. */
7842 if (!req->sconn->using_smb2 &&
7843 br_lck && lp_blocking_locks(SNUM(conn)) &&
7844 lp_lock_spin_time() && !blocking_lock &&
7845 NT_STATUS_EQUAL((status),
7846 NT_STATUS_FILE_LOCK_CONFLICT))
7848 defer_lock = true;
7849 timeout = lp_lock_spin_time();
7852 if (br_lck && defer_lock) {
7854 * A blocking lock was requested. Package up
7855 * this smb into a queued request and push it
7856 * onto the blocking lock queue.
7858 if(push_blocking_lock_request(br_lck,
7859 req,
7860 fsp,
7861 timeout,
7863 e->smblctx,
7864 e->brltype,
7865 WINDOWS_LOCK,
7866 e->offset,
7867 e->count,
7868 block_smblctx)) {
7869 TALLOC_FREE(br_lck);
7870 *async = true;
7871 return NT_STATUS_OK;
7875 TALLOC_FREE(br_lck);
7878 if (!NT_STATUS_IS_OK(status)) {
7879 break;
7883 /* If any of the above locks failed, then we must unlock
7884 all of the previous locks (X/Open spec). */
7886 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7888 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7889 i = -1; /* we want to skip the for loop */
7893 * Ensure we don't do a remove on the lock that just failed,
7894 * as under POSIX rules, if we have a lock already there, we
7895 * will delete it (and we shouldn't) .....
7897 for(i--; i >= 0; i--) {
7898 struct smbd_lock_element *e = &locks[i];
7900 do_unlock(req->sconn->msg_ctx,
7901 fsp,
7902 e->smblctx,
7903 e->count,
7904 e->offset,
7905 WINDOWS_LOCK);
7907 return status;
7910 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7911 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7913 return NT_STATUS_OK;
7916 /****************************************************************************
7917 Reply to a lockingX request.
7918 ****************************************************************************/
7920 void reply_lockingX(struct smb_request *req)
7922 connection_struct *conn = req->conn;
7923 files_struct *fsp;
7924 unsigned char locktype;
7925 unsigned char oplocklevel;
7926 uint16 num_ulocks;
7927 uint16 num_locks;
7928 int32 lock_timeout;
7929 int i;
7930 const uint8_t *data;
7931 bool large_file_format;
7932 bool err;
7933 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7934 struct smbd_lock_element *ulocks;
7935 struct smbd_lock_element *locks;
7936 bool async = false;
7938 START_PROFILE(SMBlockingX);
7940 if (req->wct < 8) {
7941 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7942 END_PROFILE(SMBlockingX);
7943 return;
7946 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7947 locktype = CVAL(req->vwv+3, 0);
7948 oplocklevel = CVAL(req->vwv+3, 1);
7949 num_ulocks = SVAL(req->vwv+6, 0);
7950 num_locks = SVAL(req->vwv+7, 0);
7951 lock_timeout = IVAL(req->vwv+4, 0);
7952 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7954 if (!check_fsp(conn, req, fsp)) {
7955 END_PROFILE(SMBlockingX);
7956 return;
7959 data = req->buf;
7961 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7962 /* we don't support these - and CANCEL_LOCK makes w2k
7963 and XP reboot so I don't really want to be
7964 compatible! (tridge) */
7965 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7966 END_PROFILE(SMBlockingX);
7967 return;
7970 /* Check if this is an oplock break on a file
7971 we have granted an oplock on.
7973 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7974 /* Client can insist on breaking to none. */
7975 bool break_to_none = (oplocklevel == 0);
7976 bool result;
7978 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7979 "for %s\n", (unsigned int)oplocklevel,
7980 fsp_fnum_dbg(fsp)));
7983 * Make sure we have granted an exclusive or batch oplock on
7984 * this file.
7987 if (fsp->oplock_type == 0) {
7989 /* The Samba4 nbench simulator doesn't understand
7990 the difference between break to level2 and break
7991 to none from level2 - it sends oplock break
7992 replies in both cases. Don't keep logging an error
7993 message here - just ignore it. JRA. */
7995 DEBUG(5,("reply_lockingX: Error : oplock break from "
7996 "client for %s (oplock=%d) and no "
7997 "oplock granted on this file (%s).\n",
7998 fsp_fnum_dbg(fsp), fsp->oplock_type,
7999 fsp_str_dbg(fsp)));
8001 /* if this is a pure oplock break request then don't
8002 * send a reply */
8003 if (num_locks == 0 && num_ulocks == 0) {
8004 END_PROFILE(SMBlockingX);
8005 return;
8006 } else {
8007 END_PROFILE(SMBlockingX);
8008 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8009 return;
8013 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8014 (break_to_none)) {
8015 result = remove_oplock(fsp);
8016 } else {
8017 result = downgrade_oplock(fsp);
8020 if (!result) {
8021 DEBUG(0, ("reply_lockingX: error in removing "
8022 "oplock on file %s\n", fsp_str_dbg(fsp)));
8023 /* Hmmm. Is this panic justified? */
8024 smb_panic("internal tdb error");
8027 reply_to_oplock_break_requests(fsp);
8029 /* if this is a pure oplock break request then don't send a
8030 * reply */
8031 if (num_locks == 0 && num_ulocks == 0) {
8032 /* Sanity check - ensure a pure oplock break is not a
8033 chained request. */
8034 if(CVAL(req->vwv+0, 0) != 0xff)
8035 DEBUG(0,("reply_lockingX: Error : pure oplock "
8036 "break is a chained %d request !\n",
8037 (unsigned int)CVAL(req->vwv+0, 0)));
8038 END_PROFILE(SMBlockingX);
8039 return;
8043 if (req->buflen <
8044 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8045 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8046 END_PROFILE(SMBlockingX);
8047 return;
8050 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8051 if (ulocks == NULL) {
8052 reply_nterror(req, NT_STATUS_NO_MEMORY);
8053 END_PROFILE(SMBlockingX);
8054 return;
8057 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8058 if (locks == NULL) {
8059 reply_nterror(req, NT_STATUS_NO_MEMORY);
8060 END_PROFILE(SMBlockingX);
8061 return;
8064 /* Data now points at the beginning of the list
8065 of smb_unlkrng structs */
8066 for(i = 0; i < (int)num_ulocks; i++) {
8067 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8068 ulocks[i].count = get_lock_count(data, i, large_file_format);
8069 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8070 ulocks[i].brltype = UNLOCK_LOCK;
8073 * There is no error code marked "stupid client bug".... :-).
8075 if(err) {
8076 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8077 END_PROFILE(SMBlockingX);
8078 return;
8082 /* Now do any requested locks */
8083 data += ((large_file_format ? 20 : 10)*num_ulocks);
8085 /* Data now points at the beginning of the list
8086 of smb_lkrng structs */
8088 for(i = 0; i < (int)num_locks; i++) {
8089 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8090 locks[i].count = get_lock_count(data, i, large_file_format);
8091 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8093 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8094 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8095 locks[i].brltype = PENDING_READ_LOCK;
8096 } else {
8097 locks[i].brltype = READ_LOCK;
8099 } else {
8100 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8101 locks[i].brltype = PENDING_WRITE_LOCK;
8102 } else {
8103 locks[i].brltype = WRITE_LOCK;
8108 * There is no error code marked "stupid client bug".... :-).
8110 if(err) {
8111 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8112 END_PROFILE(SMBlockingX);
8113 return;
8117 status = smbd_do_locking(req, fsp,
8118 locktype, lock_timeout,
8119 num_ulocks, ulocks,
8120 num_locks, locks,
8121 &async);
8122 if (!NT_STATUS_IS_OK(status)) {
8123 END_PROFILE(SMBlockingX);
8124 reply_nterror(req, status);
8125 return;
8127 if (async) {
8128 END_PROFILE(SMBlockingX);
8129 return;
8132 reply_outbuf(req, 2, 0);
8133 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8134 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8136 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8137 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8139 END_PROFILE(SMBlockingX);
8142 #undef DBGC_CLASS
8143 #define DBGC_CLASS DBGC_ALL
8145 /****************************************************************************
8146 Reply to a SMBreadbmpx (read block multiplex) request.
8147 Always reply with an error, if someone has a platform really needs this,
8148 please contact vl@samba.org
8149 ****************************************************************************/
8151 void reply_readbmpx(struct smb_request *req)
8153 START_PROFILE(SMBreadBmpx);
8154 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8155 END_PROFILE(SMBreadBmpx);
8156 return;
8159 /****************************************************************************
8160 Reply to a SMBreadbs (read block multiplex secondary) request.
8161 Always reply with an error, if someone has a platform really needs this,
8162 please contact vl@samba.org
8163 ****************************************************************************/
8165 void reply_readbs(struct smb_request *req)
8167 START_PROFILE(SMBreadBs);
8168 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8169 END_PROFILE(SMBreadBs);
8170 return;
8173 /****************************************************************************
8174 Reply to a SMBsetattrE.
8175 ****************************************************************************/
8177 void reply_setattrE(struct smb_request *req)
8179 connection_struct *conn = req->conn;
8180 struct smb_file_time ft;
8181 files_struct *fsp;
8182 NTSTATUS status;
8184 START_PROFILE(SMBsetattrE);
8185 ZERO_STRUCT(ft);
8187 if (req->wct < 7) {
8188 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8189 goto out;
8192 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8194 if(!fsp || (fsp->conn != conn)) {
8195 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8196 goto out;
8200 * Convert the DOS times into unix times.
8203 ft.atime = convert_time_t_to_timespec(
8204 srv_make_unix_date2(req->vwv+3));
8205 ft.mtime = convert_time_t_to_timespec(
8206 srv_make_unix_date2(req->vwv+5));
8207 ft.create_time = convert_time_t_to_timespec(
8208 srv_make_unix_date2(req->vwv+1));
8210 reply_outbuf(req, 0, 0);
8213 * Patch from Ray Frush <frush@engr.colostate.edu>
8214 * Sometimes times are sent as zero - ignore them.
8217 /* Ensure we have a valid stat struct for the source. */
8218 status = vfs_stat_fsp(fsp);
8219 if (!NT_STATUS_IS_OK(status)) {
8220 reply_nterror(req, status);
8221 goto out;
8224 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8225 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8226 goto out;
8229 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8230 if (!NT_STATUS_IS_OK(status)) {
8231 reply_nterror(req, status);
8232 goto out;
8235 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8236 " createtime=%u\n",
8237 fsp_fnum_dbg(fsp),
8238 (unsigned int)ft.atime.tv_sec,
8239 (unsigned int)ft.mtime.tv_sec,
8240 (unsigned int)ft.create_time.tv_sec
8242 out:
8243 END_PROFILE(SMBsetattrE);
8244 return;
8248 /* Back from the dead for OS/2..... JRA. */
8250 /****************************************************************************
8251 Reply to a SMBwritebmpx (write block multiplex primary) request.
8252 Always reply with an error, if someone has a platform really needs this,
8253 please contact vl@samba.org
8254 ****************************************************************************/
8256 void reply_writebmpx(struct smb_request *req)
8258 START_PROFILE(SMBwriteBmpx);
8259 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8260 END_PROFILE(SMBwriteBmpx);
8261 return;
8264 /****************************************************************************
8265 Reply to a SMBwritebs (write block multiplex secondary) request.
8266 Always reply with an error, if someone has a platform really needs this,
8267 please contact vl@samba.org
8268 ****************************************************************************/
8270 void reply_writebs(struct smb_request *req)
8272 START_PROFILE(SMBwriteBs);
8273 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8274 END_PROFILE(SMBwriteBs);
8275 return;
8278 /****************************************************************************
8279 Reply to a SMBgetattrE.
8280 ****************************************************************************/
8282 void reply_getattrE(struct smb_request *req)
8284 connection_struct *conn = req->conn;
8285 int mode;
8286 files_struct *fsp;
8287 struct timespec create_ts;
8289 START_PROFILE(SMBgetattrE);
8291 if (req->wct < 1) {
8292 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8293 END_PROFILE(SMBgetattrE);
8294 return;
8297 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8299 if(!fsp || (fsp->conn != conn)) {
8300 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8301 END_PROFILE(SMBgetattrE);
8302 return;
8305 /* Do an fstat on this file */
8306 if(fsp_stat(fsp)) {
8307 reply_nterror(req, map_nt_error_from_unix(errno));
8308 END_PROFILE(SMBgetattrE);
8309 return;
8312 mode = dos_mode(conn, fsp->fsp_name);
8315 * Convert the times into dos times. Set create
8316 * date to be last modify date as UNIX doesn't save
8317 * this.
8320 reply_outbuf(req, 11, 0);
8322 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8323 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8324 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8325 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8326 /* Should we check pending modtime here ? JRA */
8327 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8328 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8330 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8331 SIVAL(req->outbuf, smb_vwv6, 0);
8332 SIVAL(req->outbuf, smb_vwv8, 0);
8333 } else {
8334 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8335 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8336 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8338 SSVAL(req->outbuf,smb_vwv10, mode);
8340 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8342 END_PROFILE(SMBgetattrE);
8343 return;