smbd: Sort notify events by timestamp
[Samba.git] / source3 / smbd / reply.c
blobda59ca75ae1bb2c1f50a06e7b4a99728d78fd010
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);
343 * pull a string from the smb_buf part of a packet. In this case the
344 * string can either be null terminated or it can be terminated by the
345 * end of the smbbuf area
347 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
348 char **dest, const uint8_t *src, int flags)
350 ssize_t bufrem = smbreq_bufrem(req, src);
352 if (bufrem < 0) {
353 return 0;
356 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
357 bufrem, flags);
360 /****************************************************************************
361 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
362 ****************************************************************************/
364 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
365 files_struct *fsp)
367 if ((fsp == NULL) || (conn == NULL)) {
368 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
369 return False;
371 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
372 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
373 return False;
375 return True;
378 /****************************************************************************
379 Check if we have a correct fsp pointing to a file.
380 ****************************************************************************/
382 bool check_fsp(connection_struct *conn, struct smb_request *req,
383 files_struct *fsp)
385 if (!check_fsp_open(conn, req, fsp)) {
386 return False;
388 if (fsp->is_directory) {
389 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
390 return False;
392 if (fsp->fh->fd == -1) {
393 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
394 return False;
396 fsp->num_smb_operations++;
397 return True;
400 /****************************************************************************
401 Check if we have a correct fsp pointing to a quota fake file. Replacement for
402 the CHECK_NTQUOTA_HANDLE_OK macro.
403 ****************************************************************************/
405 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
406 files_struct *fsp)
408 if (!check_fsp_open(conn, req, fsp)) {
409 return false;
412 if (fsp->is_directory) {
413 return false;
416 if (fsp->fake_file_handle == NULL) {
417 return false;
420 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
421 return false;
424 if (fsp->fake_file_handle->private_data == NULL) {
425 return false;
428 return true;
431 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
432 const char *name, int name_type)
434 char *trim_name;
435 char *trim_name_type;
436 const char *retarget_parm;
437 char *retarget;
438 char *p;
439 int retarget_type = 0x20;
440 int retarget_port = NBT_SMB_PORT;
441 struct sockaddr_storage retarget_addr;
442 struct sockaddr_in *in_addr;
443 bool ret = false;
444 uint8_t outbuf[10];
446 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
447 return false;
450 trim_name = talloc_strdup(talloc_tos(), name);
451 if (trim_name == NULL) {
452 goto fail;
454 trim_char(trim_name, ' ', ' ');
456 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
457 name_type);
458 if (trim_name_type == NULL) {
459 goto fail;
462 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
463 trim_name_type, NULL);
464 if (retarget_parm == NULL) {
465 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
466 trim_name, NULL);
468 if (retarget_parm == NULL) {
469 goto fail;
472 retarget = talloc_strdup(trim_name, retarget_parm);
473 if (retarget == NULL) {
474 goto fail;
477 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
479 p = strchr(retarget, ':');
480 if (p != NULL) {
481 *p++ = '\0';
482 retarget_port = atoi(p);
485 p = strchr_m(retarget, '#');
486 if (p != NULL) {
487 *p++ = '\0';
488 if (sscanf(p, "%x", &retarget_type) != 1) {
489 goto fail;
493 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
494 if (!ret) {
495 DEBUG(10, ("could not resolve %s\n", retarget));
496 goto fail;
499 if (retarget_addr.ss_family != AF_INET) {
500 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
501 goto fail;
504 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
506 _smb_setlen(outbuf, 6);
507 SCVAL(outbuf, 0, 0x84);
508 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
509 *(uint16_t *)(outbuf+8) = htons(retarget_port);
511 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
512 NULL)) {
513 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
514 "failed.");
517 ret = true;
518 fail:
519 TALLOC_FREE(trim_name);
520 return ret;
523 static void reply_called_name_not_present(char *outbuf)
525 smb_setlen(outbuf, 1);
526 SCVAL(outbuf, 0, 0x83);
527 SCVAL(outbuf, 4, 0x82);
530 /****************************************************************************
531 Reply to a (netbios-level) special message.
532 ****************************************************************************/
534 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
536 int msg_type = CVAL(inbuf,0);
537 int msg_flags = CVAL(inbuf,1);
539 * We only really use 4 bytes of the outbuf, but for the smb_setlen
540 * calculation & friends (srv_send_smb uses that) we need the full smb
541 * header.
543 char outbuf[smb_size];
545 memset(outbuf, '\0', sizeof(outbuf));
547 smb_setlen(outbuf,0);
549 switch (msg_type) {
550 case NBSSrequest: /* session request */
552 /* inbuf_size is guarenteed to be at least 4. */
553 fstring name1,name2;
554 int name_type1, name_type2;
555 int name_len1, name_len2;
557 *name1 = *name2 = 0;
559 if (sconn->nbt.got_session) {
560 exit_server_cleanly("multiple session request not permitted");
563 SCVAL(outbuf,0,NBSSpositive);
564 SCVAL(outbuf,3,0);
566 /* inbuf_size is guaranteed to be at least 4. */
567 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
568 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
569 DEBUG(0,("Invalid name length in session request\n"));
570 reply_called_name_not_present(outbuf);
571 break;
573 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
574 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
575 DEBUG(0,("Invalid name length in session request\n"));
576 reply_called_name_not_present(outbuf);
577 break;
580 name_type1 = name_extract((unsigned char *)inbuf,
581 inbuf_size,(unsigned int)4,name1);
582 name_type2 = name_extract((unsigned char *)inbuf,
583 inbuf_size,(unsigned int)(4 + name_len1),name2);
585 if (name_type1 == -1 || name_type2 == -1) {
586 DEBUG(0,("Invalid name type in session request\n"));
587 reply_called_name_not_present(outbuf);
588 break;
591 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
592 name1, name_type1, name2, name_type2));
594 if (netbios_session_retarget(sconn, name1, name_type1)) {
595 exit_server_cleanly("retargeted client");
599 * Windows NT/2k uses "*SMBSERVER" and XP uses
600 * "*SMBSERV" arrggg!!!
602 if (strequal(name1, "*SMBSERVER ")
603 || strequal(name1, "*SMBSERV ")) {
604 char *raddr;
606 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
607 talloc_tos());
608 if (raddr == NULL) {
609 exit_server_cleanly("could not allocate raddr");
612 fstrcpy(name1, raddr);
615 set_local_machine_name(name1, True);
616 set_remote_machine_name(name2, True);
618 if (is_ipaddress(sconn->remote_hostname)) {
619 char *p = discard_const_p(char, sconn->remote_hostname);
621 talloc_free(p);
623 sconn->remote_hostname = talloc_strdup(sconn,
624 get_remote_machine_name());
625 if (sconn->remote_hostname == NULL) {
626 exit_server_cleanly("could not copy remote name");
628 sconn->conn->remote_hostname = sconn->remote_hostname;
631 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
632 get_local_machine_name(), get_remote_machine_name(),
633 name_type2));
635 if (name_type2 == 'R') {
636 /* We are being asked for a pathworks session ---
637 no thanks! */
638 reply_called_name_not_present(outbuf);
639 break;
642 reload_services(sconn, conn_snum_used, true);
643 reopen_logs();
645 sconn->nbt.got_session = true;
646 break;
649 case 0x89: /* session keepalive request
650 (some old clients produce this?) */
651 SCVAL(outbuf,0,NBSSkeepalive);
652 SCVAL(outbuf,3,0);
653 break;
655 case NBSSpositive: /* positive session response */
656 case NBSSnegative: /* negative session response */
657 case NBSSretarget: /* retarget session response */
658 DEBUG(0,("Unexpected session response\n"));
659 break;
661 case NBSSkeepalive: /* session keepalive */
662 default:
663 return;
666 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
667 msg_type, msg_flags));
669 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
671 if (CVAL(outbuf, 0) != 0x82) {
672 exit_server_cleanly("invalid netbios session");
674 return;
677 /****************************************************************************
678 Reply to a tcon.
679 conn POINTER CAN BE NULL HERE !
680 ****************************************************************************/
682 void reply_tcon(struct smb_request *req)
684 connection_struct *conn = req->conn;
685 const char *service;
686 char *service_buf = NULL;
687 char *password = NULL;
688 char *dev = NULL;
689 int pwlen=0;
690 NTSTATUS nt_status;
691 const uint8_t *p;
692 const char *p2;
693 TALLOC_CTX *ctx = talloc_tos();
694 struct smbd_server_connection *sconn = req->sconn;
695 NTTIME now = timeval_to_nttime(&req->request_time);
697 START_PROFILE(SMBtcon);
699 if (req->buflen < 4) {
700 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
701 END_PROFILE(SMBtcon);
702 return;
705 p = req->buf + 1;
706 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
707 p += 1;
708 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
709 p += pwlen+1;
710 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
711 p += 1;
713 if (service_buf == NULL || password == NULL || dev == NULL) {
714 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
715 END_PROFILE(SMBtcon);
716 return;
718 p2 = strrchr_m(service_buf,'\\');
719 if (p2) {
720 service = p2+1;
721 } else {
722 service = service_buf;
725 conn = make_connection(sconn, now, service, dev,
726 req->vuid,&nt_status);
727 req->conn = conn;
729 if (!conn) {
730 reply_nterror(req, nt_status);
731 END_PROFILE(SMBtcon);
732 return;
735 reply_outbuf(req, 2, 0);
736 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
737 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
738 SSVAL(req->outbuf,smb_tid,conn->cnum);
740 DEBUG(3,("tcon service=%s cnum=%d\n",
741 service, conn->cnum));
743 END_PROFILE(SMBtcon);
744 return;
747 /****************************************************************************
748 Reply to a tcon and X.
749 conn POINTER CAN BE NULL HERE !
750 ****************************************************************************/
752 void reply_tcon_and_X(struct smb_request *req)
754 connection_struct *conn = req->conn;
755 const char *service = NULL;
756 TALLOC_CTX *ctx = talloc_tos();
757 /* what the cleint thinks the device is */
758 char *client_devicetype = NULL;
759 /* what the server tells the client the share represents */
760 const char *server_devicetype;
761 NTSTATUS nt_status;
762 int passlen;
763 char *path = NULL;
764 const uint8_t *p;
765 const char *q;
766 uint16_t tcon_flags;
767 struct smbXsrv_session *session = NULL;
768 NTTIME now = timeval_to_nttime(&req->request_time);
769 bool session_key_updated = false;
770 uint16_t optional_support = 0;
771 struct smbd_server_connection *sconn = req->sconn;
773 START_PROFILE(SMBtconX);
775 if (req->wct < 4) {
776 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
777 END_PROFILE(SMBtconX);
778 return;
781 passlen = SVAL(req->vwv+3, 0);
782 tcon_flags = SVAL(req->vwv+2, 0);
784 /* we might have to close an old one */
785 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
786 struct smbXsrv_tcon *tcon;
787 NTSTATUS status;
789 tcon = conn->tcon;
790 req->conn = NULL;
791 conn = NULL;
794 * TODO: cancel all outstanding requests on the tcon
796 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
797 if (!NT_STATUS_IS_OK(status)) {
798 DEBUG(0, ("reply_tcon_and_X: "
799 "smbXsrv_tcon_disconnect() failed: %s\n",
800 nt_errstr(status)));
802 * If we hit this case, there is something completely
803 * wrong, so we better disconnect the transport connection.
805 END_PROFILE(SMBtconX);
806 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
807 return;
810 TALLOC_FREE(tcon);
813 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
814 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
815 END_PROFILE(SMBtconX);
816 return;
819 if (sconn->smb1.negprot.encrypted_passwords) {
820 p = req->buf + passlen;
821 } else {
822 p = req->buf + passlen + 1;
825 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
827 if (path == NULL) {
828 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
829 END_PROFILE(SMBtconX);
830 return;
834 * the service name can be either: \\server\share
835 * or share directly like on the DELL PowerVault 705
837 if (*path=='\\') {
838 q = strchr_m(path+2,'\\');
839 if (!q) {
840 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
841 END_PROFILE(SMBtconX);
842 return;
844 service = q+1;
845 } else {
846 service = path;
849 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
850 &client_devicetype, p,
851 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
853 if (client_devicetype == NULL) {
854 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
855 END_PROFILE(SMBtconX);
856 return;
859 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
861 nt_status = smb1srv_session_lookup(req->sconn->conn,
862 req->vuid, now, &session);
863 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
864 reply_force_doserror(req, ERRSRV, ERRbaduid);
865 END_PROFILE(SMBtconX);
866 return;
868 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
869 reply_nterror(req, nt_status);
870 END_PROFILE(SMBtconX);
871 return;
873 if (!NT_STATUS_IS_OK(nt_status)) {
874 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
875 END_PROFILE(SMBtconX);
876 return;
879 if (session->global->auth_session_info == NULL) {
880 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
881 END_PROFILE(SMBtconX);
882 return;
886 * If there is no application key defined yet
887 * we create one.
889 * This means we setup the application key on the
890 * first tcon that happens via the given session.
892 * Once the application key is defined, it does not
893 * change any more.
895 if (session->global->application_key.length == 0 &&
896 session->global->signing_key.length > 0)
898 struct smbXsrv_session *x = session;
899 struct auth_session_info *session_info =
900 session->global->auth_session_info;
901 uint8_t session_key[16];
903 ZERO_STRUCT(session_key);
904 memcpy(session_key, x->global->signing_key.data,
905 MIN(x->global->signing_key.length, sizeof(session_key)));
908 * The application key is truncated/padded to 16 bytes
910 x->global->application_key = data_blob_talloc(x->global,
911 session_key,
912 sizeof(session_key));
913 ZERO_STRUCT(session_key);
914 if (x->global->application_key.data == NULL) {
915 reply_nterror(req, NT_STATUS_NO_MEMORY);
916 END_PROFILE(SMBtconX);
917 return;
920 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
921 smb_key_derivation(x->global->application_key.data,
922 x->global->application_key.length,
923 x->global->application_key.data);
924 optional_support |= SMB_EXTENDED_SIGNATURES;
928 * Place the application key into the session_info
930 data_blob_clear_free(&session_info->session_key);
931 session_info->session_key = data_blob_dup_talloc(session_info,
932 x->global->application_key);
933 if (session_info->session_key.data == NULL) {
934 data_blob_clear_free(&x->global->application_key);
935 reply_nterror(req, NT_STATUS_NO_MEMORY);
936 END_PROFILE(SMBtconX);
937 return;
939 session_key_updated = true;
942 conn = make_connection(sconn, now, service, client_devicetype,
943 req->vuid, &nt_status);
944 req->conn =conn;
946 if (!conn) {
947 if (session_key_updated) {
948 struct smbXsrv_session *x = session;
949 struct auth_session_info *session_info =
950 session->global->auth_session_info;
951 data_blob_clear_free(&x->global->application_key);
952 data_blob_clear_free(&session_info->session_key);
954 reply_nterror(req, nt_status);
955 END_PROFILE(SMBtconX);
956 return;
959 if ( IS_IPC(conn) )
960 server_devicetype = "IPC";
961 else if ( IS_PRINT(conn) )
962 server_devicetype = "LPT1:";
963 else
964 server_devicetype = "A:";
966 if (get_Protocol() < PROTOCOL_NT1) {
967 reply_outbuf(req, 2, 0);
968 if (message_push_string(&req->outbuf, server_devicetype,
969 STR_TERMINATE|STR_ASCII) == -1) {
970 reply_nterror(req, NT_STATUS_NO_MEMORY);
971 END_PROFILE(SMBtconX);
972 return;
974 } else {
975 /* NT sets the fstype of IPC$ to the null string */
976 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
978 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
979 /* Return permissions. */
980 uint32 perm1 = 0;
981 uint32 perm2 = 0;
983 reply_outbuf(req, 7, 0);
985 if (IS_IPC(conn)) {
986 perm1 = FILE_ALL_ACCESS;
987 perm2 = FILE_ALL_ACCESS;
988 } else {
989 perm1 = conn->share_access;
992 SIVAL(req->outbuf, smb_vwv3, perm1);
993 SIVAL(req->outbuf, smb_vwv5, perm2);
994 } else {
995 reply_outbuf(req, 3, 0);
998 if ((message_push_string(&req->outbuf, server_devicetype,
999 STR_TERMINATE|STR_ASCII) == -1)
1000 || (message_push_string(&req->outbuf, fstype,
1001 STR_TERMINATE) == -1)) {
1002 reply_nterror(req, NT_STATUS_NO_MEMORY);
1003 END_PROFILE(SMBtconX);
1004 return;
1007 /* what does setting this bit do? It is set by NT4 and
1008 may affect the ability to autorun mounted cdroms */
1009 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1010 optional_support |=
1011 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1013 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1014 DEBUG(2,("Serving %s as a Dfs root\n",
1015 lp_servicename(ctx, SNUM(conn)) ));
1016 optional_support |= SMB_SHARE_IN_DFS;
1019 SSVAL(req->outbuf, smb_vwv2, optional_support);
1022 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1023 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1025 DEBUG(3,("tconX service=%s \n",
1026 service));
1028 /* set the incoming and outgoing tid to the just created one */
1029 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1030 SSVAL(req->outbuf,smb_tid,conn->cnum);
1032 END_PROFILE(SMBtconX);
1034 req->tid = conn->cnum;
1037 /****************************************************************************
1038 Reply to an unknown type.
1039 ****************************************************************************/
1041 void reply_unknown_new(struct smb_request *req, uint8 type)
1043 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1044 smb_fn_name(type), type, type));
1045 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1046 return;
1049 /****************************************************************************
1050 Reply to an ioctl.
1051 conn POINTER CAN BE NULL HERE !
1052 ****************************************************************************/
1054 void reply_ioctl(struct smb_request *req)
1056 connection_struct *conn = req->conn;
1057 uint16 device;
1058 uint16 function;
1059 uint32 ioctl_code;
1060 int replysize;
1061 char *p;
1063 START_PROFILE(SMBioctl);
1065 if (req->wct < 3) {
1066 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1067 END_PROFILE(SMBioctl);
1068 return;
1071 device = SVAL(req->vwv+1, 0);
1072 function = SVAL(req->vwv+2, 0);
1073 ioctl_code = (device << 16) + function;
1075 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1077 switch (ioctl_code) {
1078 case IOCTL_QUERY_JOB_INFO:
1079 replysize = 32;
1080 break;
1081 default:
1082 reply_force_doserror(req, ERRSRV, ERRnosupport);
1083 END_PROFILE(SMBioctl);
1084 return;
1087 reply_outbuf(req, 8, replysize+1);
1088 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1089 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1090 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1091 p = smb_buf(req->outbuf);
1092 memset(p, '\0', replysize+1); /* valgrind-safe. */
1093 p += 1; /* Allow for alignment */
1095 switch (ioctl_code) {
1096 case IOCTL_QUERY_JOB_INFO:
1098 files_struct *fsp = file_fsp(
1099 req, SVAL(req->vwv+0, 0));
1100 if (!fsp) {
1101 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1102 END_PROFILE(SMBioctl);
1103 return;
1105 /* Job number */
1106 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1108 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1109 lp_netbios_name(), 15,
1110 STR_TERMINATE|STR_ASCII);
1111 if (conn) {
1112 srvstr_push((char *)req->outbuf, req->flags2,
1113 p+18,
1114 lp_servicename(talloc_tos(),
1115 SNUM(conn)),
1116 13, STR_TERMINATE|STR_ASCII);
1117 } else {
1118 memset(p+18, 0, 13);
1120 break;
1124 END_PROFILE(SMBioctl);
1125 return;
1128 /****************************************************************************
1129 Strange checkpath NTSTATUS mapping.
1130 ****************************************************************************/
1132 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1134 /* Strange DOS error code semantics only for checkpath... */
1135 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1136 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1137 /* We need to map to ERRbadpath */
1138 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1141 return status;
1144 /****************************************************************************
1145 Reply to a checkpath.
1146 ****************************************************************************/
1148 void reply_checkpath(struct smb_request *req)
1150 connection_struct *conn = req->conn;
1151 struct smb_filename *smb_fname = NULL;
1152 char *name = NULL;
1153 NTSTATUS status;
1154 TALLOC_CTX *ctx = talloc_tos();
1156 START_PROFILE(SMBcheckpath);
1158 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1159 STR_TERMINATE, &status);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 status = map_checkpath_error(req->flags2, status);
1163 reply_nterror(req, status);
1164 END_PROFILE(SMBcheckpath);
1165 return;
1168 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1170 status = filename_convert(ctx,
1171 conn,
1172 req->flags2 & FLAGS2_DFS_PATHNAMES,
1173 name,
1175 NULL,
1176 &smb_fname);
1178 if (!NT_STATUS_IS_OK(status)) {
1179 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1180 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1181 ERRSRV, ERRbadpath);
1182 END_PROFILE(SMBcheckpath);
1183 return;
1185 goto path_err;
1188 if (!VALID_STAT(smb_fname->st) &&
1189 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1190 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1191 smb_fname_str_dbg(smb_fname), strerror(errno)));
1192 status = map_nt_error_from_unix(errno);
1193 goto path_err;
1196 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1197 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1198 ERRDOS, ERRbadpath);
1199 goto out;
1202 reply_outbuf(req, 0, 0);
1204 path_err:
1205 /* We special case this - as when a Windows machine
1206 is parsing a path is steps through the components
1207 one at a time - if a component fails it expects
1208 ERRbadpath, not ERRbadfile.
1210 status = map_checkpath_error(req->flags2, status);
1211 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1213 * Windows returns different error codes if
1214 * the parent directory is valid but not the
1215 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1216 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1217 * if the path is invalid.
1219 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1220 ERRDOS, ERRbadpath);
1221 goto out;
1224 reply_nterror(req, status);
1226 out:
1227 TALLOC_FREE(smb_fname);
1228 END_PROFILE(SMBcheckpath);
1229 return;
1232 /****************************************************************************
1233 Reply to a getatr.
1234 ****************************************************************************/
1236 void reply_getatr(struct smb_request *req)
1238 connection_struct *conn = req->conn;
1239 struct smb_filename *smb_fname = NULL;
1240 char *fname = NULL;
1241 int mode=0;
1242 off_t size=0;
1243 time_t mtime=0;
1244 const char *p;
1245 NTSTATUS status;
1246 TALLOC_CTX *ctx = talloc_tos();
1247 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1249 START_PROFILE(SMBgetatr);
1251 p = (const char *)req->buf + 1;
1252 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1253 if (!NT_STATUS_IS_OK(status)) {
1254 reply_nterror(req, status);
1255 goto out;
1258 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1259 under WfWg - weird! */
1260 if (*fname == '\0') {
1261 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1262 if (!CAN_WRITE(conn)) {
1263 mode |= FILE_ATTRIBUTE_READONLY;
1265 size = 0;
1266 mtime = 0;
1267 } else {
1268 status = filename_convert(ctx,
1269 conn,
1270 req->flags2 & FLAGS2_DFS_PATHNAMES,
1271 fname,
1273 NULL,
1274 &smb_fname);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1277 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1278 ERRSRV, ERRbadpath);
1279 goto out;
1281 reply_nterror(req, status);
1282 goto out;
1284 if (!VALID_STAT(smb_fname->st) &&
1285 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1286 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1287 smb_fname_str_dbg(smb_fname),
1288 strerror(errno)));
1289 reply_nterror(req, map_nt_error_from_unix(errno));
1290 goto out;
1293 mode = dos_mode(conn, smb_fname);
1294 size = smb_fname->st.st_ex_size;
1296 if (ask_sharemode) {
1297 struct timespec write_time_ts;
1298 struct file_id fileid;
1300 ZERO_STRUCT(write_time_ts);
1301 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1302 get_file_infos(fileid, 0, NULL, &write_time_ts);
1303 if (!null_timespec(write_time_ts)) {
1304 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1308 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1309 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1310 size = 0;
1314 reply_outbuf(req, 10, 0);
1316 SSVAL(req->outbuf,smb_vwv0,mode);
1317 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1318 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1319 } else {
1320 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1322 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1324 if (get_Protocol() >= PROTOCOL_NT1) {
1325 SSVAL(req->outbuf, smb_flg2,
1326 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1329 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1330 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1332 out:
1333 TALLOC_FREE(smb_fname);
1334 TALLOC_FREE(fname);
1335 END_PROFILE(SMBgetatr);
1336 return;
1339 /****************************************************************************
1340 Reply to a setatr.
1341 ****************************************************************************/
1343 void reply_setatr(struct smb_request *req)
1345 struct smb_file_time ft;
1346 connection_struct *conn = req->conn;
1347 struct smb_filename *smb_fname = NULL;
1348 char *fname = NULL;
1349 int mode;
1350 time_t mtime;
1351 const char *p;
1352 NTSTATUS status;
1353 TALLOC_CTX *ctx = talloc_tos();
1355 START_PROFILE(SMBsetatr);
1357 ZERO_STRUCT(ft);
1359 if (req->wct < 2) {
1360 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1361 goto out;
1364 p = (const char *)req->buf + 1;
1365 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1366 if (!NT_STATUS_IS_OK(status)) {
1367 reply_nterror(req, status);
1368 goto out;
1371 status = filename_convert(ctx,
1372 conn,
1373 req->flags2 & FLAGS2_DFS_PATHNAMES,
1374 fname,
1376 NULL,
1377 &smb_fname);
1378 if (!NT_STATUS_IS_OK(status)) {
1379 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1380 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1381 ERRSRV, ERRbadpath);
1382 goto out;
1384 reply_nterror(req, status);
1385 goto out;
1388 if (smb_fname->base_name[0] == '.' &&
1389 smb_fname->base_name[1] == '\0') {
1391 * Not sure here is the right place to catch this
1392 * condition. Might be moved to somewhere else later -- vl
1394 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1395 goto out;
1398 mode = SVAL(req->vwv+0, 0);
1399 mtime = srv_make_unix_date3(req->vwv+1);
1401 if (mode != FILE_ATTRIBUTE_NORMAL) {
1402 if (VALID_STAT_OF_DIR(smb_fname->st))
1403 mode |= FILE_ATTRIBUTE_DIRECTORY;
1404 else
1405 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1407 status = check_access(conn, NULL, smb_fname,
1408 FILE_WRITE_ATTRIBUTES);
1409 if (!NT_STATUS_IS_OK(status)) {
1410 reply_nterror(req, status);
1411 goto out;
1414 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1415 false) != 0) {
1416 reply_nterror(req, map_nt_error_from_unix(errno));
1417 goto out;
1421 ft.mtime = convert_time_t_to_timespec(mtime);
1422 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1423 if (!NT_STATUS_IS_OK(status)) {
1424 reply_nterror(req, status);
1425 goto out;
1428 reply_outbuf(req, 0, 0);
1430 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1431 mode));
1432 out:
1433 TALLOC_FREE(smb_fname);
1434 END_PROFILE(SMBsetatr);
1435 return;
1438 /****************************************************************************
1439 Reply to a dskattr.
1440 ****************************************************************************/
1442 void reply_dskattr(struct smb_request *req)
1444 connection_struct *conn = req->conn;
1445 uint64_t dfree,dsize,bsize;
1446 START_PROFILE(SMBdskattr);
1448 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1449 reply_nterror(req, map_nt_error_from_unix(errno));
1450 END_PROFILE(SMBdskattr);
1451 return;
1454 reply_outbuf(req, 5, 0);
1456 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1457 double total_space, free_space;
1458 /* we need to scale this to a number that DOS6 can handle. We
1459 use floating point so we can handle large drives on systems
1460 that don't have 64 bit integers
1462 we end up displaying a maximum of 2G to DOS systems
1464 total_space = dsize * (double)bsize;
1465 free_space = dfree * (double)bsize;
1467 dsize = (uint64_t)((total_space+63*512) / (64*512));
1468 dfree = (uint64_t)((free_space+63*512) / (64*512));
1470 if (dsize > 0xFFFF) dsize = 0xFFFF;
1471 if (dfree > 0xFFFF) dfree = 0xFFFF;
1473 SSVAL(req->outbuf,smb_vwv0,dsize);
1474 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1475 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1476 SSVAL(req->outbuf,smb_vwv3,dfree);
1477 } else {
1478 SSVAL(req->outbuf,smb_vwv0,dsize);
1479 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1480 SSVAL(req->outbuf,smb_vwv2,512);
1481 SSVAL(req->outbuf,smb_vwv3,dfree);
1484 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1486 END_PROFILE(SMBdskattr);
1487 return;
1491 * Utility function to split the filename from the directory.
1493 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1494 char **fname_dir_out,
1495 char **fname_mask_out)
1497 const char *p = NULL;
1498 char *fname_dir = NULL;
1499 char *fname_mask = NULL;
1501 p = strrchr_m(fname_in, '/');
1502 if (!p) {
1503 fname_dir = talloc_strdup(ctx, ".");
1504 fname_mask = talloc_strdup(ctx, fname_in);
1505 } else {
1506 fname_dir = talloc_strndup(ctx, fname_in,
1507 PTR_DIFF(p, fname_in));
1508 fname_mask = talloc_strdup(ctx, p+1);
1511 if (!fname_dir || !fname_mask) {
1512 TALLOC_FREE(fname_dir);
1513 TALLOC_FREE(fname_mask);
1514 return NT_STATUS_NO_MEMORY;
1517 *fname_dir_out = fname_dir;
1518 *fname_mask_out = fname_mask;
1519 return NT_STATUS_OK;
1522 /****************************************************************************
1523 Reply to a search.
1524 Can be called from SMBsearch, SMBffirst or SMBfunique.
1525 ****************************************************************************/
1527 void reply_search(struct smb_request *req)
1529 connection_struct *conn = req->conn;
1530 char *path = NULL;
1531 const char *mask = NULL;
1532 char *directory = NULL;
1533 struct smb_filename *smb_fname = NULL;
1534 char *fname = NULL;
1535 off_t size;
1536 uint32 mode;
1537 struct timespec date;
1538 uint32 dirtype;
1539 unsigned int numentries = 0;
1540 unsigned int maxentries = 0;
1541 bool finished = False;
1542 const char *p;
1543 int status_len;
1544 char status[21];
1545 int dptr_num= -1;
1546 bool check_descend = False;
1547 bool expect_close = False;
1548 NTSTATUS nt_status;
1549 bool mask_contains_wcard = False;
1550 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1551 TALLOC_CTX *ctx = talloc_tos();
1552 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1553 struct dptr_struct *dirptr = NULL;
1554 struct smbd_server_connection *sconn = req->sconn;
1556 START_PROFILE(SMBsearch);
1558 if (req->wct < 2) {
1559 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1560 goto out;
1563 if (lp_posix_pathnames()) {
1564 reply_unknown_new(req, req->cmd);
1565 goto out;
1568 /* If we were called as SMBffirst then we must expect close. */
1569 if(req->cmd == SMBffirst) {
1570 expect_close = True;
1573 reply_outbuf(req, 1, 3);
1574 maxentries = SVAL(req->vwv+0, 0);
1575 dirtype = SVAL(req->vwv+1, 0);
1576 p = (const char *)req->buf + 1;
1577 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1578 &nt_status, &mask_contains_wcard);
1579 if (!NT_STATUS_IS_OK(nt_status)) {
1580 reply_nterror(req, nt_status);
1581 goto out;
1584 p++;
1585 status_len = SVAL(p, 0);
1586 p += 2;
1588 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1590 if (status_len == 0) {
1591 nt_status = filename_convert(ctx, conn,
1592 req->flags2 & FLAGS2_DFS_PATHNAMES,
1593 path,
1594 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1595 &mask_contains_wcard,
1596 &smb_fname);
1597 if (!NT_STATUS_IS_OK(nt_status)) {
1598 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1599 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1600 ERRSRV, ERRbadpath);
1601 goto out;
1603 reply_nterror(req, nt_status);
1604 goto out;
1607 directory = smb_fname->base_name;
1609 p = strrchr_m(directory,'/');
1610 if ((p != NULL) && (*directory != '/')) {
1611 mask = p + 1;
1612 directory = talloc_strndup(ctx, directory,
1613 PTR_DIFF(p, directory));
1614 } else {
1615 mask = directory;
1616 directory = talloc_strdup(ctx,".");
1619 if (!directory) {
1620 reply_nterror(req, NT_STATUS_NO_MEMORY);
1621 goto out;
1624 memset((char *)status,'\0',21);
1625 SCVAL(status,0,(dirtype & 0x1F));
1627 nt_status = dptr_create(conn,
1628 NULL, /* req */
1629 NULL, /* fsp */
1630 directory,
1631 True,
1632 expect_close,
1633 req->smbpid,
1634 mask,
1635 mask_contains_wcard,
1636 dirtype,
1637 &dirptr);
1638 if (!NT_STATUS_IS_OK(nt_status)) {
1639 reply_nterror(req, nt_status);
1640 goto out;
1642 dptr_num = dptr_dnum(dirptr);
1643 } else {
1644 int status_dirtype;
1645 const char *dirpath;
1647 memcpy(status,p,21);
1648 status_dirtype = CVAL(status,0) & 0x1F;
1649 if (status_dirtype != (dirtype & 0x1F)) {
1650 dirtype = status_dirtype;
1653 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1654 if (!dirptr) {
1655 goto SearchEmpty;
1657 dirpath = dptr_path(sconn, dptr_num);
1658 directory = talloc_strdup(ctx, dirpath);
1659 if (!directory) {
1660 reply_nterror(req, NT_STATUS_NO_MEMORY);
1661 goto out;
1664 mask = dptr_wcard(sconn, dptr_num);
1665 if (!mask) {
1666 goto SearchEmpty;
1669 * For a 'continue' search we have no string. So
1670 * check from the initial saved string.
1672 mask_contains_wcard = ms_has_wild(mask);
1673 dirtype = dptr_attr(sconn, dptr_num);
1676 DEBUG(4,("dptr_num is %d\n",dptr_num));
1678 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1679 dptr_init_search_op(dirptr);
1681 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1682 char buf[DIR_STRUCT_SIZE];
1683 memcpy(buf,status,21);
1684 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1685 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1686 reply_nterror(req, NT_STATUS_NO_MEMORY);
1687 goto out;
1689 dptr_fill(sconn, buf+12,dptr_num);
1690 if (dptr_zero(buf+12) && (status_len==0)) {
1691 numentries = 1;
1692 } else {
1693 numentries = 0;
1695 if (message_push_blob(&req->outbuf,
1696 data_blob_const(buf, sizeof(buf)))
1697 == -1) {
1698 reply_nterror(req, NT_STATUS_NO_MEMORY);
1699 goto out;
1701 } else {
1702 unsigned int i;
1703 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1704 size_t available_space = sconn->smb1.sessions.max_send - hdr_size;
1706 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1708 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1709 directory,lp_dont_descend(ctx, SNUM(conn))));
1710 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1711 check_descend = True;
1714 for (i=numentries;(i<maxentries) && !finished;i++) {
1715 finished = !get_dir_entry(ctx,
1716 dirptr,
1717 mask,
1718 dirtype,
1719 &fname,
1720 &size,
1721 &mode,
1722 &date,
1723 check_descend,
1724 ask_sharemode);
1725 if (!finished) {
1726 char buf[DIR_STRUCT_SIZE];
1727 memcpy(buf,status,21);
1728 if (!make_dir_struct(ctx,
1729 buf,
1730 mask,
1731 fname,
1732 size,
1733 mode,
1734 convert_timespec_to_time_t(date),
1735 !allow_long_path_components)) {
1736 reply_nterror(req, NT_STATUS_NO_MEMORY);
1737 goto out;
1739 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1740 break;
1742 if (message_push_blob(&req->outbuf,
1743 data_blob_const(buf, sizeof(buf)))
1744 == -1) {
1745 reply_nterror(req, NT_STATUS_NO_MEMORY);
1746 goto out;
1748 numentries++;
1753 SearchEmpty:
1755 /* If we were called as SMBffirst with smb_search_id == NULL
1756 and no entries were found then return error and close dirptr
1757 (X/Open spec) */
1759 if (numentries == 0) {
1760 dptr_close(sconn, &dptr_num);
1761 } else if(expect_close && status_len == 0) {
1762 /* Close the dptr - we know it's gone */
1763 dptr_close(sconn, &dptr_num);
1766 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1767 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1768 dptr_close(sconn, &dptr_num);
1771 if ((numentries == 0) && !mask_contains_wcard) {
1772 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1773 goto out;
1776 SSVAL(req->outbuf,smb_vwv0,numentries);
1777 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1778 SCVAL(smb_buf(req->outbuf),0,5);
1779 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1781 /* The replies here are never long name. */
1782 SSVAL(req->outbuf, smb_flg2,
1783 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1784 if (!allow_long_path_components) {
1785 SSVAL(req->outbuf, smb_flg2,
1786 SVAL(req->outbuf, smb_flg2)
1787 & (~FLAGS2_LONG_PATH_COMPONENTS));
1790 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1791 SSVAL(req->outbuf, smb_flg2,
1792 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1794 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1795 smb_fn_name(req->cmd),
1796 mask,
1797 directory,
1798 dirtype,
1799 numentries,
1800 maxentries ));
1801 out:
1802 TALLOC_FREE(directory);
1803 TALLOC_FREE(smb_fname);
1804 END_PROFILE(SMBsearch);
1805 return;
1808 /****************************************************************************
1809 Reply to a fclose (stop directory search).
1810 ****************************************************************************/
1812 void reply_fclose(struct smb_request *req)
1814 int status_len;
1815 char status[21];
1816 int dptr_num= -2;
1817 const char *p;
1818 char *path = NULL;
1819 NTSTATUS err;
1820 bool path_contains_wcard = False;
1821 TALLOC_CTX *ctx = talloc_tos();
1822 struct smbd_server_connection *sconn = req->sconn;
1824 START_PROFILE(SMBfclose);
1826 if (lp_posix_pathnames()) {
1827 reply_unknown_new(req, req->cmd);
1828 END_PROFILE(SMBfclose);
1829 return;
1832 p = (const char *)req->buf + 1;
1833 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1834 &err, &path_contains_wcard);
1835 if (!NT_STATUS_IS_OK(err)) {
1836 reply_nterror(req, err);
1837 END_PROFILE(SMBfclose);
1838 return;
1840 p++;
1841 status_len = SVAL(p,0);
1842 p += 2;
1844 if (status_len == 0) {
1845 reply_force_doserror(req, ERRSRV, ERRsrverror);
1846 END_PROFILE(SMBfclose);
1847 return;
1850 memcpy(status,p,21);
1852 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1853 /* Close the dptr - we know it's gone */
1854 dptr_close(sconn, &dptr_num);
1857 reply_outbuf(req, 1, 0);
1858 SSVAL(req->outbuf,smb_vwv0,0);
1860 DEBUG(3,("search close\n"));
1862 END_PROFILE(SMBfclose);
1863 return;
1866 /****************************************************************************
1867 Reply to an open.
1868 ****************************************************************************/
1870 void reply_open(struct smb_request *req)
1872 connection_struct *conn = req->conn;
1873 struct smb_filename *smb_fname = NULL;
1874 char *fname = NULL;
1875 uint32 fattr=0;
1876 off_t size = 0;
1877 time_t mtime=0;
1878 int info;
1879 files_struct *fsp;
1880 int oplock_request;
1881 int deny_mode;
1882 uint32 dos_attr;
1883 uint32 access_mask;
1884 uint32 share_mode;
1885 uint32 create_disposition;
1886 uint32 create_options = 0;
1887 uint32_t private_flags = 0;
1888 NTSTATUS status;
1889 TALLOC_CTX *ctx = talloc_tos();
1891 START_PROFILE(SMBopen);
1893 if (req->wct < 2) {
1894 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1895 goto out;
1898 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1899 deny_mode = SVAL(req->vwv+0, 0);
1900 dos_attr = SVAL(req->vwv+1, 0);
1902 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1903 STR_TERMINATE, &status);
1904 if (!NT_STATUS_IS_OK(status)) {
1905 reply_nterror(req, status);
1906 goto out;
1909 if (!map_open_params_to_ntcreate(fname, deny_mode,
1910 OPENX_FILE_EXISTS_OPEN, &access_mask,
1911 &share_mode, &create_disposition,
1912 &create_options, &private_flags)) {
1913 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1914 goto out;
1917 status = filename_convert(ctx,
1918 conn,
1919 req->flags2 & FLAGS2_DFS_PATHNAMES,
1920 fname,
1921 UCF_PREP_CREATEFILE,
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 /* Ensure we're pointing at the correct stat struct. */
1963 TALLOC_FREE(smb_fname);
1964 smb_fname = fsp->fsp_name;
1966 size = smb_fname->st.st_ex_size;
1967 fattr = dos_mode(conn, smb_fname);
1969 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1971 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1972 DEBUG(3,("attempt to open a directory %s\n",
1973 fsp_str_dbg(fsp)));
1974 close_file(req, fsp, ERROR_CLOSE);
1975 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1976 ERRDOS, ERRnoaccess);
1977 goto out;
1980 reply_outbuf(req, 7, 0);
1981 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1982 SSVAL(req->outbuf,smb_vwv1,fattr);
1983 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1984 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1985 } else {
1986 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1988 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1989 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1991 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1992 SCVAL(req->outbuf,smb_flg,
1993 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1996 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1997 SCVAL(req->outbuf,smb_flg,
1998 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2000 out:
2001 END_PROFILE(SMBopen);
2002 return;
2005 /****************************************************************************
2006 Reply to an open and X.
2007 ****************************************************************************/
2009 void reply_open_and_X(struct smb_request *req)
2011 connection_struct *conn = req->conn;
2012 struct smb_filename *smb_fname = NULL;
2013 char *fname = NULL;
2014 uint16 open_flags;
2015 int deny_mode;
2016 uint32 smb_attr;
2017 /* Breakout the oplock request bits so we can set the
2018 reply bits separately. */
2019 int ex_oplock_request;
2020 int core_oplock_request;
2021 int oplock_request;
2022 #if 0
2023 int smb_sattr = SVAL(req->vwv+4, 0);
2024 uint32 smb_time = make_unix_date3(req->vwv+6);
2025 #endif
2026 int smb_ofun;
2027 uint32 fattr=0;
2028 int mtime=0;
2029 int smb_action = 0;
2030 files_struct *fsp;
2031 NTSTATUS status;
2032 uint64_t allocation_size;
2033 ssize_t retval = -1;
2034 uint32 access_mask;
2035 uint32 share_mode;
2036 uint32 create_disposition;
2037 uint32 create_options = 0;
2038 uint32_t private_flags = 0;
2039 TALLOC_CTX *ctx = talloc_tos();
2041 START_PROFILE(SMBopenX);
2043 if (req->wct < 15) {
2044 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2045 goto out;
2048 open_flags = SVAL(req->vwv+2, 0);
2049 deny_mode = SVAL(req->vwv+3, 0);
2050 smb_attr = SVAL(req->vwv+5, 0);
2051 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2052 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2053 oplock_request = ex_oplock_request | core_oplock_request;
2054 smb_ofun = SVAL(req->vwv+8, 0);
2055 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2057 /* If it's an IPC, pass off the pipe handler. */
2058 if (IS_IPC(conn)) {
2059 if (lp_nt_pipe_support()) {
2060 reply_open_pipe_and_X(conn, req);
2061 } else {
2062 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2064 goto out;
2067 /* XXXX we need to handle passed times, sattr and flags */
2068 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2069 STR_TERMINATE, &status);
2070 if (!NT_STATUS_IS_OK(status)) {
2071 reply_nterror(req, status);
2072 goto out;
2075 if (!map_open_params_to_ntcreate(fname, deny_mode,
2076 smb_ofun,
2077 &access_mask, &share_mode,
2078 &create_disposition,
2079 &create_options,
2080 &private_flags)) {
2081 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2082 goto out;
2085 status = filename_convert(ctx,
2086 conn,
2087 req->flags2 & FLAGS2_DFS_PATHNAMES,
2088 fname,
2089 UCF_PREP_CREATEFILE,
2090 NULL,
2091 &smb_fname);
2092 if (!NT_STATUS_IS_OK(status)) {
2093 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2094 reply_botherror(req,
2095 NT_STATUS_PATH_NOT_COVERED,
2096 ERRSRV, ERRbadpath);
2097 goto out;
2099 reply_nterror(req, status);
2100 goto out;
2103 status = SMB_VFS_CREATE_FILE(
2104 conn, /* conn */
2105 req, /* req */
2106 0, /* root_dir_fid */
2107 smb_fname, /* fname */
2108 access_mask, /* access_mask */
2109 share_mode, /* share_access */
2110 create_disposition, /* create_disposition*/
2111 create_options, /* create_options */
2112 smb_attr, /* file_attributes */
2113 oplock_request, /* oplock_request */
2114 0, /* allocation_size */
2115 private_flags,
2116 NULL, /* sd */
2117 NULL, /* ea_list */
2118 &fsp, /* result */
2119 &smb_action); /* pinfo */
2121 if (!NT_STATUS_IS_OK(status)) {
2122 if (open_was_deferred(req->sconn, req->mid)) {
2123 /* We have re-scheduled this call. */
2124 goto out;
2126 reply_openerror(req, status);
2127 goto out;
2130 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2131 if the file is truncated or created. */
2132 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2133 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2134 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2135 close_file(req, fsp, ERROR_CLOSE);
2136 reply_nterror(req, NT_STATUS_DISK_FULL);
2137 goto out;
2139 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2140 if (retval < 0) {
2141 close_file(req, fsp, ERROR_CLOSE);
2142 reply_nterror(req, NT_STATUS_DISK_FULL);
2143 goto out;
2145 status = vfs_stat_fsp(fsp);
2146 if (!NT_STATUS_IS_OK(status)) {
2147 close_file(req, fsp, ERROR_CLOSE);
2148 reply_nterror(req, status);
2149 goto out;
2153 fattr = dos_mode(conn, fsp->fsp_name);
2154 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2155 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2156 close_file(req, fsp, ERROR_CLOSE);
2157 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2158 goto out;
2161 /* If the caller set the extended oplock request bit
2162 and we granted one (by whatever means) - set the
2163 correct bit for extended oplock reply.
2166 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2167 smb_action |= EXTENDED_OPLOCK_GRANTED;
2170 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2171 smb_action |= EXTENDED_OPLOCK_GRANTED;
2174 /* If the caller set the core oplock request bit
2175 and we granted one (by whatever means) - set the
2176 correct bit for core oplock reply.
2179 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2180 reply_outbuf(req, 19, 0);
2181 } else {
2182 reply_outbuf(req, 15, 0);
2185 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2186 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2188 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2189 SCVAL(req->outbuf, smb_flg,
2190 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2193 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2194 SCVAL(req->outbuf, smb_flg,
2195 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2198 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2199 SSVAL(req->outbuf,smb_vwv3,fattr);
2200 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2201 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2202 } else {
2203 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2205 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2206 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2207 SSVAL(req->outbuf,smb_vwv11,smb_action);
2209 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2210 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2213 out:
2214 TALLOC_FREE(smb_fname);
2215 END_PROFILE(SMBopenX);
2216 return;
2219 /****************************************************************************
2220 Reply to a SMBulogoffX.
2221 ****************************************************************************/
2223 void reply_ulogoffX(struct smb_request *req)
2225 struct smbd_server_connection *sconn = req->sconn;
2226 struct user_struct *vuser;
2227 struct smbXsrv_session *session = NULL;
2228 NTSTATUS status;
2230 START_PROFILE(SMBulogoffX);
2232 vuser = get_valid_user_struct(sconn, req->vuid);
2234 if(vuser == NULL) {
2235 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2236 (unsigned long long)req->vuid));
2238 req->vuid = UID_FIELD_INVALID;
2239 reply_force_doserror(req, ERRSRV, ERRbaduid);
2240 END_PROFILE(SMBulogoffX);
2241 return;
2244 session = vuser->session;
2245 vuser = NULL;
2248 * TODO: cancel all outstanding requests on the session
2250 status = smbXsrv_session_logoff(session);
2251 if (!NT_STATUS_IS_OK(status)) {
2252 DEBUG(0, ("reply_ulogoff: "
2253 "smbXsrv_session_logoff() failed: %s\n",
2254 nt_errstr(status)));
2256 * If we hit this case, there is something completely
2257 * wrong, so we better disconnect the transport connection.
2259 END_PROFILE(SMBulogoffX);
2260 exit_server(__location__ ": smbXsrv_session_logoff failed");
2261 return;
2264 TALLOC_FREE(session);
2266 reply_outbuf(req, 2, 0);
2267 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2268 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2270 DEBUG(3, ("ulogoffX vuid=%llu\n",
2271 (unsigned long long)req->vuid));
2273 END_PROFILE(SMBulogoffX);
2274 req->vuid = UID_FIELD_INVALID;
2277 /****************************************************************************
2278 Reply to a mknew or a create.
2279 ****************************************************************************/
2281 void reply_mknew(struct smb_request *req)
2283 connection_struct *conn = req->conn;
2284 struct smb_filename *smb_fname = NULL;
2285 char *fname = NULL;
2286 uint32 fattr = 0;
2287 struct smb_file_time ft;
2288 files_struct *fsp;
2289 int oplock_request = 0;
2290 NTSTATUS status;
2291 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2292 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2293 uint32 create_disposition;
2294 uint32 create_options = 0;
2295 TALLOC_CTX *ctx = talloc_tos();
2297 START_PROFILE(SMBcreate);
2298 ZERO_STRUCT(ft);
2300 if (req->wct < 3) {
2301 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2302 goto out;
2305 fattr = SVAL(req->vwv+0, 0);
2306 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2308 /* mtime. */
2309 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2311 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2312 STR_TERMINATE, &status);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 reply_nterror(req, status);
2315 goto out;
2318 status = filename_convert(ctx,
2319 conn,
2320 req->flags2 & FLAGS2_DFS_PATHNAMES,
2321 fname,
2322 UCF_PREP_CREATEFILE,
2323 NULL,
2324 &smb_fname);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2327 reply_botherror(req,
2328 NT_STATUS_PATH_NOT_COVERED,
2329 ERRSRV, ERRbadpath);
2330 goto out;
2332 reply_nterror(req, status);
2333 goto out;
2336 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2337 DEBUG(0,("Attempt to create file (%s) with volid set - "
2338 "please report this\n",
2339 smb_fname_str_dbg(smb_fname)));
2342 if(req->cmd == SMBmknew) {
2343 /* We should fail if file exists. */
2344 create_disposition = FILE_CREATE;
2345 } else {
2346 /* Create if file doesn't exist, truncate if it does. */
2347 create_disposition = FILE_OVERWRITE_IF;
2350 status = SMB_VFS_CREATE_FILE(
2351 conn, /* conn */
2352 req, /* req */
2353 0, /* root_dir_fid */
2354 smb_fname, /* fname */
2355 access_mask, /* access_mask */
2356 share_mode, /* share_access */
2357 create_disposition, /* create_disposition*/
2358 create_options, /* create_options */
2359 fattr, /* file_attributes */
2360 oplock_request, /* oplock_request */
2361 0, /* allocation_size */
2362 0, /* private_flags */
2363 NULL, /* sd */
2364 NULL, /* ea_list */
2365 &fsp, /* result */
2366 NULL); /* pinfo */
2368 if (!NT_STATUS_IS_OK(status)) {
2369 if (open_was_deferred(req->sconn, req->mid)) {
2370 /* We have re-scheduled this call. */
2371 goto out;
2373 reply_openerror(req, status);
2374 goto out;
2377 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2378 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2379 if (!NT_STATUS_IS_OK(status)) {
2380 END_PROFILE(SMBcreate);
2381 goto out;
2384 reply_outbuf(req, 1, 0);
2385 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2387 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2388 SCVAL(req->outbuf,smb_flg,
2389 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2392 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2393 SCVAL(req->outbuf,smb_flg,
2394 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2397 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2398 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2399 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2400 (unsigned int)fattr));
2402 out:
2403 TALLOC_FREE(smb_fname);
2404 END_PROFILE(SMBcreate);
2405 return;
2408 /****************************************************************************
2409 Reply to a create temporary file.
2410 ****************************************************************************/
2412 void reply_ctemp(struct smb_request *req)
2414 connection_struct *conn = req->conn;
2415 struct smb_filename *smb_fname = NULL;
2416 char *wire_name = NULL;
2417 char *fname = NULL;
2418 uint32 fattr;
2419 files_struct *fsp;
2420 int oplock_request;
2421 char *s;
2422 NTSTATUS status;
2423 int i;
2424 TALLOC_CTX *ctx = talloc_tos();
2426 START_PROFILE(SMBctemp);
2428 if (req->wct < 3) {
2429 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2430 goto out;
2433 fattr = SVAL(req->vwv+0, 0);
2434 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2436 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2437 STR_TERMINATE, &status);
2438 if (!NT_STATUS_IS_OK(status)) {
2439 reply_nterror(req, status);
2440 goto out;
2443 for (i = 0; i < 10; i++) {
2444 if (*wire_name) {
2445 fname = talloc_asprintf(ctx,
2446 "%s/TMP%s",
2447 wire_name,
2448 generate_random_str_list(ctx, 5, "0123456789"));
2449 } else {
2450 fname = talloc_asprintf(ctx,
2451 "TMP%s",
2452 generate_random_str_list(ctx, 5, "0123456789"));
2455 if (!fname) {
2456 reply_nterror(req, NT_STATUS_NO_MEMORY);
2457 goto out;
2460 status = filename_convert(ctx, conn,
2461 req->flags2 & FLAGS2_DFS_PATHNAMES,
2462 fname,
2463 UCF_PREP_CREATEFILE,
2464 NULL,
2465 &smb_fname);
2466 if (!NT_STATUS_IS_OK(status)) {
2467 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2468 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2469 ERRSRV, ERRbadpath);
2470 goto out;
2472 reply_nterror(req, status);
2473 goto out;
2476 /* Create the file. */
2477 status = SMB_VFS_CREATE_FILE(
2478 conn, /* conn */
2479 req, /* req */
2480 0, /* root_dir_fid */
2481 smb_fname, /* fname */
2482 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2483 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2484 FILE_CREATE, /* create_disposition*/
2485 0, /* create_options */
2486 fattr, /* file_attributes */
2487 oplock_request, /* oplock_request */
2488 0, /* allocation_size */
2489 0, /* private_flags */
2490 NULL, /* sd */
2491 NULL, /* ea_list */
2492 &fsp, /* result */
2493 NULL); /* pinfo */
2495 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2496 TALLOC_FREE(fname);
2497 TALLOC_FREE(smb_fname);
2498 continue;
2501 if (!NT_STATUS_IS_OK(status)) {
2502 if (open_was_deferred(req->sconn, req->mid)) {
2503 /* We have re-scheduled this call. */
2504 goto out;
2506 reply_openerror(req, status);
2507 goto out;
2510 break;
2513 if (i == 10) {
2514 /* Collision after 10 times... */
2515 reply_nterror(req, status);
2516 goto out;
2519 reply_outbuf(req, 1, 0);
2520 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2522 /* the returned filename is relative to the directory */
2523 s = strrchr_m(fsp->fsp_name->base_name, '/');
2524 if (!s) {
2525 s = fsp->fsp_name->base_name;
2526 } else {
2527 s++;
2530 #if 0
2531 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2532 thing in the byte section. JRA */
2533 SSVALS(p, 0, -1); /* what is this? not in spec */
2534 #endif
2535 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2536 == -1) {
2537 reply_nterror(req, NT_STATUS_NO_MEMORY);
2538 goto out;
2541 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2542 SCVAL(req->outbuf, smb_flg,
2543 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2546 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2547 SCVAL(req->outbuf, smb_flg,
2548 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2551 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2552 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2553 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2554 out:
2555 TALLOC_FREE(smb_fname);
2556 TALLOC_FREE(wire_name);
2557 END_PROFILE(SMBctemp);
2558 return;
2561 /*******************************************************************
2562 Check if a user is allowed to rename a file.
2563 ********************************************************************/
2565 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2566 uint16 dirtype)
2568 if (!CAN_WRITE(conn)) {
2569 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2572 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2573 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2574 /* Only bother to read the DOS attribute if we might deny the
2575 rename on the grounds of attribute missmatch. */
2576 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2577 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2578 return NT_STATUS_NO_SUCH_FILE;
2582 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2583 if (fsp->posix_open) {
2584 return NT_STATUS_OK;
2587 /* If no pathnames are open below this
2588 directory, allow the rename. */
2590 if (file_find_subpath(fsp)) {
2591 return NT_STATUS_ACCESS_DENIED;
2593 return NT_STATUS_OK;
2596 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2597 return NT_STATUS_OK;
2600 return NT_STATUS_ACCESS_DENIED;
2603 /*******************************************************************
2604 * unlink a file with all relevant access checks
2605 *******************************************************************/
2607 static NTSTATUS do_unlink(connection_struct *conn,
2608 struct smb_request *req,
2609 struct smb_filename *smb_fname,
2610 uint32 dirtype)
2612 uint32 fattr;
2613 files_struct *fsp;
2614 uint32 dirtype_orig = dirtype;
2615 NTSTATUS status;
2616 int ret;
2617 bool posix_paths = lp_posix_pathnames();
2619 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2620 smb_fname_str_dbg(smb_fname),
2621 dirtype));
2623 if (!CAN_WRITE(conn)) {
2624 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2627 if (posix_paths) {
2628 ret = SMB_VFS_LSTAT(conn, smb_fname);
2629 } else {
2630 ret = SMB_VFS_STAT(conn, smb_fname);
2632 if (ret != 0) {
2633 return map_nt_error_from_unix(errno);
2636 fattr = dos_mode(conn, smb_fname);
2638 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2639 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2642 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2643 if (!dirtype) {
2644 return NT_STATUS_NO_SUCH_FILE;
2647 if (!dir_check_ftype(fattr, dirtype)) {
2648 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2649 return NT_STATUS_FILE_IS_A_DIRECTORY;
2651 return NT_STATUS_NO_SUCH_FILE;
2654 if (dirtype_orig & 0x8000) {
2655 /* These will never be set for POSIX. */
2656 return NT_STATUS_NO_SUCH_FILE;
2659 #if 0
2660 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2661 return NT_STATUS_FILE_IS_A_DIRECTORY;
2664 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2665 return NT_STATUS_NO_SUCH_FILE;
2668 if (dirtype & 0xFF00) {
2669 /* These will never be set for POSIX. */
2670 return NT_STATUS_NO_SUCH_FILE;
2673 dirtype &= 0xFF;
2674 if (!dirtype) {
2675 return NT_STATUS_NO_SUCH_FILE;
2678 /* Can't delete a directory. */
2679 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2680 return NT_STATUS_FILE_IS_A_DIRECTORY;
2682 #endif
2684 #if 0 /* JRATEST */
2685 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2686 return NT_STATUS_OBJECT_NAME_INVALID;
2687 #endif /* JRATEST */
2689 /* On open checks the open itself will check the share mode, so
2690 don't do it here as we'll get it wrong. */
2692 status = SMB_VFS_CREATE_FILE
2693 (conn, /* conn */
2694 req, /* req */
2695 0, /* root_dir_fid */
2696 smb_fname, /* fname */
2697 DELETE_ACCESS, /* access_mask */
2698 FILE_SHARE_NONE, /* share_access */
2699 FILE_OPEN, /* create_disposition*/
2700 FILE_NON_DIRECTORY_FILE, /* create_options */
2701 /* file_attributes */
2702 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2703 FILE_ATTRIBUTE_NORMAL,
2704 0, /* oplock_request */
2705 0, /* allocation_size */
2706 0, /* private_flags */
2707 NULL, /* sd */
2708 NULL, /* ea_list */
2709 &fsp, /* result */
2710 NULL); /* pinfo */
2712 if (!NT_STATUS_IS_OK(status)) {
2713 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2714 nt_errstr(status)));
2715 return status;
2718 status = can_set_delete_on_close(fsp, fattr);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2721 "(%s)\n",
2722 smb_fname_str_dbg(smb_fname),
2723 nt_errstr(status)));
2724 close_file(req, fsp, NORMAL_CLOSE);
2725 return status;
2728 /* The set is across all open files on this dev/inode pair. */
2729 if (!set_delete_on_close(fsp, True,
2730 conn->session_info->security_token,
2731 conn->session_info->unix_token)) {
2732 close_file(req, fsp, NORMAL_CLOSE);
2733 return NT_STATUS_ACCESS_DENIED;
2736 return close_file(req, fsp, NORMAL_CLOSE);
2739 /****************************************************************************
2740 The guts of the unlink command, split out so it may be called by the NT SMB
2741 code.
2742 ****************************************************************************/
2744 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2745 uint32 dirtype, struct smb_filename *smb_fname,
2746 bool has_wild)
2748 char *fname_dir = NULL;
2749 char *fname_mask = NULL;
2750 int count=0;
2751 NTSTATUS status = NT_STATUS_OK;
2752 TALLOC_CTX *ctx = talloc_tos();
2754 /* Split up the directory from the filename/mask. */
2755 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2756 &fname_dir, &fname_mask);
2757 if (!NT_STATUS_IS_OK(status)) {
2758 goto out;
2762 * We should only check the mangled cache
2763 * here if unix_convert failed. This means
2764 * that the path in 'mask' doesn't exist
2765 * on the file system and so we need to look
2766 * for a possible mangle. This patch from
2767 * Tine Smukavec <valentin.smukavec@hermes.si>.
2770 if (!VALID_STAT(smb_fname->st) &&
2771 mangle_is_mangled(fname_mask, conn->params)) {
2772 char *new_mask = NULL;
2773 mangle_lookup_name_from_8_3(ctx, fname_mask,
2774 &new_mask, conn->params);
2775 if (new_mask) {
2776 TALLOC_FREE(fname_mask);
2777 fname_mask = new_mask;
2781 if (!has_wild) {
2784 * Only one file needs to be unlinked. Append the mask back
2785 * onto the directory.
2787 TALLOC_FREE(smb_fname->base_name);
2788 if (ISDOT(fname_dir)) {
2789 /* Ensure we use canonical names on open. */
2790 smb_fname->base_name = talloc_asprintf(smb_fname,
2791 "%s",
2792 fname_mask);
2793 } else {
2794 smb_fname->base_name = talloc_asprintf(smb_fname,
2795 "%s/%s",
2796 fname_dir,
2797 fname_mask);
2799 if (!smb_fname->base_name) {
2800 status = NT_STATUS_NO_MEMORY;
2801 goto out;
2803 if (dirtype == 0) {
2804 dirtype = FILE_ATTRIBUTE_NORMAL;
2807 status = check_name(conn, smb_fname->base_name);
2808 if (!NT_STATUS_IS_OK(status)) {
2809 goto out;
2812 status = do_unlink(conn, req, smb_fname, dirtype);
2813 if (!NT_STATUS_IS_OK(status)) {
2814 goto out;
2817 count++;
2818 } else {
2819 struct smb_Dir *dir_hnd = NULL;
2820 long offset = 0;
2821 const char *dname = NULL;
2822 char *talloced = NULL;
2824 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2825 status = NT_STATUS_OBJECT_NAME_INVALID;
2826 goto out;
2829 if (strequal(fname_mask,"????????.???")) {
2830 TALLOC_FREE(fname_mask);
2831 fname_mask = talloc_strdup(ctx, "*");
2832 if (!fname_mask) {
2833 status = NT_STATUS_NO_MEMORY;
2834 goto out;
2838 status = check_name(conn, fname_dir);
2839 if (!NT_STATUS_IS_OK(status)) {
2840 goto out;
2843 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2844 dirtype);
2845 if (dir_hnd == NULL) {
2846 status = map_nt_error_from_unix(errno);
2847 goto out;
2850 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2851 the pattern matches against the long name, otherwise the short name
2852 We don't implement this yet XXXX
2855 status = NT_STATUS_NO_SUCH_FILE;
2857 while ((dname = ReadDirName(dir_hnd, &offset,
2858 &smb_fname->st, &talloced))) {
2859 TALLOC_CTX *frame = talloc_stackframe();
2861 if (!is_visible_file(conn, fname_dir, dname,
2862 &smb_fname->st, true)) {
2863 TALLOC_FREE(frame);
2864 TALLOC_FREE(talloced);
2865 continue;
2868 /* Quick check for "." and ".." */
2869 if (ISDOT(dname) || ISDOTDOT(dname)) {
2870 TALLOC_FREE(frame);
2871 TALLOC_FREE(talloced);
2872 continue;
2875 if(!mask_match(dname, fname_mask,
2876 conn->case_sensitive)) {
2877 TALLOC_FREE(frame);
2878 TALLOC_FREE(talloced);
2879 continue;
2882 TALLOC_FREE(smb_fname->base_name);
2883 if (ISDOT(fname_dir)) {
2884 /* Ensure we use canonical names on open. */
2885 smb_fname->base_name =
2886 talloc_asprintf(smb_fname, "%s",
2887 dname);
2888 } else {
2889 smb_fname->base_name =
2890 talloc_asprintf(smb_fname, "%s/%s",
2891 fname_dir, dname);
2894 if (!smb_fname->base_name) {
2895 TALLOC_FREE(dir_hnd);
2896 status = NT_STATUS_NO_MEMORY;
2897 TALLOC_FREE(frame);
2898 TALLOC_FREE(talloced);
2899 goto out;
2902 status = check_name(conn, smb_fname->base_name);
2903 if (!NT_STATUS_IS_OK(status)) {
2904 TALLOC_FREE(dir_hnd);
2905 TALLOC_FREE(frame);
2906 TALLOC_FREE(talloced);
2907 goto out;
2910 status = do_unlink(conn, req, smb_fname, dirtype);
2911 if (!NT_STATUS_IS_OK(status)) {
2912 TALLOC_FREE(frame);
2913 TALLOC_FREE(talloced);
2914 continue;
2917 count++;
2918 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2919 smb_fname->base_name));
2921 TALLOC_FREE(frame);
2922 TALLOC_FREE(talloced);
2924 TALLOC_FREE(dir_hnd);
2927 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2928 status = map_nt_error_from_unix(errno);
2931 out:
2932 TALLOC_FREE(fname_dir);
2933 TALLOC_FREE(fname_mask);
2934 return status;
2937 /****************************************************************************
2938 Reply to a unlink
2939 ****************************************************************************/
2941 void reply_unlink(struct smb_request *req)
2943 connection_struct *conn = req->conn;
2944 char *name = NULL;
2945 struct smb_filename *smb_fname = NULL;
2946 uint32 dirtype;
2947 NTSTATUS status;
2948 bool path_contains_wcard = False;
2949 TALLOC_CTX *ctx = talloc_tos();
2951 START_PROFILE(SMBunlink);
2953 if (req->wct < 1) {
2954 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2955 goto out;
2958 dirtype = SVAL(req->vwv+0, 0);
2960 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2961 STR_TERMINATE, &status,
2962 &path_contains_wcard);
2963 if (!NT_STATUS_IS_OK(status)) {
2964 reply_nterror(req, status);
2965 goto out;
2968 status = filename_convert(ctx, conn,
2969 req->flags2 & FLAGS2_DFS_PATHNAMES,
2970 name,
2971 UCF_COND_ALLOW_WCARD_LCOMP,
2972 &path_contains_wcard,
2973 &smb_fname);
2974 if (!NT_STATUS_IS_OK(status)) {
2975 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2976 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2977 ERRSRV, ERRbadpath);
2978 goto out;
2980 reply_nterror(req, status);
2981 goto out;
2984 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2986 status = unlink_internals(conn, req, dirtype, smb_fname,
2987 path_contains_wcard);
2988 if (!NT_STATUS_IS_OK(status)) {
2989 if (open_was_deferred(req->sconn, req->mid)) {
2990 /* We have re-scheduled this call. */
2991 goto out;
2993 reply_nterror(req, status);
2994 goto out;
2997 reply_outbuf(req, 0, 0);
2998 out:
2999 TALLOC_FREE(smb_fname);
3000 END_PROFILE(SMBunlink);
3001 return;
3004 /****************************************************************************
3005 Fail for readbraw.
3006 ****************************************************************************/
3008 static void fail_readraw(void)
3010 const char *errstr = talloc_asprintf(talloc_tos(),
3011 "FAIL ! reply_readbraw: socket write fail (%s)",
3012 strerror(errno));
3013 if (!errstr) {
3014 errstr = "";
3016 exit_server_cleanly(errstr);
3019 /****************************************************************************
3020 Fake (read/write) sendfile. Returns -1 on read or write fail.
3021 ****************************************************************************/
3023 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
3025 size_t bufsize;
3026 size_t tosend = nread;
3027 char *buf;
3029 if (nread == 0) {
3030 return 0;
3033 bufsize = MIN(nread, 65536);
3035 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3036 return -1;
3039 while (tosend > 0) {
3040 ssize_t ret;
3041 size_t cur_read;
3043 if (tosend > bufsize) {
3044 cur_read = bufsize;
3045 } else {
3046 cur_read = tosend;
3048 ret = read_file(fsp,buf,startpos,cur_read);
3049 if (ret == -1) {
3050 SAFE_FREE(buf);
3051 return -1;
3054 /* If we had a short read, fill with zeros. */
3055 if (ret < cur_read) {
3056 memset(buf + ret, '\0', cur_read - ret);
3059 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3060 != cur_read) {
3061 char addr[INET6_ADDRSTRLEN];
3063 * Try and give an error message saying what
3064 * client failed.
3066 DEBUG(0, ("write_data failed for client %s. "
3067 "Error %s\n",
3068 get_peer_addr(fsp->conn->sconn->sock, addr,
3069 sizeof(addr)),
3070 strerror(errno)));
3071 SAFE_FREE(buf);
3072 return -1;
3074 tosend -= cur_read;
3075 startpos += cur_read;
3078 SAFE_FREE(buf);
3079 return (ssize_t)nread;
3082 /****************************************************************************
3083 Deal with the case of sendfile reading less bytes from the file than
3084 requested. Fill with zeros (all we can do).
3085 ****************************************************************************/
3087 void sendfile_short_send(files_struct *fsp,
3088 ssize_t nread,
3089 size_t headersize,
3090 size_t smb_maxcnt)
3092 #define SHORT_SEND_BUFSIZE 1024
3093 if (nread < headersize) {
3094 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3095 "header for file %s (%s). Terminating\n",
3096 fsp_str_dbg(fsp), strerror(errno)));
3097 exit_server_cleanly("sendfile_short_send failed");
3100 nread -= headersize;
3102 if (nread < smb_maxcnt) {
3103 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3104 if (!buf) {
3105 exit_server_cleanly("sendfile_short_send: "
3106 "malloc failed");
3109 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3110 "with zeros !\n", fsp_str_dbg(fsp)));
3112 while (nread < smb_maxcnt) {
3114 * We asked for the real file size and told sendfile
3115 * to not go beyond the end of the file. But it can
3116 * happen that in between our fstat call and the
3117 * sendfile call the file was truncated. This is very
3118 * bad because we have already announced the larger
3119 * number of bytes to the client.
3121 * The best we can do now is to send 0-bytes, just as
3122 * a read from a hole in a sparse file would do.
3124 * This should happen rarely enough that I don't care
3125 * about efficiency here :-)
3127 size_t to_write;
3129 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3130 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3131 != to_write) {
3132 char addr[INET6_ADDRSTRLEN];
3134 * Try and give an error message saying what
3135 * client failed.
3137 DEBUG(0, ("write_data failed for client %s. "
3138 "Error %s\n",
3139 get_peer_addr(
3140 fsp->conn->sconn->sock, addr,
3141 sizeof(addr)),
3142 strerror(errno)));
3143 exit_server_cleanly("sendfile_short_send: "
3144 "write_data failed");
3146 nread += to_write;
3148 SAFE_FREE(buf);
3152 /****************************************************************************
3153 Return a readbraw error (4 bytes of zero).
3154 ****************************************************************************/
3156 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3158 char header[4];
3160 SIVAL(header,0,0);
3162 smbd_lock_socket(sconn);
3163 if (write_data(sconn->sock,header,4) != 4) {
3164 char addr[INET6_ADDRSTRLEN];
3166 * Try and give an error message saying what
3167 * client failed.
3169 DEBUG(0, ("write_data failed for client %s. "
3170 "Error %s\n",
3171 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3172 strerror(errno)));
3174 fail_readraw();
3176 smbd_unlock_socket(sconn);
3179 /****************************************************************************
3180 Use sendfile in readbraw.
3181 ****************************************************************************/
3183 static void send_file_readbraw(connection_struct *conn,
3184 struct smb_request *req,
3185 files_struct *fsp,
3186 off_t startpos,
3187 size_t nread,
3188 ssize_t mincount)
3190 struct smbd_server_connection *sconn = req->sconn;
3191 char *outbuf = NULL;
3192 ssize_t ret=0;
3195 * We can only use sendfile on a non-chained packet
3196 * but we can use on a non-oplocked file. tridge proved this
3197 * on a train in Germany :-). JRA.
3198 * reply_readbraw has already checked the length.
3201 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3202 (fsp->wcp == NULL) &&
3203 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3204 ssize_t sendfile_read = -1;
3205 char header[4];
3206 DATA_BLOB header_blob;
3208 _smb_setlen(header,nread);
3209 header_blob = data_blob_const(header, 4);
3211 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3212 &header_blob, startpos,
3213 nread);
3214 if (sendfile_read == -1) {
3215 /* Returning ENOSYS means no data at all was sent.
3216 * Do this as a normal read. */
3217 if (errno == ENOSYS) {
3218 goto normal_readbraw;
3222 * Special hack for broken Linux with no working sendfile. If we
3223 * return EINTR we sent the header but not the rest of the data.
3224 * Fake this up by doing read/write calls.
3226 if (errno == EINTR) {
3227 /* Ensure we don't do this again. */
3228 set_use_sendfile(SNUM(conn), False);
3229 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3231 if (fake_sendfile(fsp, startpos, nread) == -1) {
3232 DEBUG(0,("send_file_readbraw: "
3233 "fake_sendfile failed for "
3234 "file %s (%s).\n",
3235 fsp_str_dbg(fsp),
3236 strerror(errno)));
3237 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3239 return;
3242 DEBUG(0,("send_file_readbraw: sendfile failed for "
3243 "file %s (%s). Terminating\n",
3244 fsp_str_dbg(fsp), strerror(errno)));
3245 exit_server_cleanly("send_file_readbraw sendfile failed");
3246 } else if (sendfile_read == 0) {
3248 * Some sendfile implementations return 0 to indicate
3249 * that there was a short read, but nothing was
3250 * actually written to the socket. In this case,
3251 * fallback to the normal read path so the header gets
3252 * the correct byte count.
3254 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3255 "bytes falling back to the normal read: "
3256 "%s\n", fsp_str_dbg(fsp)));
3257 goto normal_readbraw;
3260 /* Deal with possible short send. */
3261 if (sendfile_read != 4+nread) {
3262 sendfile_short_send(fsp, sendfile_read, 4, nread);
3264 return;
3267 normal_readbraw:
3269 outbuf = talloc_array(NULL, char, nread+4);
3270 if (!outbuf) {
3271 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3272 (unsigned)(nread+4)));
3273 reply_readbraw_error(sconn);
3274 return;
3277 if (nread > 0) {
3278 ret = read_file(fsp,outbuf+4,startpos,nread);
3279 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3280 if (ret < mincount)
3281 ret = 0;
3282 #else
3283 if (ret < nread)
3284 ret = 0;
3285 #endif
3288 _smb_setlen(outbuf,ret);
3289 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3290 char addr[INET6_ADDRSTRLEN];
3292 * Try and give an error message saying what
3293 * client failed.
3295 DEBUG(0, ("write_data failed for client %s. "
3296 "Error %s\n",
3297 get_peer_addr(fsp->conn->sconn->sock, addr,
3298 sizeof(addr)),
3299 strerror(errno)));
3301 fail_readraw();
3304 TALLOC_FREE(outbuf);
3307 /****************************************************************************
3308 Reply to a readbraw (core+ protocol).
3309 ****************************************************************************/
3311 void reply_readbraw(struct smb_request *req)
3313 connection_struct *conn = req->conn;
3314 struct smbd_server_connection *sconn = req->sconn;
3315 ssize_t maxcount,mincount;
3316 size_t nread = 0;
3317 off_t startpos;
3318 files_struct *fsp;
3319 struct lock_struct lock;
3320 off_t size = 0;
3322 START_PROFILE(SMBreadbraw);
3324 if (srv_is_signing_active(sconn) || req->encrypted) {
3325 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3326 "raw reads/writes are disallowed.");
3329 if (req->wct < 8) {
3330 reply_readbraw_error(sconn);
3331 END_PROFILE(SMBreadbraw);
3332 return;
3335 if (sconn->smb1.echo_handler.trusted_fde) {
3336 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3337 "'async smb echo handler = yes'\n"));
3338 reply_readbraw_error(sconn);
3339 END_PROFILE(SMBreadbraw);
3340 return;
3344 * Special check if an oplock break has been issued
3345 * and the readraw request croses on the wire, we must
3346 * return a zero length response here.
3349 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3352 * We have to do a check_fsp by hand here, as
3353 * we must always return 4 zero bytes on error,
3354 * not a NTSTATUS.
3357 if (!fsp || !conn || conn != fsp->conn ||
3358 req->vuid != fsp->vuid ||
3359 fsp->is_directory || fsp->fh->fd == -1) {
3361 * fsp could be NULL here so use the value from the packet. JRA.
3363 DEBUG(3,("reply_readbraw: fnum %d not valid "
3364 "- cache prime?\n",
3365 (int)SVAL(req->vwv+0, 0)));
3366 reply_readbraw_error(sconn);
3367 END_PROFILE(SMBreadbraw);
3368 return;
3371 /* Do a "by hand" version of CHECK_READ. */
3372 if (!(fsp->can_read ||
3373 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3374 (fsp->access_mask & FILE_EXECUTE)))) {
3375 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3376 (int)SVAL(req->vwv+0, 0)));
3377 reply_readbraw_error(sconn);
3378 END_PROFILE(SMBreadbraw);
3379 return;
3382 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3384 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3385 if(req->wct == 10) {
3387 * This is a large offset (64 bit) read.
3390 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3392 if(startpos < 0) {
3393 DEBUG(0,("reply_readbraw: negative 64 bit "
3394 "readraw offset (%.0f) !\n",
3395 (double)startpos ));
3396 reply_readbraw_error(sconn);
3397 END_PROFILE(SMBreadbraw);
3398 return;
3402 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3403 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3405 /* ensure we don't overrun the packet size */
3406 maxcount = MIN(65535,maxcount);
3408 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3409 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3410 &lock);
3412 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3413 reply_readbraw_error(sconn);
3414 END_PROFILE(SMBreadbraw);
3415 return;
3418 if (fsp_stat(fsp) == 0) {
3419 size = fsp->fsp_name->st.st_ex_size;
3422 if (startpos >= size) {
3423 nread = 0;
3424 } else {
3425 nread = MIN(maxcount,(size - startpos));
3428 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3429 if (nread < mincount)
3430 nread = 0;
3431 #endif
3433 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3434 "min=%lu nread=%lu\n",
3435 fsp_fnum_dbg(fsp), (double)startpos,
3436 (unsigned long)maxcount,
3437 (unsigned long)mincount,
3438 (unsigned long)nread ) );
3440 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3442 DEBUG(5,("reply_readbraw finished\n"));
3444 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3446 END_PROFILE(SMBreadbraw);
3447 return;
3450 #undef DBGC_CLASS
3451 #define DBGC_CLASS DBGC_LOCKING
3453 /****************************************************************************
3454 Reply to a lockread (core+ protocol).
3455 ****************************************************************************/
3457 void reply_lockread(struct smb_request *req)
3459 connection_struct *conn = req->conn;
3460 ssize_t nread = -1;
3461 char *data;
3462 off_t startpos;
3463 size_t numtoread;
3464 size_t maxtoread;
3465 NTSTATUS status;
3466 files_struct *fsp;
3467 struct byte_range_lock *br_lck = NULL;
3468 char *p = NULL;
3469 struct smbd_server_connection *sconn = req->sconn;
3471 START_PROFILE(SMBlockread);
3473 if (req->wct < 5) {
3474 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3475 END_PROFILE(SMBlockread);
3476 return;
3479 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3481 if (!check_fsp(conn, req, fsp)) {
3482 END_PROFILE(SMBlockread);
3483 return;
3486 if (!CHECK_READ(fsp,req)) {
3487 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3488 END_PROFILE(SMBlockread);
3489 return;
3492 numtoread = SVAL(req->vwv+1, 0);
3493 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3496 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3497 * protocol request that predates the read/write lock concept.
3498 * Thus instead of asking for a read lock here we need to ask
3499 * for a write lock. JRA.
3500 * Note that the requested lock size is unaffected by max_send.
3503 br_lck = do_lock(req->sconn->msg_ctx,
3504 fsp,
3505 (uint64_t)req->smbpid,
3506 (uint64_t)numtoread,
3507 (uint64_t)startpos,
3508 WRITE_LOCK,
3509 WINDOWS_LOCK,
3510 False, /* Non-blocking lock. */
3511 &status,
3512 NULL,
3513 NULL);
3514 TALLOC_FREE(br_lck);
3516 if (NT_STATUS_V(status)) {
3517 reply_nterror(req, status);
3518 END_PROFILE(SMBlockread);
3519 return;
3523 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3525 maxtoread = sconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3527 if (numtoread > maxtoread) {
3528 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3529 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3530 (unsigned int)numtoread, (unsigned int)maxtoread,
3531 (unsigned int)sconn->smb1.sessions.max_send));
3532 numtoread = maxtoread;
3535 reply_outbuf(req, 5, numtoread + 3);
3537 data = smb_buf(req->outbuf) + 3;
3539 nread = read_file(fsp,data,startpos,numtoread);
3541 if (nread < 0) {
3542 reply_nterror(req, map_nt_error_from_unix(errno));
3543 END_PROFILE(SMBlockread);
3544 return;
3547 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3549 SSVAL(req->outbuf,smb_vwv0,nread);
3550 SSVAL(req->outbuf,smb_vwv5,nread+3);
3551 p = smb_buf(req->outbuf);
3552 SCVAL(p,0,0); /* pad byte. */
3553 SSVAL(p,1,nread);
3555 DEBUG(3,("lockread %s num=%d nread=%d\n",
3556 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3558 END_PROFILE(SMBlockread);
3559 return;
3562 #undef DBGC_CLASS
3563 #define DBGC_CLASS DBGC_ALL
3565 /****************************************************************************
3566 Reply to a read.
3567 ****************************************************************************/
3569 void reply_read(struct smb_request *req)
3571 connection_struct *conn = req->conn;
3572 size_t numtoread;
3573 size_t maxtoread;
3574 ssize_t nread = 0;
3575 char *data;
3576 off_t startpos;
3577 files_struct *fsp;
3578 struct lock_struct lock;
3579 struct smbd_server_connection *sconn = req->sconn;
3581 START_PROFILE(SMBread);
3583 if (req->wct < 3) {
3584 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3585 END_PROFILE(SMBread);
3586 return;
3589 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3591 if (!check_fsp(conn, req, fsp)) {
3592 END_PROFILE(SMBread);
3593 return;
3596 if (!CHECK_READ(fsp,req)) {
3597 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3598 END_PROFILE(SMBread);
3599 return;
3602 numtoread = SVAL(req->vwv+1, 0);
3603 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3606 * The requested read size cannot be greater than max_send. JRA.
3608 maxtoread = sconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3610 if (numtoread > maxtoread) {
3611 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3612 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3613 (unsigned int)numtoread, (unsigned int)maxtoread,
3614 (unsigned int)sconn->smb1.sessions.max_send));
3615 numtoread = maxtoread;
3618 reply_outbuf(req, 5, numtoread+3);
3620 data = smb_buf(req->outbuf) + 3;
3622 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3623 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3624 &lock);
3626 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3627 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3628 END_PROFILE(SMBread);
3629 return;
3632 if (numtoread > 0)
3633 nread = read_file(fsp,data,startpos,numtoread);
3635 if (nread < 0) {
3636 reply_nterror(req, map_nt_error_from_unix(errno));
3637 goto strict_unlock;
3640 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3642 SSVAL(req->outbuf,smb_vwv0,nread);
3643 SSVAL(req->outbuf,smb_vwv5,nread+3);
3644 SCVAL(smb_buf(req->outbuf),0,1);
3645 SSVAL(smb_buf(req->outbuf),1,nread);
3647 DEBUG(3, ("read %s num=%d nread=%d\n",
3648 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3650 strict_unlock:
3651 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3653 END_PROFILE(SMBread);
3654 return;
3657 /****************************************************************************
3658 Setup readX header.
3659 ****************************************************************************/
3661 static int setup_readX_header(struct smb_request *req, char *outbuf,
3662 size_t smb_maxcnt)
3664 int outsize;
3666 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3668 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3670 SCVAL(outbuf,smb_vwv0,0xFF);
3671 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3672 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3673 SSVAL(outbuf,smb_vwv6,
3674 (smb_wct - 4) /* offset from smb header to wct */
3675 + 1 /* the wct field */
3676 + 12 * sizeof(uint16_t) /* vwv */
3677 + 2); /* the buflen field */
3678 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3679 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3680 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3681 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3682 return outsize;
3685 /****************************************************************************
3686 Reply to a read and X - possibly using sendfile.
3687 ****************************************************************************/
3689 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3690 files_struct *fsp, off_t startpos,
3691 size_t smb_maxcnt)
3693 ssize_t nread = -1;
3694 struct lock_struct lock;
3695 int saved_errno = 0;
3697 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3698 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3699 &lock);
3701 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3702 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3703 return;
3707 * We can only use sendfile on a non-chained packet
3708 * but we can use on a non-oplocked file. tridge proved this
3709 * on a train in Germany :-). JRA.
3712 if (!req_is_in_chain(req) &&
3713 !req->encrypted &&
3714 (fsp->base_fsp == NULL) &&
3715 (fsp->wcp == NULL) &&
3716 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3717 uint8 headerbuf[smb_size + 12 * 2];
3718 DATA_BLOB header;
3720 if(fsp_stat(fsp) == -1) {
3721 reply_nterror(req, map_nt_error_from_unix(errno));
3722 goto strict_unlock;
3725 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3726 (startpos > fsp->fsp_name->st.st_ex_size) ||
3727 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3729 * We already know that we would do a short read, so don't
3730 * try the sendfile() path.
3732 goto nosendfile_read;
3736 * Set up the packet header before send. We
3737 * assume here the sendfile will work (get the
3738 * correct amount of data).
3741 header = data_blob_const(headerbuf, sizeof(headerbuf));
3743 construct_reply_common_req(req, (char *)headerbuf);
3744 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3746 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3747 startpos, smb_maxcnt);
3748 if (nread == -1) {
3749 /* Returning ENOSYS means no data at all was sent.
3750 Do this as a normal read. */
3751 if (errno == ENOSYS) {
3752 goto normal_read;
3756 * Special hack for broken Linux with no working sendfile. If we
3757 * return EINTR we sent the header but not the rest of the data.
3758 * Fake this up by doing read/write calls.
3761 if (errno == EINTR) {
3762 /* Ensure we don't do this again. */
3763 set_use_sendfile(SNUM(conn), False);
3764 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3765 nread = fake_sendfile(fsp, startpos,
3766 smb_maxcnt);
3767 if (nread == -1) {
3768 DEBUG(0,("send_file_readX: "
3769 "fake_sendfile failed for "
3770 "file %s (%s).\n",
3771 fsp_str_dbg(fsp),
3772 strerror(errno)));
3773 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3775 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3776 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3777 /* No outbuf here means successful sendfile. */
3778 goto strict_unlock;
3781 DEBUG(0,("send_file_readX: sendfile failed for file "
3782 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3783 strerror(errno)));
3784 exit_server_cleanly("send_file_readX sendfile failed");
3785 } else if (nread == 0) {
3787 * Some sendfile implementations return 0 to indicate
3788 * that there was a short read, but nothing was
3789 * actually written to the socket. In this case,
3790 * fallback to the normal read path so the header gets
3791 * the correct byte count.
3793 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3794 "falling back to the normal read: %s\n",
3795 fsp_str_dbg(fsp)));
3796 goto normal_read;
3799 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3800 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3802 /* Deal with possible short send. */
3803 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3804 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3806 /* No outbuf here means successful sendfile. */
3807 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3808 SMB_PERFCOUNT_END(&req->pcd);
3809 goto strict_unlock;
3812 normal_read:
3814 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3815 uint8 headerbuf[smb_size + 2*12];
3817 construct_reply_common_req(req, (char *)headerbuf);
3818 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3820 /* Send out the header. */
3821 if (write_data(req->sconn->sock, (char *)headerbuf,
3822 sizeof(headerbuf)) != sizeof(headerbuf)) {
3824 char addr[INET6_ADDRSTRLEN];
3826 * Try and give an error message saying what
3827 * client failed.
3829 DEBUG(0, ("write_data failed for client %s. "
3830 "Error %s\n",
3831 get_peer_addr(req->sconn->sock, addr,
3832 sizeof(addr)),
3833 strerror(errno)));
3835 DEBUG(0,("send_file_readX: write_data failed for file "
3836 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3837 strerror(errno)));
3838 exit_server_cleanly("send_file_readX sendfile failed");
3840 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3841 if (nread == -1) {
3842 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3843 "file %s (%s).\n", fsp_str_dbg(fsp),
3844 strerror(errno)));
3845 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3847 goto strict_unlock;
3850 nosendfile_read:
3852 reply_outbuf(req, 12, smb_maxcnt);
3853 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3854 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3856 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3857 saved_errno = errno;
3859 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3861 if (nread < 0) {
3862 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3863 return;
3866 setup_readX_header(req, (char *)req->outbuf, nread);
3868 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3869 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3870 return;
3872 strict_unlock:
3873 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3874 TALLOC_FREE(req->outbuf);
3875 return;
3878 /****************************************************************************
3879 Work out how much space we have for a read return.
3880 ****************************************************************************/
3882 static size_t calc_max_read_pdu(const struct smb_request *req)
3884 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3885 return req->sconn->smb1.sessions.max_send;
3888 if (!lp_large_readwrite()) {
3889 return req->sconn->smb1.sessions.max_send;
3892 if (req_is_in_chain(req)) {
3893 return req->sconn->smb1.sessions.max_send;
3896 if (req->encrypted) {
3898 * Don't take encrypted traffic up to the
3899 * limit. There are padding considerations
3900 * that make that tricky.
3902 return req->sconn->smb1.sessions.max_send;
3905 if (srv_is_signing_active(req->sconn)) {
3906 return 0x1FFFF;
3909 if (!lp_unix_extensions()) {
3910 return 0x1FFFF;
3914 * We can do ultra-large POSIX reads.
3916 return 0xFFFFFF;
3919 /****************************************************************************
3920 Calculate how big a read can be. Copes with all clients. It's always
3921 safe to return a short read - Windows does this.
3922 ****************************************************************************/
3924 static size_t calc_read_size(const struct smb_request *req,
3925 size_t upper_size,
3926 size_t lower_size)
3928 size_t max_pdu = calc_max_read_pdu(req);
3929 size_t total_size = 0;
3930 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3931 size_t max_len = max_pdu - hdr_len;
3934 * Windows explicitly ignores upper size of 0xFFFF.
3935 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3936 * We must do the same as these will never fit even in
3937 * an extended size NetBIOS packet.
3939 if (upper_size == 0xFFFF) {
3940 upper_size = 0;
3943 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3944 upper_size = 0;
3947 total_size = ((upper_size<<16) | lower_size);
3950 * LARGE_READX test shows it's always safe to return
3951 * a short read. Windows does so.
3953 return MIN(total_size, max_len);
3956 /****************************************************************************
3957 Reply to a read and X.
3958 ****************************************************************************/
3960 void reply_read_and_X(struct smb_request *req)
3962 connection_struct *conn = req->conn;
3963 files_struct *fsp;
3964 off_t startpos;
3965 size_t smb_maxcnt;
3966 size_t upper_size;
3967 bool big_readX = False;
3968 #if 0
3969 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3970 #endif
3972 START_PROFILE(SMBreadX);
3974 if ((req->wct != 10) && (req->wct != 12)) {
3975 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3976 return;
3979 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3980 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3981 smb_maxcnt = SVAL(req->vwv+5, 0);
3983 /* If it's an IPC, pass off the pipe handler. */
3984 if (IS_IPC(conn)) {
3985 reply_pipe_read_and_X(req);
3986 END_PROFILE(SMBreadX);
3987 return;
3990 if (!check_fsp(conn, req, fsp)) {
3991 END_PROFILE(SMBreadX);
3992 return;
3995 if (!CHECK_READ(fsp,req)) {
3996 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3997 END_PROFILE(SMBreadX);
3998 return;
4001 upper_size = SVAL(req->vwv+7, 0);
4002 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4003 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4005 * This is a heuristic to avoid keeping large
4006 * outgoing buffers around over long-lived aio
4007 * requests.
4009 big_readX = True;
4012 if (req->wct == 12) {
4014 * This is a large offset (64 bit) read.
4016 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4020 if (!big_readX) {
4021 NTSTATUS status = schedule_aio_read_and_X(conn,
4022 req,
4023 fsp,
4024 startpos,
4025 smb_maxcnt);
4026 if (NT_STATUS_IS_OK(status)) {
4027 /* Read scheduled - we're done. */
4028 goto out;
4030 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4031 /* Real error - report to client. */
4032 END_PROFILE(SMBreadX);
4033 reply_nterror(req, status);
4034 return;
4036 /* NT_STATUS_RETRY - fall back to sync read. */
4039 smbd_lock_socket(req->sconn);
4040 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4041 smbd_unlock_socket(req->sconn);
4043 out:
4044 END_PROFILE(SMBreadX);
4045 return;
4048 /****************************************************************************
4049 Error replies to writebraw must have smb_wct == 1. Fix this up.
4050 ****************************************************************************/
4052 void error_to_writebrawerr(struct smb_request *req)
4054 uint8 *old_outbuf = req->outbuf;
4056 reply_outbuf(req, 1, 0);
4058 memcpy(req->outbuf, old_outbuf, smb_size);
4059 TALLOC_FREE(old_outbuf);
4062 /****************************************************************************
4063 Read 4 bytes of a smb packet and return the smb length of the packet.
4064 Store the result in the buffer. This version of the function will
4065 never return a session keepalive (length of zero).
4066 Timeout is in milliseconds.
4067 ****************************************************************************/
4069 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4070 size_t *len)
4072 uint8_t msgtype = NBSSkeepalive;
4074 while (msgtype == NBSSkeepalive) {
4075 NTSTATUS status;
4077 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4078 len);
4079 if (!NT_STATUS_IS_OK(status)) {
4080 char addr[INET6_ADDRSTRLEN];
4081 /* Try and give an error message
4082 * saying what client failed. */
4083 DEBUG(0, ("read_fd_with_timeout failed for "
4084 "client %s read error = %s.\n",
4085 get_peer_addr(fd,addr,sizeof(addr)),
4086 nt_errstr(status)));
4087 return status;
4090 msgtype = CVAL(inbuf, 0);
4093 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4094 (unsigned long)len));
4096 return NT_STATUS_OK;
4099 /****************************************************************************
4100 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4101 ****************************************************************************/
4103 void reply_writebraw(struct smb_request *req)
4105 connection_struct *conn = req->conn;
4106 char *buf = NULL;
4107 ssize_t nwritten=0;
4108 ssize_t total_written=0;
4109 size_t numtowrite=0;
4110 size_t tcount;
4111 off_t startpos;
4112 const char *data=NULL;
4113 bool write_through;
4114 files_struct *fsp;
4115 struct lock_struct lock;
4116 NTSTATUS status;
4118 START_PROFILE(SMBwritebraw);
4121 * If we ever reply with an error, it must have the SMB command
4122 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4123 * we're finished.
4125 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4127 if (srv_is_signing_active(req->sconn)) {
4128 END_PROFILE(SMBwritebraw);
4129 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4130 "raw reads/writes are disallowed.");
4133 if (req->wct < 12) {
4134 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4135 error_to_writebrawerr(req);
4136 END_PROFILE(SMBwritebraw);
4137 return;
4140 if (req->sconn->smb1.echo_handler.trusted_fde) {
4141 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4142 "'async smb echo handler = yes'\n"));
4143 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4144 error_to_writebrawerr(req);
4145 END_PROFILE(SMBwritebraw);
4146 return;
4149 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4150 if (!check_fsp(conn, req, fsp)) {
4151 error_to_writebrawerr(req);
4152 END_PROFILE(SMBwritebraw);
4153 return;
4156 if (!CHECK_WRITE(fsp)) {
4157 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4158 error_to_writebrawerr(req);
4159 END_PROFILE(SMBwritebraw);
4160 return;
4163 tcount = IVAL(req->vwv+1, 0);
4164 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4165 write_through = BITSETW(req->vwv+7,0);
4167 /* We have to deal with slightly different formats depending
4168 on whether we are using the core+ or lanman1.0 protocol */
4170 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4171 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4172 data = smb_buf_const(req->inbuf);
4173 } else {
4174 numtowrite = SVAL(req->vwv+10, 0);
4175 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4178 /* Ensure we don't write bytes past the end of this packet. */
4179 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4180 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4181 error_to_writebrawerr(req);
4182 END_PROFILE(SMBwritebraw);
4183 return;
4186 if (!fsp->print_file) {
4187 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4188 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4189 &lock);
4191 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4192 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4193 error_to_writebrawerr(req);
4194 END_PROFILE(SMBwritebraw);
4195 return;
4199 if (numtowrite>0) {
4200 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4203 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4204 "wrote=%d sync=%d\n",
4205 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4206 (int)nwritten, (int)write_through));
4208 if (nwritten < (ssize_t)numtowrite) {
4209 reply_nterror(req, NT_STATUS_DISK_FULL);
4210 error_to_writebrawerr(req);
4211 goto strict_unlock;
4214 total_written = nwritten;
4216 /* Allocate a buffer of 64k + length. */
4217 buf = talloc_array(NULL, char, 65540);
4218 if (!buf) {
4219 reply_nterror(req, NT_STATUS_NO_MEMORY);
4220 error_to_writebrawerr(req);
4221 goto strict_unlock;
4224 /* Return a SMBwritebraw message to the redirector to tell
4225 * it to send more bytes */
4227 memcpy(buf, req->inbuf, smb_size);
4228 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4229 SCVAL(buf,smb_com,SMBwritebraw);
4230 SSVALS(buf,smb_vwv0,0xFFFF);
4231 show_msg(buf);
4232 if (!srv_send_smb(req->sconn,
4233 buf,
4234 false, 0, /* no signing */
4235 IS_CONN_ENCRYPTED(conn),
4236 &req->pcd)) {
4237 exit_server_cleanly("reply_writebraw: srv_send_smb "
4238 "failed.");
4241 /* Now read the raw data into the buffer and write it */
4242 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4243 &numtowrite);
4244 if (!NT_STATUS_IS_OK(status)) {
4245 exit_server_cleanly("secondary writebraw failed");
4248 /* Set up outbuf to return the correct size */
4249 reply_outbuf(req, 1, 0);
4251 if (numtowrite != 0) {
4253 if (numtowrite > 0xFFFF) {
4254 DEBUG(0,("reply_writebraw: Oversize secondary write "
4255 "raw requested (%u). Terminating\n",
4256 (unsigned int)numtowrite ));
4257 exit_server_cleanly("secondary writebraw failed");
4260 if (tcount > nwritten+numtowrite) {
4261 DEBUG(3,("reply_writebraw: Client overestimated the "
4262 "write %d %d %d\n",
4263 (int)tcount,(int)nwritten,(int)numtowrite));
4266 status = read_data(req->sconn->sock, buf+4, numtowrite);
4268 if (!NT_STATUS_IS_OK(status)) {
4269 char addr[INET6_ADDRSTRLEN];
4270 /* Try and give an error message
4271 * saying what client failed. */
4272 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4273 "raw read failed (%s) for client %s. "
4274 "Terminating\n", nt_errstr(status),
4275 get_peer_addr(req->sconn->sock, addr,
4276 sizeof(addr))));
4277 exit_server_cleanly("secondary writebraw failed");
4280 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4281 if (nwritten == -1) {
4282 TALLOC_FREE(buf);
4283 reply_nterror(req, map_nt_error_from_unix(errno));
4284 error_to_writebrawerr(req);
4285 goto strict_unlock;
4288 if (nwritten < (ssize_t)numtowrite) {
4289 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4290 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4293 if (nwritten > 0) {
4294 total_written += nwritten;
4298 TALLOC_FREE(buf);
4299 SSVAL(req->outbuf,smb_vwv0,total_written);
4301 status = sync_file(conn, fsp, write_through);
4302 if (!NT_STATUS_IS_OK(status)) {
4303 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4304 fsp_str_dbg(fsp), nt_errstr(status)));
4305 reply_nterror(req, status);
4306 error_to_writebrawerr(req);
4307 goto strict_unlock;
4310 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4311 "wrote=%d\n",
4312 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4313 (int)total_written));
4315 if (!fsp->print_file) {
4316 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4319 /* We won't return a status if write through is not selected - this
4320 * follows what WfWg does */
4321 END_PROFILE(SMBwritebraw);
4323 if (!write_through && total_written==tcount) {
4325 #if RABBIT_PELLET_FIX
4327 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4328 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4329 * JRA.
4331 if (!send_keepalive(req->sconn->sock)) {
4332 exit_server_cleanly("reply_writebraw: send of "
4333 "keepalive failed");
4335 #endif
4336 TALLOC_FREE(req->outbuf);
4338 return;
4340 strict_unlock:
4341 if (!fsp->print_file) {
4342 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4345 END_PROFILE(SMBwritebraw);
4346 return;
4349 #undef DBGC_CLASS
4350 #define DBGC_CLASS DBGC_LOCKING
4352 /****************************************************************************
4353 Reply to a writeunlock (core+).
4354 ****************************************************************************/
4356 void reply_writeunlock(struct smb_request *req)
4358 connection_struct *conn = req->conn;
4359 ssize_t nwritten = -1;
4360 size_t numtowrite;
4361 off_t startpos;
4362 const char *data;
4363 NTSTATUS status = NT_STATUS_OK;
4364 files_struct *fsp;
4365 struct lock_struct lock;
4366 int saved_errno = 0;
4368 START_PROFILE(SMBwriteunlock);
4370 if (req->wct < 5) {
4371 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4372 END_PROFILE(SMBwriteunlock);
4373 return;
4376 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4378 if (!check_fsp(conn, req, fsp)) {
4379 END_PROFILE(SMBwriteunlock);
4380 return;
4383 if (!CHECK_WRITE(fsp)) {
4384 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4385 END_PROFILE(SMBwriteunlock);
4386 return;
4389 numtowrite = SVAL(req->vwv+1, 0);
4390 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4391 data = (const char *)req->buf + 3;
4393 if (!fsp->print_file && numtowrite > 0) {
4394 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4395 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4396 &lock);
4398 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4399 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4400 END_PROFILE(SMBwriteunlock);
4401 return;
4405 /* The special X/Open SMB protocol handling of
4406 zero length writes is *NOT* done for
4407 this call */
4408 if(numtowrite == 0) {
4409 nwritten = 0;
4410 } else {
4411 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4412 saved_errno = errno;
4415 status = sync_file(conn, fsp, False /* write through */);
4416 if (!NT_STATUS_IS_OK(status)) {
4417 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4418 fsp_str_dbg(fsp), nt_errstr(status)));
4419 reply_nterror(req, status);
4420 goto strict_unlock;
4423 if(nwritten < 0) {
4424 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4425 goto strict_unlock;
4428 if((nwritten < numtowrite) && (numtowrite != 0)) {
4429 reply_nterror(req, NT_STATUS_DISK_FULL);
4430 goto strict_unlock;
4433 if (numtowrite && !fsp->print_file) {
4434 status = do_unlock(req->sconn->msg_ctx,
4435 fsp,
4436 (uint64_t)req->smbpid,
4437 (uint64_t)numtowrite,
4438 (uint64_t)startpos,
4439 WINDOWS_LOCK);
4441 if (NT_STATUS_V(status)) {
4442 reply_nterror(req, status);
4443 goto strict_unlock;
4447 reply_outbuf(req, 1, 0);
4449 SSVAL(req->outbuf,smb_vwv0,nwritten);
4451 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4452 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4454 strict_unlock:
4455 if (numtowrite && !fsp->print_file) {
4456 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4459 END_PROFILE(SMBwriteunlock);
4460 return;
4463 #undef DBGC_CLASS
4464 #define DBGC_CLASS DBGC_ALL
4466 /****************************************************************************
4467 Reply to a write.
4468 ****************************************************************************/
4470 void reply_write(struct smb_request *req)
4472 connection_struct *conn = req->conn;
4473 size_t numtowrite;
4474 ssize_t nwritten = -1;
4475 off_t startpos;
4476 const char *data;
4477 files_struct *fsp;
4478 struct lock_struct lock;
4479 NTSTATUS status;
4480 int saved_errno = 0;
4482 START_PROFILE(SMBwrite);
4484 if (req->wct < 5) {
4485 END_PROFILE(SMBwrite);
4486 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4487 return;
4490 /* If it's an IPC, pass off the pipe handler. */
4491 if (IS_IPC(conn)) {
4492 reply_pipe_write(req);
4493 END_PROFILE(SMBwrite);
4494 return;
4497 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4499 if (!check_fsp(conn, req, fsp)) {
4500 END_PROFILE(SMBwrite);
4501 return;
4504 if (!CHECK_WRITE(fsp)) {
4505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4506 END_PROFILE(SMBwrite);
4507 return;
4510 numtowrite = SVAL(req->vwv+1, 0);
4511 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4512 data = (const char *)req->buf + 3;
4514 if (!fsp->print_file) {
4515 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4516 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4517 &lock);
4519 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4520 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4521 END_PROFILE(SMBwrite);
4522 return;
4527 * X/Open SMB protocol says that if smb_vwv1 is
4528 * zero then the file size should be extended or
4529 * truncated to the size given in smb_vwv[2-3].
4532 if(numtowrite == 0) {
4534 * This is actually an allocate call, and set EOF. JRA.
4536 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4537 if (nwritten < 0) {
4538 reply_nterror(req, NT_STATUS_DISK_FULL);
4539 goto strict_unlock;
4541 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4542 if (nwritten < 0) {
4543 reply_nterror(req, NT_STATUS_DISK_FULL);
4544 goto strict_unlock;
4546 trigger_write_time_update_immediate(fsp);
4547 } else {
4548 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4551 status = sync_file(conn, fsp, False);
4552 if (!NT_STATUS_IS_OK(status)) {
4553 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4554 fsp_str_dbg(fsp), nt_errstr(status)));
4555 reply_nterror(req, status);
4556 goto strict_unlock;
4559 if(nwritten < 0) {
4560 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4561 goto strict_unlock;
4564 if((nwritten == 0) && (numtowrite != 0)) {
4565 reply_nterror(req, NT_STATUS_DISK_FULL);
4566 goto strict_unlock;
4569 reply_outbuf(req, 1, 0);
4571 SSVAL(req->outbuf,smb_vwv0,nwritten);
4573 if (nwritten < (ssize_t)numtowrite) {
4574 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4575 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4578 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4580 strict_unlock:
4581 if (!fsp->print_file) {
4582 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4585 END_PROFILE(SMBwrite);
4586 return;
4589 /****************************************************************************
4590 Ensure a buffer is a valid writeX for recvfile purposes.
4591 ****************************************************************************/
4593 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4594 (2*14) + /* word count (including bcc) */ \
4595 1 /* pad byte */)
4597 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4598 const uint8_t *inbuf)
4600 size_t numtowrite;
4601 unsigned int doff = 0;
4602 size_t len = smb_len_large(inbuf);
4603 uint16_t fnum;
4604 struct smbXsrv_open *op = NULL;
4605 struct files_struct *fsp = NULL;
4606 NTSTATUS status;
4608 if (is_encrypted_packet(sconn, inbuf)) {
4609 /* Can't do this on encrypted
4610 * connections. */
4611 return false;
4614 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4615 return false;
4618 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4619 CVAL(inbuf,smb_wct) != 14) {
4620 DEBUG(10,("is_valid_writeX_buffer: chained or "
4621 "invalid word length.\n"));
4622 return false;
4625 fnum = SVAL(inbuf, smb_vwv2);
4626 status = smb1srv_open_lookup(sconn->conn,
4627 fnum,
4628 0, /* now */
4629 &op);
4630 if (!NT_STATUS_IS_OK(status)) {
4631 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4632 return false;
4634 fsp = op->compat;
4635 if (fsp == NULL) {
4636 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4637 return false;
4639 if (fsp->conn == NULL) {
4640 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4641 return false;
4644 if (IS_IPC(fsp->conn)) {
4645 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4646 return false;
4648 if (IS_PRINT(fsp->conn)) {
4649 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4650 return false;
4652 doff = SVAL(inbuf,smb_vwv11);
4654 numtowrite = SVAL(inbuf,smb_vwv10);
4656 if (len > doff && len - doff > 0xFFFF) {
4657 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4660 if (numtowrite == 0) {
4661 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4662 return false;
4665 /* Ensure the sizes match up. */
4666 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4667 /* no pad byte...old smbclient :-( */
4668 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4669 (unsigned int)doff,
4670 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4671 return false;
4674 if (len - doff != numtowrite) {
4675 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4676 "len = %u, doff = %u, numtowrite = %u\n",
4677 (unsigned int)len,
4678 (unsigned int)doff,
4679 (unsigned int)numtowrite ));
4680 return false;
4683 DEBUG(10,("is_valid_writeX_buffer: true "
4684 "len = %u, doff = %u, numtowrite = %u\n",
4685 (unsigned int)len,
4686 (unsigned int)doff,
4687 (unsigned int)numtowrite ));
4689 return true;
4692 /****************************************************************************
4693 Reply to a write and X.
4694 ****************************************************************************/
4696 void reply_write_and_X(struct smb_request *req)
4698 connection_struct *conn = req->conn;
4699 files_struct *fsp;
4700 struct lock_struct lock;
4701 off_t startpos;
4702 size_t numtowrite;
4703 bool write_through;
4704 ssize_t nwritten;
4705 unsigned int smb_doff;
4706 unsigned int smblen;
4707 const char *data;
4708 NTSTATUS status;
4709 int saved_errno = 0;
4711 START_PROFILE(SMBwriteX);
4713 if ((req->wct != 12) && (req->wct != 14)) {
4714 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4715 goto out;
4718 numtowrite = SVAL(req->vwv+10, 0);
4719 smb_doff = SVAL(req->vwv+11, 0);
4720 smblen = smb_len(req->inbuf);
4722 if (req->unread_bytes > 0xFFFF ||
4723 (smblen > smb_doff &&
4724 smblen - smb_doff > 0xFFFF)) {
4725 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4728 if (req->unread_bytes) {
4729 /* Can't do a recvfile write on IPC$ */
4730 if (IS_IPC(conn)) {
4731 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4732 goto out;
4734 if (numtowrite != req->unread_bytes) {
4735 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4736 goto out;
4738 } else {
4739 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4740 smb_doff + numtowrite > smblen) {
4741 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4742 goto out;
4746 /* If it's an IPC, pass off the pipe handler. */
4747 if (IS_IPC(conn)) {
4748 if (req->unread_bytes) {
4749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4750 goto out;
4752 reply_pipe_write_and_X(req);
4753 goto out;
4756 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4757 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4758 write_through = BITSETW(req->vwv+7,0);
4760 if (!check_fsp(conn, req, fsp)) {
4761 goto out;
4764 if (!CHECK_WRITE(fsp)) {
4765 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4766 goto out;
4769 data = smb_base(req->inbuf) + smb_doff;
4771 if(req->wct == 14) {
4773 * This is a large offset (64 bit) write.
4775 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4779 /* X/Open SMB protocol says that, unlike SMBwrite
4780 if the length is zero then NO truncation is
4781 done, just a write of zero. To truncate a file,
4782 use SMBwrite. */
4784 if(numtowrite == 0) {
4785 nwritten = 0;
4786 } else {
4787 if (req->unread_bytes == 0) {
4788 status = schedule_aio_write_and_X(conn,
4789 req,
4790 fsp,
4791 data,
4792 startpos,
4793 numtowrite);
4795 if (NT_STATUS_IS_OK(status)) {
4796 /* write scheduled - we're done. */
4797 goto out;
4799 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4800 /* Real error - report to client. */
4801 reply_nterror(req, status);
4802 goto out;
4804 /* NT_STATUS_RETRY - fall through to sync write. */
4807 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4808 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4809 &lock);
4811 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4812 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4813 goto out;
4816 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4817 saved_errno = errno;
4819 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4822 if(nwritten < 0) {
4823 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4824 goto out;
4827 if((nwritten == 0) && (numtowrite != 0)) {
4828 reply_nterror(req, NT_STATUS_DISK_FULL);
4829 goto out;
4832 reply_outbuf(req, 6, 0);
4833 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4834 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4835 SSVAL(req->outbuf,smb_vwv2,nwritten);
4836 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4838 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4839 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4841 status = sync_file(conn, fsp, write_through);
4842 if (!NT_STATUS_IS_OK(status)) {
4843 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4844 fsp_str_dbg(fsp), nt_errstr(status)));
4845 reply_nterror(req, status);
4846 goto out;
4849 END_PROFILE(SMBwriteX);
4850 return;
4852 out:
4853 if (req->unread_bytes) {
4854 /* writeX failed. drain socket. */
4855 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4856 req->unread_bytes) {
4857 smb_panic("failed to drain pending bytes");
4859 req->unread_bytes = 0;
4862 END_PROFILE(SMBwriteX);
4863 return;
4866 /****************************************************************************
4867 Reply to a lseek.
4868 ****************************************************************************/
4870 void reply_lseek(struct smb_request *req)
4872 connection_struct *conn = req->conn;
4873 off_t startpos;
4874 off_t res= -1;
4875 int mode,umode;
4876 files_struct *fsp;
4878 START_PROFILE(SMBlseek);
4880 if (req->wct < 4) {
4881 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4882 END_PROFILE(SMBlseek);
4883 return;
4886 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4888 if (!check_fsp(conn, req, fsp)) {
4889 return;
4892 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
4894 mode = SVAL(req->vwv+1, 0) & 3;
4895 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4896 startpos = (off_t)IVALS(req->vwv+2, 0);
4898 switch (mode) {
4899 case 0:
4900 umode = SEEK_SET;
4901 res = startpos;
4902 break;
4903 case 1:
4904 umode = SEEK_CUR;
4905 res = fsp->fh->pos + startpos;
4906 break;
4907 case 2:
4908 umode = SEEK_END;
4909 break;
4910 default:
4911 umode = SEEK_SET;
4912 res = startpos;
4913 break;
4916 if (umode == SEEK_END) {
4917 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4918 if(errno == EINVAL) {
4919 off_t current_pos = startpos;
4921 if(fsp_stat(fsp) == -1) {
4922 reply_nterror(req,
4923 map_nt_error_from_unix(errno));
4924 END_PROFILE(SMBlseek);
4925 return;
4928 current_pos += fsp->fsp_name->st.st_ex_size;
4929 if(current_pos < 0)
4930 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4934 if(res == -1) {
4935 reply_nterror(req, map_nt_error_from_unix(errno));
4936 END_PROFILE(SMBlseek);
4937 return;
4941 fsp->fh->pos = res;
4943 reply_outbuf(req, 2, 0);
4944 SIVAL(req->outbuf,smb_vwv0,res);
4946 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4947 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4949 END_PROFILE(SMBlseek);
4950 return;
4953 /****************************************************************************
4954 Reply to a flush.
4955 ****************************************************************************/
4957 void reply_flush(struct smb_request *req)
4959 connection_struct *conn = req->conn;
4960 uint16 fnum;
4961 files_struct *fsp;
4963 START_PROFILE(SMBflush);
4965 if (req->wct < 1) {
4966 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4967 return;
4970 fnum = SVAL(req->vwv+0, 0);
4971 fsp = file_fsp(req, fnum);
4973 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4974 return;
4977 if (!fsp) {
4978 file_sync_all(conn);
4979 } else {
4980 NTSTATUS status = sync_file(conn, fsp, True);
4981 if (!NT_STATUS_IS_OK(status)) {
4982 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4983 fsp_str_dbg(fsp), nt_errstr(status)));
4984 reply_nterror(req, status);
4985 END_PROFILE(SMBflush);
4986 return;
4990 reply_outbuf(req, 0, 0);
4992 DEBUG(3,("flush\n"));
4993 END_PROFILE(SMBflush);
4994 return;
4997 /****************************************************************************
4998 Reply to a exit.
4999 conn POINTER CAN BE NULL HERE !
5000 ****************************************************************************/
5002 void reply_exit(struct smb_request *req)
5004 START_PROFILE(SMBexit);
5006 file_close_pid(req->sconn, req->smbpid, req->vuid);
5008 reply_outbuf(req, 0, 0);
5010 DEBUG(3,("exit\n"));
5012 END_PROFILE(SMBexit);
5013 return;
5016 struct reply_close_state {
5017 files_struct *fsp;
5018 struct smb_request *smbreq;
5021 static void do_smb1_close(struct tevent_req *req);
5023 void reply_close(struct smb_request *req)
5025 connection_struct *conn = req->conn;
5026 NTSTATUS status = NT_STATUS_OK;
5027 files_struct *fsp = NULL;
5028 START_PROFILE(SMBclose);
5030 if (req->wct < 3) {
5031 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5032 END_PROFILE(SMBclose);
5033 return;
5036 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5039 * We can only use check_fsp if we know it's not a directory.
5042 if (!check_fsp_open(conn, req, fsp)) {
5043 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5044 END_PROFILE(SMBclose);
5045 return;
5048 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5049 fsp->is_directory ? "directory" : "file",
5050 fsp->fh->fd, fsp_fnum_dbg(fsp),
5051 conn->num_files_open));
5053 if (!fsp->is_directory) {
5054 time_t t;
5057 * Take care of any time sent in the close.
5060 t = srv_make_unix_date3(req->vwv+1);
5061 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5064 if (fsp->num_aio_requests != 0) {
5066 struct reply_close_state *state;
5068 DEBUG(10, ("closing with aio %u requests pending\n",
5069 fsp->num_aio_requests));
5072 * We depend on the aio_extra destructor to take care of this
5073 * close request once fsp->num_aio_request drops to 0.
5076 fsp->deferred_close = tevent_wait_send(
5077 fsp, fsp->conn->sconn->ev_ctx);
5078 if (fsp->deferred_close == NULL) {
5079 status = NT_STATUS_NO_MEMORY;
5080 goto done;
5083 state = talloc(fsp, struct reply_close_state);
5084 if (state == NULL) {
5085 TALLOC_FREE(fsp->deferred_close);
5086 status = NT_STATUS_NO_MEMORY;
5087 goto done;
5089 state->fsp = fsp;
5090 state->smbreq = talloc_move(fsp, &req);
5091 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5092 state);
5093 END_PROFILE(SMBclose);
5094 return;
5098 * close_file() returns the unix errno if an error was detected on
5099 * close - normally this is due to a disk full error. If not then it
5100 * was probably an I/O error.
5103 status = close_file(req, fsp, NORMAL_CLOSE);
5104 done:
5105 if (!NT_STATUS_IS_OK(status)) {
5106 reply_nterror(req, status);
5107 END_PROFILE(SMBclose);
5108 return;
5111 reply_outbuf(req, 0, 0);
5112 END_PROFILE(SMBclose);
5113 return;
5116 static void do_smb1_close(struct tevent_req *req)
5118 struct reply_close_state *state = tevent_req_callback_data(
5119 req, struct reply_close_state);
5120 struct smb_request *smbreq;
5121 NTSTATUS status;
5122 int ret;
5124 ret = tevent_wait_recv(req);
5125 TALLOC_FREE(req);
5126 if (ret != 0) {
5127 DEBUG(10, ("tevent_wait_recv returned %s\n",
5128 strerror(ret)));
5130 * Continue anyway, this should never happen
5135 * fsp->smb2_close_request right now is a talloc grandchild of
5136 * fsp. When we close_file(fsp), it would go with it. No chance to
5137 * reply...
5139 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5141 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5142 if (NT_STATUS_IS_OK(status)) {
5143 reply_outbuf(smbreq, 0, 0);
5144 } else {
5145 reply_nterror(smbreq, status);
5147 if (!srv_send_smb(smbreq->sconn,
5148 (char *)smbreq->outbuf,
5149 true,
5150 smbreq->seqnum+1,
5151 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5152 NULL)) {
5153 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5154 "failed.");
5156 TALLOC_FREE(smbreq);
5159 /****************************************************************************
5160 Reply to a writeclose (Core+ protocol).
5161 ****************************************************************************/
5163 void reply_writeclose(struct smb_request *req)
5165 connection_struct *conn = req->conn;
5166 size_t numtowrite;
5167 ssize_t nwritten = -1;
5168 NTSTATUS close_status = NT_STATUS_OK;
5169 off_t startpos;
5170 const char *data;
5171 struct timespec mtime;
5172 files_struct *fsp;
5173 struct lock_struct lock;
5175 START_PROFILE(SMBwriteclose);
5177 if (req->wct < 6) {
5178 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5179 END_PROFILE(SMBwriteclose);
5180 return;
5183 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5185 if (!check_fsp(conn, req, fsp)) {
5186 END_PROFILE(SMBwriteclose);
5187 return;
5189 if (!CHECK_WRITE(fsp)) {
5190 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5191 END_PROFILE(SMBwriteclose);
5192 return;
5195 numtowrite = SVAL(req->vwv+1, 0);
5196 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5197 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5198 data = (const char *)req->buf + 1;
5200 if (fsp->print_file == NULL) {
5201 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5202 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5203 &lock);
5205 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5206 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5207 END_PROFILE(SMBwriteclose);
5208 return;
5212 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5214 if (fsp->print_file == NULL) {
5215 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5218 set_close_write_time(fsp, mtime);
5221 * More insanity. W2K only closes the file if writelen > 0.
5222 * JRA.
5225 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5226 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5227 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5229 if (numtowrite) {
5230 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5231 "file %s\n", fsp_str_dbg(fsp)));
5232 close_status = close_file(req, fsp, NORMAL_CLOSE);
5233 fsp = NULL;
5236 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5237 reply_nterror(req, NT_STATUS_DISK_FULL);
5238 goto out;
5241 if(!NT_STATUS_IS_OK(close_status)) {
5242 reply_nterror(req, close_status);
5243 goto out;
5246 reply_outbuf(req, 1, 0);
5248 SSVAL(req->outbuf,smb_vwv0,nwritten);
5250 out:
5252 END_PROFILE(SMBwriteclose);
5253 return;
5256 #undef DBGC_CLASS
5257 #define DBGC_CLASS DBGC_LOCKING
5259 /****************************************************************************
5260 Reply to a lock.
5261 ****************************************************************************/
5263 void reply_lock(struct smb_request *req)
5265 connection_struct *conn = req->conn;
5266 uint64_t count,offset;
5267 NTSTATUS status;
5268 files_struct *fsp;
5269 struct byte_range_lock *br_lck = NULL;
5271 START_PROFILE(SMBlock);
5273 if (req->wct < 5) {
5274 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5275 END_PROFILE(SMBlock);
5276 return;
5279 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5281 if (!check_fsp(conn, req, fsp)) {
5282 END_PROFILE(SMBlock);
5283 return;
5286 count = (uint64_t)IVAL(req->vwv+1, 0);
5287 offset = (uint64_t)IVAL(req->vwv+3, 0);
5289 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5290 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5292 br_lck = do_lock(req->sconn->msg_ctx,
5293 fsp,
5294 (uint64_t)req->smbpid,
5295 count,
5296 offset,
5297 WRITE_LOCK,
5298 WINDOWS_LOCK,
5299 False, /* Non-blocking lock. */
5300 &status,
5301 NULL,
5302 NULL);
5304 TALLOC_FREE(br_lck);
5306 if (NT_STATUS_V(status)) {
5307 reply_nterror(req, status);
5308 END_PROFILE(SMBlock);
5309 return;
5312 reply_outbuf(req, 0, 0);
5314 END_PROFILE(SMBlock);
5315 return;
5318 /****************************************************************************
5319 Reply to a unlock.
5320 ****************************************************************************/
5322 void reply_unlock(struct smb_request *req)
5324 connection_struct *conn = req->conn;
5325 uint64_t count,offset;
5326 NTSTATUS status;
5327 files_struct *fsp;
5329 START_PROFILE(SMBunlock);
5331 if (req->wct < 5) {
5332 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5333 END_PROFILE(SMBunlock);
5334 return;
5337 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5339 if (!check_fsp(conn, req, fsp)) {
5340 END_PROFILE(SMBunlock);
5341 return;
5344 count = (uint64_t)IVAL(req->vwv+1, 0);
5345 offset = (uint64_t)IVAL(req->vwv+3, 0);
5347 status = do_unlock(req->sconn->msg_ctx,
5348 fsp,
5349 (uint64_t)req->smbpid,
5350 count,
5351 offset,
5352 WINDOWS_LOCK);
5354 if (NT_STATUS_V(status)) {
5355 reply_nterror(req, status);
5356 END_PROFILE(SMBunlock);
5357 return;
5360 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5361 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5363 reply_outbuf(req, 0, 0);
5365 END_PROFILE(SMBunlock);
5366 return;
5369 #undef DBGC_CLASS
5370 #define DBGC_CLASS DBGC_ALL
5372 /****************************************************************************
5373 Reply to a tdis.
5374 conn POINTER CAN BE NULL HERE !
5375 ****************************************************************************/
5377 void reply_tdis(struct smb_request *req)
5379 NTSTATUS status;
5380 connection_struct *conn = req->conn;
5381 struct smbXsrv_tcon *tcon;
5383 START_PROFILE(SMBtdis);
5385 if (!conn) {
5386 DEBUG(4,("Invalid connection in tdis\n"));
5387 reply_force_doserror(req, ERRSRV, ERRinvnid);
5388 END_PROFILE(SMBtdis);
5389 return;
5392 tcon = conn->tcon;
5393 req->conn = NULL;
5396 * TODO: cancel all outstanding requests on the tcon
5398 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5399 if (!NT_STATUS_IS_OK(status)) {
5400 DEBUG(0, ("reply_tdis: "
5401 "smbXsrv_tcon_disconnect() failed: %s\n",
5402 nt_errstr(status)));
5404 * If we hit this case, there is something completely
5405 * wrong, so we better disconnect the transport connection.
5407 END_PROFILE(SMBtdis);
5408 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5409 return;
5412 TALLOC_FREE(tcon);
5414 reply_outbuf(req, 0, 0);
5415 END_PROFILE(SMBtdis);
5416 return;
5419 /****************************************************************************
5420 Reply to a echo.
5421 conn POINTER CAN BE NULL HERE !
5422 ****************************************************************************/
5424 void reply_echo(struct smb_request *req)
5426 connection_struct *conn = req->conn;
5427 struct smb_perfcount_data local_pcd;
5428 struct smb_perfcount_data *cur_pcd;
5429 int smb_reverb;
5430 int seq_num;
5432 START_PROFILE(SMBecho);
5434 smb_init_perfcount_data(&local_pcd);
5436 if (req->wct < 1) {
5437 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5438 END_PROFILE(SMBecho);
5439 return;
5442 smb_reverb = SVAL(req->vwv+0, 0);
5444 reply_outbuf(req, 1, req->buflen);
5446 /* copy any incoming data back out */
5447 if (req->buflen > 0) {
5448 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5451 if (smb_reverb > 100) {
5452 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5453 smb_reverb = 100;
5456 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5458 /* this makes sure we catch the request pcd */
5459 if (seq_num == smb_reverb) {
5460 cur_pcd = &req->pcd;
5461 } else {
5462 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5463 cur_pcd = &local_pcd;
5466 SSVAL(req->outbuf,smb_vwv0,seq_num);
5468 show_msg((char *)req->outbuf);
5469 if (!srv_send_smb(req->sconn,
5470 (char *)req->outbuf,
5471 true, req->seqnum+1,
5472 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5473 cur_pcd))
5474 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5477 DEBUG(3,("echo %d times\n", smb_reverb));
5479 TALLOC_FREE(req->outbuf);
5481 END_PROFILE(SMBecho);
5482 return;
5485 /****************************************************************************
5486 Reply to a printopen.
5487 ****************************************************************************/
5489 void reply_printopen(struct smb_request *req)
5491 connection_struct *conn = req->conn;
5492 files_struct *fsp;
5493 NTSTATUS status;
5495 START_PROFILE(SMBsplopen);
5497 if (req->wct < 2) {
5498 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5499 END_PROFILE(SMBsplopen);
5500 return;
5503 if (!CAN_PRINT(conn)) {
5504 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5505 END_PROFILE(SMBsplopen);
5506 return;
5509 status = file_new(req, conn, &fsp);
5510 if(!NT_STATUS_IS_OK(status)) {
5511 reply_nterror(req, status);
5512 END_PROFILE(SMBsplopen);
5513 return;
5516 /* Open for exclusive use, write only. */
5517 status = print_spool_open(fsp, NULL, req->vuid);
5519 if (!NT_STATUS_IS_OK(status)) {
5520 file_free(req, fsp);
5521 reply_nterror(req, status);
5522 END_PROFILE(SMBsplopen);
5523 return;
5526 reply_outbuf(req, 1, 0);
5527 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5529 DEBUG(3,("openprint fd=%d %s\n",
5530 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5532 END_PROFILE(SMBsplopen);
5533 return;
5536 /****************************************************************************
5537 Reply to a printclose.
5538 ****************************************************************************/
5540 void reply_printclose(struct smb_request *req)
5542 connection_struct *conn = req->conn;
5543 files_struct *fsp;
5544 NTSTATUS status;
5546 START_PROFILE(SMBsplclose);
5548 if (req->wct < 1) {
5549 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5550 END_PROFILE(SMBsplclose);
5551 return;
5554 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5556 if (!check_fsp(conn, req, fsp)) {
5557 END_PROFILE(SMBsplclose);
5558 return;
5561 if (!CAN_PRINT(conn)) {
5562 reply_force_doserror(req, ERRSRV, ERRerror);
5563 END_PROFILE(SMBsplclose);
5564 return;
5567 DEBUG(3,("printclose fd=%d %s\n",
5568 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5570 status = close_file(req, fsp, NORMAL_CLOSE);
5572 if(!NT_STATUS_IS_OK(status)) {
5573 reply_nterror(req, status);
5574 END_PROFILE(SMBsplclose);
5575 return;
5578 reply_outbuf(req, 0, 0);
5580 END_PROFILE(SMBsplclose);
5581 return;
5584 /****************************************************************************
5585 Reply to a printqueue.
5586 ****************************************************************************/
5588 void reply_printqueue(struct smb_request *req)
5590 connection_struct *conn = req->conn;
5591 int max_count;
5592 int start_index;
5594 START_PROFILE(SMBsplretq);
5596 if (req->wct < 2) {
5597 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5598 END_PROFILE(SMBsplretq);
5599 return;
5602 max_count = SVAL(req->vwv+0, 0);
5603 start_index = SVAL(req->vwv+1, 0);
5605 /* we used to allow the client to get the cnum wrong, but that
5606 is really quite gross and only worked when there was only
5607 one printer - I think we should now only accept it if they
5608 get it right (tridge) */
5609 if (!CAN_PRINT(conn)) {
5610 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5611 END_PROFILE(SMBsplretq);
5612 return;
5615 reply_outbuf(req, 2, 3);
5616 SSVAL(req->outbuf,smb_vwv0,0);
5617 SSVAL(req->outbuf,smb_vwv1,0);
5618 SCVAL(smb_buf(req->outbuf),0,1);
5619 SSVAL(smb_buf(req->outbuf),1,0);
5621 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5622 start_index, max_count));
5625 TALLOC_CTX *mem_ctx = talloc_tos();
5626 NTSTATUS status;
5627 WERROR werr;
5628 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5629 struct rpc_pipe_client *cli = NULL;
5630 struct dcerpc_binding_handle *b = NULL;
5631 struct policy_handle handle;
5632 struct spoolss_DevmodeContainer devmode_ctr;
5633 union spoolss_JobInfo *info;
5634 uint32_t count;
5635 uint32_t num_to_get;
5636 uint32_t first;
5637 uint32_t i;
5639 ZERO_STRUCT(handle);
5641 status = rpc_pipe_open_interface(conn,
5642 &ndr_table_spoolss,
5643 conn->session_info,
5644 conn->sconn->remote_address,
5645 conn->sconn->msg_ctx,
5646 &cli);
5647 if (!NT_STATUS_IS_OK(status)) {
5648 DEBUG(0, ("reply_printqueue: "
5649 "could not connect to spoolss: %s\n",
5650 nt_errstr(status)));
5651 reply_nterror(req, status);
5652 goto out;
5654 b = cli->binding_handle;
5656 ZERO_STRUCT(devmode_ctr);
5658 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5659 sharename,
5660 NULL, devmode_ctr,
5661 SEC_FLAG_MAXIMUM_ALLOWED,
5662 &handle,
5663 &werr);
5664 if (!NT_STATUS_IS_OK(status)) {
5665 reply_nterror(req, status);
5666 goto out;
5668 if (!W_ERROR_IS_OK(werr)) {
5669 reply_nterror(req, werror_to_ntstatus(werr));
5670 goto out;
5673 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5674 &handle,
5675 0, /* firstjob */
5676 0xff, /* numjobs */
5677 2, /* level */
5678 0, /* offered */
5679 &count,
5680 &info);
5681 if (!W_ERROR_IS_OK(werr)) {
5682 reply_nterror(req, werror_to_ntstatus(werr));
5683 goto out;
5686 if (max_count > 0) {
5687 first = start_index;
5688 } else {
5689 first = start_index + max_count + 1;
5692 if (first >= count) {
5693 num_to_get = first;
5694 } else {
5695 num_to_get = first + MIN(ABS(max_count), count - first);
5698 for (i = first; i < num_to_get; i++) {
5699 char blob[28];
5700 char *p = blob;
5701 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5702 int qstatus;
5703 uint16_t qrapjobid = pjobid_to_rap(sharename,
5704 info[i].info2.job_id);
5706 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5707 qstatus = 2;
5708 } else {
5709 qstatus = 3;
5712 srv_put_dos_date2(p, 0, qtime);
5713 SCVAL(p, 4, qstatus);
5714 SSVAL(p, 5, qrapjobid);
5715 SIVAL(p, 7, info[i].info2.size);
5716 SCVAL(p, 11, 0);
5717 srvstr_push(blob, req->flags2, p+12,
5718 info[i].info2.notify_name, 16, STR_ASCII);
5720 if (message_push_blob(
5721 &req->outbuf,
5722 data_blob_const(
5723 blob, sizeof(blob))) == -1) {
5724 reply_nterror(req, NT_STATUS_NO_MEMORY);
5725 goto out;
5729 if (count > 0) {
5730 SSVAL(req->outbuf,smb_vwv0,count);
5731 SSVAL(req->outbuf,smb_vwv1,
5732 (max_count>0?first+count:first-1));
5733 SCVAL(smb_buf(req->outbuf),0,1);
5734 SSVAL(smb_buf(req->outbuf),1,28*count);
5738 DEBUG(3, ("%u entries returned in queue\n",
5739 (unsigned)count));
5741 out:
5742 if (b && is_valid_policy_hnd(&handle)) {
5743 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5748 END_PROFILE(SMBsplretq);
5749 return;
5752 /****************************************************************************
5753 Reply to a printwrite.
5754 ****************************************************************************/
5756 void reply_printwrite(struct smb_request *req)
5758 connection_struct *conn = req->conn;
5759 int numtowrite;
5760 const char *data;
5761 files_struct *fsp;
5763 START_PROFILE(SMBsplwr);
5765 if (req->wct < 1) {
5766 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5767 END_PROFILE(SMBsplwr);
5768 return;
5771 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5773 if (!check_fsp(conn, req, fsp)) {
5774 END_PROFILE(SMBsplwr);
5775 return;
5778 if (!fsp->print_file) {
5779 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5780 END_PROFILE(SMBsplwr);
5781 return;
5784 if (!CHECK_WRITE(fsp)) {
5785 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5786 END_PROFILE(SMBsplwr);
5787 return;
5790 numtowrite = SVAL(req->buf, 1);
5792 if (req->buflen < numtowrite + 3) {
5793 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5794 END_PROFILE(SMBsplwr);
5795 return;
5798 data = (const char *)req->buf + 3;
5800 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5801 reply_nterror(req, map_nt_error_from_unix(errno));
5802 END_PROFILE(SMBsplwr);
5803 return;
5806 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5808 END_PROFILE(SMBsplwr);
5809 return;
5812 /****************************************************************************
5813 Reply to a mkdir.
5814 ****************************************************************************/
5816 void reply_mkdir(struct smb_request *req)
5818 connection_struct *conn = req->conn;
5819 struct smb_filename *smb_dname = NULL;
5820 char *directory = NULL;
5821 NTSTATUS status;
5822 TALLOC_CTX *ctx = talloc_tos();
5824 START_PROFILE(SMBmkdir);
5826 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5827 STR_TERMINATE, &status);
5828 if (!NT_STATUS_IS_OK(status)) {
5829 reply_nterror(req, status);
5830 goto out;
5833 status = filename_convert(ctx, conn,
5834 req->flags2 & FLAGS2_DFS_PATHNAMES,
5835 directory,
5836 UCF_PREP_CREATEFILE,
5837 NULL,
5838 &smb_dname);
5839 if (!NT_STATUS_IS_OK(status)) {
5840 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5841 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5842 ERRSRV, ERRbadpath);
5843 goto out;
5845 reply_nterror(req, status);
5846 goto out;
5849 status = create_directory(conn, req, smb_dname);
5851 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5853 if (!NT_STATUS_IS_OK(status)) {
5855 if (!use_nt_status()
5856 && NT_STATUS_EQUAL(status,
5857 NT_STATUS_OBJECT_NAME_COLLISION)) {
5859 * Yes, in the DOS error code case we get a
5860 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5861 * samba4 torture test.
5863 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5866 reply_nterror(req, status);
5867 goto out;
5870 reply_outbuf(req, 0, 0);
5872 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5873 out:
5874 TALLOC_FREE(smb_dname);
5875 END_PROFILE(SMBmkdir);
5876 return;
5879 /****************************************************************************
5880 Reply to a rmdir.
5881 ****************************************************************************/
5883 void reply_rmdir(struct smb_request *req)
5885 connection_struct *conn = req->conn;
5886 struct smb_filename *smb_dname = NULL;
5887 char *directory = NULL;
5888 NTSTATUS status;
5889 TALLOC_CTX *ctx = talloc_tos();
5890 files_struct *fsp = NULL;
5891 int info = 0;
5892 struct smbd_server_connection *sconn = req->sconn;
5894 START_PROFILE(SMBrmdir);
5896 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5897 STR_TERMINATE, &status);
5898 if (!NT_STATUS_IS_OK(status)) {
5899 reply_nterror(req, status);
5900 goto out;
5903 status = filename_convert(ctx, conn,
5904 req->flags2 & FLAGS2_DFS_PATHNAMES,
5905 directory,
5907 NULL,
5908 &smb_dname);
5909 if (!NT_STATUS_IS_OK(status)) {
5910 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5911 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5912 ERRSRV, ERRbadpath);
5913 goto out;
5915 reply_nterror(req, status);
5916 goto out;
5919 if (is_ntfs_stream_smb_fname(smb_dname)) {
5920 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5921 goto out;
5924 status = SMB_VFS_CREATE_FILE(
5925 conn, /* conn */
5926 req, /* req */
5927 0, /* root_dir_fid */
5928 smb_dname, /* fname */
5929 DELETE_ACCESS, /* access_mask */
5930 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5931 FILE_SHARE_DELETE),
5932 FILE_OPEN, /* create_disposition*/
5933 FILE_DIRECTORY_FILE, /* create_options */
5934 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5935 0, /* oplock_request */
5936 0, /* allocation_size */
5937 0, /* private_flags */
5938 NULL, /* sd */
5939 NULL, /* ea_list */
5940 &fsp, /* result */
5941 &info); /* pinfo */
5943 if (!NT_STATUS_IS_OK(status)) {
5944 if (open_was_deferred(req->sconn, req->mid)) {
5945 /* We have re-scheduled this call. */
5946 goto out;
5948 reply_nterror(req, status);
5949 goto out;
5952 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5953 if (!NT_STATUS_IS_OK(status)) {
5954 close_file(req, fsp, ERROR_CLOSE);
5955 reply_nterror(req, status);
5956 goto out;
5959 if (!set_delete_on_close(fsp, true,
5960 conn->session_info->security_token,
5961 conn->session_info->unix_token)) {
5962 close_file(req, fsp, ERROR_CLOSE);
5963 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5964 goto out;
5967 status = close_file(req, fsp, NORMAL_CLOSE);
5968 if (!NT_STATUS_IS_OK(status)) {
5969 reply_nterror(req, status);
5970 } else {
5971 reply_outbuf(req, 0, 0);
5974 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5976 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5977 out:
5978 TALLOC_FREE(smb_dname);
5979 END_PROFILE(SMBrmdir);
5980 return;
5983 /*******************************************************************
5984 Resolve wildcards in a filename rename.
5985 ********************************************************************/
5987 static bool resolve_wildcards(TALLOC_CTX *ctx,
5988 const char *name1,
5989 const char *name2,
5990 char **pp_newname)
5992 char *name2_copy = NULL;
5993 char *root1 = NULL;
5994 char *root2 = NULL;
5995 char *ext1 = NULL;
5996 char *ext2 = NULL;
5997 char *p,*p2, *pname1, *pname2;
5999 name2_copy = talloc_strdup(ctx, name2);
6000 if (!name2_copy) {
6001 return False;
6004 pname1 = strrchr_m(name1,'/');
6005 pname2 = strrchr_m(name2_copy,'/');
6007 if (!pname1 || !pname2) {
6008 return False;
6011 /* Truncate the copy of name2 at the last '/' */
6012 *pname2 = '\0';
6014 /* Now go past the '/' */
6015 pname1++;
6016 pname2++;
6018 root1 = talloc_strdup(ctx, pname1);
6019 root2 = talloc_strdup(ctx, pname2);
6021 if (!root1 || !root2) {
6022 return False;
6025 p = strrchr_m(root1,'.');
6026 if (p) {
6027 *p = 0;
6028 ext1 = talloc_strdup(ctx, p+1);
6029 } else {
6030 ext1 = talloc_strdup(ctx, "");
6032 p = strrchr_m(root2,'.');
6033 if (p) {
6034 *p = 0;
6035 ext2 = talloc_strdup(ctx, p+1);
6036 } else {
6037 ext2 = talloc_strdup(ctx, "");
6040 if (!ext1 || !ext2) {
6041 return False;
6044 p = root1;
6045 p2 = root2;
6046 while (*p2) {
6047 if (*p2 == '?') {
6048 /* Hmmm. Should this be mb-aware ? */
6049 *p2 = *p;
6050 p2++;
6051 } else if (*p2 == '*') {
6052 *p2 = '\0';
6053 root2 = talloc_asprintf(ctx, "%s%s",
6054 root2,
6056 if (!root2) {
6057 return False;
6059 break;
6060 } else {
6061 p2++;
6063 if (*p) {
6064 p++;
6068 p = ext1;
6069 p2 = ext2;
6070 while (*p2) {
6071 if (*p2 == '?') {
6072 /* Hmmm. Should this be mb-aware ? */
6073 *p2 = *p;
6074 p2++;
6075 } else if (*p2 == '*') {
6076 *p2 = '\0';
6077 ext2 = talloc_asprintf(ctx, "%s%s",
6078 ext2,
6080 if (!ext2) {
6081 return False;
6083 break;
6084 } else {
6085 p2++;
6087 if (*p) {
6088 p++;
6092 if (*ext2) {
6093 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6094 name2_copy,
6095 root2,
6096 ext2);
6097 } else {
6098 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6099 name2_copy,
6100 root2);
6103 if (!*pp_newname) {
6104 return False;
6107 return True;
6110 /****************************************************************************
6111 Ensure open files have their names updated. Updated to notify other smbd's
6112 asynchronously.
6113 ****************************************************************************/
6115 static void rename_open_files(connection_struct *conn,
6116 struct share_mode_lock *lck,
6117 struct file_id id,
6118 uint32_t orig_name_hash,
6119 const struct smb_filename *smb_fname_dst)
6121 files_struct *fsp;
6122 bool did_rename = False;
6123 NTSTATUS status;
6124 uint32_t new_name_hash = 0;
6126 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6127 fsp = file_find_di_next(fsp)) {
6128 /* fsp_name is a relative path under the fsp. To change this for other
6129 sharepaths we need to manipulate relative paths. */
6130 /* TODO - create the absolute path and manipulate the newname
6131 relative to the sharepath. */
6132 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6133 continue;
6135 if (fsp->name_hash != orig_name_hash) {
6136 continue;
6138 DEBUG(10, ("rename_open_files: renaming file %s "
6139 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6140 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6141 smb_fname_str_dbg(smb_fname_dst)));
6143 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6144 if (NT_STATUS_IS_OK(status)) {
6145 did_rename = True;
6146 new_name_hash = fsp->name_hash;
6150 if (!did_rename) {
6151 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6152 "for %s\n", file_id_string_tos(&id),
6153 smb_fname_str_dbg(smb_fname_dst)));
6156 /* Send messages to all smbd's (not ourself) that the name has changed. */
6157 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6158 orig_name_hash, new_name_hash,
6159 smb_fname_dst);
6163 /****************************************************************************
6164 We need to check if the source path is a parent directory of the destination
6165 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6166 refuse the rename with a sharing violation. Under UNIX the above call can
6167 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6168 probably need to check that the client is a Windows one before disallowing
6169 this as a UNIX client (one with UNIX extensions) can know the source is a
6170 symlink and make this decision intelligently. Found by an excellent bug
6171 report from <AndyLiebman@aol.com>.
6172 ****************************************************************************/
6174 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6175 const struct smb_filename *smb_fname_dst)
6177 const char *psrc = smb_fname_src->base_name;
6178 const char *pdst = smb_fname_dst->base_name;
6179 size_t slen;
6181 if (psrc[0] == '.' && psrc[1] == '/') {
6182 psrc += 2;
6184 if (pdst[0] == '.' && pdst[1] == '/') {
6185 pdst += 2;
6187 if ((slen = strlen(psrc)) > strlen(pdst)) {
6188 return False;
6190 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6194 * Do the notify calls from a rename
6197 static void notify_rename(connection_struct *conn, bool is_dir,
6198 const struct smb_filename *smb_fname_src,
6199 const struct smb_filename *smb_fname_dst)
6201 char *parent_dir_src = NULL;
6202 char *parent_dir_dst = NULL;
6203 uint32 mask;
6205 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6206 : FILE_NOTIFY_CHANGE_FILE_NAME;
6208 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6209 &parent_dir_src, NULL) ||
6210 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6211 &parent_dir_dst, NULL)) {
6212 goto out;
6215 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6216 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6217 smb_fname_src->base_name);
6218 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6219 smb_fname_dst->base_name);
6221 else {
6222 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6223 smb_fname_src->base_name);
6224 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6225 smb_fname_dst->base_name);
6228 /* this is a strange one. w2k3 gives an additional event for
6229 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6230 files, but not directories */
6231 if (!is_dir) {
6232 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6233 FILE_NOTIFY_CHANGE_ATTRIBUTES
6234 |FILE_NOTIFY_CHANGE_CREATION,
6235 smb_fname_dst->base_name);
6237 out:
6238 TALLOC_FREE(parent_dir_src);
6239 TALLOC_FREE(parent_dir_dst);
6242 /****************************************************************************
6243 Returns an error if the parent directory for a filename is open in an
6244 incompatible way.
6245 ****************************************************************************/
6247 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6248 const struct smb_filename *smb_fname_dst_in)
6250 char *parent_dir = NULL;
6251 struct smb_filename smb_fname_parent;
6252 struct file_id id;
6253 files_struct *fsp = NULL;
6254 int ret;
6256 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6257 &parent_dir, NULL)) {
6258 return NT_STATUS_NO_MEMORY;
6260 ZERO_STRUCT(smb_fname_parent);
6261 smb_fname_parent.base_name = parent_dir;
6263 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6264 if (ret == -1) {
6265 return map_nt_error_from_unix(errno);
6269 * We're only checking on this smbd here, mostly good
6270 * enough.. and will pass tests.
6273 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6274 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6275 fsp = file_find_di_next(fsp)) {
6276 if (fsp->access_mask & DELETE_ACCESS) {
6277 return NT_STATUS_SHARING_VIOLATION;
6280 return NT_STATUS_OK;
6283 /****************************************************************************
6284 Rename an open file - given an fsp.
6285 ****************************************************************************/
6287 NTSTATUS rename_internals_fsp(connection_struct *conn,
6288 files_struct *fsp,
6289 const struct smb_filename *smb_fname_dst_in,
6290 uint32 attrs,
6291 bool replace_if_exists)
6293 TALLOC_CTX *ctx = talloc_tos();
6294 struct smb_filename *smb_fname_dst = NULL;
6295 NTSTATUS status = NT_STATUS_OK;
6296 struct share_mode_lock *lck = NULL;
6297 bool dst_exists, old_is_stream, new_is_stream;
6299 status = check_name(conn, smb_fname_dst_in->base_name);
6300 if (!NT_STATUS_IS_OK(status)) {
6301 return status;
6304 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6305 if (!NT_STATUS_IS_OK(status)) {
6306 return status;
6309 /* Make a copy of the dst smb_fname structs */
6311 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6312 if (smb_fname_dst == NULL) {
6313 status = NT_STATUS_NO_MEMORY;
6314 goto out;
6318 * Check for special case with case preserving and not
6319 * case sensitive. If the old last component differs from the original
6320 * last component only by case, then we should allow
6321 * the rename (user is trying to change the case of the
6322 * filename).
6324 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6325 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6326 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6327 char *last_slash;
6328 char *fname_dst_lcomp_base_mod = NULL;
6329 struct smb_filename *smb_fname_orig_lcomp = NULL;
6332 * Get the last component of the destination name.
6334 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6335 if (last_slash) {
6336 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6337 } else {
6338 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6340 if (!fname_dst_lcomp_base_mod) {
6341 status = NT_STATUS_NO_MEMORY;
6342 goto out;
6346 * Create an smb_filename struct using the original last
6347 * component of the destination.
6349 smb_fname_orig_lcomp = synthetic_smb_fname_split(
6350 ctx, smb_fname_dst->original_lcomp, NULL);
6351 if (smb_fname_orig_lcomp == NULL) {
6352 status = NT_STATUS_NO_MEMORY;
6353 TALLOC_FREE(fname_dst_lcomp_base_mod);
6354 goto out;
6357 /* If the base names only differ by case, use original. */
6358 if(!strcsequal(fname_dst_lcomp_base_mod,
6359 smb_fname_orig_lcomp->base_name)) {
6360 char *tmp;
6362 * Replace the modified last component with the
6363 * original.
6365 if (last_slash) {
6366 *last_slash = '\0'; /* Truncate at the '/' */
6367 tmp = talloc_asprintf(smb_fname_dst,
6368 "%s/%s",
6369 smb_fname_dst->base_name,
6370 smb_fname_orig_lcomp->base_name);
6371 } else {
6372 tmp = talloc_asprintf(smb_fname_dst,
6373 "%s",
6374 smb_fname_orig_lcomp->base_name);
6376 if (tmp == NULL) {
6377 status = NT_STATUS_NO_MEMORY;
6378 TALLOC_FREE(fname_dst_lcomp_base_mod);
6379 TALLOC_FREE(smb_fname_orig_lcomp);
6380 goto out;
6382 TALLOC_FREE(smb_fname_dst->base_name);
6383 smb_fname_dst->base_name = tmp;
6386 /* If the stream_names only differ by case, use original. */
6387 if(!strcsequal(smb_fname_dst->stream_name,
6388 smb_fname_orig_lcomp->stream_name)) {
6389 char *tmp = NULL;
6390 /* Use the original stream. */
6391 tmp = talloc_strdup(smb_fname_dst,
6392 smb_fname_orig_lcomp->stream_name);
6393 if (tmp == NULL) {
6394 status = NT_STATUS_NO_MEMORY;
6395 TALLOC_FREE(fname_dst_lcomp_base_mod);
6396 TALLOC_FREE(smb_fname_orig_lcomp);
6397 goto out;
6399 TALLOC_FREE(smb_fname_dst->stream_name);
6400 smb_fname_dst->stream_name = tmp;
6402 TALLOC_FREE(fname_dst_lcomp_base_mod);
6403 TALLOC_FREE(smb_fname_orig_lcomp);
6407 * If the src and dest names are identical - including case,
6408 * don't do the rename, just return success.
6411 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6412 strcsequal(fsp->fsp_name->stream_name,
6413 smb_fname_dst->stream_name)) {
6414 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6415 "- returning success\n",
6416 smb_fname_str_dbg(smb_fname_dst)));
6417 status = NT_STATUS_OK;
6418 goto out;
6421 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6422 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6424 /* Return the correct error code if both names aren't streams. */
6425 if (!old_is_stream && new_is_stream) {
6426 status = NT_STATUS_OBJECT_NAME_INVALID;
6427 goto out;
6430 if (old_is_stream && !new_is_stream) {
6431 status = NT_STATUS_INVALID_PARAMETER;
6432 goto out;
6435 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6437 if(!replace_if_exists && dst_exists) {
6438 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6439 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6440 smb_fname_str_dbg(smb_fname_dst)));
6441 status = NT_STATUS_OBJECT_NAME_COLLISION;
6442 goto out;
6445 if (dst_exists) {
6446 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6447 &smb_fname_dst->st);
6448 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6449 fileid);
6450 /* The file can be open when renaming a stream */
6451 if (dst_fsp && !new_is_stream) {
6452 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6453 status = NT_STATUS_ACCESS_DENIED;
6454 goto out;
6458 /* Ensure we have a valid stat struct for the source. */
6459 status = vfs_stat_fsp(fsp);
6460 if (!NT_STATUS_IS_OK(status)) {
6461 goto out;
6464 status = can_rename(conn, fsp, attrs);
6466 if (!NT_STATUS_IS_OK(status)) {
6467 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6468 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6469 smb_fname_str_dbg(smb_fname_dst)));
6470 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6471 status = NT_STATUS_ACCESS_DENIED;
6472 goto out;
6475 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6476 status = NT_STATUS_ACCESS_DENIED;
6479 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6482 * We have the file open ourselves, so not being able to get the
6483 * corresponding share mode lock is a fatal error.
6486 SMB_ASSERT(lck != NULL);
6488 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6489 uint32 create_options = fsp->fh->private_options;
6491 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6492 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6493 smb_fname_str_dbg(smb_fname_dst)));
6495 if (!fsp->is_directory &&
6496 !lp_posix_pathnames() &&
6497 (lp_map_archive(SNUM(conn)) ||
6498 lp_store_dos_attributes(SNUM(conn)))) {
6499 /* We must set the archive bit on the newly
6500 renamed file. */
6501 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6502 uint32_t old_dosmode = dos_mode(conn,
6503 smb_fname_dst);
6504 file_set_dosmode(conn,
6505 smb_fname_dst,
6506 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6507 NULL,
6508 true);
6512 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6513 smb_fname_dst);
6515 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6516 smb_fname_dst);
6519 * A rename acts as a new file create w.r.t. allowing an initial delete
6520 * on close, probably because in Windows there is a new handle to the
6521 * new file. If initial delete on close was requested but not
6522 * originally set, we need to set it here. This is probably not 100% correct,
6523 * but will work for the CIFSFS client which in non-posix mode
6524 * depends on these semantics. JRA.
6527 if (create_options & FILE_DELETE_ON_CLOSE) {
6528 status = can_set_delete_on_close(fsp, 0);
6530 if (NT_STATUS_IS_OK(status)) {
6531 /* Note that here we set the *inital* delete on close flag,
6532 * not the regular one. The magic gets handled in close. */
6533 fsp->initial_delete_on_close = True;
6536 TALLOC_FREE(lck);
6537 status = NT_STATUS_OK;
6538 goto out;
6541 TALLOC_FREE(lck);
6543 if (errno == ENOTDIR || errno == EISDIR) {
6544 status = NT_STATUS_OBJECT_NAME_COLLISION;
6545 } else {
6546 status = map_nt_error_from_unix(errno);
6549 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6550 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6551 smb_fname_str_dbg(smb_fname_dst)));
6553 out:
6554 TALLOC_FREE(smb_fname_dst);
6556 return status;
6559 /****************************************************************************
6560 The guts of the rename command, split out so it may be called by the NT SMB
6561 code.
6562 ****************************************************************************/
6564 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6565 connection_struct *conn,
6566 struct smb_request *req,
6567 struct smb_filename *smb_fname_src,
6568 struct smb_filename *smb_fname_dst,
6569 uint32 attrs,
6570 bool replace_if_exists,
6571 bool src_has_wild,
6572 bool dest_has_wild,
6573 uint32_t access_mask)
6575 char *fname_src_dir = NULL;
6576 char *fname_src_mask = NULL;
6577 int count=0;
6578 NTSTATUS status = NT_STATUS_OK;
6579 struct smb_Dir *dir_hnd = NULL;
6580 const char *dname = NULL;
6581 char *talloced = NULL;
6582 long offset = 0;
6583 int create_options = 0;
6584 bool posix_pathnames = lp_posix_pathnames();
6585 int rc;
6588 * Split the old name into directory and last component
6589 * strings. Note that unix_convert may have stripped off a
6590 * leading ./ from both name and newname if the rename is
6591 * at the root of the share. We need to make sure either both
6592 * name and newname contain a / character or neither of them do
6593 * as this is checked in resolve_wildcards().
6596 /* Split up the directory from the filename/mask. */
6597 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6598 &fname_src_dir, &fname_src_mask);
6599 if (!NT_STATUS_IS_OK(status)) {
6600 status = NT_STATUS_NO_MEMORY;
6601 goto out;
6605 * We should only check the mangled cache
6606 * here if unix_convert failed. This means
6607 * that the path in 'mask' doesn't exist
6608 * on the file system and so we need to look
6609 * for a possible mangle. This patch from
6610 * Tine Smukavec <valentin.smukavec@hermes.si>.
6613 if (!VALID_STAT(smb_fname_src->st) &&
6614 mangle_is_mangled(fname_src_mask, conn->params)) {
6615 char *new_mask = NULL;
6616 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6617 conn->params);
6618 if (new_mask) {
6619 TALLOC_FREE(fname_src_mask);
6620 fname_src_mask = new_mask;
6624 if (!src_has_wild) {
6625 files_struct *fsp;
6628 * Only one file needs to be renamed. Append the mask back
6629 * onto the directory.
6631 TALLOC_FREE(smb_fname_src->base_name);
6632 if (ISDOT(fname_src_dir)) {
6633 /* Ensure we use canonical names on open. */
6634 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6635 "%s",
6636 fname_src_mask);
6637 } else {
6638 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6639 "%s/%s",
6640 fname_src_dir,
6641 fname_src_mask);
6643 if (!smb_fname_src->base_name) {
6644 status = NT_STATUS_NO_MEMORY;
6645 goto out;
6648 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6649 "case_preserve = %d, short case preserve = %d, "
6650 "directory = %s, newname = %s, "
6651 "last_component_dest = %s\n",
6652 conn->case_sensitive, conn->case_preserve,
6653 conn->short_case_preserve,
6654 smb_fname_str_dbg(smb_fname_src),
6655 smb_fname_str_dbg(smb_fname_dst),
6656 smb_fname_dst->original_lcomp));
6658 /* The dest name still may have wildcards. */
6659 if (dest_has_wild) {
6660 char *fname_dst_mod = NULL;
6661 if (!resolve_wildcards(smb_fname_dst,
6662 smb_fname_src->base_name,
6663 smb_fname_dst->base_name,
6664 &fname_dst_mod)) {
6665 DEBUG(6, ("rename_internals: resolve_wildcards "
6666 "%s %s failed\n",
6667 smb_fname_src->base_name,
6668 smb_fname_dst->base_name));
6669 status = NT_STATUS_NO_MEMORY;
6670 goto out;
6672 TALLOC_FREE(smb_fname_dst->base_name);
6673 smb_fname_dst->base_name = fname_dst_mod;
6676 ZERO_STRUCT(smb_fname_src->st);
6677 if (posix_pathnames) {
6678 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6679 } else {
6680 rc = SMB_VFS_STAT(conn, smb_fname_src);
6682 if (rc == -1) {
6683 status = map_nt_error_from_unix_common(errno);
6684 goto out;
6687 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6688 create_options |= FILE_DIRECTORY_FILE;
6691 status = SMB_VFS_CREATE_FILE(
6692 conn, /* conn */
6693 req, /* req */
6694 0, /* root_dir_fid */
6695 smb_fname_src, /* fname */
6696 access_mask, /* access_mask */
6697 (FILE_SHARE_READ | /* share_access */
6698 FILE_SHARE_WRITE),
6699 FILE_OPEN, /* create_disposition*/
6700 create_options, /* create_options */
6701 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6702 0, /* oplock_request */
6703 0, /* allocation_size */
6704 0, /* private_flags */
6705 NULL, /* sd */
6706 NULL, /* ea_list */
6707 &fsp, /* result */
6708 NULL); /* pinfo */
6710 if (!NT_STATUS_IS_OK(status)) {
6711 DEBUG(3, ("Could not open rename source %s: %s\n",
6712 smb_fname_str_dbg(smb_fname_src),
6713 nt_errstr(status)));
6714 goto out;
6717 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6718 attrs, replace_if_exists);
6720 close_file(req, fsp, NORMAL_CLOSE);
6722 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6723 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6724 smb_fname_str_dbg(smb_fname_dst)));
6726 goto out;
6730 * Wildcards - process each file that matches.
6732 if (strequal(fname_src_mask, "????????.???")) {
6733 TALLOC_FREE(fname_src_mask);
6734 fname_src_mask = talloc_strdup(ctx, "*");
6735 if (!fname_src_mask) {
6736 status = NT_STATUS_NO_MEMORY;
6737 goto out;
6741 status = check_name(conn, fname_src_dir);
6742 if (!NT_STATUS_IS_OK(status)) {
6743 goto out;
6746 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6747 attrs);
6748 if (dir_hnd == NULL) {
6749 status = map_nt_error_from_unix(errno);
6750 goto out;
6753 status = NT_STATUS_NO_SUCH_FILE;
6755 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6756 * - gentest fix. JRA
6759 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6760 &talloced))) {
6761 files_struct *fsp = NULL;
6762 char *destname = NULL;
6763 bool sysdir_entry = False;
6765 /* Quick check for "." and ".." */
6766 if (ISDOT(dname) || ISDOTDOT(dname)) {
6767 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6768 sysdir_entry = True;
6769 } else {
6770 TALLOC_FREE(talloced);
6771 continue;
6775 if (!is_visible_file(conn, fname_src_dir, dname,
6776 &smb_fname_src->st, false)) {
6777 TALLOC_FREE(talloced);
6778 continue;
6781 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6782 TALLOC_FREE(talloced);
6783 continue;
6786 if (sysdir_entry) {
6787 status = NT_STATUS_OBJECT_NAME_INVALID;
6788 break;
6791 TALLOC_FREE(smb_fname_src->base_name);
6792 if (ISDOT(fname_src_dir)) {
6793 /* Ensure we use canonical names on open. */
6794 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6795 "%s",
6796 dname);
6797 } else {
6798 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6799 "%s/%s",
6800 fname_src_dir,
6801 dname);
6803 if (!smb_fname_src->base_name) {
6804 status = NT_STATUS_NO_MEMORY;
6805 goto out;
6808 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6809 smb_fname_dst->base_name,
6810 &destname)) {
6811 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6812 smb_fname_src->base_name, destname));
6813 TALLOC_FREE(talloced);
6814 continue;
6816 if (!destname) {
6817 status = NT_STATUS_NO_MEMORY;
6818 goto out;
6821 TALLOC_FREE(smb_fname_dst->base_name);
6822 smb_fname_dst->base_name = destname;
6824 ZERO_STRUCT(smb_fname_src->st);
6825 if (posix_pathnames) {
6826 SMB_VFS_LSTAT(conn, smb_fname_src);
6827 } else {
6828 SMB_VFS_STAT(conn, smb_fname_src);
6831 create_options = 0;
6833 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6834 create_options |= FILE_DIRECTORY_FILE;
6837 status = SMB_VFS_CREATE_FILE(
6838 conn, /* conn */
6839 req, /* req */
6840 0, /* root_dir_fid */
6841 smb_fname_src, /* fname */
6842 access_mask, /* access_mask */
6843 (FILE_SHARE_READ | /* share_access */
6844 FILE_SHARE_WRITE),
6845 FILE_OPEN, /* create_disposition*/
6846 create_options, /* create_options */
6847 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6848 0, /* oplock_request */
6849 0, /* allocation_size */
6850 0, /* private_flags */
6851 NULL, /* sd */
6852 NULL, /* ea_list */
6853 &fsp, /* result */
6854 NULL); /* pinfo */
6856 if (!NT_STATUS_IS_OK(status)) {
6857 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6858 "returned %s rename %s -> %s\n",
6859 nt_errstr(status),
6860 smb_fname_str_dbg(smb_fname_src),
6861 smb_fname_str_dbg(smb_fname_dst)));
6862 break;
6865 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6866 dname);
6867 if (!smb_fname_dst->original_lcomp) {
6868 status = NT_STATUS_NO_MEMORY;
6869 goto out;
6872 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6873 attrs, replace_if_exists);
6875 close_file(req, fsp, NORMAL_CLOSE);
6877 if (!NT_STATUS_IS_OK(status)) {
6878 DEBUG(3, ("rename_internals_fsp returned %s for "
6879 "rename %s -> %s\n", nt_errstr(status),
6880 smb_fname_str_dbg(smb_fname_src),
6881 smb_fname_str_dbg(smb_fname_dst)));
6882 break;
6885 count++;
6887 DEBUG(3,("rename_internals: doing rename on %s -> "
6888 "%s\n", smb_fname_str_dbg(smb_fname_src),
6889 smb_fname_str_dbg(smb_fname_src)));
6890 TALLOC_FREE(talloced);
6892 TALLOC_FREE(dir_hnd);
6894 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6895 status = map_nt_error_from_unix(errno);
6898 out:
6899 TALLOC_FREE(talloced);
6900 TALLOC_FREE(fname_src_dir);
6901 TALLOC_FREE(fname_src_mask);
6902 return status;
6905 /****************************************************************************
6906 Reply to a mv.
6907 ****************************************************************************/
6909 void reply_mv(struct smb_request *req)
6911 connection_struct *conn = req->conn;
6912 char *name = NULL;
6913 char *newname = NULL;
6914 const char *p;
6915 uint32 attrs;
6916 NTSTATUS status;
6917 bool src_has_wcard = False;
6918 bool dest_has_wcard = False;
6919 TALLOC_CTX *ctx = talloc_tos();
6920 struct smb_filename *smb_fname_src = NULL;
6921 struct smb_filename *smb_fname_dst = NULL;
6922 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6923 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6924 bool stream_rename = false;
6926 START_PROFILE(SMBmv);
6928 if (req->wct < 1) {
6929 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6930 goto out;
6933 attrs = SVAL(req->vwv+0, 0);
6935 p = (const char *)req->buf + 1;
6936 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6937 &status, &src_has_wcard);
6938 if (!NT_STATUS_IS_OK(status)) {
6939 reply_nterror(req, status);
6940 goto out;
6942 p++;
6943 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6944 &status, &dest_has_wcard);
6945 if (!NT_STATUS_IS_OK(status)) {
6946 reply_nterror(req, status);
6947 goto out;
6950 if (!lp_posix_pathnames()) {
6951 /* The newname must begin with a ':' if the
6952 name contains a ':'. */
6953 if (strchr_m(name, ':')) {
6954 if (newname[0] != ':') {
6955 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6956 goto out;
6958 stream_rename = true;
6962 status = filename_convert(ctx,
6963 conn,
6964 req->flags2 & FLAGS2_DFS_PATHNAMES,
6965 name,
6966 src_ucf_flags,
6967 &src_has_wcard,
6968 &smb_fname_src);
6970 if (!NT_STATUS_IS_OK(status)) {
6971 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6972 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6973 ERRSRV, ERRbadpath);
6974 goto out;
6976 reply_nterror(req, status);
6977 goto out;
6980 status = filename_convert(ctx,
6981 conn,
6982 req->flags2 & FLAGS2_DFS_PATHNAMES,
6983 newname,
6984 dst_ucf_flags,
6985 &dest_has_wcard,
6986 &smb_fname_dst);
6988 if (!NT_STATUS_IS_OK(status)) {
6989 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6990 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6991 ERRSRV, ERRbadpath);
6992 goto out;
6994 reply_nterror(req, status);
6995 goto out;
6998 if (stream_rename) {
6999 /* smb_fname_dst->base_name must be the same as
7000 smb_fname_src->base_name. */
7001 TALLOC_FREE(smb_fname_dst->base_name);
7002 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7003 smb_fname_src->base_name);
7004 if (!smb_fname_dst->base_name) {
7005 reply_nterror(req, NT_STATUS_NO_MEMORY);
7006 goto out;
7010 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7011 smb_fname_str_dbg(smb_fname_dst)));
7013 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7014 attrs, False, src_has_wcard, dest_has_wcard,
7015 DELETE_ACCESS);
7016 if (!NT_STATUS_IS_OK(status)) {
7017 if (open_was_deferred(req->sconn, req->mid)) {
7018 /* We have re-scheduled this call. */
7019 goto out;
7021 reply_nterror(req, status);
7022 goto out;
7025 reply_outbuf(req, 0, 0);
7026 out:
7027 TALLOC_FREE(smb_fname_src);
7028 TALLOC_FREE(smb_fname_dst);
7029 END_PROFILE(SMBmv);
7030 return;
7033 /*******************************************************************
7034 Copy a file as part of a reply_copy.
7035 ******************************************************************/
7038 * TODO: check error codes on all callers
7041 NTSTATUS copy_file(TALLOC_CTX *ctx,
7042 connection_struct *conn,
7043 struct smb_filename *smb_fname_src,
7044 struct smb_filename *smb_fname_dst,
7045 int ofun,
7046 int count,
7047 bool target_is_directory)
7049 struct smb_filename *smb_fname_dst_tmp = NULL;
7050 off_t ret=-1;
7051 files_struct *fsp1,*fsp2;
7052 uint32 dosattrs;
7053 uint32 new_create_disposition;
7054 NTSTATUS status;
7057 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7058 if (smb_fname_dst_tmp == NULL) {
7059 return NT_STATUS_NO_MEMORY;
7063 * If the target is a directory, extract the last component from the
7064 * src filename and append it to the dst filename
7066 if (target_is_directory) {
7067 const char *p;
7069 /* dest/target can't be a stream if it's a directory. */
7070 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7072 p = strrchr_m(smb_fname_src->base_name,'/');
7073 if (p) {
7074 p++;
7075 } else {
7076 p = smb_fname_src->base_name;
7078 smb_fname_dst_tmp->base_name =
7079 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7081 if (!smb_fname_dst_tmp->base_name) {
7082 status = NT_STATUS_NO_MEMORY;
7083 goto out;
7087 status = vfs_file_exist(conn, smb_fname_src);
7088 if (!NT_STATUS_IS_OK(status)) {
7089 goto out;
7092 if (!target_is_directory && count) {
7093 new_create_disposition = FILE_OPEN;
7094 } else {
7095 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7096 0, ofun,
7097 NULL, NULL,
7098 &new_create_disposition,
7099 NULL,
7100 NULL)) {
7101 status = NT_STATUS_INVALID_PARAMETER;
7102 goto out;
7106 /* Open the src file for reading. */
7107 status = SMB_VFS_CREATE_FILE(
7108 conn, /* conn */
7109 NULL, /* req */
7110 0, /* root_dir_fid */
7111 smb_fname_src, /* fname */
7112 FILE_GENERIC_READ, /* access_mask */
7113 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7114 FILE_OPEN, /* create_disposition*/
7115 0, /* create_options */
7116 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7117 INTERNAL_OPEN_ONLY, /* oplock_request */
7118 0, /* allocation_size */
7119 0, /* private_flags */
7120 NULL, /* sd */
7121 NULL, /* ea_list */
7122 &fsp1, /* result */
7123 NULL); /* psbuf */
7125 if (!NT_STATUS_IS_OK(status)) {
7126 goto out;
7129 dosattrs = dos_mode(conn, smb_fname_src);
7131 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7132 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7135 /* Open the dst file for writing. */
7136 status = SMB_VFS_CREATE_FILE(
7137 conn, /* conn */
7138 NULL, /* req */
7139 0, /* root_dir_fid */
7140 smb_fname_dst, /* fname */
7141 FILE_GENERIC_WRITE, /* access_mask */
7142 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7143 new_create_disposition, /* create_disposition*/
7144 0, /* create_options */
7145 dosattrs, /* file_attributes */
7146 INTERNAL_OPEN_ONLY, /* oplock_request */
7147 0, /* allocation_size */
7148 0, /* private_flags */
7149 NULL, /* sd */
7150 NULL, /* ea_list */
7151 &fsp2, /* result */
7152 NULL); /* psbuf */
7154 if (!NT_STATUS_IS_OK(status)) {
7155 close_file(NULL, fsp1, ERROR_CLOSE);
7156 goto out;
7159 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7160 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7161 if (ret == -1) {
7162 DEBUG(0, ("error - vfs lseek returned error %s\n",
7163 strerror(errno)));
7164 status = map_nt_error_from_unix(errno);
7165 close_file(NULL, fsp1, ERROR_CLOSE);
7166 close_file(NULL, fsp2, ERROR_CLOSE);
7167 goto out;
7171 /* Do the actual copy. */
7172 if (smb_fname_src->st.st_ex_size) {
7173 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7174 } else {
7175 ret = 0;
7178 close_file(NULL, fsp1, NORMAL_CLOSE);
7180 /* Ensure the modtime is set correctly on the destination file. */
7181 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7184 * As we are opening fsp1 read-only we only expect
7185 * an error on close on fsp2 if we are out of space.
7186 * Thus we don't look at the error return from the
7187 * close of fsp1.
7189 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7191 if (!NT_STATUS_IS_OK(status)) {
7192 goto out;
7195 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7196 status = NT_STATUS_DISK_FULL;
7197 goto out;
7200 status = NT_STATUS_OK;
7202 out:
7203 TALLOC_FREE(smb_fname_dst_tmp);
7204 return status;
7207 /****************************************************************************
7208 Reply to a file copy.
7209 ****************************************************************************/
7211 void reply_copy(struct smb_request *req)
7213 connection_struct *conn = req->conn;
7214 struct smb_filename *smb_fname_src = NULL;
7215 struct smb_filename *smb_fname_dst = NULL;
7216 char *fname_src = NULL;
7217 char *fname_dst = NULL;
7218 char *fname_src_mask = NULL;
7219 char *fname_src_dir = NULL;
7220 const char *p;
7221 int count=0;
7222 int error = ERRnoaccess;
7223 int tid2;
7224 int ofun;
7225 int flags;
7226 bool target_is_directory=False;
7227 bool source_has_wild = False;
7228 bool dest_has_wild = False;
7229 NTSTATUS status;
7230 TALLOC_CTX *ctx = talloc_tos();
7232 START_PROFILE(SMBcopy);
7234 if (req->wct < 3) {
7235 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7236 goto out;
7239 tid2 = SVAL(req->vwv+0, 0);
7240 ofun = SVAL(req->vwv+1, 0);
7241 flags = SVAL(req->vwv+2, 0);
7243 p = (const char *)req->buf;
7244 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7245 &status, &source_has_wild);
7246 if (!NT_STATUS_IS_OK(status)) {
7247 reply_nterror(req, status);
7248 goto out;
7250 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7251 &status, &dest_has_wild);
7252 if (!NT_STATUS_IS_OK(status)) {
7253 reply_nterror(req, status);
7254 goto out;
7257 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7259 if (tid2 != conn->cnum) {
7260 /* can't currently handle inter share copies XXXX */
7261 DEBUG(3,("Rejecting inter-share copy\n"));
7262 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7263 goto out;
7266 status = filename_convert(ctx, conn,
7267 req->flags2 & FLAGS2_DFS_PATHNAMES,
7268 fname_src,
7269 UCF_COND_ALLOW_WCARD_LCOMP,
7270 &source_has_wild,
7271 &smb_fname_src);
7272 if (!NT_STATUS_IS_OK(status)) {
7273 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7274 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7275 ERRSRV, ERRbadpath);
7276 goto out;
7278 reply_nterror(req, status);
7279 goto out;
7282 status = filename_convert(ctx, conn,
7283 req->flags2 & FLAGS2_DFS_PATHNAMES,
7284 fname_dst,
7285 UCF_COND_ALLOW_WCARD_LCOMP,
7286 &dest_has_wild,
7287 &smb_fname_dst);
7288 if (!NT_STATUS_IS_OK(status)) {
7289 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7290 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7291 ERRSRV, ERRbadpath);
7292 goto out;
7294 reply_nterror(req, status);
7295 goto out;
7298 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7300 if ((flags&1) && target_is_directory) {
7301 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7302 goto out;
7305 if ((flags&2) && !target_is_directory) {
7306 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7307 goto out;
7310 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7311 /* wants a tree copy! XXXX */
7312 DEBUG(3,("Rejecting tree copy\n"));
7313 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7314 goto out;
7317 /* Split up the directory from the filename/mask. */
7318 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7319 &fname_src_dir, &fname_src_mask);
7320 if (!NT_STATUS_IS_OK(status)) {
7321 reply_nterror(req, NT_STATUS_NO_MEMORY);
7322 goto out;
7326 * We should only check the mangled cache
7327 * here if unix_convert failed. This means
7328 * that the path in 'mask' doesn't exist
7329 * on the file system and so we need to look
7330 * for a possible mangle. This patch from
7331 * Tine Smukavec <valentin.smukavec@hermes.si>.
7333 if (!VALID_STAT(smb_fname_src->st) &&
7334 mangle_is_mangled(fname_src_mask, conn->params)) {
7335 char *new_mask = NULL;
7336 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7337 &new_mask, conn->params);
7339 /* Use demangled name if one was successfully found. */
7340 if (new_mask) {
7341 TALLOC_FREE(fname_src_mask);
7342 fname_src_mask = new_mask;
7346 if (!source_has_wild) {
7349 * Only one file needs to be copied. Append the mask back onto
7350 * the directory.
7352 TALLOC_FREE(smb_fname_src->base_name);
7353 if (ISDOT(fname_src_dir)) {
7354 /* Ensure we use canonical names on open. */
7355 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7356 "%s",
7357 fname_src_mask);
7358 } else {
7359 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7360 "%s/%s",
7361 fname_src_dir,
7362 fname_src_mask);
7364 if (!smb_fname_src->base_name) {
7365 reply_nterror(req, NT_STATUS_NO_MEMORY);
7366 goto out;
7369 if (dest_has_wild) {
7370 char *fname_dst_mod = NULL;
7371 if (!resolve_wildcards(smb_fname_dst,
7372 smb_fname_src->base_name,
7373 smb_fname_dst->base_name,
7374 &fname_dst_mod)) {
7375 reply_nterror(req, NT_STATUS_NO_MEMORY);
7376 goto out;
7378 TALLOC_FREE(smb_fname_dst->base_name);
7379 smb_fname_dst->base_name = fname_dst_mod;
7382 status = check_name(conn, smb_fname_src->base_name);
7383 if (!NT_STATUS_IS_OK(status)) {
7384 reply_nterror(req, status);
7385 goto out;
7388 status = check_name(conn, smb_fname_dst->base_name);
7389 if (!NT_STATUS_IS_OK(status)) {
7390 reply_nterror(req, status);
7391 goto out;
7394 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7395 ofun, count, target_is_directory);
7397 if(!NT_STATUS_IS_OK(status)) {
7398 reply_nterror(req, status);
7399 goto out;
7400 } else {
7401 count++;
7403 } else {
7404 struct smb_Dir *dir_hnd = NULL;
7405 const char *dname = NULL;
7406 char *talloced = NULL;
7407 long offset = 0;
7410 * There is a wildcard that requires us to actually read the
7411 * src dir and copy each file matching the mask to the dst.
7412 * Right now streams won't be copied, but this could
7413 * presumably be added with a nested loop for reach dir entry.
7415 SMB_ASSERT(!smb_fname_src->stream_name);
7416 SMB_ASSERT(!smb_fname_dst->stream_name);
7418 smb_fname_src->stream_name = NULL;
7419 smb_fname_dst->stream_name = NULL;
7421 if (strequal(fname_src_mask,"????????.???")) {
7422 TALLOC_FREE(fname_src_mask);
7423 fname_src_mask = talloc_strdup(ctx, "*");
7424 if (!fname_src_mask) {
7425 reply_nterror(req, NT_STATUS_NO_MEMORY);
7426 goto out;
7430 status = check_name(conn, fname_src_dir);
7431 if (!NT_STATUS_IS_OK(status)) {
7432 reply_nterror(req, status);
7433 goto out;
7436 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7437 if (dir_hnd == NULL) {
7438 status = map_nt_error_from_unix(errno);
7439 reply_nterror(req, status);
7440 goto out;
7443 error = ERRbadfile;
7445 /* Iterate over the src dir copying each entry to the dst. */
7446 while ((dname = ReadDirName(dir_hnd, &offset,
7447 &smb_fname_src->st, &talloced))) {
7448 char *destname = NULL;
7450 if (ISDOT(dname) || ISDOTDOT(dname)) {
7451 TALLOC_FREE(talloced);
7452 continue;
7455 if (!is_visible_file(conn, fname_src_dir, dname,
7456 &smb_fname_src->st, false)) {
7457 TALLOC_FREE(talloced);
7458 continue;
7461 if(!mask_match(dname, fname_src_mask,
7462 conn->case_sensitive)) {
7463 TALLOC_FREE(talloced);
7464 continue;
7467 error = ERRnoaccess;
7469 /* Get the src smb_fname struct setup. */
7470 TALLOC_FREE(smb_fname_src->base_name);
7471 if (ISDOT(fname_src_dir)) {
7472 /* Ensure we use canonical names on open. */
7473 smb_fname_src->base_name =
7474 talloc_asprintf(smb_fname_src, "%s",
7475 dname);
7476 } else {
7477 smb_fname_src->base_name =
7478 talloc_asprintf(smb_fname_src, "%s/%s",
7479 fname_src_dir, dname);
7482 if (!smb_fname_src->base_name) {
7483 TALLOC_FREE(dir_hnd);
7484 TALLOC_FREE(talloced);
7485 reply_nterror(req, NT_STATUS_NO_MEMORY);
7486 goto out;
7489 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7490 smb_fname_dst->base_name,
7491 &destname)) {
7492 TALLOC_FREE(talloced);
7493 continue;
7495 if (!destname) {
7496 TALLOC_FREE(dir_hnd);
7497 TALLOC_FREE(talloced);
7498 reply_nterror(req, NT_STATUS_NO_MEMORY);
7499 goto out;
7502 TALLOC_FREE(smb_fname_dst->base_name);
7503 smb_fname_dst->base_name = destname;
7505 status = check_name(conn, smb_fname_src->base_name);
7506 if (!NT_STATUS_IS_OK(status)) {
7507 TALLOC_FREE(dir_hnd);
7508 TALLOC_FREE(talloced);
7509 reply_nterror(req, status);
7510 goto out;
7513 status = check_name(conn, smb_fname_dst->base_name);
7514 if (!NT_STATUS_IS_OK(status)) {
7515 TALLOC_FREE(dir_hnd);
7516 TALLOC_FREE(talloced);
7517 reply_nterror(req, status);
7518 goto out;
7521 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7522 smb_fname_src->base_name,
7523 smb_fname_dst->base_name));
7525 status = copy_file(ctx, conn, smb_fname_src,
7526 smb_fname_dst, ofun, count,
7527 target_is_directory);
7528 if (NT_STATUS_IS_OK(status)) {
7529 count++;
7532 TALLOC_FREE(talloced);
7534 TALLOC_FREE(dir_hnd);
7537 if (count == 0) {
7538 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7539 goto out;
7542 reply_outbuf(req, 1, 0);
7543 SSVAL(req->outbuf,smb_vwv0,count);
7544 out:
7545 TALLOC_FREE(smb_fname_src);
7546 TALLOC_FREE(smb_fname_dst);
7547 TALLOC_FREE(fname_src);
7548 TALLOC_FREE(fname_dst);
7549 TALLOC_FREE(fname_src_mask);
7550 TALLOC_FREE(fname_src_dir);
7552 END_PROFILE(SMBcopy);
7553 return;
7556 #undef DBGC_CLASS
7557 #define DBGC_CLASS DBGC_LOCKING
7559 /****************************************************************************
7560 Get a lock pid, dealing with large count requests.
7561 ****************************************************************************/
7563 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7564 bool large_file_format)
7566 if(!large_file_format)
7567 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7568 else
7569 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7572 /****************************************************************************
7573 Get a lock count, dealing with large count requests.
7574 ****************************************************************************/
7576 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7577 bool large_file_format)
7579 uint64_t count = 0;
7581 if(!large_file_format) {
7582 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7583 } else {
7585 #if defined(HAVE_LONGLONG)
7586 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7587 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7588 #else /* HAVE_LONGLONG */
7591 * NT4.x seems to be broken in that it sends large file (64 bit)
7592 * lockingX calls even if the CAP_LARGE_FILES was *not*
7593 * negotiated. For boxes without large unsigned ints truncate the
7594 * lock count by dropping the top 32 bits.
7597 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7598 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7599 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7600 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7601 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7604 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7605 #endif /* HAVE_LONGLONG */
7608 return count;
7611 #if !defined(HAVE_LONGLONG)
7612 /****************************************************************************
7613 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7614 ****************************************************************************/
7616 static uint32 map_lock_offset(uint32 high, uint32 low)
7618 unsigned int i;
7619 uint32 mask = 0;
7620 uint32 highcopy = high;
7623 * Try and find out how many significant bits there are in high.
7626 for(i = 0; highcopy; i++)
7627 highcopy >>= 1;
7630 * We use 31 bits not 32 here as POSIX
7631 * lock offsets may not be negative.
7634 mask = (~0) << (31 - i);
7636 if(low & mask)
7637 return 0; /* Fail. */
7639 high <<= (31 - i);
7641 return (high|low);
7643 #endif /* !defined(HAVE_LONGLONG) */
7645 /****************************************************************************
7646 Get a lock offset, dealing with large offset requests.
7647 ****************************************************************************/
7649 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7650 bool large_file_format, bool *err)
7652 uint64_t offset = 0;
7654 *err = False;
7656 if(!large_file_format) {
7657 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7658 } else {
7660 #if defined(HAVE_LONGLONG)
7661 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7662 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7663 #else /* HAVE_LONGLONG */
7666 * NT4.x seems to be broken in that it sends large file (64 bit)
7667 * lockingX calls even if the CAP_LARGE_FILES was *not*
7668 * negotiated. For boxes without large unsigned ints mangle the
7669 * lock offset by mapping the top 32 bits onto the lower 32.
7672 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7673 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7674 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7675 uint32 new_low = 0;
7677 if((new_low = map_lock_offset(high, low)) == 0) {
7678 *err = True;
7679 return (uint64_t)-1;
7682 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7683 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7684 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7685 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7688 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7689 #endif /* HAVE_LONGLONG */
7692 return offset;
7695 NTSTATUS smbd_do_locking(struct smb_request *req,
7696 files_struct *fsp,
7697 uint8_t type,
7698 int32_t timeout,
7699 uint16_t num_ulocks,
7700 struct smbd_lock_element *ulocks,
7701 uint16_t num_locks,
7702 struct smbd_lock_element *locks,
7703 bool *async)
7705 connection_struct *conn = req->conn;
7706 int i;
7707 NTSTATUS status = NT_STATUS_OK;
7709 *async = false;
7711 /* Data now points at the beginning of the list
7712 of smb_unlkrng structs */
7713 for(i = 0; i < (int)num_ulocks; i++) {
7714 struct smbd_lock_element *e = &ulocks[i];
7716 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7717 "pid %u, file %s\n",
7718 (double)e->offset,
7719 (double)e->count,
7720 (unsigned int)e->smblctx,
7721 fsp_str_dbg(fsp)));
7723 if (e->brltype != UNLOCK_LOCK) {
7724 /* this can only happen with SMB2 */
7725 return NT_STATUS_INVALID_PARAMETER;
7728 status = do_unlock(req->sconn->msg_ctx,
7729 fsp,
7730 e->smblctx,
7731 e->count,
7732 e->offset,
7733 WINDOWS_LOCK);
7735 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7736 nt_errstr(status)));
7738 if (!NT_STATUS_IS_OK(status)) {
7739 return status;
7743 /* Setup the timeout in seconds. */
7745 if (!lp_blocking_locks(SNUM(conn))) {
7746 timeout = 0;
7749 /* Data now points at the beginning of the list
7750 of smb_lkrng structs */
7752 for(i = 0; i < (int)num_locks; i++) {
7753 struct smbd_lock_element *e = &locks[i];
7755 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7756 "%llu, file %s timeout = %d\n",
7757 (double)e->offset,
7758 (double)e->count,
7759 (unsigned long long)e->smblctx,
7760 fsp_str_dbg(fsp),
7761 (int)timeout));
7763 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7764 struct blocking_lock_record *blr = NULL;
7766 if (num_locks > 1) {
7768 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7769 * if the lock vector contains one entry. When given mutliple cancel
7770 * requests in a single PDU we expect the server to return an
7771 * error. Windows servers seem to accept the request but only
7772 * cancel the first lock.
7773 * JRA - Do what Windows does (tm) :-).
7776 #if 0
7777 /* MS-CIFS (2.2.4.32.1) behavior. */
7778 return NT_STATUS_DOS(ERRDOS,
7779 ERRcancelviolation);
7780 #else
7781 /* Windows behavior. */
7782 if (i != 0) {
7783 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7784 "cancel request\n"));
7785 continue;
7787 #endif
7790 if (lp_blocking_locks(SNUM(conn))) {
7792 /* Schedule a message to ourselves to
7793 remove the blocking lock record and
7794 return the right error. */
7796 blr = blocking_lock_cancel_smb1(fsp,
7797 e->smblctx,
7798 e->offset,
7799 e->count,
7800 WINDOWS_LOCK,
7801 type,
7802 NT_STATUS_FILE_LOCK_CONFLICT);
7803 if (blr == NULL) {
7804 return NT_STATUS_DOS(
7805 ERRDOS,
7806 ERRcancelviolation);
7809 /* Remove a matching pending lock. */
7810 status = do_lock_cancel(fsp,
7811 e->smblctx,
7812 e->count,
7813 e->offset,
7814 WINDOWS_LOCK,
7815 blr);
7816 } else {
7817 bool blocking_lock = timeout ? true : false;
7818 bool defer_lock = false;
7819 struct byte_range_lock *br_lck;
7820 uint64_t block_smblctx;
7822 br_lck = do_lock(req->sconn->msg_ctx,
7823 fsp,
7824 e->smblctx,
7825 e->count,
7826 e->offset,
7827 e->brltype,
7828 WINDOWS_LOCK,
7829 blocking_lock,
7830 &status,
7831 &block_smblctx,
7832 NULL);
7834 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7835 /* Windows internal resolution for blocking locks seems
7836 to be about 200ms... Don't wait for less than that. JRA. */
7837 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7838 timeout = lp_lock_spin_time();
7840 defer_lock = true;
7843 /* If a lock sent with timeout of zero would fail, and
7844 * this lock has been requested multiple times,
7845 * according to brl_lock_failed() we convert this
7846 * request to a blocking lock with a timeout of between
7847 * 150 - 300 milliseconds.
7849 * If lp_lock_spin_time() has been set to 0, we skip
7850 * this blocking retry and fail immediately.
7852 * Replacement for do_lock_spin(). JRA. */
7854 if (!req->sconn->using_smb2 &&
7855 br_lck && lp_blocking_locks(SNUM(conn)) &&
7856 lp_lock_spin_time() && !blocking_lock &&
7857 NT_STATUS_EQUAL((status),
7858 NT_STATUS_FILE_LOCK_CONFLICT))
7860 defer_lock = true;
7861 timeout = lp_lock_spin_time();
7864 if (br_lck && defer_lock) {
7866 * A blocking lock was requested. Package up
7867 * this smb into a queued request and push it
7868 * onto the blocking lock queue.
7870 if(push_blocking_lock_request(br_lck,
7871 req,
7872 fsp,
7873 timeout,
7875 e->smblctx,
7876 e->brltype,
7877 WINDOWS_LOCK,
7878 e->offset,
7879 e->count,
7880 block_smblctx)) {
7881 TALLOC_FREE(br_lck);
7882 *async = true;
7883 return NT_STATUS_OK;
7887 TALLOC_FREE(br_lck);
7890 if (!NT_STATUS_IS_OK(status)) {
7891 break;
7895 /* If any of the above locks failed, then we must unlock
7896 all of the previous locks (X/Open spec). */
7898 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7900 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7901 i = -1; /* we want to skip the for loop */
7905 * Ensure we don't do a remove on the lock that just failed,
7906 * as under POSIX rules, if we have a lock already there, we
7907 * will delete it (and we shouldn't) .....
7909 for(i--; i >= 0; i--) {
7910 struct smbd_lock_element *e = &locks[i];
7912 do_unlock(req->sconn->msg_ctx,
7913 fsp,
7914 e->smblctx,
7915 e->count,
7916 e->offset,
7917 WINDOWS_LOCK);
7919 return status;
7922 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7923 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7925 return NT_STATUS_OK;
7928 /****************************************************************************
7929 Reply to a lockingX request.
7930 ****************************************************************************/
7932 void reply_lockingX(struct smb_request *req)
7934 connection_struct *conn = req->conn;
7935 files_struct *fsp;
7936 unsigned char locktype;
7937 unsigned char oplocklevel;
7938 uint16 num_ulocks;
7939 uint16 num_locks;
7940 int32 lock_timeout;
7941 int i;
7942 const uint8_t *data;
7943 bool large_file_format;
7944 bool err;
7945 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7946 struct smbd_lock_element *ulocks;
7947 struct smbd_lock_element *locks;
7948 bool async = false;
7950 START_PROFILE(SMBlockingX);
7952 if (req->wct < 8) {
7953 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7954 END_PROFILE(SMBlockingX);
7955 return;
7958 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7959 locktype = CVAL(req->vwv+3, 0);
7960 oplocklevel = CVAL(req->vwv+3, 1);
7961 num_ulocks = SVAL(req->vwv+6, 0);
7962 num_locks = SVAL(req->vwv+7, 0);
7963 lock_timeout = IVAL(req->vwv+4, 0);
7964 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7966 if (!check_fsp(conn, req, fsp)) {
7967 END_PROFILE(SMBlockingX);
7968 return;
7971 data = req->buf;
7973 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7974 /* we don't support these - and CANCEL_LOCK makes w2k
7975 and XP reboot so I don't really want to be
7976 compatible! (tridge) */
7977 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7978 END_PROFILE(SMBlockingX);
7979 return;
7982 /* Check if this is an oplock break on a file
7983 we have granted an oplock on.
7985 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7986 /* Client can insist on breaking to none. */
7987 bool break_to_none = (oplocklevel == 0);
7988 bool result;
7990 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7991 "for %s\n", (unsigned int)oplocklevel,
7992 fsp_fnum_dbg(fsp)));
7995 * Make sure we have granted an exclusive or batch oplock on
7996 * this file.
7999 if (fsp->oplock_type == 0) {
8001 /* The Samba4 nbench simulator doesn't understand
8002 the difference between break to level2 and break
8003 to none from level2 - it sends oplock break
8004 replies in both cases. Don't keep logging an error
8005 message here - just ignore it. JRA. */
8007 DEBUG(5,("reply_lockingX: Error : oplock break from "
8008 "client for %s (oplock=%d) and no "
8009 "oplock granted on this file (%s).\n",
8010 fsp_fnum_dbg(fsp), fsp->oplock_type,
8011 fsp_str_dbg(fsp)));
8013 /* if this is a pure oplock break request then don't
8014 * send a reply */
8015 if (num_locks == 0 && num_ulocks == 0) {
8016 END_PROFILE(SMBlockingX);
8017 return;
8018 } else {
8019 END_PROFILE(SMBlockingX);
8020 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8021 return;
8025 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8026 (break_to_none)) {
8027 result = remove_oplock(fsp);
8028 } else {
8029 result = downgrade_oplock(fsp);
8032 if (!result) {
8033 DEBUG(0, ("reply_lockingX: error in removing "
8034 "oplock on file %s\n", fsp_str_dbg(fsp)));
8035 /* Hmmm. Is this panic justified? */
8036 smb_panic("internal tdb error");
8039 /* if this is a pure oplock break request then don't send a
8040 * reply */
8041 if (num_locks == 0 && num_ulocks == 0) {
8042 /* Sanity check - ensure a pure oplock break is not a
8043 chained request. */
8044 if(CVAL(req->vwv+0, 0) != 0xff)
8045 DEBUG(0,("reply_lockingX: Error : pure oplock "
8046 "break is a chained %d request !\n",
8047 (unsigned int)CVAL(req->vwv+0, 0)));
8048 END_PROFILE(SMBlockingX);
8049 return;
8053 if (req->buflen <
8054 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8055 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8056 END_PROFILE(SMBlockingX);
8057 return;
8060 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8061 if (ulocks == NULL) {
8062 reply_nterror(req, NT_STATUS_NO_MEMORY);
8063 END_PROFILE(SMBlockingX);
8064 return;
8067 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8068 if (locks == NULL) {
8069 reply_nterror(req, NT_STATUS_NO_MEMORY);
8070 END_PROFILE(SMBlockingX);
8071 return;
8074 /* Data now points at the beginning of the list
8075 of smb_unlkrng structs */
8076 for(i = 0; i < (int)num_ulocks; i++) {
8077 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8078 ulocks[i].count = get_lock_count(data, i, large_file_format);
8079 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8080 ulocks[i].brltype = UNLOCK_LOCK;
8083 * There is no error code marked "stupid client bug".... :-).
8085 if(err) {
8086 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8087 END_PROFILE(SMBlockingX);
8088 return;
8092 /* Now do any requested locks */
8093 data += ((large_file_format ? 20 : 10)*num_ulocks);
8095 /* Data now points at the beginning of the list
8096 of smb_lkrng structs */
8098 for(i = 0; i < (int)num_locks; i++) {
8099 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8100 locks[i].count = get_lock_count(data, i, large_file_format);
8101 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8103 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8104 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8105 locks[i].brltype = PENDING_READ_LOCK;
8106 } else {
8107 locks[i].brltype = READ_LOCK;
8109 } else {
8110 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8111 locks[i].brltype = PENDING_WRITE_LOCK;
8112 } else {
8113 locks[i].brltype = WRITE_LOCK;
8118 * There is no error code marked "stupid client bug".... :-).
8120 if(err) {
8121 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8122 END_PROFILE(SMBlockingX);
8123 return;
8127 status = smbd_do_locking(req, fsp,
8128 locktype, lock_timeout,
8129 num_ulocks, ulocks,
8130 num_locks, locks,
8131 &async);
8132 if (!NT_STATUS_IS_OK(status)) {
8133 END_PROFILE(SMBlockingX);
8134 reply_nterror(req, status);
8135 return;
8137 if (async) {
8138 END_PROFILE(SMBlockingX);
8139 return;
8142 reply_outbuf(req, 2, 0);
8143 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8144 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8146 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8147 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8149 END_PROFILE(SMBlockingX);
8152 #undef DBGC_CLASS
8153 #define DBGC_CLASS DBGC_ALL
8155 /****************************************************************************
8156 Reply to a SMBreadbmpx (read block multiplex) request.
8157 Always reply with an error, if someone has a platform really needs this,
8158 please contact vl@samba.org
8159 ****************************************************************************/
8161 void reply_readbmpx(struct smb_request *req)
8163 START_PROFILE(SMBreadBmpx);
8164 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8165 END_PROFILE(SMBreadBmpx);
8166 return;
8169 /****************************************************************************
8170 Reply to a SMBreadbs (read block multiplex secondary) request.
8171 Always reply with an error, if someone has a platform really needs this,
8172 please contact vl@samba.org
8173 ****************************************************************************/
8175 void reply_readbs(struct smb_request *req)
8177 START_PROFILE(SMBreadBs);
8178 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8179 END_PROFILE(SMBreadBs);
8180 return;
8183 /****************************************************************************
8184 Reply to a SMBsetattrE.
8185 ****************************************************************************/
8187 void reply_setattrE(struct smb_request *req)
8189 connection_struct *conn = req->conn;
8190 struct smb_file_time ft;
8191 files_struct *fsp;
8192 NTSTATUS status;
8194 START_PROFILE(SMBsetattrE);
8195 ZERO_STRUCT(ft);
8197 if (req->wct < 7) {
8198 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8199 goto out;
8202 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8204 if(!fsp || (fsp->conn != conn)) {
8205 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8206 goto out;
8210 * Convert the DOS times into unix times.
8213 ft.atime = convert_time_t_to_timespec(
8214 srv_make_unix_date2(req->vwv+3));
8215 ft.mtime = convert_time_t_to_timespec(
8216 srv_make_unix_date2(req->vwv+5));
8217 ft.create_time = convert_time_t_to_timespec(
8218 srv_make_unix_date2(req->vwv+1));
8220 reply_outbuf(req, 0, 0);
8223 * Patch from Ray Frush <frush@engr.colostate.edu>
8224 * Sometimes times are sent as zero - ignore them.
8227 /* Ensure we have a valid stat struct for the source. */
8228 status = vfs_stat_fsp(fsp);
8229 if (!NT_STATUS_IS_OK(status)) {
8230 reply_nterror(req, status);
8231 goto out;
8234 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8235 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8236 goto out;
8239 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8240 if (!NT_STATUS_IS_OK(status)) {
8241 reply_nterror(req, status);
8242 goto out;
8245 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8246 " createtime=%u\n",
8247 fsp_fnum_dbg(fsp),
8248 (unsigned int)ft.atime.tv_sec,
8249 (unsigned int)ft.mtime.tv_sec,
8250 (unsigned int)ft.create_time.tv_sec
8252 out:
8253 END_PROFILE(SMBsetattrE);
8254 return;
8258 /* Back from the dead for OS/2..... JRA. */
8260 /****************************************************************************
8261 Reply to a SMBwritebmpx (write block multiplex primary) request.
8262 Always reply with an error, if someone has a platform really needs this,
8263 please contact vl@samba.org
8264 ****************************************************************************/
8266 void reply_writebmpx(struct smb_request *req)
8268 START_PROFILE(SMBwriteBmpx);
8269 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8270 END_PROFILE(SMBwriteBmpx);
8271 return;
8274 /****************************************************************************
8275 Reply to a SMBwritebs (write block multiplex secondary) request.
8276 Always reply with an error, if someone has a platform really needs this,
8277 please contact vl@samba.org
8278 ****************************************************************************/
8280 void reply_writebs(struct smb_request *req)
8282 START_PROFILE(SMBwriteBs);
8283 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8284 END_PROFILE(SMBwriteBs);
8285 return;
8288 /****************************************************************************
8289 Reply to a SMBgetattrE.
8290 ****************************************************************************/
8292 void reply_getattrE(struct smb_request *req)
8294 connection_struct *conn = req->conn;
8295 int mode;
8296 files_struct *fsp;
8297 struct timespec create_ts;
8299 START_PROFILE(SMBgetattrE);
8301 if (req->wct < 1) {
8302 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8303 END_PROFILE(SMBgetattrE);
8304 return;
8307 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8309 if(!fsp || (fsp->conn != conn)) {
8310 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8311 END_PROFILE(SMBgetattrE);
8312 return;
8315 /* Do an fstat on this file */
8316 if(fsp_stat(fsp)) {
8317 reply_nterror(req, map_nt_error_from_unix(errno));
8318 END_PROFILE(SMBgetattrE);
8319 return;
8322 mode = dos_mode(conn, fsp->fsp_name);
8325 * Convert the times into dos times. Set create
8326 * date to be last modify date as UNIX doesn't save
8327 * this.
8330 reply_outbuf(req, 11, 0);
8332 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8333 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8334 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8335 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8336 /* Should we check pending modtime here ? JRA */
8337 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8338 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8340 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8341 SIVAL(req->outbuf, smb_vwv6, 0);
8342 SIVAL(req->outbuf, smb_vwv8, 0);
8343 } else {
8344 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8345 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8346 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8348 SSVAL(req->outbuf,smb_vwv10, mode);
8350 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8352 END_PROFILE(SMBgetattrE);
8353 return;