lib: Split out write_data[_iov]
[Samba.git] / source3 / smbd / reply.c
blob0b6c1024481fc31f7a173cfc338489eb678ca69c
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 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 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 perm1 = 0;
983 uint32 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 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 device;
1060 uint16 function;
1061 uint32 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)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 dfree,dsize,bsize;
1460 START_PROFILE(SMBdskattr);
1462 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1463 reply_nterror(req, map_nt_error_from_unix(errno));
1464 END_PROFILE(SMBdskattr);
1465 return;
1468 reply_outbuf(req, 5, 0);
1470 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1471 double total_space, free_space;
1472 /* we need to scale this to a number that DOS6 can handle. We
1473 use floating point so we can handle large drives on systems
1474 that don't have 64 bit integers
1476 we end up displaying a maximum of 2G to DOS systems
1478 total_space = dsize * (double)bsize;
1479 free_space = dfree * (double)bsize;
1481 dsize = (uint64_t)((total_space+63*512) / (64*512));
1482 dfree = (uint64_t)((free_space+63*512) / (64*512));
1484 if (dsize > 0xFFFF) dsize = 0xFFFF;
1485 if (dfree > 0xFFFF) dfree = 0xFFFF;
1487 SSVAL(req->outbuf,smb_vwv0,dsize);
1488 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1489 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1490 SSVAL(req->outbuf,smb_vwv3,dfree);
1491 } else {
1492 SSVAL(req->outbuf,smb_vwv0,dsize);
1493 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1494 SSVAL(req->outbuf,smb_vwv2,512);
1495 SSVAL(req->outbuf,smb_vwv3,dfree);
1498 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1500 END_PROFILE(SMBdskattr);
1501 return;
1505 * Utility function to split the filename from the directory.
1507 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1508 char **fname_dir_out,
1509 char **fname_mask_out)
1511 const char *p = NULL;
1512 char *fname_dir = NULL;
1513 char *fname_mask = NULL;
1515 p = strrchr_m(fname_in, '/');
1516 if (!p) {
1517 fname_dir = talloc_strdup(ctx, ".");
1518 fname_mask = talloc_strdup(ctx, fname_in);
1519 } else {
1520 fname_dir = talloc_strndup(ctx, fname_in,
1521 PTR_DIFF(p, fname_in));
1522 fname_mask = talloc_strdup(ctx, p+1);
1525 if (!fname_dir || !fname_mask) {
1526 TALLOC_FREE(fname_dir);
1527 TALLOC_FREE(fname_mask);
1528 return NT_STATUS_NO_MEMORY;
1531 *fname_dir_out = fname_dir;
1532 *fname_mask_out = fname_mask;
1533 return NT_STATUS_OK;
1536 /****************************************************************************
1537 Make a dir struct.
1538 ****************************************************************************/
1540 static bool make_dir_struct(TALLOC_CTX *ctx,
1541 char *buf,
1542 const char *mask,
1543 const char *fname,
1544 off_t size,
1545 uint32 mode,
1546 time_t date,
1547 bool uc)
1549 char *p;
1550 char *mask2 = talloc_strdup(ctx, mask);
1552 if (!mask2) {
1553 return False;
1556 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1557 size = 0;
1560 memset(buf+1,' ',11);
1561 if ((p = strchr_m(mask2,'.')) != NULL) {
1562 *p = 0;
1563 push_ascii(buf+1,mask2,8, 0);
1564 push_ascii(buf+9,p+1,3, 0);
1565 *p = '.';
1566 } else {
1567 push_ascii(buf+1,mask2,11, 0);
1570 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1571 SCVAL(buf,21,mode);
1572 srv_put_dos_date(buf,22,date);
1573 SSVAL(buf,26,size & 0xFFFF);
1574 SSVAL(buf,28,(size >> 16)&0xFFFF);
1575 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1576 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1577 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1578 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1579 return True;
1582 /****************************************************************************
1583 Reply to a search.
1584 Can be called from SMBsearch, SMBffirst or SMBfunique.
1585 ****************************************************************************/
1587 void reply_search(struct smb_request *req)
1589 connection_struct *conn = req->conn;
1590 char *path = NULL;
1591 const char *mask = NULL;
1592 char *directory = NULL;
1593 struct smb_filename *smb_fname = NULL;
1594 char *fname = NULL;
1595 off_t size;
1596 uint32 mode;
1597 struct timespec date;
1598 uint32 dirtype;
1599 unsigned int numentries = 0;
1600 unsigned int maxentries = 0;
1601 bool finished = False;
1602 const char *p;
1603 int status_len;
1604 char status[21];
1605 int dptr_num= -1;
1606 bool check_descend = False;
1607 bool expect_close = False;
1608 NTSTATUS nt_status;
1609 bool mask_contains_wcard = False;
1610 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1611 TALLOC_CTX *ctx = talloc_tos();
1612 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1613 struct dptr_struct *dirptr = NULL;
1614 struct smbXsrv_connection *xconn = req->xconn;
1615 struct smbd_server_connection *sconn = req->sconn;
1617 START_PROFILE(SMBsearch);
1619 if (req->wct < 2) {
1620 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1621 goto out;
1624 if (lp_posix_pathnames()) {
1625 reply_unknown_new(req, req->cmd);
1626 goto out;
1629 /* If we were called as SMBffirst then we must expect close. */
1630 if(req->cmd == SMBffirst) {
1631 expect_close = True;
1634 reply_outbuf(req, 1, 3);
1635 maxentries = SVAL(req->vwv+0, 0);
1636 dirtype = SVAL(req->vwv+1, 0);
1637 p = (const char *)req->buf + 1;
1638 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1639 &nt_status, &mask_contains_wcard);
1640 if (!NT_STATUS_IS_OK(nt_status)) {
1641 reply_nterror(req, nt_status);
1642 goto out;
1645 p++;
1646 status_len = SVAL(p, 0);
1647 p += 2;
1649 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1651 if (status_len == 0) {
1652 nt_status = filename_convert(ctx, conn,
1653 req->flags2 & FLAGS2_DFS_PATHNAMES,
1654 path,
1655 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1656 &mask_contains_wcard,
1657 &smb_fname);
1658 if (!NT_STATUS_IS_OK(nt_status)) {
1659 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1660 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1661 ERRSRV, ERRbadpath);
1662 goto out;
1664 reply_nterror(req, nt_status);
1665 goto out;
1668 directory = smb_fname->base_name;
1670 p = strrchr_m(directory,'/');
1671 if ((p != NULL) && (*directory != '/')) {
1672 mask = p + 1;
1673 directory = talloc_strndup(ctx, directory,
1674 PTR_DIFF(p, directory));
1675 } else {
1676 mask = directory;
1677 directory = talloc_strdup(ctx,".");
1680 if (!directory) {
1681 reply_nterror(req, NT_STATUS_NO_MEMORY);
1682 goto out;
1685 memset((char *)status,'\0',21);
1686 SCVAL(status,0,(dirtype & 0x1F));
1688 nt_status = dptr_create(conn,
1689 NULL, /* req */
1690 NULL, /* fsp */
1691 directory,
1692 True,
1693 expect_close,
1694 req->smbpid,
1695 mask,
1696 mask_contains_wcard,
1697 dirtype,
1698 &dirptr);
1699 if (!NT_STATUS_IS_OK(nt_status)) {
1700 reply_nterror(req, nt_status);
1701 goto out;
1703 dptr_num = dptr_dnum(dirptr);
1704 } else {
1705 int status_dirtype;
1706 const char *dirpath;
1708 memcpy(status,p,21);
1709 status_dirtype = CVAL(status,0) & 0x1F;
1710 if (status_dirtype != (dirtype & 0x1F)) {
1711 dirtype = status_dirtype;
1714 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1715 if (!dirptr) {
1716 goto SearchEmpty;
1718 dirpath = dptr_path(sconn, dptr_num);
1719 directory = talloc_strdup(ctx, dirpath);
1720 if (!directory) {
1721 reply_nterror(req, NT_STATUS_NO_MEMORY);
1722 goto out;
1725 mask = dptr_wcard(sconn, dptr_num);
1726 if (!mask) {
1727 goto SearchEmpty;
1730 * For a 'continue' search we have no string. So
1731 * check from the initial saved string.
1733 mask_contains_wcard = ms_has_wild(mask);
1734 dirtype = dptr_attr(sconn, dptr_num);
1737 DEBUG(4,("dptr_num is %d\n",dptr_num));
1739 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1740 dptr_init_search_op(dirptr);
1742 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1743 char buf[DIR_STRUCT_SIZE];
1744 memcpy(buf,status,21);
1745 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1746 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1747 reply_nterror(req, NT_STATUS_NO_MEMORY);
1748 goto out;
1750 dptr_fill(sconn, buf+12,dptr_num);
1751 if (dptr_zero(buf+12) && (status_len==0)) {
1752 numentries = 1;
1753 } else {
1754 numentries = 0;
1756 if (message_push_blob(&req->outbuf,
1757 data_blob_const(buf, sizeof(buf)))
1758 == -1) {
1759 reply_nterror(req, NT_STATUS_NO_MEMORY);
1760 goto out;
1762 } else {
1763 unsigned int i;
1764 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1765 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1767 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1769 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1770 directory,lp_dont_descend(ctx, SNUM(conn))));
1771 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1772 check_descend = True;
1775 for (i=numentries;(i<maxentries) && !finished;i++) {
1776 finished = !get_dir_entry(ctx,
1777 dirptr,
1778 mask,
1779 dirtype,
1780 &fname,
1781 &size,
1782 &mode,
1783 &date,
1784 check_descend,
1785 ask_sharemode);
1786 if (!finished) {
1787 char buf[DIR_STRUCT_SIZE];
1788 memcpy(buf,status,21);
1789 if (!make_dir_struct(ctx,
1790 buf,
1791 mask,
1792 fname,
1793 size,
1794 mode,
1795 convert_timespec_to_time_t(date),
1796 !allow_long_path_components)) {
1797 reply_nterror(req, NT_STATUS_NO_MEMORY);
1798 goto out;
1800 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1801 break;
1803 if (message_push_blob(&req->outbuf,
1804 data_blob_const(buf, sizeof(buf)))
1805 == -1) {
1806 reply_nterror(req, NT_STATUS_NO_MEMORY);
1807 goto out;
1809 numentries++;
1814 SearchEmpty:
1816 /* If we were called as SMBffirst with smb_search_id == NULL
1817 and no entries were found then return error and close dirptr
1818 (X/Open spec) */
1820 if (numentries == 0) {
1821 dptr_close(sconn, &dptr_num);
1822 } else if(expect_close && status_len == 0) {
1823 /* Close the dptr - we know it's gone */
1824 dptr_close(sconn, &dptr_num);
1827 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1828 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1829 dptr_close(sconn, &dptr_num);
1832 if ((numentries == 0) && !mask_contains_wcard) {
1833 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1834 goto out;
1837 SSVAL(req->outbuf,smb_vwv0,numentries);
1838 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1839 SCVAL(smb_buf(req->outbuf),0,5);
1840 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1842 /* The replies here are never long name. */
1843 SSVAL(req->outbuf, smb_flg2,
1844 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1845 if (!allow_long_path_components) {
1846 SSVAL(req->outbuf, smb_flg2,
1847 SVAL(req->outbuf, smb_flg2)
1848 & (~FLAGS2_LONG_PATH_COMPONENTS));
1851 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1852 SSVAL(req->outbuf, smb_flg2,
1853 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1855 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1856 smb_fn_name(req->cmd),
1857 mask,
1858 directory,
1859 dirtype,
1860 numentries,
1861 maxentries ));
1862 out:
1863 TALLOC_FREE(directory);
1864 TALLOC_FREE(smb_fname);
1865 END_PROFILE(SMBsearch);
1866 return;
1869 /****************************************************************************
1870 Reply to a fclose (stop directory search).
1871 ****************************************************************************/
1873 void reply_fclose(struct smb_request *req)
1875 int status_len;
1876 char status[21];
1877 int dptr_num= -2;
1878 const char *p;
1879 char *path = NULL;
1880 NTSTATUS err;
1881 bool path_contains_wcard = False;
1882 TALLOC_CTX *ctx = talloc_tos();
1883 struct smbd_server_connection *sconn = req->sconn;
1885 START_PROFILE(SMBfclose);
1887 if (lp_posix_pathnames()) {
1888 reply_unknown_new(req, req->cmd);
1889 END_PROFILE(SMBfclose);
1890 return;
1893 p = (const char *)req->buf + 1;
1894 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1895 &err, &path_contains_wcard);
1896 if (!NT_STATUS_IS_OK(err)) {
1897 reply_nterror(req, err);
1898 END_PROFILE(SMBfclose);
1899 return;
1901 p++;
1902 status_len = SVAL(p,0);
1903 p += 2;
1905 if (status_len == 0) {
1906 reply_force_doserror(req, ERRSRV, ERRsrverror);
1907 END_PROFILE(SMBfclose);
1908 return;
1911 memcpy(status,p,21);
1913 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1914 /* Close the dptr - we know it's gone */
1915 dptr_close(sconn, &dptr_num);
1918 reply_outbuf(req, 1, 0);
1919 SSVAL(req->outbuf,smb_vwv0,0);
1921 DEBUG(3,("search close\n"));
1923 END_PROFILE(SMBfclose);
1924 return;
1927 /****************************************************************************
1928 Reply to an open.
1929 ****************************************************************************/
1931 void reply_open(struct smb_request *req)
1933 connection_struct *conn = req->conn;
1934 struct smb_filename *smb_fname = NULL;
1935 char *fname = NULL;
1936 uint32 fattr=0;
1937 off_t size = 0;
1938 time_t mtime=0;
1939 int info;
1940 files_struct *fsp;
1941 int oplock_request;
1942 int deny_mode;
1943 uint32 dos_attr;
1944 uint32 access_mask;
1945 uint32 share_mode;
1946 uint32 create_disposition;
1947 uint32 create_options = 0;
1948 uint32_t private_flags = 0;
1949 NTSTATUS status;
1950 TALLOC_CTX *ctx = talloc_tos();
1952 START_PROFILE(SMBopen);
1954 if (req->wct < 2) {
1955 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1956 goto out;
1959 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1960 deny_mode = SVAL(req->vwv+0, 0);
1961 dos_attr = SVAL(req->vwv+1, 0);
1963 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1964 STR_TERMINATE, &status);
1965 if (!NT_STATUS_IS_OK(status)) {
1966 reply_nterror(req, status);
1967 goto out;
1970 if (!map_open_params_to_ntcreate(fname, deny_mode,
1971 OPENX_FILE_EXISTS_OPEN, &access_mask,
1972 &share_mode, &create_disposition,
1973 &create_options, &private_flags)) {
1974 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1975 goto out;
1978 status = filename_convert(ctx,
1979 conn,
1980 req->flags2 & FLAGS2_DFS_PATHNAMES,
1981 fname,
1982 UCF_PREP_CREATEFILE,
1983 NULL,
1984 &smb_fname);
1985 if (!NT_STATUS_IS_OK(status)) {
1986 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1987 reply_botherror(req,
1988 NT_STATUS_PATH_NOT_COVERED,
1989 ERRSRV, ERRbadpath);
1990 goto out;
1992 reply_nterror(req, status);
1993 goto out;
1996 status = SMB_VFS_CREATE_FILE(
1997 conn, /* conn */
1998 req, /* req */
1999 0, /* root_dir_fid */
2000 smb_fname, /* fname */
2001 access_mask, /* access_mask */
2002 share_mode, /* share_access */
2003 create_disposition, /* create_disposition*/
2004 create_options, /* create_options */
2005 dos_attr, /* file_attributes */
2006 oplock_request, /* oplock_request */
2007 NULL, /* lease */
2008 0, /* allocation_size */
2009 private_flags,
2010 NULL, /* sd */
2011 NULL, /* ea_list */
2012 &fsp, /* result */
2013 &info, /* pinfo */
2014 NULL, NULL); /* create context */
2016 if (!NT_STATUS_IS_OK(status)) {
2017 if (open_was_deferred(req->xconn, req->mid)) {
2018 /* We have re-scheduled this call. */
2019 goto out;
2021 reply_openerror(req, status);
2022 goto out;
2025 /* Ensure we're pointing at the correct stat struct. */
2026 TALLOC_FREE(smb_fname);
2027 smb_fname = fsp->fsp_name;
2029 size = smb_fname->st.st_ex_size;
2030 fattr = dos_mode(conn, smb_fname);
2032 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2034 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2035 DEBUG(3,("attempt to open a directory %s\n",
2036 fsp_str_dbg(fsp)));
2037 close_file(req, fsp, ERROR_CLOSE);
2038 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2039 ERRDOS, ERRnoaccess);
2040 goto out;
2043 reply_outbuf(req, 7, 0);
2044 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2045 SSVAL(req->outbuf,smb_vwv1,fattr);
2046 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2047 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2048 } else {
2049 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2051 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
2052 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2054 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2055 SCVAL(req->outbuf,smb_flg,
2056 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2059 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2060 SCVAL(req->outbuf,smb_flg,
2061 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2063 out:
2064 END_PROFILE(SMBopen);
2065 return;
2068 /****************************************************************************
2069 Reply to an open and X.
2070 ****************************************************************************/
2072 void reply_open_and_X(struct smb_request *req)
2074 connection_struct *conn = req->conn;
2075 struct smb_filename *smb_fname = NULL;
2076 char *fname = NULL;
2077 uint16 open_flags;
2078 int deny_mode;
2079 uint32 smb_attr;
2080 /* Breakout the oplock request bits so we can set the
2081 reply bits separately. */
2082 int ex_oplock_request;
2083 int core_oplock_request;
2084 int oplock_request;
2085 #if 0
2086 int smb_sattr = SVAL(req->vwv+4, 0);
2087 uint32 smb_time = make_unix_date3(req->vwv+6);
2088 #endif
2089 int smb_ofun;
2090 uint32 fattr=0;
2091 int mtime=0;
2092 int smb_action = 0;
2093 files_struct *fsp;
2094 NTSTATUS status;
2095 uint64_t allocation_size;
2096 ssize_t retval = -1;
2097 uint32 access_mask;
2098 uint32 share_mode;
2099 uint32 create_disposition;
2100 uint32 create_options = 0;
2101 uint32_t private_flags = 0;
2102 TALLOC_CTX *ctx = talloc_tos();
2104 START_PROFILE(SMBopenX);
2106 if (req->wct < 15) {
2107 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2108 goto out;
2111 open_flags = SVAL(req->vwv+2, 0);
2112 deny_mode = SVAL(req->vwv+3, 0);
2113 smb_attr = SVAL(req->vwv+5, 0);
2114 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2115 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2116 oplock_request = ex_oplock_request | core_oplock_request;
2117 smb_ofun = SVAL(req->vwv+8, 0);
2118 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2120 /* If it's an IPC, pass off the pipe handler. */
2121 if (IS_IPC(conn)) {
2122 if (lp_nt_pipe_support()) {
2123 reply_open_pipe_and_X(conn, req);
2124 } else {
2125 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2127 goto out;
2130 /* XXXX we need to handle passed times, sattr and flags */
2131 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2132 STR_TERMINATE, &status);
2133 if (!NT_STATUS_IS_OK(status)) {
2134 reply_nterror(req, status);
2135 goto out;
2138 if (!map_open_params_to_ntcreate(fname, deny_mode,
2139 smb_ofun,
2140 &access_mask, &share_mode,
2141 &create_disposition,
2142 &create_options,
2143 &private_flags)) {
2144 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2145 goto out;
2148 status = filename_convert(ctx,
2149 conn,
2150 req->flags2 & FLAGS2_DFS_PATHNAMES,
2151 fname,
2152 UCF_PREP_CREATEFILE,
2153 NULL,
2154 &smb_fname);
2155 if (!NT_STATUS_IS_OK(status)) {
2156 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2157 reply_botherror(req,
2158 NT_STATUS_PATH_NOT_COVERED,
2159 ERRSRV, ERRbadpath);
2160 goto out;
2162 reply_nterror(req, status);
2163 goto out;
2166 status = SMB_VFS_CREATE_FILE(
2167 conn, /* conn */
2168 req, /* req */
2169 0, /* root_dir_fid */
2170 smb_fname, /* fname */
2171 access_mask, /* access_mask */
2172 share_mode, /* share_access */
2173 create_disposition, /* create_disposition*/
2174 create_options, /* create_options */
2175 smb_attr, /* file_attributes */
2176 oplock_request, /* oplock_request */
2177 NULL, /* lease */
2178 0, /* allocation_size */
2179 private_flags,
2180 NULL, /* sd */
2181 NULL, /* ea_list */
2182 &fsp, /* result */
2183 &smb_action, /* pinfo */
2184 NULL, NULL); /* create context */
2186 if (!NT_STATUS_IS_OK(status)) {
2187 if (open_was_deferred(req->xconn, req->mid)) {
2188 /* We have re-scheduled this call. */
2189 goto out;
2191 reply_openerror(req, status);
2192 goto out;
2195 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2196 if the file is truncated or created. */
2197 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2198 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2199 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2200 close_file(req, fsp, ERROR_CLOSE);
2201 reply_nterror(req, NT_STATUS_DISK_FULL);
2202 goto out;
2204 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2205 if (retval < 0) {
2206 close_file(req, fsp, ERROR_CLOSE);
2207 reply_nterror(req, NT_STATUS_DISK_FULL);
2208 goto out;
2210 status = vfs_stat_fsp(fsp);
2211 if (!NT_STATUS_IS_OK(status)) {
2212 close_file(req, fsp, ERROR_CLOSE);
2213 reply_nterror(req, status);
2214 goto out;
2218 fattr = dos_mode(conn, fsp->fsp_name);
2219 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2220 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2221 close_file(req, fsp, ERROR_CLOSE);
2222 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2223 goto out;
2226 /* If the caller set the extended oplock request bit
2227 and we granted one (by whatever means) - set the
2228 correct bit for extended oplock reply.
2231 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2232 smb_action |= EXTENDED_OPLOCK_GRANTED;
2235 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2236 smb_action |= EXTENDED_OPLOCK_GRANTED;
2239 /* If the caller set the core oplock request bit
2240 and we granted one (by whatever means) - set the
2241 correct bit for core oplock reply.
2244 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2245 reply_outbuf(req, 19, 0);
2246 } else {
2247 reply_outbuf(req, 15, 0);
2250 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2251 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2253 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2254 SCVAL(req->outbuf, smb_flg,
2255 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2258 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2259 SCVAL(req->outbuf, smb_flg,
2260 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2263 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2264 SSVAL(req->outbuf,smb_vwv3,fattr);
2265 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2266 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2267 } else {
2268 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2270 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2271 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2272 SSVAL(req->outbuf,smb_vwv11,smb_action);
2274 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2275 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2278 out:
2279 TALLOC_FREE(smb_fname);
2280 END_PROFILE(SMBopenX);
2281 return;
2284 /****************************************************************************
2285 Reply to a SMBulogoffX.
2286 ****************************************************************************/
2288 void reply_ulogoffX(struct smb_request *req)
2290 struct smbd_server_connection *sconn = req->sconn;
2291 struct user_struct *vuser;
2292 struct smbXsrv_session *session = NULL;
2293 NTSTATUS status;
2295 START_PROFILE(SMBulogoffX);
2297 vuser = get_valid_user_struct(sconn, req->vuid);
2299 if(vuser == NULL) {
2300 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2301 (unsigned long long)req->vuid));
2303 req->vuid = UID_FIELD_INVALID;
2304 reply_force_doserror(req, ERRSRV, ERRbaduid);
2305 END_PROFILE(SMBulogoffX);
2306 return;
2309 session = vuser->session;
2310 vuser = NULL;
2313 * TODO: cancel all outstanding requests on the session
2315 status = smbXsrv_session_logoff(session);
2316 if (!NT_STATUS_IS_OK(status)) {
2317 DEBUG(0, ("reply_ulogoff: "
2318 "smbXsrv_session_logoff() failed: %s\n",
2319 nt_errstr(status)));
2321 * If we hit this case, there is something completely
2322 * wrong, so we better disconnect the transport connection.
2324 END_PROFILE(SMBulogoffX);
2325 exit_server(__location__ ": smbXsrv_session_logoff failed");
2326 return;
2329 TALLOC_FREE(session);
2331 reply_outbuf(req, 2, 0);
2332 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2333 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2335 DEBUG(3, ("ulogoffX vuid=%llu\n",
2336 (unsigned long long)req->vuid));
2338 END_PROFILE(SMBulogoffX);
2339 req->vuid = UID_FIELD_INVALID;
2342 /****************************************************************************
2343 Reply to a mknew or a create.
2344 ****************************************************************************/
2346 void reply_mknew(struct smb_request *req)
2348 connection_struct *conn = req->conn;
2349 struct smb_filename *smb_fname = NULL;
2350 char *fname = NULL;
2351 uint32 fattr = 0;
2352 struct smb_file_time ft;
2353 files_struct *fsp;
2354 int oplock_request = 0;
2355 NTSTATUS status;
2356 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2357 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2358 uint32 create_disposition;
2359 uint32 create_options = 0;
2360 TALLOC_CTX *ctx = talloc_tos();
2362 START_PROFILE(SMBcreate);
2363 ZERO_STRUCT(ft);
2365 if (req->wct < 3) {
2366 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2367 goto out;
2370 fattr = SVAL(req->vwv+0, 0);
2371 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2373 /* mtime. */
2374 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2376 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2377 STR_TERMINATE, &status);
2378 if (!NT_STATUS_IS_OK(status)) {
2379 reply_nterror(req, status);
2380 goto out;
2383 status = filename_convert(ctx,
2384 conn,
2385 req->flags2 & FLAGS2_DFS_PATHNAMES,
2386 fname,
2387 UCF_PREP_CREATEFILE,
2388 NULL,
2389 &smb_fname);
2390 if (!NT_STATUS_IS_OK(status)) {
2391 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2392 reply_botherror(req,
2393 NT_STATUS_PATH_NOT_COVERED,
2394 ERRSRV, ERRbadpath);
2395 goto out;
2397 reply_nterror(req, status);
2398 goto out;
2401 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2402 DEBUG(0,("Attempt to create file (%s) with volid set - "
2403 "please report this\n",
2404 smb_fname_str_dbg(smb_fname)));
2407 if(req->cmd == SMBmknew) {
2408 /* We should fail if file exists. */
2409 create_disposition = FILE_CREATE;
2410 } else {
2411 /* Create if file doesn't exist, truncate if it does. */
2412 create_disposition = FILE_OVERWRITE_IF;
2415 status = SMB_VFS_CREATE_FILE(
2416 conn, /* conn */
2417 req, /* req */
2418 0, /* root_dir_fid */
2419 smb_fname, /* fname */
2420 access_mask, /* access_mask */
2421 share_mode, /* share_access */
2422 create_disposition, /* create_disposition*/
2423 create_options, /* create_options */
2424 fattr, /* file_attributes */
2425 oplock_request, /* oplock_request */
2426 NULL, /* lease */
2427 0, /* allocation_size */
2428 0, /* private_flags */
2429 NULL, /* sd */
2430 NULL, /* ea_list */
2431 &fsp, /* result */
2432 NULL, /* pinfo */
2433 NULL, NULL); /* create context */
2435 if (!NT_STATUS_IS_OK(status)) {
2436 if (open_was_deferred(req->xconn, req->mid)) {
2437 /* We have re-scheduled this call. */
2438 goto out;
2440 reply_openerror(req, status);
2441 goto out;
2444 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2445 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2446 if (!NT_STATUS_IS_OK(status)) {
2447 END_PROFILE(SMBcreate);
2448 goto out;
2451 reply_outbuf(req, 1, 0);
2452 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2454 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2455 SCVAL(req->outbuf,smb_flg,
2456 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2459 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2460 SCVAL(req->outbuf,smb_flg,
2461 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2464 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2465 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2466 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2467 (unsigned int)fattr));
2469 out:
2470 TALLOC_FREE(smb_fname);
2471 END_PROFILE(SMBcreate);
2472 return;
2475 /****************************************************************************
2476 Reply to a create temporary file.
2477 ****************************************************************************/
2479 void reply_ctemp(struct smb_request *req)
2481 connection_struct *conn = req->conn;
2482 struct smb_filename *smb_fname = NULL;
2483 char *wire_name = NULL;
2484 char *fname = NULL;
2485 uint32 fattr;
2486 files_struct *fsp;
2487 int oplock_request;
2488 char *s;
2489 NTSTATUS status;
2490 int i;
2491 TALLOC_CTX *ctx = talloc_tos();
2493 START_PROFILE(SMBctemp);
2495 if (req->wct < 3) {
2496 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2497 goto out;
2500 fattr = SVAL(req->vwv+0, 0);
2501 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2503 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2504 STR_TERMINATE, &status);
2505 if (!NT_STATUS_IS_OK(status)) {
2506 reply_nterror(req, status);
2507 goto out;
2510 for (i = 0; i < 10; i++) {
2511 if (*wire_name) {
2512 fname = talloc_asprintf(ctx,
2513 "%s/TMP%s",
2514 wire_name,
2515 generate_random_str_list(ctx, 5, "0123456789"));
2516 } else {
2517 fname = talloc_asprintf(ctx,
2518 "TMP%s",
2519 generate_random_str_list(ctx, 5, "0123456789"));
2522 if (!fname) {
2523 reply_nterror(req, NT_STATUS_NO_MEMORY);
2524 goto out;
2527 status = filename_convert(ctx, conn,
2528 req->flags2 & FLAGS2_DFS_PATHNAMES,
2529 fname,
2530 UCF_PREP_CREATEFILE,
2531 NULL,
2532 &smb_fname);
2533 if (!NT_STATUS_IS_OK(status)) {
2534 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2535 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2536 ERRSRV, ERRbadpath);
2537 goto out;
2539 reply_nterror(req, status);
2540 goto out;
2543 /* Create the file. */
2544 status = SMB_VFS_CREATE_FILE(
2545 conn, /* conn */
2546 req, /* req */
2547 0, /* root_dir_fid */
2548 smb_fname, /* fname */
2549 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2550 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2551 FILE_CREATE, /* create_disposition*/
2552 0, /* create_options */
2553 fattr, /* file_attributes */
2554 oplock_request, /* oplock_request */
2555 NULL, /* lease */
2556 0, /* allocation_size */
2557 0, /* private_flags */
2558 NULL, /* sd */
2559 NULL, /* ea_list */
2560 &fsp, /* result */
2561 NULL, /* pinfo */
2562 NULL, NULL); /* create context */
2564 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2565 TALLOC_FREE(fname);
2566 TALLOC_FREE(smb_fname);
2567 continue;
2570 if (!NT_STATUS_IS_OK(status)) {
2571 if (open_was_deferred(req->xconn, req->mid)) {
2572 /* We have re-scheduled this call. */
2573 goto out;
2575 reply_openerror(req, status);
2576 goto out;
2579 break;
2582 if (i == 10) {
2583 /* Collision after 10 times... */
2584 reply_nterror(req, status);
2585 goto out;
2588 reply_outbuf(req, 1, 0);
2589 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2591 /* the returned filename is relative to the directory */
2592 s = strrchr_m(fsp->fsp_name->base_name, '/');
2593 if (!s) {
2594 s = fsp->fsp_name->base_name;
2595 } else {
2596 s++;
2599 #if 0
2600 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2601 thing in the byte section. JRA */
2602 SSVALS(p, 0, -1); /* what is this? not in spec */
2603 #endif
2604 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2605 == -1) {
2606 reply_nterror(req, NT_STATUS_NO_MEMORY);
2607 goto out;
2610 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2611 SCVAL(req->outbuf, smb_flg,
2612 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2615 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2616 SCVAL(req->outbuf, smb_flg,
2617 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2620 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2621 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2622 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2623 out:
2624 TALLOC_FREE(smb_fname);
2625 TALLOC_FREE(wire_name);
2626 END_PROFILE(SMBctemp);
2627 return;
2630 /*******************************************************************
2631 Check if a user is allowed to rename a file.
2632 ********************************************************************/
2634 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2635 uint16 dirtype)
2637 if (!CAN_WRITE(conn)) {
2638 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2641 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2642 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2643 /* Only bother to read the DOS attribute if we might deny the
2644 rename on the grounds of attribute missmatch. */
2645 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2646 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2647 return NT_STATUS_NO_SUCH_FILE;
2651 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2652 if (fsp->posix_open) {
2653 return NT_STATUS_OK;
2656 /* If no pathnames are open below this
2657 directory, allow the rename. */
2659 if (file_find_subpath(fsp)) {
2660 return NT_STATUS_ACCESS_DENIED;
2662 return NT_STATUS_OK;
2665 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2666 return NT_STATUS_OK;
2669 return NT_STATUS_ACCESS_DENIED;
2672 /*******************************************************************
2673 * unlink a file with all relevant access checks
2674 *******************************************************************/
2676 static NTSTATUS do_unlink(connection_struct *conn,
2677 struct smb_request *req,
2678 struct smb_filename *smb_fname,
2679 uint32 dirtype)
2681 uint32 fattr;
2682 files_struct *fsp;
2683 uint32 dirtype_orig = dirtype;
2684 NTSTATUS status;
2685 int ret;
2686 bool posix_paths = lp_posix_pathnames();
2688 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2689 smb_fname_str_dbg(smb_fname),
2690 dirtype));
2692 if (!CAN_WRITE(conn)) {
2693 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2696 if (posix_paths) {
2697 ret = SMB_VFS_LSTAT(conn, smb_fname);
2698 } else {
2699 ret = SMB_VFS_STAT(conn, smb_fname);
2701 if (ret != 0) {
2702 return map_nt_error_from_unix(errno);
2705 fattr = dos_mode(conn, smb_fname);
2707 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2708 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2711 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2712 if (!dirtype) {
2713 return NT_STATUS_NO_SUCH_FILE;
2716 if (!dir_check_ftype(fattr, dirtype)) {
2717 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2718 return NT_STATUS_FILE_IS_A_DIRECTORY;
2720 return NT_STATUS_NO_SUCH_FILE;
2723 if (dirtype_orig & 0x8000) {
2724 /* These will never be set for POSIX. */
2725 return NT_STATUS_NO_SUCH_FILE;
2728 #if 0
2729 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2730 return NT_STATUS_FILE_IS_A_DIRECTORY;
2733 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2734 return NT_STATUS_NO_SUCH_FILE;
2737 if (dirtype & 0xFF00) {
2738 /* These will never be set for POSIX. */
2739 return NT_STATUS_NO_SUCH_FILE;
2742 dirtype &= 0xFF;
2743 if (!dirtype) {
2744 return NT_STATUS_NO_SUCH_FILE;
2747 /* Can't delete a directory. */
2748 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2749 return NT_STATUS_FILE_IS_A_DIRECTORY;
2751 #endif
2753 #if 0 /* JRATEST */
2754 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2755 return NT_STATUS_OBJECT_NAME_INVALID;
2756 #endif /* JRATEST */
2758 /* On open checks the open itself will check the share mode, so
2759 don't do it here as we'll get it wrong. */
2761 status = SMB_VFS_CREATE_FILE
2762 (conn, /* conn */
2763 req, /* req */
2764 0, /* root_dir_fid */
2765 smb_fname, /* fname */
2766 DELETE_ACCESS, /* access_mask */
2767 FILE_SHARE_NONE, /* share_access */
2768 FILE_OPEN, /* create_disposition*/
2769 FILE_NON_DIRECTORY_FILE, /* create_options */
2770 /* file_attributes */
2771 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2772 FILE_ATTRIBUTE_NORMAL,
2773 0, /* oplock_request */
2774 NULL, /* lease */
2775 0, /* allocation_size */
2776 0, /* private_flags */
2777 NULL, /* sd */
2778 NULL, /* ea_list */
2779 &fsp, /* result */
2780 NULL, /* pinfo */
2781 NULL, NULL); /* create context */
2783 if (!NT_STATUS_IS_OK(status)) {
2784 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2785 nt_errstr(status)));
2786 return status;
2789 status = can_set_delete_on_close(fsp, fattr);
2790 if (!NT_STATUS_IS_OK(status)) {
2791 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2792 "(%s)\n",
2793 smb_fname_str_dbg(smb_fname),
2794 nt_errstr(status)));
2795 close_file(req, fsp, NORMAL_CLOSE);
2796 return status;
2799 /* The set is across all open files on this dev/inode pair. */
2800 if (!set_delete_on_close(fsp, True,
2801 conn->session_info->security_token,
2802 conn->session_info->unix_token)) {
2803 close_file(req, fsp, NORMAL_CLOSE);
2804 return NT_STATUS_ACCESS_DENIED;
2807 return close_file(req, fsp, NORMAL_CLOSE);
2810 /****************************************************************************
2811 The guts of the unlink command, split out so it may be called by the NT SMB
2812 code.
2813 ****************************************************************************/
2815 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2816 uint32 dirtype, struct smb_filename *smb_fname,
2817 bool has_wild)
2819 char *fname_dir = NULL;
2820 char *fname_mask = NULL;
2821 int count=0;
2822 NTSTATUS status = NT_STATUS_OK;
2823 TALLOC_CTX *ctx = talloc_tos();
2825 /* Split up the directory from the filename/mask. */
2826 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2827 &fname_dir, &fname_mask);
2828 if (!NT_STATUS_IS_OK(status)) {
2829 goto out;
2833 * We should only check the mangled cache
2834 * here if unix_convert failed. This means
2835 * that the path in 'mask' doesn't exist
2836 * on the file system and so we need to look
2837 * for a possible mangle. This patch from
2838 * Tine Smukavec <valentin.smukavec@hermes.si>.
2841 if (!VALID_STAT(smb_fname->st) &&
2842 mangle_is_mangled(fname_mask, conn->params)) {
2843 char *new_mask = NULL;
2844 mangle_lookup_name_from_8_3(ctx, fname_mask,
2845 &new_mask, conn->params);
2846 if (new_mask) {
2847 TALLOC_FREE(fname_mask);
2848 fname_mask = new_mask;
2852 if (!has_wild) {
2855 * Only one file needs to be unlinked. Append the mask back
2856 * onto the directory.
2858 TALLOC_FREE(smb_fname->base_name);
2859 if (ISDOT(fname_dir)) {
2860 /* Ensure we use canonical names on open. */
2861 smb_fname->base_name = talloc_asprintf(smb_fname,
2862 "%s",
2863 fname_mask);
2864 } else {
2865 smb_fname->base_name = talloc_asprintf(smb_fname,
2866 "%s/%s",
2867 fname_dir,
2868 fname_mask);
2870 if (!smb_fname->base_name) {
2871 status = NT_STATUS_NO_MEMORY;
2872 goto out;
2874 if (dirtype == 0) {
2875 dirtype = FILE_ATTRIBUTE_NORMAL;
2878 status = check_name(conn, smb_fname->base_name);
2879 if (!NT_STATUS_IS_OK(status)) {
2880 goto out;
2883 status = do_unlink(conn, req, smb_fname, dirtype);
2884 if (!NT_STATUS_IS_OK(status)) {
2885 goto out;
2888 count++;
2889 } else {
2890 struct smb_Dir *dir_hnd = NULL;
2891 long offset = 0;
2892 const char *dname = NULL;
2893 char *talloced = NULL;
2895 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2896 status = NT_STATUS_OBJECT_NAME_INVALID;
2897 goto out;
2900 if (strequal(fname_mask,"????????.???")) {
2901 TALLOC_FREE(fname_mask);
2902 fname_mask = talloc_strdup(ctx, "*");
2903 if (!fname_mask) {
2904 status = NT_STATUS_NO_MEMORY;
2905 goto out;
2909 status = check_name(conn, fname_dir);
2910 if (!NT_STATUS_IS_OK(status)) {
2911 goto out;
2914 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2915 dirtype);
2916 if (dir_hnd == NULL) {
2917 status = map_nt_error_from_unix(errno);
2918 goto out;
2921 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2922 the pattern matches against the long name, otherwise the short name
2923 We don't implement this yet XXXX
2926 status = NT_STATUS_NO_SUCH_FILE;
2928 while ((dname = ReadDirName(dir_hnd, &offset,
2929 &smb_fname->st, &talloced))) {
2930 TALLOC_CTX *frame = talloc_stackframe();
2932 if (!is_visible_file(conn, fname_dir, dname,
2933 &smb_fname->st, true)) {
2934 TALLOC_FREE(frame);
2935 TALLOC_FREE(talloced);
2936 continue;
2939 /* Quick check for "." and ".." */
2940 if (ISDOT(dname) || ISDOTDOT(dname)) {
2941 TALLOC_FREE(frame);
2942 TALLOC_FREE(talloced);
2943 continue;
2946 if(!mask_match(dname, fname_mask,
2947 conn->case_sensitive)) {
2948 TALLOC_FREE(frame);
2949 TALLOC_FREE(talloced);
2950 continue;
2953 TALLOC_FREE(smb_fname->base_name);
2954 if (ISDOT(fname_dir)) {
2955 /* Ensure we use canonical names on open. */
2956 smb_fname->base_name =
2957 talloc_asprintf(smb_fname, "%s",
2958 dname);
2959 } else {
2960 smb_fname->base_name =
2961 talloc_asprintf(smb_fname, "%s/%s",
2962 fname_dir, dname);
2965 if (!smb_fname->base_name) {
2966 TALLOC_FREE(dir_hnd);
2967 status = NT_STATUS_NO_MEMORY;
2968 TALLOC_FREE(frame);
2969 TALLOC_FREE(talloced);
2970 goto out;
2973 status = check_name(conn, smb_fname->base_name);
2974 if (!NT_STATUS_IS_OK(status)) {
2975 TALLOC_FREE(dir_hnd);
2976 TALLOC_FREE(frame);
2977 TALLOC_FREE(talloced);
2978 goto out;
2981 status = do_unlink(conn, req, smb_fname, dirtype);
2982 if (!NT_STATUS_IS_OK(status)) {
2983 TALLOC_FREE(dir_hnd);
2984 TALLOC_FREE(frame);
2985 TALLOC_FREE(talloced);
2986 goto out;
2989 count++;
2990 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2991 smb_fname->base_name));
2993 TALLOC_FREE(frame);
2994 TALLOC_FREE(talloced);
2996 TALLOC_FREE(dir_hnd);
2999 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3000 status = map_nt_error_from_unix(errno);
3003 out:
3004 TALLOC_FREE(fname_dir);
3005 TALLOC_FREE(fname_mask);
3006 return status;
3009 /****************************************************************************
3010 Reply to a unlink
3011 ****************************************************************************/
3013 void reply_unlink(struct smb_request *req)
3015 connection_struct *conn = req->conn;
3016 char *name = NULL;
3017 struct smb_filename *smb_fname = NULL;
3018 uint32 dirtype;
3019 NTSTATUS status;
3020 bool path_contains_wcard = False;
3021 TALLOC_CTX *ctx = talloc_tos();
3023 START_PROFILE(SMBunlink);
3025 if (req->wct < 1) {
3026 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3027 goto out;
3030 dirtype = SVAL(req->vwv+0, 0);
3032 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3033 STR_TERMINATE, &status,
3034 &path_contains_wcard);
3035 if (!NT_STATUS_IS_OK(status)) {
3036 reply_nterror(req, status);
3037 goto out;
3040 status = filename_convert(ctx, conn,
3041 req->flags2 & FLAGS2_DFS_PATHNAMES,
3042 name,
3043 UCF_COND_ALLOW_WCARD_LCOMP,
3044 &path_contains_wcard,
3045 &smb_fname);
3046 if (!NT_STATUS_IS_OK(status)) {
3047 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3048 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3049 ERRSRV, ERRbadpath);
3050 goto out;
3052 reply_nterror(req, status);
3053 goto out;
3056 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3058 status = unlink_internals(conn, req, dirtype, smb_fname,
3059 path_contains_wcard);
3060 if (!NT_STATUS_IS_OK(status)) {
3061 if (open_was_deferred(req->xconn, req->mid)) {
3062 /* We have re-scheduled this call. */
3063 goto out;
3065 reply_nterror(req, status);
3066 goto out;
3069 reply_outbuf(req, 0, 0);
3070 out:
3071 TALLOC_FREE(smb_fname);
3072 END_PROFILE(SMBunlink);
3073 return;
3076 /****************************************************************************
3077 Fail for readbraw.
3078 ****************************************************************************/
3080 static void fail_readraw(void)
3082 const char *errstr = talloc_asprintf(talloc_tos(),
3083 "FAIL ! reply_readbraw: socket write fail (%s)",
3084 strerror(errno));
3085 if (!errstr) {
3086 errstr = "";
3088 exit_server_cleanly(errstr);
3091 /****************************************************************************
3092 Fake (read/write) sendfile. Returns -1 on read or write fail.
3093 ****************************************************************************/
3095 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3096 off_t startpos, size_t nread)
3098 size_t bufsize;
3099 size_t tosend = nread;
3100 char *buf;
3102 if (nread == 0) {
3103 return 0;
3106 bufsize = MIN(nread, 65536);
3108 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3109 return -1;
3112 while (tosend > 0) {
3113 ssize_t ret;
3114 size_t cur_read;
3116 cur_read = MIN(tosend, bufsize);
3117 ret = read_file(fsp,buf,startpos,cur_read);
3118 if (ret == -1) {
3119 SAFE_FREE(buf);
3120 return -1;
3123 /* If we had a short read, fill with zeros. */
3124 if (ret < cur_read) {
3125 memset(buf + ret, '\0', cur_read - ret);
3128 ret = write_data(xconn->transport.sock, buf, cur_read);
3129 if (ret != cur_read) {
3130 int saved_errno = errno;
3132 * Try and give an error message saying what
3133 * client failed.
3135 DEBUG(0, ("write_data failed for client %s. "
3136 "Error %s\n",
3137 smbXsrv_connection_dbg(xconn),
3138 strerror(saved_errno)));
3139 SAFE_FREE(buf);
3140 errno = saved_errno;
3141 return -1;
3143 tosend -= cur_read;
3144 startpos += cur_read;
3147 SAFE_FREE(buf);
3148 return (ssize_t)nread;
3151 /****************************************************************************
3152 Deal with the case of sendfile reading less bytes from the file than
3153 requested. Fill with zeros (all we can do). Returns 0 on success
3154 ****************************************************************************/
3156 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3157 files_struct *fsp,
3158 ssize_t nread,
3159 size_t headersize,
3160 size_t smb_maxcnt)
3162 #define SHORT_SEND_BUFSIZE 1024
3163 if (nread < headersize) {
3164 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3165 "header for file %s (%s). Terminating\n",
3166 fsp_str_dbg(fsp), strerror(errno)));
3167 return -1;
3170 nread -= headersize;
3172 if (nread < smb_maxcnt) {
3173 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3174 if (!buf) {
3175 DEBUG(0,("sendfile_short_send: malloc failed "
3176 "for file %s (%s). Terminating\n",
3177 fsp_str_dbg(fsp), strerror(errno)));
3178 return -1;
3181 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3182 "with zeros !\n", fsp_str_dbg(fsp)));
3184 while (nread < smb_maxcnt) {
3186 * We asked for the real file size and told sendfile
3187 * to not go beyond the end of the file. But it can
3188 * happen that in between our fstat call and the
3189 * sendfile call the file was truncated. This is very
3190 * bad because we have already announced the larger
3191 * number of bytes to the client.
3193 * The best we can do now is to send 0-bytes, just as
3194 * a read from a hole in a sparse file would do.
3196 * This should happen rarely enough that I don't care
3197 * about efficiency here :-)
3199 size_t to_write;
3200 ssize_t ret;
3202 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3203 ret = write_data(xconn->transport.sock, buf, to_write);
3204 if (ret != to_write) {
3205 int saved_errno = errno;
3207 * Try and give an error message saying what
3208 * client failed.
3210 DEBUG(0, ("write_data failed for client %s. "
3211 "Error %s\n",
3212 smbXsrv_connection_dbg(xconn),
3213 strerror(saved_errno)));
3214 errno = saved_errno;
3215 return -1;
3217 nread += to_write;
3219 SAFE_FREE(buf);
3222 return 0;
3225 /****************************************************************************
3226 Return a readbraw error (4 bytes of zero).
3227 ****************************************************************************/
3229 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3231 char header[4];
3233 SIVAL(header,0,0);
3235 smbd_lock_socket(xconn);
3236 if (write_data(xconn->transport.sock,header,4) != 4) {
3237 int saved_errno = errno;
3239 * Try and give an error message saying what
3240 * client failed.
3242 DEBUG(0, ("write_data failed for client %s. "
3243 "Error %s\n",
3244 smbXsrv_connection_dbg(xconn),
3245 strerror(saved_errno)));
3246 errno = saved_errno;
3248 fail_readraw();
3250 smbd_unlock_socket(xconn);
3253 /****************************************************************************
3254 Use sendfile in readbraw.
3255 ****************************************************************************/
3257 static void send_file_readbraw(connection_struct *conn,
3258 struct smb_request *req,
3259 files_struct *fsp,
3260 off_t startpos,
3261 size_t nread,
3262 ssize_t mincount)
3264 struct smbXsrv_connection *xconn = req->xconn;
3265 char *outbuf = NULL;
3266 ssize_t ret=0;
3269 * We can only use sendfile on a non-chained packet
3270 * but we can use on a non-oplocked file. tridge proved this
3271 * on a train in Germany :-). JRA.
3272 * reply_readbraw has already checked the length.
3275 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3276 (fsp->wcp == NULL) &&
3277 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3278 ssize_t sendfile_read = -1;
3279 char header[4];
3280 DATA_BLOB header_blob;
3282 _smb_setlen(header,nread);
3283 header_blob = data_blob_const(header, 4);
3285 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3286 &header_blob, startpos,
3287 nread);
3288 if (sendfile_read == -1) {
3289 /* Returning ENOSYS means no data at all was sent.
3290 * Do this as a normal read. */
3291 if (errno == ENOSYS) {
3292 goto normal_readbraw;
3296 * Special hack for broken Linux with no working sendfile. If we
3297 * return EINTR we sent the header but not the rest of the data.
3298 * Fake this up by doing read/write calls.
3300 if (errno == EINTR) {
3301 /* Ensure we don't do this again. */
3302 set_use_sendfile(SNUM(conn), False);
3303 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3305 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3306 DEBUG(0,("send_file_readbraw: "
3307 "fake_sendfile failed for "
3308 "file %s (%s).\n",
3309 fsp_str_dbg(fsp),
3310 strerror(errno)));
3311 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3313 return;
3316 DEBUG(0,("send_file_readbraw: sendfile failed for "
3317 "file %s (%s). Terminating\n",
3318 fsp_str_dbg(fsp), strerror(errno)));
3319 exit_server_cleanly("send_file_readbraw sendfile failed");
3320 } else if (sendfile_read == 0) {
3322 * Some sendfile implementations return 0 to indicate
3323 * that there was a short read, but nothing was
3324 * actually written to the socket. In this case,
3325 * fallback to the normal read path so the header gets
3326 * the correct byte count.
3328 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3329 "bytes falling back to the normal read: "
3330 "%s\n", fsp_str_dbg(fsp)));
3331 goto normal_readbraw;
3334 /* Deal with possible short send. */
3335 if (sendfile_read != 4+nread) {
3336 ret = sendfile_short_send(xconn, fsp,
3337 sendfile_read, 4, nread);
3338 if (ret == -1) {
3339 fail_readraw();
3342 return;
3345 normal_readbraw:
3347 outbuf = talloc_array(NULL, char, nread+4);
3348 if (!outbuf) {
3349 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3350 (unsigned)(nread+4)));
3351 reply_readbraw_error(xconn);
3352 return;
3355 if (nread > 0) {
3356 ret = read_file(fsp,outbuf+4,startpos,nread);
3357 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3358 if (ret < mincount)
3359 ret = 0;
3360 #else
3361 if (ret < nread)
3362 ret = 0;
3363 #endif
3366 _smb_setlen(outbuf,ret);
3367 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3368 int saved_errno = errno;
3370 * Try and give an error message saying what
3371 * client failed.
3373 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3374 smbXsrv_connection_dbg(xconn),
3375 strerror(saved_errno)));
3376 errno = saved_errno;
3378 fail_readraw();
3381 TALLOC_FREE(outbuf);
3384 /****************************************************************************
3385 Reply to a readbraw (core+ protocol).
3386 ****************************************************************************/
3388 void reply_readbraw(struct smb_request *req)
3390 connection_struct *conn = req->conn;
3391 struct smbXsrv_connection *xconn = req->xconn;
3392 ssize_t maxcount,mincount;
3393 size_t nread = 0;
3394 off_t startpos;
3395 files_struct *fsp;
3396 struct lock_struct lock;
3397 off_t size = 0;
3399 START_PROFILE(SMBreadbraw);
3401 if (srv_is_signing_active(xconn) || req->encrypted) {
3402 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3403 "raw reads/writes are disallowed.");
3406 if (req->wct < 8) {
3407 reply_readbraw_error(xconn);
3408 END_PROFILE(SMBreadbraw);
3409 return;
3412 if (xconn->smb1.echo_handler.trusted_fde) {
3413 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3414 "'async smb echo handler = yes'\n"));
3415 reply_readbraw_error(xconn);
3416 END_PROFILE(SMBreadbraw);
3417 return;
3421 * Special check if an oplock break has been issued
3422 * and the readraw request croses on the wire, we must
3423 * return a zero length response here.
3426 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3429 * We have to do a check_fsp by hand here, as
3430 * we must always return 4 zero bytes on error,
3431 * not a NTSTATUS.
3434 if (!fsp || !conn || conn != fsp->conn ||
3435 req->vuid != fsp->vuid ||
3436 fsp->is_directory || fsp->fh->fd == -1) {
3438 * fsp could be NULL here so use the value from the packet. JRA.
3440 DEBUG(3,("reply_readbraw: fnum %d not valid "
3441 "- cache prime?\n",
3442 (int)SVAL(req->vwv+0, 0)));
3443 reply_readbraw_error(xconn);
3444 END_PROFILE(SMBreadbraw);
3445 return;
3448 /* Do a "by hand" version of CHECK_READ. */
3449 if (!(fsp->can_read ||
3450 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3451 (fsp->access_mask & FILE_EXECUTE)))) {
3452 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3453 (int)SVAL(req->vwv+0, 0)));
3454 reply_readbraw_error(xconn);
3455 END_PROFILE(SMBreadbraw);
3456 return;
3459 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3461 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3462 if(req->wct == 10) {
3464 * This is a large offset (64 bit) read.
3467 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3469 if(startpos < 0) {
3470 DEBUG(0,("reply_readbraw: negative 64 bit "
3471 "readraw offset (%.0f) !\n",
3472 (double)startpos ));
3473 reply_readbraw_error(xconn);
3474 END_PROFILE(SMBreadbraw);
3475 return;
3479 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3480 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3482 /* ensure we don't overrun the packet size */
3483 maxcount = MIN(65535,maxcount);
3485 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3486 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3487 &lock);
3489 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3490 reply_readbraw_error(xconn);
3491 END_PROFILE(SMBreadbraw);
3492 return;
3495 if (fsp_stat(fsp) == 0) {
3496 size = fsp->fsp_name->st.st_ex_size;
3499 if (startpos >= size) {
3500 nread = 0;
3501 } else {
3502 nread = MIN(maxcount,(size - startpos));
3505 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3506 if (nread < mincount)
3507 nread = 0;
3508 #endif
3510 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3511 "min=%lu nread=%lu\n",
3512 fsp_fnum_dbg(fsp), (double)startpos,
3513 (unsigned long)maxcount,
3514 (unsigned long)mincount,
3515 (unsigned long)nread ) );
3517 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3519 DEBUG(5,("reply_readbraw finished\n"));
3521 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3523 END_PROFILE(SMBreadbraw);
3524 return;
3527 #undef DBGC_CLASS
3528 #define DBGC_CLASS DBGC_LOCKING
3530 /****************************************************************************
3531 Reply to a lockread (core+ protocol).
3532 ****************************************************************************/
3534 void reply_lockread(struct smb_request *req)
3536 connection_struct *conn = req->conn;
3537 ssize_t nread = -1;
3538 char *data;
3539 off_t startpos;
3540 size_t numtoread;
3541 size_t maxtoread;
3542 NTSTATUS status;
3543 files_struct *fsp;
3544 struct byte_range_lock *br_lck = NULL;
3545 char *p = NULL;
3546 struct smbXsrv_connection *xconn = req->xconn;
3548 START_PROFILE(SMBlockread);
3550 if (req->wct < 5) {
3551 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3552 END_PROFILE(SMBlockread);
3553 return;
3556 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3558 if (!check_fsp(conn, req, fsp)) {
3559 END_PROFILE(SMBlockread);
3560 return;
3563 if (!CHECK_READ(fsp,req)) {
3564 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3565 END_PROFILE(SMBlockread);
3566 return;
3569 numtoread = SVAL(req->vwv+1, 0);
3570 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3573 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3574 * protocol request that predates the read/write lock concept.
3575 * Thus instead of asking for a read lock here we need to ask
3576 * for a write lock. JRA.
3577 * Note that the requested lock size is unaffected by max_send.
3580 br_lck = do_lock(req->sconn->msg_ctx,
3581 fsp,
3582 (uint64_t)req->smbpid,
3583 (uint64_t)numtoread,
3584 (uint64_t)startpos,
3585 WRITE_LOCK,
3586 WINDOWS_LOCK,
3587 False, /* Non-blocking lock. */
3588 &status,
3589 NULL);
3590 TALLOC_FREE(br_lck);
3592 if (NT_STATUS_V(status)) {
3593 reply_nterror(req, status);
3594 END_PROFILE(SMBlockread);
3595 return;
3599 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3601 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3603 if (numtoread > maxtoread) {
3604 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3605 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3606 (unsigned int)numtoread, (unsigned int)maxtoread,
3607 (unsigned int)xconn->smb1.sessions.max_send));
3608 numtoread = maxtoread;
3611 reply_outbuf(req, 5, numtoread + 3);
3613 data = smb_buf(req->outbuf) + 3;
3615 nread = read_file(fsp,data,startpos,numtoread);
3617 if (nread < 0) {
3618 reply_nterror(req, map_nt_error_from_unix(errno));
3619 END_PROFILE(SMBlockread);
3620 return;
3623 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3625 SSVAL(req->outbuf,smb_vwv0,nread);
3626 SSVAL(req->outbuf,smb_vwv5,nread+3);
3627 p = smb_buf(req->outbuf);
3628 SCVAL(p,0,0); /* pad byte. */
3629 SSVAL(p,1,nread);
3631 DEBUG(3,("lockread %s num=%d nread=%d\n",
3632 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3634 END_PROFILE(SMBlockread);
3635 return;
3638 #undef DBGC_CLASS
3639 #define DBGC_CLASS DBGC_ALL
3641 /****************************************************************************
3642 Reply to a read.
3643 ****************************************************************************/
3645 void reply_read(struct smb_request *req)
3647 connection_struct *conn = req->conn;
3648 size_t numtoread;
3649 size_t maxtoread;
3650 ssize_t nread = 0;
3651 char *data;
3652 off_t startpos;
3653 files_struct *fsp;
3654 struct lock_struct lock;
3655 struct smbXsrv_connection *xconn = req->xconn;
3657 START_PROFILE(SMBread);
3659 if (req->wct < 3) {
3660 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3661 END_PROFILE(SMBread);
3662 return;
3665 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3667 if (!check_fsp(conn, req, fsp)) {
3668 END_PROFILE(SMBread);
3669 return;
3672 if (!CHECK_READ(fsp,req)) {
3673 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3674 END_PROFILE(SMBread);
3675 return;
3678 numtoread = SVAL(req->vwv+1, 0);
3679 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3682 * The requested read size cannot be greater than max_send. JRA.
3684 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3686 if (numtoread > maxtoread) {
3687 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3688 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3689 (unsigned int)numtoread, (unsigned int)maxtoread,
3690 (unsigned int)xconn->smb1.sessions.max_send));
3691 numtoread = maxtoread;
3694 reply_outbuf(req, 5, numtoread+3);
3696 data = smb_buf(req->outbuf) + 3;
3698 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3699 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3700 &lock);
3702 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3703 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3704 END_PROFILE(SMBread);
3705 return;
3708 if (numtoread > 0)
3709 nread = read_file(fsp,data,startpos,numtoread);
3711 if (nread < 0) {
3712 reply_nterror(req, map_nt_error_from_unix(errno));
3713 goto strict_unlock;
3716 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3718 SSVAL(req->outbuf,smb_vwv0,nread);
3719 SSVAL(req->outbuf,smb_vwv5,nread+3);
3720 SCVAL(smb_buf(req->outbuf),0,1);
3721 SSVAL(smb_buf(req->outbuf),1,nread);
3723 DEBUG(3, ("read %s num=%d nread=%d\n",
3724 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3726 strict_unlock:
3727 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3729 END_PROFILE(SMBread);
3730 return;
3733 /****************************************************************************
3734 Setup readX header.
3735 ****************************************************************************/
3737 static int setup_readX_header(struct smb_request *req, char *outbuf,
3738 size_t smb_maxcnt)
3740 int outsize;
3742 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3743 False);
3745 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3747 SCVAL(outbuf,smb_vwv0,0xFF);
3748 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3749 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3750 SSVAL(outbuf,smb_vwv6,
3751 (smb_wct - 4) /* offset from smb header to wct */
3752 + 1 /* the wct field */
3753 + 12 * sizeof(uint16_t) /* vwv */
3754 + 2 /* the buflen field */
3755 + 1); /* padding byte */
3756 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3757 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3758 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3759 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3760 _smb_setlen_large(outbuf,
3761 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3762 return outsize;
3765 /****************************************************************************
3766 Reply to a read and X - possibly using sendfile.
3767 ****************************************************************************/
3769 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3770 files_struct *fsp, off_t startpos,
3771 size_t smb_maxcnt)
3773 struct smbXsrv_connection *xconn = req->xconn;
3774 ssize_t nread = -1;
3775 struct lock_struct lock;
3776 int saved_errno = 0;
3778 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3779 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3780 &lock);
3782 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3783 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3784 return;
3788 * We can only use sendfile on a non-chained packet
3789 * but we can use on a non-oplocked file. tridge proved this
3790 * on a train in Germany :-). JRA.
3793 if (!req_is_in_chain(req) &&
3794 !req->encrypted &&
3795 (fsp->base_fsp == NULL) &&
3796 (fsp->wcp == NULL) &&
3797 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3798 uint8 headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3799 DATA_BLOB header;
3801 if(fsp_stat(fsp) == -1) {
3802 reply_nterror(req, map_nt_error_from_unix(errno));
3803 goto strict_unlock;
3806 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3807 (startpos > fsp->fsp_name->st.st_ex_size) ||
3808 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3810 * We already know that we would do a short read, so don't
3811 * try the sendfile() path.
3813 goto nosendfile_read;
3817 * Set up the packet header before send. We
3818 * assume here the sendfile will work (get the
3819 * correct amount of data).
3822 header = data_blob_const(headerbuf, sizeof(headerbuf));
3824 construct_reply_common_req(req, (char *)headerbuf);
3825 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3827 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
3828 startpos, smb_maxcnt);
3829 if (nread == -1) {
3830 saved_errno = errno;
3832 /* Returning ENOSYS means no data at all was sent.
3833 Do this as a normal read. */
3834 if (errno == ENOSYS) {
3835 goto normal_read;
3839 * Special hack for broken Linux with no working sendfile. If we
3840 * return EINTR we sent the header but not the rest of the data.
3841 * Fake this up by doing read/write calls.
3844 if (errno == EINTR) {
3845 /* Ensure we don't do this again. */
3846 set_use_sendfile(SNUM(conn), False);
3847 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3848 nread = fake_sendfile(xconn, fsp, startpos,
3849 smb_maxcnt);
3850 if (nread == -1) {
3851 saved_errno = errno;
3852 DEBUG(0,("send_file_readX: "
3853 "fake_sendfile failed for "
3854 "file %s (%s) for client %s. "
3855 "Terminating\n",
3856 fsp_str_dbg(fsp),
3857 smbXsrv_connection_dbg(xconn),
3858 strerror(saved_errno)));
3859 errno = saved_errno;
3860 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3862 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3863 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3864 /* No outbuf here means successful sendfile. */
3865 goto strict_unlock;
3868 DEBUG(0,("send_file_readX: sendfile failed for file "
3869 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3870 strerror(errno)));
3871 exit_server_cleanly("send_file_readX sendfile failed");
3872 } else if (nread == 0) {
3874 * Some sendfile implementations return 0 to indicate
3875 * that there was a short read, but nothing was
3876 * actually written to the socket. In this case,
3877 * fallback to the normal read path so the header gets
3878 * the correct byte count.
3880 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3881 "falling back to the normal read: %s\n",
3882 fsp_str_dbg(fsp)));
3883 goto normal_read;
3886 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3887 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3889 /* Deal with possible short send. */
3890 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3891 ssize_t ret;
3893 ret = sendfile_short_send(xconn, fsp, nread,
3894 sizeof(headerbuf), smb_maxcnt);
3895 if (ret == -1) {
3896 const char *r;
3897 r = "send_file_readX: sendfile_short_send failed";
3898 DEBUG(0,("%s for file %s (%s).\n",
3899 r, fsp_str_dbg(fsp), strerror(errno)));
3900 exit_server_cleanly(r);
3903 /* No outbuf here means successful sendfile. */
3904 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3905 SMB_PERFCOUNT_END(&req->pcd);
3906 goto strict_unlock;
3909 normal_read:
3911 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3912 uint8 headerbuf[smb_size + 2*12 + 1 /* padding byte */];
3913 ssize_t ret;
3915 construct_reply_common_req(req, (char *)headerbuf);
3916 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3918 /* Send out the header. */
3919 ret = write_data(xconn->transport.sock, (char *)headerbuf,
3920 sizeof(headerbuf));
3921 if (ret != sizeof(headerbuf)) {
3922 saved_errno = errno;
3924 * Try and give an error message saying what
3925 * client failed.
3927 DEBUG(0,("send_file_readX: write_data failed for file "
3928 "%s (%s) for client %s. Terminating\n",
3929 fsp_str_dbg(fsp),
3930 smbXsrv_connection_dbg(xconn),
3931 strerror(saved_errno)));
3932 errno = saved_errno;
3933 exit_server_cleanly("send_file_readX sendfile failed");
3935 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
3936 if (nread == -1) {
3937 saved_errno = errno;
3938 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
3939 "%s (%s) for client %s. Terminating\n",
3940 fsp_str_dbg(fsp),
3941 smbXsrv_connection_dbg(xconn),
3942 strerror(saved_errno)));
3943 errno = saved_errno;
3944 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3946 goto strict_unlock;
3949 nosendfile_read:
3951 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
3952 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3953 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3955 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
3956 startpos, smb_maxcnt);
3957 saved_errno = errno;
3959 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3961 if (nread < 0) {
3962 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3963 return;
3966 setup_readX_header(req, (char *)req->outbuf, nread);
3968 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3969 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3970 return;
3972 strict_unlock:
3973 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3974 TALLOC_FREE(req->outbuf);
3975 return;
3978 /****************************************************************************
3979 Work out how much space we have for a read return.
3980 ****************************************************************************/
3982 static size_t calc_max_read_pdu(const struct smb_request *req)
3984 struct smbXsrv_connection *xconn = req->xconn;
3986 if (xconn->protocol < PROTOCOL_NT1) {
3987 return xconn->smb1.sessions.max_send;
3990 if (!lp_large_readwrite()) {
3991 return xconn->smb1.sessions.max_send;
3994 if (req_is_in_chain(req)) {
3995 return xconn->smb1.sessions.max_send;
3998 if (req->encrypted) {
4000 * Don't take encrypted traffic up to the
4001 * limit. There are padding considerations
4002 * that make that tricky.
4004 return xconn->smb1.sessions.max_send;
4007 if (srv_is_signing_active(xconn)) {
4008 return 0x1FFFF;
4011 if (!lp_unix_extensions()) {
4012 return 0x1FFFF;
4016 * We can do ultra-large POSIX reads.
4018 return 0xFFFFFF;
4021 /****************************************************************************
4022 Calculate how big a read can be. Copes with all clients. It's always
4023 safe to return a short read - Windows does this.
4024 ****************************************************************************/
4026 static size_t calc_read_size(const struct smb_request *req,
4027 size_t upper_size,
4028 size_t lower_size)
4030 struct smbXsrv_connection *xconn = req->xconn;
4031 size_t max_pdu = calc_max_read_pdu(req);
4032 size_t total_size = 0;
4033 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4034 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4037 * Windows explicitly ignores upper size of 0xFFFF.
4038 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4039 * We must do the same as these will never fit even in
4040 * an extended size NetBIOS packet.
4042 if (upper_size == 0xFFFF) {
4043 upper_size = 0;
4046 if (xconn->protocol < PROTOCOL_NT1) {
4047 upper_size = 0;
4050 total_size = ((upper_size<<16) | lower_size);
4053 * LARGE_READX test shows it's always safe to return
4054 * a short read. Windows does so.
4056 return MIN(total_size, max_len);
4059 /****************************************************************************
4060 Reply to a read and X.
4061 ****************************************************************************/
4063 void reply_read_and_X(struct smb_request *req)
4065 connection_struct *conn = req->conn;
4066 files_struct *fsp;
4067 off_t startpos;
4068 size_t smb_maxcnt;
4069 size_t upper_size;
4070 bool big_readX = False;
4071 #if 0
4072 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4073 #endif
4075 START_PROFILE(SMBreadX);
4077 if ((req->wct != 10) && (req->wct != 12)) {
4078 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4079 return;
4082 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4083 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4084 smb_maxcnt = SVAL(req->vwv+5, 0);
4086 /* If it's an IPC, pass off the pipe handler. */
4087 if (IS_IPC(conn)) {
4088 reply_pipe_read_and_X(req);
4089 END_PROFILE(SMBreadX);
4090 return;
4093 if (!check_fsp(conn, req, fsp)) {
4094 END_PROFILE(SMBreadX);
4095 return;
4098 if (!CHECK_READ(fsp,req)) {
4099 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4100 END_PROFILE(SMBreadX);
4101 return;
4104 upper_size = SVAL(req->vwv+7, 0);
4105 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4106 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4108 * This is a heuristic to avoid keeping large
4109 * outgoing buffers around over long-lived aio
4110 * requests.
4112 big_readX = True;
4115 if (req->wct == 12) {
4117 * This is a large offset (64 bit) read.
4119 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4123 if (!big_readX) {
4124 NTSTATUS status = schedule_aio_read_and_X(conn,
4125 req,
4126 fsp,
4127 startpos,
4128 smb_maxcnt);
4129 if (NT_STATUS_IS_OK(status)) {
4130 /* Read scheduled - we're done. */
4131 goto out;
4133 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4134 /* Real error - report to client. */
4135 END_PROFILE(SMBreadX);
4136 reply_nterror(req, status);
4137 return;
4139 /* NT_STATUS_RETRY - fall back to sync read. */
4142 smbd_lock_socket(req->xconn);
4143 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4144 smbd_unlock_socket(req->xconn);
4146 out:
4147 END_PROFILE(SMBreadX);
4148 return;
4151 /****************************************************************************
4152 Error replies to writebraw must have smb_wct == 1. Fix this up.
4153 ****************************************************************************/
4155 void error_to_writebrawerr(struct smb_request *req)
4157 uint8 *old_outbuf = req->outbuf;
4159 reply_outbuf(req, 1, 0);
4161 memcpy(req->outbuf, old_outbuf, smb_size);
4162 TALLOC_FREE(old_outbuf);
4165 /****************************************************************************
4166 Read 4 bytes of a smb packet and return the smb length of the packet.
4167 Store the result in the buffer. This version of the function will
4168 never return a session keepalive (length of zero).
4169 Timeout is in milliseconds.
4170 ****************************************************************************/
4172 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4173 size_t *len)
4175 uint8_t msgtype = NBSSkeepalive;
4177 while (msgtype == NBSSkeepalive) {
4178 NTSTATUS status;
4180 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4181 len);
4182 if (!NT_STATUS_IS_OK(status)) {
4183 char addr[INET6_ADDRSTRLEN];
4184 /* Try and give an error message
4185 * saying what client failed. */
4186 DEBUG(0, ("read_fd_with_timeout failed for "
4187 "client %s read error = %s.\n",
4188 get_peer_addr(fd,addr,sizeof(addr)),
4189 nt_errstr(status)));
4190 return status;
4193 msgtype = CVAL(inbuf, 0);
4196 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4197 (unsigned long)len));
4199 return NT_STATUS_OK;
4202 /****************************************************************************
4203 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4204 ****************************************************************************/
4206 void reply_writebraw(struct smb_request *req)
4208 connection_struct *conn = req->conn;
4209 struct smbXsrv_connection *xconn = req->xconn;
4210 char *buf = NULL;
4211 ssize_t nwritten=0;
4212 ssize_t total_written=0;
4213 size_t numtowrite=0;
4214 size_t tcount;
4215 off_t startpos;
4216 const char *data=NULL;
4217 bool write_through;
4218 files_struct *fsp;
4219 struct lock_struct lock;
4220 NTSTATUS status;
4222 START_PROFILE(SMBwritebraw);
4225 * If we ever reply with an error, it must have the SMB command
4226 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4227 * we're finished.
4229 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4231 if (srv_is_signing_active(xconn)) {
4232 END_PROFILE(SMBwritebraw);
4233 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4234 "raw reads/writes are disallowed.");
4237 if (req->wct < 12) {
4238 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4239 error_to_writebrawerr(req);
4240 END_PROFILE(SMBwritebraw);
4241 return;
4244 if (xconn->smb1.echo_handler.trusted_fde) {
4245 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4246 "'async smb echo handler = yes'\n"));
4247 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4248 error_to_writebrawerr(req);
4249 END_PROFILE(SMBwritebraw);
4250 return;
4253 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4254 if (!check_fsp(conn, req, fsp)) {
4255 error_to_writebrawerr(req);
4256 END_PROFILE(SMBwritebraw);
4257 return;
4260 if (!CHECK_WRITE(fsp)) {
4261 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4262 error_to_writebrawerr(req);
4263 END_PROFILE(SMBwritebraw);
4264 return;
4267 tcount = IVAL(req->vwv+1, 0);
4268 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4269 write_through = BITSETW(req->vwv+7,0);
4271 /* We have to deal with slightly different formats depending
4272 on whether we are using the core+ or lanman1.0 protocol */
4274 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4275 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4276 data = smb_buf_const(req->inbuf);
4277 } else {
4278 numtowrite = SVAL(req->vwv+10, 0);
4279 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4282 /* Ensure we don't write bytes past the end of this packet. */
4283 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4284 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4285 error_to_writebrawerr(req);
4286 END_PROFILE(SMBwritebraw);
4287 return;
4290 if (!fsp->print_file) {
4291 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4292 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4293 &lock);
4295 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4296 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4297 error_to_writebrawerr(req);
4298 END_PROFILE(SMBwritebraw);
4299 return;
4303 if (numtowrite>0) {
4304 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4307 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4308 "wrote=%d sync=%d\n",
4309 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4310 (int)nwritten, (int)write_through));
4312 if (nwritten < (ssize_t)numtowrite) {
4313 reply_nterror(req, NT_STATUS_DISK_FULL);
4314 error_to_writebrawerr(req);
4315 goto strict_unlock;
4318 total_written = nwritten;
4320 /* Allocate a buffer of 64k + length. */
4321 buf = talloc_array(NULL, char, 65540);
4322 if (!buf) {
4323 reply_nterror(req, NT_STATUS_NO_MEMORY);
4324 error_to_writebrawerr(req);
4325 goto strict_unlock;
4328 /* Return a SMBwritebraw message to the redirector to tell
4329 * it to send more bytes */
4331 memcpy(buf, req->inbuf, smb_size);
4332 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4333 SCVAL(buf,smb_com,SMBwritebraw);
4334 SSVALS(buf,smb_vwv0,0xFFFF);
4335 show_msg(buf);
4336 if (!srv_send_smb(req->xconn,
4337 buf,
4338 false, 0, /* no signing */
4339 IS_CONN_ENCRYPTED(conn),
4340 &req->pcd)) {
4341 exit_server_cleanly("reply_writebraw: srv_send_smb "
4342 "failed.");
4345 /* Now read the raw data into the buffer and write it */
4346 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4347 &numtowrite);
4348 if (!NT_STATUS_IS_OK(status)) {
4349 exit_server_cleanly("secondary writebraw failed");
4352 /* Set up outbuf to return the correct size */
4353 reply_outbuf(req, 1, 0);
4355 if (numtowrite != 0) {
4357 if (numtowrite > 0xFFFF) {
4358 DEBUG(0,("reply_writebraw: Oversize secondary write "
4359 "raw requested (%u). Terminating\n",
4360 (unsigned int)numtowrite ));
4361 exit_server_cleanly("secondary writebraw failed");
4364 if (tcount > nwritten+numtowrite) {
4365 DEBUG(3,("reply_writebraw: Client overestimated the "
4366 "write %d %d %d\n",
4367 (int)tcount,(int)nwritten,(int)numtowrite));
4370 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4371 numtowrite);
4373 if (!NT_STATUS_IS_OK(status)) {
4374 /* Try and give an error message
4375 * saying what client failed. */
4376 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4377 "raw read failed (%s) for client %s. "
4378 "Terminating\n", nt_errstr(status),
4379 smbXsrv_connection_dbg(xconn)));
4380 exit_server_cleanly("secondary writebraw failed");
4383 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4384 if (nwritten == -1) {
4385 TALLOC_FREE(buf);
4386 reply_nterror(req, map_nt_error_from_unix(errno));
4387 error_to_writebrawerr(req);
4388 goto strict_unlock;
4391 if (nwritten < (ssize_t)numtowrite) {
4392 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4393 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4396 if (nwritten > 0) {
4397 total_written += nwritten;
4401 TALLOC_FREE(buf);
4402 SSVAL(req->outbuf,smb_vwv0,total_written);
4404 status = sync_file(conn, fsp, write_through);
4405 if (!NT_STATUS_IS_OK(status)) {
4406 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4407 fsp_str_dbg(fsp), nt_errstr(status)));
4408 reply_nterror(req, status);
4409 error_to_writebrawerr(req);
4410 goto strict_unlock;
4413 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4414 "wrote=%d\n",
4415 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4416 (int)total_written));
4418 if (!fsp->print_file) {
4419 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4422 /* We won't return a status if write through is not selected - this
4423 * follows what WfWg does */
4424 END_PROFILE(SMBwritebraw);
4426 if (!write_through && total_written==tcount) {
4428 #if RABBIT_PELLET_FIX
4430 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4431 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4432 * JRA.
4434 if (!send_keepalive(xconn->transport.sock)) {
4435 exit_server_cleanly("reply_writebraw: send of "
4436 "keepalive failed");
4438 #endif
4439 TALLOC_FREE(req->outbuf);
4441 return;
4443 strict_unlock:
4444 if (!fsp->print_file) {
4445 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4448 END_PROFILE(SMBwritebraw);
4449 return;
4452 #undef DBGC_CLASS
4453 #define DBGC_CLASS DBGC_LOCKING
4455 /****************************************************************************
4456 Reply to a writeunlock (core+).
4457 ****************************************************************************/
4459 void reply_writeunlock(struct smb_request *req)
4461 connection_struct *conn = req->conn;
4462 ssize_t nwritten = -1;
4463 size_t numtowrite;
4464 off_t startpos;
4465 const char *data;
4466 NTSTATUS status = NT_STATUS_OK;
4467 files_struct *fsp;
4468 struct lock_struct lock;
4469 int saved_errno = 0;
4471 START_PROFILE(SMBwriteunlock);
4473 if (req->wct < 5) {
4474 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4475 END_PROFILE(SMBwriteunlock);
4476 return;
4479 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4481 if (!check_fsp(conn, req, fsp)) {
4482 END_PROFILE(SMBwriteunlock);
4483 return;
4486 if (!CHECK_WRITE(fsp)) {
4487 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4488 END_PROFILE(SMBwriteunlock);
4489 return;
4492 numtowrite = SVAL(req->vwv+1, 0);
4493 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4494 data = (const char *)req->buf + 3;
4496 if (!fsp->print_file && numtowrite > 0) {
4497 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4498 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4499 &lock);
4501 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4502 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4503 END_PROFILE(SMBwriteunlock);
4504 return;
4508 /* The special X/Open SMB protocol handling of
4509 zero length writes is *NOT* done for
4510 this call */
4511 if(numtowrite == 0) {
4512 nwritten = 0;
4513 } else {
4514 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4515 saved_errno = errno;
4518 status = sync_file(conn, fsp, False /* write through */);
4519 if (!NT_STATUS_IS_OK(status)) {
4520 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4521 fsp_str_dbg(fsp), nt_errstr(status)));
4522 reply_nterror(req, status);
4523 goto strict_unlock;
4526 if(nwritten < 0) {
4527 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4528 goto strict_unlock;
4531 if((nwritten < numtowrite) && (numtowrite != 0)) {
4532 reply_nterror(req, NT_STATUS_DISK_FULL);
4533 goto strict_unlock;
4536 if (numtowrite && !fsp->print_file) {
4537 status = do_unlock(req->sconn->msg_ctx,
4538 fsp,
4539 (uint64_t)req->smbpid,
4540 (uint64_t)numtowrite,
4541 (uint64_t)startpos,
4542 WINDOWS_LOCK);
4544 if (NT_STATUS_V(status)) {
4545 reply_nterror(req, status);
4546 goto strict_unlock;
4550 reply_outbuf(req, 1, 0);
4552 SSVAL(req->outbuf,smb_vwv0,nwritten);
4554 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4555 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4557 strict_unlock:
4558 if (numtowrite && !fsp->print_file) {
4559 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4562 END_PROFILE(SMBwriteunlock);
4563 return;
4566 #undef DBGC_CLASS
4567 #define DBGC_CLASS DBGC_ALL
4569 /****************************************************************************
4570 Reply to a write.
4571 ****************************************************************************/
4573 void reply_write(struct smb_request *req)
4575 connection_struct *conn = req->conn;
4576 size_t numtowrite;
4577 ssize_t nwritten = -1;
4578 off_t startpos;
4579 const char *data;
4580 files_struct *fsp;
4581 struct lock_struct lock;
4582 NTSTATUS status;
4583 int saved_errno = 0;
4585 START_PROFILE(SMBwrite);
4587 if (req->wct < 5) {
4588 END_PROFILE(SMBwrite);
4589 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4590 return;
4593 /* If it's an IPC, pass off the pipe handler. */
4594 if (IS_IPC(conn)) {
4595 reply_pipe_write(req);
4596 END_PROFILE(SMBwrite);
4597 return;
4600 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4602 if (!check_fsp(conn, req, fsp)) {
4603 END_PROFILE(SMBwrite);
4604 return;
4607 if (!CHECK_WRITE(fsp)) {
4608 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4609 END_PROFILE(SMBwrite);
4610 return;
4613 numtowrite = SVAL(req->vwv+1, 0);
4614 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4615 data = (const char *)req->buf + 3;
4617 if (!fsp->print_file) {
4618 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4619 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4620 &lock);
4622 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4623 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4624 END_PROFILE(SMBwrite);
4625 return;
4630 * X/Open SMB protocol says that if smb_vwv1 is
4631 * zero then the file size should be extended or
4632 * truncated to the size given in smb_vwv[2-3].
4635 if(numtowrite == 0) {
4637 * This is actually an allocate call, and set EOF. JRA.
4639 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4640 if (nwritten < 0) {
4641 reply_nterror(req, NT_STATUS_DISK_FULL);
4642 goto strict_unlock;
4644 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4645 if (nwritten < 0) {
4646 reply_nterror(req, NT_STATUS_DISK_FULL);
4647 goto strict_unlock;
4649 trigger_write_time_update_immediate(fsp);
4650 } else {
4651 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4654 status = sync_file(conn, fsp, False);
4655 if (!NT_STATUS_IS_OK(status)) {
4656 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4657 fsp_str_dbg(fsp), nt_errstr(status)));
4658 reply_nterror(req, status);
4659 goto strict_unlock;
4662 if(nwritten < 0) {
4663 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4664 goto strict_unlock;
4667 if((nwritten == 0) && (numtowrite != 0)) {
4668 reply_nterror(req, NT_STATUS_DISK_FULL);
4669 goto strict_unlock;
4672 reply_outbuf(req, 1, 0);
4674 SSVAL(req->outbuf,smb_vwv0,nwritten);
4676 if (nwritten < (ssize_t)numtowrite) {
4677 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4678 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4681 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4683 strict_unlock:
4684 if (!fsp->print_file) {
4685 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4688 END_PROFILE(SMBwrite);
4689 return;
4692 /****************************************************************************
4693 Ensure a buffer is a valid writeX for recvfile purposes.
4694 ****************************************************************************/
4696 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4697 (2*14) + /* word count (including bcc) */ \
4698 1 /* pad byte */)
4700 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4701 const uint8_t *inbuf)
4703 size_t numtowrite;
4704 unsigned int doff = 0;
4705 size_t len = smb_len_large(inbuf);
4706 uint16_t fnum;
4707 struct smbXsrv_open *op = NULL;
4708 struct files_struct *fsp = NULL;
4709 NTSTATUS status;
4711 if (is_encrypted_packet(inbuf)) {
4712 /* Can't do this on encrypted
4713 * connections. */
4714 return false;
4717 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4718 return false;
4721 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4722 CVAL(inbuf,smb_wct) != 14) {
4723 DEBUG(10,("is_valid_writeX_buffer: chained or "
4724 "invalid word length.\n"));
4725 return false;
4728 fnum = SVAL(inbuf, smb_vwv2);
4729 status = smb1srv_open_lookup(xconn,
4730 fnum,
4731 0, /* now */
4732 &op);
4733 if (!NT_STATUS_IS_OK(status)) {
4734 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4735 return false;
4737 fsp = op->compat;
4738 if (fsp == NULL) {
4739 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4740 return false;
4742 if (fsp->conn == NULL) {
4743 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4744 return false;
4747 if (IS_IPC(fsp->conn)) {
4748 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4749 return false;
4751 if (IS_PRINT(fsp->conn)) {
4752 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4753 return false;
4755 doff = SVAL(inbuf,smb_vwv11);
4757 numtowrite = SVAL(inbuf,smb_vwv10);
4759 if (len > doff && len - doff > 0xFFFF) {
4760 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4763 if (numtowrite == 0) {
4764 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4765 return false;
4768 /* Ensure the sizes match up. */
4769 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4770 /* no pad byte...old smbclient :-( */
4771 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4772 (unsigned int)doff,
4773 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4774 return false;
4777 if (len - doff != numtowrite) {
4778 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4779 "len = %u, doff = %u, numtowrite = %u\n",
4780 (unsigned int)len,
4781 (unsigned int)doff,
4782 (unsigned int)numtowrite ));
4783 return false;
4786 DEBUG(10,("is_valid_writeX_buffer: true "
4787 "len = %u, doff = %u, numtowrite = %u\n",
4788 (unsigned int)len,
4789 (unsigned int)doff,
4790 (unsigned int)numtowrite ));
4792 return true;
4795 /****************************************************************************
4796 Reply to a write and X.
4797 ****************************************************************************/
4799 void reply_write_and_X(struct smb_request *req)
4801 connection_struct *conn = req->conn;
4802 struct smbXsrv_connection *xconn = req->xconn;
4803 files_struct *fsp;
4804 struct lock_struct lock;
4805 off_t startpos;
4806 size_t numtowrite;
4807 bool write_through;
4808 ssize_t nwritten;
4809 unsigned int smb_doff;
4810 unsigned int smblen;
4811 const char *data;
4812 NTSTATUS status;
4813 int saved_errno = 0;
4815 START_PROFILE(SMBwriteX);
4817 if ((req->wct != 12) && (req->wct != 14)) {
4818 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4819 goto out;
4822 numtowrite = SVAL(req->vwv+10, 0);
4823 smb_doff = SVAL(req->vwv+11, 0);
4824 smblen = smb_len(req->inbuf);
4826 if (req->unread_bytes > 0xFFFF ||
4827 (smblen > smb_doff &&
4828 smblen - smb_doff > 0xFFFF)) {
4829 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4832 if (req->unread_bytes) {
4833 /* Can't do a recvfile write on IPC$ */
4834 if (IS_IPC(conn)) {
4835 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4836 goto out;
4838 if (numtowrite != req->unread_bytes) {
4839 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4840 goto out;
4842 } else {
4843 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4844 smb_doff + numtowrite > smblen) {
4845 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4846 goto out;
4850 /* If it's an IPC, pass off the pipe handler. */
4851 if (IS_IPC(conn)) {
4852 if (req->unread_bytes) {
4853 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4854 goto out;
4856 reply_pipe_write_and_X(req);
4857 goto out;
4860 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4861 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4862 write_through = BITSETW(req->vwv+7,0);
4864 if (!check_fsp(conn, req, fsp)) {
4865 goto out;
4868 if (!CHECK_WRITE(fsp)) {
4869 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4870 goto out;
4873 data = smb_base(req->inbuf) + smb_doff;
4875 if(req->wct == 14) {
4877 * This is a large offset (64 bit) write.
4879 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4883 /* X/Open SMB protocol says that, unlike SMBwrite
4884 if the length is zero then NO truncation is
4885 done, just a write of zero. To truncate a file,
4886 use SMBwrite. */
4888 if(numtowrite == 0) {
4889 nwritten = 0;
4890 } else {
4891 if (req->unread_bytes == 0) {
4892 status = schedule_aio_write_and_X(conn,
4893 req,
4894 fsp,
4895 data,
4896 startpos,
4897 numtowrite);
4899 if (NT_STATUS_IS_OK(status)) {
4900 /* write scheduled - we're done. */
4901 goto out;
4903 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4904 /* Real error - report to client. */
4905 reply_nterror(req, status);
4906 goto out;
4908 /* NT_STATUS_RETRY - fall through to sync write. */
4911 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4912 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4913 &lock);
4915 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4916 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4917 goto out;
4920 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4921 saved_errno = errno;
4923 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4926 if(nwritten < 0) {
4927 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4928 goto out;
4931 if((nwritten == 0) && (numtowrite != 0)) {
4932 reply_nterror(req, NT_STATUS_DISK_FULL);
4933 goto out;
4936 reply_outbuf(req, 6, 0);
4937 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4938 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4939 SSVAL(req->outbuf,smb_vwv2,nwritten);
4940 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4942 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4943 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4945 status = sync_file(conn, fsp, write_through);
4946 if (!NT_STATUS_IS_OK(status)) {
4947 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4948 fsp_str_dbg(fsp), nt_errstr(status)));
4949 reply_nterror(req, status);
4950 goto out;
4953 END_PROFILE(SMBwriteX);
4954 return;
4956 out:
4957 if (req->unread_bytes) {
4958 /* writeX failed. drain socket. */
4959 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
4960 req->unread_bytes) {
4961 smb_panic("failed to drain pending bytes");
4963 req->unread_bytes = 0;
4966 END_PROFILE(SMBwriteX);
4967 return;
4970 /****************************************************************************
4971 Reply to a lseek.
4972 ****************************************************************************/
4974 void reply_lseek(struct smb_request *req)
4976 connection_struct *conn = req->conn;
4977 off_t startpos;
4978 off_t res= -1;
4979 int mode,umode;
4980 files_struct *fsp;
4982 START_PROFILE(SMBlseek);
4984 if (req->wct < 4) {
4985 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4986 END_PROFILE(SMBlseek);
4987 return;
4990 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4992 if (!check_fsp(conn, req, fsp)) {
4993 return;
4996 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
4998 mode = SVAL(req->vwv+1, 0) & 3;
4999 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5000 startpos = (off_t)IVALS(req->vwv+2, 0);
5002 switch (mode) {
5003 case 0:
5004 umode = SEEK_SET;
5005 res = startpos;
5006 break;
5007 case 1:
5008 umode = SEEK_CUR;
5009 res = fsp->fh->pos + startpos;
5010 break;
5011 case 2:
5012 umode = SEEK_END;
5013 break;
5014 default:
5015 umode = SEEK_SET;
5016 res = startpos;
5017 break;
5020 if (umode == SEEK_END) {
5021 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5022 if(errno == EINVAL) {
5023 off_t current_pos = startpos;
5025 if(fsp_stat(fsp) == -1) {
5026 reply_nterror(req,
5027 map_nt_error_from_unix(errno));
5028 END_PROFILE(SMBlseek);
5029 return;
5032 current_pos += fsp->fsp_name->st.st_ex_size;
5033 if(current_pos < 0)
5034 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5038 if(res == -1) {
5039 reply_nterror(req, map_nt_error_from_unix(errno));
5040 END_PROFILE(SMBlseek);
5041 return;
5045 fsp->fh->pos = res;
5047 reply_outbuf(req, 2, 0);
5048 SIVAL(req->outbuf,smb_vwv0,res);
5050 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5051 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5053 END_PROFILE(SMBlseek);
5054 return;
5057 /****************************************************************************
5058 Reply to a flush.
5059 ****************************************************************************/
5061 void reply_flush(struct smb_request *req)
5063 connection_struct *conn = req->conn;
5064 uint16 fnum;
5065 files_struct *fsp;
5067 START_PROFILE(SMBflush);
5069 if (req->wct < 1) {
5070 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5071 return;
5074 fnum = SVAL(req->vwv+0, 0);
5075 fsp = file_fsp(req, fnum);
5077 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5078 return;
5081 if (!fsp) {
5082 file_sync_all(conn);
5083 } else {
5084 NTSTATUS status = sync_file(conn, fsp, True);
5085 if (!NT_STATUS_IS_OK(status)) {
5086 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5087 fsp_str_dbg(fsp), nt_errstr(status)));
5088 reply_nterror(req, status);
5089 END_PROFILE(SMBflush);
5090 return;
5094 reply_outbuf(req, 0, 0);
5096 DEBUG(3,("flush\n"));
5097 END_PROFILE(SMBflush);
5098 return;
5101 /****************************************************************************
5102 Reply to a exit.
5103 conn POINTER CAN BE NULL HERE !
5104 ****************************************************************************/
5106 void reply_exit(struct smb_request *req)
5108 START_PROFILE(SMBexit);
5110 file_close_pid(req->sconn, req->smbpid, req->vuid);
5112 reply_outbuf(req, 0, 0);
5114 DEBUG(3,("exit\n"));
5116 END_PROFILE(SMBexit);
5117 return;
5120 struct reply_close_state {
5121 files_struct *fsp;
5122 struct smb_request *smbreq;
5125 static void do_smb1_close(struct tevent_req *req);
5127 void reply_close(struct smb_request *req)
5129 connection_struct *conn = req->conn;
5130 NTSTATUS status = NT_STATUS_OK;
5131 files_struct *fsp = NULL;
5132 START_PROFILE(SMBclose);
5134 if (req->wct < 3) {
5135 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5136 END_PROFILE(SMBclose);
5137 return;
5140 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5143 * We can only use check_fsp if we know it's not a directory.
5146 if (!check_fsp_open(conn, req, fsp)) {
5147 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5148 END_PROFILE(SMBclose);
5149 return;
5152 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5153 fsp->is_directory ? "directory" : "file",
5154 fsp->fh->fd, fsp_fnum_dbg(fsp),
5155 conn->num_files_open));
5157 if (!fsp->is_directory) {
5158 time_t t;
5161 * Take care of any time sent in the close.
5164 t = srv_make_unix_date3(req->vwv+1);
5165 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5168 if (fsp->num_aio_requests != 0) {
5170 struct reply_close_state *state;
5172 DEBUG(10, ("closing with aio %u requests pending\n",
5173 fsp->num_aio_requests));
5176 * We depend on the aio_extra destructor to take care of this
5177 * close request once fsp->num_aio_request drops to 0.
5180 fsp->deferred_close = tevent_wait_send(
5181 fsp, fsp->conn->sconn->ev_ctx);
5182 if (fsp->deferred_close == NULL) {
5183 status = NT_STATUS_NO_MEMORY;
5184 goto done;
5187 state = talloc(fsp, struct reply_close_state);
5188 if (state == NULL) {
5189 TALLOC_FREE(fsp->deferred_close);
5190 status = NT_STATUS_NO_MEMORY;
5191 goto done;
5193 state->fsp = fsp;
5194 state->smbreq = talloc_move(fsp, &req);
5195 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5196 state);
5197 END_PROFILE(SMBclose);
5198 return;
5202 * close_file() returns the unix errno if an error was detected on
5203 * close - normally this is due to a disk full error. If not then it
5204 * was probably an I/O error.
5207 status = close_file(req, fsp, NORMAL_CLOSE);
5208 done:
5209 if (!NT_STATUS_IS_OK(status)) {
5210 reply_nterror(req, status);
5211 END_PROFILE(SMBclose);
5212 return;
5215 reply_outbuf(req, 0, 0);
5216 END_PROFILE(SMBclose);
5217 return;
5220 static void do_smb1_close(struct tevent_req *req)
5222 struct reply_close_state *state = tevent_req_callback_data(
5223 req, struct reply_close_state);
5224 struct smb_request *smbreq;
5225 NTSTATUS status;
5226 int ret;
5228 ret = tevent_wait_recv(req);
5229 TALLOC_FREE(req);
5230 if (ret != 0) {
5231 DEBUG(10, ("tevent_wait_recv returned %s\n",
5232 strerror(ret)));
5234 * Continue anyway, this should never happen
5239 * fsp->smb2_close_request right now is a talloc grandchild of
5240 * fsp. When we close_file(fsp), it would go with it. No chance to
5241 * reply...
5243 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5245 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5246 if (NT_STATUS_IS_OK(status)) {
5247 reply_outbuf(smbreq, 0, 0);
5248 } else {
5249 reply_nterror(smbreq, status);
5251 if (!srv_send_smb(smbreq->xconn,
5252 (char *)smbreq->outbuf,
5253 true,
5254 smbreq->seqnum+1,
5255 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5256 NULL)) {
5257 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5258 "failed.");
5260 TALLOC_FREE(smbreq);
5263 /****************************************************************************
5264 Reply to a writeclose (Core+ protocol).
5265 ****************************************************************************/
5267 void reply_writeclose(struct smb_request *req)
5269 connection_struct *conn = req->conn;
5270 size_t numtowrite;
5271 ssize_t nwritten = -1;
5272 NTSTATUS close_status = NT_STATUS_OK;
5273 off_t startpos;
5274 const char *data;
5275 struct timespec mtime;
5276 files_struct *fsp;
5277 struct lock_struct lock;
5279 START_PROFILE(SMBwriteclose);
5281 if (req->wct < 6) {
5282 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5283 END_PROFILE(SMBwriteclose);
5284 return;
5287 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5289 if (!check_fsp(conn, req, fsp)) {
5290 END_PROFILE(SMBwriteclose);
5291 return;
5293 if (!CHECK_WRITE(fsp)) {
5294 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5295 END_PROFILE(SMBwriteclose);
5296 return;
5299 numtowrite = SVAL(req->vwv+1, 0);
5300 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5301 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5302 data = (const char *)req->buf + 1;
5304 if (fsp->print_file == NULL) {
5305 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5306 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5307 &lock);
5309 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5310 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5311 END_PROFILE(SMBwriteclose);
5312 return;
5316 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5318 if (fsp->print_file == NULL) {
5319 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5322 set_close_write_time(fsp, mtime);
5325 * More insanity. W2K only closes the file if writelen > 0.
5326 * JRA.
5329 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5330 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5331 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5333 if (numtowrite) {
5334 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5335 "file %s\n", fsp_str_dbg(fsp)));
5336 close_status = close_file(req, fsp, NORMAL_CLOSE);
5337 fsp = NULL;
5340 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5341 reply_nterror(req, NT_STATUS_DISK_FULL);
5342 goto out;
5345 if(!NT_STATUS_IS_OK(close_status)) {
5346 reply_nterror(req, close_status);
5347 goto out;
5350 reply_outbuf(req, 1, 0);
5352 SSVAL(req->outbuf,smb_vwv0,nwritten);
5354 out:
5356 END_PROFILE(SMBwriteclose);
5357 return;
5360 #undef DBGC_CLASS
5361 #define DBGC_CLASS DBGC_LOCKING
5363 /****************************************************************************
5364 Reply to a lock.
5365 ****************************************************************************/
5367 void reply_lock(struct smb_request *req)
5369 connection_struct *conn = req->conn;
5370 uint64_t count,offset;
5371 NTSTATUS status;
5372 files_struct *fsp;
5373 struct byte_range_lock *br_lck = NULL;
5375 START_PROFILE(SMBlock);
5377 if (req->wct < 5) {
5378 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5379 END_PROFILE(SMBlock);
5380 return;
5383 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5385 if (!check_fsp(conn, req, fsp)) {
5386 END_PROFILE(SMBlock);
5387 return;
5390 count = (uint64_t)IVAL(req->vwv+1, 0);
5391 offset = (uint64_t)IVAL(req->vwv+3, 0);
5393 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5394 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5396 br_lck = do_lock(req->sconn->msg_ctx,
5397 fsp,
5398 (uint64_t)req->smbpid,
5399 count,
5400 offset,
5401 WRITE_LOCK,
5402 WINDOWS_LOCK,
5403 False, /* Non-blocking lock. */
5404 &status,
5405 NULL);
5407 TALLOC_FREE(br_lck);
5409 if (NT_STATUS_V(status)) {
5410 reply_nterror(req, status);
5411 END_PROFILE(SMBlock);
5412 return;
5415 reply_outbuf(req, 0, 0);
5417 END_PROFILE(SMBlock);
5418 return;
5421 /****************************************************************************
5422 Reply to a unlock.
5423 ****************************************************************************/
5425 void reply_unlock(struct smb_request *req)
5427 connection_struct *conn = req->conn;
5428 uint64_t count,offset;
5429 NTSTATUS status;
5430 files_struct *fsp;
5432 START_PROFILE(SMBunlock);
5434 if (req->wct < 5) {
5435 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5436 END_PROFILE(SMBunlock);
5437 return;
5440 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5442 if (!check_fsp(conn, req, fsp)) {
5443 END_PROFILE(SMBunlock);
5444 return;
5447 count = (uint64_t)IVAL(req->vwv+1, 0);
5448 offset = (uint64_t)IVAL(req->vwv+3, 0);
5450 status = do_unlock(req->sconn->msg_ctx,
5451 fsp,
5452 (uint64_t)req->smbpid,
5453 count,
5454 offset,
5455 WINDOWS_LOCK);
5457 if (NT_STATUS_V(status)) {
5458 reply_nterror(req, status);
5459 END_PROFILE(SMBunlock);
5460 return;
5463 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5464 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5466 reply_outbuf(req, 0, 0);
5468 END_PROFILE(SMBunlock);
5469 return;
5472 #undef DBGC_CLASS
5473 #define DBGC_CLASS DBGC_ALL
5475 /****************************************************************************
5476 Reply to a tdis.
5477 conn POINTER CAN BE NULL HERE !
5478 ****************************************************************************/
5480 void reply_tdis(struct smb_request *req)
5482 NTSTATUS status;
5483 connection_struct *conn = req->conn;
5484 struct smbXsrv_tcon *tcon;
5486 START_PROFILE(SMBtdis);
5488 if (!conn) {
5489 DEBUG(4,("Invalid connection in tdis\n"));
5490 reply_force_doserror(req, ERRSRV, ERRinvnid);
5491 END_PROFILE(SMBtdis);
5492 return;
5495 tcon = conn->tcon;
5496 req->conn = NULL;
5499 * TODO: cancel all outstanding requests on the tcon
5501 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5502 if (!NT_STATUS_IS_OK(status)) {
5503 DEBUG(0, ("reply_tdis: "
5504 "smbXsrv_tcon_disconnect() failed: %s\n",
5505 nt_errstr(status)));
5507 * If we hit this case, there is something completely
5508 * wrong, so we better disconnect the transport connection.
5510 END_PROFILE(SMBtdis);
5511 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5512 return;
5515 TALLOC_FREE(tcon);
5517 reply_outbuf(req, 0, 0);
5518 END_PROFILE(SMBtdis);
5519 return;
5522 /****************************************************************************
5523 Reply to a echo.
5524 conn POINTER CAN BE NULL HERE !
5525 ****************************************************************************/
5527 void reply_echo(struct smb_request *req)
5529 connection_struct *conn = req->conn;
5530 struct smb_perfcount_data local_pcd;
5531 struct smb_perfcount_data *cur_pcd;
5532 int smb_reverb;
5533 int seq_num;
5535 START_PROFILE(SMBecho);
5537 smb_init_perfcount_data(&local_pcd);
5539 if (req->wct < 1) {
5540 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5541 END_PROFILE(SMBecho);
5542 return;
5545 smb_reverb = SVAL(req->vwv+0, 0);
5547 reply_outbuf(req, 1, req->buflen);
5549 /* copy any incoming data back out */
5550 if (req->buflen > 0) {
5551 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5554 if (smb_reverb > 100) {
5555 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5556 smb_reverb = 100;
5559 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5561 /* this makes sure we catch the request pcd */
5562 if (seq_num == smb_reverb) {
5563 cur_pcd = &req->pcd;
5564 } else {
5565 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5566 cur_pcd = &local_pcd;
5569 SSVAL(req->outbuf,smb_vwv0,seq_num);
5571 show_msg((char *)req->outbuf);
5572 if (!srv_send_smb(req->xconn,
5573 (char *)req->outbuf,
5574 true, req->seqnum+1,
5575 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5576 cur_pcd))
5577 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5580 DEBUG(3,("echo %d times\n", smb_reverb));
5582 TALLOC_FREE(req->outbuf);
5584 END_PROFILE(SMBecho);
5585 return;
5588 /****************************************************************************
5589 Reply to a printopen.
5590 ****************************************************************************/
5592 void reply_printopen(struct smb_request *req)
5594 connection_struct *conn = req->conn;
5595 files_struct *fsp;
5596 NTSTATUS status;
5598 START_PROFILE(SMBsplopen);
5600 if (req->wct < 2) {
5601 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5602 END_PROFILE(SMBsplopen);
5603 return;
5606 if (!CAN_PRINT(conn)) {
5607 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5608 END_PROFILE(SMBsplopen);
5609 return;
5612 status = file_new(req, conn, &fsp);
5613 if(!NT_STATUS_IS_OK(status)) {
5614 reply_nterror(req, status);
5615 END_PROFILE(SMBsplopen);
5616 return;
5619 /* Open for exclusive use, write only. */
5620 status = print_spool_open(fsp, NULL, req->vuid);
5622 if (!NT_STATUS_IS_OK(status)) {
5623 file_free(req, fsp);
5624 reply_nterror(req, status);
5625 END_PROFILE(SMBsplopen);
5626 return;
5629 reply_outbuf(req, 1, 0);
5630 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5632 DEBUG(3,("openprint fd=%d %s\n",
5633 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5635 END_PROFILE(SMBsplopen);
5636 return;
5639 /****************************************************************************
5640 Reply to a printclose.
5641 ****************************************************************************/
5643 void reply_printclose(struct smb_request *req)
5645 connection_struct *conn = req->conn;
5646 files_struct *fsp;
5647 NTSTATUS status;
5649 START_PROFILE(SMBsplclose);
5651 if (req->wct < 1) {
5652 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5653 END_PROFILE(SMBsplclose);
5654 return;
5657 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5659 if (!check_fsp(conn, req, fsp)) {
5660 END_PROFILE(SMBsplclose);
5661 return;
5664 if (!CAN_PRINT(conn)) {
5665 reply_force_doserror(req, ERRSRV, ERRerror);
5666 END_PROFILE(SMBsplclose);
5667 return;
5670 DEBUG(3,("printclose fd=%d %s\n",
5671 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5673 status = close_file(req, fsp, NORMAL_CLOSE);
5675 if(!NT_STATUS_IS_OK(status)) {
5676 reply_nterror(req, status);
5677 END_PROFILE(SMBsplclose);
5678 return;
5681 reply_outbuf(req, 0, 0);
5683 END_PROFILE(SMBsplclose);
5684 return;
5687 /****************************************************************************
5688 Reply to a printqueue.
5689 ****************************************************************************/
5691 void reply_printqueue(struct smb_request *req)
5693 connection_struct *conn = req->conn;
5694 int max_count;
5695 int start_index;
5697 START_PROFILE(SMBsplretq);
5699 if (req->wct < 2) {
5700 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5701 END_PROFILE(SMBsplretq);
5702 return;
5705 max_count = SVAL(req->vwv+0, 0);
5706 start_index = SVAL(req->vwv+1, 0);
5708 /* we used to allow the client to get the cnum wrong, but that
5709 is really quite gross and only worked when there was only
5710 one printer - I think we should now only accept it if they
5711 get it right (tridge) */
5712 if (!CAN_PRINT(conn)) {
5713 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5714 END_PROFILE(SMBsplretq);
5715 return;
5718 reply_outbuf(req, 2, 3);
5719 SSVAL(req->outbuf,smb_vwv0,0);
5720 SSVAL(req->outbuf,smb_vwv1,0);
5721 SCVAL(smb_buf(req->outbuf),0,1);
5722 SSVAL(smb_buf(req->outbuf),1,0);
5724 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5725 start_index, max_count));
5728 TALLOC_CTX *mem_ctx = talloc_tos();
5729 NTSTATUS status;
5730 WERROR werr;
5731 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5732 struct rpc_pipe_client *cli = NULL;
5733 struct dcerpc_binding_handle *b = NULL;
5734 struct policy_handle handle;
5735 struct spoolss_DevmodeContainer devmode_ctr;
5736 union spoolss_JobInfo *info;
5737 uint32_t count;
5738 uint32_t num_to_get;
5739 uint32_t first;
5740 uint32_t i;
5742 ZERO_STRUCT(handle);
5744 status = rpc_pipe_open_interface(conn,
5745 &ndr_table_spoolss,
5746 conn->session_info,
5747 conn->sconn->remote_address,
5748 conn->sconn->msg_ctx,
5749 &cli);
5750 if (!NT_STATUS_IS_OK(status)) {
5751 DEBUG(0, ("reply_printqueue: "
5752 "could not connect to spoolss: %s\n",
5753 nt_errstr(status)));
5754 reply_nterror(req, status);
5755 goto out;
5757 b = cli->binding_handle;
5759 ZERO_STRUCT(devmode_ctr);
5761 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5762 sharename,
5763 NULL, devmode_ctr,
5764 SEC_FLAG_MAXIMUM_ALLOWED,
5765 &handle,
5766 &werr);
5767 if (!NT_STATUS_IS_OK(status)) {
5768 reply_nterror(req, status);
5769 goto out;
5771 if (!W_ERROR_IS_OK(werr)) {
5772 reply_nterror(req, werror_to_ntstatus(werr));
5773 goto out;
5776 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5777 &handle,
5778 0, /* firstjob */
5779 0xff, /* numjobs */
5780 2, /* level */
5781 0, /* offered */
5782 &count,
5783 &info);
5784 if (!W_ERROR_IS_OK(werr)) {
5785 reply_nterror(req, werror_to_ntstatus(werr));
5786 goto out;
5789 if (max_count > 0) {
5790 first = start_index;
5791 } else {
5792 first = start_index + max_count + 1;
5795 if (first >= count) {
5796 num_to_get = first;
5797 } else {
5798 num_to_get = first + MIN(ABS(max_count), count - first);
5801 for (i = first; i < num_to_get; i++) {
5802 char blob[28];
5803 char *p = blob;
5804 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5805 int qstatus;
5806 size_t len = 0;
5807 uint16_t qrapjobid = pjobid_to_rap(sharename,
5808 info[i].info2.job_id);
5810 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5811 qstatus = 2;
5812 } else {
5813 qstatus = 3;
5816 srv_put_dos_date2(p, 0, qtime);
5817 SCVAL(p, 4, qstatus);
5818 SSVAL(p, 5, qrapjobid);
5819 SIVAL(p, 7, info[i].info2.size);
5820 SCVAL(p, 11, 0);
5821 status = srvstr_push(blob, req->flags2, p+12,
5822 info[i].info2.notify_name, 16, STR_ASCII, &len);
5823 if (!NT_STATUS_IS_OK(status)) {
5824 reply_nterror(req, status);
5825 goto out;
5827 if (message_push_blob(
5828 &req->outbuf,
5829 data_blob_const(
5830 blob, sizeof(blob))) == -1) {
5831 reply_nterror(req, NT_STATUS_NO_MEMORY);
5832 goto out;
5836 if (count > 0) {
5837 SSVAL(req->outbuf,smb_vwv0,count);
5838 SSVAL(req->outbuf,smb_vwv1,
5839 (max_count>0?first+count:first-1));
5840 SCVAL(smb_buf(req->outbuf),0,1);
5841 SSVAL(smb_buf(req->outbuf),1,28*count);
5845 DEBUG(3, ("%u entries returned in queue\n",
5846 (unsigned)count));
5848 out:
5849 if (b && is_valid_policy_hnd(&handle)) {
5850 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5855 END_PROFILE(SMBsplretq);
5856 return;
5859 /****************************************************************************
5860 Reply to a printwrite.
5861 ****************************************************************************/
5863 void reply_printwrite(struct smb_request *req)
5865 connection_struct *conn = req->conn;
5866 int numtowrite;
5867 const char *data;
5868 files_struct *fsp;
5870 START_PROFILE(SMBsplwr);
5872 if (req->wct < 1) {
5873 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5874 END_PROFILE(SMBsplwr);
5875 return;
5878 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5880 if (!check_fsp(conn, req, fsp)) {
5881 END_PROFILE(SMBsplwr);
5882 return;
5885 if (!fsp->print_file) {
5886 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5887 END_PROFILE(SMBsplwr);
5888 return;
5891 if (!CHECK_WRITE(fsp)) {
5892 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5893 END_PROFILE(SMBsplwr);
5894 return;
5897 numtowrite = SVAL(req->buf, 1);
5899 if (req->buflen < numtowrite + 3) {
5900 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5901 END_PROFILE(SMBsplwr);
5902 return;
5905 data = (const char *)req->buf + 3;
5907 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5908 reply_nterror(req, map_nt_error_from_unix(errno));
5909 END_PROFILE(SMBsplwr);
5910 return;
5913 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5915 END_PROFILE(SMBsplwr);
5916 return;
5919 /****************************************************************************
5920 Reply to a mkdir.
5921 ****************************************************************************/
5923 void reply_mkdir(struct smb_request *req)
5925 connection_struct *conn = req->conn;
5926 struct smb_filename *smb_dname = NULL;
5927 char *directory = NULL;
5928 NTSTATUS status;
5929 TALLOC_CTX *ctx = talloc_tos();
5931 START_PROFILE(SMBmkdir);
5933 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5934 STR_TERMINATE, &status);
5935 if (!NT_STATUS_IS_OK(status)) {
5936 reply_nterror(req, status);
5937 goto out;
5940 status = filename_convert(ctx, conn,
5941 req->flags2 & FLAGS2_DFS_PATHNAMES,
5942 directory,
5943 UCF_PREP_CREATEFILE,
5944 NULL,
5945 &smb_dname);
5946 if (!NT_STATUS_IS_OK(status)) {
5947 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5948 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5949 ERRSRV, ERRbadpath);
5950 goto out;
5952 reply_nterror(req, status);
5953 goto out;
5956 status = create_directory(conn, req, smb_dname);
5958 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5960 if (!NT_STATUS_IS_OK(status)) {
5962 if (!use_nt_status()
5963 && NT_STATUS_EQUAL(status,
5964 NT_STATUS_OBJECT_NAME_COLLISION)) {
5966 * Yes, in the DOS error code case we get a
5967 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5968 * samba4 torture test.
5970 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5973 reply_nterror(req, status);
5974 goto out;
5977 reply_outbuf(req, 0, 0);
5979 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5980 out:
5981 TALLOC_FREE(smb_dname);
5982 END_PROFILE(SMBmkdir);
5983 return;
5986 /****************************************************************************
5987 Reply to a rmdir.
5988 ****************************************************************************/
5990 void reply_rmdir(struct smb_request *req)
5992 connection_struct *conn = req->conn;
5993 struct smb_filename *smb_dname = NULL;
5994 char *directory = NULL;
5995 NTSTATUS status;
5996 TALLOC_CTX *ctx = talloc_tos();
5997 files_struct *fsp = NULL;
5998 int info = 0;
5999 struct smbd_server_connection *sconn = req->sconn;
6001 START_PROFILE(SMBrmdir);
6003 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6004 STR_TERMINATE, &status);
6005 if (!NT_STATUS_IS_OK(status)) {
6006 reply_nterror(req, status);
6007 goto out;
6010 status = filename_convert(ctx, conn,
6011 req->flags2 & FLAGS2_DFS_PATHNAMES,
6012 directory,
6014 NULL,
6015 &smb_dname);
6016 if (!NT_STATUS_IS_OK(status)) {
6017 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6018 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6019 ERRSRV, ERRbadpath);
6020 goto out;
6022 reply_nterror(req, status);
6023 goto out;
6026 if (is_ntfs_stream_smb_fname(smb_dname)) {
6027 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6028 goto out;
6031 status = SMB_VFS_CREATE_FILE(
6032 conn, /* conn */
6033 req, /* req */
6034 0, /* root_dir_fid */
6035 smb_dname, /* fname */
6036 DELETE_ACCESS, /* access_mask */
6037 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6038 FILE_SHARE_DELETE),
6039 FILE_OPEN, /* create_disposition*/
6040 FILE_DIRECTORY_FILE, /* create_options */
6041 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6042 0, /* oplock_request */
6043 NULL, /* lease */
6044 0, /* allocation_size */
6045 0, /* private_flags */
6046 NULL, /* sd */
6047 NULL, /* ea_list */
6048 &fsp, /* result */
6049 &info, /* pinfo */
6050 NULL, NULL); /* create context */
6052 if (!NT_STATUS_IS_OK(status)) {
6053 if (open_was_deferred(req->xconn, req->mid)) {
6054 /* We have re-scheduled this call. */
6055 goto out;
6057 reply_nterror(req, status);
6058 goto out;
6061 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6062 if (!NT_STATUS_IS_OK(status)) {
6063 close_file(req, fsp, ERROR_CLOSE);
6064 reply_nterror(req, status);
6065 goto out;
6068 if (!set_delete_on_close(fsp, true,
6069 conn->session_info->security_token,
6070 conn->session_info->unix_token)) {
6071 close_file(req, fsp, ERROR_CLOSE);
6072 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6073 goto out;
6076 status = close_file(req, fsp, NORMAL_CLOSE);
6077 if (!NT_STATUS_IS_OK(status)) {
6078 reply_nterror(req, status);
6079 } else {
6080 reply_outbuf(req, 0, 0);
6083 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6085 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6086 out:
6087 TALLOC_FREE(smb_dname);
6088 END_PROFILE(SMBrmdir);
6089 return;
6092 /*******************************************************************
6093 Resolve wildcards in a filename rename.
6094 ********************************************************************/
6096 static bool resolve_wildcards(TALLOC_CTX *ctx,
6097 const char *name1,
6098 const char *name2,
6099 char **pp_newname)
6101 char *name2_copy = NULL;
6102 char *root1 = NULL;
6103 char *root2 = NULL;
6104 char *ext1 = NULL;
6105 char *ext2 = NULL;
6106 char *p,*p2, *pname1, *pname2;
6108 name2_copy = talloc_strdup(ctx, name2);
6109 if (!name2_copy) {
6110 return False;
6113 pname1 = strrchr_m(name1,'/');
6114 pname2 = strrchr_m(name2_copy,'/');
6116 if (!pname1 || !pname2) {
6117 return False;
6120 /* Truncate the copy of name2 at the last '/' */
6121 *pname2 = '\0';
6123 /* Now go past the '/' */
6124 pname1++;
6125 pname2++;
6127 root1 = talloc_strdup(ctx, pname1);
6128 root2 = talloc_strdup(ctx, pname2);
6130 if (!root1 || !root2) {
6131 return False;
6134 p = strrchr_m(root1,'.');
6135 if (p) {
6136 *p = 0;
6137 ext1 = talloc_strdup(ctx, p+1);
6138 } else {
6139 ext1 = talloc_strdup(ctx, "");
6141 p = strrchr_m(root2,'.');
6142 if (p) {
6143 *p = 0;
6144 ext2 = talloc_strdup(ctx, p+1);
6145 } else {
6146 ext2 = talloc_strdup(ctx, "");
6149 if (!ext1 || !ext2) {
6150 return False;
6153 p = root1;
6154 p2 = root2;
6155 while (*p2) {
6156 if (*p2 == '?') {
6157 /* Hmmm. Should this be mb-aware ? */
6158 *p2 = *p;
6159 p2++;
6160 } else if (*p2 == '*') {
6161 *p2 = '\0';
6162 root2 = talloc_asprintf(ctx, "%s%s",
6163 root2,
6165 if (!root2) {
6166 return False;
6168 break;
6169 } else {
6170 p2++;
6172 if (*p) {
6173 p++;
6177 p = ext1;
6178 p2 = ext2;
6179 while (*p2) {
6180 if (*p2 == '?') {
6181 /* Hmmm. Should this be mb-aware ? */
6182 *p2 = *p;
6183 p2++;
6184 } else if (*p2 == '*') {
6185 *p2 = '\0';
6186 ext2 = talloc_asprintf(ctx, "%s%s",
6187 ext2,
6189 if (!ext2) {
6190 return False;
6192 break;
6193 } else {
6194 p2++;
6196 if (*p) {
6197 p++;
6201 if (*ext2) {
6202 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6203 name2_copy,
6204 root2,
6205 ext2);
6206 } else {
6207 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6208 name2_copy,
6209 root2);
6212 if (!*pp_newname) {
6213 return False;
6216 return True;
6219 /****************************************************************************
6220 Ensure open files have their names updated. Updated to notify other smbd's
6221 asynchronously.
6222 ****************************************************************************/
6224 static void rename_open_files(connection_struct *conn,
6225 struct share_mode_lock *lck,
6226 struct file_id id,
6227 uint32_t orig_name_hash,
6228 const struct smb_filename *smb_fname_dst)
6230 files_struct *fsp;
6231 bool did_rename = False;
6232 NTSTATUS status;
6233 uint32_t new_name_hash = 0;
6235 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6236 fsp = file_find_di_next(fsp)) {
6237 /* fsp_name is a relative path under the fsp. To change this for other
6238 sharepaths we need to manipulate relative paths. */
6239 /* TODO - create the absolute path and manipulate the newname
6240 relative to the sharepath. */
6241 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6242 continue;
6244 if (fsp->name_hash != orig_name_hash) {
6245 continue;
6247 DEBUG(10, ("rename_open_files: renaming file %s "
6248 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6249 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6250 smb_fname_str_dbg(smb_fname_dst)));
6252 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6253 if (NT_STATUS_IS_OK(status)) {
6254 did_rename = True;
6255 new_name_hash = fsp->name_hash;
6259 if (!did_rename) {
6260 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6261 "for %s\n", file_id_string_tos(&id),
6262 smb_fname_str_dbg(smb_fname_dst)));
6265 /* Send messages to all smbd's (not ourself) that the name has changed. */
6266 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6267 orig_name_hash, new_name_hash,
6268 smb_fname_dst);
6272 /****************************************************************************
6273 We need to check if the source path is a parent directory of the destination
6274 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6275 refuse the rename with a sharing violation. Under UNIX the above call can
6276 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6277 probably need to check that the client is a Windows one before disallowing
6278 this as a UNIX client (one with UNIX extensions) can know the source is a
6279 symlink and make this decision intelligently. Found by an excellent bug
6280 report from <AndyLiebman@aol.com>.
6281 ****************************************************************************/
6283 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6284 const struct smb_filename *smb_fname_dst)
6286 const char *psrc = smb_fname_src->base_name;
6287 const char *pdst = smb_fname_dst->base_name;
6288 size_t slen;
6290 if (psrc[0] == '.' && psrc[1] == '/') {
6291 psrc += 2;
6293 if (pdst[0] == '.' && pdst[1] == '/') {
6294 pdst += 2;
6296 if ((slen = strlen(psrc)) > strlen(pdst)) {
6297 return False;
6299 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6303 * Do the notify calls from a rename
6306 static void notify_rename(connection_struct *conn, bool is_dir,
6307 const struct smb_filename *smb_fname_src,
6308 const struct smb_filename *smb_fname_dst)
6310 char *parent_dir_src = NULL;
6311 char *parent_dir_dst = NULL;
6312 uint32 mask;
6314 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6315 : FILE_NOTIFY_CHANGE_FILE_NAME;
6317 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6318 &parent_dir_src, NULL) ||
6319 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6320 &parent_dir_dst, NULL)) {
6321 goto out;
6324 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6325 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6326 smb_fname_src->base_name);
6327 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6328 smb_fname_dst->base_name);
6330 else {
6331 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6332 smb_fname_src->base_name);
6333 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6334 smb_fname_dst->base_name);
6337 /* this is a strange one. w2k3 gives an additional event for
6338 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6339 files, but not directories */
6340 if (!is_dir) {
6341 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6342 FILE_NOTIFY_CHANGE_ATTRIBUTES
6343 |FILE_NOTIFY_CHANGE_CREATION,
6344 smb_fname_dst->base_name);
6346 out:
6347 TALLOC_FREE(parent_dir_src);
6348 TALLOC_FREE(parent_dir_dst);
6351 /****************************************************************************
6352 Returns an error if the parent directory for a filename is open in an
6353 incompatible way.
6354 ****************************************************************************/
6356 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6357 const struct smb_filename *smb_fname_dst_in)
6359 char *parent_dir = NULL;
6360 struct smb_filename smb_fname_parent;
6361 struct file_id id;
6362 files_struct *fsp = NULL;
6363 int ret;
6365 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6366 &parent_dir, NULL)) {
6367 return NT_STATUS_NO_MEMORY;
6369 ZERO_STRUCT(smb_fname_parent);
6370 smb_fname_parent.base_name = parent_dir;
6372 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6373 if (ret == -1) {
6374 return map_nt_error_from_unix(errno);
6378 * We're only checking on this smbd here, mostly good
6379 * enough.. and will pass tests.
6382 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6383 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6384 fsp = file_find_di_next(fsp)) {
6385 if (fsp->access_mask & DELETE_ACCESS) {
6386 return NT_STATUS_SHARING_VIOLATION;
6389 return NT_STATUS_OK;
6392 /****************************************************************************
6393 Rename an open file - given an fsp.
6394 ****************************************************************************/
6396 NTSTATUS rename_internals_fsp(connection_struct *conn,
6397 files_struct *fsp,
6398 const struct smb_filename *smb_fname_dst_in,
6399 uint32 attrs,
6400 bool replace_if_exists)
6402 TALLOC_CTX *ctx = talloc_tos();
6403 struct smb_filename *smb_fname_dst = NULL;
6404 NTSTATUS status = NT_STATUS_OK;
6405 struct share_mode_lock *lck = NULL;
6406 bool dst_exists, old_is_stream, new_is_stream;
6408 status = check_name(conn, smb_fname_dst_in->base_name);
6409 if (!NT_STATUS_IS_OK(status)) {
6410 return status;
6413 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6414 if (!NT_STATUS_IS_OK(status)) {
6415 return status;
6418 /* Make a copy of the dst smb_fname structs */
6420 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6421 if (smb_fname_dst == NULL) {
6422 status = NT_STATUS_NO_MEMORY;
6423 goto out;
6427 * Check for special case with case preserving and not
6428 * case sensitive. If the old last component differs from the original
6429 * last component only by case, then we should allow
6430 * the rename (user is trying to change the case of the
6431 * filename).
6433 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6434 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6435 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6436 char *last_slash;
6437 char *fname_dst_lcomp_base_mod = NULL;
6438 struct smb_filename *smb_fname_orig_lcomp = NULL;
6441 * Get the last component of the destination name.
6443 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6444 if (last_slash) {
6445 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6446 } else {
6447 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6449 if (!fname_dst_lcomp_base_mod) {
6450 status = NT_STATUS_NO_MEMORY;
6451 goto out;
6455 * Create an smb_filename struct using the original last
6456 * component of the destination.
6458 smb_fname_orig_lcomp = synthetic_smb_fname_split(
6459 ctx, smb_fname_dst->original_lcomp, NULL);
6460 if (smb_fname_orig_lcomp == NULL) {
6461 status = NT_STATUS_NO_MEMORY;
6462 TALLOC_FREE(fname_dst_lcomp_base_mod);
6463 goto out;
6466 /* If the base names only differ by case, use original. */
6467 if(!strcsequal(fname_dst_lcomp_base_mod,
6468 smb_fname_orig_lcomp->base_name)) {
6469 char *tmp;
6471 * Replace the modified last component with the
6472 * original.
6474 if (last_slash) {
6475 *last_slash = '\0'; /* Truncate at the '/' */
6476 tmp = talloc_asprintf(smb_fname_dst,
6477 "%s/%s",
6478 smb_fname_dst->base_name,
6479 smb_fname_orig_lcomp->base_name);
6480 } else {
6481 tmp = talloc_asprintf(smb_fname_dst,
6482 "%s",
6483 smb_fname_orig_lcomp->base_name);
6485 if (tmp == NULL) {
6486 status = NT_STATUS_NO_MEMORY;
6487 TALLOC_FREE(fname_dst_lcomp_base_mod);
6488 TALLOC_FREE(smb_fname_orig_lcomp);
6489 goto out;
6491 TALLOC_FREE(smb_fname_dst->base_name);
6492 smb_fname_dst->base_name = tmp;
6495 /* If the stream_names only differ by case, use original. */
6496 if(!strcsequal(smb_fname_dst->stream_name,
6497 smb_fname_orig_lcomp->stream_name)) {
6498 char *tmp = NULL;
6499 /* Use the original stream. */
6500 tmp = talloc_strdup(smb_fname_dst,
6501 smb_fname_orig_lcomp->stream_name);
6502 if (tmp == NULL) {
6503 status = NT_STATUS_NO_MEMORY;
6504 TALLOC_FREE(fname_dst_lcomp_base_mod);
6505 TALLOC_FREE(smb_fname_orig_lcomp);
6506 goto out;
6508 TALLOC_FREE(smb_fname_dst->stream_name);
6509 smb_fname_dst->stream_name = tmp;
6511 TALLOC_FREE(fname_dst_lcomp_base_mod);
6512 TALLOC_FREE(smb_fname_orig_lcomp);
6516 * If the src and dest names are identical - including case,
6517 * don't do the rename, just return success.
6520 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6521 strcsequal(fsp->fsp_name->stream_name,
6522 smb_fname_dst->stream_name)) {
6523 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6524 "- returning success\n",
6525 smb_fname_str_dbg(smb_fname_dst)));
6526 status = NT_STATUS_OK;
6527 goto out;
6530 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6531 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6533 /* Return the correct error code if both names aren't streams. */
6534 if (!old_is_stream && new_is_stream) {
6535 status = NT_STATUS_OBJECT_NAME_INVALID;
6536 goto out;
6539 if (old_is_stream && !new_is_stream) {
6540 status = NT_STATUS_INVALID_PARAMETER;
6541 goto out;
6544 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6546 if(!replace_if_exists && dst_exists) {
6547 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6548 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6549 smb_fname_str_dbg(smb_fname_dst)));
6550 status = NT_STATUS_OBJECT_NAME_COLLISION;
6551 goto out;
6554 if (dst_exists) {
6555 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6556 &smb_fname_dst->st);
6557 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6558 fileid);
6559 /* The file can be open when renaming a stream */
6560 if (dst_fsp && !new_is_stream) {
6561 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6562 status = NT_STATUS_ACCESS_DENIED;
6563 goto out;
6567 /* Ensure we have a valid stat struct for the source. */
6568 status = vfs_stat_fsp(fsp);
6569 if (!NT_STATUS_IS_OK(status)) {
6570 goto out;
6573 status = can_rename(conn, fsp, attrs);
6575 if (!NT_STATUS_IS_OK(status)) {
6576 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6577 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6578 smb_fname_str_dbg(smb_fname_dst)));
6579 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6580 status = NT_STATUS_ACCESS_DENIED;
6581 goto out;
6584 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6585 status = NT_STATUS_ACCESS_DENIED;
6588 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6591 * We have the file open ourselves, so not being able to get the
6592 * corresponding share mode lock is a fatal error.
6595 SMB_ASSERT(lck != NULL);
6597 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6598 uint32 create_options = fsp->fh->private_options;
6600 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6601 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6602 smb_fname_str_dbg(smb_fname_dst)));
6604 if (!fsp->is_directory &&
6605 !lp_posix_pathnames() &&
6606 (lp_map_archive(SNUM(conn)) ||
6607 lp_store_dos_attributes(SNUM(conn)))) {
6608 /* We must set the archive bit on the newly
6609 renamed file. */
6610 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6611 uint32_t old_dosmode = dos_mode(conn,
6612 smb_fname_dst);
6613 file_set_dosmode(conn,
6614 smb_fname_dst,
6615 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6616 NULL,
6617 true);
6621 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6622 smb_fname_dst);
6624 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6625 smb_fname_dst);
6628 * A rename acts as a new file create w.r.t. allowing an initial delete
6629 * on close, probably because in Windows there is a new handle to the
6630 * new file. If initial delete on close was requested but not
6631 * originally set, we need to set it here. This is probably not 100% correct,
6632 * but will work for the CIFSFS client which in non-posix mode
6633 * depends on these semantics. JRA.
6636 if (create_options & FILE_DELETE_ON_CLOSE) {
6637 status = can_set_delete_on_close(fsp, 0);
6639 if (NT_STATUS_IS_OK(status)) {
6640 /* Note that here we set the *inital* delete on close flag,
6641 * not the regular one. The magic gets handled in close. */
6642 fsp->initial_delete_on_close = True;
6645 TALLOC_FREE(lck);
6646 status = NT_STATUS_OK;
6647 goto out;
6650 TALLOC_FREE(lck);
6652 if (errno == ENOTDIR || errno == EISDIR) {
6653 status = NT_STATUS_OBJECT_NAME_COLLISION;
6654 } else {
6655 status = map_nt_error_from_unix(errno);
6658 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6659 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6660 smb_fname_str_dbg(smb_fname_dst)));
6662 out:
6663 TALLOC_FREE(smb_fname_dst);
6665 return status;
6668 /****************************************************************************
6669 The guts of the rename command, split out so it may be called by the NT SMB
6670 code.
6671 ****************************************************************************/
6673 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6674 connection_struct *conn,
6675 struct smb_request *req,
6676 struct smb_filename *smb_fname_src,
6677 struct smb_filename *smb_fname_dst,
6678 uint32 attrs,
6679 bool replace_if_exists,
6680 bool src_has_wild,
6681 bool dest_has_wild,
6682 uint32_t access_mask)
6684 char *fname_src_dir = NULL;
6685 char *fname_src_mask = NULL;
6686 int count=0;
6687 NTSTATUS status = NT_STATUS_OK;
6688 struct smb_Dir *dir_hnd = NULL;
6689 const char *dname = NULL;
6690 char *talloced = NULL;
6691 long offset = 0;
6692 int create_options = 0;
6693 bool posix_pathnames = lp_posix_pathnames();
6694 int rc;
6697 * Split the old name into directory and last component
6698 * strings. Note that unix_convert may have stripped off a
6699 * leading ./ from both name and newname if the rename is
6700 * at the root of the share. We need to make sure either both
6701 * name and newname contain a / character or neither of them do
6702 * as this is checked in resolve_wildcards().
6705 /* Split up the directory from the filename/mask. */
6706 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6707 &fname_src_dir, &fname_src_mask);
6708 if (!NT_STATUS_IS_OK(status)) {
6709 status = NT_STATUS_NO_MEMORY;
6710 goto out;
6714 * We should only check the mangled cache
6715 * here if unix_convert failed. This means
6716 * that the path in 'mask' doesn't exist
6717 * on the file system and so we need to look
6718 * for a possible mangle. This patch from
6719 * Tine Smukavec <valentin.smukavec@hermes.si>.
6722 if (!VALID_STAT(smb_fname_src->st) &&
6723 mangle_is_mangled(fname_src_mask, conn->params)) {
6724 char *new_mask = NULL;
6725 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6726 conn->params);
6727 if (new_mask) {
6728 TALLOC_FREE(fname_src_mask);
6729 fname_src_mask = new_mask;
6733 if (!src_has_wild) {
6734 files_struct *fsp;
6737 * Only one file needs to be renamed. Append the mask back
6738 * onto the directory.
6740 TALLOC_FREE(smb_fname_src->base_name);
6741 if (ISDOT(fname_src_dir)) {
6742 /* Ensure we use canonical names on open. */
6743 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6744 "%s",
6745 fname_src_mask);
6746 } else {
6747 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6748 "%s/%s",
6749 fname_src_dir,
6750 fname_src_mask);
6752 if (!smb_fname_src->base_name) {
6753 status = NT_STATUS_NO_MEMORY;
6754 goto out;
6757 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6758 "case_preserve = %d, short case preserve = %d, "
6759 "directory = %s, newname = %s, "
6760 "last_component_dest = %s\n",
6761 conn->case_sensitive, conn->case_preserve,
6762 conn->short_case_preserve,
6763 smb_fname_str_dbg(smb_fname_src),
6764 smb_fname_str_dbg(smb_fname_dst),
6765 smb_fname_dst->original_lcomp));
6767 /* The dest name still may have wildcards. */
6768 if (dest_has_wild) {
6769 char *fname_dst_mod = NULL;
6770 if (!resolve_wildcards(smb_fname_dst,
6771 smb_fname_src->base_name,
6772 smb_fname_dst->base_name,
6773 &fname_dst_mod)) {
6774 DEBUG(6, ("rename_internals: resolve_wildcards "
6775 "%s %s failed\n",
6776 smb_fname_src->base_name,
6777 smb_fname_dst->base_name));
6778 status = NT_STATUS_NO_MEMORY;
6779 goto out;
6781 TALLOC_FREE(smb_fname_dst->base_name);
6782 smb_fname_dst->base_name = fname_dst_mod;
6785 ZERO_STRUCT(smb_fname_src->st);
6786 if (posix_pathnames) {
6787 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6788 } else {
6789 rc = SMB_VFS_STAT(conn, smb_fname_src);
6791 if (rc == -1) {
6792 status = map_nt_error_from_unix_common(errno);
6793 goto out;
6796 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6797 create_options |= FILE_DIRECTORY_FILE;
6800 status = SMB_VFS_CREATE_FILE(
6801 conn, /* conn */
6802 req, /* req */
6803 0, /* root_dir_fid */
6804 smb_fname_src, /* fname */
6805 access_mask, /* access_mask */
6806 (FILE_SHARE_READ | /* share_access */
6807 FILE_SHARE_WRITE),
6808 FILE_OPEN, /* create_disposition*/
6809 create_options, /* create_options */
6810 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6811 0, /* oplock_request */
6812 NULL, /* lease */
6813 0, /* allocation_size */
6814 0, /* private_flags */
6815 NULL, /* sd */
6816 NULL, /* ea_list */
6817 &fsp, /* result */
6818 NULL, /* pinfo */
6819 NULL, NULL); /* create context */
6821 if (!NT_STATUS_IS_OK(status)) {
6822 DEBUG(3, ("Could not open rename source %s: %s\n",
6823 smb_fname_str_dbg(smb_fname_src),
6824 nt_errstr(status)));
6825 goto out;
6828 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6829 attrs, replace_if_exists);
6831 close_file(req, fsp, NORMAL_CLOSE);
6833 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6834 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6835 smb_fname_str_dbg(smb_fname_dst)));
6837 goto out;
6841 * Wildcards - process each file that matches.
6843 if (strequal(fname_src_mask, "????????.???")) {
6844 TALLOC_FREE(fname_src_mask);
6845 fname_src_mask = talloc_strdup(ctx, "*");
6846 if (!fname_src_mask) {
6847 status = NT_STATUS_NO_MEMORY;
6848 goto out;
6852 status = check_name(conn, fname_src_dir);
6853 if (!NT_STATUS_IS_OK(status)) {
6854 goto out;
6857 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6858 attrs);
6859 if (dir_hnd == NULL) {
6860 status = map_nt_error_from_unix(errno);
6861 goto out;
6864 status = NT_STATUS_NO_SUCH_FILE;
6866 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6867 * - gentest fix. JRA
6870 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6871 &talloced))) {
6872 files_struct *fsp = NULL;
6873 char *destname = NULL;
6874 bool sysdir_entry = False;
6876 /* Quick check for "." and ".." */
6877 if (ISDOT(dname) || ISDOTDOT(dname)) {
6878 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6879 sysdir_entry = True;
6880 } else {
6881 TALLOC_FREE(talloced);
6882 continue;
6886 if (!is_visible_file(conn, fname_src_dir, dname,
6887 &smb_fname_src->st, false)) {
6888 TALLOC_FREE(talloced);
6889 continue;
6892 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6893 TALLOC_FREE(talloced);
6894 continue;
6897 if (sysdir_entry) {
6898 status = NT_STATUS_OBJECT_NAME_INVALID;
6899 break;
6902 TALLOC_FREE(smb_fname_src->base_name);
6903 if (ISDOT(fname_src_dir)) {
6904 /* Ensure we use canonical names on open. */
6905 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6906 "%s",
6907 dname);
6908 } else {
6909 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6910 "%s/%s",
6911 fname_src_dir,
6912 dname);
6914 if (!smb_fname_src->base_name) {
6915 status = NT_STATUS_NO_MEMORY;
6916 goto out;
6919 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6920 smb_fname_dst->base_name,
6921 &destname)) {
6922 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6923 smb_fname_src->base_name, destname));
6924 TALLOC_FREE(talloced);
6925 continue;
6927 if (!destname) {
6928 status = NT_STATUS_NO_MEMORY;
6929 goto out;
6932 TALLOC_FREE(smb_fname_dst->base_name);
6933 smb_fname_dst->base_name = destname;
6935 ZERO_STRUCT(smb_fname_src->st);
6936 if (posix_pathnames) {
6937 SMB_VFS_LSTAT(conn, smb_fname_src);
6938 } else {
6939 SMB_VFS_STAT(conn, smb_fname_src);
6942 create_options = 0;
6944 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6945 create_options |= FILE_DIRECTORY_FILE;
6948 status = SMB_VFS_CREATE_FILE(
6949 conn, /* conn */
6950 req, /* req */
6951 0, /* root_dir_fid */
6952 smb_fname_src, /* fname */
6953 access_mask, /* access_mask */
6954 (FILE_SHARE_READ | /* share_access */
6955 FILE_SHARE_WRITE),
6956 FILE_OPEN, /* create_disposition*/
6957 create_options, /* create_options */
6958 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6959 0, /* oplock_request */
6960 NULL, /* lease */
6961 0, /* allocation_size */
6962 0, /* private_flags */
6963 NULL, /* sd */
6964 NULL, /* ea_list */
6965 &fsp, /* result */
6966 NULL, /* pinfo */
6967 NULL, NULL); /* create context */
6969 if (!NT_STATUS_IS_OK(status)) {
6970 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6971 "returned %s rename %s -> %s\n",
6972 nt_errstr(status),
6973 smb_fname_str_dbg(smb_fname_src),
6974 smb_fname_str_dbg(smb_fname_dst)));
6975 break;
6978 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6979 dname);
6980 if (!smb_fname_dst->original_lcomp) {
6981 status = NT_STATUS_NO_MEMORY;
6982 goto out;
6985 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6986 attrs, replace_if_exists);
6988 close_file(req, fsp, NORMAL_CLOSE);
6990 if (!NT_STATUS_IS_OK(status)) {
6991 DEBUG(3, ("rename_internals_fsp returned %s for "
6992 "rename %s -> %s\n", nt_errstr(status),
6993 smb_fname_str_dbg(smb_fname_src),
6994 smb_fname_str_dbg(smb_fname_dst)));
6995 break;
6998 count++;
7000 DEBUG(3,("rename_internals: doing rename on %s -> "
7001 "%s\n", smb_fname_str_dbg(smb_fname_src),
7002 smb_fname_str_dbg(smb_fname_src)));
7003 TALLOC_FREE(talloced);
7005 TALLOC_FREE(dir_hnd);
7007 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7008 status = map_nt_error_from_unix(errno);
7011 out:
7012 TALLOC_FREE(talloced);
7013 TALLOC_FREE(fname_src_dir);
7014 TALLOC_FREE(fname_src_mask);
7015 return status;
7018 /****************************************************************************
7019 Reply to a mv.
7020 ****************************************************************************/
7022 void reply_mv(struct smb_request *req)
7024 connection_struct *conn = req->conn;
7025 char *name = NULL;
7026 char *newname = NULL;
7027 const char *p;
7028 uint32 attrs;
7029 NTSTATUS status;
7030 bool src_has_wcard = False;
7031 bool dest_has_wcard = False;
7032 TALLOC_CTX *ctx = talloc_tos();
7033 struct smb_filename *smb_fname_src = NULL;
7034 struct smb_filename *smb_fname_dst = NULL;
7035 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
7036 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
7037 bool stream_rename = false;
7039 START_PROFILE(SMBmv);
7041 if (req->wct < 1) {
7042 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7043 goto out;
7046 attrs = SVAL(req->vwv+0, 0);
7048 p = (const char *)req->buf + 1;
7049 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7050 &status, &src_has_wcard);
7051 if (!NT_STATUS_IS_OK(status)) {
7052 reply_nterror(req, status);
7053 goto out;
7055 p++;
7056 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7057 &status, &dest_has_wcard);
7058 if (!NT_STATUS_IS_OK(status)) {
7059 reply_nterror(req, status);
7060 goto out;
7063 if (!lp_posix_pathnames()) {
7064 /* The newname must begin with a ':' if the
7065 name contains a ':'. */
7066 if (strchr_m(name, ':')) {
7067 if (newname[0] != ':') {
7068 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7069 goto out;
7071 stream_rename = true;
7075 status = filename_convert(ctx,
7076 conn,
7077 req->flags2 & FLAGS2_DFS_PATHNAMES,
7078 name,
7079 src_ucf_flags,
7080 &src_has_wcard,
7081 &smb_fname_src);
7083 if (!NT_STATUS_IS_OK(status)) {
7084 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7085 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7086 ERRSRV, ERRbadpath);
7087 goto out;
7089 reply_nterror(req, status);
7090 goto out;
7093 status = filename_convert(ctx,
7094 conn,
7095 req->flags2 & FLAGS2_DFS_PATHNAMES,
7096 newname,
7097 dst_ucf_flags,
7098 &dest_has_wcard,
7099 &smb_fname_dst);
7101 if (!NT_STATUS_IS_OK(status)) {
7102 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7103 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7104 ERRSRV, ERRbadpath);
7105 goto out;
7107 reply_nterror(req, status);
7108 goto out;
7111 if (stream_rename) {
7112 /* smb_fname_dst->base_name must be the same as
7113 smb_fname_src->base_name. */
7114 TALLOC_FREE(smb_fname_dst->base_name);
7115 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7116 smb_fname_src->base_name);
7117 if (!smb_fname_dst->base_name) {
7118 reply_nterror(req, NT_STATUS_NO_MEMORY);
7119 goto out;
7123 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7124 smb_fname_str_dbg(smb_fname_dst)));
7126 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7127 attrs, False, src_has_wcard, dest_has_wcard,
7128 DELETE_ACCESS);
7129 if (!NT_STATUS_IS_OK(status)) {
7130 if (open_was_deferred(req->xconn, req->mid)) {
7131 /* We have re-scheduled this call. */
7132 goto out;
7134 reply_nterror(req, status);
7135 goto out;
7138 reply_outbuf(req, 0, 0);
7139 out:
7140 TALLOC_FREE(smb_fname_src);
7141 TALLOC_FREE(smb_fname_dst);
7142 END_PROFILE(SMBmv);
7143 return;
7146 /*******************************************************************
7147 Copy a file as part of a reply_copy.
7148 ******************************************************************/
7151 * TODO: check error codes on all callers
7154 NTSTATUS copy_file(TALLOC_CTX *ctx,
7155 connection_struct *conn,
7156 struct smb_filename *smb_fname_src,
7157 struct smb_filename *smb_fname_dst,
7158 int ofun,
7159 int count,
7160 bool target_is_directory)
7162 struct smb_filename *smb_fname_dst_tmp = NULL;
7163 off_t ret=-1;
7164 files_struct *fsp1,*fsp2;
7165 uint32 dosattrs;
7166 uint32 new_create_disposition;
7167 NTSTATUS status;
7170 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7171 if (smb_fname_dst_tmp == NULL) {
7172 return NT_STATUS_NO_MEMORY;
7176 * If the target is a directory, extract the last component from the
7177 * src filename and append it to the dst filename
7179 if (target_is_directory) {
7180 const char *p;
7182 /* dest/target can't be a stream if it's a directory. */
7183 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7185 p = strrchr_m(smb_fname_src->base_name,'/');
7186 if (p) {
7187 p++;
7188 } else {
7189 p = smb_fname_src->base_name;
7191 smb_fname_dst_tmp->base_name =
7192 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7194 if (!smb_fname_dst_tmp->base_name) {
7195 status = NT_STATUS_NO_MEMORY;
7196 goto out;
7200 status = vfs_file_exist(conn, smb_fname_src);
7201 if (!NT_STATUS_IS_OK(status)) {
7202 goto out;
7205 if (!target_is_directory && count) {
7206 new_create_disposition = FILE_OPEN;
7207 } else {
7208 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7209 0, ofun,
7210 NULL, NULL,
7211 &new_create_disposition,
7212 NULL,
7213 NULL)) {
7214 status = NT_STATUS_INVALID_PARAMETER;
7215 goto out;
7219 /* Open the src file for reading. */
7220 status = SMB_VFS_CREATE_FILE(
7221 conn, /* conn */
7222 NULL, /* req */
7223 0, /* root_dir_fid */
7224 smb_fname_src, /* fname */
7225 FILE_GENERIC_READ, /* access_mask */
7226 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7227 FILE_OPEN, /* create_disposition*/
7228 0, /* create_options */
7229 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7230 INTERNAL_OPEN_ONLY, /* oplock_request */
7231 NULL, /* lease */
7232 0, /* allocation_size */
7233 0, /* private_flags */
7234 NULL, /* sd */
7235 NULL, /* ea_list */
7236 &fsp1, /* result */
7237 NULL, /* psbuf */
7238 NULL, NULL); /* create context */
7240 if (!NT_STATUS_IS_OK(status)) {
7241 goto out;
7244 dosattrs = dos_mode(conn, smb_fname_src);
7246 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7247 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7250 /* Open the dst file for writing. */
7251 status = SMB_VFS_CREATE_FILE(
7252 conn, /* conn */
7253 NULL, /* req */
7254 0, /* root_dir_fid */
7255 smb_fname_dst, /* fname */
7256 FILE_GENERIC_WRITE, /* access_mask */
7257 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7258 new_create_disposition, /* create_disposition*/
7259 0, /* create_options */
7260 dosattrs, /* file_attributes */
7261 INTERNAL_OPEN_ONLY, /* oplock_request */
7262 NULL, /* lease */
7263 0, /* allocation_size */
7264 0, /* private_flags */
7265 NULL, /* sd */
7266 NULL, /* ea_list */
7267 &fsp2, /* result */
7268 NULL, /* psbuf */
7269 NULL, NULL); /* create context */
7271 if (!NT_STATUS_IS_OK(status)) {
7272 close_file(NULL, fsp1, ERROR_CLOSE);
7273 goto out;
7276 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7277 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7278 if (ret == -1) {
7279 DEBUG(0, ("error - vfs lseek returned error %s\n",
7280 strerror(errno)));
7281 status = map_nt_error_from_unix(errno);
7282 close_file(NULL, fsp1, ERROR_CLOSE);
7283 close_file(NULL, fsp2, ERROR_CLOSE);
7284 goto out;
7288 /* Do the actual copy. */
7289 if (smb_fname_src->st.st_ex_size) {
7290 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7291 } else {
7292 ret = 0;
7295 close_file(NULL, fsp1, NORMAL_CLOSE);
7297 /* Ensure the modtime is set correctly on the destination file. */
7298 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7301 * As we are opening fsp1 read-only we only expect
7302 * an error on close on fsp2 if we are out of space.
7303 * Thus we don't look at the error return from the
7304 * close of fsp1.
7306 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7308 if (!NT_STATUS_IS_OK(status)) {
7309 goto out;
7312 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7313 status = NT_STATUS_DISK_FULL;
7314 goto out;
7317 status = NT_STATUS_OK;
7319 out:
7320 TALLOC_FREE(smb_fname_dst_tmp);
7321 return status;
7324 /****************************************************************************
7325 Reply to a file copy.
7326 ****************************************************************************/
7328 void reply_copy(struct smb_request *req)
7330 connection_struct *conn = req->conn;
7331 struct smb_filename *smb_fname_src = NULL;
7332 struct smb_filename *smb_fname_dst = NULL;
7333 char *fname_src = NULL;
7334 char *fname_dst = NULL;
7335 char *fname_src_mask = NULL;
7336 char *fname_src_dir = NULL;
7337 const char *p;
7338 int count=0;
7339 int error = ERRnoaccess;
7340 int tid2;
7341 int ofun;
7342 int flags;
7343 bool target_is_directory=False;
7344 bool source_has_wild = False;
7345 bool dest_has_wild = False;
7346 NTSTATUS status;
7347 TALLOC_CTX *ctx = talloc_tos();
7349 START_PROFILE(SMBcopy);
7351 if (req->wct < 3) {
7352 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7353 goto out;
7356 tid2 = SVAL(req->vwv+0, 0);
7357 ofun = SVAL(req->vwv+1, 0);
7358 flags = SVAL(req->vwv+2, 0);
7360 p = (const char *)req->buf;
7361 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7362 &status, &source_has_wild);
7363 if (!NT_STATUS_IS_OK(status)) {
7364 reply_nterror(req, status);
7365 goto out;
7367 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7368 &status, &dest_has_wild);
7369 if (!NT_STATUS_IS_OK(status)) {
7370 reply_nterror(req, status);
7371 goto out;
7374 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7376 if (tid2 != conn->cnum) {
7377 /* can't currently handle inter share copies XXXX */
7378 DEBUG(3,("Rejecting inter-share copy\n"));
7379 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7380 goto out;
7383 status = filename_convert(ctx, conn,
7384 req->flags2 & FLAGS2_DFS_PATHNAMES,
7385 fname_src,
7386 UCF_COND_ALLOW_WCARD_LCOMP,
7387 &source_has_wild,
7388 &smb_fname_src);
7389 if (!NT_STATUS_IS_OK(status)) {
7390 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7391 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7392 ERRSRV, ERRbadpath);
7393 goto out;
7395 reply_nterror(req, status);
7396 goto out;
7399 status = filename_convert(ctx, conn,
7400 req->flags2 & FLAGS2_DFS_PATHNAMES,
7401 fname_dst,
7402 UCF_COND_ALLOW_WCARD_LCOMP,
7403 &dest_has_wild,
7404 &smb_fname_dst);
7405 if (!NT_STATUS_IS_OK(status)) {
7406 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7407 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7408 ERRSRV, ERRbadpath);
7409 goto out;
7411 reply_nterror(req, status);
7412 goto out;
7415 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7417 if ((flags&1) && target_is_directory) {
7418 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7419 goto out;
7422 if ((flags&2) && !target_is_directory) {
7423 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7424 goto out;
7427 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7428 /* wants a tree copy! XXXX */
7429 DEBUG(3,("Rejecting tree copy\n"));
7430 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7431 goto out;
7434 /* Split up the directory from the filename/mask. */
7435 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7436 &fname_src_dir, &fname_src_mask);
7437 if (!NT_STATUS_IS_OK(status)) {
7438 reply_nterror(req, NT_STATUS_NO_MEMORY);
7439 goto out;
7443 * We should only check the mangled cache
7444 * here if unix_convert failed. This means
7445 * that the path in 'mask' doesn't exist
7446 * on the file system and so we need to look
7447 * for a possible mangle. This patch from
7448 * Tine Smukavec <valentin.smukavec@hermes.si>.
7450 if (!VALID_STAT(smb_fname_src->st) &&
7451 mangle_is_mangled(fname_src_mask, conn->params)) {
7452 char *new_mask = NULL;
7453 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7454 &new_mask, conn->params);
7456 /* Use demangled name if one was successfully found. */
7457 if (new_mask) {
7458 TALLOC_FREE(fname_src_mask);
7459 fname_src_mask = new_mask;
7463 if (!source_has_wild) {
7466 * Only one file needs to be copied. Append the mask back onto
7467 * the directory.
7469 TALLOC_FREE(smb_fname_src->base_name);
7470 if (ISDOT(fname_src_dir)) {
7471 /* Ensure we use canonical names on open. */
7472 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7473 "%s",
7474 fname_src_mask);
7475 } else {
7476 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7477 "%s/%s",
7478 fname_src_dir,
7479 fname_src_mask);
7481 if (!smb_fname_src->base_name) {
7482 reply_nterror(req, NT_STATUS_NO_MEMORY);
7483 goto out;
7486 if (dest_has_wild) {
7487 char *fname_dst_mod = NULL;
7488 if (!resolve_wildcards(smb_fname_dst,
7489 smb_fname_src->base_name,
7490 smb_fname_dst->base_name,
7491 &fname_dst_mod)) {
7492 reply_nterror(req, NT_STATUS_NO_MEMORY);
7493 goto out;
7495 TALLOC_FREE(smb_fname_dst->base_name);
7496 smb_fname_dst->base_name = fname_dst_mod;
7499 status = check_name(conn, smb_fname_src->base_name);
7500 if (!NT_STATUS_IS_OK(status)) {
7501 reply_nterror(req, status);
7502 goto out;
7505 status = check_name(conn, smb_fname_dst->base_name);
7506 if (!NT_STATUS_IS_OK(status)) {
7507 reply_nterror(req, status);
7508 goto out;
7511 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7512 ofun, count, target_is_directory);
7514 if(!NT_STATUS_IS_OK(status)) {
7515 reply_nterror(req, status);
7516 goto out;
7517 } else {
7518 count++;
7520 } else {
7521 struct smb_Dir *dir_hnd = NULL;
7522 const char *dname = NULL;
7523 char *talloced = NULL;
7524 long offset = 0;
7527 * There is a wildcard that requires us to actually read the
7528 * src dir and copy each file matching the mask to the dst.
7529 * Right now streams won't be copied, but this could
7530 * presumably be added with a nested loop for reach dir entry.
7532 SMB_ASSERT(!smb_fname_src->stream_name);
7533 SMB_ASSERT(!smb_fname_dst->stream_name);
7535 smb_fname_src->stream_name = NULL;
7536 smb_fname_dst->stream_name = NULL;
7538 if (strequal(fname_src_mask,"????????.???")) {
7539 TALLOC_FREE(fname_src_mask);
7540 fname_src_mask = talloc_strdup(ctx, "*");
7541 if (!fname_src_mask) {
7542 reply_nterror(req, NT_STATUS_NO_MEMORY);
7543 goto out;
7547 status = check_name(conn, fname_src_dir);
7548 if (!NT_STATUS_IS_OK(status)) {
7549 reply_nterror(req, status);
7550 goto out;
7553 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7554 if (dir_hnd == NULL) {
7555 status = map_nt_error_from_unix(errno);
7556 reply_nterror(req, status);
7557 goto out;
7560 error = ERRbadfile;
7562 /* Iterate over the src dir copying each entry to the dst. */
7563 while ((dname = ReadDirName(dir_hnd, &offset,
7564 &smb_fname_src->st, &talloced))) {
7565 char *destname = NULL;
7567 if (ISDOT(dname) || ISDOTDOT(dname)) {
7568 TALLOC_FREE(talloced);
7569 continue;
7572 if (!is_visible_file(conn, fname_src_dir, dname,
7573 &smb_fname_src->st, false)) {
7574 TALLOC_FREE(talloced);
7575 continue;
7578 if(!mask_match(dname, fname_src_mask,
7579 conn->case_sensitive)) {
7580 TALLOC_FREE(talloced);
7581 continue;
7584 error = ERRnoaccess;
7586 /* Get the src smb_fname struct setup. */
7587 TALLOC_FREE(smb_fname_src->base_name);
7588 if (ISDOT(fname_src_dir)) {
7589 /* Ensure we use canonical names on open. */
7590 smb_fname_src->base_name =
7591 talloc_asprintf(smb_fname_src, "%s",
7592 dname);
7593 } else {
7594 smb_fname_src->base_name =
7595 talloc_asprintf(smb_fname_src, "%s/%s",
7596 fname_src_dir, dname);
7599 if (!smb_fname_src->base_name) {
7600 TALLOC_FREE(dir_hnd);
7601 TALLOC_FREE(talloced);
7602 reply_nterror(req, NT_STATUS_NO_MEMORY);
7603 goto out;
7606 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7607 smb_fname_dst->base_name,
7608 &destname)) {
7609 TALLOC_FREE(talloced);
7610 continue;
7612 if (!destname) {
7613 TALLOC_FREE(dir_hnd);
7614 TALLOC_FREE(talloced);
7615 reply_nterror(req, NT_STATUS_NO_MEMORY);
7616 goto out;
7619 TALLOC_FREE(smb_fname_dst->base_name);
7620 smb_fname_dst->base_name = destname;
7622 status = check_name(conn, smb_fname_src->base_name);
7623 if (!NT_STATUS_IS_OK(status)) {
7624 TALLOC_FREE(dir_hnd);
7625 TALLOC_FREE(talloced);
7626 reply_nterror(req, status);
7627 goto out;
7630 status = check_name(conn, smb_fname_dst->base_name);
7631 if (!NT_STATUS_IS_OK(status)) {
7632 TALLOC_FREE(dir_hnd);
7633 TALLOC_FREE(talloced);
7634 reply_nterror(req, status);
7635 goto out;
7638 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7639 smb_fname_src->base_name,
7640 smb_fname_dst->base_name));
7642 status = copy_file(ctx, conn, smb_fname_src,
7643 smb_fname_dst, ofun, count,
7644 target_is_directory);
7645 if (NT_STATUS_IS_OK(status)) {
7646 count++;
7649 TALLOC_FREE(talloced);
7651 TALLOC_FREE(dir_hnd);
7654 if (count == 0) {
7655 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7656 goto out;
7659 reply_outbuf(req, 1, 0);
7660 SSVAL(req->outbuf,smb_vwv0,count);
7661 out:
7662 TALLOC_FREE(smb_fname_src);
7663 TALLOC_FREE(smb_fname_dst);
7664 TALLOC_FREE(fname_src);
7665 TALLOC_FREE(fname_dst);
7666 TALLOC_FREE(fname_src_mask);
7667 TALLOC_FREE(fname_src_dir);
7669 END_PROFILE(SMBcopy);
7670 return;
7673 #undef DBGC_CLASS
7674 #define DBGC_CLASS DBGC_LOCKING
7676 /****************************************************************************
7677 Get a lock pid, dealing with large count requests.
7678 ****************************************************************************/
7680 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7681 bool large_file_format)
7683 if(!large_file_format)
7684 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7685 else
7686 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7689 /****************************************************************************
7690 Get a lock count, dealing with large count requests.
7691 ****************************************************************************/
7693 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7694 bool large_file_format)
7696 uint64_t count = 0;
7698 if(!large_file_format) {
7699 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7700 } else {
7702 * No BVAL, this is reversed!
7704 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7705 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7708 return count;
7711 /****************************************************************************
7712 Get a lock offset, dealing with large offset requests.
7713 ****************************************************************************/
7715 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7716 bool large_file_format)
7718 uint64_t offset = 0;
7720 if(!large_file_format) {
7721 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7722 } else {
7724 * No BVAL, this is reversed!
7726 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7727 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7730 return offset;
7733 NTSTATUS smbd_do_locking(struct smb_request *req,
7734 files_struct *fsp,
7735 uint8_t type,
7736 int32_t timeout,
7737 uint16_t num_locks,
7738 struct smbd_lock_element *locks,
7739 bool *async)
7741 connection_struct *conn = req->conn;
7742 int i;
7743 NTSTATUS status = NT_STATUS_OK;
7745 *async = false;
7747 /* Setup the timeout in seconds. */
7749 if (!lp_blocking_locks(SNUM(conn))) {
7750 timeout = 0;
7753 for(i = 0; i < (int)num_locks; i++) {
7754 struct smbd_lock_element *e = &locks[i];
7756 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7757 "%llu, file %s timeout = %d\n",
7758 (double)e->offset,
7759 (double)e->count,
7760 (unsigned long long)e->smblctx,
7761 fsp_str_dbg(fsp),
7762 (int)timeout));
7764 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7765 struct blocking_lock_record *blr = NULL;
7767 if (num_locks > 1) {
7769 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7770 * if the lock vector contains one entry. When given multiple cancel
7771 * requests in a single PDU we expect the server to return an
7772 * error. Windows servers seem to accept the request but only
7773 * cancel the first lock.
7774 * JRA - Do what Windows does (tm) :-).
7777 #if 0
7778 /* MS-CIFS (2.2.4.32.1) behavior. */
7779 return NT_STATUS_DOS(ERRDOS,
7780 ERRcancelviolation);
7781 #else
7782 /* Windows behavior. */
7783 if (i != 0) {
7784 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7785 "cancel request\n"));
7786 continue;
7788 #endif
7791 if (lp_blocking_locks(SNUM(conn))) {
7793 /* Schedule a message to ourselves to
7794 remove the blocking lock record and
7795 return the right error. */
7797 blr = blocking_lock_cancel_smb1(fsp,
7798 e->smblctx,
7799 e->offset,
7800 e->count,
7801 WINDOWS_LOCK,
7802 type,
7803 NT_STATUS_FILE_LOCK_CONFLICT);
7804 if (blr == NULL) {
7805 return NT_STATUS_DOS(
7806 ERRDOS,
7807 ERRcancelviolation);
7810 /* Remove a matching pending lock. */
7811 status = do_lock_cancel(fsp,
7812 e->smblctx,
7813 e->count,
7814 e->offset,
7815 WINDOWS_LOCK);
7816 } else {
7817 bool blocking_lock = timeout ? true : false;
7818 bool defer_lock = false;
7819 struct byte_range_lock *br_lck;
7820 uint64_t block_smblctx;
7822 br_lck = do_lock(req->sconn->msg_ctx,
7823 fsp,
7824 e->smblctx,
7825 e->count,
7826 e->offset,
7827 e->brltype,
7828 WINDOWS_LOCK,
7829 blocking_lock,
7830 &status,
7831 &block_smblctx);
7833 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7834 /* Windows internal resolution for blocking locks seems
7835 to be about 200ms... Don't wait for less than that. JRA. */
7836 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7837 timeout = lp_lock_spin_time();
7839 defer_lock = true;
7842 /* If a lock sent with timeout of zero would fail, and
7843 * this lock has been requested multiple times,
7844 * according to brl_lock_failed() we convert this
7845 * request to a blocking lock with a timeout of between
7846 * 150 - 300 milliseconds.
7848 * If lp_lock_spin_time() has been set to 0, we skip
7849 * this blocking retry and fail immediately.
7851 * Replacement for do_lock_spin(). JRA. */
7853 if (!req->sconn->using_smb2 &&
7854 br_lck && lp_blocking_locks(SNUM(conn)) &&
7855 lp_lock_spin_time() && !blocking_lock &&
7856 NT_STATUS_EQUAL((status),
7857 NT_STATUS_FILE_LOCK_CONFLICT))
7859 defer_lock = true;
7860 timeout = lp_lock_spin_time();
7863 if (br_lck && defer_lock) {
7865 * A blocking lock was requested. Package up
7866 * this smb into a queued request and push it
7867 * onto the blocking lock queue.
7869 if(push_blocking_lock_request(br_lck,
7870 req,
7871 fsp,
7872 timeout,
7874 e->smblctx,
7875 e->brltype,
7876 WINDOWS_LOCK,
7877 e->offset,
7878 e->count,
7879 block_smblctx)) {
7880 TALLOC_FREE(br_lck);
7881 *async = true;
7882 return NT_STATUS_OK;
7886 TALLOC_FREE(br_lck);
7889 if (!NT_STATUS_IS_OK(status)) {
7890 break;
7894 /* If any of the above locks failed, then we must unlock
7895 all of the previous locks (X/Open spec). */
7897 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7899 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7900 i = -1; /* we want to skip the for loop */
7904 * Ensure we don't do a remove on the lock that just failed,
7905 * as under POSIX rules, if we have a lock already there, we
7906 * will delete it (and we shouldn't) .....
7908 for(i--; i >= 0; i--) {
7909 struct smbd_lock_element *e = &locks[i];
7911 do_unlock(req->sconn->msg_ctx,
7912 fsp,
7913 e->smblctx,
7914 e->count,
7915 e->offset,
7916 WINDOWS_LOCK);
7918 return status;
7921 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
7922 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
7924 return NT_STATUS_OK;
7927 NTSTATUS smbd_do_unlocking(struct smb_request *req,
7928 files_struct *fsp,
7929 uint16_t num_ulocks,
7930 struct smbd_lock_element *ulocks)
7932 int i;
7934 for(i = 0; i < (int)num_ulocks; i++) {
7935 struct smbd_lock_element *e = &ulocks[i];
7936 NTSTATUS status;
7938 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
7939 "pid %u, file %s\n", __func__,
7940 (double)e->offset,
7941 (double)e->count,
7942 (unsigned int)e->smblctx,
7943 fsp_str_dbg(fsp)));
7945 if (e->brltype != UNLOCK_LOCK) {
7946 /* this can only happen with SMB2 */
7947 return NT_STATUS_INVALID_PARAMETER;
7950 status = do_unlock(req->sconn->msg_ctx,
7951 fsp,
7952 e->smblctx,
7953 e->count,
7954 e->offset,
7955 WINDOWS_LOCK);
7957 DEBUG(10, ("%s: unlock returned %s\n", __func__,
7958 nt_errstr(status)));
7960 if (!NT_STATUS_IS_OK(status)) {
7961 return status;
7965 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
7966 num_ulocks));
7968 return NT_STATUS_OK;
7971 /****************************************************************************
7972 Reply to a lockingX request.
7973 ****************************************************************************/
7975 void reply_lockingX(struct smb_request *req)
7977 connection_struct *conn = req->conn;
7978 files_struct *fsp;
7979 unsigned char locktype;
7980 unsigned char oplocklevel;
7981 uint16 num_ulocks;
7982 uint16 num_locks;
7983 int32 lock_timeout;
7984 int i;
7985 const uint8_t *data;
7986 bool large_file_format;
7987 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7988 struct smbd_lock_element *ulocks;
7989 struct smbd_lock_element *locks;
7990 bool async = false;
7992 START_PROFILE(SMBlockingX);
7994 if (req->wct < 8) {
7995 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7996 END_PROFILE(SMBlockingX);
7997 return;
8000 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8001 locktype = CVAL(req->vwv+3, 0);
8002 oplocklevel = CVAL(req->vwv+3, 1);
8003 num_ulocks = SVAL(req->vwv+6, 0);
8004 num_locks = SVAL(req->vwv+7, 0);
8005 lock_timeout = IVAL(req->vwv+4, 0);
8006 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8008 if (!check_fsp(conn, req, fsp)) {
8009 END_PROFILE(SMBlockingX);
8010 return;
8013 data = req->buf;
8015 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8016 /* we don't support these - and CANCEL_LOCK makes w2k
8017 and XP reboot so I don't really want to be
8018 compatible! (tridge) */
8019 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8020 END_PROFILE(SMBlockingX);
8021 return;
8024 /* Check if this is an oplock break on a file
8025 we have granted an oplock on.
8027 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8028 /* Client can insist on breaking to none. */
8029 bool break_to_none = (oplocklevel == 0);
8030 bool result;
8032 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8033 "for %s\n", (unsigned int)oplocklevel,
8034 fsp_fnum_dbg(fsp)));
8037 * Make sure we have granted an exclusive or batch oplock on
8038 * this file.
8041 if (fsp->oplock_type == 0) {
8043 /* The Samba4 nbench simulator doesn't understand
8044 the difference between break to level2 and break
8045 to none from level2 - it sends oplock break
8046 replies in both cases. Don't keep logging an error
8047 message here - just ignore it. JRA. */
8049 DEBUG(5,("reply_lockingX: Error : oplock break from "
8050 "client for %s (oplock=%d) and no "
8051 "oplock granted on this file (%s).\n",
8052 fsp_fnum_dbg(fsp), fsp->oplock_type,
8053 fsp_str_dbg(fsp)));
8055 /* if this is a pure oplock break request then don't
8056 * send a reply */
8057 if (num_locks == 0 && num_ulocks == 0) {
8058 END_PROFILE(SMBlockingX);
8059 return;
8060 } else {
8061 END_PROFILE(SMBlockingX);
8062 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8063 return;
8067 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8068 (break_to_none)) {
8069 result = remove_oplock(fsp);
8070 } else {
8071 result = downgrade_oplock(fsp);
8074 if (!result) {
8075 DEBUG(0, ("reply_lockingX: error in removing "
8076 "oplock on file %s\n", fsp_str_dbg(fsp)));
8077 /* Hmmm. Is this panic justified? */
8078 smb_panic("internal tdb error");
8081 /* if this is a pure oplock break request then don't send a
8082 * reply */
8083 if (num_locks == 0 && num_ulocks == 0) {
8084 /* Sanity check - ensure a pure oplock break is not a
8085 chained request. */
8086 if (CVAL(req->vwv+0, 0) != 0xff) {
8087 DEBUG(0,("reply_lockingX: Error : pure oplock "
8088 "break is a chained %d request !\n",
8089 (unsigned int)CVAL(req->vwv+0, 0)));
8091 END_PROFILE(SMBlockingX);
8092 return;
8096 if (req->buflen <
8097 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8098 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8099 END_PROFILE(SMBlockingX);
8100 return;
8103 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8104 if (ulocks == NULL) {
8105 reply_nterror(req, NT_STATUS_NO_MEMORY);
8106 END_PROFILE(SMBlockingX);
8107 return;
8110 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8111 if (locks == NULL) {
8112 reply_nterror(req, NT_STATUS_NO_MEMORY);
8113 END_PROFILE(SMBlockingX);
8114 return;
8117 /* Data now points at the beginning of the list
8118 of smb_unlkrng structs */
8119 for(i = 0; i < (int)num_ulocks; i++) {
8120 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8121 ulocks[i].count = get_lock_count(data, i, large_file_format);
8122 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8123 ulocks[i].brltype = UNLOCK_LOCK;
8126 /* Now do any requested locks */
8127 data += ((large_file_format ? 20 : 10)*num_ulocks);
8129 /* Data now points at the beginning of the list
8130 of smb_lkrng structs */
8132 for(i = 0; i < (int)num_locks; i++) {
8133 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8134 locks[i].count = get_lock_count(data, i, large_file_format);
8135 locks[i].offset = get_lock_offset(data, i, large_file_format);
8137 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8138 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8139 locks[i].brltype = PENDING_READ_LOCK;
8140 } else {
8141 locks[i].brltype = READ_LOCK;
8143 } else {
8144 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8145 locks[i].brltype = PENDING_WRITE_LOCK;
8146 } else {
8147 locks[i].brltype = WRITE_LOCK;
8152 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8153 if (!NT_STATUS_IS_OK(status)) {
8154 END_PROFILE(SMBlockingX);
8155 reply_nterror(req, status);
8156 return;
8159 status = smbd_do_locking(req, fsp,
8160 locktype, lock_timeout,
8161 num_locks, locks,
8162 &async);
8163 if (!NT_STATUS_IS_OK(status)) {
8164 END_PROFILE(SMBlockingX);
8165 reply_nterror(req, status);
8166 return;
8168 if (async) {
8169 END_PROFILE(SMBlockingX);
8170 return;
8173 reply_outbuf(req, 2, 0);
8174 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8175 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8177 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8178 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8180 END_PROFILE(SMBlockingX);
8183 #undef DBGC_CLASS
8184 #define DBGC_CLASS DBGC_ALL
8186 /****************************************************************************
8187 Reply to a SMBreadbmpx (read block multiplex) request.
8188 Always reply with an error, if someone has a platform really needs this,
8189 please contact vl@samba.org
8190 ****************************************************************************/
8192 void reply_readbmpx(struct smb_request *req)
8194 START_PROFILE(SMBreadBmpx);
8195 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8196 END_PROFILE(SMBreadBmpx);
8197 return;
8200 /****************************************************************************
8201 Reply to a SMBreadbs (read block multiplex secondary) request.
8202 Always reply with an error, if someone has a platform really needs this,
8203 please contact vl@samba.org
8204 ****************************************************************************/
8206 void reply_readbs(struct smb_request *req)
8208 START_PROFILE(SMBreadBs);
8209 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8210 END_PROFILE(SMBreadBs);
8211 return;
8214 /****************************************************************************
8215 Reply to a SMBsetattrE.
8216 ****************************************************************************/
8218 void reply_setattrE(struct smb_request *req)
8220 connection_struct *conn = req->conn;
8221 struct smb_file_time ft;
8222 files_struct *fsp;
8223 NTSTATUS status;
8225 START_PROFILE(SMBsetattrE);
8226 ZERO_STRUCT(ft);
8228 if (req->wct < 7) {
8229 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8230 goto out;
8233 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8235 if(!fsp || (fsp->conn != conn)) {
8236 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8237 goto out;
8241 * Convert the DOS times into unix times.
8244 ft.atime = convert_time_t_to_timespec(
8245 srv_make_unix_date2(req->vwv+3));
8246 ft.mtime = convert_time_t_to_timespec(
8247 srv_make_unix_date2(req->vwv+5));
8248 ft.create_time = convert_time_t_to_timespec(
8249 srv_make_unix_date2(req->vwv+1));
8251 reply_outbuf(req, 0, 0);
8254 * Patch from Ray Frush <frush@engr.colostate.edu>
8255 * Sometimes times are sent as zero - ignore them.
8258 /* Ensure we have a valid stat struct for the source. */
8259 status = vfs_stat_fsp(fsp);
8260 if (!NT_STATUS_IS_OK(status)) {
8261 reply_nterror(req, status);
8262 goto out;
8265 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8266 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8267 goto out;
8270 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8271 if (!NT_STATUS_IS_OK(status)) {
8272 reply_nterror(req, status);
8273 goto out;
8276 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8277 " createtime=%u\n",
8278 fsp_fnum_dbg(fsp),
8279 (unsigned int)ft.atime.tv_sec,
8280 (unsigned int)ft.mtime.tv_sec,
8281 (unsigned int)ft.create_time.tv_sec
8283 out:
8284 END_PROFILE(SMBsetattrE);
8285 return;
8289 /* Back from the dead for OS/2..... JRA. */
8291 /****************************************************************************
8292 Reply to a SMBwritebmpx (write block multiplex primary) request.
8293 Always reply with an error, if someone has a platform really needs this,
8294 please contact vl@samba.org
8295 ****************************************************************************/
8297 void reply_writebmpx(struct smb_request *req)
8299 START_PROFILE(SMBwriteBmpx);
8300 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8301 END_PROFILE(SMBwriteBmpx);
8302 return;
8305 /****************************************************************************
8306 Reply to a SMBwritebs (write block multiplex secondary) request.
8307 Always reply with an error, if someone has a platform really needs this,
8308 please contact vl@samba.org
8309 ****************************************************************************/
8311 void reply_writebs(struct smb_request *req)
8313 START_PROFILE(SMBwriteBs);
8314 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8315 END_PROFILE(SMBwriteBs);
8316 return;
8319 /****************************************************************************
8320 Reply to a SMBgetattrE.
8321 ****************************************************************************/
8323 void reply_getattrE(struct smb_request *req)
8325 connection_struct *conn = req->conn;
8326 int mode;
8327 files_struct *fsp;
8328 struct timespec create_ts;
8330 START_PROFILE(SMBgetattrE);
8332 if (req->wct < 1) {
8333 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8334 END_PROFILE(SMBgetattrE);
8335 return;
8338 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8340 if(!fsp || (fsp->conn != conn)) {
8341 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8342 END_PROFILE(SMBgetattrE);
8343 return;
8346 /* Do an fstat on this file */
8347 if(fsp_stat(fsp)) {
8348 reply_nterror(req, map_nt_error_from_unix(errno));
8349 END_PROFILE(SMBgetattrE);
8350 return;
8353 mode = dos_mode(conn, fsp->fsp_name);
8356 * Convert the times into dos times. Set create
8357 * date to be last modify date as UNIX doesn't save
8358 * this.
8361 reply_outbuf(req, 11, 0);
8363 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8364 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8365 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8366 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8367 /* Should we check pending modtime here ? JRA */
8368 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8369 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8371 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8372 SIVAL(req->outbuf, smb_vwv6, 0);
8373 SIVAL(req->outbuf, smb_vwv8, 0);
8374 } else {
8375 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8376 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8377 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8379 SSVAL(req->outbuf,smb_vwv10, mode);
8381 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8383 END_PROFILE(SMBgetattrE);
8384 return;