lib: replace: Add strsep function (missing on Solaris).
[Samba.git] / source3 / smbd / reply.c
blobb1b91e1d025d6eaad86c5097e345c7464809a3c3
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
46 #include "lib/sys_rw_data.h"
48 /****************************************************************************
49 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
50 path or anything including wildcards.
51 We're assuming here that '/' is not the second byte in any multibyte char
52 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
53 set.
54 ****************************************************************************/
56 /* Custom version for processing POSIX paths. */
57 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
59 static NTSTATUS check_path_syntax_internal(char *path,
60 bool posix_path,
61 bool *p_last_component_contains_wcard)
63 char *d = path;
64 const char *s = path;
65 NTSTATUS ret = NT_STATUS_OK;
66 bool start_of_name_component = True;
67 bool stream_started = false;
69 *p_last_component_contains_wcard = False;
71 while (*s) {
72 if (stream_started) {
73 switch (*s) {
74 case '/':
75 case '\\':
76 return NT_STATUS_OBJECT_NAME_INVALID;
77 case ':':
78 if (s[1] == '\0') {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 if (strchr_m(&s[1], ':')) {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 break;
88 if ((*s == ':') && !posix_path && !stream_started) {
89 if (*p_last_component_contains_wcard) {
90 return NT_STATUS_OBJECT_NAME_INVALID;
92 /* Stream names allow more characters than file names.
93 We're overloading posix_path here to allow a wider
94 range of characters. If stream_started is true this
95 is still a Windows path even if posix_path is true.
96 JRA.
98 stream_started = true;
99 start_of_name_component = false;
100 posix_path = true;
102 if (s[1] == '\0') {
103 return NT_STATUS_OBJECT_NAME_INVALID;
107 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
109 * Safe to assume is not the second part of a mb char
110 * as this is handled below.
112 /* Eat multiple '/' or '\\' */
113 while (IS_PATH_SEP(*s,posix_path)) {
114 s++;
116 if ((d != path) && (*s != '\0')) {
117 /* We only care about non-leading or trailing '/' or '\\' */
118 *d++ = '/';
121 start_of_name_component = True;
122 /* New component. */
123 *p_last_component_contains_wcard = False;
124 continue;
127 if (start_of_name_component) {
128 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
129 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
132 * No mb char starts with '.' so we're safe checking the directory separator here.
135 /* If we just added a '/' - delete it */
136 if ((d > path) && (*(d-1) == '/')) {
137 *(d-1) = '\0';
138 d--;
141 /* Are we at the start ? Can't go back further if so. */
142 if (d <= path) {
143 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
144 break;
146 /* Go back one level... */
147 /* We know this is safe as '/' cannot be part of a mb sequence. */
148 /* NOTE - if this assumption is invalid we are not in good shape... */
149 /* Decrement d first as d points to the *next* char to write into. */
150 for (d--; d > path; d--) {
151 if (*d == '/')
152 break;
154 s += 2; /* Else go past the .. */
155 /* We're still at the start of a name component, just the previous one. */
156 continue;
158 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
159 if (posix_path) {
160 /* Eat the '.' */
161 s++;
162 continue;
168 if (!(*s & 0x80)) {
169 if (!posix_path) {
170 if (*s <= 0x1f || *s == '|') {
171 return NT_STATUS_OBJECT_NAME_INVALID;
173 switch (*s) {
174 case '*':
175 case '?':
176 case '<':
177 case '>':
178 case '"':
179 *p_last_component_contains_wcard = True;
180 break;
181 default:
182 break;
185 *d++ = *s++;
186 } else {
187 size_t siz;
188 /* Get the size of the next MB character. */
189 next_codepoint(s,&siz);
190 switch(siz) {
191 case 5:
192 *d++ = *s++;
193 /*fall through*/
194 case 4:
195 *d++ = *s++;
196 /*fall through*/
197 case 3:
198 *d++ = *s++;
199 /*fall through*/
200 case 2:
201 *d++ = *s++;
202 /*fall through*/
203 case 1:
204 *d++ = *s++;
205 break;
206 default:
207 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
208 *d = '\0';
209 return NT_STATUS_INVALID_PARAMETER;
212 start_of_name_component = False;
215 *d = '\0';
217 return ret;
220 /****************************************************************************
221 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
222 No wildcards allowed.
223 ****************************************************************************/
225 NTSTATUS check_path_syntax(char *path)
227 bool ignore;
228 return check_path_syntax_internal(path, False, &ignore);
231 /****************************************************************************
232 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
233 Wildcards allowed - p_contains_wcard returns true if the last component contained
234 a wildcard.
235 ****************************************************************************/
237 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
239 return check_path_syntax_internal(path, False, p_contains_wcard);
242 /****************************************************************************
243 Check the path for a POSIX client.
244 We're assuming here that '/' is not the second byte in any multibyte char
245 set (a safe assumption).
246 ****************************************************************************/
248 NTSTATUS check_path_syntax_posix(char *path)
250 bool ignore;
251 return check_path_syntax_internal(path, True, &ignore);
254 /****************************************************************************
255 Pull a string and check the path allowing a wilcard - provide for error return.
256 ****************************************************************************/
258 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
259 const char *base_ptr,
260 uint16_t smb_flags2,
261 char **pp_dest,
262 const char *src,
263 size_t src_len,
264 int flags,
265 NTSTATUS *err,
266 bool *contains_wcard)
268 size_t ret;
270 *pp_dest = NULL;
272 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
273 src_len, flags);
275 if (!*pp_dest) {
276 *err = NT_STATUS_INVALID_PARAMETER;
277 return ret;
280 *contains_wcard = False;
282 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
284 * For a DFS path the function parse_dfs_path()
285 * will do the path processing, just make a copy.
287 *err = NT_STATUS_OK;
288 return ret;
291 if (lp_posix_pathnames()) {
292 *err = check_path_syntax_posix(*pp_dest);
293 } else {
294 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
297 return ret;
300 /****************************************************************************
301 Pull a string and check the path - provide for error return.
302 ****************************************************************************/
304 size_t srvstr_get_path(TALLOC_CTX *ctx,
305 const char *base_ptr,
306 uint16_t smb_flags2,
307 char **pp_dest,
308 const char *src,
309 size_t src_len,
310 int flags,
311 NTSTATUS *err)
313 bool ignore;
314 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
315 src_len, flags, err, &ignore);
318 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
319 char **pp_dest, const char *src, int flags,
320 NTSTATUS *err, bool *contains_wcard)
322 ssize_t bufrem = smbreq_bufrem(req, src);
324 if (bufrem < 0) {
325 *err = NT_STATUS_INVALID_PARAMETER;
326 return 0;
329 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
330 req->flags2, pp_dest, src, bufrem, flags,
331 err, contains_wcard);
334 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
335 char **pp_dest, const char *src, int flags,
336 NTSTATUS *err)
338 bool ignore;
339 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
340 flags, err, &ignore);
344 * pull a string from the smb_buf part of a packet. In this case the
345 * string can either be null terminated or it can be terminated by the
346 * end of the smbbuf area
348 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
349 char **dest, const uint8_t *src, int flags)
351 ssize_t bufrem = smbreq_bufrem(req, src);
353 if (bufrem < 0) {
354 return 0;
357 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
358 bufrem, flags);
361 /****************************************************************************
362 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
363 ****************************************************************************/
365 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
366 files_struct *fsp)
368 if ((fsp == NULL) || (conn == NULL)) {
369 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
370 return False;
372 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
373 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
374 return False;
376 return True;
379 /****************************************************************************
380 Check if we have a correct fsp pointing to a file.
381 ****************************************************************************/
383 bool check_fsp(connection_struct *conn, struct smb_request *req,
384 files_struct *fsp)
386 if (!check_fsp_open(conn, req, fsp)) {
387 return False;
389 if (fsp->is_directory) {
390 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
391 return False;
393 if (fsp->fh->fd == -1) {
394 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
395 return False;
397 fsp->num_smb_operations++;
398 return True;
401 /****************************************************************************
402 Check if we have a correct fsp pointing to a quota fake file. Replacement for
403 the CHECK_NTQUOTA_HANDLE_OK macro.
404 ****************************************************************************/
406 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
407 files_struct *fsp)
409 if (!check_fsp_open(conn, req, fsp)) {
410 return false;
413 if (fsp->is_directory) {
414 return false;
417 if (fsp->fake_file_handle == NULL) {
418 return false;
421 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
422 return false;
425 if (fsp->fake_file_handle->private_data == NULL) {
426 return false;
429 return true;
432 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
433 const char *name, int name_type)
435 char *trim_name;
436 char *trim_name_type;
437 const char *retarget_parm;
438 char *retarget;
439 char *p;
440 int retarget_type = 0x20;
441 int retarget_port = NBT_SMB_PORT;
442 struct sockaddr_storage retarget_addr;
443 struct sockaddr_in *in_addr;
444 bool ret = false;
445 uint8_t outbuf[10];
447 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
448 return false;
451 trim_name = talloc_strdup(talloc_tos(), name);
452 if (trim_name == NULL) {
453 goto fail;
455 trim_char(trim_name, ' ', ' ');
457 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
458 name_type);
459 if (trim_name_type == NULL) {
460 goto fail;
463 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
464 trim_name_type, NULL);
465 if (retarget_parm == NULL) {
466 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
467 trim_name, NULL);
469 if (retarget_parm == NULL) {
470 goto fail;
473 retarget = talloc_strdup(trim_name, retarget_parm);
474 if (retarget == NULL) {
475 goto fail;
478 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
480 p = strchr(retarget, ':');
481 if (p != NULL) {
482 *p++ = '\0';
483 retarget_port = atoi(p);
486 p = strchr_m(retarget, '#');
487 if (p != NULL) {
488 *p++ = '\0';
489 if (sscanf(p, "%x", &retarget_type) != 1) {
490 goto fail;
494 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
495 if (!ret) {
496 DEBUG(10, ("could not resolve %s\n", retarget));
497 goto fail;
500 if (retarget_addr.ss_family != AF_INET) {
501 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
502 goto fail;
505 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
507 _smb_setlen(outbuf, 6);
508 SCVAL(outbuf, 0, 0x84);
509 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
510 *(uint16_t *)(outbuf+8) = htons(retarget_port);
512 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
513 NULL)) {
514 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
515 "failed.");
518 ret = true;
519 fail:
520 TALLOC_FREE(trim_name);
521 return ret;
524 static void reply_called_name_not_present(char *outbuf)
526 smb_setlen(outbuf, 1);
527 SCVAL(outbuf, 0, 0x83);
528 SCVAL(outbuf, 4, 0x82);
531 /****************************************************************************
532 Reply to a (netbios-level) special message.
533 ****************************************************************************/
535 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
537 struct smbd_server_connection *sconn = xconn->client->sconn;
538 int msg_type = CVAL(inbuf,0);
539 int msg_flags = CVAL(inbuf,1);
541 * We only really use 4 bytes of the outbuf, but for the smb_setlen
542 * calculation & friends (srv_send_smb uses that) we need the full smb
543 * header.
545 char outbuf[smb_size];
547 memset(outbuf, '\0', sizeof(outbuf));
549 smb_setlen(outbuf,0);
551 switch (msg_type) {
552 case NBSSrequest: /* session request */
554 /* inbuf_size is guarenteed to be at least 4. */
555 fstring name1,name2;
556 int name_type1, name_type2;
557 int name_len1, name_len2;
559 *name1 = *name2 = 0;
561 if (xconn->transport.nbt.got_session) {
562 exit_server_cleanly("multiple session request not permitted");
565 SCVAL(outbuf,0,NBSSpositive);
566 SCVAL(outbuf,3,0);
568 /* inbuf_size is guaranteed to be at least 4. */
569 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
570 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
571 DEBUG(0,("Invalid name length in session request\n"));
572 reply_called_name_not_present(outbuf);
573 break;
575 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
576 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
577 DEBUG(0,("Invalid name length in session request\n"));
578 reply_called_name_not_present(outbuf);
579 break;
582 name_type1 = name_extract((unsigned char *)inbuf,
583 inbuf_size,(unsigned int)4,name1);
584 name_type2 = name_extract((unsigned char *)inbuf,
585 inbuf_size,(unsigned int)(4 + name_len1),name2);
587 if (name_type1 == -1 || name_type2 == -1) {
588 DEBUG(0,("Invalid name type in session request\n"));
589 reply_called_name_not_present(outbuf);
590 break;
593 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
594 name1, name_type1, name2, name_type2));
596 if (netbios_session_retarget(xconn, name1, name_type1)) {
597 exit_server_cleanly("retargeted client");
601 * Windows NT/2k uses "*SMBSERVER" and XP uses
602 * "*SMBSERV" arrggg!!!
604 if (strequal(name1, "*SMBSERVER ")
605 || strequal(name1, "*SMBSERV ")) {
606 char *raddr;
608 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
609 talloc_tos());
610 if (raddr == NULL) {
611 exit_server_cleanly("could not allocate raddr");
614 fstrcpy(name1, raddr);
617 set_local_machine_name(name1, True);
618 set_remote_machine_name(name2, True);
620 if (is_ipaddress(sconn->remote_hostname)) {
621 char *p = discard_const_p(char, sconn->remote_hostname);
623 talloc_free(p);
625 sconn->remote_hostname = talloc_strdup(sconn,
626 get_remote_machine_name());
627 if (sconn->remote_hostname == NULL) {
628 exit_server_cleanly("could not copy remote name");
630 xconn->remote_hostname = sconn->remote_hostname;
633 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
634 get_local_machine_name(), get_remote_machine_name(),
635 name_type2));
637 if (name_type2 == 'R') {
638 /* We are being asked for a pathworks session ---
639 no thanks! */
640 reply_called_name_not_present(outbuf);
641 break;
644 reload_services(sconn, conn_snum_used, true);
645 reopen_logs();
647 xconn->transport.nbt.got_session = true;
648 break;
651 case 0x89: /* session keepalive request
652 (some old clients produce this?) */
653 SCVAL(outbuf,0,NBSSkeepalive);
654 SCVAL(outbuf,3,0);
655 break;
657 case NBSSpositive: /* positive session response */
658 case NBSSnegative: /* negative session response */
659 case NBSSretarget: /* retarget session response */
660 DEBUG(0,("Unexpected session response\n"));
661 break;
663 case NBSSkeepalive: /* session keepalive */
664 default:
665 return;
668 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
669 msg_type, msg_flags));
671 srv_send_smb(xconn, outbuf, false, 0, false, NULL);
673 if (CVAL(outbuf, 0) != 0x82) {
674 exit_server_cleanly("invalid netbios session");
676 return;
679 /****************************************************************************
680 Reply to a tcon.
681 conn POINTER CAN BE NULL HERE !
682 ****************************************************************************/
684 void reply_tcon(struct smb_request *req)
686 connection_struct *conn = req->conn;
687 const char *service;
688 char *service_buf = NULL;
689 char *password = NULL;
690 char *dev = NULL;
691 int pwlen=0;
692 NTSTATUS nt_status;
693 const uint8_t *p;
694 const char *p2;
695 TALLOC_CTX *ctx = talloc_tos();
696 struct smbXsrv_connection *xconn = req->xconn;
697 NTTIME now = timeval_to_nttime(&req->request_time);
699 START_PROFILE(SMBtcon);
701 if (req->buflen < 4) {
702 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
703 END_PROFILE(SMBtcon);
704 return;
707 p = req->buf + 1;
708 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
709 p += 1;
710 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
711 p += pwlen+1;
712 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
713 p += 1;
715 if (service_buf == NULL || password == NULL || dev == NULL) {
716 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
717 END_PROFILE(SMBtcon);
718 return;
720 p2 = strrchr_m(service_buf,'\\');
721 if (p2) {
722 service = p2+1;
723 } else {
724 service = service_buf;
727 conn = make_connection(req, now, service, dev,
728 req->vuid,&nt_status);
729 req->conn = conn;
731 if (!conn) {
732 reply_nterror(req, nt_status);
733 END_PROFILE(SMBtcon);
734 return;
737 reply_outbuf(req, 2, 0);
738 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
739 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
740 SSVAL(req->outbuf,smb_tid,conn->cnum);
742 DEBUG(3,("tcon service=%s cnum=%d\n",
743 service, conn->cnum));
745 END_PROFILE(SMBtcon);
746 return;
749 /****************************************************************************
750 Reply to a tcon and X.
751 conn POINTER CAN BE NULL HERE !
752 ****************************************************************************/
754 void reply_tcon_and_X(struct smb_request *req)
756 connection_struct *conn = req->conn;
757 const char *service = NULL;
758 TALLOC_CTX *ctx = talloc_tos();
759 /* what the cleint thinks the device is */
760 char *client_devicetype = NULL;
761 /* what the server tells the client the share represents */
762 const char *server_devicetype;
763 NTSTATUS nt_status;
764 int passlen;
765 char *path = NULL;
766 const uint8_t *p;
767 const char *q;
768 uint16_t tcon_flags;
769 struct smbXsrv_session *session = NULL;
770 NTTIME now = timeval_to_nttime(&req->request_time);
771 bool session_key_updated = false;
772 uint16_t optional_support = 0;
773 struct smbXsrv_connection *xconn = req->xconn;
775 START_PROFILE(SMBtconX);
777 if (req->wct < 4) {
778 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
779 END_PROFILE(SMBtconX);
780 return;
783 passlen = SVAL(req->vwv+3, 0);
784 tcon_flags = SVAL(req->vwv+2, 0);
786 /* we might have to close an old one */
787 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
788 struct smbXsrv_tcon *tcon;
789 NTSTATUS status;
791 tcon = conn->tcon;
792 req->conn = NULL;
793 conn = NULL;
796 * TODO: cancel all outstanding requests on the tcon
798 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
799 if (!NT_STATUS_IS_OK(status)) {
800 DEBUG(0, ("reply_tcon_and_X: "
801 "smbXsrv_tcon_disconnect() failed: %s\n",
802 nt_errstr(status)));
804 * If we hit this case, there is something completely
805 * wrong, so we better disconnect the transport connection.
807 END_PROFILE(SMBtconX);
808 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
809 return;
812 TALLOC_FREE(tcon);
815 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
816 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
817 END_PROFILE(SMBtconX);
818 return;
821 if (xconn->smb1.negprot.encrypted_passwords) {
822 p = req->buf + passlen;
823 } else {
824 p = req->buf + passlen + 1;
827 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
829 if (path == NULL) {
830 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
831 END_PROFILE(SMBtconX);
832 return;
836 * the service name can be either: \\server\share
837 * or share directly like on the DELL PowerVault 705
839 if (*path=='\\') {
840 q = strchr_m(path+2,'\\');
841 if (!q) {
842 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
843 END_PROFILE(SMBtconX);
844 return;
846 service = q+1;
847 } else {
848 service = path;
851 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
852 &client_devicetype, p,
853 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
855 if (client_devicetype == NULL) {
856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
857 END_PROFILE(SMBtconX);
858 return;
861 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
863 nt_status = smb1srv_session_lookup(xconn,
864 req->vuid, now, &session);
865 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
866 reply_force_doserror(req, ERRSRV, ERRbaduid);
867 END_PROFILE(SMBtconX);
868 return;
870 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
871 reply_nterror(req, nt_status);
872 END_PROFILE(SMBtconX);
873 return;
875 if (!NT_STATUS_IS_OK(nt_status)) {
876 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
877 END_PROFILE(SMBtconX);
878 return;
881 if (session->global->auth_session_info == NULL) {
882 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
883 END_PROFILE(SMBtconX);
884 return;
888 * If there is no application key defined yet
889 * we create one.
891 * This means we setup the application key on the
892 * first tcon that happens via the given session.
894 * Once the application key is defined, it does not
895 * change any more.
897 if (session->global->application_key.length == 0 &&
898 session->global->signing_key.length > 0)
900 struct smbXsrv_session *x = session;
901 struct auth_session_info *session_info =
902 session->global->auth_session_info;
903 uint8_t session_key[16];
905 ZERO_STRUCT(session_key);
906 memcpy(session_key, x->global->signing_key.data,
907 MIN(x->global->signing_key.length, sizeof(session_key)));
910 * The application key is truncated/padded to 16 bytes
912 x->global->application_key = data_blob_talloc(x->global,
913 session_key,
914 sizeof(session_key));
915 ZERO_STRUCT(session_key);
916 if (x->global->application_key.data == NULL) {
917 reply_nterror(req, NT_STATUS_NO_MEMORY);
918 END_PROFILE(SMBtconX);
919 return;
922 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
923 smb_key_derivation(x->global->application_key.data,
924 x->global->application_key.length,
925 x->global->application_key.data);
926 optional_support |= SMB_EXTENDED_SIGNATURES;
930 * Place the application key into the session_info
932 data_blob_clear_free(&session_info->session_key);
933 session_info->session_key = data_blob_dup_talloc(session_info,
934 x->global->application_key);
935 if (session_info->session_key.data == NULL) {
936 data_blob_clear_free(&x->global->application_key);
937 reply_nterror(req, NT_STATUS_NO_MEMORY);
938 END_PROFILE(SMBtconX);
939 return;
941 session_key_updated = true;
944 conn = make_connection(req, now, service, client_devicetype,
945 req->vuid, &nt_status);
946 req->conn =conn;
948 if (!conn) {
949 if (session_key_updated) {
950 struct smbXsrv_session *x = session;
951 struct auth_session_info *session_info =
952 session->global->auth_session_info;
953 data_blob_clear_free(&x->global->application_key);
954 data_blob_clear_free(&session_info->session_key);
956 reply_nterror(req, nt_status);
957 END_PROFILE(SMBtconX);
958 return;
961 if ( IS_IPC(conn) )
962 server_devicetype = "IPC";
963 else if ( IS_PRINT(conn) )
964 server_devicetype = "LPT1:";
965 else
966 server_devicetype = "A:";
968 if (get_Protocol() < PROTOCOL_NT1) {
969 reply_outbuf(req, 2, 0);
970 if (message_push_string(&req->outbuf, server_devicetype,
971 STR_TERMINATE|STR_ASCII) == -1) {
972 reply_nterror(req, NT_STATUS_NO_MEMORY);
973 END_PROFILE(SMBtconX);
974 return;
976 } else {
977 /* NT sets the fstype of IPC$ to the null string */
978 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
980 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
981 /* Return permissions. */
982 uint32_t perm1 = 0;
983 uint32_t perm2 = 0;
985 reply_outbuf(req, 7, 0);
987 if (IS_IPC(conn)) {
988 perm1 = FILE_ALL_ACCESS;
989 perm2 = FILE_ALL_ACCESS;
990 } else {
991 perm1 = conn->share_access;
994 SIVAL(req->outbuf, smb_vwv3, perm1);
995 SIVAL(req->outbuf, smb_vwv5, perm2);
996 } else {
997 reply_outbuf(req, 3, 0);
1000 if ((message_push_string(&req->outbuf, server_devicetype,
1001 STR_TERMINATE|STR_ASCII) == -1)
1002 || (message_push_string(&req->outbuf, fstype,
1003 STR_TERMINATE) == -1)) {
1004 reply_nterror(req, NT_STATUS_NO_MEMORY);
1005 END_PROFILE(SMBtconX);
1006 return;
1009 /* what does setting this bit do? It is set by NT4 and
1010 may affect the ability to autorun mounted cdroms */
1011 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1012 optional_support |=
1013 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1015 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1016 DEBUG(2,("Serving %s as a Dfs root\n",
1017 lp_servicename(ctx, SNUM(conn)) ));
1018 optional_support |= SMB_SHARE_IN_DFS;
1021 SSVAL(req->outbuf, smb_vwv2, optional_support);
1024 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1025 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1027 DEBUG(3,("tconX service=%s \n",
1028 service));
1030 /* set the incoming and outgoing tid to the just created one */
1031 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1032 SSVAL(req->outbuf,smb_tid,conn->cnum);
1034 END_PROFILE(SMBtconX);
1036 req->tid = conn->cnum;
1039 /****************************************************************************
1040 Reply to an unknown type.
1041 ****************************************************************************/
1043 void reply_unknown_new(struct smb_request *req, uint8_t type)
1045 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1046 smb_fn_name(type), type, type));
1047 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1048 return;
1051 /****************************************************************************
1052 Reply to an ioctl.
1053 conn POINTER CAN BE NULL HERE !
1054 ****************************************************************************/
1056 void reply_ioctl(struct smb_request *req)
1058 connection_struct *conn = req->conn;
1059 uint16_t device;
1060 uint16_t function;
1061 uint32_t ioctl_code;
1062 int replysize;
1063 char *p;
1065 START_PROFILE(SMBioctl);
1067 if (req->wct < 3) {
1068 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1069 END_PROFILE(SMBioctl);
1070 return;
1073 device = SVAL(req->vwv+1, 0);
1074 function = SVAL(req->vwv+2, 0);
1075 ioctl_code = (device << 16) + function;
1077 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1079 switch (ioctl_code) {
1080 case IOCTL_QUERY_JOB_INFO:
1081 replysize = 32;
1082 break;
1083 default:
1084 reply_force_doserror(req, ERRSRV, ERRnosupport);
1085 END_PROFILE(SMBioctl);
1086 return;
1089 reply_outbuf(req, 8, replysize+1);
1090 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1091 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1092 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1093 p = smb_buf(req->outbuf);
1094 memset(p, '\0', replysize+1); /* valgrind-safe. */
1095 p += 1; /* Allow for alignment */
1097 switch (ioctl_code) {
1098 case IOCTL_QUERY_JOB_INFO:
1100 NTSTATUS status;
1101 size_t len = 0;
1102 files_struct *fsp = file_fsp(
1103 req, SVAL(req->vwv+0, 0));
1104 if (!fsp) {
1105 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1106 END_PROFILE(SMBioctl);
1107 return;
1109 /* Job number */
1110 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1112 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1113 lp_netbios_name(), 15,
1114 STR_TERMINATE|STR_ASCII, &len);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 reply_nterror(req, status);
1117 END_PROFILE(SMBioctl);
1118 return;
1120 if (conn) {
1121 status = srvstr_push((char *)req->outbuf, req->flags2,
1122 p+18,
1123 lp_servicename(talloc_tos(),
1124 SNUM(conn)),
1125 13, STR_TERMINATE|STR_ASCII, &len);
1126 if (!NT_STATUS_IS_OK(status)) {
1127 reply_nterror(req, status);
1128 END_PROFILE(SMBioctl);
1129 return;
1131 } else {
1132 memset(p+18, 0, 13);
1134 break;
1138 END_PROFILE(SMBioctl);
1139 return;
1142 /****************************************************************************
1143 Strange checkpath NTSTATUS mapping.
1144 ****************************************************************************/
1146 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1148 /* Strange DOS error code semantics only for checkpath... */
1149 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1150 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1151 /* We need to map to ERRbadpath */
1152 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1155 return status;
1158 /****************************************************************************
1159 Reply to a checkpath.
1160 ****************************************************************************/
1162 void reply_checkpath(struct smb_request *req)
1164 connection_struct *conn = req->conn;
1165 struct smb_filename *smb_fname = NULL;
1166 char *name = NULL;
1167 NTSTATUS status;
1168 TALLOC_CTX *ctx = talloc_tos();
1170 START_PROFILE(SMBcheckpath);
1172 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1173 STR_TERMINATE, &status);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 status = map_checkpath_error(req->flags2, status);
1177 reply_nterror(req, status);
1178 END_PROFILE(SMBcheckpath);
1179 return;
1182 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1184 status = filename_convert(ctx,
1185 conn,
1186 req->flags2 & FLAGS2_DFS_PATHNAMES,
1187 name,
1189 NULL,
1190 &smb_fname);
1192 if (!NT_STATUS_IS_OK(status)) {
1193 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1194 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1195 ERRSRV, ERRbadpath);
1196 END_PROFILE(SMBcheckpath);
1197 return;
1199 goto path_err;
1202 if (!VALID_STAT(smb_fname->st) &&
1203 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1204 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1205 smb_fname_str_dbg(smb_fname), strerror(errno)));
1206 status = map_nt_error_from_unix(errno);
1207 goto path_err;
1210 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1211 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1212 ERRDOS, ERRbadpath);
1213 goto out;
1216 reply_outbuf(req, 0, 0);
1218 path_err:
1219 /* We special case this - as when a Windows machine
1220 is parsing a path is steps through the components
1221 one at a time - if a component fails it expects
1222 ERRbadpath, not ERRbadfile.
1224 status = map_checkpath_error(req->flags2, status);
1225 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1227 * Windows returns different error codes if
1228 * the parent directory is valid but not the
1229 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1230 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1231 * if the path is invalid.
1233 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1234 ERRDOS, ERRbadpath);
1235 goto out;
1238 reply_nterror(req, status);
1240 out:
1241 TALLOC_FREE(smb_fname);
1242 END_PROFILE(SMBcheckpath);
1243 return;
1246 /****************************************************************************
1247 Reply to a getatr.
1248 ****************************************************************************/
1250 void reply_getatr(struct smb_request *req)
1252 connection_struct *conn = req->conn;
1253 struct smb_filename *smb_fname = NULL;
1254 char *fname = NULL;
1255 int mode=0;
1256 off_t size=0;
1257 time_t mtime=0;
1258 const char *p;
1259 NTSTATUS status;
1260 TALLOC_CTX *ctx = talloc_tos();
1261 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1263 START_PROFILE(SMBgetatr);
1265 p = (const char *)req->buf + 1;
1266 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 reply_nterror(req, status);
1269 goto out;
1272 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1273 under WfWg - weird! */
1274 if (*fname == '\0') {
1275 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1276 if (!CAN_WRITE(conn)) {
1277 mode |= FILE_ATTRIBUTE_READONLY;
1279 size = 0;
1280 mtime = 0;
1281 } else {
1282 status = filename_convert(ctx,
1283 conn,
1284 req->flags2 & FLAGS2_DFS_PATHNAMES,
1285 fname,
1287 NULL,
1288 &smb_fname);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1291 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1292 ERRSRV, ERRbadpath);
1293 goto out;
1295 reply_nterror(req, status);
1296 goto out;
1298 if (!VALID_STAT(smb_fname->st) &&
1299 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1300 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1301 smb_fname_str_dbg(smb_fname),
1302 strerror(errno)));
1303 reply_nterror(req, map_nt_error_from_unix(errno));
1304 goto out;
1307 mode = dos_mode(conn, smb_fname);
1308 size = smb_fname->st.st_ex_size;
1310 if (ask_sharemode) {
1311 struct timespec write_time_ts;
1312 struct file_id fileid;
1314 ZERO_STRUCT(write_time_ts);
1315 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1316 get_file_infos(fileid, 0, NULL, &write_time_ts);
1317 if (!null_timespec(write_time_ts)) {
1318 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1322 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1323 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1324 size = 0;
1328 reply_outbuf(req, 10, 0);
1330 SSVAL(req->outbuf,smb_vwv0,mode);
1331 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1332 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1333 } else {
1334 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1336 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1338 if (get_Protocol() >= PROTOCOL_NT1) {
1339 SSVAL(req->outbuf, smb_flg2,
1340 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1343 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1344 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1346 out:
1347 TALLOC_FREE(smb_fname);
1348 TALLOC_FREE(fname);
1349 END_PROFILE(SMBgetatr);
1350 return;
1353 /****************************************************************************
1354 Reply to a setatr.
1355 ****************************************************************************/
1357 void reply_setatr(struct smb_request *req)
1359 struct smb_file_time ft;
1360 connection_struct *conn = req->conn;
1361 struct smb_filename *smb_fname = NULL;
1362 char *fname = NULL;
1363 int mode;
1364 time_t mtime;
1365 const char *p;
1366 NTSTATUS status;
1367 TALLOC_CTX *ctx = talloc_tos();
1369 START_PROFILE(SMBsetatr);
1371 ZERO_STRUCT(ft);
1373 if (req->wct < 2) {
1374 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1375 goto out;
1378 p = (const char *)req->buf + 1;
1379 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 reply_nterror(req, status);
1382 goto out;
1385 status = filename_convert(ctx,
1386 conn,
1387 req->flags2 & FLAGS2_DFS_PATHNAMES,
1388 fname,
1390 NULL,
1391 &smb_fname);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1394 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1395 ERRSRV, ERRbadpath);
1396 goto out;
1398 reply_nterror(req, status);
1399 goto out;
1402 if (smb_fname->base_name[0] == '.' &&
1403 smb_fname->base_name[1] == '\0') {
1405 * Not sure here is the right place to catch this
1406 * condition. Might be moved to somewhere else later -- vl
1408 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1409 goto out;
1412 mode = SVAL(req->vwv+0, 0);
1413 mtime = srv_make_unix_date3(req->vwv+1);
1415 if (mode != FILE_ATTRIBUTE_NORMAL) {
1416 if (VALID_STAT_OF_DIR(smb_fname->st))
1417 mode |= FILE_ATTRIBUTE_DIRECTORY;
1418 else
1419 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1421 status = check_access(conn, NULL, smb_fname,
1422 FILE_WRITE_ATTRIBUTES);
1423 if (!NT_STATUS_IS_OK(status)) {
1424 reply_nterror(req, status);
1425 goto out;
1428 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1429 false) != 0) {
1430 reply_nterror(req, map_nt_error_from_unix(errno));
1431 goto out;
1435 ft.mtime = convert_time_t_to_timespec(mtime);
1436 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1437 if (!NT_STATUS_IS_OK(status)) {
1438 reply_nterror(req, status);
1439 goto out;
1442 reply_outbuf(req, 0, 0);
1444 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1445 mode));
1446 out:
1447 TALLOC_FREE(smb_fname);
1448 END_PROFILE(SMBsetatr);
1449 return;
1452 /****************************************************************************
1453 Reply to a dskattr.
1454 ****************************************************************************/
1456 void reply_dskattr(struct smb_request *req)
1458 connection_struct *conn = req->conn;
1459 uint64_t ret;
1460 uint64_t dfree,dsize,bsize;
1461 START_PROFILE(SMBdskattr);
1463 ret = get_dfree_info(conn, ".", &bsize, &dfree, &dsize);
1464 if (ret == (uint64_t)-1) {
1465 reply_nterror(req, map_nt_error_from_unix(errno));
1466 END_PROFILE(SMBdskattr);
1467 return;
1471 * Force max to fit in 16 bit fields.
1473 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1474 dfree /= 2;
1475 dsize /= 2;
1476 bsize *= 2;
1477 if (bsize > (WORDMAX*512)) {
1478 bsize = (WORDMAX*512);
1479 if (dsize > WORDMAX)
1480 dsize = WORDMAX;
1481 if (dfree > WORDMAX)
1482 dfree = WORDMAX;
1483 break;
1487 reply_outbuf(req, 5, 0);
1489 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1490 double total_space, free_space;
1491 /* we need to scale this to a number that DOS6 can handle. We
1492 use floating point so we can handle large drives on systems
1493 that don't have 64 bit integers
1495 we end up displaying a maximum of 2G to DOS systems
1497 total_space = dsize * (double)bsize;
1498 free_space = dfree * (double)bsize;
1500 dsize = (uint64_t)((total_space+63*512) / (64*512));
1501 dfree = (uint64_t)((free_space+63*512) / (64*512));
1503 if (dsize > 0xFFFF) dsize = 0xFFFF;
1504 if (dfree > 0xFFFF) dfree = 0xFFFF;
1506 SSVAL(req->outbuf,smb_vwv0,dsize);
1507 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1508 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1509 SSVAL(req->outbuf,smb_vwv3,dfree);
1510 } else {
1511 SSVAL(req->outbuf,smb_vwv0,dsize);
1512 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1513 SSVAL(req->outbuf,smb_vwv2,512);
1514 SSVAL(req->outbuf,smb_vwv3,dfree);
1517 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1519 END_PROFILE(SMBdskattr);
1520 return;
1524 * Utility function to split the filename from the directory.
1526 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1527 char **fname_dir_out,
1528 char **fname_mask_out)
1530 const char *p = NULL;
1531 char *fname_dir = NULL;
1532 char *fname_mask = NULL;
1534 p = strrchr_m(fname_in, '/');
1535 if (!p) {
1536 fname_dir = talloc_strdup(ctx, ".");
1537 fname_mask = talloc_strdup(ctx, fname_in);
1538 } else {
1539 fname_dir = talloc_strndup(ctx, fname_in,
1540 PTR_DIFF(p, fname_in));
1541 fname_mask = talloc_strdup(ctx, p+1);
1544 if (!fname_dir || !fname_mask) {
1545 TALLOC_FREE(fname_dir);
1546 TALLOC_FREE(fname_mask);
1547 return NT_STATUS_NO_MEMORY;
1550 *fname_dir_out = fname_dir;
1551 *fname_mask_out = fname_mask;
1552 return NT_STATUS_OK;
1555 /****************************************************************************
1556 Make a dir struct.
1557 ****************************************************************************/
1559 static bool make_dir_struct(TALLOC_CTX *ctx,
1560 char *buf,
1561 const char *mask,
1562 const char *fname,
1563 off_t size,
1564 uint32_t mode,
1565 time_t date,
1566 bool uc)
1568 char *p;
1569 char *mask2 = talloc_strdup(ctx, mask);
1571 if (!mask2) {
1572 return False;
1575 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1576 size = 0;
1579 memset(buf+1,' ',11);
1580 if ((p = strchr_m(mask2,'.')) != NULL) {
1581 *p = 0;
1582 push_ascii(buf+1,mask2,8, 0);
1583 push_ascii(buf+9,p+1,3, 0);
1584 *p = '.';
1585 } else {
1586 push_ascii(buf+1,mask2,11, 0);
1589 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1590 SCVAL(buf,21,mode);
1591 srv_put_dos_date(buf,22,date);
1592 SSVAL(buf,26,size & 0xFFFF);
1593 SSVAL(buf,28,(size >> 16)&0xFFFF);
1594 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1595 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1596 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1597 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1598 return True;
1601 /****************************************************************************
1602 Reply to a search.
1603 Can be called from SMBsearch, SMBffirst or SMBfunique.
1604 ****************************************************************************/
1606 void reply_search(struct smb_request *req)
1608 connection_struct *conn = req->conn;
1609 char *path = NULL;
1610 const char *mask = NULL;
1611 char *directory = NULL;
1612 struct smb_filename *smb_fname = NULL;
1613 char *fname = NULL;
1614 off_t size;
1615 uint32_t mode;
1616 struct timespec date;
1617 uint32_t dirtype;
1618 unsigned int numentries = 0;
1619 unsigned int maxentries = 0;
1620 bool finished = False;
1621 const char *p;
1622 int status_len;
1623 char status[21];
1624 int dptr_num= -1;
1625 bool check_descend = False;
1626 bool expect_close = False;
1627 NTSTATUS nt_status;
1628 bool mask_contains_wcard = False;
1629 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1630 TALLOC_CTX *ctx = talloc_tos();
1631 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1632 struct dptr_struct *dirptr = NULL;
1633 struct smbXsrv_connection *xconn = req->xconn;
1634 struct smbd_server_connection *sconn = req->sconn;
1636 START_PROFILE(SMBsearch);
1638 if (req->wct < 2) {
1639 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1640 goto out;
1643 if (lp_posix_pathnames()) {
1644 reply_unknown_new(req, req->cmd);
1645 goto out;
1648 /* If we were called as SMBffirst then we must expect close. */
1649 if(req->cmd == SMBffirst) {
1650 expect_close = True;
1653 reply_outbuf(req, 1, 3);
1654 maxentries = SVAL(req->vwv+0, 0);
1655 dirtype = SVAL(req->vwv+1, 0);
1656 p = (const char *)req->buf + 1;
1657 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1658 &nt_status, &mask_contains_wcard);
1659 if (!NT_STATUS_IS_OK(nt_status)) {
1660 reply_nterror(req, nt_status);
1661 goto out;
1664 p++;
1665 status_len = SVAL(p, 0);
1666 p += 2;
1668 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1670 if (status_len == 0) {
1671 nt_status = filename_convert(ctx, conn,
1672 req->flags2 & FLAGS2_DFS_PATHNAMES,
1673 path,
1674 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1675 &mask_contains_wcard,
1676 &smb_fname);
1677 if (!NT_STATUS_IS_OK(nt_status)) {
1678 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1679 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1680 ERRSRV, ERRbadpath);
1681 goto out;
1683 reply_nterror(req, nt_status);
1684 goto out;
1687 directory = smb_fname->base_name;
1689 p = strrchr_m(directory,'/');
1690 if ((p != NULL) && (*directory != '/')) {
1691 mask = p + 1;
1692 directory = talloc_strndup(ctx, directory,
1693 PTR_DIFF(p, directory));
1694 } else {
1695 mask = directory;
1696 directory = talloc_strdup(ctx,".");
1699 if (!directory) {
1700 reply_nterror(req, NT_STATUS_NO_MEMORY);
1701 goto out;
1704 memset((char *)status,'\0',21);
1705 SCVAL(status,0,(dirtype & 0x1F));
1707 nt_status = dptr_create(conn,
1708 NULL, /* req */
1709 NULL, /* fsp */
1710 directory,
1711 True,
1712 expect_close,
1713 req->smbpid,
1714 mask,
1715 mask_contains_wcard,
1716 dirtype,
1717 &dirptr);
1718 if (!NT_STATUS_IS_OK(nt_status)) {
1719 reply_nterror(req, nt_status);
1720 goto out;
1722 dptr_num = dptr_dnum(dirptr);
1723 } else {
1724 int status_dirtype;
1725 const char *dirpath;
1727 memcpy(status,p,21);
1728 status_dirtype = CVAL(status,0) & 0x1F;
1729 if (status_dirtype != (dirtype & 0x1F)) {
1730 dirtype = status_dirtype;
1733 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1734 if (!dirptr) {
1735 goto SearchEmpty;
1737 dirpath = dptr_path(sconn, dptr_num);
1738 directory = talloc_strdup(ctx, dirpath);
1739 if (!directory) {
1740 reply_nterror(req, NT_STATUS_NO_MEMORY);
1741 goto out;
1744 mask = dptr_wcard(sconn, dptr_num);
1745 if (!mask) {
1746 goto SearchEmpty;
1749 * For a 'continue' search we have no string. So
1750 * check from the initial saved string.
1752 mask_contains_wcard = ms_has_wild(mask);
1753 dirtype = dptr_attr(sconn, dptr_num);
1756 DEBUG(4,("dptr_num is %d\n",dptr_num));
1758 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1759 dptr_init_search_op(dirptr);
1761 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1762 char buf[DIR_STRUCT_SIZE];
1763 memcpy(buf,status,21);
1764 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1765 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1766 reply_nterror(req, NT_STATUS_NO_MEMORY);
1767 goto out;
1769 dptr_fill(sconn, buf+12,dptr_num);
1770 if (dptr_zero(buf+12) && (status_len==0)) {
1771 numentries = 1;
1772 } else {
1773 numentries = 0;
1775 if (message_push_blob(&req->outbuf,
1776 data_blob_const(buf, sizeof(buf)))
1777 == -1) {
1778 reply_nterror(req, NT_STATUS_NO_MEMORY);
1779 goto out;
1781 } else {
1782 unsigned int i;
1783 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1784 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1786 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1788 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1789 directory,lp_dont_descend(ctx, SNUM(conn))));
1790 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1791 check_descend = True;
1794 for (i=numentries;(i<maxentries) && !finished;i++) {
1795 finished = !get_dir_entry(ctx,
1796 dirptr,
1797 mask,
1798 dirtype,
1799 &fname,
1800 &size,
1801 &mode,
1802 &date,
1803 check_descend,
1804 ask_sharemode);
1805 if (!finished) {
1806 char buf[DIR_STRUCT_SIZE];
1807 memcpy(buf,status,21);
1808 if (!make_dir_struct(ctx,
1809 buf,
1810 mask,
1811 fname,
1812 size,
1813 mode,
1814 convert_timespec_to_time_t(date),
1815 !allow_long_path_components)) {
1816 reply_nterror(req, NT_STATUS_NO_MEMORY);
1817 goto out;
1819 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1820 break;
1822 if (message_push_blob(&req->outbuf,
1823 data_blob_const(buf, sizeof(buf)))
1824 == -1) {
1825 reply_nterror(req, NT_STATUS_NO_MEMORY);
1826 goto out;
1828 numentries++;
1833 SearchEmpty:
1835 /* If we were called as SMBffirst with smb_search_id == NULL
1836 and no entries were found then return error and close dirptr
1837 (X/Open spec) */
1839 if (numentries == 0) {
1840 dptr_close(sconn, &dptr_num);
1841 } else if(expect_close && status_len == 0) {
1842 /* Close the dptr - we know it's gone */
1843 dptr_close(sconn, &dptr_num);
1846 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1847 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1848 dptr_close(sconn, &dptr_num);
1851 if ((numentries == 0) && !mask_contains_wcard) {
1852 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1853 goto out;
1856 SSVAL(req->outbuf,smb_vwv0,numentries);
1857 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1858 SCVAL(smb_buf(req->outbuf),0,5);
1859 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1861 /* The replies here are never long name. */
1862 SSVAL(req->outbuf, smb_flg2,
1863 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1864 if (!allow_long_path_components) {
1865 SSVAL(req->outbuf, smb_flg2,
1866 SVAL(req->outbuf, smb_flg2)
1867 & (~FLAGS2_LONG_PATH_COMPONENTS));
1870 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1871 SSVAL(req->outbuf, smb_flg2,
1872 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1874 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1875 smb_fn_name(req->cmd),
1876 mask,
1877 directory,
1878 dirtype,
1879 numentries,
1880 maxentries ));
1881 out:
1882 TALLOC_FREE(directory);
1883 TALLOC_FREE(smb_fname);
1884 END_PROFILE(SMBsearch);
1885 return;
1888 /****************************************************************************
1889 Reply to a fclose (stop directory search).
1890 ****************************************************************************/
1892 void reply_fclose(struct smb_request *req)
1894 int status_len;
1895 char status[21];
1896 int dptr_num= -2;
1897 const char *p;
1898 char *path = NULL;
1899 NTSTATUS err;
1900 bool path_contains_wcard = False;
1901 TALLOC_CTX *ctx = talloc_tos();
1902 struct smbd_server_connection *sconn = req->sconn;
1904 START_PROFILE(SMBfclose);
1906 if (lp_posix_pathnames()) {
1907 reply_unknown_new(req, req->cmd);
1908 END_PROFILE(SMBfclose);
1909 return;
1912 p = (const char *)req->buf + 1;
1913 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1914 &err, &path_contains_wcard);
1915 if (!NT_STATUS_IS_OK(err)) {
1916 reply_nterror(req, err);
1917 END_PROFILE(SMBfclose);
1918 return;
1920 p++;
1921 status_len = SVAL(p,0);
1922 p += 2;
1924 if (status_len == 0) {
1925 reply_force_doserror(req, ERRSRV, ERRsrverror);
1926 END_PROFILE(SMBfclose);
1927 return;
1930 memcpy(status,p,21);
1932 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1933 /* Close the dptr - we know it's gone */
1934 dptr_close(sconn, &dptr_num);
1937 reply_outbuf(req, 1, 0);
1938 SSVAL(req->outbuf,smb_vwv0,0);
1940 DEBUG(3,("search close\n"));
1942 END_PROFILE(SMBfclose);
1943 return;
1946 /****************************************************************************
1947 Reply to an open.
1948 ****************************************************************************/
1950 void reply_open(struct smb_request *req)
1952 connection_struct *conn = req->conn;
1953 struct smb_filename *smb_fname = NULL;
1954 char *fname = NULL;
1955 uint32_t fattr=0;
1956 off_t size = 0;
1957 time_t mtime=0;
1958 int info;
1959 files_struct *fsp;
1960 int oplock_request;
1961 int deny_mode;
1962 uint32_t dos_attr;
1963 uint32_t access_mask;
1964 uint32_t share_mode;
1965 uint32_t create_disposition;
1966 uint32_t create_options = 0;
1967 uint32_t private_flags = 0;
1968 NTSTATUS status;
1969 TALLOC_CTX *ctx = talloc_tos();
1971 START_PROFILE(SMBopen);
1973 if (req->wct < 2) {
1974 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1975 goto out;
1978 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1979 deny_mode = SVAL(req->vwv+0, 0);
1980 dos_attr = SVAL(req->vwv+1, 0);
1982 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1983 STR_TERMINATE, &status);
1984 if (!NT_STATUS_IS_OK(status)) {
1985 reply_nterror(req, status);
1986 goto out;
1989 if (!map_open_params_to_ntcreate(fname, deny_mode,
1990 OPENX_FILE_EXISTS_OPEN, &access_mask,
1991 &share_mode, &create_disposition,
1992 &create_options, &private_flags)) {
1993 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1994 goto out;
1997 status = filename_convert(ctx,
1998 conn,
1999 req->flags2 & FLAGS2_DFS_PATHNAMES,
2000 fname,
2001 UCF_PREP_CREATEFILE,
2002 NULL,
2003 &smb_fname);
2004 if (!NT_STATUS_IS_OK(status)) {
2005 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2006 reply_botherror(req,
2007 NT_STATUS_PATH_NOT_COVERED,
2008 ERRSRV, ERRbadpath);
2009 goto out;
2011 reply_nterror(req, status);
2012 goto out;
2015 status = SMB_VFS_CREATE_FILE(
2016 conn, /* conn */
2017 req, /* req */
2018 0, /* root_dir_fid */
2019 smb_fname, /* fname */
2020 access_mask, /* access_mask */
2021 share_mode, /* share_access */
2022 create_disposition, /* create_disposition*/
2023 create_options, /* create_options */
2024 dos_attr, /* file_attributes */
2025 oplock_request, /* oplock_request */
2026 NULL, /* lease */
2027 0, /* allocation_size */
2028 private_flags,
2029 NULL, /* sd */
2030 NULL, /* ea_list */
2031 &fsp, /* result */
2032 &info, /* pinfo */
2033 NULL, NULL); /* create context */
2035 if (!NT_STATUS_IS_OK(status)) {
2036 if (open_was_deferred(req->xconn, req->mid)) {
2037 /* We have re-scheduled this call. */
2038 goto out;
2040 reply_openerror(req, status);
2041 goto out;
2044 /* Ensure we're pointing at the correct stat struct. */
2045 TALLOC_FREE(smb_fname);
2046 smb_fname = fsp->fsp_name;
2048 size = smb_fname->st.st_ex_size;
2049 fattr = dos_mode(conn, smb_fname);
2051 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2053 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2054 DEBUG(3,("attempt to open a directory %s\n",
2055 fsp_str_dbg(fsp)));
2056 close_file(req, fsp, ERROR_CLOSE);
2057 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2058 ERRDOS, ERRnoaccess);
2059 goto out;
2062 reply_outbuf(req, 7, 0);
2063 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2064 SSVAL(req->outbuf,smb_vwv1,fattr);
2065 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2066 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2067 } else {
2068 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2070 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2071 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2073 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2074 SCVAL(req->outbuf,smb_flg,
2075 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2078 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2079 SCVAL(req->outbuf,smb_flg,
2080 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2082 out:
2083 END_PROFILE(SMBopen);
2084 return;
2087 /****************************************************************************
2088 Reply to an open and X.
2089 ****************************************************************************/
2091 void reply_open_and_X(struct smb_request *req)
2093 connection_struct *conn = req->conn;
2094 struct smb_filename *smb_fname = NULL;
2095 char *fname = NULL;
2096 uint16_t open_flags;
2097 int deny_mode;
2098 uint32_t smb_attr;
2099 /* Breakout the oplock request bits so we can set the
2100 reply bits separately. */
2101 int ex_oplock_request;
2102 int core_oplock_request;
2103 int oplock_request;
2104 #if 0
2105 int smb_sattr = SVAL(req->vwv+4, 0);
2106 uint32_t smb_time = make_unix_date3(req->vwv+6);
2107 #endif
2108 int smb_ofun;
2109 uint32_t fattr=0;
2110 int mtime=0;
2111 int smb_action = 0;
2112 files_struct *fsp;
2113 NTSTATUS status;
2114 uint64_t allocation_size;
2115 ssize_t retval = -1;
2116 uint32_t access_mask;
2117 uint32_t share_mode;
2118 uint32_t create_disposition;
2119 uint32_t create_options = 0;
2120 uint32_t private_flags = 0;
2121 TALLOC_CTX *ctx = talloc_tos();
2123 START_PROFILE(SMBopenX);
2125 if (req->wct < 15) {
2126 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2127 goto out;
2130 open_flags = SVAL(req->vwv+2, 0);
2131 deny_mode = SVAL(req->vwv+3, 0);
2132 smb_attr = SVAL(req->vwv+5, 0);
2133 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2134 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2135 oplock_request = ex_oplock_request | core_oplock_request;
2136 smb_ofun = SVAL(req->vwv+8, 0);
2137 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2139 /* If it's an IPC, pass off the pipe handler. */
2140 if (IS_IPC(conn)) {
2141 if (lp_nt_pipe_support()) {
2142 reply_open_pipe_and_X(conn, req);
2143 } else {
2144 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2146 goto out;
2149 /* XXXX we need to handle passed times, sattr and flags */
2150 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2151 STR_TERMINATE, &status);
2152 if (!NT_STATUS_IS_OK(status)) {
2153 reply_nterror(req, status);
2154 goto out;
2157 if (!map_open_params_to_ntcreate(fname, deny_mode,
2158 smb_ofun,
2159 &access_mask, &share_mode,
2160 &create_disposition,
2161 &create_options,
2162 &private_flags)) {
2163 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2164 goto out;
2167 status = filename_convert(ctx,
2168 conn,
2169 req->flags2 & FLAGS2_DFS_PATHNAMES,
2170 fname,
2171 UCF_PREP_CREATEFILE,
2172 NULL,
2173 &smb_fname);
2174 if (!NT_STATUS_IS_OK(status)) {
2175 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2176 reply_botherror(req,
2177 NT_STATUS_PATH_NOT_COVERED,
2178 ERRSRV, ERRbadpath);
2179 goto out;
2181 reply_nterror(req, status);
2182 goto out;
2185 status = SMB_VFS_CREATE_FILE(
2186 conn, /* conn */
2187 req, /* req */
2188 0, /* root_dir_fid */
2189 smb_fname, /* fname */
2190 access_mask, /* access_mask */
2191 share_mode, /* share_access */
2192 create_disposition, /* create_disposition*/
2193 create_options, /* create_options */
2194 smb_attr, /* file_attributes */
2195 oplock_request, /* oplock_request */
2196 NULL, /* lease */
2197 0, /* allocation_size */
2198 private_flags,
2199 NULL, /* sd */
2200 NULL, /* ea_list */
2201 &fsp, /* result */
2202 &smb_action, /* pinfo */
2203 NULL, NULL); /* create context */
2205 if (!NT_STATUS_IS_OK(status)) {
2206 if (open_was_deferred(req->xconn, req->mid)) {
2207 /* We have re-scheduled this call. */
2208 goto out;
2210 reply_openerror(req, status);
2211 goto out;
2214 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2215 if the file is truncated or created. */
2216 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2217 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2218 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2219 close_file(req, fsp, ERROR_CLOSE);
2220 reply_nterror(req, NT_STATUS_DISK_FULL);
2221 goto out;
2223 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2224 if (retval < 0) {
2225 close_file(req, fsp, ERROR_CLOSE);
2226 reply_nterror(req, NT_STATUS_DISK_FULL);
2227 goto out;
2229 status = vfs_stat_fsp(fsp);
2230 if (!NT_STATUS_IS_OK(status)) {
2231 close_file(req, fsp, ERROR_CLOSE);
2232 reply_nterror(req, status);
2233 goto out;
2237 fattr = dos_mode(conn, fsp->fsp_name);
2238 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2239 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2240 close_file(req, fsp, ERROR_CLOSE);
2241 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2242 goto out;
2245 /* If the caller set the extended oplock request bit
2246 and we granted one (by whatever means) - set the
2247 correct bit for extended oplock reply.
2250 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2251 smb_action |= EXTENDED_OPLOCK_GRANTED;
2254 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2255 smb_action |= EXTENDED_OPLOCK_GRANTED;
2258 /* If the caller set the core oplock request bit
2259 and we granted one (by whatever means) - set the
2260 correct bit for core oplock reply.
2263 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2264 reply_outbuf(req, 19, 0);
2265 } else {
2266 reply_outbuf(req, 15, 0);
2269 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2270 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2272 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2273 SCVAL(req->outbuf, smb_flg,
2274 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2277 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2278 SCVAL(req->outbuf, smb_flg,
2279 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2282 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2283 SSVAL(req->outbuf,smb_vwv3,fattr);
2284 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2285 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2286 } else {
2287 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2289 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2290 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2291 SSVAL(req->outbuf,smb_vwv11,smb_action);
2293 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2294 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2297 out:
2298 TALLOC_FREE(smb_fname);
2299 END_PROFILE(SMBopenX);
2300 return;
2303 /****************************************************************************
2304 Reply to a SMBulogoffX.
2305 ****************************************************************************/
2307 void reply_ulogoffX(struct smb_request *req)
2309 struct smbd_server_connection *sconn = req->sconn;
2310 struct user_struct *vuser;
2311 struct smbXsrv_session *session = NULL;
2312 NTSTATUS status;
2314 START_PROFILE(SMBulogoffX);
2316 vuser = get_valid_user_struct(sconn, req->vuid);
2318 if(vuser == NULL) {
2319 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2320 (unsigned long long)req->vuid));
2322 req->vuid = UID_FIELD_INVALID;
2323 reply_force_doserror(req, ERRSRV, ERRbaduid);
2324 END_PROFILE(SMBulogoffX);
2325 return;
2328 session = vuser->session;
2329 vuser = NULL;
2332 * TODO: cancel all outstanding requests on the session
2334 status = smbXsrv_session_logoff(session);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 DEBUG(0, ("reply_ulogoff: "
2337 "smbXsrv_session_logoff() failed: %s\n",
2338 nt_errstr(status)));
2340 * If we hit this case, there is something completely
2341 * wrong, so we better disconnect the transport connection.
2343 END_PROFILE(SMBulogoffX);
2344 exit_server(__location__ ": smbXsrv_session_logoff failed");
2345 return;
2348 TALLOC_FREE(session);
2350 reply_outbuf(req, 2, 0);
2351 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2352 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2354 DEBUG(3, ("ulogoffX vuid=%llu\n",
2355 (unsigned long long)req->vuid));
2357 END_PROFILE(SMBulogoffX);
2358 req->vuid = UID_FIELD_INVALID;
2361 /****************************************************************************
2362 Reply to a mknew or a create.
2363 ****************************************************************************/
2365 void reply_mknew(struct smb_request *req)
2367 connection_struct *conn = req->conn;
2368 struct smb_filename *smb_fname = NULL;
2369 char *fname = NULL;
2370 uint32_t fattr = 0;
2371 struct smb_file_time ft;
2372 files_struct *fsp;
2373 int oplock_request = 0;
2374 NTSTATUS status;
2375 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2376 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2377 uint32_t create_disposition;
2378 uint32_t create_options = 0;
2379 TALLOC_CTX *ctx = talloc_tos();
2381 START_PROFILE(SMBcreate);
2382 ZERO_STRUCT(ft);
2384 if (req->wct < 3) {
2385 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2386 goto out;
2389 fattr = SVAL(req->vwv+0, 0);
2390 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2392 /* mtime. */
2393 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2395 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2396 STR_TERMINATE, &status);
2397 if (!NT_STATUS_IS_OK(status)) {
2398 reply_nterror(req, status);
2399 goto out;
2402 status = filename_convert(ctx,
2403 conn,
2404 req->flags2 & FLAGS2_DFS_PATHNAMES,
2405 fname,
2406 UCF_PREP_CREATEFILE,
2407 NULL,
2408 &smb_fname);
2409 if (!NT_STATUS_IS_OK(status)) {
2410 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2411 reply_botherror(req,
2412 NT_STATUS_PATH_NOT_COVERED,
2413 ERRSRV, ERRbadpath);
2414 goto out;
2416 reply_nterror(req, status);
2417 goto out;
2420 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2421 DEBUG(0,("Attempt to create file (%s) with volid set - "
2422 "please report this\n",
2423 smb_fname_str_dbg(smb_fname)));
2426 if(req->cmd == SMBmknew) {
2427 /* We should fail if file exists. */
2428 create_disposition = FILE_CREATE;
2429 } else {
2430 /* Create if file doesn't exist, truncate if it does. */
2431 create_disposition = FILE_OVERWRITE_IF;
2434 status = SMB_VFS_CREATE_FILE(
2435 conn, /* conn */
2436 req, /* req */
2437 0, /* root_dir_fid */
2438 smb_fname, /* fname */
2439 access_mask, /* access_mask */
2440 share_mode, /* share_access */
2441 create_disposition, /* create_disposition*/
2442 create_options, /* create_options */
2443 fattr, /* file_attributes */
2444 oplock_request, /* oplock_request */
2445 NULL, /* lease */
2446 0, /* allocation_size */
2447 0, /* private_flags */
2448 NULL, /* sd */
2449 NULL, /* ea_list */
2450 &fsp, /* result */
2451 NULL, /* pinfo */
2452 NULL, NULL); /* create context */
2454 if (!NT_STATUS_IS_OK(status)) {
2455 if (open_was_deferred(req->xconn, req->mid)) {
2456 /* We have re-scheduled this call. */
2457 goto out;
2459 reply_openerror(req, status);
2460 goto out;
2463 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2464 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2465 if (!NT_STATUS_IS_OK(status)) {
2466 END_PROFILE(SMBcreate);
2467 goto out;
2470 reply_outbuf(req, 1, 0);
2471 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2473 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2474 SCVAL(req->outbuf,smb_flg,
2475 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2478 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2479 SCVAL(req->outbuf,smb_flg,
2480 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2483 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2484 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2485 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2486 (unsigned int)fattr));
2488 out:
2489 TALLOC_FREE(smb_fname);
2490 END_PROFILE(SMBcreate);
2491 return;
2494 /****************************************************************************
2495 Reply to a create temporary file.
2496 ****************************************************************************/
2498 void reply_ctemp(struct smb_request *req)
2500 connection_struct *conn = req->conn;
2501 struct smb_filename *smb_fname = NULL;
2502 char *wire_name = NULL;
2503 char *fname = NULL;
2504 uint32_t fattr;
2505 files_struct *fsp;
2506 int oplock_request;
2507 char *s;
2508 NTSTATUS status;
2509 int i;
2510 TALLOC_CTX *ctx = talloc_tos();
2512 START_PROFILE(SMBctemp);
2514 if (req->wct < 3) {
2515 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2516 goto out;
2519 fattr = SVAL(req->vwv+0, 0);
2520 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2522 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2523 STR_TERMINATE, &status);
2524 if (!NT_STATUS_IS_OK(status)) {
2525 reply_nterror(req, status);
2526 goto out;
2529 for (i = 0; i < 10; i++) {
2530 if (*wire_name) {
2531 fname = talloc_asprintf(ctx,
2532 "%s/TMP%s",
2533 wire_name,
2534 generate_random_str_list(ctx, 5, "0123456789"));
2535 } else {
2536 fname = talloc_asprintf(ctx,
2537 "TMP%s",
2538 generate_random_str_list(ctx, 5, "0123456789"));
2541 if (!fname) {
2542 reply_nterror(req, NT_STATUS_NO_MEMORY);
2543 goto out;
2546 status = filename_convert(ctx, conn,
2547 req->flags2 & FLAGS2_DFS_PATHNAMES,
2548 fname,
2549 UCF_PREP_CREATEFILE,
2550 NULL,
2551 &smb_fname);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2554 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2555 ERRSRV, ERRbadpath);
2556 goto out;
2558 reply_nterror(req, status);
2559 goto out;
2562 /* Create the file. */
2563 status = SMB_VFS_CREATE_FILE(
2564 conn, /* conn */
2565 req, /* req */
2566 0, /* root_dir_fid */
2567 smb_fname, /* fname */
2568 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2569 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2570 FILE_CREATE, /* create_disposition*/
2571 0, /* create_options */
2572 fattr, /* file_attributes */
2573 oplock_request, /* oplock_request */
2574 NULL, /* lease */
2575 0, /* allocation_size */
2576 0, /* private_flags */
2577 NULL, /* sd */
2578 NULL, /* ea_list */
2579 &fsp, /* result */
2580 NULL, /* pinfo */
2581 NULL, NULL); /* create context */
2583 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2584 TALLOC_FREE(fname);
2585 TALLOC_FREE(smb_fname);
2586 continue;
2589 if (!NT_STATUS_IS_OK(status)) {
2590 if (open_was_deferred(req->xconn, req->mid)) {
2591 /* We have re-scheduled this call. */
2592 goto out;
2594 reply_openerror(req, status);
2595 goto out;
2598 break;
2601 if (i == 10) {
2602 /* Collision after 10 times... */
2603 reply_nterror(req, status);
2604 goto out;
2607 reply_outbuf(req, 1, 0);
2608 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2610 /* the returned filename is relative to the directory */
2611 s = strrchr_m(fsp->fsp_name->base_name, '/');
2612 if (!s) {
2613 s = fsp->fsp_name->base_name;
2614 } else {
2615 s++;
2618 #if 0
2619 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2620 thing in the byte section. JRA */
2621 SSVALS(p, 0, -1); /* what is this? not in spec */
2622 #endif
2623 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2624 == -1) {
2625 reply_nterror(req, NT_STATUS_NO_MEMORY);
2626 goto out;
2629 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2630 SCVAL(req->outbuf, smb_flg,
2631 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2634 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2635 SCVAL(req->outbuf, smb_flg,
2636 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2639 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2640 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2641 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2642 out:
2643 TALLOC_FREE(smb_fname);
2644 TALLOC_FREE(wire_name);
2645 END_PROFILE(SMBctemp);
2646 return;
2649 /*******************************************************************
2650 Check if a user is allowed to rename a file.
2651 ********************************************************************/
2653 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2654 uint16_t dirtype)
2656 if (!CAN_WRITE(conn)) {
2657 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2660 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2661 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2662 /* Only bother to read the DOS attribute if we might deny the
2663 rename on the grounds of attribute missmatch. */
2664 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2665 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2666 return NT_STATUS_NO_SUCH_FILE;
2670 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2671 if (fsp->posix_open) {
2672 return NT_STATUS_OK;
2675 /* If no pathnames are open below this
2676 directory, allow the rename. */
2678 if (file_find_subpath(fsp)) {
2679 return NT_STATUS_ACCESS_DENIED;
2681 return NT_STATUS_OK;
2684 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2685 return NT_STATUS_OK;
2688 return NT_STATUS_ACCESS_DENIED;
2691 /*******************************************************************
2692 * unlink a file with all relevant access checks
2693 *******************************************************************/
2695 static NTSTATUS do_unlink(connection_struct *conn,
2696 struct smb_request *req,
2697 struct smb_filename *smb_fname,
2698 uint32_t dirtype)
2700 uint32_t fattr;
2701 files_struct *fsp;
2702 uint32_t dirtype_orig = dirtype;
2703 NTSTATUS status;
2704 int ret;
2705 bool posix_paths = lp_posix_pathnames();
2707 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2708 smb_fname_str_dbg(smb_fname),
2709 dirtype));
2711 if (!CAN_WRITE(conn)) {
2712 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2715 if (posix_paths) {
2716 ret = SMB_VFS_LSTAT(conn, smb_fname);
2717 } else {
2718 ret = SMB_VFS_STAT(conn, smb_fname);
2720 if (ret != 0) {
2721 return map_nt_error_from_unix(errno);
2724 fattr = dos_mode(conn, smb_fname);
2726 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2727 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2730 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2731 if (!dirtype) {
2732 return NT_STATUS_NO_SUCH_FILE;
2735 if (!dir_check_ftype(fattr, dirtype)) {
2736 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2737 return NT_STATUS_FILE_IS_A_DIRECTORY;
2739 return NT_STATUS_NO_SUCH_FILE;
2742 if (dirtype_orig & 0x8000) {
2743 /* These will never be set for POSIX. */
2744 return NT_STATUS_NO_SUCH_FILE;
2747 #if 0
2748 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2749 return NT_STATUS_FILE_IS_A_DIRECTORY;
2752 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2753 return NT_STATUS_NO_SUCH_FILE;
2756 if (dirtype & 0xFF00) {
2757 /* These will never be set for POSIX. */
2758 return NT_STATUS_NO_SUCH_FILE;
2761 dirtype &= 0xFF;
2762 if (!dirtype) {
2763 return NT_STATUS_NO_SUCH_FILE;
2766 /* Can't delete a directory. */
2767 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2768 return NT_STATUS_FILE_IS_A_DIRECTORY;
2770 #endif
2772 #if 0 /* JRATEST */
2773 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2774 return NT_STATUS_OBJECT_NAME_INVALID;
2775 #endif /* JRATEST */
2777 /* On open checks the open itself will check the share mode, so
2778 don't do it here as we'll get it wrong. */
2780 status = SMB_VFS_CREATE_FILE
2781 (conn, /* conn */
2782 req, /* req */
2783 0, /* root_dir_fid */
2784 smb_fname, /* fname */
2785 DELETE_ACCESS, /* access_mask */
2786 FILE_SHARE_NONE, /* share_access */
2787 FILE_OPEN, /* create_disposition*/
2788 FILE_NON_DIRECTORY_FILE, /* create_options */
2789 /* file_attributes */
2790 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2791 FILE_ATTRIBUTE_NORMAL,
2792 0, /* oplock_request */
2793 NULL, /* lease */
2794 0, /* allocation_size */
2795 0, /* private_flags */
2796 NULL, /* sd */
2797 NULL, /* ea_list */
2798 &fsp, /* result */
2799 NULL, /* pinfo */
2800 NULL, NULL); /* create context */
2802 if (!NT_STATUS_IS_OK(status)) {
2803 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2804 nt_errstr(status)));
2805 return status;
2808 status = can_set_delete_on_close(fsp, fattr);
2809 if (!NT_STATUS_IS_OK(status)) {
2810 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2811 "(%s)\n",
2812 smb_fname_str_dbg(smb_fname),
2813 nt_errstr(status)));
2814 close_file(req, fsp, NORMAL_CLOSE);
2815 return status;
2818 /* The set is across all open files on this dev/inode pair. */
2819 if (!set_delete_on_close(fsp, True,
2820 conn->session_info->security_token,
2821 conn->session_info->unix_token)) {
2822 close_file(req, fsp, NORMAL_CLOSE);
2823 return NT_STATUS_ACCESS_DENIED;
2826 return close_file(req, fsp, NORMAL_CLOSE);
2829 /****************************************************************************
2830 The guts of the unlink command, split out so it may be called by the NT SMB
2831 code.
2832 ****************************************************************************/
2834 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2835 uint32_t dirtype, struct smb_filename *smb_fname,
2836 bool has_wild)
2838 char *fname_dir = NULL;
2839 char *fname_mask = NULL;
2840 int count=0;
2841 NTSTATUS status = NT_STATUS_OK;
2842 TALLOC_CTX *ctx = talloc_tos();
2844 /* Split up the directory from the filename/mask. */
2845 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2846 &fname_dir, &fname_mask);
2847 if (!NT_STATUS_IS_OK(status)) {
2848 goto out;
2852 * We should only check the mangled cache
2853 * here if unix_convert failed. This means
2854 * that the path in 'mask' doesn't exist
2855 * on the file system and so we need to look
2856 * for a possible mangle. This patch from
2857 * Tine Smukavec <valentin.smukavec@hermes.si>.
2860 if (!VALID_STAT(smb_fname->st) &&
2861 mangle_is_mangled(fname_mask, conn->params)) {
2862 char *new_mask = NULL;
2863 mangle_lookup_name_from_8_3(ctx, fname_mask,
2864 &new_mask, conn->params);
2865 if (new_mask) {
2866 TALLOC_FREE(fname_mask);
2867 fname_mask = new_mask;
2871 if (!has_wild) {
2874 * Only one file needs to be unlinked. Append the mask back
2875 * onto the directory.
2877 TALLOC_FREE(smb_fname->base_name);
2878 if (ISDOT(fname_dir)) {
2879 /* Ensure we use canonical names on open. */
2880 smb_fname->base_name = talloc_asprintf(smb_fname,
2881 "%s",
2882 fname_mask);
2883 } else {
2884 smb_fname->base_name = talloc_asprintf(smb_fname,
2885 "%s/%s",
2886 fname_dir,
2887 fname_mask);
2889 if (!smb_fname->base_name) {
2890 status = NT_STATUS_NO_MEMORY;
2891 goto out;
2893 if (dirtype == 0) {
2894 dirtype = FILE_ATTRIBUTE_NORMAL;
2897 status = check_name(conn, smb_fname->base_name);
2898 if (!NT_STATUS_IS_OK(status)) {
2899 goto out;
2902 status = do_unlink(conn, req, smb_fname, dirtype);
2903 if (!NT_STATUS_IS_OK(status)) {
2904 goto out;
2907 count++;
2908 } else {
2909 struct smb_Dir *dir_hnd = NULL;
2910 long offset = 0;
2911 const char *dname = NULL;
2912 char *talloced = NULL;
2914 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2915 status = NT_STATUS_OBJECT_NAME_INVALID;
2916 goto out;
2919 if (strequal(fname_mask,"????????.???")) {
2920 TALLOC_FREE(fname_mask);
2921 fname_mask = talloc_strdup(ctx, "*");
2922 if (!fname_mask) {
2923 status = NT_STATUS_NO_MEMORY;
2924 goto out;
2928 status = check_name(conn, fname_dir);
2929 if (!NT_STATUS_IS_OK(status)) {
2930 goto out;
2933 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2934 dirtype);
2935 if (dir_hnd == NULL) {
2936 status = map_nt_error_from_unix(errno);
2937 goto out;
2940 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2941 the pattern matches against the long name, otherwise the short name
2942 We don't implement this yet XXXX
2945 status = NT_STATUS_NO_SUCH_FILE;
2947 while ((dname = ReadDirName(dir_hnd, &offset,
2948 &smb_fname->st, &talloced))) {
2949 TALLOC_CTX *frame = talloc_stackframe();
2951 if (!is_visible_file(conn, fname_dir, dname,
2952 &smb_fname->st, true)) {
2953 TALLOC_FREE(frame);
2954 TALLOC_FREE(talloced);
2955 continue;
2958 /* Quick check for "." and ".." */
2959 if (ISDOT(dname) || ISDOTDOT(dname)) {
2960 TALLOC_FREE(frame);
2961 TALLOC_FREE(talloced);
2962 continue;
2965 if(!mask_match(dname, fname_mask,
2966 conn->case_sensitive)) {
2967 TALLOC_FREE(frame);
2968 TALLOC_FREE(talloced);
2969 continue;
2972 TALLOC_FREE(smb_fname->base_name);
2973 if (ISDOT(fname_dir)) {
2974 /* Ensure we use canonical names on open. */
2975 smb_fname->base_name =
2976 talloc_asprintf(smb_fname, "%s",
2977 dname);
2978 } else {
2979 smb_fname->base_name =
2980 talloc_asprintf(smb_fname, "%s/%s",
2981 fname_dir, dname);
2984 if (!smb_fname->base_name) {
2985 TALLOC_FREE(dir_hnd);
2986 status = NT_STATUS_NO_MEMORY;
2987 TALLOC_FREE(frame);
2988 TALLOC_FREE(talloced);
2989 goto out;
2992 status = check_name(conn, smb_fname->base_name);
2993 if (!NT_STATUS_IS_OK(status)) {
2994 TALLOC_FREE(dir_hnd);
2995 TALLOC_FREE(frame);
2996 TALLOC_FREE(talloced);
2997 goto out;
3000 status = do_unlink(conn, req, smb_fname, dirtype);
3001 if (!NT_STATUS_IS_OK(status)) {
3002 TALLOC_FREE(dir_hnd);
3003 TALLOC_FREE(frame);
3004 TALLOC_FREE(talloced);
3005 goto out;
3008 count++;
3009 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3010 smb_fname->base_name));
3012 TALLOC_FREE(frame);
3013 TALLOC_FREE(talloced);
3015 TALLOC_FREE(dir_hnd);
3018 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3019 status = map_nt_error_from_unix(errno);
3022 out:
3023 TALLOC_FREE(fname_dir);
3024 TALLOC_FREE(fname_mask);
3025 return status;
3028 /****************************************************************************
3029 Reply to a unlink
3030 ****************************************************************************/
3032 void reply_unlink(struct smb_request *req)
3034 connection_struct *conn = req->conn;
3035 char *name = NULL;
3036 struct smb_filename *smb_fname = NULL;
3037 uint32_t dirtype;
3038 NTSTATUS status;
3039 bool path_contains_wcard = False;
3040 TALLOC_CTX *ctx = talloc_tos();
3042 START_PROFILE(SMBunlink);
3044 if (req->wct < 1) {
3045 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3046 goto out;
3049 dirtype = SVAL(req->vwv+0, 0);
3051 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3052 STR_TERMINATE, &status,
3053 &path_contains_wcard);
3054 if (!NT_STATUS_IS_OK(status)) {
3055 reply_nterror(req, status);
3056 goto out;
3059 status = filename_convert(ctx, conn,
3060 req->flags2 & FLAGS2_DFS_PATHNAMES,
3061 name,
3062 UCF_COND_ALLOW_WCARD_LCOMP,
3063 &path_contains_wcard,
3064 &smb_fname);
3065 if (!NT_STATUS_IS_OK(status)) {
3066 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3067 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3068 ERRSRV, ERRbadpath);
3069 goto out;
3071 reply_nterror(req, status);
3072 goto out;
3075 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3077 status = unlink_internals(conn, req, dirtype, smb_fname,
3078 path_contains_wcard);
3079 if (!NT_STATUS_IS_OK(status)) {
3080 if (open_was_deferred(req->xconn, req->mid)) {
3081 /* We have re-scheduled this call. */
3082 goto out;
3084 reply_nterror(req, status);
3085 goto out;
3088 reply_outbuf(req, 0, 0);
3089 out:
3090 TALLOC_FREE(smb_fname);
3091 END_PROFILE(SMBunlink);
3092 return;
3095 /****************************************************************************
3096 Fail for readbraw.
3097 ****************************************************************************/
3099 static void fail_readraw(void)
3101 const char *errstr = talloc_asprintf(talloc_tos(),
3102 "FAIL ! reply_readbraw: socket write fail (%s)",
3103 strerror(errno));
3104 if (!errstr) {
3105 errstr = "";
3107 exit_server_cleanly(errstr);
3110 /****************************************************************************
3111 Fake (read/write) sendfile. Returns -1 on read or write fail.
3112 ****************************************************************************/
3114 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3115 off_t startpos, size_t nread)
3117 size_t bufsize;
3118 size_t tosend = nread;
3119 char *buf;
3121 if (nread == 0) {
3122 return 0;
3125 bufsize = MIN(nread, 65536);
3127 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3128 return -1;
3131 while (tosend > 0) {
3132 ssize_t ret;
3133 size_t cur_read;
3135 cur_read = MIN(tosend, bufsize);
3136 ret = read_file(fsp,buf,startpos,cur_read);
3137 if (ret == -1) {
3138 SAFE_FREE(buf);
3139 return -1;
3142 /* If we had a short read, fill with zeros. */
3143 if (ret < cur_read) {
3144 memset(buf + ret, '\0', cur_read - ret);
3147 ret = write_data(xconn->transport.sock, buf, cur_read);
3148 if (ret != cur_read) {
3149 int saved_errno = errno;
3151 * Try and give an error message saying what
3152 * client failed.
3154 DEBUG(0, ("write_data failed for client %s. "
3155 "Error %s\n",
3156 smbXsrv_connection_dbg(xconn),
3157 strerror(saved_errno)));
3158 SAFE_FREE(buf);
3159 errno = saved_errno;
3160 return -1;
3162 tosend -= cur_read;
3163 startpos += cur_read;
3166 SAFE_FREE(buf);
3167 return (ssize_t)nread;
3170 /****************************************************************************
3171 Deal with the case of sendfile reading less bytes from the file than
3172 requested. Fill with zeros (all we can do). Returns 0 on success
3173 ****************************************************************************/
3175 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3176 files_struct *fsp,
3177 ssize_t nread,
3178 size_t headersize,
3179 size_t smb_maxcnt)
3181 #define SHORT_SEND_BUFSIZE 1024
3182 if (nread < headersize) {
3183 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3184 "header for file %s (%s). Terminating\n",
3185 fsp_str_dbg(fsp), strerror(errno)));
3186 return -1;
3189 nread -= headersize;
3191 if (nread < smb_maxcnt) {
3192 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3193 if (!buf) {
3194 DEBUG(0,("sendfile_short_send: malloc failed "
3195 "for file %s (%s). Terminating\n",
3196 fsp_str_dbg(fsp), strerror(errno)));
3197 return -1;
3200 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3201 "with zeros !\n", fsp_str_dbg(fsp)));
3203 while (nread < smb_maxcnt) {
3205 * We asked for the real file size and told sendfile
3206 * to not go beyond the end of the file. But it can
3207 * happen that in between our fstat call and the
3208 * sendfile call the file was truncated. This is very
3209 * bad because we have already announced the larger
3210 * number of bytes to the client.
3212 * The best we can do now is to send 0-bytes, just as
3213 * a read from a hole in a sparse file would do.
3215 * This should happen rarely enough that I don't care
3216 * about efficiency here :-)
3218 size_t to_write;
3219 ssize_t ret;
3221 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3222 ret = write_data(xconn->transport.sock, buf, to_write);
3223 if (ret != to_write) {
3224 int saved_errno = errno;
3226 * Try and give an error message saying what
3227 * client failed.
3229 DEBUG(0, ("write_data failed for client %s. "
3230 "Error %s\n",
3231 smbXsrv_connection_dbg(xconn),
3232 strerror(saved_errno)));
3233 errno = saved_errno;
3234 return -1;
3236 nread += to_write;
3238 SAFE_FREE(buf);
3241 return 0;
3244 /****************************************************************************
3245 Return a readbraw error (4 bytes of zero).
3246 ****************************************************************************/
3248 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3250 char header[4];
3252 SIVAL(header,0,0);
3254 smbd_lock_socket(xconn);
3255 if (write_data(xconn->transport.sock,header,4) != 4) {
3256 int saved_errno = errno;
3258 * Try and give an error message saying what
3259 * client failed.
3261 DEBUG(0, ("write_data failed for client %s. "
3262 "Error %s\n",
3263 smbXsrv_connection_dbg(xconn),
3264 strerror(saved_errno)));
3265 errno = saved_errno;
3267 fail_readraw();
3269 smbd_unlock_socket(xconn);
3272 /****************************************************************************
3273 Use sendfile in readbraw.
3274 ****************************************************************************/
3276 static void send_file_readbraw(connection_struct *conn,
3277 struct smb_request *req,
3278 files_struct *fsp,
3279 off_t startpos,
3280 size_t nread,
3281 ssize_t mincount)
3283 struct smbXsrv_connection *xconn = req->xconn;
3284 char *outbuf = NULL;
3285 ssize_t ret=0;
3288 * We can only use sendfile on a non-chained packet
3289 * but we can use on a non-oplocked file. tridge proved this
3290 * on a train in Germany :-). JRA.
3291 * reply_readbraw has already checked the length.
3294 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3295 (fsp->wcp == NULL) &&
3296 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3297 ssize_t sendfile_read = -1;
3298 char header[4];
3299 DATA_BLOB header_blob;
3301 _smb_setlen(header,nread);
3302 header_blob = data_blob_const(header, 4);
3304 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3305 &header_blob, startpos,
3306 nread);
3307 if (sendfile_read == -1) {
3308 /* Returning ENOSYS means no data at all was sent.
3309 * Do this as a normal read. */
3310 if (errno == ENOSYS) {
3311 goto normal_readbraw;
3315 * Special hack for broken Linux with no working sendfile. If we
3316 * return EINTR we sent the header but not the rest of the data.
3317 * Fake this up by doing read/write calls.
3319 if (errno == EINTR) {
3320 /* Ensure we don't do this again. */
3321 set_use_sendfile(SNUM(conn), False);
3322 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3324 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3325 DEBUG(0,("send_file_readbraw: "
3326 "fake_sendfile failed for "
3327 "file %s (%s).\n",
3328 fsp_str_dbg(fsp),
3329 strerror(errno)));
3330 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3332 return;
3335 DEBUG(0,("send_file_readbraw: sendfile failed for "
3336 "file %s (%s). Terminating\n",
3337 fsp_str_dbg(fsp), strerror(errno)));
3338 exit_server_cleanly("send_file_readbraw sendfile failed");
3339 } else if (sendfile_read == 0) {
3341 * Some sendfile implementations return 0 to indicate
3342 * that there was a short read, but nothing was
3343 * actually written to the socket. In this case,
3344 * fallback to the normal read path so the header gets
3345 * the correct byte count.
3347 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3348 "bytes falling back to the normal read: "
3349 "%s\n", fsp_str_dbg(fsp)));
3350 goto normal_readbraw;
3353 /* Deal with possible short send. */
3354 if (sendfile_read != 4+nread) {
3355 ret = sendfile_short_send(xconn, fsp,
3356 sendfile_read, 4, nread);
3357 if (ret == -1) {
3358 fail_readraw();
3361 return;
3364 normal_readbraw:
3366 outbuf = talloc_array(NULL, char, nread+4);
3367 if (!outbuf) {
3368 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3369 (unsigned)(nread+4)));
3370 reply_readbraw_error(xconn);
3371 return;
3374 if (nread > 0) {
3375 ret = read_file(fsp,outbuf+4,startpos,nread);
3376 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3377 if (ret < mincount)
3378 ret = 0;
3379 #else
3380 if (ret < nread)
3381 ret = 0;
3382 #endif
3385 _smb_setlen(outbuf,ret);
3386 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3387 int saved_errno = errno;
3389 * Try and give an error message saying what
3390 * client failed.
3392 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3393 smbXsrv_connection_dbg(xconn),
3394 strerror(saved_errno)));
3395 errno = saved_errno;
3397 fail_readraw();
3400 TALLOC_FREE(outbuf);
3403 /****************************************************************************
3404 Reply to a readbraw (core+ protocol).
3405 ****************************************************************************/
3407 void reply_readbraw(struct smb_request *req)
3409 connection_struct *conn = req->conn;
3410 struct smbXsrv_connection *xconn = req->xconn;
3411 ssize_t maxcount,mincount;
3412 size_t nread = 0;
3413 off_t startpos;
3414 files_struct *fsp;
3415 struct lock_struct lock;
3416 off_t size = 0;
3418 START_PROFILE(SMBreadbraw);
3420 if (srv_is_signing_active(xconn) || req->encrypted) {
3421 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3422 "raw reads/writes are disallowed.");
3425 if (req->wct < 8) {
3426 reply_readbraw_error(xconn);
3427 END_PROFILE(SMBreadbraw);
3428 return;
3431 if (xconn->smb1.echo_handler.trusted_fde) {
3432 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3433 "'async smb echo handler = yes'\n"));
3434 reply_readbraw_error(xconn);
3435 END_PROFILE(SMBreadbraw);
3436 return;
3440 * Special check if an oplock break has been issued
3441 * and the readraw request croses on the wire, we must
3442 * return a zero length response here.
3445 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3448 * We have to do a check_fsp by hand here, as
3449 * we must always return 4 zero bytes on error,
3450 * not a NTSTATUS.
3453 if (!fsp || !conn || conn != fsp->conn ||
3454 req->vuid != fsp->vuid ||
3455 fsp->is_directory || fsp->fh->fd == -1) {
3457 * fsp could be NULL here so use the value from the packet. JRA.
3459 DEBUG(3,("reply_readbraw: fnum %d not valid "
3460 "- cache prime?\n",
3461 (int)SVAL(req->vwv+0, 0)));
3462 reply_readbraw_error(xconn);
3463 END_PROFILE(SMBreadbraw);
3464 return;
3467 /* Do a "by hand" version of CHECK_READ. */
3468 if (!(fsp->can_read ||
3469 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3470 (fsp->access_mask & FILE_EXECUTE)))) {
3471 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3472 (int)SVAL(req->vwv+0, 0)));
3473 reply_readbraw_error(xconn);
3474 END_PROFILE(SMBreadbraw);
3475 return;
3478 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3480 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3481 if(req->wct == 10) {
3483 * This is a large offset (64 bit) read.
3486 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3488 if(startpos < 0) {
3489 DEBUG(0,("reply_readbraw: negative 64 bit "
3490 "readraw offset (%.0f) !\n",
3491 (double)startpos ));
3492 reply_readbraw_error(xconn);
3493 END_PROFILE(SMBreadbraw);
3494 return;
3498 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3499 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3501 /* ensure we don't overrun the packet size */
3502 maxcount = MIN(65535,maxcount);
3504 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3505 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3506 &lock);
3508 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3509 reply_readbraw_error(xconn);
3510 END_PROFILE(SMBreadbraw);
3511 return;
3514 if (fsp_stat(fsp) == 0) {
3515 size = fsp->fsp_name->st.st_ex_size;
3518 if (startpos >= size) {
3519 nread = 0;
3520 } else {
3521 nread = MIN(maxcount,(size - startpos));
3524 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3525 if (nread < mincount)
3526 nread = 0;
3527 #endif
3529 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3530 "min=%lu nread=%lu\n",
3531 fsp_fnum_dbg(fsp), (double)startpos,
3532 (unsigned long)maxcount,
3533 (unsigned long)mincount,
3534 (unsigned long)nread ) );
3536 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3538 DEBUG(5,("reply_readbraw finished\n"));
3540 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3542 END_PROFILE(SMBreadbraw);
3543 return;
3546 #undef DBGC_CLASS
3547 #define DBGC_CLASS DBGC_LOCKING
3549 /****************************************************************************
3550 Reply to a lockread (core+ protocol).
3551 ****************************************************************************/
3553 void reply_lockread(struct smb_request *req)
3555 connection_struct *conn = req->conn;
3556 ssize_t nread = -1;
3557 char *data;
3558 off_t startpos;
3559 size_t numtoread;
3560 size_t maxtoread;
3561 NTSTATUS status;
3562 files_struct *fsp;
3563 struct byte_range_lock *br_lck = NULL;
3564 char *p = NULL;
3565 struct smbXsrv_connection *xconn = req->xconn;
3567 START_PROFILE(SMBlockread);
3569 if (req->wct < 5) {
3570 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3571 END_PROFILE(SMBlockread);
3572 return;
3575 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3577 if (!check_fsp(conn, req, fsp)) {
3578 END_PROFILE(SMBlockread);
3579 return;
3582 if (!CHECK_READ(fsp,req)) {
3583 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3584 END_PROFILE(SMBlockread);
3585 return;
3588 numtoread = SVAL(req->vwv+1, 0);
3589 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3592 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3593 * protocol request that predates the read/write lock concept.
3594 * Thus instead of asking for a read lock here we need to ask
3595 * for a write lock. JRA.
3596 * Note that the requested lock size is unaffected by max_send.
3599 br_lck = do_lock(req->sconn->msg_ctx,
3600 fsp,
3601 (uint64_t)req->smbpid,
3602 (uint64_t)numtoread,
3603 (uint64_t)startpos,
3604 WRITE_LOCK,
3605 WINDOWS_LOCK,
3606 False, /* Non-blocking lock. */
3607 &status,
3608 NULL);
3609 TALLOC_FREE(br_lck);
3611 if (NT_STATUS_V(status)) {
3612 reply_nterror(req, status);
3613 END_PROFILE(SMBlockread);
3614 return;
3618 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3620 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3622 if (numtoread > maxtoread) {
3623 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3624 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3625 (unsigned int)numtoread, (unsigned int)maxtoread,
3626 (unsigned int)xconn->smb1.sessions.max_send));
3627 numtoread = maxtoread;
3630 reply_outbuf(req, 5, numtoread + 3);
3632 data = smb_buf(req->outbuf) + 3;
3634 nread = read_file(fsp,data,startpos,numtoread);
3636 if (nread < 0) {
3637 reply_nterror(req, map_nt_error_from_unix(errno));
3638 END_PROFILE(SMBlockread);
3639 return;
3642 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3644 SSVAL(req->outbuf,smb_vwv0,nread);
3645 SSVAL(req->outbuf,smb_vwv5,nread+3);
3646 p = smb_buf(req->outbuf);
3647 SCVAL(p,0,0); /* pad byte. */
3648 SSVAL(p,1,nread);
3650 DEBUG(3,("lockread %s num=%d nread=%d\n",
3651 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3653 END_PROFILE(SMBlockread);
3654 return;
3657 #undef DBGC_CLASS
3658 #define DBGC_CLASS DBGC_ALL
3660 /****************************************************************************
3661 Reply to a read.
3662 ****************************************************************************/
3664 void reply_read(struct smb_request *req)
3666 connection_struct *conn = req->conn;
3667 size_t numtoread;
3668 size_t maxtoread;
3669 ssize_t nread = 0;
3670 char *data;
3671 off_t startpos;
3672 files_struct *fsp;
3673 struct lock_struct lock;
3674 struct smbXsrv_connection *xconn = req->xconn;
3676 START_PROFILE(SMBread);
3678 if (req->wct < 3) {
3679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3680 END_PROFILE(SMBread);
3681 return;
3684 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3686 if (!check_fsp(conn, req, fsp)) {
3687 END_PROFILE(SMBread);
3688 return;
3691 if (!CHECK_READ(fsp,req)) {
3692 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3693 END_PROFILE(SMBread);
3694 return;
3697 numtoread = SVAL(req->vwv+1, 0);
3698 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3701 * The requested read size cannot be greater than max_send. JRA.
3703 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3705 if (numtoread > maxtoread) {
3706 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3707 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3708 (unsigned int)numtoread, (unsigned int)maxtoread,
3709 (unsigned int)xconn->smb1.sessions.max_send));
3710 numtoread = maxtoread;
3713 reply_outbuf(req, 5, numtoread+3);
3715 data = smb_buf(req->outbuf) + 3;
3717 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3718 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3719 &lock);
3721 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3722 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3723 END_PROFILE(SMBread);
3724 return;
3727 if (numtoread > 0)
3728 nread = read_file(fsp,data,startpos,numtoread);
3730 if (nread < 0) {
3731 reply_nterror(req, map_nt_error_from_unix(errno));
3732 goto strict_unlock;
3735 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3737 SSVAL(req->outbuf,smb_vwv0,nread);
3738 SSVAL(req->outbuf,smb_vwv5,nread+3);
3739 SCVAL(smb_buf(req->outbuf),0,1);
3740 SSVAL(smb_buf(req->outbuf),1,nread);
3742 DEBUG(3, ("read %s num=%d nread=%d\n",
3743 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3745 strict_unlock:
3746 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3748 END_PROFILE(SMBread);
3749 return;
3752 /****************************************************************************
3753 Setup readX header.
3754 ****************************************************************************/
3756 static int setup_readX_header(struct smb_request *req, char *outbuf,
3757 size_t smb_maxcnt)
3759 int outsize;
3761 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3762 False);
3764 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3766 SCVAL(outbuf,smb_vwv0,0xFF);
3767 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3768 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3769 SSVAL(outbuf,smb_vwv6,
3770 (smb_wct - 4) /* offset from smb header to wct */
3771 + 1 /* the wct field */
3772 + 12 * sizeof(uint16_t) /* vwv */
3773 + 2 /* the buflen field */
3774 + 1); /* padding byte */
3775 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3776 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3777 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3778 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3779 _smb_setlen_large(outbuf,
3780 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3781 return outsize;
3784 /****************************************************************************
3785 Reply to a read and X - possibly using sendfile.
3786 ****************************************************************************/
3788 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3789 files_struct *fsp, off_t startpos,
3790 size_t smb_maxcnt)
3792 struct smbXsrv_connection *xconn = req->xconn;
3793 ssize_t nread = -1;
3794 struct lock_struct lock;
3795 int saved_errno = 0;
3797 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3798 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3799 &lock);
3801 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3802 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3803 return;
3807 * We can only use sendfile on a non-chained packet
3808 * but we can use on a non-oplocked file. tridge proved this
3809 * on a train in Germany :-). JRA.
3812 if (!req_is_in_chain(req) &&
3813 !req->encrypted &&
3814 (fsp->base_fsp == NULL) &&
3815 (fsp->wcp == NULL) &&
3816 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3817 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3818 DATA_BLOB header;
3820 if(fsp_stat(fsp) == -1) {
3821 reply_nterror(req, map_nt_error_from_unix(errno));
3822 goto strict_unlock;
3825 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3826 (startpos > fsp->fsp_name->st.st_ex_size) ||
3827 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3829 * We already know that we would do a short read, so don't
3830 * try the sendfile() path.
3832 goto nosendfile_read;
3836 * Set up the packet header before send. We
3837 * assume here the sendfile will work (get the
3838 * correct amount of data).
3841 header = data_blob_const(headerbuf, sizeof(headerbuf));
3843 construct_reply_common_req(req, (char *)headerbuf);
3844 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3846 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
3847 startpos, smb_maxcnt);
3848 if (nread == -1) {
3849 saved_errno = errno;
3851 /* Returning ENOSYS means no data at all was sent.
3852 Do this as a normal read. */
3853 if (errno == ENOSYS) {
3854 goto normal_read;
3858 * Special hack for broken Linux with no working sendfile. If we
3859 * return EINTR we sent the header but not the rest of the data.
3860 * Fake this up by doing read/write calls.
3863 if (errno == EINTR) {
3864 /* Ensure we don't do this again. */
3865 set_use_sendfile(SNUM(conn), False);
3866 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3867 nread = fake_sendfile(xconn, fsp, startpos,
3868 smb_maxcnt);
3869 if (nread == -1) {
3870 saved_errno = errno;
3871 DEBUG(0,("send_file_readX: "
3872 "fake_sendfile failed for "
3873 "file %s (%s) for client %s. "
3874 "Terminating\n",
3875 fsp_str_dbg(fsp),
3876 smbXsrv_connection_dbg(xconn),
3877 strerror(saved_errno)));
3878 errno = saved_errno;
3879 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3881 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3882 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3883 /* No outbuf here means successful sendfile. */
3884 goto strict_unlock;
3887 DEBUG(0,("send_file_readX: sendfile failed for file "
3888 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3889 strerror(errno)));
3890 exit_server_cleanly("send_file_readX sendfile failed");
3891 } else if (nread == 0) {
3893 * Some sendfile implementations return 0 to indicate
3894 * that there was a short read, but nothing was
3895 * actually written to the socket. In this case,
3896 * fallback to the normal read path so the header gets
3897 * the correct byte count.
3899 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3900 "falling back to the normal read: %s\n",
3901 fsp_str_dbg(fsp)));
3902 goto normal_read;
3905 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3906 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3908 /* Deal with possible short send. */
3909 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3910 ssize_t ret;
3912 ret = sendfile_short_send(xconn, fsp, nread,
3913 sizeof(headerbuf), smb_maxcnt);
3914 if (ret == -1) {
3915 const char *r;
3916 r = "send_file_readX: sendfile_short_send failed";
3917 DEBUG(0,("%s for file %s (%s).\n",
3918 r, fsp_str_dbg(fsp), strerror(errno)));
3919 exit_server_cleanly(r);
3922 /* No outbuf here means successful sendfile. */
3923 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3924 SMB_PERFCOUNT_END(&req->pcd);
3925 goto strict_unlock;
3928 normal_read:
3930 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3931 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
3932 ssize_t ret;
3934 construct_reply_common_req(req, (char *)headerbuf);
3935 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3937 /* Send out the header. */
3938 ret = write_data(xconn->transport.sock, (char *)headerbuf,
3939 sizeof(headerbuf));
3940 if (ret != sizeof(headerbuf)) {
3941 saved_errno = errno;
3943 * Try and give an error message saying what
3944 * client failed.
3946 DEBUG(0,("send_file_readX: write_data failed for file "
3947 "%s (%s) for client %s. Terminating\n",
3948 fsp_str_dbg(fsp),
3949 smbXsrv_connection_dbg(xconn),
3950 strerror(saved_errno)));
3951 errno = saved_errno;
3952 exit_server_cleanly("send_file_readX sendfile failed");
3954 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
3955 if (nread == -1) {
3956 saved_errno = errno;
3957 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
3958 "%s (%s) for client %s. Terminating\n",
3959 fsp_str_dbg(fsp),
3960 smbXsrv_connection_dbg(xconn),
3961 strerror(saved_errno)));
3962 errno = saved_errno;
3963 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3965 goto strict_unlock;
3968 nosendfile_read:
3970 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
3971 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3972 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3974 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
3975 startpos, smb_maxcnt);
3976 saved_errno = errno;
3978 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3980 if (nread < 0) {
3981 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3982 return;
3985 setup_readX_header(req, (char *)req->outbuf, nread);
3987 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3988 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3989 return;
3991 strict_unlock:
3992 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3993 TALLOC_FREE(req->outbuf);
3994 return;
3997 /****************************************************************************
3998 Work out how much space we have for a read return.
3999 ****************************************************************************/
4001 static size_t calc_max_read_pdu(const struct smb_request *req)
4003 struct smbXsrv_connection *xconn = req->xconn;
4005 if (xconn->protocol < PROTOCOL_NT1) {
4006 return xconn->smb1.sessions.max_send;
4009 if (!lp_large_readwrite()) {
4010 return xconn->smb1.sessions.max_send;
4013 if (req_is_in_chain(req)) {
4014 return xconn->smb1.sessions.max_send;
4017 if (req->encrypted) {
4019 * Don't take encrypted traffic up to the
4020 * limit. There are padding considerations
4021 * that make that tricky.
4023 return xconn->smb1.sessions.max_send;
4026 if (srv_is_signing_active(xconn)) {
4027 return 0x1FFFF;
4030 if (!lp_unix_extensions()) {
4031 return 0x1FFFF;
4035 * We can do ultra-large POSIX reads.
4037 return 0xFFFFFF;
4040 /****************************************************************************
4041 Calculate how big a read can be. Copes with all clients. It's always
4042 safe to return a short read - Windows does this.
4043 ****************************************************************************/
4045 static size_t calc_read_size(const struct smb_request *req,
4046 size_t upper_size,
4047 size_t lower_size)
4049 struct smbXsrv_connection *xconn = req->xconn;
4050 size_t max_pdu = calc_max_read_pdu(req);
4051 size_t total_size = 0;
4052 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4053 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4056 * Windows explicitly ignores upper size of 0xFFFF.
4057 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4058 * We must do the same as these will never fit even in
4059 * an extended size NetBIOS packet.
4061 if (upper_size == 0xFFFF) {
4062 upper_size = 0;
4065 if (xconn->protocol < PROTOCOL_NT1) {
4066 upper_size = 0;
4069 total_size = ((upper_size<<16) | lower_size);
4072 * LARGE_READX test shows it's always safe to return
4073 * a short read. Windows does so.
4075 return MIN(total_size, max_len);
4078 /****************************************************************************
4079 Reply to a read and X.
4080 ****************************************************************************/
4082 void reply_read_and_X(struct smb_request *req)
4084 connection_struct *conn = req->conn;
4085 files_struct *fsp;
4086 off_t startpos;
4087 size_t smb_maxcnt;
4088 size_t upper_size;
4089 bool big_readX = False;
4090 #if 0
4091 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4092 #endif
4094 START_PROFILE(SMBreadX);
4096 if ((req->wct != 10) && (req->wct != 12)) {
4097 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4098 return;
4101 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4102 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4103 smb_maxcnt = SVAL(req->vwv+5, 0);
4105 /* If it's an IPC, pass off the pipe handler. */
4106 if (IS_IPC(conn)) {
4107 reply_pipe_read_and_X(req);
4108 END_PROFILE(SMBreadX);
4109 return;
4112 if (!check_fsp(conn, req, fsp)) {
4113 END_PROFILE(SMBreadX);
4114 return;
4117 if (!CHECK_READ(fsp,req)) {
4118 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4119 END_PROFILE(SMBreadX);
4120 return;
4123 upper_size = SVAL(req->vwv+7, 0);
4124 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4125 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4127 * This is a heuristic to avoid keeping large
4128 * outgoing buffers around over long-lived aio
4129 * requests.
4131 big_readX = True;
4134 if (req->wct == 12) {
4136 * This is a large offset (64 bit) read.
4138 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4142 if (!big_readX) {
4143 NTSTATUS status = schedule_aio_read_and_X(conn,
4144 req,
4145 fsp,
4146 startpos,
4147 smb_maxcnt);
4148 if (NT_STATUS_IS_OK(status)) {
4149 /* Read scheduled - we're done. */
4150 goto out;
4152 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4153 /* Real error - report to client. */
4154 END_PROFILE(SMBreadX);
4155 reply_nterror(req, status);
4156 return;
4158 /* NT_STATUS_RETRY - fall back to sync read. */
4161 smbd_lock_socket(req->xconn);
4162 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4163 smbd_unlock_socket(req->xconn);
4165 out:
4166 END_PROFILE(SMBreadX);
4167 return;
4170 /****************************************************************************
4171 Error replies to writebraw must have smb_wct == 1. Fix this up.
4172 ****************************************************************************/
4174 void error_to_writebrawerr(struct smb_request *req)
4176 uint8_t *old_outbuf = req->outbuf;
4178 reply_outbuf(req, 1, 0);
4180 memcpy(req->outbuf, old_outbuf, smb_size);
4181 TALLOC_FREE(old_outbuf);
4184 /****************************************************************************
4185 Read 4 bytes of a smb packet and return the smb length of the packet.
4186 Store the result in the buffer. This version of the function will
4187 never return a session keepalive (length of zero).
4188 Timeout is in milliseconds.
4189 ****************************************************************************/
4191 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4192 size_t *len)
4194 uint8_t msgtype = NBSSkeepalive;
4196 while (msgtype == NBSSkeepalive) {
4197 NTSTATUS status;
4199 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4200 len);
4201 if (!NT_STATUS_IS_OK(status)) {
4202 char addr[INET6_ADDRSTRLEN];
4203 /* Try and give an error message
4204 * saying what client failed. */
4205 DEBUG(0, ("read_fd_with_timeout failed for "
4206 "client %s read error = %s.\n",
4207 get_peer_addr(fd,addr,sizeof(addr)),
4208 nt_errstr(status)));
4209 return status;
4212 msgtype = CVAL(inbuf, 0);
4215 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4216 (unsigned long)len));
4218 return NT_STATUS_OK;
4221 /****************************************************************************
4222 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4223 ****************************************************************************/
4225 void reply_writebraw(struct smb_request *req)
4227 connection_struct *conn = req->conn;
4228 struct smbXsrv_connection *xconn = req->xconn;
4229 char *buf = NULL;
4230 ssize_t nwritten=0;
4231 ssize_t total_written=0;
4232 size_t numtowrite=0;
4233 size_t tcount;
4234 off_t startpos;
4235 const char *data=NULL;
4236 bool write_through;
4237 files_struct *fsp;
4238 struct lock_struct lock;
4239 NTSTATUS status;
4241 START_PROFILE(SMBwritebraw);
4244 * If we ever reply with an error, it must have the SMB command
4245 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4246 * we're finished.
4248 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4250 if (srv_is_signing_active(xconn)) {
4251 END_PROFILE(SMBwritebraw);
4252 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4253 "raw reads/writes are disallowed.");
4256 if (req->wct < 12) {
4257 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4258 error_to_writebrawerr(req);
4259 END_PROFILE(SMBwritebraw);
4260 return;
4263 if (xconn->smb1.echo_handler.trusted_fde) {
4264 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4265 "'async smb echo handler = yes'\n"));
4266 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4267 error_to_writebrawerr(req);
4268 END_PROFILE(SMBwritebraw);
4269 return;
4272 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4273 if (!check_fsp(conn, req, fsp)) {
4274 error_to_writebrawerr(req);
4275 END_PROFILE(SMBwritebraw);
4276 return;
4279 if (!CHECK_WRITE(fsp)) {
4280 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4281 error_to_writebrawerr(req);
4282 END_PROFILE(SMBwritebraw);
4283 return;
4286 tcount = IVAL(req->vwv+1, 0);
4287 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4288 write_through = BITSETW(req->vwv+7,0);
4290 /* We have to deal with slightly different formats depending
4291 on whether we are using the core+ or lanman1.0 protocol */
4293 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4294 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4295 data = smb_buf_const(req->inbuf);
4296 } else {
4297 numtowrite = SVAL(req->vwv+10, 0);
4298 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4301 /* Ensure we don't write bytes past the end of this packet. */
4302 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4303 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4304 error_to_writebrawerr(req);
4305 END_PROFILE(SMBwritebraw);
4306 return;
4309 if (!fsp->print_file) {
4310 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4311 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4312 &lock);
4314 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4315 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4316 error_to_writebrawerr(req);
4317 END_PROFILE(SMBwritebraw);
4318 return;
4322 if (numtowrite>0) {
4323 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4326 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4327 "wrote=%d sync=%d\n",
4328 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4329 (int)nwritten, (int)write_through));
4331 if (nwritten < (ssize_t)numtowrite) {
4332 reply_nterror(req, NT_STATUS_DISK_FULL);
4333 error_to_writebrawerr(req);
4334 goto strict_unlock;
4337 total_written = nwritten;
4339 /* Allocate a buffer of 64k + length. */
4340 buf = talloc_array(NULL, char, 65540);
4341 if (!buf) {
4342 reply_nterror(req, NT_STATUS_NO_MEMORY);
4343 error_to_writebrawerr(req);
4344 goto strict_unlock;
4347 /* Return a SMBwritebraw message to the redirector to tell
4348 * it to send more bytes */
4350 memcpy(buf, req->inbuf, smb_size);
4351 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4352 SCVAL(buf,smb_com,SMBwritebraw);
4353 SSVALS(buf,smb_vwv0,0xFFFF);
4354 show_msg(buf);
4355 if (!srv_send_smb(req->xconn,
4356 buf,
4357 false, 0, /* no signing */
4358 IS_CONN_ENCRYPTED(conn),
4359 &req->pcd)) {
4360 exit_server_cleanly("reply_writebraw: srv_send_smb "
4361 "failed.");
4364 /* Now read the raw data into the buffer and write it */
4365 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4366 &numtowrite);
4367 if (!NT_STATUS_IS_OK(status)) {
4368 exit_server_cleanly("secondary writebraw failed");
4371 /* Set up outbuf to return the correct size */
4372 reply_outbuf(req, 1, 0);
4374 if (numtowrite != 0) {
4376 if (numtowrite > 0xFFFF) {
4377 DEBUG(0,("reply_writebraw: Oversize secondary write "
4378 "raw requested (%u). Terminating\n",
4379 (unsigned int)numtowrite ));
4380 exit_server_cleanly("secondary writebraw failed");
4383 if (tcount > nwritten+numtowrite) {
4384 DEBUG(3,("reply_writebraw: Client overestimated the "
4385 "write %d %d %d\n",
4386 (int)tcount,(int)nwritten,(int)numtowrite));
4389 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4390 numtowrite);
4392 if (!NT_STATUS_IS_OK(status)) {
4393 /* Try and give an error message
4394 * saying what client failed. */
4395 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4396 "raw read failed (%s) for client %s. "
4397 "Terminating\n", nt_errstr(status),
4398 smbXsrv_connection_dbg(xconn)));
4399 exit_server_cleanly("secondary writebraw failed");
4402 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4403 if (nwritten == -1) {
4404 TALLOC_FREE(buf);
4405 reply_nterror(req, map_nt_error_from_unix(errno));
4406 error_to_writebrawerr(req);
4407 goto strict_unlock;
4410 if (nwritten < (ssize_t)numtowrite) {
4411 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4412 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4415 if (nwritten > 0) {
4416 total_written += nwritten;
4420 TALLOC_FREE(buf);
4421 SSVAL(req->outbuf,smb_vwv0,total_written);
4423 status = sync_file(conn, fsp, write_through);
4424 if (!NT_STATUS_IS_OK(status)) {
4425 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4426 fsp_str_dbg(fsp), nt_errstr(status)));
4427 reply_nterror(req, status);
4428 error_to_writebrawerr(req);
4429 goto strict_unlock;
4432 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4433 "wrote=%d\n",
4434 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4435 (int)total_written));
4437 if (!fsp->print_file) {
4438 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4441 /* We won't return a status if write through is not selected - this
4442 * follows what WfWg does */
4443 END_PROFILE(SMBwritebraw);
4445 if (!write_through && total_written==tcount) {
4447 #if RABBIT_PELLET_FIX
4449 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4450 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4451 * JRA.
4453 if (!send_keepalive(xconn->transport.sock)) {
4454 exit_server_cleanly("reply_writebraw: send of "
4455 "keepalive failed");
4457 #endif
4458 TALLOC_FREE(req->outbuf);
4460 return;
4462 strict_unlock:
4463 if (!fsp->print_file) {
4464 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4467 END_PROFILE(SMBwritebraw);
4468 return;
4471 #undef DBGC_CLASS
4472 #define DBGC_CLASS DBGC_LOCKING
4474 /****************************************************************************
4475 Reply to a writeunlock (core+).
4476 ****************************************************************************/
4478 void reply_writeunlock(struct smb_request *req)
4480 connection_struct *conn = req->conn;
4481 ssize_t nwritten = -1;
4482 size_t numtowrite;
4483 off_t startpos;
4484 const char *data;
4485 NTSTATUS status = NT_STATUS_OK;
4486 files_struct *fsp;
4487 struct lock_struct lock;
4488 int saved_errno = 0;
4490 START_PROFILE(SMBwriteunlock);
4492 if (req->wct < 5) {
4493 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4494 END_PROFILE(SMBwriteunlock);
4495 return;
4498 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4500 if (!check_fsp(conn, req, fsp)) {
4501 END_PROFILE(SMBwriteunlock);
4502 return;
4505 if (!CHECK_WRITE(fsp)) {
4506 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4507 END_PROFILE(SMBwriteunlock);
4508 return;
4511 numtowrite = SVAL(req->vwv+1, 0);
4512 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4513 data = (const char *)req->buf + 3;
4515 if (!fsp->print_file && numtowrite > 0) {
4516 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4517 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4518 &lock);
4520 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4521 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4522 END_PROFILE(SMBwriteunlock);
4523 return;
4527 /* The special X/Open SMB protocol handling of
4528 zero length writes is *NOT* done for
4529 this call */
4530 if(numtowrite == 0) {
4531 nwritten = 0;
4532 } else {
4533 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4534 saved_errno = errno;
4537 status = sync_file(conn, fsp, False /* write through */);
4538 if (!NT_STATUS_IS_OK(status)) {
4539 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4540 fsp_str_dbg(fsp), nt_errstr(status)));
4541 reply_nterror(req, status);
4542 goto strict_unlock;
4545 if(nwritten < 0) {
4546 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4547 goto strict_unlock;
4550 if((nwritten < numtowrite) && (numtowrite != 0)) {
4551 reply_nterror(req, NT_STATUS_DISK_FULL);
4552 goto strict_unlock;
4555 if (numtowrite && !fsp->print_file) {
4556 status = do_unlock(req->sconn->msg_ctx,
4557 fsp,
4558 (uint64_t)req->smbpid,
4559 (uint64_t)numtowrite,
4560 (uint64_t)startpos,
4561 WINDOWS_LOCK);
4563 if (NT_STATUS_V(status)) {
4564 reply_nterror(req, status);
4565 goto strict_unlock;
4569 reply_outbuf(req, 1, 0);
4571 SSVAL(req->outbuf,smb_vwv0,nwritten);
4573 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4574 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4576 strict_unlock:
4577 if (numtowrite && !fsp->print_file) {
4578 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4581 END_PROFILE(SMBwriteunlock);
4582 return;
4585 #undef DBGC_CLASS
4586 #define DBGC_CLASS DBGC_ALL
4588 /****************************************************************************
4589 Reply to a write.
4590 ****************************************************************************/
4592 void reply_write(struct smb_request *req)
4594 connection_struct *conn = req->conn;
4595 size_t numtowrite;
4596 ssize_t nwritten = -1;
4597 off_t startpos;
4598 const char *data;
4599 files_struct *fsp;
4600 struct lock_struct lock;
4601 NTSTATUS status;
4602 int saved_errno = 0;
4604 START_PROFILE(SMBwrite);
4606 if (req->wct < 5) {
4607 END_PROFILE(SMBwrite);
4608 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4609 return;
4612 /* If it's an IPC, pass off the pipe handler. */
4613 if (IS_IPC(conn)) {
4614 reply_pipe_write(req);
4615 END_PROFILE(SMBwrite);
4616 return;
4619 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4621 if (!check_fsp(conn, req, fsp)) {
4622 END_PROFILE(SMBwrite);
4623 return;
4626 if (!CHECK_WRITE(fsp)) {
4627 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4628 END_PROFILE(SMBwrite);
4629 return;
4632 numtowrite = SVAL(req->vwv+1, 0);
4633 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4634 data = (const char *)req->buf + 3;
4636 if (!fsp->print_file) {
4637 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4638 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4639 &lock);
4641 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4642 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4643 END_PROFILE(SMBwrite);
4644 return;
4649 * X/Open SMB protocol says that if smb_vwv1 is
4650 * zero then the file size should be extended or
4651 * truncated to the size given in smb_vwv[2-3].
4654 if(numtowrite == 0) {
4656 * This is actually an allocate call, and set EOF. JRA.
4658 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4659 if (nwritten < 0) {
4660 reply_nterror(req, NT_STATUS_DISK_FULL);
4661 goto strict_unlock;
4663 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4664 if (nwritten < 0) {
4665 reply_nterror(req, NT_STATUS_DISK_FULL);
4666 goto strict_unlock;
4668 trigger_write_time_update_immediate(fsp);
4669 } else {
4670 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4673 status = sync_file(conn, fsp, False);
4674 if (!NT_STATUS_IS_OK(status)) {
4675 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4676 fsp_str_dbg(fsp), nt_errstr(status)));
4677 reply_nterror(req, status);
4678 goto strict_unlock;
4681 if(nwritten < 0) {
4682 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4683 goto strict_unlock;
4686 if((nwritten == 0) && (numtowrite != 0)) {
4687 reply_nterror(req, NT_STATUS_DISK_FULL);
4688 goto strict_unlock;
4691 reply_outbuf(req, 1, 0);
4693 SSVAL(req->outbuf,smb_vwv0,nwritten);
4695 if (nwritten < (ssize_t)numtowrite) {
4696 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4697 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4700 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4702 strict_unlock:
4703 if (!fsp->print_file) {
4704 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4707 END_PROFILE(SMBwrite);
4708 return;
4711 /****************************************************************************
4712 Ensure a buffer is a valid writeX for recvfile purposes.
4713 ****************************************************************************/
4715 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4716 (2*14) + /* word count (including bcc) */ \
4717 1 /* pad byte */)
4719 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4720 const uint8_t *inbuf)
4722 size_t numtowrite;
4723 unsigned int doff = 0;
4724 size_t len = smb_len_large(inbuf);
4725 uint16_t fnum;
4726 struct smbXsrv_open *op = NULL;
4727 struct files_struct *fsp = NULL;
4728 NTSTATUS status;
4730 if (is_encrypted_packet(inbuf)) {
4731 /* Can't do this on encrypted
4732 * connections. */
4733 return false;
4736 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4737 return false;
4740 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4741 CVAL(inbuf,smb_wct) != 14) {
4742 DEBUG(10,("is_valid_writeX_buffer: chained or "
4743 "invalid word length.\n"));
4744 return false;
4747 fnum = SVAL(inbuf, smb_vwv2);
4748 status = smb1srv_open_lookup(xconn,
4749 fnum,
4750 0, /* now */
4751 &op);
4752 if (!NT_STATUS_IS_OK(status)) {
4753 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4754 return false;
4756 fsp = op->compat;
4757 if (fsp == NULL) {
4758 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4759 return false;
4761 if (fsp->conn == NULL) {
4762 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4763 return false;
4766 if (IS_IPC(fsp->conn)) {
4767 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4768 return false;
4770 if (IS_PRINT(fsp->conn)) {
4771 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4772 return false;
4774 doff = SVAL(inbuf,smb_vwv11);
4776 numtowrite = SVAL(inbuf,smb_vwv10);
4778 if (len > doff && len - doff > 0xFFFF) {
4779 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4782 if (numtowrite == 0) {
4783 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4784 return false;
4787 /* Ensure the sizes match up. */
4788 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4789 /* no pad byte...old smbclient :-( */
4790 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4791 (unsigned int)doff,
4792 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4793 return false;
4796 if (len - doff != numtowrite) {
4797 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4798 "len = %u, doff = %u, numtowrite = %u\n",
4799 (unsigned int)len,
4800 (unsigned int)doff,
4801 (unsigned int)numtowrite ));
4802 return false;
4805 DEBUG(10,("is_valid_writeX_buffer: true "
4806 "len = %u, doff = %u, numtowrite = %u\n",
4807 (unsigned int)len,
4808 (unsigned int)doff,
4809 (unsigned int)numtowrite ));
4811 return true;
4814 /****************************************************************************
4815 Reply to a write and X.
4816 ****************************************************************************/
4818 void reply_write_and_X(struct smb_request *req)
4820 connection_struct *conn = req->conn;
4821 struct smbXsrv_connection *xconn = req->xconn;
4822 files_struct *fsp;
4823 struct lock_struct lock;
4824 off_t startpos;
4825 size_t numtowrite;
4826 bool write_through;
4827 ssize_t nwritten;
4828 unsigned int smb_doff;
4829 unsigned int smblen;
4830 const char *data;
4831 NTSTATUS status;
4832 int saved_errno = 0;
4834 START_PROFILE(SMBwriteX);
4836 if ((req->wct != 12) && (req->wct != 14)) {
4837 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4838 goto out;
4841 numtowrite = SVAL(req->vwv+10, 0);
4842 smb_doff = SVAL(req->vwv+11, 0);
4843 smblen = smb_len(req->inbuf);
4845 if (req->unread_bytes > 0xFFFF ||
4846 (smblen > smb_doff &&
4847 smblen - smb_doff > 0xFFFF)) {
4848 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4851 if (req->unread_bytes) {
4852 /* Can't do a recvfile write on IPC$ */
4853 if (IS_IPC(conn)) {
4854 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4855 goto out;
4857 if (numtowrite != req->unread_bytes) {
4858 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4859 goto out;
4861 } else {
4862 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4863 smb_doff + numtowrite > smblen) {
4864 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4865 goto out;
4869 /* If it's an IPC, pass off the pipe handler. */
4870 if (IS_IPC(conn)) {
4871 if (req->unread_bytes) {
4872 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4873 goto out;
4875 reply_pipe_write_and_X(req);
4876 goto out;
4879 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4880 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4881 write_through = BITSETW(req->vwv+7,0);
4883 if (!check_fsp(conn, req, fsp)) {
4884 goto out;
4887 if (!CHECK_WRITE(fsp)) {
4888 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4889 goto out;
4892 data = smb_base(req->inbuf) + smb_doff;
4894 if(req->wct == 14) {
4896 * This is a large offset (64 bit) write.
4898 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4902 /* X/Open SMB protocol says that, unlike SMBwrite
4903 if the length is zero then NO truncation is
4904 done, just a write of zero. To truncate a file,
4905 use SMBwrite. */
4907 if(numtowrite == 0) {
4908 nwritten = 0;
4909 } else {
4910 if (req->unread_bytes == 0) {
4911 status = schedule_aio_write_and_X(conn,
4912 req,
4913 fsp,
4914 data,
4915 startpos,
4916 numtowrite);
4918 if (NT_STATUS_IS_OK(status)) {
4919 /* write scheduled - we're done. */
4920 goto out;
4922 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4923 /* Real error - report to client. */
4924 reply_nterror(req, status);
4925 goto out;
4927 /* NT_STATUS_RETRY - fall through to sync write. */
4930 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4931 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4932 &lock);
4934 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4935 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4936 goto out;
4939 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4940 saved_errno = errno;
4942 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4945 if(nwritten < 0) {
4946 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4947 goto out;
4950 if((nwritten == 0) && (numtowrite != 0)) {
4951 reply_nterror(req, NT_STATUS_DISK_FULL);
4952 goto out;
4955 reply_outbuf(req, 6, 0);
4956 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4957 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4958 SSVAL(req->outbuf,smb_vwv2,nwritten);
4959 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4961 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4962 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4964 status = sync_file(conn, fsp, write_through);
4965 if (!NT_STATUS_IS_OK(status)) {
4966 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4967 fsp_str_dbg(fsp), nt_errstr(status)));
4968 reply_nterror(req, status);
4969 goto out;
4972 END_PROFILE(SMBwriteX);
4973 return;
4975 out:
4976 if (req->unread_bytes) {
4977 /* writeX failed. drain socket. */
4978 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
4979 req->unread_bytes) {
4980 smb_panic("failed to drain pending bytes");
4982 req->unread_bytes = 0;
4985 END_PROFILE(SMBwriteX);
4986 return;
4989 /****************************************************************************
4990 Reply to a lseek.
4991 ****************************************************************************/
4993 void reply_lseek(struct smb_request *req)
4995 connection_struct *conn = req->conn;
4996 off_t startpos;
4997 off_t res= -1;
4998 int mode,umode;
4999 files_struct *fsp;
5001 START_PROFILE(SMBlseek);
5003 if (req->wct < 4) {
5004 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5005 END_PROFILE(SMBlseek);
5006 return;
5009 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5011 if (!check_fsp(conn, req, fsp)) {
5012 return;
5015 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5017 mode = SVAL(req->vwv+1, 0) & 3;
5018 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5019 startpos = (off_t)IVALS(req->vwv+2, 0);
5021 switch (mode) {
5022 case 0:
5023 umode = SEEK_SET;
5024 res = startpos;
5025 break;
5026 case 1:
5027 umode = SEEK_CUR;
5028 res = fsp->fh->pos + startpos;
5029 break;
5030 case 2:
5031 umode = SEEK_END;
5032 break;
5033 default:
5034 umode = SEEK_SET;
5035 res = startpos;
5036 break;
5039 if (umode == SEEK_END) {
5040 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5041 if(errno == EINVAL) {
5042 off_t current_pos = startpos;
5044 if(fsp_stat(fsp) == -1) {
5045 reply_nterror(req,
5046 map_nt_error_from_unix(errno));
5047 END_PROFILE(SMBlseek);
5048 return;
5051 current_pos += fsp->fsp_name->st.st_ex_size;
5052 if(current_pos < 0)
5053 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5057 if(res == -1) {
5058 reply_nterror(req, map_nt_error_from_unix(errno));
5059 END_PROFILE(SMBlseek);
5060 return;
5064 fsp->fh->pos = res;
5066 reply_outbuf(req, 2, 0);
5067 SIVAL(req->outbuf,smb_vwv0,res);
5069 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5070 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5072 END_PROFILE(SMBlseek);
5073 return;
5076 /****************************************************************************
5077 Reply to a flush.
5078 ****************************************************************************/
5080 void reply_flush(struct smb_request *req)
5082 connection_struct *conn = req->conn;
5083 uint16_t fnum;
5084 files_struct *fsp;
5086 START_PROFILE(SMBflush);
5088 if (req->wct < 1) {
5089 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5090 return;
5093 fnum = SVAL(req->vwv+0, 0);
5094 fsp = file_fsp(req, fnum);
5096 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5097 return;
5100 if (!fsp) {
5101 file_sync_all(conn);
5102 } else {
5103 NTSTATUS status = sync_file(conn, fsp, True);
5104 if (!NT_STATUS_IS_OK(status)) {
5105 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5106 fsp_str_dbg(fsp), nt_errstr(status)));
5107 reply_nterror(req, status);
5108 END_PROFILE(SMBflush);
5109 return;
5113 reply_outbuf(req, 0, 0);
5115 DEBUG(3,("flush\n"));
5116 END_PROFILE(SMBflush);
5117 return;
5120 /****************************************************************************
5121 Reply to a exit.
5122 conn POINTER CAN BE NULL HERE !
5123 ****************************************************************************/
5125 void reply_exit(struct smb_request *req)
5127 START_PROFILE(SMBexit);
5129 file_close_pid(req->sconn, req->smbpid, req->vuid);
5131 reply_outbuf(req, 0, 0);
5133 DEBUG(3,("exit\n"));
5135 END_PROFILE(SMBexit);
5136 return;
5139 struct reply_close_state {
5140 files_struct *fsp;
5141 struct smb_request *smbreq;
5144 static void do_smb1_close(struct tevent_req *req);
5146 void reply_close(struct smb_request *req)
5148 connection_struct *conn = req->conn;
5149 NTSTATUS status = NT_STATUS_OK;
5150 files_struct *fsp = NULL;
5151 START_PROFILE(SMBclose);
5153 if (req->wct < 3) {
5154 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5155 END_PROFILE(SMBclose);
5156 return;
5159 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5162 * We can only use check_fsp if we know it's not a directory.
5165 if (!check_fsp_open(conn, req, fsp)) {
5166 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5167 END_PROFILE(SMBclose);
5168 return;
5171 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5172 fsp->is_directory ? "directory" : "file",
5173 fsp->fh->fd, fsp_fnum_dbg(fsp),
5174 conn->num_files_open));
5176 if (!fsp->is_directory) {
5177 time_t t;
5180 * Take care of any time sent in the close.
5183 t = srv_make_unix_date3(req->vwv+1);
5184 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5187 if (fsp->num_aio_requests != 0) {
5189 struct reply_close_state *state;
5191 DEBUG(10, ("closing with aio %u requests pending\n",
5192 fsp->num_aio_requests));
5195 * We depend on the aio_extra destructor to take care of this
5196 * close request once fsp->num_aio_request drops to 0.
5199 fsp->deferred_close = tevent_wait_send(
5200 fsp, fsp->conn->sconn->ev_ctx);
5201 if (fsp->deferred_close == NULL) {
5202 status = NT_STATUS_NO_MEMORY;
5203 goto done;
5206 state = talloc(fsp, struct reply_close_state);
5207 if (state == NULL) {
5208 TALLOC_FREE(fsp->deferred_close);
5209 status = NT_STATUS_NO_MEMORY;
5210 goto done;
5212 state->fsp = fsp;
5213 state->smbreq = talloc_move(fsp, &req);
5214 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5215 state);
5216 END_PROFILE(SMBclose);
5217 return;
5221 * close_file() returns the unix errno if an error was detected on
5222 * close - normally this is due to a disk full error. If not then it
5223 * was probably an I/O error.
5226 status = close_file(req, fsp, NORMAL_CLOSE);
5227 done:
5228 if (!NT_STATUS_IS_OK(status)) {
5229 reply_nterror(req, status);
5230 END_PROFILE(SMBclose);
5231 return;
5234 reply_outbuf(req, 0, 0);
5235 END_PROFILE(SMBclose);
5236 return;
5239 static void do_smb1_close(struct tevent_req *req)
5241 struct reply_close_state *state = tevent_req_callback_data(
5242 req, struct reply_close_state);
5243 struct smb_request *smbreq;
5244 NTSTATUS status;
5245 int ret;
5247 ret = tevent_wait_recv(req);
5248 TALLOC_FREE(req);
5249 if (ret != 0) {
5250 DEBUG(10, ("tevent_wait_recv returned %s\n",
5251 strerror(ret)));
5253 * Continue anyway, this should never happen
5258 * fsp->smb2_close_request right now is a talloc grandchild of
5259 * fsp. When we close_file(fsp), it would go with it. No chance to
5260 * reply...
5262 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5264 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5265 if (NT_STATUS_IS_OK(status)) {
5266 reply_outbuf(smbreq, 0, 0);
5267 } else {
5268 reply_nterror(smbreq, status);
5270 if (!srv_send_smb(smbreq->xconn,
5271 (char *)smbreq->outbuf,
5272 true,
5273 smbreq->seqnum+1,
5274 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5275 NULL)) {
5276 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5277 "failed.");
5279 TALLOC_FREE(smbreq);
5282 /****************************************************************************
5283 Reply to a writeclose (Core+ protocol).
5284 ****************************************************************************/
5286 void reply_writeclose(struct smb_request *req)
5288 connection_struct *conn = req->conn;
5289 size_t numtowrite;
5290 ssize_t nwritten = -1;
5291 NTSTATUS close_status = NT_STATUS_OK;
5292 off_t startpos;
5293 const char *data;
5294 struct timespec mtime;
5295 files_struct *fsp;
5296 struct lock_struct lock;
5298 START_PROFILE(SMBwriteclose);
5300 if (req->wct < 6) {
5301 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5302 END_PROFILE(SMBwriteclose);
5303 return;
5306 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5308 if (!check_fsp(conn, req, fsp)) {
5309 END_PROFILE(SMBwriteclose);
5310 return;
5312 if (!CHECK_WRITE(fsp)) {
5313 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5314 END_PROFILE(SMBwriteclose);
5315 return;
5318 numtowrite = SVAL(req->vwv+1, 0);
5319 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5320 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5321 data = (const char *)req->buf + 1;
5323 if (fsp->print_file == NULL) {
5324 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5325 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5326 &lock);
5328 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5329 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5330 END_PROFILE(SMBwriteclose);
5331 return;
5335 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5337 if (fsp->print_file == NULL) {
5338 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5341 set_close_write_time(fsp, mtime);
5344 * More insanity. W2K only closes the file if writelen > 0.
5345 * JRA.
5348 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5349 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5350 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5352 if (numtowrite) {
5353 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5354 "file %s\n", fsp_str_dbg(fsp)));
5355 close_status = close_file(req, fsp, NORMAL_CLOSE);
5356 fsp = NULL;
5359 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5360 reply_nterror(req, NT_STATUS_DISK_FULL);
5361 goto out;
5364 if(!NT_STATUS_IS_OK(close_status)) {
5365 reply_nterror(req, close_status);
5366 goto out;
5369 reply_outbuf(req, 1, 0);
5371 SSVAL(req->outbuf,smb_vwv0,nwritten);
5373 out:
5375 END_PROFILE(SMBwriteclose);
5376 return;
5379 #undef DBGC_CLASS
5380 #define DBGC_CLASS DBGC_LOCKING
5382 /****************************************************************************
5383 Reply to a lock.
5384 ****************************************************************************/
5386 void reply_lock(struct smb_request *req)
5388 connection_struct *conn = req->conn;
5389 uint64_t count,offset;
5390 NTSTATUS status;
5391 files_struct *fsp;
5392 struct byte_range_lock *br_lck = NULL;
5394 START_PROFILE(SMBlock);
5396 if (req->wct < 5) {
5397 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5398 END_PROFILE(SMBlock);
5399 return;
5402 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5404 if (!check_fsp(conn, req, fsp)) {
5405 END_PROFILE(SMBlock);
5406 return;
5409 count = (uint64_t)IVAL(req->vwv+1, 0);
5410 offset = (uint64_t)IVAL(req->vwv+3, 0);
5412 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5413 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5415 br_lck = do_lock(req->sconn->msg_ctx,
5416 fsp,
5417 (uint64_t)req->smbpid,
5418 count,
5419 offset,
5420 WRITE_LOCK,
5421 WINDOWS_LOCK,
5422 False, /* Non-blocking lock. */
5423 &status,
5424 NULL);
5426 TALLOC_FREE(br_lck);
5428 if (NT_STATUS_V(status)) {
5429 reply_nterror(req, status);
5430 END_PROFILE(SMBlock);
5431 return;
5434 reply_outbuf(req, 0, 0);
5436 END_PROFILE(SMBlock);
5437 return;
5440 /****************************************************************************
5441 Reply to a unlock.
5442 ****************************************************************************/
5444 void reply_unlock(struct smb_request *req)
5446 connection_struct *conn = req->conn;
5447 uint64_t count,offset;
5448 NTSTATUS status;
5449 files_struct *fsp;
5451 START_PROFILE(SMBunlock);
5453 if (req->wct < 5) {
5454 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5455 END_PROFILE(SMBunlock);
5456 return;
5459 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5461 if (!check_fsp(conn, req, fsp)) {
5462 END_PROFILE(SMBunlock);
5463 return;
5466 count = (uint64_t)IVAL(req->vwv+1, 0);
5467 offset = (uint64_t)IVAL(req->vwv+3, 0);
5469 status = do_unlock(req->sconn->msg_ctx,
5470 fsp,
5471 (uint64_t)req->smbpid,
5472 count,
5473 offset,
5474 WINDOWS_LOCK);
5476 if (NT_STATUS_V(status)) {
5477 reply_nterror(req, status);
5478 END_PROFILE(SMBunlock);
5479 return;
5482 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5483 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5485 reply_outbuf(req, 0, 0);
5487 END_PROFILE(SMBunlock);
5488 return;
5491 #undef DBGC_CLASS
5492 #define DBGC_CLASS DBGC_ALL
5494 /****************************************************************************
5495 Reply to a tdis.
5496 conn POINTER CAN BE NULL HERE !
5497 ****************************************************************************/
5499 void reply_tdis(struct smb_request *req)
5501 NTSTATUS status;
5502 connection_struct *conn = req->conn;
5503 struct smbXsrv_tcon *tcon;
5505 START_PROFILE(SMBtdis);
5507 if (!conn) {
5508 DEBUG(4,("Invalid connection in tdis\n"));
5509 reply_force_doserror(req, ERRSRV, ERRinvnid);
5510 END_PROFILE(SMBtdis);
5511 return;
5514 tcon = conn->tcon;
5515 req->conn = NULL;
5518 * TODO: cancel all outstanding requests on the tcon
5520 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5521 if (!NT_STATUS_IS_OK(status)) {
5522 DEBUG(0, ("reply_tdis: "
5523 "smbXsrv_tcon_disconnect() failed: %s\n",
5524 nt_errstr(status)));
5526 * If we hit this case, there is something completely
5527 * wrong, so we better disconnect the transport connection.
5529 END_PROFILE(SMBtdis);
5530 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5531 return;
5534 TALLOC_FREE(tcon);
5536 reply_outbuf(req, 0, 0);
5537 END_PROFILE(SMBtdis);
5538 return;
5541 /****************************************************************************
5542 Reply to a echo.
5543 conn POINTER CAN BE NULL HERE !
5544 ****************************************************************************/
5546 void reply_echo(struct smb_request *req)
5548 connection_struct *conn = req->conn;
5549 struct smb_perfcount_data local_pcd;
5550 struct smb_perfcount_data *cur_pcd;
5551 int smb_reverb;
5552 int seq_num;
5554 START_PROFILE(SMBecho);
5556 smb_init_perfcount_data(&local_pcd);
5558 if (req->wct < 1) {
5559 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5560 END_PROFILE(SMBecho);
5561 return;
5564 smb_reverb = SVAL(req->vwv+0, 0);
5566 reply_outbuf(req, 1, req->buflen);
5568 /* copy any incoming data back out */
5569 if (req->buflen > 0) {
5570 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5573 if (smb_reverb > 100) {
5574 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5575 smb_reverb = 100;
5578 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5580 /* this makes sure we catch the request pcd */
5581 if (seq_num == smb_reverb) {
5582 cur_pcd = &req->pcd;
5583 } else {
5584 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5585 cur_pcd = &local_pcd;
5588 SSVAL(req->outbuf,smb_vwv0,seq_num);
5590 show_msg((char *)req->outbuf);
5591 if (!srv_send_smb(req->xconn,
5592 (char *)req->outbuf,
5593 true, req->seqnum+1,
5594 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5595 cur_pcd))
5596 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5599 DEBUG(3,("echo %d times\n", smb_reverb));
5601 TALLOC_FREE(req->outbuf);
5603 END_PROFILE(SMBecho);
5604 return;
5607 /****************************************************************************
5608 Reply to a printopen.
5609 ****************************************************************************/
5611 void reply_printopen(struct smb_request *req)
5613 connection_struct *conn = req->conn;
5614 files_struct *fsp;
5615 NTSTATUS status;
5617 START_PROFILE(SMBsplopen);
5619 if (req->wct < 2) {
5620 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5621 END_PROFILE(SMBsplopen);
5622 return;
5625 if (!CAN_PRINT(conn)) {
5626 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5627 END_PROFILE(SMBsplopen);
5628 return;
5631 status = file_new(req, conn, &fsp);
5632 if(!NT_STATUS_IS_OK(status)) {
5633 reply_nterror(req, status);
5634 END_PROFILE(SMBsplopen);
5635 return;
5638 /* Open for exclusive use, write only. */
5639 status = print_spool_open(fsp, NULL, req->vuid);
5641 if (!NT_STATUS_IS_OK(status)) {
5642 file_free(req, fsp);
5643 reply_nterror(req, status);
5644 END_PROFILE(SMBsplopen);
5645 return;
5648 reply_outbuf(req, 1, 0);
5649 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5651 DEBUG(3,("openprint fd=%d %s\n",
5652 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5654 END_PROFILE(SMBsplopen);
5655 return;
5658 /****************************************************************************
5659 Reply to a printclose.
5660 ****************************************************************************/
5662 void reply_printclose(struct smb_request *req)
5664 connection_struct *conn = req->conn;
5665 files_struct *fsp;
5666 NTSTATUS status;
5668 START_PROFILE(SMBsplclose);
5670 if (req->wct < 1) {
5671 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5672 END_PROFILE(SMBsplclose);
5673 return;
5676 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5678 if (!check_fsp(conn, req, fsp)) {
5679 END_PROFILE(SMBsplclose);
5680 return;
5683 if (!CAN_PRINT(conn)) {
5684 reply_force_doserror(req, ERRSRV, ERRerror);
5685 END_PROFILE(SMBsplclose);
5686 return;
5689 DEBUG(3,("printclose fd=%d %s\n",
5690 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5692 status = close_file(req, fsp, NORMAL_CLOSE);
5694 if(!NT_STATUS_IS_OK(status)) {
5695 reply_nterror(req, status);
5696 END_PROFILE(SMBsplclose);
5697 return;
5700 reply_outbuf(req, 0, 0);
5702 END_PROFILE(SMBsplclose);
5703 return;
5706 /****************************************************************************
5707 Reply to a printqueue.
5708 ****************************************************************************/
5710 void reply_printqueue(struct smb_request *req)
5712 connection_struct *conn = req->conn;
5713 int max_count;
5714 int start_index;
5716 START_PROFILE(SMBsplretq);
5718 if (req->wct < 2) {
5719 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5720 END_PROFILE(SMBsplretq);
5721 return;
5724 max_count = SVAL(req->vwv+0, 0);
5725 start_index = SVAL(req->vwv+1, 0);
5727 /* we used to allow the client to get the cnum wrong, but that
5728 is really quite gross and only worked when there was only
5729 one printer - I think we should now only accept it if they
5730 get it right (tridge) */
5731 if (!CAN_PRINT(conn)) {
5732 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5733 END_PROFILE(SMBsplretq);
5734 return;
5737 reply_outbuf(req, 2, 3);
5738 SSVAL(req->outbuf,smb_vwv0,0);
5739 SSVAL(req->outbuf,smb_vwv1,0);
5740 SCVAL(smb_buf(req->outbuf),0,1);
5741 SSVAL(smb_buf(req->outbuf),1,0);
5743 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5744 start_index, max_count));
5747 TALLOC_CTX *mem_ctx = talloc_tos();
5748 NTSTATUS status;
5749 WERROR werr;
5750 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5751 struct rpc_pipe_client *cli = NULL;
5752 struct dcerpc_binding_handle *b = NULL;
5753 struct policy_handle handle;
5754 struct spoolss_DevmodeContainer devmode_ctr;
5755 union spoolss_JobInfo *info;
5756 uint32_t count;
5757 uint32_t num_to_get;
5758 uint32_t first;
5759 uint32_t i;
5761 ZERO_STRUCT(handle);
5763 status = rpc_pipe_open_interface(conn,
5764 &ndr_table_spoolss,
5765 conn->session_info,
5766 conn->sconn->remote_address,
5767 conn->sconn->msg_ctx,
5768 &cli);
5769 if (!NT_STATUS_IS_OK(status)) {
5770 DEBUG(0, ("reply_printqueue: "
5771 "could not connect to spoolss: %s\n",
5772 nt_errstr(status)));
5773 reply_nterror(req, status);
5774 goto out;
5776 b = cli->binding_handle;
5778 ZERO_STRUCT(devmode_ctr);
5780 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5781 sharename,
5782 NULL, devmode_ctr,
5783 SEC_FLAG_MAXIMUM_ALLOWED,
5784 &handle,
5785 &werr);
5786 if (!NT_STATUS_IS_OK(status)) {
5787 reply_nterror(req, status);
5788 goto out;
5790 if (!W_ERROR_IS_OK(werr)) {
5791 reply_nterror(req, werror_to_ntstatus(werr));
5792 goto out;
5795 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5796 &handle,
5797 0, /* firstjob */
5798 0xff, /* numjobs */
5799 2, /* level */
5800 0, /* offered */
5801 &count,
5802 &info);
5803 if (!W_ERROR_IS_OK(werr)) {
5804 reply_nterror(req, werror_to_ntstatus(werr));
5805 goto out;
5808 if (max_count > 0) {
5809 first = start_index;
5810 } else {
5811 first = start_index + max_count + 1;
5814 if (first >= count) {
5815 num_to_get = first;
5816 } else {
5817 num_to_get = first + MIN(ABS(max_count), count - first);
5820 for (i = first; i < num_to_get; i++) {
5821 char blob[28];
5822 char *p = blob;
5823 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5824 int qstatus;
5825 size_t len = 0;
5826 uint16_t qrapjobid = pjobid_to_rap(sharename,
5827 info[i].info2.job_id);
5829 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5830 qstatus = 2;
5831 } else {
5832 qstatus = 3;
5835 srv_put_dos_date2(p, 0, qtime);
5836 SCVAL(p, 4, qstatus);
5837 SSVAL(p, 5, qrapjobid);
5838 SIVAL(p, 7, info[i].info2.size);
5839 SCVAL(p, 11, 0);
5840 status = srvstr_push(blob, req->flags2, p+12,
5841 info[i].info2.notify_name, 16, STR_ASCII, &len);
5842 if (!NT_STATUS_IS_OK(status)) {
5843 reply_nterror(req, status);
5844 goto out;
5846 if (message_push_blob(
5847 &req->outbuf,
5848 data_blob_const(
5849 blob, sizeof(blob))) == -1) {
5850 reply_nterror(req, NT_STATUS_NO_MEMORY);
5851 goto out;
5855 if (count > 0) {
5856 SSVAL(req->outbuf,smb_vwv0,count);
5857 SSVAL(req->outbuf,smb_vwv1,
5858 (max_count>0?first+count:first-1));
5859 SCVAL(smb_buf(req->outbuf),0,1);
5860 SSVAL(smb_buf(req->outbuf),1,28*count);
5864 DEBUG(3, ("%u entries returned in queue\n",
5865 (unsigned)count));
5867 out:
5868 if (b && is_valid_policy_hnd(&handle)) {
5869 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5874 END_PROFILE(SMBsplretq);
5875 return;
5878 /****************************************************************************
5879 Reply to a printwrite.
5880 ****************************************************************************/
5882 void reply_printwrite(struct smb_request *req)
5884 connection_struct *conn = req->conn;
5885 int numtowrite;
5886 const char *data;
5887 files_struct *fsp;
5889 START_PROFILE(SMBsplwr);
5891 if (req->wct < 1) {
5892 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5893 END_PROFILE(SMBsplwr);
5894 return;
5897 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5899 if (!check_fsp(conn, req, fsp)) {
5900 END_PROFILE(SMBsplwr);
5901 return;
5904 if (!fsp->print_file) {
5905 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5906 END_PROFILE(SMBsplwr);
5907 return;
5910 if (!CHECK_WRITE(fsp)) {
5911 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5912 END_PROFILE(SMBsplwr);
5913 return;
5916 numtowrite = SVAL(req->buf, 1);
5918 if (req->buflen < numtowrite + 3) {
5919 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5920 END_PROFILE(SMBsplwr);
5921 return;
5924 data = (const char *)req->buf + 3;
5926 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5927 reply_nterror(req, map_nt_error_from_unix(errno));
5928 END_PROFILE(SMBsplwr);
5929 return;
5932 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5934 END_PROFILE(SMBsplwr);
5935 return;
5938 /****************************************************************************
5939 Reply to a mkdir.
5940 ****************************************************************************/
5942 void reply_mkdir(struct smb_request *req)
5944 connection_struct *conn = req->conn;
5945 struct smb_filename *smb_dname = NULL;
5946 char *directory = NULL;
5947 NTSTATUS status;
5948 TALLOC_CTX *ctx = talloc_tos();
5950 START_PROFILE(SMBmkdir);
5952 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5953 STR_TERMINATE, &status);
5954 if (!NT_STATUS_IS_OK(status)) {
5955 reply_nterror(req, status);
5956 goto out;
5959 status = filename_convert(ctx, conn,
5960 req->flags2 & FLAGS2_DFS_PATHNAMES,
5961 directory,
5962 UCF_PREP_CREATEFILE,
5963 NULL,
5964 &smb_dname);
5965 if (!NT_STATUS_IS_OK(status)) {
5966 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5967 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5968 ERRSRV, ERRbadpath);
5969 goto out;
5971 reply_nterror(req, status);
5972 goto out;
5975 status = create_directory(conn, req, smb_dname);
5977 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5979 if (!NT_STATUS_IS_OK(status)) {
5981 if (!use_nt_status()
5982 && NT_STATUS_EQUAL(status,
5983 NT_STATUS_OBJECT_NAME_COLLISION)) {
5985 * Yes, in the DOS error code case we get a
5986 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5987 * samba4 torture test.
5989 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5992 reply_nterror(req, status);
5993 goto out;
5996 reply_outbuf(req, 0, 0);
5998 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5999 out:
6000 TALLOC_FREE(smb_dname);
6001 END_PROFILE(SMBmkdir);
6002 return;
6005 /****************************************************************************
6006 Reply to a rmdir.
6007 ****************************************************************************/
6009 void reply_rmdir(struct smb_request *req)
6011 connection_struct *conn = req->conn;
6012 struct smb_filename *smb_dname = NULL;
6013 char *directory = NULL;
6014 NTSTATUS status;
6015 TALLOC_CTX *ctx = talloc_tos();
6016 files_struct *fsp = NULL;
6017 int info = 0;
6018 struct smbd_server_connection *sconn = req->sconn;
6020 START_PROFILE(SMBrmdir);
6022 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6023 STR_TERMINATE, &status);
6024 if (!NT_STATUS_IS_OK(status)) {
6025 reply_nterror(req, status);
6026 goto out;
6029 status = filename_convert(ctx, conn,
6030 req->flags2 & FLAGS2_DFS_PATHNAMES,
6031 directory,
6033 NULL,
6034 &smb_dname);
6035 if (!NT_STATUS_IS_OK(status)) {
6036 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6037 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6038 ERRSRV, ERRbadpath);
6039 goto out;
6041 reply_nterror(req, status);
6042 goto out;
6045 if (is_ntfs_stream_smb_fname(smb_dname)) {
6046 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6047 goto out;
6050 status = SMB_VFS_CREATE_FILE(
6051 conn, /* conn */
6052 req, /* req */
6053 0, /* root_dir_fid */
6054 smb_dname, /* fname */
6055 DELETE_ACCESS, /* access_mask */
6056 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6057 FILE_SHARE_DELETE),
6058 FILE_OPEN, /* create_disposition*/
6059 FILE_DIRECTORY_FILE, /* create_options */
6060 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6061 0, /* oplock_request */
6062 NULL, /* lease */
6063 0, /* allocation_size */
6064 0, /* private_flags */
6065 NULL, /* sd */
6066 NULL, /* ea_list */
6067 &fsp, /* result */
6068 &info, /* pinfo */
6069 NULL, NULL); /* create context */
6071 if (!NT_STATUS_IS_OK(status)) {
6072 if (open_was_deferred(req->xconn, req->mid)) {
6073 /* We have re-scheduled this call. */
6074 goto out;
6076 reply_nterror(req, status);
6077 goto out;
6080 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6081 if (!NT_STATUS_IS_OK(status)) {
6082 close_file(req, fsp, ERROR_CLOSE);
6083 reply_nterror(req, status);
6084 goto out;
6087 if (!set_delete_on_close(fsp, true,
6088 conn->session_info->security_token,
6089 conn->session_info->unix_token)) {
6090 close_file(req, fsp, ERROR_CLOSE);
6091 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6092 goto out;
6095 status = close_file(req, fsp, NORMAL_CLOSE);
6096 if (!NT_STATUS_IS_OK(status)) {
6097 reply_nterror(req, status);
6098 } else {
6099 reply_outbuf(req, 0, 0);
6102 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6104 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6105 out:
6106 TALLOC_FREE(smb_dname);
6107 END_PROFILE(SMBrmdir);
6108 return;
6111 /*******************************************************************
6112 Resolve wildcards in a filename rename.
6113 ********************************************************************/
6115 static bool resolve_wildcards(TALLOC_CTX *ctx,
6116 const char *name1,
6117 const char *name2,
6118 char **pp_newname)
6120 char *name2_copy = NULL;
6121 char *root1 = NULL;
6122 char *root2 = NULL;
6123 char *ext1 = NULL;
6124 char *ext2 = NULL;
6125 char *p,*p2, *pname1, *pname2;
6127 name2_copy = talloc_strdup(ctx, name2);
6128 if (!name2_copy) {
6129 return False;
6132 pname1 = strrchr_m(name1,'/');
6133 pname2 = strrchr_m(name2_copy,'/');
6135 if (!pname1 || !pname2) {
6136 return False;
6139 /* Truncate the copy of name2 at the last '/' */
6140 *pname2 = '\0';
6142 /* Now go past the '/' */
6143 pname1++;
6144 pname2++;
6146 root1 = talloc_strdup(ctx, pname1);
6147 root2 = talloc_strdup(ctx, pname2);
6149 if (!root1 || !root2) {
6150 return False;
6153 p = strrchr_m(root1,'.');
6154 if (p) {
6155 *p = 0;
6156 ext1 = talloc_strdup(ctx, p+1);
6157 } else {
6158 ext1 = talloc_strdup(ctx, "");
6160 p = strrchr_m(root2,'.');
6161 if (p) {
6162 *p = 0;
6163 ext2 = talloc_strdup(ctx, p+1);
6164 } else {
6165 ext2 = talloc_strdup(ctx, "");
6168 if (!ext1 || !ext2) {
6169 return False;
6172 p = root1;
6173 p2 = root2;
6174 while (*p2) {
6175 if (*p2 == '?') {
6176 /* Hmmm. Should this be mb-aware ? */
6177 *p2 = *p;
6178 p2++;
6179 } else if (*p2 == '*') {
6180 *p2 = '\0';
6181 root2 = talloc_asprintf(ctx, "%s%s",
6182 root2,
6184 if (!root2) {
6185 return False;
6187 break;
6188 } else {
6189 p2++;
6191 if (*p) {
6192 p++;
6196 p = ext1;
6197 p2 = ext2;
6198 while (*p2) {
6199 if (*p2 == '?') {
6200 /* Hmmm. Should this be mb-aware ? */
6201 *p2 = *p;
6202 p2++;
6203 } else if (*p2 == '*') {
6204 *p2 = '\0';
6205 ext2 = talloc_asprintf(ctx, "%s%s",
6206 ext2,
6208 if (!ext2) {
6209 return False;
6211 break;
6212 } else {
6213 p2++;
6215 if (*p) {
6216 p++;
6220 if (*ext2) {
6221 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6222 name2_copy,
6223 root2,
6224 ext2);
6225 } else {
6226 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6227 name2_copy,
6228 root2);
6231 if (!*pp_newname) {
6232 return False;
6235 return True;
6238 /****************************************************************************
6239 Ensure open files have their names updated. Updated to notify other smbd's
6240 asynchronously.
6241 ****************************************************************************/
6243 static void rename_open_files(connection_struct *conn,
6244 struct share_mode_lock *lck,
6245 struct file_id id,
6246 uint32_t orig_name_hash,
6247 const struct smb_filename *smb_fname_dst)
6249 files_struct *fsp;
6250 bool did_rename = False;
6251 NTSTATUS status;
6252 uint32_t new_name_hash = 0;
6254 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6255 fsp = file_find_di_next(fsp)) {
6256 /* fsp_name is a relative path under the fsp. To change this for other
6257 sharepaths we need to manipulate relative paths. */
6258 /* TODO - create the absolute path and manipulate the newname
6259 relative to the sharepath. */
6260 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6261 continue;
6263 if (fsp->name_hash != orig_name_hash) {
6264 continue;
6266 DEBUG(10, ("rename_open_files: renaming file %s "
6267 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6268 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6269 smb_fname_str_dbg(smb_fname_dst)));
6271 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6272 if (NT_STATUS_IS_OK(status)) {
6273 did_rename = True;
6274 new_name_hash = fsp->name_hash;
6278 if (!did_rename) {
6279 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6280 "for %s\n", file_id_string_tos(&id),
6281 smb_fname_str_dbg(smb_fname_dst)));
6284 /* Send messages to all smbd's (not ourself) that the name has changed. */
6285 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6286 orig_name_hash, new_name_hash,
6287 smb_fname_dst);
6291 /****************************************************************************
6292 We need to check if the source path is a parent directory of the destination
6293 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6294 refuse the rename with a sharing violation. Under UNIX the above call can
6295 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6296 probably need to check that the client is a Windows one before disallowing
6297 this as a UNIX client (one with UNIX extensions) can know the source is a
6298 symlink and make this decision intelligently. Found by an excellent bug
6299 report from <AndyLiebman@aol.com>.
6300 ****************************************************************************/
6302 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6303 const struct smb_filename *smb_fname_dst)
6305 const char *psrc = smb_fname_src->base_name;
6306 const char *pdst = smb_fname_dst->base_name;
6307 size_t slen;
6309 if (psrc[0] == '.' && psrc[1] == '/') {
6310 psrc += 2;
6312 if (pdst[0] == '.' && pdst[1] == '/') {
6313 pdst += 2;
6315 if ((slen = strlen(psrc)) > strlen(pdst)) {
6316 return False;
6318 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6322 * Do the notify calls from a rename
6325 static void notify_rename(connection_struct *conn, bool is_dir,
6326 const struct smb_filename *smb_fname_src,
6327 const struct smb_filename *smb_fname_dst)
6329 char *parent_dir_src = NULL;
6330 char *parent_dir_dst = NULL;
6331 uint32_t mask;
6333 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6334 : FILE_NOTIFY_CHANGE_FILE_NAME;
6336 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6337 &parent_dir_src, NULL) ||
6338 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6339 &parent_dir_dst, NULL)) {
6340 goto out;
6343 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6344 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6345 smb_fname_src->base_name);
6346 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6347 smb_fname_dst->base_name);
6349 else {
6350 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6351 smb_fname_src->base_name);
6352 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6353 smb_fname_dst->base_name);
6356 /* this is a strange one. w2k3 gives an additional event for
6357 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6358 files, but not directories */
6359 if (!is_dir) {
6360 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6361 FILE_NOTIFY_CHANGE_ATTRIBUTES
6362 |FILE_NOTIFY_CHANGE_CREATION,
6363 smb_fname_dst->base_name);
6365 out:
6366 TALLOC_FREE(parent_dir_src);
6367 TALLOC_FREE(parent_dir_dst);
6370 /****************************************************************************
6371 Returns an error if the parent directory for a filename is open in an
6372 incompatible way.
6373 ****************************************************************************/
6375 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6376 const struct smb_filename *smb_fname_dst_in)
6378 char *parent_dir = NULL;
6379 struct smb_filename smb_fname_parent;
6380 struct file_id id;
6381 files_struct *fsp = NULL;
6382 int ret;
6384 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6385 &parent_dir, NULL)) {
6386 return NT_STATUS_NO_MEMORY;
6388 ZERO_STRUCT(smb_fname_parent);
6389 smb_fname_parent.base_name = parent_dir;
6391 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6392 if (ret == -1) {
6393 return map_nt_error_from_unix(errno);
6397 * We're only checking on this smbd here, mostly good
6398 * enough.. and will pass tests.
6401 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6402 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6403 fsp = file_find_di_next(fsp)) {
6404 if (fsp->access_mask & DELETE_ACCESS) {
6405 return NT_STATUS_SHARING_VIOLATION;
6408 return NT_STATUS_OK;
6411 /****************************************************************************
6412 Rename an open file - given an fsp.
6413 ****************************************************************************/
6415 NTSTATUS rename_internals_fsp(connection_struct *conn,
6416 files_struct *fsp,
6417 const struct smb_filename *smb_fname_dst_in,
6418 uint32_t attrs,
6419 bool replace_if_exists)
6421 TALLOC_CTX *ctx = talloc_tos();
6422 struct smb_filename *smb_fname_dst = NULL;
6423 NTSTATUS status = NT_STATUS_OK;
6424 struct share_mode_lock *lck = NULL;
6425 bool dst_exists, old_is_stream, new_is_stream;
6427 status = check_name(conn, smb_fname_dst_in->base_name);
6428 if (!NT_STATUS_IS_OK(status)) {
6429 return status;
6432 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6433 if (!NT_STATUS_IS_OK(status)) {
6434 return status;
6437 /* Make a copy of the dst smb_fname structs */
6439 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6440 if (smb_fname_dst == NULL) {
6441 status = NT_STATUS_NO_MEMORY;
6442 goto out;
6446 * Check for special case with case preserving and not
6447 * case sensitive. If the old last component differs from the original
6448 * last component only by case, then we should allow
6449 * the rename (user is trying to change the case of the
6450 * filename).
6452 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6453 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6454 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6455 char *last_slash;
6456 char *fname_dst_lcomp_base_mod = NULL;
6457 struct smb_filename *smb_fname_orig_lcomp = NULL;
6460 * Get the last component of the destination name.
6462 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6463 if (last_slash) {
6464 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6465 } else {
6466 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6468 if (!fname_dst_lcomp_base_mod) {
6469 status = NT_STATUS_NO_MEMORY;
6470 goto out;
6474 * Create an smb_filename struct using the original last
6475 * component of the destination.
6477 smb_fname_orig_lcomp = synthetic_smb_fname_split(
6478 ctx, smb_fname_dst->original_lcomp, NULL);
6479 if (smb_fname_orig_lcomp == NULL) {
6480 status = NT_STATUS_NO_MEMORY;
6481 TALLOC_FREE(fname_dst_lcomp_base_mod);
6482 goto out;
6485 /* If the base names only differ by case, use original. */
6486 if(!strcsequal(fname_dst_lcomp_base_mod,
6487 smb_fname_orig_lcomp->base_name)) {
6488 char *tmp;
6490 * Replace the modified last component with the
6491 * original.
6493 if (last_slash) {
6494 *last_slash = '\0'; /* Truncate at the '/' */
6495 tmp = talloc_asprintf(smb_fname_dst,
6496 "%s/%s",
6497 smb_fname_dst->base_name,
6498 smb_fname_orig_lcomp->base_name);
6499 } else {
6500 tmp = talloc_asprintf(smb_fname_dst,
6501 "%s",
6502 smb_fname_orig_lcomp->base_name);
6504 if (tmp == NULL) {
6505 status = NT_STATUS_NO_MEMORY;
6506 TALLOC_FREE(fname_dst_lcomp_base_mod);
6507 TALLOC_FREE(smb_fname_orig_lcomp);
6508 goto out;
6510 TALLOC_FREE(smb_fname_dst->base_name);
6511 smb_fname_dst->base_name = tmp;
6514 /* If the stream_names only differ by case, use original. */
6515 if(!strcsequal(smb_fname_dst->stream_name,
6516 smb_fname_orig_lcomp->stream_name)) {
6517 char *tmp = NULL;
6518 /* Use the original stream. */
6519 tmp = talloc_strdup(smb_fname_dst,
6520 smb_fname_orig_lcomp->stream_name);
6521 if (tmp == NULL) {
6522 status = NT_STATUS_NO_MEMORY;
6523 TALLOC_FREE(fname_dst_lcomp_base_mod);
6524 TALLOC_FREE(smb_fname_orig_lcomp);
6525 goto out;
6527 TALLOC_FREE(smb_fname_dst->stream_name);
6528 smb_fname_dst->stream_name = tmp;
6530 TALLOC_FREE(fname_dst_lcomp_base_mod);
6531 TALLOC_FREE(smb_fname_orig_lcomp);
6535 * If the src and dest names are identical - including case,
6536 * don't do the rename, just return success.
6539 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6540 strcsequal(fsp->fsp_name->stream_name,
6541 smb_fname_dst->stream_name)) {
6542 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6543 "- returning success\n",
6544 smb_fname_str_dbg(smb_fname_dst)));
6545 status = NT_STATUS_OK;
6546 goto out;
6549 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6550 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6552 /* Return the correct error code if both names aren't streams. */
6553 if (!old_is_stream && new_is_stream) {
6554 status = NT_STATUS_OBJECT_NAME_INVALID;
6555 goto out;
6558 if (old_is_stream && !new_is_stream) {
6559 status = NT_STATUS_INVALID_PARAMETER;
6560 goto out;
6563 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6565 if(!replace_if_exists && dst_exists) {
6566 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6567 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6568 smb_fname_str_dbg(smb_fname_dst)));
6569 status = NT_STATUS_OBJECT_NAME_COLLISION;
6570 goto out;
6573 if (dst_exists) {
6574 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6575 &smb_fname_dst->st);
6576 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6577 fileid);
6578 /* The file can be open when renaming a stream */
6579 if (dst_fsp && !new_is_stream) {
6580 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6581 status = NT_STATUS_ACCESS_DENIED;
6582 goto out;
6586 /* Ensure we have a valid stat struct for the source. */
6587 status = vfs_stat_fsp(fsp);
6588 if (!NT_STATUS_IS_OK(status)) {
6589 goto out;
6592 status = can_rename(conn, fsp, attrs);
6594 if (!NT_STATUS_IS_OK(status)) {
6595 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6596 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6597 smb_fname_str_dbg(smb_fname_dst)));
6598 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6599 status = NT_STATUS_ACCESS_DENIED;
6600 goto out;
6603 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6604 status = NT_STATUS_ACCESS_DENIED;
6607 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6610 * We have the file open ourselves, so not being able to get the
6611 * corresponding share mode lock is a fatal error.
6614 SMB_ASSERT(lck != NULL);
6616 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6617 uint32_t create_options = fsp->fh->private_options;
6619 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6620 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6621 smb_fname_str_dbg(smb_fname_dst)));
6623 if (!fsp->is_directory &&
6624 !lp_posix_pathnames() &&
6625 (lp_map_archive(SNUM(conn)) ||
6626 lp_store_dos_attributes(SNUM(conn)))) {
6627 /* We must set the archive bit on the newly
6628 renamed file. */
6629 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6630 uint32_t old_dosmode = dos_mode(conn,
6631 smb_fname_dst);
6632 file_set_dosmode(conn,
6633 smb_fname_dst,
6634 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6635 NULL,
6636 true);
6640 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6641 smb_fname_dst);
6643 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6644 smb_fname_dst);
6647 * A rename acts as a new file create w.r.t. allowing an initial delete
6648 * on close, probably because in Windows there is a new handle to the
6649 * new file. If initial delete on close was requested but not
6650 * originally set, we need to set it here. This is probably not 100% correct,
6651 * but will work for the CIFSFS client which in non-posix mode
6652 * depends on these semantics. JRA.
6655 if (create_options & FILE_DELETE_ON_CLOSE) {
6656 status = can_set_delete_on_close(fsp, 0);
6658 if (NT_STATUS_IS_OK(status)) {
6659 /* Note that here we set the *inital* delete on close flag,
6660 * not the regular one. The magic gets handled in close. */
6661 fsp->initial_delete_on_close = True;
6664 TALLOC_FREE(lck);
6665 status = NT_STATUS_OK;
6666 goto out;
6669 TALLOC_FREE(lck);
6671 if (errno == ENOTDIR || errno == EISDIR) {
6672 status = NT_STATUS_OBJECT_NAME_COLLISION;
6673 } else {
6674 status = map_nt_error_from_unix(errno);
6677 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6678 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6679 smb_fname_str_dbg(smb_fname_dst)));
6681 out:
6682 TALLOC_FREE(smb_fname_dst);
6684 return status;
6687 /****************************************************************************
6688 The guts of the rename command, split out so it may be called by the NT SMB
6689 code.
6690 ****************************************************************************/
6692 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6693 connection_struct *conn,
6694 struct smb_request *req,
6695 struct smb_filename *smb_fname_src,
6696 struct smb_filename *smb_fname_dst,
6697 uint32_t attrs,
6698 bool replace_if_exists,
6699 bool src_has_wild,
6700 bool dest_has_wild,
6701 uint32_t access_mask)
6703 char *fname_src_dir = NULL;
6704 char *fname_src_mask = NULL;
6705 int count=0;
6706 NTSTATUS status = NT_STATUS_OK;
6707 struct smb_Dir *dir_hnd = NULL;
6708 const char *dname = NULL;
6709 char *talloced = NULL;
6710 long offset = 0;
6711 int create_options = 0;
6712 bool posix_pathnames = lp_posix_pathnames();
6713 int rc;
6716 * Split the old name into directory and last component
6717 * strings. Note that unix_convert may have stripped off a
6718 * leading ./ from both name and newname if the rename is
6719 * at the root of the share. We need to make sure either both
6720 * name and newname contain a / character or neither of them do
6721 * as this is checked in resolve_wildcards().
6724 /* Split up the directory from the filename/mask. */
6725 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6726 &fname_src_dir, &fname_src_mask);
6727 if (!NT_STATUS_IS_OK(status)) {
6728 status = NT_STATUS_NO_MEMORY;
6729 goto out;
6733 * We should only check the mangled cache
6734 * here if unix_convert failed. This means
6735 * that the path in 'mask' doesn't exist
6736 * on the file system and so we need to look
6737 * for a possible mangle. This patch from
6738 * Tine Smukavec <valentin.smukavec@hermes.si>.
6741 if (!VALID_STAT(smb_fname_src->st) &&
6742 mangle_is_mangled(fname_src_mask, conn->params)) {
6743 char *new_mask = NULL;
6744 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6745 conn->params);
6746 if (new_mask) {
6747 TALLOC_FREE(fname_src_mask);
6748 fname_src_mask = new_mask;
6752 if (!src_has_wild) {
6753 files_struct *fsp;
6756 * Only one file needs to be renamed. Append the mask back
6757 * onto the directory.
6759 TALLOC_FREE(smb_fname_src->base_name);
6760 if (ISDOT(fname_src_dir)) {
6761 /* Ensure we use canonical names on open. */
6762 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6763 "%s",
6764 fname_src_mask);
6765 } else {
6766 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6767 "%s/%s",
6768 fname_src_dir,
6769 fname_src_mask);
6771 if (!smb_fname_src->base_name) {
6772 status = NT_STATUS_NO_MEMORY;
6773 goto out;
6776 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6777 "case_preserve = %d, short case preserve = %d, "
6778 "directory = %s, newname = %s, "
6779 "last_component_dest = %s\n",
6780 conn->case_sensitive, conn->case_preserve,
6781 conn->short_case_preserve,
6782 smb_fname_str_dbg(smb_fname_src),
6783 smb_fname_str_dbg(smb_fname_dst),
6784 smb_fname_dst->original_lcomp));
6786 /* The dest name still may have wildcards. */
6787 if (dest_has_wild) {
6788 char *fname_dst_mod = NULL;
6789 if (!resolve_wildcards(smb_fname_dst,
6790 smb_fname_src->base_name,
6791 smb_fname_dst->base_name,
6792 &fname_dst_mod)) {
6793 DEBUG(6, ("rename_internals: resolve_wildcards "
6794 "%s %s failed\n",
6795 smb_fname_src->base_name,
6796 smb_fname_dst->base_name));
6797 status = NT_STATUS_NO_MEMORY;
6798 goto out;
6800 TALLOC_FREE(smb_fname_dst->base_name);
6801 smb_fname_dst->base_name = fname_dst_mod;
6804 ZERO_STRUCT(smb_fname_src->st);
6805 if (posix_pathnames) {
6806 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6807 } else {
6808 rc = SMB_VFS_STAT(conn, smb_fname_src);
6810 if (rc == -1) {
6811 status = map_nt_error_from_unix_common(errno);
6812 goto out;
6815 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6816 create_options |= FILE_DIRECTORY_FILE;
6819 status = SMB_VFS_CREATE_FILE(
6820 conn, /* conn */
6821 req, /* req */
6822 0, /* root_dir_fid */
6823 smb_fname_src, /* fname */
6824 access_mask, /* access_mask */
6825 (FILE_SHARE_READ | /* share_access */
6826 FILE_SHARE_WRITE),
6827 FILE_OPEN, /* create_disposition*/
6828 create_options, /* create_options */
6829 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6830 0, /* oplock_request */
6831 NULL, /* lease */
6832 0, /* allocation_size */
6833 0, /* private_flags */
6834 NULL, /* sd */
6835 NULL, /* ea_list */
6836 &fsp, /* result */
6837 NULL, /* pinfo */
6838 NULL, NULL); /* create context */
6840 if (!NT_STATUS_IS_OK(status)) {
6841 DEBUG(3, ("Could not open rename source %s: %s\n",
6842 smb_fname_str_dbg(smb_fname_src),
6843 nt_errstr(status)));
6844 goto out;
6847 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6848 attrs, replace_if_exists);
6850 close_file(req, fsp, NORMAL_CLOSE);
6852 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6853 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6854 smb_fname_str_dbg(smb_fname_dst)));
6856 goto out;
6860 * Wildcards - process each file that matches.
6862 if (strequal(fname_src_mask, "????????.???")) {
6863 TALLOC_FREE(fname_src_mask);
6864 fname_src_mask = talloc_strdup(ctx, "*");
6865 if (!fname_src_mask) {
6866 status = NT_STATUS_NO_MEMORY;
6867 goto out;
6871 status = check_name(conn, fname_src_dir);
6872 if (!NT_STATUS_IS_OK(status)) {
6873 goto out;
6876 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6877 attrs);
6878 if (dir_hnd == NULL) {
6879 status = map_nt_error_from_unix(errno);
6880 goto out;
6883 status = NT_STATUS_NO_SUCH_FILE;
6885 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6886 * - gentest fix. JRA
6889 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6890 &talloced))) {
6891 files_struct *fsp = NULL;
6892 char *destname = NULL;
6893 bool sysdir_entry = False;
6895 /* Quick check for "." and ".." */
6896 if (ISDOT(dname) || ISDOTDOT(dname)) {
6897 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6898 sysdir_entry = True;
6899 } else {
6900 TALLOC_FREE(talloced);
6901 continue;
6905 if (!is_visible_file(conn, fname_src_dir, dname,
6906 &smb_fname_src->st, false)) {
6907 TALLOC_FREE(talloced);
6908 continue;
6911 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6912 TALLOC_FREE(talloced);
6913 continue;
6916 if (sysdir_entry) {
6917 status = NT_STATUS_OBJECT_NAME_INVALID;
6918 break;
6921 TALLOC_FREE(smb_fname_src->base_name);
6922 if (ISDOT(fname_src_dir)) {
6923 /* Ensure we use canonical names on open. */
6924 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6925 "%s",
6926 dname);
6927 } else {
6928 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6929 "%s/%s",
6930 fname_src_dir,
6931 dname);
6933 if (!smb_fname_src->base_name) {
6934 status = NT_STATUS_NO_MEMORY;
6935 goto out;
6938 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6939 smb_fname_dst->base_name,
6940 &destname)) {
6941 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6942 smb_fname_src->base_name, destname));
6943 TALLOC_FREE(talloced);
6944 continue;
6946 if (!destname) {
6947 status = NT_STATUS_NO_MEMORY;
6948 goto out;
6951 TALLOC_FREE(smb_fname_dst->base_name);
6952 smb_fname_dst->base_name = destname;
6954 ZERO_STRUCT(smb_fname_src->st);
6955 if (posix_pathnames) {
6956 SMB_VFS_LSTAT(conn, smb_fname_src);
6957 } else {
6958 SMB_VFS_STAT(conn, smb_fname_src);
6961 create_options = 0;
6963 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6964 create_options |= FILE_DIRECTORY_FILE;
6967 status = SMB_VFS_CREATE_FILE(
6968 conn, /* conn */
6969 req, /* req */
6970 0, /* root_dir_fid */
6971 smb_fname_src, /* fname */
6972 access_mask, /* access_mask */
6973 (FILE_SHARE_READ | /* share_access */
6974 FILE_SHARE_WRITE),
6975 FILE_OPEN, /* create_disposition*/
6976 create_options, /* create_options */
6977 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6978 0, /* oplock_request */
6979 NULL, /* lease */
6980 0, /* allocation_size */
6981 0, /* private_flags */
6982 NULL, /* sd */
6983 NULL, /* ea_list */
6984 &fsp, /* result */
6985 NULL, /* pinfo */
6986 NULL, NULL); /* create context */
6988 if (!NT_STATUS_IS_OK(status)) {
6989 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6990 "returned %s rename %s -> %s\n",
6991 nt_errstr(status),
6992 smb_fname_str_dbg(smb_fname_src),
6993 smb_fname_str_dbg(smb_fname_dst)));
6994 break;
6997 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6998 dname);
6999 if (!smb_fname_dst->original_lcomp) {
7000 status = NT_STATUS_NO_MEMORY;
7001 goto out;
7004 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7005 attrs, replace_if_exists);
7007 close_file(req, fsp, NORMAL_CLOSE);
7009 if (!NT_STATUS_IS_OK(status)) {
7010 DEBUG(3, ("rename_internals_fsp returned %s for "
7011 "rename %s -> %s\n", nt_errstr(status),
7012 smb_fname_str_dbg(smb_fname_src),
7013 smb_fname_str_dbg(smb_fname_dst)));
7014 break;
7017 count++;
7019 DEBUG(3,("rename_internals: doing rename on %s -> "
7020 "%s\n", smb_fname_str_dbg(smb_fname_src),
7021 smb_fname_str_dbg(smb_fname_src)));
7022 TALLOC_FREE(talloced);
7024 TALLOC_FREE(dir_hnd);
7026 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7027 status = map_nt_error_from_unix(errno);
7030 out:
7031 TALLOC_FREE(talloced);
7032 TALLOC_FREE(fname_src_dir);
7033 TALLOC_FREE(fname_src_mask);
7034 return status;
7037 /****************************************************************************
7038 Reply to a mv.
7039 ****************************************************************************/
7041 void reply_mv(struct smb_request *req)
7043 connection_struct *conn = req->conn;
7044 char *name = NULL;
7045 char *newname = NULL;
7046 const char *p;
7047 uint32_t attrs;
7048 NTSTATUS status;
7049 bool src_has_wcard = False;
7050 bool dest_has_wcard = False;
7051 TALLOC_CTX *ctx = talloc_tos();
7052 struct smb_filename *smb_fname_src = NULL;
7053 struct smb_filename *smb_fname_dst = NULL;
7054 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
7055 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
7056 bool stream_rename = false;
7058 START_PROFILE(SMBmv);
7060 if (req->wct < 1) {
7061 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7062 goto out;
7065 attrs = SVAL(req->vwv+0, 0);
7067 p = (const char *)req->buf + 1;
7068 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7069 &status, &src_has_wcard);
7070 if (!NT_STATUS_IS_OK(status)) {
7071 reply_nterror(req, status);
7072 goto out;
7074 p++;
7075 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7076 &status, &dest_has_wcard);
7077 if (!NT_STATUS_IS_OK(status)) {
7078 reply_nterror(req, status);
7079 goto out;
7082 if (!lp_posix_pathnames()) {
7083 /* The newname must begin with a ':' if the
7084 name contains a ':'. */
7085 if (strchr_m(name, ':')) {
7086 if (newname[0] != ':') {
7087 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7088 goto out;
7090 stream_rename = true;
7094 status = filename_convert(ctx,
7095 conn,
7096 req->flags2 & FLAGS2_DFS_PATHNAMES,
7097 name,
7098 src_ucf_flags,
7099 &src_has_wcard,
7100 &smb_fname_src);
7102 if (!NT_STATUS_IS_OK(status)) {
7103 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7104 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7105 ERRSRV, ERRbadpath);
7106 goto out;
7108 reply_nterror(req, status);
7109 goto out;
7112 status = filename_convert(ctx,
7113 conn,
7114 req->flags2 & FLAGS2_DFS_PATHNAMES,
7115 newname,
7116 dst_ucf_flags,
7117 &dest_has_wcard,
7118 &smb_fname_dst);
7120 if (!NT_STATUS_IS_OK(status)) {
7121 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7122 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7123 ERRSRV, ERRbadpath);
7124 goto out;
7126 reply_nterror(req, status);
7127 goto out;
7130 if (stream_rename) {
7131 /* smb_fname_dst->base_name must be the same as
7132 smb_fname_src->base_name. */
7133 TALLOC_FREE(smb_fname_dst->base_name);
7134 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7135 smb_fname_src->base_name);
7136 if (!smb_fname_dst->base_name) {
7137 reply_nterror(req, NT_STATUS_NO_MEMORY);
7138 goto out;
7142 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7143 smb_fname_str_dbg(smb_fname_dst)));
7145 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7146 attrs, False, src_has_wcard, dest_has_wcard,
7147 DELETE_ACCESS);
7148 if (!NT_STATUS_IS_OK(status)) {
7149 if (open_was_deferred(req->xconn, req->mid)) {
7150 /* We have re-scheduled this call. */
7151 goto out;
7153 reply_nterror(req, status);
7154 goto out;
7157 reply_outbuf(req, 0, 0);
7158 out:
7159 TALLOC_FREE(smb_fname_src);
7160 TALLOC_FREE(smb_fname_dst);
7161 END_PROFILE(SMBmv);
7162 return;
7165 /*******************************************************************
7166 Copy a file as part of a reply_copy.
7167 ******************************************************************/
7170 * TODO: check error codes on all callers
7173 NTSTATUS copy_file(TALLOC_CTX *ctx,
7174 connection_struct *conn,
7175 struct smb_filename *smb_fname_src,
7176 struct smb_filename *smb_fname_dst,
7177 int ofun,
7178 int count,
7179 bool target_is_directory)
7181 struct smb_filename *smb_fname_dst_tmp = NULL;
7182 off_t ret=-1;
7183 files_struct *fsp1,*fsp2;
7184 uint32_t dosattrs;
7185 uint32_t new_create_disposition;
7186 NTSTATUS status;
7189 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7190 if (smb_fname_dst_tmp == NULL) {
7191 return NT_STATUS_NO_MEMORY;
7195 * If the target is a directory, extract the last component from the
7196 * src filename and append it to the dst filename
7198 if (target_is_directory) {
7199 const char *p;
7201 /* dest/target can't be a stream if it's a directory. */
7202 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7204 p = strrchr_m(smb_fname_src->base_name,'/');
7205 if (p) {
7206 p++;
7207 } else {
7208 p = smb_fname_src->base_name;
7210 smb_fname_dst_tmp->base_name =
7211 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7213 if (!smb_fname_dst_tmp->base_name) {
7214 status = NT_STATUS_NO_MEMORY;
7215 goto out;
7219 status = vfs_file_exist(conn, smb_fname_src);
7220 if (!NT_STATUS_IS_OK(status)) {
7221 goto out;
7224 if (!target_is_directory && count) {
7225 new_create_disposition = FILE_OPEN;
7226 } else {
7227 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7228 0, ofun,
7229 NULL, NULL,
7230 &new_create_disposition,
7231 NULL,
7232 NULL)) {
7233 status = NT_STATUS_INVALID_PARAMETER;
7234 goto out;
7238 /* Open the src file for reading. */
7239 status = SMB_VFS_CREATE_FILE(
7240 conn, /* conn */
7241 NULL, /* req */
7242 0, /* root_dir_fid */
7243 smb_fname_src, /* fname */
7244 FILE_GENERIC_READ, /* access_mask */
7245 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7246 FILE_OPEN, /* create_disposition*/
7247 0, /* create_options */
7248 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7249 INTERNAL_OPEN_ONLY, /* oplock_request */
7250 NULL, /* lease */
7251 0, /* allocation_size */
7252 0, /* private_flags */
7253 NULL, /* sd */
7254 NULL, /* ea_list */
7255 &fsp1, /* result */
7256 NULL, /* psbuf */
7257 NULL, NULL); /* create context */
7259 if (!NT_STATUS_IS_OK(status)) {
7260 goto out;
7263 dosattrs = dos_mode(conn, smb_fname_src);
7265 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7266 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7269 /* Open the dst file for writing. */
7270 status = SMB_VFS_CREATE_FILE(
7271 conn, /* conn */
7272 NULL, /* req */
7273 0, /* root_dir_fid */
7274 smb_fname_dst, /* fname */
7275 FILE_GENERIC_WRITE, /* access_mask */
7276 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7277 new_create_disposition, /* create_disposition*/
7278 0, /* create_options */
7279 dosattrs, /* file_attributes */
7280 INTERNAL_OPEN_ONLY, /* oplock_request */
7281 NULL, /* lease */
7282 0, /* allocation_size */
7283 0, /* private_flags */
7284 NULL, /* sd */
7285 NULL, /* ea_list */
7286 &fsp2, /* result */
7287 NULL, /* psbuf */
7288 NULL, NULL); /* create context */
7290 if (!NT_STATUS_IS_OK(status)) {
7291 close_file(NULL, fsp1, ERROR_CLOSE);
7292 goto out;
7295 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7296 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7297 if (ret == -1) {
7298 DEBUG(0, ("error - vfs lseek returned error %s\n",
7299 strerror(errno)));
7300 status = map_nt_error_from_unix(errno);
7301 close_file(NULL, fsp1, ERROR_CLOSE);
7302 close_file(NULL, fsp2, ERROR_CLOSE);
7303 goto out;
7307 /* Do the actual copy. */
7308 if (smb_fname_src->st.st_ex_size) {
7309 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7310 } else {
7311 ret = 0;
7314 close_file(NULL, fsp1, NORMAL_CLOSE);
7316 /* Ensure the modtime is set correctly on the destination file. */
7317 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7320 * As we are opening fsp1 read-only we only expect
7321 * an error on close on fsp2 if we are out of space.
7322 * Thus we don't look at the error return from the
7323 * close of fsp1.
7325 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7327 if (!NT_STATUS_IS_OK(status)) {
7328 goto out;
7331 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7332 status = NT_STATUS_DISK_FULL;
7333 goto out;
7336 status = NT_STATUS_OK;
7338 out:
7339 TALLOC_FREE(smb_fname_dst_tmp);
7340 return status;
7343 /****************************************************************************
7344 Reply to a file copy.
7345 ****************************************************************************/
7347 void reply_copy(struct smb_request *req)
7349 connection_struct *conn = req->conn;
7350 struct smb_filename *smb_fname_src = NULL;
7351 struct smb_filename *smb_fname_dst = NULL;
7352 char *fname_src = NULL;
7353 char *fname_dst = NULL;
7354 char *fname_src_mask = NULL;
7355 char *fname_src_dir = NULL;
7356 const char *p;
7357 int count=0;
7358 int error = ERRnoaccess;
7359 int tid2;
7360 int ofun;
7361 int flags;
7362 bool target_is_directory=False;
7363 bool source_has_wild = False;
7364 bool dest_has_wild = False;
7365 NTSTATUS status;
7366 TALLOC_CTX *ctx = talloc_tos();
7368 START_PROFILE(SMBcopy);
7370 if (req->wct < 3) {
7371 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7372 goto out;
7375 tid2 = SVAL(req->vwv+0, 0);
7376 ofun = SVAL(req->vwv+1, 0);
7377 flags = SVAL(req->vwv+2, 0);
7379 p = (const char *)req->buf;
7380 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7381 &status, &source_has_wild);
7382 if (!NT_STATUS_IS_OK(status)) {
7383 reply_nterror(req, status);
7384 goto out;
7386 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7387 &status, &dest_has_wild);
7388 if (!NT_STATUS_IS_OK(status)) {
7389 reply_nterror(req, status);
7390 goto out;
7393 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7395 if (tid2 != conn->cnum) {
7396 /* can't currently handle inter share copies XXXX */
7397 DEBUG(3,("Rejecting inter-share copy\n"));
7398 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7399 goto out;
7402 status = filename_convert(ctx, conn,
7403 req->flags2 & FLAGS2_DFS_PATHNAMES,
7404 fname_src,
7405 UCF_COND_ALLOW_WCARD_LCOMP,
7406 &source_has_wild,
7407 &smb_fname_src);
7408 if (!NT_STATUS_IS_OK(status)) {
7409 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7410 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7411 ERRSRV, ERRbadpath);
7412 goto out;
7414 reply_nterror(req, status);
7415 goto out;
7418 status = filename_convert(ctx, conn,
7419 req->flags2 & FLAGS2_DFS_PATHNAMES,
7420 fname_dst,
7421 UCF_COND_ALLOW_WCARD_LCOMP,
7422 &dest_has_wild,
7423 &smb_fname_dst);
7424 if (!NT_STATUS_IS_OK(status)) {
7425 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7426 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7427 ERRSRV, ERRbadpath);
7428 goto out;
7430 reply_nterror(req, status);
7431 goto out;
7434 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7436 if ((flags&1) && target_is_directory) {
7437 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7438 goto out;
7441 if ((flags&2) && !target_is_directory) {
7442 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7443 goto out;
7446 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7447 /* wants a tree copy! XXXX */
7448 DEBUG(3,("Rejecting tree copy\n"));
7449 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7450 goto out;
7453 /* Split up the directory from the filename/mask. */
7454 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7455 &fname_src_dir, &fname_src_mask);
7456 if (!NT_STATUS_IS_OK(status)) {
7457 reply_nterror(req, NT_STATUS_NO_MEMORY);
7458 goto out;
7462 * We should only check the mangled cache
7463 * here if unix_convert failed. This means
7464 * that the path in 'mask' doesn't exist
7465 * on the file system and so we need to look
7466 * for a possible mangle. This patch from
7467 * Tine Smukavec <valentin.smukavec@hermes.si>.
7469 if (!VALID_STAT(smb_fname_src->st) &&
7470 mangle_is_mangled(fname_src_mask, conn->params)) {
7471 char *new_mask = NULL;
7472 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7473 &new_mask, conn->params);
7475 /* Use demangled name if one was successfully found. */
7476 if (new_mask) {
7477 TALLOC_FREE(fname_src_mask);
7478 fname_src_mask = new_mask;
7482 if (!source_has_wild) {
7485 * Only one file needs to be copied. Append the mask back onto
7486 * the directory.
7488 TALLOC_FREE(smb_fname_src->base_name);
7489 if (ISDOT(fname_src_dir)) {
7490 /* Ensure we use canonical names on open. */
7491 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7492 "%s",
7493 fname_src_mask);
7494 } else {
7495 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7496 "%s/%s",
7497 fname_src_dir,
7498 fname_src_mask);
7500 if (!smb_fname_src->base_name) {
7501 reply_nterror(req, NT_STATUS_NO_MEMORY);
7502 goto out;
7505 if (dest_has_wild) {
7506 char *fname_dst_mod = NULL;
7507 if (!resolve_wildcards(smb_fname_dst,
7508 smb_fname_src->base_name,
7509 smb_fname_dst->base_name,
7510 &fname_dst_mod)) {
7511 reply_nterror(req, NT_STATUS_NO_MEMORY);
7512 goto out;
7514 TALLOC_FREE(smb_fname_dst->base_name);
7515 smb_fname_dst->base_name = fname_dst_mod;
7518 status = check_name(conn, smb_fname_src->base_name);
7519 if (!NT_STATUS_IS_OK(status)) {
7520 reply_nterror(req, status);
7521 goto out;
7524 status = check_name(conn, smb_fname_dst->base_name);
7525 if (!NT_STATUS_IS_OK(status)) {
7526 reply_nterror(req, status);
7527 goto out;
7530 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7531 ofun, count, target_is_directory);
7533 if(!NT_STATUS_IS_OK(status)) {
7534 reply_nterror(req, status);
7535 goto out;
7536 } else {
7537 count++;
7539 } else {
7540 struct smb_Dir *dir_hnd = NULL;
7541 const char *dname = NULL;
7542 char *talloced = NULL;
7543 long offset = 0;
7546 * There is a wildcard that requires us to actually read the
7547 * src dir and copy each file matching the mask to the dst.
7548 * Right now streams won't be copied, but this could
7549 * presumably be added with a nested loop for reach dir entry.
7551 SMB_ASSERT(!smb_fname_src->stream_name);
7552 SMB_ASSERT(!smb_fname_dst->stream_name);
7554 smb_fname_src->stream_name = NULL;
7555 smb_fname_dst->stream_name = NULL;
7557 if (strequal(fname_src_mask,"????????.???")) {
7558 TALLOC_FREE(fname_src_mask);
7559 fname_src_mask = talloc_strdup(ctx, "*");
7560 if (!fname_src_mask) {
7561 reply_nterror(req, NT_STATUS_NO_MEMORY);
7562 goto out;
7566 status = check_name(conn, fname_src_dir);
7567 if (!NT_STATUS_IS_OK(status)) {
7568 reply_nterror(req, status);
7569 goto out;
7572 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7573 if (dir_hnd == NULL) {
7574 status = map_nt_error_from_unix(errno);
7575 reply_nterror(req, status);
7576 goto out;
7579 error = ERRbadfile;
7581 /* Iterate over the src dir copying each entry to the dst. */
7582 while ((dname = ReadDirName(dir_hnd, &offset,
7583 &smb_fname_src->st, &talloced))) {
7584 char *destname = NULL;
7586 if (ISDOT(dname) || ISDOTDOT(dname)) {
7587 TALLOC_FREE(talloced);
7588 continue;
7591 if (!is_visible_file(conn, fname_src_dir, dname,
7592 &smb_fname_src->st, false)) {
7593 TALLOC_FREE(talloced);
7594 continue;
7597 if(!mask_match(dname, fname_src_mask,
7598 conn->case_sensitive)) {
7599 TALLOC_FREE(talloced);
7600 continue;
7603 error = ERRnoaccess;
7605 /* Get the src smb_fname struct setup. */
7606 TALLOC_FREE(smb_fname_src->base_name);
7607 if (ISDOT(fname_src_dir)) {
7608 /* Ensure we use canonical names on open. */
7609 smb_fname_src->base_name =
7610 talloc_asprintf(smb_fname_src, "%s",
7611 dname);
7612 } else {
7613 smb_fname_src->base_name =
7614 talloc_asprintf(smb_fname_src, "%s/%s",
7615 fname_src_dir, dname);
7618 if (!smb_fname_src->base_name) {
7619 TALLOC_FREE(dir_hnd);
7620 TALLOC_FREE(talloced);
7621 reply_nterror(req, NT_STATUS_NO_MEMORY);
7622 goto out;
7625 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7626 smb_fname_dst->base_name,
7627 &destname)) {
7628 TALLOC_FREE(talloced);
7629 continue;
7631 if (!destname) {
7632 TALLOC_FREE(dir_hnd);
7633 TALLOC_FREE(talloced);
7634 reply_nterror(req, NT_STATUS_NO_MEMORY);
7635 goto out;
7638 TALLOC_FREE(smb_fname_dst->base_name);
7639 smb_fname_dst->base_name = destname;
7641 status = check_name(conn, smb_fname_src->base_name);
7642 if (!NT_STATUS_IS_OK(status)) {
7643 TALLOC_FREE(dir_hnd);
7644 TALLOC_FREE(talloced);
7645 reply_nterror(req, status);
7646 goto out;
7649 status = check_name(conn, smb_fname_dst->base_name);
7650 if (!NT_STATUS_IS_OK(status)) {
7651 TALLOC_FREE(dir_hnd);
7652 TALLOC_FREE(talloced);
7653 reply_nterror(req, status);
7654 goto out;
7657 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7658 smb_fname_src->base_name,
7659 smb_fname_dst->base_name));
7661 status = copy_file(ctx, conn, smb_fname_src,
7662 smb_fname_dst, ofun, count,
7663 target_is_directory);
7664 if (NT_STATUS_IS_OK(status)) {
7665 count++;
7668 TALLOC_FREE(talloced);
7670 TALLOC_FREE(dir_hnd);
7673 if (count == 0) {
7674 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7675 goto out;
7678 reply_outbuf(req, 1, 0);
7679 SSVAL(req->outbuf,smb_vwv0,count);
7680 out:
7681 TALLOC_FREE(smb_fname_src);
7682 TALLOC_FREE(smb_fname_dst);
7683 TALLOC_FREE(fname_src);
7684 TALLOC_FREE(fname_dst);
7685 TALLOC_FREE(fname_src_mask);
7686 TALLOC_FREE(fname_src_dir);
7688 END_PROFILE(SMBcopy);
7689 return;
7692 #undef DBGC_CLASS
7693 #define DBGC_CLASS DBGC_LOCKING
7695 /****************************************************************************
7696 Get a lock pid, dealing with large count requests.
7697 ****************************************************************************/
7699 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7700 bool large_file_format)
7702 if(!large_file_format)
7703 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7704 else
7705 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7708 /****************************************************************************
7709 Get a lock count, dealing with large count requests.
7710 ****************************************************************************/
7712 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7713 bool large_file_format)
7715 uint64_t count = 0;
7717 if(!large_file_format) {
7718 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7719 } else {
7721 * No BVAL, this is reversed!
7723 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7724 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7727 return count;
7730 /****************************************************************************
7731 Get a lock offset, dealing with large offset requests.
7732 ****************************************************************************/
7734 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7735 bool large_file_format)
7737 uint64_t offset = 0;
7739 if(!large_file_format) {
7740 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7741 } else {
7743 * No BVAL, this is reversed!
7745 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7746 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7749 return offset;
7752 NTSTATUS smbd_do_locking(struct smb_request *req,
7753 files_struct *fsp,
7754 uint8_t type,
7755 int32_t timeout,
7756 uint16_t num_locks,
7757 struct smbd_lock_element *locks,
7758 bool *async)
7760 connection_struct *conn = req->conn;
7761 int i;
7762 NTSTATUS status = NT_STATUS_OK;
7764 *async = false;
7766 /* Setup the timeout in seconds. */
7768 if (!lp_blocking_locks(SNUM(conn))) {
7769 timeout = 0;
7772 for(i = 0; i < (int)num_locks; i++) {
7773 struct smbd_lock_element *e = &locks[i];
7775 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7776 "%llu, file %s timeout = %d\n",
7777 (double)e->offset,
7778 (double)e->count,
7779 (unsigned long long)e->smblctx,
7780 fsp_str_dbg(fsp),
7781 (int)timeout));
7783 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7784 struct blocking_lock_record *blr = NULL;
7786 if (num_locks > 1) {
7788 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7789 * if the lock vector contains one entry. When given multiple cancel
7790 * requests in a single PDU we expect the server to return an
7791 * error. Windows servers seem to accept the request but only
7792 * cancel the first lock.
7793 * JRA - Do what Windows does (tm) :-).
7796 #if 0
7797 /* MS-CIFS (2.2.4.32.1) behavior. */
7798 return NT_STATUS_DOS(ERRDOS,
7799 ERRcancelviolation);
7800 #else
7801 /* Windows behavior. */
7802 if (i != 0) {
7803 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7804 "cancel request\n"));
7805 continue;
7807 #endif
7810 if (lp_blocking_locks(SNUM(conn))) {
7812 /* Schedule a message to ourselves to
7813 remove the blocking lock record and
7814 return the right error. */
7816 blr = blocking_lock_cancel_smb1(fsp,
7817 e->smblctx,
7818 e->offset,
7819 e->count,
7820 WINDOWS_LOCK,
7821 type,
7822 NT_STATUS_FILE_LOCK_CONFLICT);
7823 if (blr == NULL) {
7824 return NT_STATUS_DOS(
7825 ERRDOS,
7826 ERRcancelviolation);
7829 /* Remove a matching pending lock. */
7830 status = do_lock_cancel(fsp,
7831 e->smblctx,
7832 e->count,
7833 e->offset,
7834 WINDOWS_LOCK);
7835 } else {
7836 bool blocking_lock = timeout ? true : false;
7837 bool defer_lock = false;
7838 struct byte_range_lock *br_lck;
7839 uint64_t block_smblctx;
7841 br_lck = do_lock(req->sconn->msg_ctx,
7842 fsp,
7843 e->smblctx,
7844 e->count,
7845 e->offset,
7846 e->brltype,
7847 WINDOWS_LOCK,
7848 blocking_lock,
7849 &status,
7850 &block_smblctx);
7852 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7853 /* Windows internal resolution for blocking locks seems
7854 to be about 200ms... Don't wait for less than that. JRA. */
7855 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7856 timeout = lp_lock_spin_time();
7858 defer_lock = true;
7861 /* If a lock sent with timeout of zero would fail, and
7862 * this lock has been requested multiple times,
7863 * according to brl_lock_failed() we convert this
7864 * request to a blocking lock with a timeout of between
7865 * 150 - 300 milliseconds.
7867 * If lp_lock_spin_time() has been set to 0, we skip
7868 * this blocking retry and fail immediately.
7870 * Replacement for do_lock_spin(). JRA. */
7872 if (!req->sconn->using_smb2 &&
7873 br_lck && lp_blocking_locks(SNUM(conn)) &&
7874 lp_lock_spin_time() && !blocking_lock &&
7875 NT_STATUS_EQUAL((status),
7876 NT_STATUS_FILE_LOCK_CONFLICT))
7878 defer_lock = true;
7879 timeout = lp_lock_spin_time();
7882 if (br_lck && defer_lock) {
7884 * A blocking lock was requested. Package up
7885 * this smb into a queued request and push it
7886 * onto the blocking lock queue.
7888 if(push_blocking_lock_request(br_lck,
7889 req,
7890 fsp,
7891 timeout,
7893 e->smblctx,
7894 e->brltype,
7895 WINDOWS_LOCK,
7896 e->offset,
7897 e->count,
7898 block_smblctx)) {
7899 TALLOC_FREE(br_lck);
7900 *async = true;
7901 return NT_STATUS_OK;
7905 TALLOC_FREE(br_lck);
7908 if (!NT_STATUS_IS_OK(status)) {
7909 break;
7913 /* If any of the above locks failed, then we must unlock
7914 all of the previous locks (X/Open spec). */
7916 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7918 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7919 i = -1; /* we want to skip the for loop */
7923 * Ensure we don't do a remove on the lock that just failed,
7924 * as under POSIX rules, if we have a lock already there, we
7925 * will delete it (and we shouldn't) .....
7927 for(i--; i >= 0; i--) {
7928 struct smbd_lock_element *e = &locks[i];
7930 do_unlock(req->sconn->msg_ctx,
7931 fsp,
7932 e->smblctx,
7933 e->count,
7934 e->offset,
7935 WINDOWS_LOCK);
7937 return status;
7940 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
7941 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
7943 return NT_STATUS_OK;
7946 NTSTATUS smbd_do_unlocking(struct smb_request *req,
7947 files_struct *fsp,
7948 uint16_t num_ulocks,
7949 struct smbd_lock_element *ulocks)
7951 int i;
7953 for(i = 0; i < (int)num_ulocks; i++) {
7954 struct smbd_lock_element *e = &ulocks[i];
7955 NTSTATUS status;
7957 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
7958 "pid %u, file %s\n", __func__,
7959 (double)e->offset,
7960 (double)e->count,
7961 (unsigned int)e->smblctx,
7962 fsp_str_dbg(fsp)));
7964 if (e->brltype != UNLOCK_LOCK) {
7965 /* this can only happen with SMB2 */
7966 return NT_STATUS_INVALID_PARAMETER;
7969 status = do_unlock(req->sconn->msg_ctx,
7970 fsp,
7971 e->smblctx,
7972 e->count,
7973 e->offset,
7974 WINDOWS_LOCK);
7976 DEBUG(10, ("%s: unlock returned %s\n", __func__,
7977 nt_errstr(status)));
7979 if (!NT_STATUS_IS_OK(status)) {
7980 return status;
7984 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
7985 num_ulocks));
7987 return NT_STATUS_OK;
7990 /****************************************************************************
7991 Reply to a lockingX request.
7992 ****************************************************************************/
7994 void reply_lockingX(struct smb_request *req)
7996 connection_struct *conn = req->conn;
7997 files_struct *fsp;
7998 unsigned char locktype;
7999 unsigned char oplocklevel;
8000 uint16_t num_ulocks;
8001 uint16_t num_locks;
8002 int32_t lock_timeout;
8003 int i;
8004 const uint8_t *data;
8005 bool large_file_format;
8006 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8007 struct smbd_lock_element *ulocks;
8008 struct smbd_lock_element *locks;
8009 bool async = false;
8011 START_PROFILE(SMBlockingX);
8013 if (req->wct < 8) {
8014 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8015 END_PROFILE(SMBlockingX);
8016 return;
8019 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8020 locktype = CVAL(req->vwv+3, 0);
8021 oplocklevel = CVAL(req->vwv+3, 1);
8022 num_ulocks = SVAL(req->vwv+6, 0);
8023 num_locks = SVAL(req->vwv+7, 0);
8024 lock_timeout = IVAL(req->vwv+4, 0);
8025 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8027 if (!check_fsp(conn, req, fsp)) {
8028 END_PROFILE(SMBlockingX);
8029 return;
8032 data = req->buf;
8034 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8035 /* we don't support these - and CANCEL_LOCK makes w2k
8036 and XP reboot so I don't really want to be
8037 compatible! (tridge) */
8038 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8039 END_PROFILE(SMBlockingX);
8040 return;
8043 /* Check if this is an oplock break on a file
8044 we have granted an oplock on.
8046 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8047 /* Client can insist on breaking to none. */
8048 bool break_to_none = (oplocklevel == 0);
8049 bool result;
8051 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8052 "for %s\n", (unsigned int)oplocklevel,
8053 fsp_fnum_dbg(fsp)));
8056 * Make sure we have granted an exclusive or batch oplock on
8057 * this file.
8060 if (fsp->oplock_type == 0) {
8062 /* The Samba4 nbench simulator doesn't understand
8063 the difference between break to level2 and break
8064 to none from level2 - it sends oplock break
8065 replies in both cases. Don't keep logging an error
8066 message here - just ignore it. JRA. */
8068 DEBUG(5,("reply_lockingX: Error : oplock break from "
8069 "client for %s (oplock=%d) and no "
8070 "oplock granted on this file (%s).\n",
8071 fsp_fnum_dbg(fsp), fsp->oplock_type,
8072 fsp_str_dbg(fsp)));
8074 /* if this is a pure oplock break request then don't
8075 * send a reply */
8076 if (num_locks == 0 && num_ulocks == 0) {
8077 END_PROFILE(SMBlockingX);
8078 return;
8079 } else {
8080 END_PROFILE(SMBlockingX);
8081 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8082 return;
8086 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8087 (break_to_none)) {
8088 result = remove_oplock(fsp);
8089 } else {
8090 result = downgrade_oplock(fsp);
8093 if (!result) {
8094 DEBUG(0, ("reply_lockingX: error in removing "
8095 "oplock on file %s\n", fsp_str_dbg(fsp)));
8096 /* Hmmm. Is this panic justified? */
8097 smb_panic("internal tdb error");
8100 /* if this is a pure oplock break request then don't send a
8101 * reply */
8102 if (num_locks == 0 && num_ulocks == 0) {
8103 /* Sanity check - ensure a pure oplock break is not a
8104 chained request. */
8105 if (CVAL(req->vwv+0, 0) != 0xff) {
8106 DEBUG(0,("reply_lockingX: Error : pure oplock "
8107 "break is a chained %d request !\n",
8108 (unsigned int)CVAL(req->vwv+0, 0)));
8110 END_PROFILE(SMBlockingX);
8111 return;
8115 if (req->buflen <
8116 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8117 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8118 END_PROFILE(SMBlockingX);
8119 return;
8122 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8123 if (ulocks == NULL) {
8124 reply_nterror(req, NT_STATUS_NO_MEMORY);
8125 END_PROFILE(SMBlockingX);
8126 return;
8129 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8130 if (locks == NULL) {
8131 reply_nterror(req, NT_STATUS_NO_MEMORY);
8132 END_PROFILE(SMBlockingX);
8133 return;
8136 /* Data now points at the beginning of the list
8137 of smb_unlkrng structs */
8138 for(i = 0; i < (int)num_ulocks; i++) {
8139 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8140 ulocks[i].count = get_lock_count(data, i, large_file_format);
8141 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8142 ulocks[i].brltype = UNLOCK_LOCK;
8145 /* Now do any requested locks */
8146 data += ((large_file_format ? 20 : 10)*num_ulocks);
8148 /* Data now points at the beginning of the list
8149 of smb_lkrng structs */
8151 for(i = 0; i < (int)num_locks; i++) {
8152 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8153 locks[i].count = get_lock_count(data, i, large_file_format);
8154 locks[i].offset = get_lock_offset(data, i, large_file_format);
8156 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8157 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8158 locks[i].brltype = PENDING_READ_LOCK;
8159 } else {
8160 locks[i].brltype = READ_LOCK;
8162 } else {
8163 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8164 locks[i].brltype = PENDING_WRITE_LOCK;
8165 } else {
8166 locks[i].brltype = WRITE_LOCK;
8171 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8172 if (!NT_STATUS_IS_OK(status)) {
8173 END_PROFILE(SMBlockingX);
8174 reply_nterror(req, status);
8175 return;
8178 status = smbd_do_locking(req, fsp,
8179 locktype, lock_timeout,
8180 num_locks, locks,
8181 &async);
8182 if (!NT_STATUS_IS_OK(status)) {
8183 END_PROFILE(SMBlockingX);
8184 reply_nterror(req, status);
8185 return;
8187 if (async) {
8188 END_PROFILE(SMBlockingX);
8189 return;
8192 reply_outbuf(req, 2, 0);
8193 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8194 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8196 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8197 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8199 END_PROFILE(SMBlockingX);
8202 #undef DBGC_CLASS
8203 #define DBGC_CLASS DBGC_ALL
8205 /****************************************************************************
8206 Reply to a SMBreadbmpx (read block multiplex) request.
8207 Always reply with an error, if someone has a platform really needs this,
8208 please contact vl@samba.org
8209 ****************************************************************************/
8211 void reply_readbmpx(struct smb_request *req)
8213 START_PROFILE(SMBreadBmpx);
8214 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8215 END_PROFILE(SMBreadBmpx);
8216 return;
8219 /****************************************************************************
8220 Reply to a SMBreadbs (read block multiplex secondary) request.
8221 Always reply with an error, if someone has a platform really needs this,
8222 please contact vl@samba.org
8223 ****************************************************************************/
8225 void reply_readbs(struct smb_request *req)
8227 START_PROFILE(SMBreadBs);
8228 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8229 END_PROFILE(SMBreadBs);
8230 return;
8233 /****************************************************************************
8234 Reply to a SMBsetattrE.
8235 ****************************************************************************/
8237 void reply_setattrE(struct smb_request *req)
8239 connection_struct *conn = req->conn;
8240 struct smb_file_time ft;
8241 files_struct *fsp;
8242 NTSTATUS status;
8244 START_PROFILE(SMBsetattrE);
8245 ZERO_STRUCT(ft);
8247 if (req->wct < 7) {
8248 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8249 goto out;
8252 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8254 if(!fsp || (fsp->conn != conn)) {
8255 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8256 goto out;
8260 * Convert the DOS times into unix times.
8263 ft.atime = convert_time_t_to_timespec(
8264 srv_make_unix_date2(req->vwv+3));
8265 ft.mtime = convert_time_t_to_timespec(
8266 srv_make_unix_date2(req->vwv+5));
8267 ft.create_time = convert_time_t_to_timespec(
8268 srv_make_unix_date2(req->vwv+1));
8270 reply_outbuf(req, 0, 0);
8273 * Patch from Ray Frush <frush@engr.colostate.edu>
8274 * Sometimes times are sent as zero - ignore them.
8277 /* Ensure we have a valid stat struct for the source. */
8278 status = vfs_stat_fsp(fsp);
8279 if (!NT_STATUS_IS_OK(status)) {
8280 reply_nterror(req, status);
8281 goto out;
8284 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8285 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8286 goto out;
8289 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8290 if (!NT_STATUS_IS_OK(status)) {
8291 reply_nterror(req, status);
8292 goto out;
8295 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8296 " createtime=%u\n",
8297 fsp_fnum_dbg(fsp),
8298 (unsigned int)ft.atime.tv_sec,
8299 (unsigned int)ft.mtime.tv_sec,
8300 (unsigned int)ft.create_time.tv_sec
8302 out:
8303 END_PROFILE(SMBsetattrE);
8304 return;
8308 /* Back from the dead for OS/2..... JRA. */
8310 /****************************************************************************
8311 Reply to a SMBwritebmpx (write block multiplex primary) request.
8312 Always reply with an error, if someone has a platform really needs this,
8313 please contact vl@samba.org
8314 ****************************************************************************/
8316 void reply_writebmpx(struct smb_request *req)
8318 START_PROFILE(SMBwriteBmpx);
8319 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8320 END_PROFILE(SMBwriteBmpx);
8321 return;
8324 /****************************************************************************
8325 Reply to a SMBwritebs (write block multiplex secondary) request.
8326 Always reply with an error, if someone has a platform really needs this,
8327 please contact vl@samba.org
8328 ****************************************************************************/
8330 void reply_writebs(struct smb_request *req)
8332 START_PROFILE(SMBwriteBs);
8333 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8334 END_PROFILE(SMBwriteBs);
8335 return;
8338 /****************************************************************************
8339 Reply to a SMBgetattrE.
8340 ****************************************************************************/
8342 void reply_getattrE(struct smb_request *req)
8344 connection_struct *conn = req->conn;
8345 int mode;
8346 files_struct *fsp;
8347 struct timespec create_ts;
8349 START_PROFILE(SMBgetattrE);
8351 if (req->wct < 1) {
8352 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8353 END_PROFILE(SMBgetattrE);
8354 return;
8357 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8359 if(!fsp || (fsp->conn != conn)) {
8360 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8361 END_PROFILE(SMBgetattrE);
8362 return;
8365 /* Do an fstat on this file */
8366 if(fsp_stat(fsp)) {
8367 reply_nterror(req, map_nt_error_from_unix(errno));
8368 END_PROFILE(SMBgetattrE);
8369 return;
8372 mode = dos_mode(conn, fsp->fsp_name);
8375 * Convert the times into dos times. Set create
8376 * date to be last modify date as UNIX doesn't save
8377 * this.
8380 reply_outbuf(req, 11, 0);
8382 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8383 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8384 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8385 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8386 /* Should we check pending modtime here ? JRA */
8387 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8388 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8390 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8391 SIVAL(req->outbuf, smb_vwv6, 0);
8392 SIVAL(req->outbuf, smb_vwv8, 0);
8393 } else {
8394 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8395 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8396 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8398 SSVAL(req->outbuf,smb_vwv10, mode);
8400 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8402 END_PROFILE(SMBgetattrE);
8403 return;