s3:vfs: add create tags to SMB_VFS_CREATEFILE
[Samba.git] / source3 / smbd / reply.c
blobfd4ec53aed82441f94f673cc283eae7a24460d1d
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
47 /****************************************************************************
48 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
49 path or anything including wildcards.
50 We're assuming here that '/' is not the second byte in any multibyte char
51 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
52 set.
53 ****************************************************************************/
55 /* Custom version for processing POSIX paths. */
56 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
58 static NTSTATUS check_path_syntax_internal(char *path,
59 bool posix_path,
60 bool *p_last_component_contains_wcard)
62 char *d = path;
63 const char *s = path;
64 NTSTATUS ret = NT_STATUS_OK;
65 bool start_of_name_component = True;
66 bool stream_started = false;
68 *p_last_component_contains_wcard = False;
70 while (*s) {
71 if (stream_started) {
72 switch (*s) {
73 case '/':
74 case '\\':
75 return NT_STATUS_OBJECT_NAME_INVALID;
76 case ':':
77 if (s[1] == '\0') {
78 return NT_STATUS_OBJECT_NAME_INVALID;
80 if (strchr_m(&s[1], ':')) {
81 return NT_STATUS_OBJECT_NAME_INVALID;
83 break;
87 if ((*s == ':') && !posix_path && !stream_started) {
88 if (*p_last_component_contains_wcard) {
89 return NT_STATUS_OBJECT_NAME_INVALID;
91 /* Stream names allow more characters than file names.
92 We're overloading posix_path here to allow a wider
93 range of characters. If stream_started is true this
94 is still a Windows path even if posix_path is true.
95 JRA.
97 stream_started = true;
98 start_of_name_component = false;
99 posix_path = true;
101 if (s[1] == '\0') {
102 return NT_STATUS_OBJECT_NAME_INVALID;
106 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
108 * Safe to assume is not the second part of a mb char
109 * as this is handled below.
111 /* Eat multiple '/' or '\\' */
112 while (IS_PATH_SEP(*s,posix_path)) {
113 s++;
115 if ((d != path) && (*s != '\0')) {
116 /* We only care about non-leading or trailing '/' or '\\' */
117 *d++ = '/';
120 start_of_name_component = True;
121 /* New component. */
122 *p_last_component_contains_wcard = False;
123 continue;
126 if (start_of_name_component) {
127 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
128 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
131 * No mb char starts with '.' so we're safe checking the directory separator here.
134 /* If we just added a '/' - delete it */
135 if ((d > path) && (*(d-1) == '/')) {
136 *(d-1) = '\0';
137 d--;
140 /* Are we at the start ? Can't go back further if so. */
141 if (d <= path) {
142 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
143 break;
145 /* Go back one level... */
146 /* We know this is safe as '/' cannot be part of a mb sequence. */
147 /* NOTE - if this assumption is invalid we are not in good shape... */
148 /* Decrement d first as d points to the *next* char to write into. */
149 for (d--; d > path; d--) {
150 if (*d == '/')
151 break;
153 s += 2; /* Else go past the .. */
154 /* We're still at the start of a name component, just the previous one. */
155 continue;
157 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
158 if (posix_path) {
159 /* Eat the '.' */
160 s++;
161 continue;
167 if (!(*s & 0x80)) {
168 if (!posix_path) {
169 if (*s <= 0x1f || *s == '|') {
170 return NT_STATUS_OBJECT_NAME_INVALID;
172 switch (*s) {
173 case '*':
174 case '?':
175 case '<':
176 case '>':
177 case '"':
178 *p_last_component_contains_wcard = True;
179 break;
180 default:
181 break;
184 *d++ = *s++;
185 } else {
186 size_t siz;
187 /* Get the size of the next MB character. */
188 next_codepoint(s,&siz);
189 switch(siz) {
190 case 5:
191 *d++ = *s++;
192 /*fall through*/
193 case 4:
194 *d++ = *s++;
195 /*fall through*/
196 case 3:
197 *d++ = *s++;
198 /*fall through*/
199 case 2:
200 *d++ = *s++;
201 /*fall through*/
202 case 1:
203 *d++ = *s++;
204 break;
205 default:
206 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
207 *d = '\0';
208 return NT_STATUS_INVALID_PARAMETER;
211 start_of_name_component = False;
214 *d = '\0';
216 return ret;
219 /****************************************************************************
220 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
221 No wildcards allowed.
222 ****************************************************************************/
224 NTSTATUS check_path_syntax(char *path)
226 bool ignore;
227 return check_path_syntax_internal(path, False, &ignore);
230 /****************************************************************************
231 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
232 Wildcards allowed - p_contains_wcard returns true if the last component contained
233 a wildcard.
234 ****************************************************************************/
236 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
238 return check_path_syntax_internal(path, False, p_contains_wcard);
241 /****************************************************************************
242 Check the path for a POSIX client.
243 We're assuming here that '/' is not the second byte in any multibyte char
244 set (a safe assumption).
245 ****************************************************************************/
247 NTSTATUS check_path_syntax_posix(char *path)
249 bool ignore;
250 return check_path_syntax_internal(path, True, &ignore);
253 /****************************************************************************
254 Pull a string and check the path allowing a wilcard - provide for error return.
255 ****************************************************************************/
257 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
258 const char *base_ptr,
259 uint16 smb_flags2,
260 char **pp_dest,
261 const char *src,
262 size_t src_len,
263 int flags,
264 NTSTATUS *err,
265 bool *contains_wcard)
267 size_t ret;
269 *pp_dest = NULL;
271 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
272 src_len, flags);
274 if (!*pp_dest) {
275 *err = NT_STATUS_INVALID_PARAMETER;
276 return ret;
279 *contains_wcard = False;
281 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
283 * For a DFS path the function parse_dfs_path()
284 * will do the path processing, just make a copy.
286 *err = NT_STATUS_OK;
287 return ret;
290 if (lp_posix_pathnames()) {
291 *err = check_path_syntax_posix(*pp_dest);
292 } else {
293 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
296 return ret;
299 /****************************************************************************
300 Pull a string and check the path - provide for error return.
301 ****************************************************************************/
303 size_t srvstr_get_path(TALLOC_CTX *ctx,
304 const char *base_ptr,
305 uint16 smb_flags2,
306 char **pp_dest,
307 const char *src,
308 size_t src_len,
309 int flags,
310 NTSTATUS *err)
312 bool ignore;
313 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
314 src_len, flags, err, &ignore);
317 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
318 char **pp_dest, const char *src, int flags,
319 NTSTATUS *err, bool *contains_wcard)
321 ssize_t bufrem = smbreq_bufrem(req, src);
323 if (bufrem < 0) {
324 *err = NT_STATUS_INVALID_PARAMETER;
325 return 0;
328 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
329 req->flags2, pp_dest, src, bufrem, flags,
330 err, contains_wcard);
333 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
334 char **pp_dest, const char *src, int flags,
335 NTSTATUS *err)
337 bool ignore;
338 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
339 flags, err, &ignore);
343 * pull a string from the smb_buf part of a packet. In this case the
344 * string can either be null terminated or it can be terminated by the
345 * end of the smbbuf area
347 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
348 char **dest, const uint8_t *src, int flags)
350 ssize_t bufrem = smbreq_bufrem(req, src);
352 if (bufrem < 0) {
353 return 0;
356 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
357 bufrem, flags);
360 /****************************************************************************
361 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
362 ****************************************************************************/
364 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
365 files_struct *fsp)
367 if ((fsp == NULL) || (conn == NULL)) {
368 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
369 return False;
371 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
372 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
373 return False;
375 return True;
378 /****************************************************************************
379 Check if we have a correct fsp pointing to a file.
380 ****************************************************************************/
382 bool check_fsp(connection_struct *conn, struct smb_request *req,
383 files_struct *fsp)
385 if (!check_fsp_open(conn, req, fsp)) {
386 return False;
388 if (fsp->is_directory) {
389 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
390 return False;
392 if (fsp->fh->fd == -1) {
393 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
394 return False;
396 fsp->num_smb_operations++;
397 return True;
400 /****************************************************************************
401 Check if we have a correct fsp pointing to a quota fake file. Replacement for
402 the CHECK_NTQUOTA_HANDLE_OK macro.
403 ****************************************************************************/
405 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
406 files_struct *fsp)
408 if (!check_fsp_open(conn, req, fsp)) {
409 return false;
412 if (fsp->is_directory) {
413 return false;
416 if (fsp->fake_file_handle == NULL) {
417 return false;
420 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
421 return false;
424 if (fsp->fake_file_handle->private_data == NULL) {
425 return false;
428 return true;
431 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
432 const char *name, int name_type)
434 char *trim_name;
435 char *trim_name_type;
436 const char *retarget_parm;
437 char *retarget;
438 char *p;
439 int retarget_type = 0x20;
440 int retarget_port = NBT_SMB_PORT;
441 struct sockaddr_storage retarget_addr;
442 struct sockaddr_in *in_addr;
443 bool ret = false;
444 uint8_t outbuf[10];
446 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
447 return false;
450 trim_name = talloc_strdup(talloc_tos(), name);
451 if (trim_name == NULL) {
452 goto fail;
454 trim_char(trim_name, ' ', ' ');
456 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
457 name_type);
458 if (trim_name_type == NULL) {
459 goto fail;
462 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
463 trim_name_type, NULL);
464 if (retarget_parm == NULL) {
465 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
466 trim_name, NULL);
468 if (retarget_parm == NULL) {
469 goto fail;
472 retarget = talloc_strdup(trim_name, retarget_parm);
473 if (retarget == NULL) {
474 goto fail;
477 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
479 p = strchr(retarget, ':');
480 if (p != NULL) {
481 *p++ = '\0';
482 retarget_port = atoi(p);
485 p = strchr_m(retarget, '#');
486 if (p != NULL) {
487 *p++ = '\0';
488 if (sscanf(p, "%x", &retarget_type) != 1) {
489 goto fail;
493 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
494 if (!ret) {
495 DEBUG(10, ("could not resolve %s\n", retarget));
496 goto fail;
499 if (retarget_addr.ss_family != AF_INET) {
500 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
501 goto fail;
504 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
506 _smb_setlen(outbuf, 6);
507 SCVAL(outbuf, 0, 0x84);
508 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
509 *(uint16_t *)(outbuf+8) = htons(retarget_port);
511 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
512 NULL)) {
513 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
514 "failed.");
517 ret = true;
518 fail:
519 TALLOC_FREE(trim_name);
520 return ret;
523 static void reply_called_name_not_present(char *outbuf)
525 smb_setlen(outbuf, 1);
526 SCVAL(outbuf, 0, 0x83);
527 SCVAL(outbuf, 4, 0x82);
530 /****************************************************************************
531 Reply to a (netbios-level) special message.
532 ****************************************************************************/
534 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
536 struct smbd_server_connection *sconn = xconn->client->sconn;
537 int msg_type = CVAL(inbuf,0);
538 int msg_flags = CVAL(inbuf,1);
540 * We only really use 4 bytes of the outbuf, but for the smb_setlen
541 * calculation & friends (srv_send_smb uses that) we need the full smb
542 * header.
544 char outbuf[smb_size];
546 memset(outbuf, '\0', sizeof(outbuf));
548 smb_setlen(outbuf,0);
550 switch (msg_type) {
551 case NBSSrequest: /* session request */
553 /* inbuf_size is guarenteed to be at least 4. */
554 fstring name1,name2;
555 int name_type1, name_type2;
556 int name_len1, name_len2;
558 *name1 = *name2 = 0;
560 if (xconn->transport.nbt.got_session) {
561 exit_server_cleanly("multiple session request not permitted");
564 SCVAL(outbuf,0,NBSSpositive);
565 SCVAL(outbuf,3,0);
567 /* inbuf_size is guaranteed to be at least 4. */
568 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
569 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
570 DEBUG(0,("Invalid name length in session request\n"));
571 reply_called_name_not_present(outbuf);
572 break;
574 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
575 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
576 DEBUG(0,("Invalid name length in session request\n"));
577 reply_called_name_not_present(outbuf);
578 break;
581 name_type1 = name_extract((unsigned char *)inbuf,
582 inbuf_size,(unsigned int)4,name1);
583 name_type2 = name_extract((unsigned char *)inbuf,
584 inbuf_size,(unsigned int)(4 + name_len1),name2);
586 if (name_type1 == -1 || name_type2 == -1) {
587 DEBUG(0,("Invalid name type in session request\n"));
588 reply_called_name_not_present(outbuf);
589 break;
592 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
593 name1, name_type1, name2, name_type2));
595 if (netbios_session_retarget(xconn, name1, name_type1)) {
596 exit_server_cleanly("retargeted client");
600 * Windows NT/2k uses "*SMBSERVER" and XP uses
601 * "*SMBSERV" arrggg!!!
603 if (strequal(name1, "*SMBSERVER ")
604 || strequal(name1, "*SMBSERV ")) {
605 char *raddr;
607 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
608 talloc_tos());
609 if (raddr == NULL) {
610 exit_server_cleanly("could not allocate raddr");
613 fstrcpy(name1, raddr);
616 set_local_machine_name(name1, True);
617 set_remote_machine_name(name2, True);
619 if (is_ipaddress(sconn->remote_hostname)) {
620 char *p = discard_const_p(char, sconn->remote_hostname);
622 talloc_free(p);
624 sconn->remote_hostname = talloc_strdup(sconn,
625 get_remote_machine_name());
626 if (sconn->remote_hostname == NULL) {
627 exit_server_cleanly("could not copy remote name");
629 xconn->remote_hostname = sconn->remote_hostname;
632 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
633 get_local_machine_name(), get_remote_machine_name(),
634 name_type2));
636 if (name_type2 == 'R') {
637 /* We are being asked for a pathworks session ---
638 no thanks! */
639 reply_called_name_not_present(outbuf);
640 break;
643 reload_services(sconn, conn_snum_used, true);
644 reopen_logs();
646 xconn->transport.nbt.got_session = true;
647 break;
650 case 0x89: /* session keepalive request
651 (some old clients produce this?) */
652 SCVAL(outbuf,0,NBSSkeepalive);
653 SCVAL(outbuf,3,0);
654 break;
656 case NBSSpositive: /* positive session response */
657 case NBSSnegative: /* negative session response */
658 case NBSSretarget: /* retarget session response */
659 DEBUG(0,("Unexpected session response\n"));
660 break;
662 case NBSSkeepalive: /* session keepalive */
663 default:
664 return;
667 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
668 msg_type, msg_flags));
670 srv_send_smb(xconn, outbuf, false, 0, false, NULL);
672 if (CVAL(outbuf, 0) != 0x82) {
673 exit_server_cleanly("invalid netbios session");
675 return;
678 /****************************************************************************
679 Reply to a tcon.
680 conn POINTER CAN BE NULL HERE !
681 ****************************************************************************/
683 void reply_tcon(struct smb_request *req)
685 connection_struct *conn = req->conn;
686 const char *service;
687 char *service_buf = NULL;
688 char *password = NULL;
689 char *dev = NULL;
690 int pwlen=0;
691 NTSTATUS nt_status;
692 const uint8_t *p;
693 const char *p2;
694 TALLOC_CTX *ctx = talloc_tos();
695 struct smbXsrv_connection *xconn = req->xconn;
696 NTTIME now = timeval_to_nttime(&req->request_time);
698 START_PROFILE(SMBtcon);
700 if (req->buflen < 4) {
701 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
702 END_PROFILE(SMBtcon);
703 return;
706 p = req->buf + 1;
707 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
708 p += 1;
709 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
710 p += pwlen+1;
711 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
712 p += 1;
714 if (service_buf == NULL || password == NULL || dev == NULL) {
715 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
716 END_PROFILE(SMBtcon);
717 return;
719 p2 = strrchr_m(service_buf,'\\');
720 if (p2) {
721 service = p2+1;
722 } else {
723 service = service_buf;
726 conn = make_connection(req, now, service, dev,
727 req->vuid,&nt_status);
728 req->conn = conn;
730 if (!conn) {
731 reply_nterror(req, nt_status);
732 END_PROFILE(SMBtcon);
733 return;
736 reply_outbuf(req, 2, 0);
737 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
738 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
739 SSVAL(req->outbuf,smb_tid,conn->cnum);
741 DEBUG(3,("tcon service=%s cnum=%d\n",
742 service, conn->cnum));
744 END_PROFILE(SMBtcon);
745 return;
748 /****************************************************************************
749 Reply to a tcon and X.
750 conn POINTER CAN BE NULL HERE !
751 ****************************************************************************/
753 void reply_tcon_and_X(struct smb_request *req)
755 connection_struct *conn = req->conn;
756 const char *service = NULL;
757 TALLOC_CTX *ctx = talloc_tos();
758 /* what the cleint thinks the device is */
759 char *client_devicetype = NULL;
760 /* what the server tells the client the share represents */
761 const char *server_devicetype;
762 NTSTATUS nt_status;
763 int passlen;
764 char *path = NULL;
765 const uint8_t *p;
766 const char *q;
767 uint16_t tcon_flags;
768 struct smbXsrv_session *session = NULL;
769 NTTIME now = timeval_to_nttime(&req->request_time);
770 bool session_key_updated = false;
771 uint16_t optional_support = 0;
772 struct smbXsrv_connection *xconn = req->xconn;
774 START_PROFILE(SMBtconX);
776 if (req->wct < 4) {
777 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
778 END_PROFILE(SMBtconX);
779 return;
782 passlen = SVAL(req->vwv+3, 0);
783 tcon_flags = SVAL(req->vwv+2, 0);
785 /* we might have to close an old one */
786 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
787 struct smbXsrv_tcon *tcon;
788 NTSTATUS status;
790 tcon = conn->tcon;
791 req->conn = NULL;
792 conn = NULL;
795 * TODO: cancel all outstanding requests on the tcon
797 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
798 if (!NT_STATUS_IS_OK(status)) {
799 DEBUG(0, ("reply_tcon_and_X: "
800 "smbXsrv_tcon_disconnect() failed: %s\n",
801 nt_errstr(status)));
803 * If we hit this case, there is something completely
804 * wrong, so we better disconnect the transport connection.
806 END_PROFILE(SMBtconX);
807 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
808 return;
811 TALLOC_FREE(tcon);
814 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
815 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
816 END_PROFILE(SMBtconX);
817 return;
820 if (xconn->smb1.negprot.encrypted_passwords) {
821 p = req->buf + passlen;
822 } else {
823 p = req->buf + passlen + 1;
826 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
828 if (path == NULL) {
829 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
830 END_PROFILE(SMBtconX);
831 return;
835 * the service name can be either: \\server\share
836 * or share directly like on the DELL PowerVault 705
838 if (*path=='\\') {
839 q = strchr_m(path+2,'\\');
840 if (!q) {
841 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
842 END_PROFILE(SMBtconX);
843 return;
845 service = q+1;
846 } else {
847 service = path;
850 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
851 &client_devicetype, p,
852 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
854 if (client_devicetype == NULL) {
855 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
856 END_PROFILE(SMBtconX);
857 return;
860 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
862 nt_status = smb1srv_session_lookup(xconn,
863 req->vuid, now, &session);
864 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
865 reply_force_doserror(req, ERRSRV, ERRbaduid);
866 END_PROFILE(SMBtconX);
867 return;
869 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
870 reply_nterror(req, nt_status);
871 END_PROFILE(SMBtconX);
872 return;
874 if (!NT_STATUS_IS_OK(nt_status)) {
875 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
876 END_PROFILE(SMBtconX);
877 return;
880 if (session->global->auth_session_info == NULL) {
881 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
882 END_PROFILE(SMBtconX);
883 return;
887 * If there is no application key defined yet
888 * we create one.
890 * This means we setup the application key on the
891 * first tcon that happens via the given session.
893 * Once the application key is defined, it does not
894 * change any more.
896 if (session->global->application_key.length == 0 &&
897 session->global->signing_key.length > 0)
899 struct smbXsrv_session *x = session;
900 struct auth_session_info *session_info =
901 session->global->auth_session_info;
902 uint8_t session_key[16];
904 ZERO_STRUCT(session_key);
905 memcpy(session_key, x->global->signing_key.data,
906 MIN(x->global->signing_key.length, sizeof(session_key)));
909 * The application key is truncated/padded to 16 bytes
911 x->global->application_key = data_blob_talloc(x->global,
912 session_key,
913 sizeof(session_key));
914 ZERO_STRUCT(session_key);
915 if (x->global->application_key.data == NULL) {
916 reply_nterror(req, NT_STATUS_NO_MEMORY);
917 END_PROFILE(SMBtconX);
918 return;
921 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
922 smb_key_derivation(x->global->application_key.data,
923 x->global->application_key.length,
924 x->global->application_key.data);
925 optional_support |= SMB_EXTENDED_SIGNATURES;
929 * Place the application key into the session_info
931 data_blob_clear_free(&session_info->session_key);
932 session_info->session_key = data_blob_dup_talloc(session_info,
933 x->global->application_key);
934 if (session_info->session_key.data == NULL) {
935 data_blob_clear_free(&x->global->application_key);
936 reply_nterror(req, NT_STATUS_NO_MEMORY);
937 END_PROFILE(SMBtconX);
938 return;
940 session_key_updated = true;
943 conn = make_connection(req, now, service, client_devicetype,
944 req->vuid, &nt_status);
945 req->conn =conn;
947 if (!conn) {
948 if (session_key_updated) {
949 struct smbXsrv_session *x = session;
950 struct auth_session_info *session_info =
951 session->global->auth_session_info;
952 data_blob_clear_free(&x->global->application_key);
953 data_blob_clear_free(&session_info->session_key);
955 reply_nterror(req, nt_status);
956 END_PROFILE(SMBtconX);
957 return;
960 if ( IS_IPC(conn) )
961 server_devicetype = "IPC";
962 else if ( IS_PRINT(conn) )
963 server_devicetype = "LPT1:";
964 else
965 server_devicetype = "A:";
967 if (get_Protocol() < PROTOCOL_NT1) {
968 reply_outbuf(req, 2, 0);
969 if (message_push_string(&req->outbuf, server_devicetype,
970 STR_TERMINATE|STR_ASCII) == -1) {
971 reply_nterror(req, NT_STATUS_NO_MEMORY);
972 END_PROFILE(SMBtconX);
973 return;
975 } else {
976 /* NT sets the fstype of IPC$ to the null string */
977 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
979 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
980 /* Return permissions. */
981 uint32 perm1 = 0;
982 uint32 perm2 = 0;
984 reply_outbuf(req, 7, 0);
986 if (IS_IPC(conn)) {
987 perm1 = FILE_ALL_ACCESS;
988 perm2 = FILE_ALL_ACCESS;
989 } else {
990 perm1 = conn->share_access;
993 SIVAL(req->outbuf, smb_vwv3, perm1);
994 SIVAL(req->outbuf, smb_vwv5, perm2);
995 } else {
996 reply_outbuf(req, 3, 0);
999 if ((message_push_string(&req->outbuf, server_devicetype,
1000 STR_TERMINATE|STR_ASCII) == -1)
1001 || (message_push_string(&req->outbuf, fstype,
1002 STR_TERMINATE) == -1)) {
1003 reply_nterror(req, NT_STATUS_NO_MEMORY);
1004 END_PROFILE(SMBtconX);
1005 return;
1008 /* what does setting this bit do? It is set by NT4 and
1009 may affect the ability to autorun mounted cdroms */
1010 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1011 optional_support |=
1012 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1014 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1015 DEBUG(2,("Serving %s as a Dfs root\n",
1016 lp_servicename(ctx, SNUM(conn)) ));
1017 optional_support |= SMB_SHARE_IN_DFS;
1020 SSVAL(req->outbuf, smb_vwv2, optional_support);
1023 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1024 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1026 DEBUG(3,("tconX service=%s \n",
1027 service));
1029 /* set the incoming and outgoing tid to the just created one */
1030 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1031 SSVAL(req->outbuf,smb_tid,conn->cnum);
1033 END_PROFILE(SMBtconX);
1035 req->tid = conn->cnum;
1038 /****************************************************************************
1039 Reply to an unknown type.
1040 ****************************************************************************/
1042 void reply_unknown_new(struct smb_request *req, uint8 type)
1044 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1045 smb_fn_name(type), type, type));
1046 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1047 return;
1050 /****************************************************************************
1051 Reply to an ioctl.
1052 conn POINTER CAN BE NULL HERE !
1053 ****************************************************************************/
1055 void reply_ioctl(struct smb_request *req)
1057 connection_struct *conn = req->conn;
1058 uint16 device;
1059 uint16 function;
1060 uint32 ioctl_code;
1061 int replysize;
1062 char *p;
1064 START_PROFILE(SMBioctl);
1066 if (req->wct < 3) {
1067 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1068 END_PROFILE(SMBioctl);
1069 return;
1072 device = SVAL(req->vwv+1, 0);
1073 function = SVAL(req->vwv+2, 0);
1074 ioctl_code = (device << 16) + function;
1076 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1078 switch (ioctl_code) {
1079 case IOCTL_QUERY_JOB_INFO:
1080 replysize = 32;
1081 break;
1082 default:
1083 reply_force_doserror(req, ERRSRV, ERRnosupport);
1084 END_PROFILE(SMBioctl);
1085 return;
1088 reply_outbuf(req, 8, replysize+1);
1089 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1090 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1091 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1092 p = smb_buf(req->outbuf);
1093 memset(p, '\0', replysize+1); /* valgrind-safe. */
1094 p += 1; /* Allow for alignment */
1096 switch (ioctl_code) {
1097 case IOCTL_QUERY_JOB_INFO:
1099 NTSTATUS status;
1100 size_t len = 0;
1101 files_struct *fsp = file_fsp(
1102 req, SVAL(req->vwv+0, 0));
1103 if (!fsp) {
1104 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1105 END_PROFILE(SMBioctl);
1106 return;
1108 /* Job number */
1109 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1111 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1112 lp_netbios_name(), 15,
1113 STR_TERMINATE|STR_ASCII, &len);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 reply_nterror(req, status);
1116 END_PROFILE(SMBioctl);
1117 return;
1119 if (conn) {
1120 status = srvstr_push((char *)req->outbuf, req->flags2,
1121 p+18,
1122 lp_servicename(talloc_tos(),
1123 SNUM(conn)),
1124 13, STR_TERMINATE|STR_ASCII, &len);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 reply_nterror(req, status);
1127 END_PROFILE(SMBioctl);
1128 return;
1130 } else {
1131 memset(p+18, 0, 13);
1133 break;
1137 END_PROFILE(SMBioctl);
1138 return;
1141 /****************************************************************************
1142 Strange checkpath NTSTATUS mapping.
1143 ****************************************************************************/
1145 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1147 /* Strange DOS error code semantics only for checkpath... */
1148 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1149 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1150 /* We need to map to ERRbadpath */
1151 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1154 return status;
1157 /****************************************************************************
1158 Reply to a checkpath.
1159 ****************************************************************************/
1161 void reply_checkpath(struct smb_request *req)
1163 connection_struct *conn = req->conn;
1164 struct smb_filename *smb_fname = NULL;
1165 char *name = NULL;
1166 NTSTATUS status;
1167 TALLOC_CTX *ctx = talloc_tos();
1169 START_PROFILE(SMBcheckpath);
1171 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1172 STR_TERMINATE, &status);
1174 if (!NT_STATUS_IS_OK(status)) {
1175 status = map_checkpath_error(req->flags2, status);
1176 reply_nterror(req, status);
1177 END_PROFILE(SMBcheckpath);
1178 return;
1181 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1183 status = filename_convert(ctx,
1184 conn,
1185 req->flags2 & FLAGS2_DFS_PATHNAMES,
1186 name,
1188 NULL,
1189 &smb_fname);
1191 if (!NT_STATUS_IS_OK(status)) {
1192 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1193 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1194 ERRSRV, ERRbadpath);
1195 END_PROFILE(SMBcheckpath);
1196 return;
1198 goto path_err;
1201 if (!VALID_STAT(smb_fname->st) &&
1202 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1203 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1204 smb_fname_str_dbg(smb_fname), strerror(errno)));
1205 status = map_nt_error_from_unix(errno);
1206 goto path_err;
1209 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1210 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1211 ERRDOS, ERRbadpath);
1212 goto out;
1215 reply_outbuf(req, 0, 0);
1217 path_err:
1218 /* We special case this - as when a Windows machine
1219 is parsing a path is steps through the components
1220 one at a time - if a component fails it expects
1221 ERRbadpath, not ERRbadfile.
1223 status = map_checkpath_error(req->flags2, status);
1224 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1226 * Windows returns different error codes if
1227 * the parent directory is valid but not the
1228 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1229 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1230 * if the path is invalid.
1232 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1233 ERRDOS, ERRbadpath);
1234 goto out;
1237 reply_nterror(req, status);
1239 out:
1240 TALLOC_FREE(smb_fname);
1241 END_PROFILE(SMBcheckpath);
1242 return;
1245 /****************************************************************************
1246 Reply to a getatr.
1247 ****************************************************************************/
1249 void reply_getatr(struct smb_request *req)
1251 connection_struct *conn = req->conn;
1252 struct smb_filename *smb_fname = NULL;
1253 char *fname = NULL;
1254 int mode=0;
1255 off_t size=0;
1256 time_t mtime=0;
1257 const char *p;
1258 NTSTATUS status;
1259 TALLOC_CTX *ctx = talloc_tos();
1260 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1262 START_PROFILE(SMBgetatr);
1264 p = (const char *)req->buf + 1;
1265 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1266 if (!NT_STATUS_IS_OK(status)) {
1267 reply_nterror(req, status);
1268 goto out;
1271 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1272 under WfWg - weird! */
1273 if (*fname == '\0') {
1274 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1275 if (!CAN_WRITE(conn)) {
1276 mode |= FILE_ATTRIBUTE_READONLY;
1278 size = 0;
1279 mtime = 0;
1280 } else {
1281 status = filename_convert(ctx,
1282 conn,
1283 req->flags2 & FLAGS2_DFS_PATHNAMES,
1284 fname,
1286 NULL,
1287 &smb_fname);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1290 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1291 ERRSRV, ERRbadpath);
1292 goto out;
1294 reply_nterror(req, status);
1295 goto out;
1297 if (!VALID_STAT(smb_fname->st) &&
1298 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1299 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1300 smb_fname_str_dbg(smb_fname),
1301 strerror(errno)));
1302 reply_nterror(req, map_nt_error_from_unix(errno));
1303 goto out;
1306 mode = dos_mode(conn, smb_fname);
1307 size = smb_fname->st.st_ex_size;
1309 if (ask_sharemode) {
1310 struct timespec write_time_ts;
1311 struct file_id fileid;
1313 ZERO_STRUCT(write_time_ts);
1314 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1315 get_file_infos(fileid, 0, NULL, &write_time_ts);
1316 if (!null_timespec(write_time_ts)) {
1317 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1321 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1322 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1323 size = 0;
1327 reply_outbuf(req, 10, 0);
1329 SSVAL(req->outbuf,smb_vwv0,mode);
1330 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1331 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1332 } else {
1333 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1335 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1337 if (get_Protocol() >= PROTOCOL_NT1) {
1338 SSVAL(req->outbuf, smb_flg2,
1339 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1342 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1343 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1345 out:
1346 TALLOC_FREE(smb_fname);
1347 TALLOC_FREE(fname);
1348 END_PROFILE(SMBgetatr);
1349 return;
1352 /****************************************************************************
1353 Reply to a setatr.
1354 ****************************************************************************/
1356 void reply_setatr(struct smb_request *req)
1358 struct smb_file_time ft;
1359 connection_struct *conn = req->conn;
1360 struct smb_filename *smb_fname = NULL;
1361 char *fname = NULL;
1362 int mode;
1363 time_t mtime;
1364 const char *p;
1365 NTSTATUS status;
1366 TALLOC_CTX *ctx = talloc_tos();
1368 START_PROFILE(SMBsetatr);
1370 ZERO_STRUCT(ft);
1372 if (req->wct < 2) {
1373 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1374 goto out;
1377 p = (const char *)req->buf + 1;
1378 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 reply_nterror(req, status);
1381 goto out;
1384 status = filename_convert(ctx,
1385 conn,
1386 req->flags2 & FLAGS2_DFS_PATHNAMES,
1387 fname,
1389 NULL,
1390 &smb_fname);
1391 if (!NT_STATUS_IS_OK(status)) {
1392 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1393 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1394 ERRSRV, ERRbadpath);
1395 goto out;
1397 reply_nterror(req, status);
1398 goto out;
1401 if (smb_fname->base_name[0] == '.' &&
1402 smb_fname->base_name[1] == '\0') {
1404 * Not sure here is the right place to catch this
1405 * condition. Might be moved to somewhere else later -- vl
1407 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1408 goto out;
1411 mode = SVAL(req->vwv+0, 0);
1412 mtime = srv_make_unix_date3(req->vwv+1);
1414 if (mode != FILE_ATTRIBUTE_NORMAL) {
1415 if (VALID_STAT_OF_DIR(smb_fname->st))
1416 mode |= FILE_ATTRIBUTE_DIRECTORY;
1417 else
1418 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1420 status = check_access(conn, NULL, smb_fname,
1421 FILE_WRITE_ATTRIBUTES);
1422 if (!NT_STATUS_IS_OK(status)) {
1423 reply_nterror(req, status);
1424 goto out;
1427 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1428 false) != 0) {
1429 reply_nterror(req, map_nt_error_from_unix(errno));
1430 goto out;
1434 ft.mtime = convert_time_t_to_timespec(mtime);
1435 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1436 if (!NT_STATUS_IS_OK(status)) {
1437 reply_nterror(req, status);
1438 goto out;
1441 reply_outbuf(req, 0, 0);
1443 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1444 mode));
1445 out:
1446 TALLOC_FREE(smb_fname);
1447 END_PROFILE(SMBsetatr);
1448 return;
1451 /****************************************************************************
1452 Reply to a dskattr.
1453 ****************************************************************************/
1455 void reply_dskattr(struct smb_request *req)
1457 connection_struct *conn = req->conn;
1458 uint64_t dfree,dsize,bsize;
1459 START_PROFILE(SMBdskattr);
1461 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1462 reply_nterror(req, map_nt_error_from_unix(errno));
1463 END_PROFILE(SMBdskattr);
1464 return;
1467 reply_outbuf(req, 5, 0);
1469 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1470 double total_space, free_space;
1471 /* we need to scale this to a number that DOS6 can handle. We
1472 use floating point so we can handle large drives on systems
1473 that don't have 64 bit integers
1475 we end up displaying a maximum of 2G to DOS systems
1477 total_space = dsize * (double)bsize;
1478 free_space = dfree * (double)bsize;
1480 dsize = (uint64_t)((total_space+63*512) / (64*512));
1481 dfree = (uint64_t)((free_space+63*512) / (64*512));
1483 if (dsize > 0xFFFF) dsize = 0xFFFF;
1484 if (dfree > 0xFFFF) dfree = 0xFFFF;
1486 SSVAL(req->outbuf,smb_vwv0,dsize);
1487 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1488 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1489 SSVAL(req->outbuf,smb_vwv3,dfree);
1490 } else {
1491 SSVAL(req->outbuf,smb_vwv0,dsize);
1492 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1493 SSVAL(req->outbuf,smb_vwv2,512);
1494 SSVAL(req->outbuf,smb_vwv3,dfree);
1497 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1499 END_PROFILE(SMBdskattr);
1500 return;
1504 * Utility function to split the filename from the directory.
1506 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1507 char **fname_dir_out,
1508 char **fname_mask_out)
1510 const char *p = NULL;
1511 char *fname_dir = NULL;
1512 char *fname_mask = NULL;
1514 p = strrchr_m(fname_in, '/');
1515 if (!p) {
1516 fname_dir = talloc_strdup(ctx, ".");
1517 fname_mask = talloc_strdup(ctx, fname_in);
1518 } else {
1519 fname_dir = talloc_strndup(ctx, fname_in,
1520 PTR_DIFF(p, fname_in));
1521 fname_mask = talloc_strdup(ctx, p+1);
1524 if (!fname_dir || !fname_mask) {
1525 TALLOC_FREE(fname_dir);
1526 TALLOC_FREE(fname_mask);
1527 return NT_STATUS_NO_MEMORY;
1530 *fname_dir_out = fname_dir;
1531 *fname_mask_out = fname_mask;
1532 return NT_STATUS_OK;
1535 /****************************************************************************
1536 Make a dir struct.
1537 ****************************************************************************/
1539 static bool make_dir_struct(TALLOC_CTX *ctx,
1540 char *buf,
1541 const char *mask,
1542 const char *fname,
1543 off_t size,
1544 uint32 mode,
1545 time_t date,
1546 bool uc)
1548 char *p;
1549 char *mask2 = talloc_strdup(ctx, mask);
1551 if (!mask2) {
1552 return False;
1555 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1556 size = 0;
1559 memset(buf+1,' ',11);
1560 if ((p = strchr_m(mask2,'.')) != NULL) {
1561 *p = 0;
1562 push_ascii(buf+1,mask2,8, 0);
1563 push_ascii(buf+9,p+1,3, 0);
1564 *p = '.';
1565 } else {
1566 push_ascii(buf+1,mask2,11, 0);
1569 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1570 SCVAL(buf,21,mode);
1571 srv_put_dos_date(buf,22,date);
1572 SSVAL(buf,26,size & 0xFFFF);
1573 SSVAL(buf,28,(size >> 16)&0xFFFF);
1574 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1575 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1576 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1577 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1578 return True;
1581 /****************************************************************************
1582 Reply to a search.
1583 Can be called from SMBsearch, SMBffirst or SMBfunique.
1584 ****************************************************************************/
1586 void reply_search(struct smb_request *req)
1588 connection_struct *conn = req->conn;
1589 char *path = NULL;
1590 const char *mask = NULL;
1591 char *directory = NULL;
1592 struct smb_filename *smb_fname = NULL;
1593 char *fname = NULL;
1594 off_t size;
1595 uint32 mode;
1596 struct timespec date;
1597 uint32 dirtype;
1598 unsigned int numentries = 0;
1599 unsigned int maxentries = 0;
1600 bool finished = False;
1601 const char *p;
1602 int status_len;
1603 char status[21];
1604 int dptr_num= -1;
1605 bool check_descend = False;
1606 bool expect_close = False;
1607 NTSTATUS nt_status;
1608 bool mask_contains_wcard = False;
1609 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1610 TALLOC_CTX *ctx = talloc_tos();
1611 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1612 struct dptr_struct *dirptr = NULL;
1613 struct smbXsrv_connection *xconn = req->xconn;
1614 struct smbd_server_connection *sconn = req->sconn;
1616 START_PROFILE(SMBsearch);
1618 if (req->wct < 2) {
1619 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1620 goto out;
1623 if (lp_posix_pathnames()) {
1624 reply_unknown_new(req, req->cmd);
1625 goto out;
1628 /* If we were called as SMBffirst then we must expect close. */
1629 if(req->cmd == SMBffirst) {
1630 expect_close = True;
1633 reply_outbuf(req, 1, 3);
1634 maxentries = SVAL(req->vwv+0, 0);
1635 dirtype = SVAL(req->vwv+1, 0);
1636 p = (const char *)req->buf + 1;
1637 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1638 &nt_status, &mask_contains_wcard);
1639 if (!NT_STATUS_IS_OK(nt_status)) {
1640 reply_nterror(req, nt_status);
1641 goto out;
1644 p++;
1645 status_len = SVAL(p, 0);
1646 p += 2;
1648 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1650 if (status_len == 0) {
1651 nt_status = filename_convert(ctx, conn,
1652 req->flags2 & FLAGS2_DFS_PATHNAMES,
1653 path,
1654 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1655 &mask_contains_wcard,
1656 &smb_fname);
1657 if (!NT_STATUS_IS_OK(nt_status)) {
1658 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1659 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1660 ERRSRV, ERRbadpath);
1661 goto out;
1663 reply_nterror(req, nt_status);
1664 goto out;
1667 directory = smb_fname->base_name;
1669 p = strrchr_m(directory,'/');
1670 if ((p != NULL) && (*directory != '/')) {
1671 mask = p + 1;
1672 directory = talloc_strndup(ctx, directory,
1673 PTR_DIFF(p, directory));
1674 } else {
1675 mask = directory;
1676 directory = talloc_strdup(ctx,".");
1679 if (!directory) {
1680 reply_nterror(req, NT_STATUS_NO_MEMORY);
1681 goto out;
1684 memset((char *)status,'\0',21);
1685 SCVAL(status,0,(dirtype & 0x1F));
1687 nt_status = dptr_create(conn,
1688 NULL, /* req */
1689 NULL, /* fsp */
1690 directory,
1691 True,
1692 expect_close,
1693 req->smbpid,
1694 mask,
1695 mask_contains_wcard,
1696 dirtype,
1697 &dirptr);
1698 if (!NT_STATUS_IS_OK(nt_status)) {
1699 reply_nterror(req, nt_status);
1700 goto out;
1702 dptr_num = dptr_dnum(dirptr);
1703 } else {
1704 int status_dirtype;
1705 const char *dirpath;
1707 memcpy(status,p,21);
1708 status_dirtype = CVAL(status,0) & 0x1F;
1709 if (status_dirtype != (dirtype & 0x1F)) {
1710 dirtype = status_dirtype;
1713 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1714 if (!dirptr) {
1715 goto SearchEmpty;
1717 dirpath = dptr_path(sconn, dptr_num);
1718 directory = talloc_strdup(ctx, dirpath);
1719 if (!directory) {
1720 reply_nterror(req, NT_STATUS_NO_MEMORY);
1721 goto out;
1724 mask = dptr_wcard(sconn, dptr_num);
1725 if (!mask) {
1726 goto SearchEmpty;
1729 * For a 'continue' search we have no string. So
1730 * check from the initial saved string.
1732 mask_contains_wcard = ms_has_wild(mask);
1733 dirtype = dptr_attr(sconn, dptr_num);
1736 DEBUG(4,("dptr_num is %d\n",dptr_num));
1738 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1739 dptr_init_search_op(dirptr);
1741 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1742 char buf[DIR_STRUCT_SIZE];
1743 memcpy(buf,status,21);
1744 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1745 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1746 reply_nterror(req, NT_STATUS_NO_MEMORY);
1747 goto out;
1749 dptr_fill(sconn, buf+12,dptr_num);
1750 if (dptr_zero(buf+12) && (status_len==0)) {
1751 numentries = 1;
1752 } else {
1753 numentries = 0;
1755 if (message_push_blob(&req->outbuf,
1756 data_blob_const(buf, sizeof(buf)))
1757 == -1) {
1758 reply_nterror(req, NT_STATUS_NO_MEMORY);
1759 goto out;
1761 } else {
1762 unsigned int i;
1763 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1764 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1766 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1768 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1769 directory,lp_dont_descend(ctx, SNUM(conn))));
1770 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1771 check_descend = True;
1774 for (i=numentries;(i<maxentries) && !finished;i++) {
1775 finished = !get_dir_entry(ctx,
1776 dirptr,
1777 mask,
1778 dirtype,
1779 &fname,
1780 &size,
1781 &mode,
1782 &date,
1783 check_descend,
1784 ask_sharemode);
1785 if (!finished) {
1786 char buf[DIR_STRUCT_SIZE];
1787 memcpy(buf,status,21);
1788 if (!make_dir_struct(ctx,
1789 buf,
1790 mask,
1791 fname,
1792 size,
1793 mode,
1794 convert_timespec_to_time_t(date),
1795 !allow_long_path_components)) {
1796 reply_nterror(req, NT_STATUS_NO_MEMORY);
1797 goto out;
1799 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1800 break;
1802 if (message_push_blob(&req->outbuf,
1803 data_blob_const(buf, sizeof(buf)))
1804 == -1) {
1805 reply_nterror(req, NT_STATUS_NO_MEMORY);
1806 goto out;
1808 numentries++;
1813 SearchEmpty:
1815 /* If we were called as SMBffirst with smb_search_id == NULL
1816 and no entries were found then return error and close dirptr
1817 (X/Open spec) */
1819 if (numentries == 0) {
1820 dptr_close(sconn, &dptr_num);
1821 } else if(expect_close && status_len == 0) {
1822 /* Close the dptr - we know it's gone */
1823 dptr_close(sconn, &dptr_num);
1826 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1827 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1828 dptr_close(sconn, &dptr_num);
1831 if ((numentries == 0) && !mask_contains_wcard) {
1832 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1833 goto out;
1836 SSVAL(req->outbuf,smb_vwv0,numentries);
1837 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1838 SCVAL(smb_buf(req->outbuf),0,5);
1839 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1841 /* The replies here are never long name. */
1842 SSVAL(req->outbuf, smb_flg2,
1843 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1844 if (!allow_long_path_components) {
1845 SSVAL(req->outbuf, smb_flg2,
1846 SVAL(req->outbuf, smb_flg2)
1847 & (~FLAGS2_LONG_PATH_COMPONENTS));
1850 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1851 SSVAL(req->outbuf, smb_flg2,
1852 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1854 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1855 smb_fn_name(req->cmd),
1856 mask,
1857 directory,
1858 dirtype,
1859 numentries,
1860 maxentries ));
1861 out:
1862 TALLOC_FREE(directory);
1863 TALLOC_FREE(smb_fname);
1864 END_PROFILE(SMBsearch);
1865 return;
1868 /****************************************************************************
1869 Reply to a fclose (stop directory search).
1870 ****************************************************************************/
1872 void reply_fclose(struct smb_request *req)
1874 int status_len;
1875 char status[21];
1876 int dptr_num= -2;
1877 const char *p;
1878 char *path = NULL;
1879 NTSTATUS err;
1880 bool path_contains_wcard = False;
1881 TALLOC_CTX *ctx = talloc_tos();
1882 struct smbd_server_connection *sconn = req->sconn;
1884 START_PROFILE(SMBfclose);
1886 if (lp_posix_pathnames()) {
1887 reply_unknown_new(req, req->cmd);
1888 END_PROFILE(SMBfclose);
1889 return;
1892 p = (const char *)req->buf + 1;
1893 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1894 &err, &path_contains_wcard);
1895 if (!NT_STATUS_IS_OK(err)) {
1896 reply_nterror(req, err);
1897 END_PROFILE(SMBfclose);
1898 return;
1900 p++;
1901 status_len = SVAL(p,0);
1902 p += 2;
1904 if (status_len == 0) {
1905 reply_force_doserror(req, ERRSRV, ERRsrverror);
1906 END_PROFILE(SMBfclose);
1907 return;
1910 memcpy(status,p,21);
1912 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1913 /* Close the dptr - we know it's gone */
1914 dptr_close(sconn, &dptr_num);
1917 reply_outbuf(req, 1, 0);
1918 SSVAL(req->outbuf,smb_vwv0,0);
1920 DEBUG(3,("search close\n"));
1922 END_PROFILE(SMBfclose);
1923 return;
1926 /****************************************************************************
1927 Reply to an open.
1928 ****************************************************************************/
1930 void reply_open(struct smb_request *req)
1932 connection_struct *conn = req->conn;
1933 struct smb_filename *smb_fname = NULL;
1934 char *fname = NULL;
1935 uint32 fattr=0;
1936 off_t size = 0;
1937 time_t mtime=0;
1938 int info;
1939 files_struct *fsp;
1940 int oplock_request;
1941 int deny_mode;
1942 uint32 dos_attr;
1943 uint32 access_mask;
1944 uint32 share_mode;
1945 uint32 create_disposition;
1946 uint32 create_options = 0;
1947 uint32_t private_flags = 0;
1948 NTSTATUS status;
1949 TALLOC_CTX *ctx = talloc_tos();
1951 START_PROFILE(SMBopen);
1953 if (req->wct < 2) {
1954 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1955 goto out;
1958 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1959 deny_mode = SVAL(req->vwv+0, 0);
1960 dos_attr = SVAL(req->vwv+1, 0);
1962 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1963 STR_TERMINATE, &status);
1964 if (!NT_STATUS_IS_OK(status)) {
1965 reply_nterror(req, status);
1966 goto out;
1969 if (!map_open_params_to_ntcreate(fname, deny_mode,
1970 OPENX_FILE_EXISTS_OPEN, &access_mask,
1971 &share_mode, &create_disposition,
1972 &create_options, &private_flags)) {
1973 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1974 goto out;
1977 status = filename_convert(ctx,
1978 conn,
1979 req->flags2 & FLAGS2_DFS_PATHNAMES,
1980 fname,
1981 UCF_PREP_CREATEFILE,
1982 NULL,
1983 &smb_fname);
1984 if (!NT_STATUS_IS_OK(status)) {
1985 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1986 reply_botherror(req,
1987 NT_STATUS_PATH_NOT_COVERED,
1988 ERRSRV, ERRbadpath);
1989 goto out;
1991 reply_nterror(req, status);
1992 goto out;
1995 status = SMB_VFS_CREATE_FILE(
1996 conn, /* conn */
1997 req, /* req */
1998 0, /* root_dir_fid */
1999 smb_fname, /* fname */
2000 access_mask, /* access_mask */
2001 share_mode, /* share_access */
2002 create_disposition, /* create_disposition*/
2003 create_options, /* create_options */
2004 dos_attr, /* file_attributes */
2005 oplock_request, /* oplock_request */
2006 NULL, /* lease */
2007 0, /* allocation_size */
2008 private_flags,
2009 NULL, /* sd */
2010 NULL, /* ea_list */
2011 &fsp, /* result */
2012 &info, /* pinfo */
2013 NULL, NULL); /* create context */
2015 if (!NT_STATUS_IS_OK(status)) {
2016 if (open_was_deferred(req->xconn, req->mid)) {
2017 /* We have re-scheduled this call. */
2018 goto out;
2020 reply_openerror(req, status);
2021 goto out;
2024 /* Ensure we're pointing at the correct stat struct. */
2025 TALLOC_FREE(smb_fname);
2026 smb_fname = fsp->fsp_name;
2028 size = smb_fname->st.st_ex_size;
2029 fattr = dos_mode(conn, smb_fname);
2031 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2033 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2034 DEBUG(3,("attempt to open a directory %s\n",
2035 fsp_str_dbg(fsp)));
2036 close_file(req, fsp, ERROR_CLOSE);
2037 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2038 ERRDOS, ERRnoaccess);
2039 goto out;
2042 reply_outbuf(req, 7, 0);
2043 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2044 SSVAL(req->outbuf,smb_vwv1,fattr);
2045 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2046 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2047 } else {
2048 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2050 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
2051 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2053 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2054 SCVAL(req->outbuf,smb_flg,
2055 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2058 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2059 SCVAL(req->outbuf,smb_flg,
2060 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2062 out:
2063 END_PROFILE(SMBopen);
2064 return;
2067 /****************************************************************************
2068 Reply to an open and X.
2069 ****************************************************************************/
2071 void reply_open_and_X(struct smb_request *req)
2073 connection_struct *conn = req->conn;
2074 struct smb_filename *smb_fname = NULL;
2075 char *fname = NULL;
2076 uint16 open_flags;
2077 int deny_mode;
2078 uint32 smb_attr;
2079 /* Breakout the oplock request bits so we can set the
2080 reply bits separately. */
2081 int ex_oplock_request;
2082 int core_oplock_request;
2083 int oplock_request;
2084 #if 0
2085 int smb_sattr = SVAL(req->vwv+4, 0);
2086 uint32 smb_time = make_unix_date3(req->vwv+6);
2087 #endif
2088 int smb_ofun;
2089 uint32 fattr=0;
2090 int mtime=0;
2091 int smb_action = 0;
2092 files_struct *fsp;
2093 NTSTATUS status;
2094 uint64_t allocation_size;
2095 ssize_t retval = -1;
2096 uint32 access_mask;
2097 uint32 share_mode;
2098 uint32 create_disposition;
2099 uint32 create_options = 0;
2100 uint32_t private_flags = 0;
2101 TALLOC_CTX *ctx = talloc_tos();
2103 START_PROFILE(SMBopenX);
2105 if (req->wct < 15) {
2106 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2107 goto out;
2110 open_flags = SVAL(req->vwv+2, 0);
2111 deny_mode = SVAL(req->vwv+3, 0);
2112 smb_attr = SVAL(req->vwv+5, 0);
2113 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2114 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2115 oplock_request = ex_oplock_request | core_oplock_request;
2116 smb_ofun = SVAL(req->vwv+8, 0);
2117 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2119 /* If it's an IPC, pass off the pipe handler. */
2120 if (IS_IPC(conn)) {
2121 if (lp_nt_pipe_support()) {
2122 reply_open_pipe_and_X(conn, req);
2123 } else {
2124 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2126 goto out;
2129 /* XXXX we need to handle passed times, sattr and flags */
2130 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2131 STR_TERMINATE, &status);
2132 if (!NT_STATUS_IS_OK(status)) {
2133 reply_nterror(req, status);
2134 goto out;
2137 if (!map_open_params_to_ntcreate(fname, deny_mode,
2138 smb_ofun,
2139 &access_mask, &share_mode,
2140 &create_disposition,
2141 &create_options,
2142 &private_flags)) {
2143 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2144 goto out;
2147 status = filename_convert(ctx,
2148 conn,
2149 req->flags2 & FLAGS2_DFS_PATHNAMES,
2150 fname,
2151 UCF_PREP_CREATEFILE,
2152 NULL,
2153 &smb_fname);
2154 if (!NT_STATUS_IS_OK(status)) {
2155 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2156 reply_botherror(req,
2157 NT_STATUS_PATH_NOT_COVERED,
2158 ERRSRV, ERRbadpath);
2159 goto out;
2161 reply_nterror(req, status);
2162 goto out;
2165 status = SMB_VFS_CREATE_FILE(
2166 conn, /* conn */
2167 req, /* req */
2168 0, /* root_dir_fid */
2169 smb_fname, /* fname */
2170 access_mask, /* access_mask */
2171 share_mode, /* share_access */
2172 create_disposition, /* create_disposition*/
2173 create_options, /* create_options */
2174 smb_attr, /* file_attributes */
2175 oplock_request, /* oplock_request */
2176 NULL, /* lease */
2177 0, /* allocation_size */
2178 private_flags,
2179 NULL, /* sd */
2180 NULL, /* ea_list */
2181 &fsp, /* result */
2182 &smb_action, /* pinfo */
2183 NULL, NULL); /* create context */
2185 if (!NT_STATUS_IS_OK(status)) {
2186 if (open_was_deferred(req->xconn, req->mid)) {
2187 /* We have re-scheduled this call. */
2188 goto out;
2190 reply_openerror(req, status);
2191 goto out;
2194 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2195 if the file is truncated or created. */
2196 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2197 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2198 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2199 close_file(req, fsp, ERROR_CLOSE);
2200 reply_nterror(req, NT_STATUS_DISK_FULL);
2201 goto out;
2203 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2204 if (retval < 0) {
2205 close_file(req, fsp, ERROR_CLOSE);
2206 reply_nterror(req, NT_STATUS_DISK_FULL);
2207 goto out;
2209 status = vfs_stat_fsp(fsp);
2210 if (!NT_STATUS_IS_OK(status)) {
2211 close_file(req, fsp, ERROR_CLOSE);
2212 reply_nterror(req, status);
2213 goto out;
2217 fattr = dos_mode(conn, fsp->fsp_name);
2218 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2219 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2220 close_file(req, fsp, ERROR_CLOSE);
2221 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2222 goto out;
2225 /* If the caller set the extended oplock request bit
2226 and we granted one (by whatever means) - set the
2227 correct bit for extended oplock reply.
2230 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2231 smb_action |= EXTENDED_OPLOCK_GRANTED;
2234 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2235 smb_action |= EXTENDED_OPLOCK_GRANTED;
2238 /* If the caller set the core oplock request bit
2239 and we granted one (by whatever means) - set the
2240 correct bit for core oplock reply.
2243 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2244 reply_outbuf(req, 19, 0);
2245 } else {
2246 reply_outbuf(req, 15, 0);
2249 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2250 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2252 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2253 SCVAL(req->outbuf, smb_flg,
2254 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2257 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2258 SCVAL(req->outbuf, smb_flg,
2259 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2262 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2263 SSVAL(req->outbuf,smb_vwv3,fattr);
2264 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2265 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2266 } else {
2267 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2269 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2270 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2271 SSVAL(req->outbuf,smb_vwv11,smb_action);
2273 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2274 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2277 out:
2278 TALLOC_FREE(smb_fname);
2279 END_PROFILE(SMBopenX);
2280 return;
2283 /****************************************************************************
2284 Reply to a SMBulogoffX.
2285 ****************************************************************************/
2287 void reply_ulogoffX(struct smb_request *req)
2289 struct smbd_server_connection *sconn = req->sconn;
2290 struct user_struct *vuser;
2291 struct smbXsrv_session *session = NULL;
2292 NTSTATUS status;
2294 START_PROFILE(SMBulogoffX);
2296 vuser = get_valid_user_struct(sconn, req->vuid);
2298 if(vuser == NULL) {
2299 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2300 (unsigned long long)req->vuid));
2302 req->vuid = UID_FIELD_INVALID;
2303 reply_force_doserror(req, ERRSRV, ERRbaduid);
2304 END_PROFILE(SMBulogoffX);
2305 return;
2308 session = vuser->session;
2309 vuser = NULL;
2312 * TODO: cancel all outstanding requests on the session
2314 status = smbXsrv_session_logoff(session);
2315 if (!NT_STATUS_IS_OK(status)) {
2316 DEBUG(0, ("reply_ulogoff: "
2317 "smbXsrv_session_logoff() failed: %s\n",
2318 nt_errstr(status)));
2320 * If we hit this case, there is something completely
2321 * wrong, so we better disconnect the transport connection.
2323 END_PROFILE(SMBulogoffX);
2324 exit_server(__location__ ": smbXsrv_session_logoff failed");
2325 return;
2328 TALLOC_FREE(session);
2330 reply_outbuf(req, 2, 0);
2331 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2332 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2334 DEBUG(3, ("ulogoffX vuid=%llu\n",
2335 (unsigned long long)req->vuid));
2337 END_PROFILE(SMBulogoffX);
2338 req->vuid = UID_FIELD_INVALID;
2341 /****************************************************************************
2342 Reply to a mknew or a create.
2343 ****************************************************************************/
2345 void reply_mknew(struct smb_request *req)
2347 connection_struct *conn = req->conn;
2348 struct smb_filename *smb_fname = NULL;
2349 char *fname = NULL;
2350 uint32 fattr = 0;
2351 struct smb_file_time ft;
2352 files_struct *fsp;
2353 int oplock_request = 0;
2354 NTSTATUS status;
2355 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2356 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2357 uint32 create_disposition;
2358 uint32 create_options = 0;
2359 TALLOC_CTX *ctx = talloc_tos();
2361 START_PROFILE(SMBcreate);
2362 ZERO_STRUCT(ft);
2364 if (req->wct < 3) {
2365 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2366 goto out;
2369 fattr = SVAL(req->vwv+0, 0);
2370 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2372 /* mtime. */
2373 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2375 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2376 STR_TERMINATE, &status);
2377 if (!NT_STATUS_IS_OK(status)) {
2378 reply_nterror(req, status);
2379 goto out;
2382 status = filename_convert(ctx,
2383 conn,
2384 req->flags2 & FLAGS2_DFS_PATHNAMES,
2385 fname,
2386 UCF_PREP_CREATEFILE,
2387 NULL,
2388 &smb_fname);
2389 if (!NT_STATUS_IS_OK(status)) {
2390 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2391 reply_botherror(req,
2392 NT_STATUS_PATH_NOT_COVERED,
2393 ERRSRV, ERRbadpath);
2394 goto out;
2396 reply_nterror(req, status);
2397 goto out;
2400 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2401 DEBUG(0,("Attempt to create file (%s) with volid set - "
2402 "please report this\n",
2403 smb_fname_str_dbg(smb_fname)));
2406 if(req->cmd == SMBmknew) {
2407 /* We should fail if file exists. */
2408 create_disposition = FILE_CREATE;
2409 } else {
2410 /* Create if file doesn't exist, truncate if it does. */
2411 create_disposition = FILE_OVERWRITE_IF;
2414 status = SMB_VFS_CREATE_FILE(
2415 conn, /* conn */
2416 req, /* req */
2417 0, /* root_dir_fid */
2418 smb_fname, /* fname */
2419 access_mask, /* access_mask */
2420 share_mode, /* share_access */
2421 create_disposition, /* create_disposition*/
2422 create_options, /* create_options */
2423 fattr, /* file_attributes */
2424 oplock_request, /* oplock_request */
2425 NULL, /* lease */
2426 0, /* allocation_size */
2427 0, /* private_flags */
2428 NULL, /* sd */
2429 NULL, /* ea_list */
2430 &fsp, /* result */
2431 NULL, /* pinfo */
2432 NULL, NULL); /* create context */
2434 if (!NT_STATUS_IS_OK(status)) {
2435 if (open_was_deferred(req->xconn, req->mid)) {
2436 /* We have re-scheduled this call. */
2437 goto out;
2439 reply_openerror(req, status);
2440 goto out;
2443 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2444 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2445 if (!NT_STATUS_IS_OK(status)) {
2446 END_PROFILE(SMBcreate);
2447 goto out;
2450 reply_outbuf(req, 1, 0);
2451 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2453 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2454 SCVAL(req->outbuf,smb_flg,
2455 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2458 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2459 SCVAL(req->outbuf,smb_flg,
2460 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2463 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2464 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2465 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2466 (unsigned int)fattr));
2468 out:
2469 TALLOC_FREE(smb_fname);
2470 END_PROFILE(SMBcreate);
2471 return;
2474 /****************************************************************************
2475 Reply to a create temporary file.
2476 ****************************************************************************/
2478 void reply_ctemp(struct smb_request *req)
2480 connection_struct *conn = req->conn;
2481 struct smb_filename *smb_fname = NULL;
2482 char *wire_name = NULL;
2483 char *fname = NULL;
2484 uint32 fattr;
2485 files_struct *fsp;
2486 int oplock_request;
2487 char *s;
2488 NTSTATUS status;
2489 int i;
2490 TALLOC_CTX *ctx = talloc_tos();
2492 START_PROFILE(SMBctemp);
2494 if (req->wct < 3) {
2495 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2496 goto out;
2499 fattr = SVAL(req->vwv+0, 0);
2500 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2502 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2503 STR_TERMINATE, &status);
2504 if (!NT_STATUS_IS_OK(status)) {
2505 reply_nterror(req, status);
2506 goto out;
2509 for (i = 0; i < 10; i++) {
2510 if (*wire_name) {
2511 fname = talloc_asprintf(ctx,
2512 "%s/TMP%s",
2513 wire_name,
2514 generate_random_str_list(ctx, 5, "0123456789"));
2515 } else {
2516 fname = talloc_asprintf(ctx,
2517 "TMP%s",
2518 generate_random_str_list(ctx, 5, "0123456789"));
2521 if (!fname) {
2522 reply_nterror(req, NT_STATUS_NO_MEMORY);
2523 goto out;
2526 status = filename_convert(ctx, conn,
2527 req->flags2 & FLAGS2_DFS_PATHNAMES,
2528 fname,
2529 UCF_PREP_CREATEFILE,
2530 NULL,
2531 &smb_fname);
2532 if (!NT_STATUS_IS_OK(status)) {
2533 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2534 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2535 ERRSRV, ERRbadpath);
2536 goto out;
2538 reply_nterror(req, status);
2539 goto out;
2542 /* Create the file. */
2543 status = SMB_VFS_CREATE_FILE(
2544 conn, /* conn */
2545 req, /* req */
2546 0, /* root_dir_fid */
2547 smb_fname, /* fname */
2548 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2549 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2550 FILE_CREATE, /* create_disposition*/
2551 0, /* create_options */
2552 fattr, /* file_attributes */
2553 oplock_request, /* oplock_request */
2554 NULL, /* lease */
2555 0, /* allocation_size */
2556 0, /* private_flags */
2557 NULL, /* sd */
2558 NULL, /* ea_list */
2559 &fsp, /* result */
2560 NULL, /* pinfo */
2561 NULL, NULL); /* create context */
2563 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2564 TALLOC_FREE(fname);
2565 TALLOC_FREE(smb_fname);
2566 continue;
2569 if (!NT_STATUS_IS_OK(status)) {
2570 if (open_was_deferred(req->xconn, req->mid)) {
2571 /* We have re-scheduled this call. */
2572 goto out;
2574 reply_openerror(req, status);
2575 goto out;
2578 break;
2581 if (i == 10) {
2582 /* Collision after 10 times... */
2583 reply_nterror(req, status);
2584 goto out;
2587 reply_outbuf(req, 1, 0);
2588 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2590 /* the returned filename is relative to the directory */
2591 s = strrchr_m(fsp->fsp_name->base_name, '/');
2592 if (!s) {
2593 s = fsp->fsp_name->base_name;
2594 } else {
2595 s++;
2598 #if 0
2599 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2600 thing in the byte section. JRA */
2601 SSVALS(p, 0, -1); /* what is this? not in spec */
2602 #endif
2603 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2604 == -1) {
2605 reply_nterror(req, NT_STATUS_NO_MEMORY);
2606 goto out;
2609 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2610 SCVAL(req->outbuf, smb_flg,
2611 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2614 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2615 SCVAL(req->outbuf, smb_flg,
2616 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2619 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2620 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2621 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2622 out:
2623 TALLOC_FREE(smb_fname);
2624 TALLOC_FREE(wire_name);
2625 END_PROFILE(SMBctemp);
2626 return;
2629 /*******************************************************************
2630 Check if a user is allowed to rename a file.
2631 ********************************************************************/
2633 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2634 uint16 dirtype)
2636 if (!CAN_WRITE(conn)) {
2637 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2640 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2641 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2642 /* Only bother to read the DOS attribute if we might deny the
2643 rename on the grounds of attribute missmatch. */
2644 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2645 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2646 return NT_STATUS_NO_SUCH_FILE;
2650 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2651 if (fsp->posix_open) {
2652 return NT_STATUS_OK;
2655 /* If no pathnames are open below this
2656 directory, allow the rename. */
2658 if (file_find_subpath(fsp)) {
2659 return NT_STATUS_ACCESS_DENIED;
2661 return NT_STATUS_OK;
2664 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2665 return NT_STATUS_OK;
2668 return NT_STATUS_ACCESS_DENIED;
2671 /*******************************************************************
2672 * unlink a file with all relevant access checks
2673 *******************************************************************/
2675 static NTSTATUS do_unlink(connection_struct *conn,
2676 struct smb_request *req,
2677 struct smb_filename *smb_fname,
2678 uint32 dirtype)
2680 uint32 fattr;
2681 files_struct *fsp;
2682 uint32 dirtype_orig = dirtype;
2683 NTSTATUS status;
2684 int ret;
2685 bool posix_paths = lp_posix_pathnames();
2687 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2688 smb_fname_str_dbg(smb_fname),
2689 dirtype));
2691 if (!CAN_WRITE(conn)) {
2692 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2695 if (posix_paths) {
2696 ret = SMB_VFS_LSTAT(conn, smb_fname);
2697 } else {
2698 ret = SMB_VFS_STAT(conn, smb_fname);
2700 if (ret != 0) {
2701 return map_nt_error_from_unix(errno);
2704 fattr = dos_mode(conn, smb_fname);
2706 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2707 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2710 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2711 if (!dirtype) {
2712 return NT_STATUS_NO_SUCH_FILE;
2715 if (!dir_check_ftype(fattr, dirtype)) {
2716 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2717 return NT_STATUS_FILE_IS_A_DIRECTORY;
2719 return NT_STATUS_NO_SUCH_FILE;
2722 if (dirtype_orig & 0x8000) {
2723 /* These will never be set for POSIX. */
2724 return NT_STATUS_NO_SUCH_FILE;
2727 #if 0
2728 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2729 return NT_STATUS_FILE_IS_A_DIRECTORY;
2732 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2733 return NT_STATUS_NO_SUCH_FILE;
2736 if (dirtype & 0xFF00) {
2737 /* These will never be set for POSIX. */
2738 return NT_STATUS_NO_SUCH_FILE;
2741 dirtype &= 0xFF;
2742 if (!dirtype) {
2743 return NT_STATUS_NO_SUCH_FILE;
2746 /* Can't delete a directory. */
2747 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2748 return NT_STATUS_FILE_IS_A_DIRECTORY;
2750 #endif
2752 #if 0 /* JRATEST */
2753 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2754 return NT_STATUS_OBJECT_NAME_INVALID;
2755 #endif /* JRATEST */
2757 /* On open checks the open itself will check the share mode, so
2758 don't do it here as we'll get it wrong. */
2760 status = SMB_VFS_CREATE_FILE
2761 (conn, /* conn */
2762 req, /* req */
2763 0, /* root_dir_fid */
2764 smb_fname, /* fname */
2765 DELETE_ACCESS, /* access_mask */
2766 FILE_SHARE_NONE, /* share_access */
2767 FILE_OPEN, /* create_disposition*/
2768 FILE_NON_DIRECTORY_FILE, /* create_options */
2769 /* file_attributes */
2770 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2771 FILE_ATTRIBUTE_NORMAL,
2772 0, /* oplock_request */
2773 NULL, /* lease */
2774 0, /* allocation_size */
2775 0, /* private_flags */
2776 NULL, /* sd */
2777 NULL, /* ea_list */
2778 &fsp, /* result */
2779 NULL, /* pinfo */
2780 NULL, NULL); /* create context */
2782 if (!NT_STATUS_IS_OK(status)) {
2783 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2784 nt_errstr(status)));
2785 return status;
2788 status = can_set_delete_on_close(fsp, fattr);
2789 if (!NT_STATUS_IS_OK(status)) {
2790 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2791 "(%s)\n",
2792 smb_fname_str_dbg(smb_fname),
2793 nt_errstr(status)));
2794 close_file(req, fsp, NORMAL_CLOSE);
2795 return status;
2798 /* The set is across all open files on this dev/inode pair. */
2799 if (!set_delete_on_close(fsp, True,
2800 conn->session_info->security_token,
2801 conn->session_info->unix_token)) {
2802 close_file(req, fsp, NORMAL_CLOSE);
2803 return NT_STATUS_ACCESS_DENIED;
2806 return close_file(req, fsp, NORMAL_CLOSE);
2809 /****************************************************************************
2810 The guts of the unlink command, split out so it may be called by the NT SMB
2811 code.
2812 ****************************************************************************/
2814 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2815 uint32 dirtype, struct smb_filename *smb_fname,
2816 bool has_wild)
2818 char *fname_dir = NULL;
2819 char *fname_mask = NULL;
2820 int count=0;
2821 NTSTATUS status = NT_STATUS_OK;
2822 TALLOC_CTX *ctx = talloc_tos();
2824 /* Split up the directory from the filename/mask. */
2825 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2826 &fname_dir, &fname_mask);
2827 if (!NT_STATUS_IS_OK(status)) {
2828 goto out;
2832 * We should only check the mangled cache
2833 * here if unix_convert failed. This means
2834 * that the path in 'mask' doesn't exist
2835 * on the file system and so we need to look
2836 * for a possible mangle. This patch from
2837 * Tine Smukavec <valentin.smukavec@hermes.si>.
2840 if (!VALID_STAT(smb_fname->st) &&
2841 mangle_is_mangled(fname_mask, conn->params)) {
2842 char *new_mask = NULL;
2843 mangle_lookup_name_from_8_3(ctx, fname_mask,
2844 &new_mask, conn->params);
2845 if (new_mask) {
2846 TALLOC_FREE(fname_mask);
2847 fname_mask = new_mask;
2851 if (!has_wild) {
2854 * Only one file needs to be unlinked. Append the mask back
2855 * onto the directory.
2857 TALLOC_FREE(smb_fname->base_name);
2858 if (ISDOT(fname_dir)) {
2859 /* Ensure we use canonical names on open. */
2860 smb_fname->base_name = talloc_asprintf(smb_fname,
2861 "%s",
2862 fname_mask);
2863 } else {
2864 smb_fname->base_name = talloc_asprintf(smb_fname,
2865 "%s/%s",
2866 fname_dir,
2867 fname_mask);
2869 if (!smb_fname->base_name) {
2870 status = NT_STATUS_NO_MEMORY;
2871 goto out;
2873 if (dirtype == 0) {
2874 dirtype = FILE_ATTRIBUTE_NORMAL;
2877 status = check_name(conn, smb_fname->base_name);
2878 if (!NT_STATUS_IS_OK(status)) {
2879 goto out;
2882 status = do_unlink(conn, req, smb_fname, dirtype);
2883 if (!NT_STATUS_IS_OK(status)) {
2884 goto out;
2887 count++;
2888 } else {
2889 struct smb_Dir *dir_hnd = NULL;
2890 long offset = 0;
2891 const char *dname = NULL;
2892 char *talloced = NULL;
2894 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2895 status = NT_STATUS_OBJECT_NAME_INVALID;
2896 goto out;
2899 if (strequal(fname_mask,"????????.???")) {
2900 TALLOC_FREE(fname_mask);
2901 fname_mask = talloc_strdup(ctx, "*");
2902 if (!fname_mask) {
2903 status = NT_STATUS_NO_MEMORY;
2904 goto out;
2908 status = check_name(conn, fname_dir);
2909 if (!NT_STATUS_IS_OK(status)) {
2910 goto out;
2913 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2914 dirtype);
2915 if (dir_hnd == NULL) {
2916 status = map_nt_error_from_unix(errno);
2917 goto out;
2920 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2921 the pattern matches against the long name, otherwise the short name
2922 We don't implement this yet XXXX
2925 status = NT_STATUS_NO_SUCH_FILE;
2927 while ((dname = ReadDirName(dir_hnd, &offset,
2928 &smb_fname->st, &talloced))) {
2929 TALLOC_CTX *frame = talloc_stackframe();
2931 if (!is_visible_file(conn, fname_dir, dname,
2932 &smb_fname->st, true)) {
2933 TALLOC_FREE(frame);
2934 TALLOC_FREE(talloced);
2935 continue;
2938 /* Quick check for "." and ".." */
2939 if (ISDOT(dname) || ISDOTDOT(dname)) {
2940 TALLOC_FREE(frame);
2941 TALLOC_FREE(talloced);
2942 continue;
2945 if(!mask_match(dname, fname_mask,
2946 conn->case_sensitive)) {
2947 TALLOC_FREE(frame);
2948 TALLOC_FREE(talloced);
2949 continue;
2952 TALLOC_FREE(smb_fname->base_name);
2953 if (ISDOT(fname_dir)) {
2954 /* Ensure we use canonical names on open. */
2955 smb_fname->base_name =
2956 talloc_asprintf(smb_fname, "%s",
2957 dname);
2958 } else {
2959 smb_fname->base_name =
2960 talloc_asprintf(smb_fname, "%s/%s",
2961 fname_dir, dname);
2964 if (!smb_fname->base_name) {
2965 TALLOC_FREE(dir_hnd);
2966 status = NT_STATUS_NO_MEMORY;
2967 TALLOC_FREE(frame);
2968 TALLOC_FREE(talloced);
2969 goto out;
2972 status = check_name(conn, smb_fname->base_name);
2973 if (!NT_STATUS_IS_OK(status)) {
2974 TALLOC_FREE(dir_hnd);
2975 TALLOC_FREE(frame);
2976 TALLOC_FREE(talloced);
2977 goto out;
2980 status = do_unlink(conn, req, smb_fname, dirtype);
2981 if (!NT_STATUS_IS_OK(status)) {
2982 TALLOC_FREE(dir_hnd);
2983 TALLOC_FREE(frame);
2984 TALLOC_FREE(talloced);
2985 goto out;
2988 count++;
2989 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2990 smb_fname->base_name));
2992 TALLOC_FREE(frame);
2993 TALLOC_FREE(talloced);
2995 TALLOC_FREE(dir_hnd);
2998 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2999 status = map_nt_error_from_unix(errno);
3002 out:
3003 TALLOC_FREE(fname_dir);
3004 TALLOC_FREE(fname_mask);
3005 return status;
3008 /****************************************************************************
3009 Reply to a unlink
3010 ****************************************************************************/
3012 void reply_unlink(struct smb_request *req)
3014 connection_struct *conn = req->conn;
3015 char *name = NULL;
3016 struct smb_filename *smb_fname = NULL;
3017 uint32 dirtype;
3018 NTSTATUS status;
3019 bool path_contains_wcard = False;
3020 TALLOC_CTX *ctx = talloc_tos();
3022 START_PROFILE(SMBunlink);
3024 if (req->wct < 1) {
3025 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3026 goto out;
3029 dirtype = SVAL(req->vwv+0, 0);
3031 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3032 STR_TERMINATE, &status,
3033 &path_contains_wcard);
3034 if (!NT_STATUS_IS_OK(status)) {
3035 reply_nterror(req, status);
3036 goto out;
3039 status = filename_convert(ctx, conn,
3040 req->flags2 & FLAGS2_DFS_PATHNAMES,
3041 name,
3042 UCF_COND_ALLOW_WCARD_LCOMP,
3043 &path_contains_wcard,
3044 &smb_fname);
3045 if (!NT_STATUS_IS_OK(status)) {
3046 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3047 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3048 ERRSRV, ERRbadpath);
3049 goto out;
3051 reply_nterror(req, status);
3052 goto out;
3055 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3057 status = unlink_internals(conn, req, dirtype, smb_fname,
3058 path_contains_wcard);
3059 if (!NT_STATUS_IS_OK(status)) {
3060 if (open_was_deferred(req->xconn, req->mid)) {
3061 /* We have re-scheduled this call. */
3062 goto out;
3064 reply_nterror(req, status);
3065 goto out;
3068 reply_outbuf(req, 0, 0);
3069 out:
3070 TALLOC_FREE(smb_fname);
3071 END_PROFILE(SMBunlink);
3072 return;
3075 /****************************************************************************
3076 Fail for readbraw.
3077 ****************************************************************************/
3079 static void fail_readraw(void)
3081 const char *errstr = talloc_asprintf(talloc_tos(),
3082 "FAIL ! reply_readbraw: socket write fail (%s)",
3083 strerror(errno));
3084 if (!errstr) {
3085 errstr = "";
3087 exit_server_cleanly(errstr);
3090 /****************************************************************************
3091 Fake (read/write) sendfile. Returns -1 on read or write fail.
3092 ****************************************************************************/
3094 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3095 off_t startpos, size_t nread)
3097 size_t bufsize;
3098 size_t tosend = nread;
3099 char *buf;
3101 if (nread == 0) {
3102 return 0;
3105 bufsize = MIN(nread, 65536);
3107 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3108 return -1;
3111 while (tosend > 0) {
3112 ssize_t ret;
3113 size_t cur_read;
3115 cur_read = MIN(tosend, bufsize);
3116 ret = read_file(fsp,buf,startpos,cur_read);
3117 if (ret == -1) {
3118 SAFE_FREE(buf);
3119 return -1;
3122 /* If we had a short read, fill with zeros. */
3123 if (ret < cur_read) {
3124 memset(buf + ret, '\0', cur_read - ret);
3127 ret = write_data(xconn->transport.sock, buf, cur_read);
3128 if (ret != cur_read) {
3129 int saved_errno = errno;
3131 * Try and give an error message saying what
3132 * client failed.
3134 DEBUG(0, ("write_data failed for client %s. "
3135 "Error %s\n",
3136 smbXsrv_connection_dbg(xconn),
3137 strerror(saved_errno)));
3138 SAFE_FREE(buf);
3139 errno = saved_errno;
3140 return -1;
3142 tosend -= cur_read;
3143 startpos += cur_read;
3146 SAFE_FREE(buf);
3147 return (ssize_t)nread;
3150 /****************************************************************************
3151 Deal with the case of sendfile reading less bytes from the file than
3152 requested. Fill with zeros (all we can do). Returns 0 on success
3153 ****************************************************************************/
3155 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3156 files_struct *fsp,
3157 ssize_t nread,
3158 size_t headersize,
3159 size_t smb_maxcnt)
3161 #define SHORT_SEND_BUFSIZE 1024
3162 if (nread < headersize) {
3163 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3164 "header for file %s (%s). Terminating\n",
3165 fsp_str_dbg(fsp), strerror(errno)));
3166 return -1;
3169 nread -= headersize;
3171 if (nread < smb_maxcnt) {
3172 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3173 if (!buf) {
3174 DEBUG(0,("sendfile_short_send: malloc failed "
3175 "for file %s (%s). Terminating\n",
3176 fsp_str_dbg(fsp), strerror(errno)));
3177 return -1;
3180 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3181 "with zeros !\n", fsp_str_dbg(fsp)));
3183 while (nread < smb_maxcnt) {
3185 * We asked for the real file size and told sendfile
3186 * to not go beyond the end of the file. But it can
3187 * happen that in between our fstat call and the
3188 * sendfile call the file was truncated. This is very
3189 * bad because we have already announced the larger
3190 * number of bytes to the client.
3192 * The best we can do now is to send 0-bytes, just as
3193 * a read from a hole in a sparse file would do.
3195 * This should happen rarely enough that I don't care
3196 * about efficiency here :-)
3198 size_t to_write;
3199 ssize_t ret;
3201 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3202 ret = write_data(xconn->transport.sock, buf, to_write);
3203 if (ret != to_write) {
3204 int saved_errno = errno;
3206 * Try and give an error message saying what
3207 * client failed.
3209 DEBUG(0, ("write_data failed for client %s. "
3210 "Error %s\n",
3211 smbXsrv_connection_dbg(xconn),
3212 strerror(saved_errno)));
3213 errno = saved_errno;
3214 return -1;
3216 nread += to_write;
3218 SAFE_FREE(buf);
3221 return 0;
3224 /****************************************************************************
3225 Return a readbraw error (4 bytes of zero).
3226 ****************************************************************************/
3228 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3230 char header[4];
3232 SIVAL(header,0,0);
3234 smbd_lock_socket(xconn);
3235 if (write_data(xconn->transport.sock,header,4) != 4) {
3236 int saved_errno = errno;
3238 * Try and give an error message saying what
3239 * client failed.
3241 DEBUG(0, ("write_data failed for client %s. "
3242 "Error %s\n",
3243 smbXsrv_connection_dbg(xconn),
3244 strerror(saved_errno)));
3245 errno = saved_errno;
3247 fail_readraw();
3249 smbd_unlock_socket(xconn);
3252 /****************************************************************************
3253 Use sendfile in readbraw.
3254 ****************************************************************************/
3256 static void send_file_readbraw(connection_struct *conn,
3257 struct smb_request *req,
3258 files_struct *fsp,
3259 off_t startpos,
3260 size_t nread,
3261 ssize_t mincount)
3263 struct smbXsrv_connection *xconn = req->xconn;
3264 char *outbuf = NULL;
3265 ssize_t ret=0;
3268 * We can only use sendfile on a non-chained packet
3269 * but we can use on a non-oplocked file. tridge proved this
3270 * on a train in Germany :-). JRA.
3271 * reply_readbraw has already checked the length.
3274 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3275 (fsp->wcp == NULL) &&
3276 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3277 ssize_t sendfile_read = -1;
3278 char header[4];
3279 DATA_BLOB header_blob;
3281 _smb_setlen(header,nread);
3282 header_blob = data_blob_const(header, 4);
3284 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3285 &header_blob, startpos,
3286 nread);
3287 if (sendfile_read == -1) {
3288 /* Returning ENOSYS means no data at all was sent.
3289 * Do this as a normal read. */
3290 if (errno == ENOSYS) {
3291 goto normal_readbraw;
3295 * Special hack for broken Linux with no working sendfile. If we
3296 * return EINTR we sent the header but not the rest of the data.
3297 * Fake this up by doing read/write calls.
3299 if (errno == EINTR) {
3300 /* Ensure we don't do this again. */
3301 set_use_sendfile(SNUM(conn), False);
3302 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3304 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3305 DEBUG(0,("send_file_readbraw: "
3306 "fake_sendfile failed for "
3307 "file %s (%s).\n",
3308 fsp_str_dbg(fsp),
3309 strerror(errno)));
3310 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3312 return;
3315 DEBUG(0,("send_file_readbraw: sendfile failed for "
3316 "file %s (%s). Terminating\n",
3317 fsp_str_dbg(fsp), strerror(errno)));
3318 exit_server_cleanly("send_file_readbraw sendfile failed");
3319 } else if (sendfile_read == 0) {
3321 * Some sendfile implementations return 0 to indicate
3322 * that there was a short read, but nothing was
3323 * actually written to the socket. In this case,
3324 * fallback to the normal read path so the header gets
3325 * the correct byte count.
3327 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3328 "bytes falling back to the normal read: "
3329 "%s\n", fsp_str_dbg(fsp)));
3330 goto normal_readbraw;
3333 /* Deal with possible short send. */
3334 if (sendfile_read != 4+nread) {
3335 ret = sendfile_short_send(xconn, fsp,
3336 sendfile_read, 4, nread);
3337 if (ret == -1) {
3338 fail_readraw();
3341 return;
3344 normal_readbraw:
3346 outbuf = talloc_array(NULL, char, nread+4);
3347 if (!outbuf) {
3348 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3349 (unsigned)(nread+4)));
3350 reply_readbraw_error(xconn);
3351 return;
3354 if (nread > 0) {
3355 ret = read_file(fsp,outbuf+4,startpos,nread);
3356 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3357 if (ret < mincount)
3358 ret = 0;
3359 #else
3360 if (ret < nread)
3361 ret = 0;
3362 #endif
3365 _smb_setlen(outbuf,ret);
3366 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3367 int saved_errno = errno;
3369 * Try and give an error message saying what
3370 * client failed.
3372 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3373 smbXsrv_connection_dbg(xconn),
3374 strerror(saved_errno)));
3375 errno = saved_errno;
3377 fail_readraw();
3380 TALLOC_FREE(outbuf);
3383 /****************************************************************************
3384 Reply to a readbraw (core+ protocol).
3385 ****************************************************************************/
3387 void reply_readbraw(struct smb_request *req)
3389 connection_struct *conn = req->conn;
3390 struct smbXsrv_connection *xconn = req->xconn;
3391 ssize_t maxcount,mincount;
3392 size_t nread = 0;
3393 off_t startpos;
3394 files_struct *fsp;
3395 struct lock_struct lock;
3396 off_t size = 0;
3398 START_PROFILE(SMBreadbraw);
3400 if (srv_is_signing_active(xconn) || req->encrypted) {
3401 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3402 "raw reads/writes are disallowed.");
3405 if (req->wct < 8) {
3406 reply_readbraw_error(xconn);
3407 END_PROFILE(SMBreadbraw);
3408 return;
3411 if (xconn->smb1.echo_handler.trusted_fde) {
3412 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3413 "'async smb echo handler = yes'\n"));
3414 reply_readbraw_error(xconn);
3415 END_PROFILE(SMBreadbraw);
3416 return;
3420 * Special check if an oplock break has been issued
3421 * and the readraw request croses on the wire, we must
3422 * return a zero length response here.
3425 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3428 * We have to do a check_fsp by hand here, as
3429 * we must always return 4 zero bytes on error,
3430 * not a NTSTATUS.
3433 if (!fsp || !conn || conn != fsp->conn ||
3434 req->vuid != fsp->vuid ||
3435 fsp->is_directory || fsp->fh->fd == -1) {
3437 * fsp could be NULL here so use the value from the packet. JRA.
3439 DEBUG(3,("reply_readbraw: fnum %d not valid "
3440 "- cache prime?\n",
3441 (int)SVAL(req->vwv+0, 0)));
3442 reply_readbraw_error(xconn);
3443 END_PROFILE(SMBreadbraw);
3444 return;
3447 /* Do a "by hand" version of CHECK_READ. */
3448 if (!(fsp->can_read ||
3449 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3450 (fsp->access_mask & FILE_EXECUTE)))) {
3451 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3452 (int)SVAL(req->vwv+0, 0)));
3453 reply_readbraw_error(xconn);
3454 END_PROFILE(SMBreadbraw);
3455 return;
3458 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3460 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3461 if(req->wct == 10) {
3463 * This is a large offset (64 bit) read.
3466 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3468 if(startpos < 0) {
3469 DEBUG(0,("reply_readbraw: negative 64 bit "
3470 "readraw offset (%.0f) !\n",
3471 (double)startpos ));
3472 reply_readbraw_error(xconn);
3473 END_PROFILE(SMBreadbraw);
3474 return;
3478 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3479 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3481 /* ensure we don't overrun the packet size */
3482 maxcount = MIN(65535,maxcount);
3484 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3485 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3486 &lock);
3488 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3489 reply_readbraw_error(xconn);
3490 END_PROFILE(SMBreadbraw);
3491 return;
3494 if (fsp_stat(fsp) == 0) {
3495 size = fsp->fsp_name->st.st_ex_size;
3498 if (startpos >= size) {
3499 nread = 0;
3500 } else {
3501 nread = MIN(maxcount,(size - startpos));
3504 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3505 if (nread < mincount)
3506 nread = 0;
3507 #endif
3509 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3510 "min=%lu nread=%lu\n",
3511 fsp_fnum_dbg(fsp), (double)startpos,
3512 (unsigned long)maxcount,
3513 (unsigned long)mincount,
3514 (unsigned long)nread ) );
3516 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3518 DEBUG(5,("reply_readbraw finished\n"));
3520 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3522 END_PROFILE(SMBreadbraw);
3523 return;
3526 #undef DBGC_CLASS
3527 #define DBGC_CLASS DBGC_LOCKING
3529 /****************************************************************************
3530 Reply to a lockread (core+ protocol).
3531 ****************************************************************************/
3533 void reply_lockread(struct smb_request *req)
3535 connection_struct *conn = req->conn;
3536 ssize_t nread = -1;
3537 char *data;
3538 off_t startpos;
3539 size_t numtoread;
3540 size_t maxtoread;
3541 NTSTATUS status;
3542 files_struct *fsp;
3543 struct byte_range_lock *br_lck = NULL;
3544 char *p = NULL;
3545 struct smbXsrv_connection *xconn = req->xconn;
3547 START_PROFILE(SMBlockread);
3549 if (req->wct < 5) {
3550 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3551 END_PROFILE(SMBlockread);
3552 return;
3555 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3557 if (!check_fsp(conn, req, fsp)) {
3558 END_PROFILE(SMBlockread);
3559 return;
3562 if (!CHECK_READ(fsp,req)) {
3563 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3564 END_PROFILE(SMBlockread);
3565 return;
3568 numtoread = SVAL(req->vwv+1, 0);
3569 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3572 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3573 * protocol request that predates the read/write lock concept.
3574 * Thus instead of asking for a read lock here we need to ask
3575 * for a write lock. JRA.
3576 * Note that the requested lock size is unaffected by max_send.
3579 br_lck = do_lock(req->sconn->msg_ctx,
3580 fsp,
3581 (uint64_t)req->smbpid,
3582 (uint64_t)numtoread,
3583 (uint64_t)startpos,
3584 WRITE_LOCK,
3585 WINDOWS_LOCK,
3586 False, /* Non-blocking lock. */
3587 &status,
3588 NULL);
3589 TALLOC_FREE(br_lck);
3591 if (NT_STATUS_V(status)) {
3592 reply_nterror(req, status);
3593 END_PROFILE(SMBlockread);
3594 return;
3598 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3600 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3602 if (numtoread > maxtoread) {
3603 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3604 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3605 (unsigned int)numtoread, (unsigned int)maxtoread,
3606 (unsigned int)xconn->smb1.sessions.max_send));
3607 numtoread = maxtoread;
3610 reply_outbuf(req, 5, numtoread + 3);
3612 data = smb_buf(req->outbuf) + 3;
3614 nread = read_file(fsp,data,startpos,numtoread);
3616 if (nread < 0) {
3617 reply_nterror(req, map_nt_error_from_unix(errno));
3618 END_PROFILE(SMBlockread);
3619 return;
3622 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3624 SSVAL(req->outbuf,smb_vwv0,nread);
3625 SSVAL(req->outbuf,smb_vwv5,nread+3);
3626 p = smb_buf(req->outbuf);
3627 SCVAL(p,0,0); /* pad byte. */
3628 SSVAL(p,1,nread);
3630 DEBUG(3,("lockread %s num=%d nread=%d\n",
3631 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3633 END_PROFILE(SMBlockread);
3634 return;
3637 #undef DBGC_CLASS
3638 #define DBGC_CLASS DBGC_ALL
3640 /****************************************************************************
3641 Reply to a read.
3642 ****************************************************************************/
3644 void reply_read(struct smb_request *req)
3646 connection_struct *conn = req->conn;
3647 size_t numtoread;
3648 size_t maxtoread;
3649 ssize_t nread = 0;
3650 char *data;
3651 off_t startpos;
3652 files_struct *fsp;
3653 struct lock_struct lock;
3654 struct smbXsrv_connection *xconn = req->xconn;
3656 START_PROFILE(SMBread);
3658 if (req->wct < 3) {
3659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3660 END_PROFILE(SMBread);
3661 return;
3664 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3666 if (!check_fsp(conn, req, fsp)) {
3667 END_PROFILE(SMBread);
3668 return;
3671 if (!CHECK_READ(fsp,req)) {
3672 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3673 END_PROFILE(SMBread);
3674 return;
3677 numtoread = SVAL(req->vwv+1, 0);
3678 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3681 * The requested read size cannot be greater than max_send. JRA.
3683 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3685 if (numtoread > maxtoread) {
3686 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3687 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3688 (unsigned int)numtoread, (unsigned int)maxtoread,
3689 (unsigned int)xconn->smb1.sessions.max_send));
3690 numtoread = maxtoread;
3693 reply_outbuf(req, 5, numtoread+3);
3695 data = smb_buf(req->outbuf) + 3;
3697 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3698 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3699 &lock);
3701 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3702 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3703 END_PROFILE(SMBread);
3704 return;
3707 if (numtoread > 0)
3708 nread = read_file(fsp,data,startpos,numtoread);
3710 if (nread < 0) {
3711 reply_nterror(req, map_nt_error_from_unix(errno));
3712 goto strict_unlock;
3715 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3717 SSVAL(req->outbuf,smb_vwv0,nread);
3718 SSVAL(req->outbuf,smb_vwv5,nread+3);
3719 SCVAL(smb_buf(req->outbuf),0,1);
3720 SSVAL(smb_buf(req->outbuf),1,nread);
3722 DEBUG(3, ("read %s num=%d nread=%d\n",
3723 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3725 strict_unlock:
3726 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3728 END_PROFILE(SMBread);
3729 return;
3732 /****************************************************************************
3733 Setup readX header.
3734 ****************************************************************************/
3736 static int setup_readX_header(struct smb_request *req, char *outbuf,
3737 size_t smb_maxcnt)
3739 int outsize;
3741 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3742 False);
3744 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3746 SCVAL(outbuf,smb_vwv0,0xFF);
3747 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3748 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3749 SSVAL(outbuf,smb_vwv6,
3750 (smb_wct - 4) /* offset from smb header to wct */
3751 + 1 /* the wct field */
3752 + 12 * sizeof(uint16_t) /* vwv */
3753 + 2 /* the buflen field */
3754 + 1); /* padding byte */
3755 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3756 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3757 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3758 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3759 _smb_setlen_large(outbuf,
3760 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3761 return outsize;
3764 /****************************************************************************
3765 Reply to a read and X - possibly using sendfile.
3766 ****************************************************************************/
3768 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3769 files_struct *fsp, off_t startpos,
3770 size_t smb_maxcnt)
3772 struct smbXsrv_connection *xconn = req->xconn;
3773 ssize_t nread = -1;
3774 struct lock_struct lock;
3775 int saved_errno = 0;
3777 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3778 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3779 &lock);
3781 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3782 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3783 return;
3787 * We can only use sendfile on a non-chained packet
3788 * but we can use on a non-oplocked file. tridge proved this
3789 * on a train in Germany :-). JRA.
3792 if (!req_is_in_chain(req) &&
3793 !req->encrypted &&
3794 (fsp->base_fsp == NULL) &&
3795 (fsp->wcp == NULL) &&
3796 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3797 uint8 headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3798 DATA_BLOB header;
3800 if(fsp_stat(fsp) == -1) {
3801 reply_nterror(req, map_nt_error_from_unix(errno));
3802 goto strict_unlock;
3805 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3806 (startpos > fsp->fsp_name->st.st_ex_size) ||
3807 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3809 * We already know that we would do a short read, so don't
3810 * try the sendfile() path.
3812 goto nosendfile_read;
3816 * Set up the packet header before send. We
3817 * assume here the sendfile will work (get the
3818 * correct amount of data).
3821 header = data_blob_const(headerbuf, sizeof(headerbuf));
3823 construct_reply_common_req(req, (char *)headerbuf);
3824 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3826 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
3827 startpos, smb_maxcnt);
3828 if (nread == -1) {
3829 saved_errno = errno;
3831 /* Returning ENOSYS means no data at all was sent.
3832 Do this as a normal read. */
3833 if (errno == ENOSYS) {
3834 goto normal_read;
3838 * Special hack for broken Linux with no working sendfile. If we
3839 * return EINTR we sent the header but not the rest of the data.
3840 * Fake this up by doing read/write calls.
3843 if (errno == EINTR) {
3844 /* Ensure we don't do this again. */
3845 set_use_sendfile(SNUM(conn), False);
3846 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3847 nread = fake_sendfile(xconn, fsp, startpos,
3848 smb_maxcnt);
3849 if (nread == -1) {
3850 saved_errno = errno;
3851 DEBUG(0,("send_file_readX: "
3852 "fake_sendfile failed for "
3853 "file %s (%s) for client %s. "
3854 "Terminating\n",
3855 fsp_str_dbg(fsp),
3856 smbXsrv_connection_dbg(xconn),
3857 strerror(saved_errno)));
3858 errno = saved_errno;
3859 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3861 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3862 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3863 /* No outbuf here means successful sendfile. */
3864 goto strict_unlock;
3867 DEBUG(0,("send_file_readX: sendfile failed for file "
3868 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3869 strerror(errno)));
3870 exit_server_cleanly("send_file_readX sendfile failed");
3871 } else if (nread == 0) {
3873 * Some sendfile implementations return 0 to indicate
3874 * that there was a short read, but nothing was
3875 * actually written to the socket. In this case,
3876 * fallback to the normal read path so the header gets
3877 * the correct byte count.
3879 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3880 "falling back to the normal read: %s\n",
3881 fsp_str_dbg(fsp)));
3882 goto normal_read;
3885 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3886 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3888 /* Deal with possible short send. */
3889 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3890 ssize_t ret;
3892 ret = sendfile_short_send(xconn, fsp, nread,
3893 sizeof(headerbuf), smb_maxcnt);
3894 if (ret == -1) {
3895 const char *r;
3896 r = "send_file_readX: sendfile_short_send failed";
3897 DEBUG(0,("%s for file %s (%s).\n",
3898 r, fsp_str_dbg(fsp), strerror(errno)));
3899 exit_server_cleanly(r);
3902 /* No outbuf here means successful sendfile. */
3903 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3904 SMB_PERFCOUNT_END(&req->pcd);
3905 goto strict_unlock;
3908 normal_read:
3910 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3911 uint8 headerbuf[smb_size + 2*12 + 1 /* padding byte */];
3912 ssize_t ret;
3914 construct_reply_common_req(req, (char *)headerbuf);
3915 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3917 /* Send out the header. */
3918 ret = write_data(xconn->transport.sock, (char *)headerbuf,
3919 sizeof(headerbuf));
3920 if (ret != sizeof(headerbuf)) {
3921 saved_errno = errno;
3923 * Try and give an error message saying what
3924 * client failed.
3926 DEBUG(0,("send_file_readX: write_data failed for file "
3927 "%s (%s) for client %s. Terminating\n",
3928 fsp_str_dbg(fsp),
3929 smbXsrv_connection_dbg(xconn),
3930 strerror(saved_errno)));
3931 errno = saved_errno;
3932 exit_server_cleanly("send_file_readX sendfile failed");
3934 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
3935 if (nread == -1) {
3936 saved_errno = errno;
3937 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
3938 "%s (%s) for client %s. Terminating\n",
3939 fsp_str_dbg(fsp),
3940 smbXsrv_connection_dbg(xconn),
3941 strerror(saved_errno)));
3942 errno = saved_errno;
3943 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3945 goto strict_unlock;
3948 nosendfile_read:
3950 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
3951 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3952 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3954 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
3955 startpos, smb_maxcnt);
3956 saved_errno = errno;
3958 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3960 if (nread < 0) {
3961 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3962 return;
3965 setup_readX_header(req, (char *)req->outbuf, nread);
3967 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3968 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3969 return;
3971 strict_unlock:
3972 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3973 TALLOC_FREE(req->outbuf);
3974 return;
3977 /****************************************************************************
3978 Work out how much space we have for a read return.
3979 ****************************************************************************/
3981 static size_t calc_max_read_pdu(const struct smb_request *req)
3983 struct smbXsrv_connection *xconn = req->xconn;
3985 if (xconn->protocol < PROTOCOL_NT1) {
3986 return xconn->smb1.sessions.max_send;
3989 if (!lp_large_readwrite()) {
3990 return xconn->smb1.sessions.max_send;
3993 if (req_is_in_chain(req)) {
3994 return xconn->smb1.sessions.max_send;
3997 if (req->encrypted) {
3999 * Don't take encrypted traffic up to the
4000 * limit. There are padding considerations
4001 * that make that tricky.
4003 return xconn->smb1.sessions.max_send;
4006 if (srv_is_signing_active(xconn)) {
4007 return 0x1FFFF;
4010 if (!lp_unix_extensions()) {
4011 return 0x1FFFF;
4015 * We can do ultra-large POSIX reads.
4017 return 0xFFFFFF;
4020 /****************************************************************************
4021 Calculate how big a read can be. Copes with all clients. It's always
4022 safe to return a short read - Windows does this.
4023 ****************************************************************************/
4025 static size_t calc_read_size(const struct smb_request *req,
4026 size_t upper_size,
4027 size_t lower_size)
4029 struct smbXsrv_connection *xconn = req->xconn;
4030 size_t max_pdu = calc_max_read_pdu(req);
4031 size_t total_size = 0;
4032 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4033 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4036 * Windows explicitly ignores upper size of 0xFFFF.
4037 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4038 * We must do the same as these will never fit even in
4039 * an extended size NetBIOS packet.
4041 if (upper_size == 0xFFFF) {
4042 upper_size = 0;
4045 if (xconn->protocol < PROTOCOL_NT1) {
4046 upper_size = 0;
4049 total_size = ((upper_size<<16) | lower_size);
4052 * LARGE_READX test shows it's always safe to return
4053 * a short read. Windows does so.
4055 return MIN(total_size, max_len);
4058 /****************************************************************************
4059 Reply to a read and X.
4060 ****************************************************************************/
4062 void reply_read_and_X(struct smb_request *req)
4064 connection_struct *conn = req->conn;
4065 files_struct *fsp;
4066 off_t startpos;
4067 size_t smb_maxcnt;
4068 size_t upper_size;
4069 bool big_readX = False;
4070 #if 0
4071 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4072 #endif
4074 START_PROFILE(SMBreadX);
4076 if ((req->wct != 10) && (req->wct != 12)) {
4077 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4078 return;
4081 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4082 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4083 smb_maxcnt = SVAL(req->vwv+5, 0);
4085 /* If it's an IPC, pass off the pipe handler. */
4086 if (IS_IPC(conn)) {
4087 reply_pipe_read_and_X(req);
4088 END_PROFILE(SMBreadX);
4089 return;
4092 if (!check_fsp(conn, req, fsp)) {
4093 END_PROFILE(SMBreadX);
4094 return;
4097 if (!CHECK_READ(fsp,req)) {
4098 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4099 END_PROFILE(SMBreadX);
4100 return;
4103 upper_size = SVAL(req->vwv+7, 0);
4104 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4105 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4107 * This is a heuristic to avoid keeping large
4108 * outgoing buffers around over long-lived aio
4109 * requests.
4111 big_readX = True;
4114 if (req->wct == 12) {
4116 * This is a large offset (64 bit) read.
4118 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4122 if (!big_readX) {
4123 NTSTATUS status = schedule_aio_read_and_X(conn,
4124 req,
4125 fsp,
4126 startpos,
4127 smb_maxcnt);
4128 if (NT_STATUS_IS_OK(status)) {
4129 /* Read scheduled - we're done. */
4130 goto out;
4132 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4133 /* Real error - report to client. */
4134 END_PROFILE(SMBreadX);
4135 reply_nterror(req, status);
4136 return;
4138 /* NT_STATUS_RETRY - fall back to sync read. */
4141 smbd_lock_socket(req->xconn);
4142 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4143 smbd_unlock_socket(req->xconn);
4145 out:
4146 END_PROFILE(SMBreadX);
4147 return;
4150 /****************************************************************************
4151 Error replies to writebraw must have smb_wct == 1. Fix this up.
4152 ****************************************************************************/
4154 void error_to_writebrawerr(struct smb_request *req)
4156 uint8 *old_outbuf = req->outbuf;
4158 reply_outbuf(req, 1, 0);
4160 memcpy(req->outbuf, old_outbuf, smb_size);
4161 TALLOC_FREE(old_outbuf);
4164 /****************************************************************************
4165 Read 4 bytes of a smb packet and return the smb length of the packet.
4166 Store the result in the buffer. This version of the function will
4167 never return a session keepalive (length of zero).
4168 Timeout is in milliseconds.
4169 ****************************************************************************/
4171 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4172 size_t *len)
4174 uint8_t msgtype = NBSSkeepalive;
4176 while (msgtype == NBSSkeepalive) {
4177 NTSTATUS status;
4179 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4180 len);
4181 if (!NT_STATUS_IS_OK(status)) {
4182 char addr[INET6_ADDRSTRLEN];
4183 /* Try and give an error message
4184 * saying what client failed. */
4185 DEBUG(0, ("read_fd_with_timeout failed for "
4186 "client %s read error = %s.\n",
4187 get_peer_addr(fd,addr,sizeof(addr)),
4188 nt_errstr(status)));
4189 return status;
4192 msgtype = CVAL(inbuf, 0);
4195 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4196 (unsigned long)len));
4198 return NT_STATUS_OK;
4201 /****************************************************************************
4202 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4203 ****************************************************************************/
4205 void reply_writebraw(struct smb_request *req)
4207 connection_struct *conn = req->conn;
4208 struct smbXsrv_connection *xconn = req->xconn;
4209 char *buf = NULL;
4210 ssize_t nwritten=0;
4211 ssize_t total_written=0;
4212 size_t numtowrite=0;
4213 size_t tcount;
4214 off_t startpos;
4215 const char *data=NULL;
4216 bool write_through;
4217 files_struct *fsp;
4218 struct lock_struct lock;
4219 NTSTATUS status;
4221 START_PROFILE(SMBwritebraw);
4224 * If we ever reply with an error, it must have the SMB command
4225 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4226 * we're finished.
4228 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4230 if (srv_is_signing_active(xconn)) {
4231 END_PROFILE(SMBwritebraw);
4232 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4233 "raw reads/writes are disallowed.");
4236 if (req->wct < 12) {
4237 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4238 error_to_writebrawerr(req);
4239 END_PROFILE(SMBwritebraw);
4240 return;
4243 if (xconn->smb1.echo_handler.trusted_fde) {
4244 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4245 "'async smb echo handler = yes'\n"));
4246 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4247 error_to_writebrawerr(req);
4248 END_PROFILE(SMBwritebraw);
4249 return;
4252 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4253 if (!check_fsp(conn, req, fsp)) {
4254 error_to_writebrawerr(req);
4255 END_PROFILE(SMBwritebraw);
4256 return;
4259 if (!CHECK_WRITE(fsp)) {
4260 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4261 error_to_writebrawerr(req);
4262 END_PROFILE(SMBwritebraw);
4263 return;
4266 tcount = IVAL(req->vwv+1, 0);
4267 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4268 write_through = BITSETW(req->vwv+7,0);
4270 /* We have to deal with slightly different formats depending
4271 on whether we are using the core+ or lanman1.0 protocol */
4273 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4274 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4275 data = smb_buf_const(req->inbuf);
4276 } else {
4277 numtowrite = SVAL(req->vwv+10, 0);
4278 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4281 /* Ensure we don't write bytes past the end of this packet. */
4282 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4283 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4284 error_to_writebrawerr(req);
4285 END_PROFILE(SMBwritebraw);
4286 return;
4289 if (!fsp->print_file) {
4290 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4291 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4292 &lock);
4294 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4295 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4296 error_to_writebrawerr(req);
4297 END_PROFILE(SMBwritebraw);
4298 return;
4302 if (numtowrite>0) {
4303 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4306 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4307 "wrote=%d sync=%d\n",
4308 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4309 (int)nwritten, (int)write_through));
4311 if (nwritten < (ssize_t)numtowrite) {
4312 reply_nterror(req, NT_STATUS_DISK_FULL);
4313 error_to_writebrawerr(req);
4314 goto strict_unlock;
4317 total_written = nwritten;
4319 /* Allocate a buffer of 64k + length. */
4320 buf = talloc_array(NULL, char, 65540);
4321 if (!buf) {
4322 reply_nterror(req, NT_STATUS_NO_MEMORY);
4323 error_to_writebrawerr(req);
4324 goto strict_unlock;
4327 /* Return a SMBwritebraw message to the redirector to tell
4328 * it to send more bytes */
4330 memcpy(buf, req->inbuf, smb_size);
4331 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4332 SCVAL(buf,smb_com,SMBwritebraw);
4333 SSVALS(buf,smb_vwv0,0xFFFF);
4334 show_msg(buf);
4335 if (!srv_send_smb(req->xconn,
4336 buf,
4337 false, 0, /* no signing */
4338 IS_CONN_ENCRYPTED(conn),
4339 &req->pcd)) {
4340 exit_server_cleanly("reply_writebraw: srv_send_smb "
4341 "failed.");
4344 /* Now read the raw data into the buffer and write it */
4345 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4346 &numtowrite);
4347 if (!NT_STATUS_IS_OK(status)) {
4348 exit_server_cleanly("secondary writebraw failed");
4351 /* Set up outbuf to return the correct size */
4352 reply_outbuf(req, 1, 0);
4354 if (numtowrite != 0) {
4356 if (numtowrite > 0xFFFF) {
4357 DEBUG(0,("reply_writebraw: Oversize secondary write "
4358 "raw requested (%u). Terminating\n",
4359 (unsigned int)numtowrite ));
4360 exit_server_cleanly("secondary writebraw failed");
4363 if (tcount > nwritten+numtowrite) {
4364 DEBUG(3,("reply_writebraw: Client overestimated the "
4365 "write %d %d %d\n",
4366 (int)tcount,(int)nwritten,(int)numtowrite));
4369 status = read_data(xconn->transport.sock, buf+4, numtowrite);
4371 if (!NT_STATUS_IS_OK(status)) {
4372 /* Try and give an error message
4373 * saying what client failed. */
4374 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4375 "raw read failed (%s) for client %s. "
4376 "Terminating\n", nt_errstr(status),
4377 smbXsrv_connection_dbg(xconn)));
4378 exit_server_cleanly("secondary writebraw failed");
4381 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4382 if (nwritten == -1) {
4383 TALLOC_FREE(buf);
4384 reply_nterror(req, map_nt_error_from_unix(errno));
4385 error_to_writebrawerr(req);
4386 goto strict_unlock;
4389 if (nwritten < (ssize_t)numtowrite) {
4390 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4391 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4394 if (nwritten > 0) {
4395 total_written += nwritten;
4399 TALLOC_FREE(buf);
4400 SSVAL(req->outbuf,smb_vwv0,total_written);
4402 status = sync_file(conn, fsp, write_through);
4403 if (!NT_STATUS_IS_OK(status)) {
4404 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4405 fsp_str_dbg(fsp), nt_errstr(status)));
4406 reply_nterror(req, status);
4407 error_to_writebrawerr(req);
4408 goto strict_unlock;
4411 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4412 "wrote=%d\n",
4413 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4414 (int)total_written));
4416 if (!fsp->print_file) {
4417 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4420 /* We won't return a status if write through is not selected - this
4421 * follows what WfWg does */
4422 END_PROFILE(SMBwritebraw);
4424 if (!write_through && total_written==tcount) {
4426 #if RABBIT_PELLET_FIX
4428 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4429 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4430 * JRA.
4432 if (!send_keepalive(xconn->transport.sock)) {
4433 exit_server_cleanly("reply_writebraw: send of "
4434 "keepalive failed");
4436 #endif
4437 TALLOC_FREE(req->outbuf);
4439 return;
4441 strict_unlock:
4442 if (!fsp->print_file) {
4443 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4446 END_PROFILE(SMBwritebraw);
4447 return;
4450 #undef DBGC_CLASS
4451 #define DBGC_CLASS DBGC_LOCKING
4453 /****************************************************************************
4454 Reply to a writeunlock (core+).
4455 ****************************************************************************/
4457 void reply_writeunlock(struct smb_request *req)
4459 connection_struct *conn = req->conn;
4460 ssize_t nwritten = -1;
4461 size_t numtowrite;
4462 off_t startpos;
4463 const char *data;
4464 NTSTATUS status = NT_STATUS_OK;
4465 files_struct *fsp;
4466 struct lock_struct lock;
4467 int saved_errno = 0;
4469 START_PROFILE(SMBwriteunlock);
4471 if (req->wct < 5) {
4472 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4473 END_PROFILE(SMBwriteunlock);
4474 return;
4477 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4479 if (!check_fsp(conn, req, fsp)) {
4480 END_PROFILE(SMBwriteunlock);
4481 return;
4484 if (!CHECK_WRITE(fsp)) {
4485 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4486 END_PROFILE(SMBwriteunlock);
4487 return;
4490 numtowrite = SVAL(req->vwv+1, 0);
4491 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4492 data = (const char *)req->buf + 3;
4494 if (!fsp->print_file && numtowrite > 0) {
4495 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4496 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4497 &lock);
4499 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4500 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4501 END_PROFILE(SMBwriteunlock);
4502 return;
4506 /* The special X/Open SMB protocol handling of
4507 zero length writes is *NOT* done for
4508 this call */
4509 if(numtowrite == 0) {
4510 nwritten = 0;
4511 } else {
4512 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4513 saved_errno = errno;
4516 status = sync_file(conn, fsp, False /* write through */);
4517 if (!NT_STATUS_IS_OK(status)) {
4518 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4519 fsp_str_dbg(fsp), nt_errstr(status)));
4520 reply_nterror(req, status);
4521 goto strict_unlock;
4524 if(nwritten < 0) {
4525 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4526 goto strict_unlock;
4529 if((nwritten < numtowrite) && (numtowrite != 0)) {
4530 reply_nterror(req, NT_STATUS_DISK_FULL);
4531 goto strict_unlock;
4534 if (numtowrite && !fsp->print_file) {
4535 status = do_unlock(req->sconn->msg_ctx,
4536 fsp,
4537 (uint64_t)req->smbpid,
4538 (uint64_t)numtowrite,
4539 (uint64_t)startpos,
4540 WINDOWS_LOCK);
4542 if (NT_STATUS_V(status)) {
4543 reply_nterror(req, status);
4544 goto strict_unlock;
4548 reply_outbuf(req, 1, 0);
4550 SSVAL(req->outbuf,smb_vwv0,nwritten);
4552 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4553 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4555 strict_unlock:
4556 if (numtowrite && !fsp->print_file) {
4557 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4560 END_PROFILE(SMBwriteunlock);
4561 return;
4564 #undef DBGC_CLASS
4565 #define DBGC_CLASS DBGC_ALL
4567 /****************************************************************************
4568 Reply to a write.
4569 ****************************************************************************/
4571 void reply_write(struct smb_request *req)
4573 connection_struct *conn = req->conn;
4574 size_t numtowrite;
4575 ssize_t nwritten = -1;
4576 off_t startpos;
4577 const char *data;
4578 files_struct *fsp;
4579 struct lock_struct lock;
4580 NTSTATUS status;
4581 int saved_errno = 0;
4583 START_PROFILE(SMBwrite);
4585 if (req->wct < 5) {
4586 END_PROFILE(SMBwrite);
4587 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4588 return;
4591 /* If it's an IPC, pass off the pipe handler. */
4592 if (IS_IPC(conn)) {
4593 reply_pipe_write(req);
4594 END_PROFILE(SMBwrite);
4595 return;
4598 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4600 if (!check_fsp(conn, req, fsp)) {
4601 END_PROFILE(SMBwrite);
4602 return;
4605 if (!CHECK_WRITE(fsp)) {
4606 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4607 END_PROFILE(SMBwrite);
4608 return;
4611 numtowrite = SVAL(req->vwv+1, 0);
4612 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4613 data = (const char *)req->buf + 3;
4615 if (!fsp->print_file) {
4616 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4617 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4618 &lock);
4620 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4621 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4622 END_PROFILE(SMBwrite);
4623 return;
4628 * X/Open SMB protocol says that if smb_vwv1 is
4629 * zero then the file size should be extended or
4630 * truncated to the size given in smb_vwv[2-3].
4633 if(numtowrite == 0) {
4635 * This is actually an allocate call, and set EOF. JRA.
4637 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4638 if (nwritten < 0) {
4639 reply_nterror(req, NT_STATUS_DISK_FULL);
4640 goto strict_unlock;
4642 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4643 if (nwritten < 0) {
4644 reply_nterror(req, NT_STATUS_DISK_FULL);
4645 goto strict_unlock;
4647 trigger_write_time_update_immediate(fsp);
4648 } else {
4649 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4652 status = sync_file(conn, fsp, False);
4653 if (!NT_STATUS_IS_OK(status)) {
4654 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4655 fsp_str_dbg(fsp), nt_errstr(status)));
4656 reply_nterror(req, status);
4657 goto strict_unlock;
4660 if(nwritten < 0) {
4661 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4662 goto strict_unlock;
4665 if((nwritten == 0) && (numtowrite != 0)) {
4666 reply_nterror(req, NT_STATUS_DISK_FULL);
4667 goto strict_unlock;
4670 reply_outbuf(req, 1, 0);
4672 SSVAL(req->outbuf,smb_vwv0,nwritten);
4674 if (nwritten < (ssize_t)numtowrite) {
4675 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4676 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4679 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4681 strict_unlock:
4682 if (!fsp->print_file) {
4683 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4686 END_PROFILE(SMBwrite);
4687 return;
4690 /****************************************************************************
4691 Ensure a buffer is a valid writeX for recvfile purposes.
4692 ****************************************************************************/
4694 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4695 (2*14) + /* word count (including bcc) */ \
4696 1 /* pad byte */)
4698 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4699 const uint8_t *inbuf)
4701 size_t numtowrite;
4702 unsigned int doff = 0;
4703 size_t len = smb_len_large(inbuf);
4704 uint16_t fnum;
4705 struct smbXsrv_open *op = NULL;
4706 struct files_struct *fsp = NULL;
4707 NTSTATUS status;
4709 if (is_encrypted_packet(inbuf)) {
4710 /* Can't do this on encrypted
4711 * connections. */
4712 return false;
4715 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4716 return false;
4719 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4720 CVAL(inbuf,smb_wct) != 14) {
4721 DEBUG(10,("is_valid_writeX_buffer: chained or "
4722 "invalid word length.\n"));
4723 return false;
4726 fnum = SVAL(inbuf, smb_vwv2);
4727 status = smb1srv_open_lookup(xconn,
4728 fnum,
4729 0, /* now */
4730 &op);
4731 if (!NT_STATUS_IS_OK(status)) {
4732 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4733 return false;
4735 fsp = op->compat;
4736 if (fsp == NULL) {
4737 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4738 return false;
4740 if (fsp->conn == NULL) {
4741 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4742 return false;
4745 if (IS_IPC(fsp->conn)) {
4746 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4747 return false;
4749 if (IS_PRINT(fsp->conn)) {
4750 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4751 return false;
4753 doff = SVAL(inbuf,smb_vwv11);
4755 numtowrite = SVAL(inbuf,smb_vwv10);
4757 if (len > doff && len - doff > 0xFFFF) {
4758 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4761 if (numtowrite == 0) {
4762 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4763 return false;
4766 /* Ensure the sizes match up. */
4767 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4768 /* no pad byte...old smbclient :-( */
4769 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4770 (unsigned int)doff,
4771 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4772 return false;
4775 if (len - doff != numtowrite) {
4776 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4777 "len = %u, doff = %u, numtowrite = %u\n",
4778 (unsigned int)len,
4779 (unsigned int)doff,
4780 (unsigned int)numtowrite ));
4781 return false;
4784 DEBUG(10,("is_valid_writeX_buffer: true "
4785 "len = %u, doff = %u, numtowrite = %u\n",
4786 (unsigned int)len,
4787 (unsigned int)doff,
4788 (unsigned int)numtowrite ));
4790 return true;
4793 /****************************************************************************
4794 Reply to a write and X.
4795 ****************************************************************************/
4797 void reply_write_and_X(struct smb_request *req)
4799 connection_struct *conn = req->conn;
4800 struct smbXsrv_connection *xconn = req->xconn;
4801 files_struct *fsp;
4802 struct lock_struct lock;
4803 off_t startpos;
4804 size_t numtowrite;
4805 bool write_through;
4806 ssize_t nwritten;
4807 unsigned int smb_doff;
4808 unsigned int smblen;
4809 const char *data;
4810 NTSTATUS status;
4811 int saved_errno = 0;
4813 START_PROFILE(SMBwriteX);
4815 if ((req->wct != 12) && (req->wct != 14)) {
4816 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4817 goto out;
4820 numtowrite = SVAL(req->vwv+10, 0);
4821 smb_doff = SVAL(req->vwv+11, 0);
4822 smblen = smb_len(req->inbuf);
4824 if (req->unread_bytes > 0xFFFF ||
4825 (smblen > smb_doff &&
4826 smblen - smb_doff > 0xFFFF)) {
4827 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4830 if (req->unread_bytes) {
4831 /* Can't do a recvfile write on IPC$ */
4832 if (IS_IPC(conn)) {
4833 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4834 goto out;
4836 if (numtowrite != req->unread_bytes) {
4837 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4838 goto out;
4840 } else {
4841 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4842 smb_doff + numtowrite > smblen) {
4843 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4844 goto out;
4848 /* If it's an IPC, pass off the pipe handler. */
4849 if (IS_IPC(conn)) {
4850 if (req->unread_bytes) {
4851 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4852 goto out;
4854 reply_pipe_write_and_X(req);
4855 goto out;
4858 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4859 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4860 write_through = BITSETW(req->vwv+7,0);
4862 if (!check_fsp(conn, req, fsp)) {
4863 goto out;
4866 if (!CHECK_WRITE(fsp)) {
4867 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4868 goto out;
4871 data = smb_base(req->inbuf) + smb_doff;
4873 if(req->wct == 14) {
4875 * This is a large offset (64 bit) write.
4877 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4881 /* X/Open SMB protocol says that, unlike SMBwrite
4882 if the length is zero then NO truncation is
4883 done, just a write of zero. To truncate a file,
4884 use SMBwrite. */
4886 if(numtowrite == 0) {
4887 nwritten = 0;
4888 } else {
4889 if (req->unread_bytes == 0) {
4890 status = schedule_aio_write_and_X(conn,
4891 req,
4892 fsp,
4893 data,
4894 startpos,
4895 numtowrite);
4897 if (NT_STATUS_IS_OK(status)) {
4898 /* write scheduled - we're done. */
4899 goto out;
4901 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4902 /* Real error - report to client. */
4903 reply_nterror(req, status);
4904 goto out;
4906 /* NT_STATUS_RETRY - fall through to sync write. */
4909 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4910 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4911 &lock);
4913 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4914 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4915 goto out;
4918 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4919 saved_errno = errno;
4921 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4924 if(nwritten < 0) {
4925 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4926 goto out;
4929 if((nwritten == 0) && (numtowrite != 0)) {
4930 reply_nterror(req, NT_STATUS_DISK_FULL);
4931 goto out;
4934 reply_outbuf(req, 6, 0);
4935 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4936 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4937 SSVAL(req->outbuf,smb_vwv2,nwritten);
4938 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4940 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4941 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4943 status = sync_file(conn, fsp, write_through);
4944 if (!NT_STATUS_IS_OK(status)) {
4945 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4946 fsp_str_dbg(fsp), nt_errstr(status)));
4947 reply_nterror(req, status);
4948 goto out;
4951 END_PROFILE(SMBwriteX);
4952 return;
4954 out:
4955 if (req->unread_bytes) {
4956 /* writeX failed. drain socket. */
4957 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
4958 req->unread_bytes) {
4959 smb_panic("failed to drain pending bytes");
4961 req->unread_bytes = 0;
4964 END_PROFILE(SMBwriteX);
4965 return;
4968 /****************************************************************************
4969 Reply to a lseek.
4970 ****************************************************************************/
4972 void reply_lseek(struct smb_request *req)
4974 connection_struct *conn = req->conn;
4975 off_t startpos;
4976 off_t res= -1;
4977 int mode,umode;
4978 files_struct *fsp;
4980 START_PROFILE(SMBlseek);
4982 if (req->wct < 4) {
4983 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4984 END_PROFILE(SMBlseek);
4985 return;
4988 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4990 if (!check_fsp(conn, req, fsp)) {
4991 return;
4994 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
4996 mode = SVAL(req->vwv+1, 0) & 3;
4997 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4998 startpos = (off_t)IVALS(req->vwv+2, 0);
5000 switch (mode) {
5001 case 0:
5002 umode = SEEK_SET;
5003 res = startpos;
5004 break;
5005 case 1:
5006 umode = SEEK_CUR;
5007 res = fsp->fh->pos + startpos;
5008 break;
5009 case 2:
5010 umode = SEEK_END;
5011 break;
5012 default:
5013 umode = SEEK_SET;
5014 res = startpos;
5015 break;
5018 if (umode == SEEK_END) {
5019 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5020 if(errno == EINVAL) {
5021 off_t current_pos = startpos;
5023 if(fsp_stat(fsp) == -1) {
5024 reply_nterror(req,
5025 map_nt_error_from_unix(errno));
5026 END_PROFILE(SMBlseek);
5027 return;
5030 current_pos += fsp->fsp_name->st.st_ex_size;
5031 if(current_pos < 0)
5032 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5036 if(res == -1) {
5037 reply_nterror(req, map_nt_error_from_unix(errno));
5038 END_PROFILE(SMBlseek);
5039 return;
5043 fsp->fh->pos = res;
5045 reply_outbuf(req, 2, 0);
5046 SIVAL(req->outbuf,smb_vwv0,res);
5048 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5049 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5051 END_PROFILE(SMBlseek);
5052 return;
5055 /****************************************************************************
5056 Reply to a flush.
5057 ****************************************************************************/
5059 void reply_flush(struct smb_request *req)
5061 connection_struct *conn = req->conn;
5062 uint16 fnum;
5063 files_struct *fsp;
5065 START_PROFILE(SMBflush);
5067 if (req->wct < 1) {
5068 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5069 return;
5072 fnum = SVAL(req->vwv+0, 0);
5073 fsp = file_fsp(req, fnum);
5075 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5076 return;
5079 if (!fsp) {
5080 file_sync_all(conn);
5081 } else {
5082 NTSTATUS status = sync_file(conn, fsp, True);
5083 if (!NT_STATUS_IS_OK(status)) {
5084 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5085 fsp_str_dbg(fsp), nt_errstr(status)));
5086 reply_nterror(req, status);
5087 END_PROFILE(SMBflush);
5088 return;
5092 reply_outbuf(req, 0, 0);
5094 DEBUG(3,("flush\n"));
5095 END_PROFILE(SMBflush);
5096 return;
5099 /****************************************************************************
5100 Reply to a exit.
5101 conn POINTER CAN BE NULL HERE !
5102 ****************************************************************************/
5104 void reply_exit(struct smb_request *req)
5106 START_PROFILE(SMBexit);
5108 file_close_pid(req->sconn, req->smbpid, req->vuid);
5110 reply_outbuf(req, 0, 0);
5112 DEBUG(3,("exit\n"));
5114 END_PROFILE(SMBexit);
5115 return;
5118 struct reply_close_state {
5119 files_struct *fsp;
5120 struct smb_request *smbreq;
5123 static void do_smb1_close(struct tevent_req *req);
5125 void reply_close(struct smb_request *req)
5127 connection_struct *conn = req->conn;
5128 NTSTATUS status = NT_STATUS_OK;
5129 files_struct *fsp = NULL;
5130 START_PROFILE(SMBclose);
5132 if (req->wct < 3) {
5133 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5134 END_PROFILE(SMBclose);
5135 return;
5138 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5141 * We can only use check_fsp if we know it's not a directory.
5144 if (!check_fsp_open(conn, req, fsp)) {
5145 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5146 END_PROFILE(SMBclose);
5147 return;
5150 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5151 fsp->is_directory ? "directory" : "file",
5152 fsp->fh->fd, fsp_fnum_dbg(fsp),
5153 conn->num_files_open));
5155 if (!fsp->is_directory) {
5156 time_t t;
5159 * Take care of any time sent in the close.
5162 t = srv_make_unix_date3(req->vwv+1);
5163 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5166 if (fsp->num_aio_requests != 0) {
5168 struct reply_close_state *state;
5170 DEBUG(10, ("closing with aio %u requests pending\n",
5171 fsp->num_aio_requests));
5174 * We depend on the aio_extra destructor to take care of this
5175 * close request once fsp->num_aio_request drops to 0.
5178 fsp->deferred_close = tevent_wait_send(
5179 fsp, fsp->conn->sconn->ev_ctx);
5180 if (fsp->deferred_close == NULL) {
5181 status = NT_STATUS_NO_MEMORY;
5182 goto done;
5185 state = talloc(fsp, struct reply_close_state);
5186 if (state == NULL) {
5187 TALLOC_FREE(fsp->deferred_close);
5188 status = NT_STATUS_NO_MEMORY;
5189 goto done;
5191 state->fsp = fsp;
5192 state->smbreq = talloc_move(fsp, &req);
5193 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5194 state);
5195 END_PROFILE(SMBclose);
5196 return;
5200 * close_file() returns the unix errno if an error was detected on
5201 * close - normally this is due to a disk full error. If not then it
5202 * was probably an I/O error.
5205 status = close_file(req, fsp, NORMAL_CLOSE);
5206 done:
5207 if (!NT_STATUS_IS_OK(status)) {
5208 reply_nterror(req, status);
5209 END_PROFILE(SMBclose);
5210 return;
5213 reply_outbuf(req, 0, 0);
5214 END_PROFILE(SMBclose);
5215 return;
5218 static void do_smb1_close(struct tevent_req *req)
5220 struct reply_close_state *state = tevent_req_callback_data(
5221 req, struct reply_close_state);
5222 struct smb_request *smbreq;
5223 NTSTATUS status;
5224 int ret;
5226 ret = tevent_wait_recv(req);
5227 TALLOC_FREE(req);
5228 if (ret != 0) {
5229 DEBUG(10, ("tevent_wait_recv returned %s\n",
5230 strerror(ret)));
5232 * Continue anyway, this should never happen
5237 * fsp->smb2_close_request right now is a talloc grandchild of
5238 * fsp. When we close_file(fsp), it would go with it. No chance to
5239 * reply...
5241 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5243 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5244 if (NT_STATUS_IS_OK(status)) {
5245 reply_outbuf(smbreq, 0, 0);
5246 } else {
5247 reply_nterror(smbreq, status);
5249 if (!srv_send_smb(smbreq->xconn,
5250 (char *)smbreq->outbuf,
5251 true,
5252 smbreq->seqnum+1,
5253 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5254 NULL)) {
5255 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5256 "failed.");
5258 TALLOC_FREE(smbreq);
5261 /****************************************************************************
5262 Reply to a writeclose (Core+ protocol).
5263 ****************************************************************************/
5265 void reply_writeclose(struct smb_request *req)
5267 connection_struct *conn = req->conn;
5268 size_t numtowrite;
5269 ssize_t nwritten = -1;
5270 NTSTATUS close_status = NT_STATUS_OK;
5271 off_t startpos;
5272 const char *data;
5273 struct timespec mtime;
5274 files_struct *fsp;
5275 struct lock_struct lock;
5277 START_PROFILE(SMBwriteclose);
5279 if (req->wct < 6) {
5280 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5281 END_PROFILE(SMBwriteclose);
5282 return;
5285 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5287 if (!check_fsp(conn, req, fsp)) {
5288 END_PROFILE(SMBwriteclose);
5289 return;
5291 if (!CHECK_WRITE(fsp)) {
5292 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5293 END_PROFILE(SMBwriteclose);
5294 return;
5297 numtowrite = SVAL(req->vwv+1, 0);
5298 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5299 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5300 data = (const char *)req->buf + 1;
5302 if (fsp->print_file == NULL) {
5303 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5304 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5305 &lock);
5307 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5308 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5309 END_PROFILE(SMBwriteclose);
5310 return;
5314 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5316 if (fsp->print_file == NULL) {
5317 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5320 set_close_write_time(fsp, mtime);
5323 * More insanity. W2K only closes the file if writelen > 0.
5324 * JRA.
5327 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5328 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5329 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5331 if (numtowrite) {
5332 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5333 "file %s\n", fsp_str_dbg(fsp)));
5334 close_status = close_file(req, fsp, NORMAL_CLOSE);
5335 fsp = NULL;
5338 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5339 reply_nterror(req, NT_STATUS_DISK_FULL);
5340 goto out;
5343 if(!NT_STATUS_IS_OK(close_status)) {
5344 reply_nterror(req, close_status);
5345 goto out;
5348 reply_outbuf(req, 1, 0);
5350 SSVAL(req->outbuf,smb_vwv0,nwritten);
5352 out:
5354 END_PROFILE(SMBwriteclose);
5355 return;
5358 #undef DBGC_CLASS
5359 #define DBGC_CLASS DBGC_LOCKING
5361 /****************************************************************************
5362 Reply to a lock.
5363 ****************************************************************************/
5365 void reply_lock(struct smb_request *req)
5367 connection_struct *conn = req->conn;
5368 uint64_t count,offset;
5369 NTSTATUS status;
5370 files_struct *fsp;
5371 struct byte_range_lock *br_lck = NULL;
5373 START_PROFILE(SMBlock);
5375 if (req->wct < 5) {
5376 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5377 END_PROFILE(SMBlock);
5378 return;
5381 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5383 if (!check_fsp(conn, req, fsp)) {
5384 END_PROFILE(SMBlock);
5385 return;
5388 count = (uint64_t)IVAL(req->vwv+1, 0);
5389 offset = (uint64_t)IVAL(req->vwv+3, 0);
5391 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5392 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5394 br_lck = do_lock(req->sconn->msg_ctx,
5395 fsp,
5396 (uint64_t)req->smbpid,
5397 count,
5398 offset,
5399 WRITE_LOCK,
5400 WINDOWS_LOCK,
5401 False, /* Non-blocking lock. */
5402 &status,
5403 NULL);
5405 TALLOC_FREE(br_lck);
5407 if (NT_STATUS_V(status)) {
5408 reply_nterror(req, status);
5409 END_PROFILE(SMBlock);
5410 return;
5413 reply_outbuf(req, 0, 0);
5415 END_PROFILE(SMBlock);
5416 return;
5419 /****************************************************************************
5420 Reply to a unlock.
5421 ****************************************************************************/
5423 void reply_unlock(struct smb_request *req)
5425 connection_struct *conn = req->conn;
5426 uint64_t count,offset;
5427 NTSTATUS status;
5428 files_struct *fsp;
5430 START_PROFILE(SMBunlock);
5432 if (req->wct < 5) {
5433 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5434 END_PROFILE(SMBunlock);
5435 return;
5438 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5440 if (!check_fsp(conn, req, fsp)) {
5441 END_PROFILE(SMBunlock);
5442 return;
5445 count = (uint64_t)IVAL(req->vwv+1, 0);
5446 offset = (uint64_t)IVAL(req->vwv+3, 0);
5448 status = do_unlock(req->sconn->msg_ctx,
5449 fsp,
5450 (uint64_t)req->smbpid,
5451 count,
5452 offset,
5453 WINDOWS_LOCK);
5455 if (NT_STATUS_V(status)) {
5456 reply_nterror(req, status);
5457 END_PROFILE(SMBunlock);
5458 return;
5461 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5462 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5464 reply_outbuf(req, 0, 0);
5466 END_PROFILE(SMBunlock);
5467 return;
5470 #undef DBGC_CLASS
5471 #define DBGC_CLASS DBGC_ALL
5473 /****************************************************************************
5474 Reply to a tdis.
5475 conn POINTER CAN BE NULL HERE !
5476 ****************************************************************************/
5478 void reply_tdis(struct smb_request *req)
5480 NTSTATUS status;
5481 connection_struct *conn = req->conn;
5482 struct smbXsrv_tcon *tcon;
5484 START_PROFILE(SMBtdis);
5486 if (!conn) {
5487 DEBUG(4,("Invalid connection in tdis\n"));
5488 reply_force_doserror(req, ERRSRV, ERRinvnid);
5489 END_PROFILE(SMBtdis);
5490 return;
5493 tcon = conn->tcon;
5494 req->conn = NULL;
5497 * TODO: cancel all outstanding requests on the tcon
5499 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5500 if (!NT_STATUS_IS_OK(status)) {
5501 DEBUG(0, ("reply_tdis: "
5502 "smbXsrv_tcon_disconnect() failed: %s\n",
5503 nt_errstr(status)));
5505 * If we hit this case, there is something completely
5506 * wrong, so we better disconnect the transport connection.
5508 END_PROFILE(SMBtdis);
5509 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5510 return;
5513 TALLOC_FREE(tcon);
5515 reply_outbuf(req, 0, 0);
5516 END_PROFILE(SMBtdis);
5517 return;
5520 /****************************************************************************
5521 Reply to a echo.
5522 conn POINTER CAN BE NULL HERE !
5523 ****************************************************************************/
5525 void reply_echo(struct smb_request *req)
5527 connection_struct *conn = req->conn;
5528 struct smb_perfcount_data local_pcd;
5529 struct smb_perfcount_data *cur_pcd;
5530 int smb_reverb;
5531 int seq_num;
5533 START_PROFILE(SMBecho);
5535 smb_init_perfcount_data(&local_pcd);
5537 if (req->wct < 1) {
5538 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5539 END_PROFILE(SMBecho);
5540 return;
5543 smb_reverb = SVAL(req->vwv+0, 0);
5545 reply_outbuf(req, 1, req->buflen);
5547 /* copy any incoming data back out */
5548 if (req->buflen > 0) {
5549 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5552 if (smb_reverb > 100) {
5553 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5554 smb_reverb = 100;
5557 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5559 /* this makes sure we catch the request pcd */
5560 if (seq_num == smb_reverb) {
5561 cur_pcd = &req->pcd;
5562 } else {
5563 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5564 cur_pcd = &local_pcd;
5567 SSVAL(req->outbuf,smb_vwv0,seq_num);
5569 show_msg((char *)req->outbuf);
5570 if (!srv_send_smb(req->xconn,
5571 (char *)req->outbuf,
5572 true, req->seqnum+1,
5573 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5574 cur_pcd))
5575 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5578 DEBUG(3,("echo %d times\n", smb_reverb));
5580 TALLOC_FREE(req->outbuf);
5582 END_PROFILE(SMBecho);
5583 return;
5586 /****************************************************************************
5587 Reply to a printopen.
5588 ****************************************************************************/
5590 void reply_printopen(struct smb_request *req)
5592 connection_struct *conn = req->conn;
5593 files_struct *fsp;
5594 NTSTATUS status;
5596 START_PROFILE(SMBsplopen);
5598 if (req->wct < 2) {
5599 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5600 END_PROFILE(SMBsplopen);
5601 return;
5604 if (!CAN_PRINT(conn)) {
5605 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5606 END_PROFILE(SMBsplopen);
5607 return;
5610 status = file_new(req, conn, &fsp);
5611 if(!NT_STATUS_IS_OK(status)) {
5612 reply_nterror(req, status);
5613 END_PROFILE(SMBsplopen);
5614 return;
5617 /* Open for exclusive use, write only. */
5618 status = print_spool_open(fsp, NULL, req->vuid);
5620 if (!NT_STATUS_IS_OK(status)) {
5621 file_free(req, fsp);
5622 reply_nterror(req, status);
5623 END_PROFILE(SMBsplopen);
5624 return;
5627 reply_outbuf(req, 1, 0);
5628 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5630 DEBUG(3,("openprint fd=%d %s\n",
5631 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5633 END_PROFILE(SMBsplopen);
5634 return;
5637 /****************************************************************************
5638 Reply to a printclose.
5639 ****************************************************************************/
5641 void reply_printclose(struct smb_request *req)
5643 connection_struct *conn = req->conn;
5644 files_struct *fsp;
5645 NTSTATUS status;
5647 START_PROFILE(SMBsplclose);
5649 if (req->wct < 1) {
5650 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5651 END_PROFILE(SMBsplclose);
5652 return;
5655 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5657 if (!check_fsp(conn, req, fsp)) {
5658 END_PROFILE(SMBsplclose);
5659 return;
5662 if (!CAN_PRINT(conn)) {
5663 reply_force_doserror(req, ERRSRV, ERRerror);
5664 END_PROFILE(SMBsplclose);
5665 return;
5668 DEBUG(3,("printclose fd=%d %s\n",
5669 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5671 status = close_file(req, fsp, NORMAL_CLOSE);
5673 if(!NT_STATUS_IS_OK(status)) {
5674 reply_nterror(req, status);
5675 END_PROFILE(SMBsplclose);
5676 return;
5679 reply_outbuf(req, 0, 0);
5681 END_PROFILE(SMBsplclose);
5682 return;
5685 /****************************************************************************
5686 Reply to a printqueue.
5687 ****************************************************************************/
5689 void reply_printqueue(struct smb_request *req)
5691 connection_struct *conn = req->conn;
5692 int max_count;
5693 int start_index;
5695 START_PROFILE(SMBsplretq);
5697 if (req->wct < 2) {
5698 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5699 END_PROFILE(SMBsplretq);
5700 return;
5703 max_count = SVAL(req->vwv+0, 0);
5704 start_index = SVAL(req->vwv+1, 0);
5706 /* we used to allow the client to get the cnum wrong, but that
5707 is really quite gross and only worked when there was only
5708 one printer - I think we should now only accept it if they
5709 get it right (tridge) */
5710 if (!CAN_PRINT(conn)) {
5711 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5712 END_PROFILE(SMBsplretq);
5713 return;
5716 reply_outbuf(req, 2, 3);
5717 SSVAL(req->outbuf,smb_vwv0,0);
5718 SSVAL(req->outbuf,smb_vwv1,0);
5719 SCVAL(smb_buf(req->outbuf),0,1);
5720 SSVAL(smb_buf(req->outbuf),1,0);
5722 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5723 start_index, max_count));
5726 TALLOC_CTX *mem_ctx = talloc_tos();
5727 NTSTATUS status;
5728 WERROR werr;
5729 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5730 struct rpc_pipe_client *cli = NULL;
5731 struct dcerpc_binding_handle *b = NULL;
5732 struct policy_handle handle;
5733 struct spoolss_DevmodeContainer devmode_ctr;
5734 union spoolss_JobInfo *info;
5735 uint32_t count;
5736 uint32_t num_to_get;
5737 uint32_t first;
5738 uint32_t i;
5740 ZERO_STRUCT(handle);
5742 status = rpc_pipe_open_interface(conn,
5743 &ndr_table_spoolss,
5744 conn->session_info,
5745 conn->sconn->remote_address,
5746 conn->sconn->msg_ctx,
5747 &cli);
5748 if (!NT_STATUS_IS_OK(status)) {
5749 DEBUG(0, ("reply_printqueue: "
5750 "could not connect to spoolss: %s\n",
5751 nt_errstr(status)));
5752 reply_nterror(req, status);
5753 goto out;
5755 b = cli->binding_handle;
5757 ZERO_STRUCT(devmode_ctr);
5759 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5760 sharename,
5761 NULL, devmode_ctr,
5762 SEC_FLAG_MAXIMUM_ALLOWED,
5763 &handle,
5764 &werr);
5765 if (!NT_STATUS_IS_OK(status)) {
5766 reply_nterror(req, status);
5767 goto out;
5769 if (!W_ERROR_IS_OK(werr)) {
5770 reply_nterror(req, werror_to_ntstatus(werr));
5771 goto out;
5774 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5775 &handle,
5776 0, /* firstjob */
5777 0xff, /* numjobs */
5778 2, /* level */
5779 0, /* offered */
5780 &count,
5781 &info);
5782 if (!W_ERROR_IS_OK(werr)) {
5783 reply_nterror(req, werror_to_ntstatus(werr));
5784 goto out;
5787 if (max_count > 0) {
5788 first = start_index;
5789 } else {
5790 first = start_index + max_count + 1;
5793 if (first >= count) {
5794 num_to_get = first;
5795 } else {
5796 num_to_get = first + MIN(ABS(max_count), count - first);
5799 for (i = first; i < num_to_get; i++) {
5800 char blob[28];
5801 char *p = blob;
5802 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5803 int qstatus;
5804 size_t len = 0;
5805 uint16_t qrapjobid = pjobid_to_rap(sharename,
5806 info[i].info2.job_id);
5808 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5809 qstatus = 2;
5810 } else {
5811 qstatus = 3;
5814 srv_put_dos_date2(p, 0, qtime);
5815 SCVAL(p, 4, qstatus);
5816 SSVAL(p, 5, qrapjobid);
5817 SIVAL(p, 7, info[i].info2.size);
5818 SCVAL(p, 11, 0);
5819 status = srvstr_push(blob, req->flags2, p+12,
5820 info[i].info2.notify_name, 16, STR_ASCII, &len);
5821 if (!NT_STATUS_IS_OK(status)) {
5822 reply_nterror(req, status);
5823 goto out;
5825 if (message_push_blob(
5826 &req->outbuf,
5827 data_blob_const(
5828 blob, sizeof(blob))) == -1) {
5829 reply_nterror(req, NT_STATUS_NO_MEMORY);
5830 goto out;
5834 if (count > 0) {
5835 SSVAL(req->outbuf,smb_vwv0,count);
5836 SSVAL(req->outbuf,smb_vwv1,
5837 (max_count>0?first+count:first-1));
5838 SCVAL(smb_buf(req->outbuf),0,1);
5839 SSVAL(smb_buf(req->outbuf),1,28*count);
5843 DEBUG(3, ("%u entries returned in queue\n",
5844 (unsigned)count));
5846 out:
5847 if (b && is_valid_policy_hnd(&handle)) {
5848 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5853 END_PROFILE(SMBsplretq);
5854 return;
5857 /****************************************************************************
5858 Reply to a printwrite.
5859 ****************************************************************************/
5861 void reply_printwrite(struct smb_request *req)
5863 connection_struct *conn = req->conn;
5864 int numtowrite;
5865 const char *data;
5866 files_struct *fsp;
5868 START_PROFILE(SMBsplwr);
5870 if (req->wct < 1) {
5871 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5872 END_PROFILE(SMBsplwr);
5873 return;
5876 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5878 if (!check_fsp(conn, req, fsp)) {
5879 END_PROFILE(SMBsplwr);
5880 return;
5883 if (!fsp->print_file) {
5884 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5885 END_PROFILE(SMBsplwr);
5886 return;
5889 if (!CHECK_WRITE(fsp)) {
5890 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5891 END_PROFILE(SMBsplwr);
5892 return;
5895 numtowrite = SVAL(req->buf, 1);
5897 if (req->buflen < numtowrite + 3) {
5898 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5899 END_PROFILE(SMBsplwr);
5900 return;
5903 data = (const char *)req->buf + 3;
5905 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5906 reply_nterror(req, map_nt_error_from_unix(errno));
5907 END_PROFILE(SMBsplwr);
5908 return;
5911 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5913 END_PROFILE(SMBsplwr);
5914 return;
5917 /****************************************************************************
5918 Reply to a mkdir.
5919 ****************************************************************************/
5921 void reply_mkdir(struct smb_request *req)
5923 connection_struct *conn = req->conn;
5924 struct smb_filename *smb_dname = NULL;
5925 char *directory = NULL;
5926 NTSTATUS status;
5927 TALLOC_CTX *ctx = talloc_tos();
5929 START_PROFILE(SMBmkdir);
5931 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5932 STR_TERMINATE, &status);
5933 if (!NT_STATUS_IS_OK(status)) {
5934 reply_nterror(req, status);
5935 goto out;
5938 status = filename_convert(ctx, conn,
5939 req->flags2 & FLAGS2_DFS_PATHNAMES,
5940 directory,
5941 UCF_PREP_CREATEFILE,
5942 NULL,
5943 &smb_dname);
5944 if (!NT_STATUS_IS_OK(status)) {
5945 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5946 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5947 ERRSRV, ERRbadpath);
5948 goto out;
5950 reply_nterror(req, status);
5951 goto out;
5954 status = create_directory(conn, req, smb_dname);
5956 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5958 if (!NT_STATUS_IS_OK(status)) {
5960 if (!use_nt_status()
5961 && NT_STATUS_EQUAL(status,
5962 NT_STATUS_OBJECT_NAME_COLLISION)) {
5964 * Yes, in the DOS error code case we get a
5965 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5966 * samba4 torture test.
5968 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5971 reply_nterror(req, status);
5972 goto out;
5975 reply_outbuf(req, 0, 0);
5977 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5978 out:
5979 TALLOC_FREE(smb_dname);
5980 END_PROFILE(SMBmkdir);
5981 return;
5984 /****************************************************************************
5985 Reply to a rmdir.
5986 ****************************************************************************/
5988 void reply_rmdir(struct smb_request *req)
5990 connection_struct *conn = req->conn;
5991 struct smb_filename *smb_dname = NULL;
5992 char *directory = NULL;
5993 NTSTATUS status;
5994 TALLOC_CTX *ctx = talloc_tos();
5995 files_struct *fsp = NULL;
5996 int info = 0;
5997 struct smbd_server_connection *sconn = req->sconn;
5999 START_PROFILE(SMBrmdir);
6001 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6002 STR_TERMINATE, &status);
6003 if (!NT_STATUS_IS_OK(status)) {
6004 reply_nterror(req, status);
6005 goto out;
6008 status = filename_convert(ctx, conn,
6009 req->flags2 & FLAGS2_DFS_PATHNAMES,
6010 directory,
6012 NULL,
6013 &smb_dname);
6014 if (!NT_STATUS_IS_OK(status)) {
6015 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6016 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6017 ERRSRV, ERRbadpath);
6018 goto out;
6020 reply_nterror(req, status);
6021 goto out;
6024 if (is_ntfs_stream_smb_fname(smb_dname)) {
6025 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6026 goto out;
6029 status = SMB_VFS_CREATE_FILE(
6030 conn, /* conn */
6031 req, /* req */
6032 0, /* root_dir_fid */
6033 smb_dname, /* fname */
6034 DELETE_ACCESS, /* access_mask */
6035 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6036 FILE_SHARE_DELETE),
6037 FILE_OPEN, /* create_disposition*/
6038 FILE_DIRECTORY_FILE, /* create_options */
6039 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6040 0, /* oplock_request */
6041 NULL, /* lease */
6042 0, /* allocation_size */
6043 0, /* private_flags */
6044 NULL, /* sd */
6045 NULL, /* ea_list */
6046 &fsp, /* result */
6047 &info, /* pinfo */
6048 NULL, NULL); /* create context */
6050 if (!NT_STATUS_IS_OK(status)) {
6051 if (open_was_deferred(req->xconn, req->mid)) {
6052 /* We have re-scheduled this call. */
6053 goto out;
6055 reply_nterror(req, status);
6056 goto out;
6059 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6060 if (!NT_STATUS_IS_OK(status)) {
6061 close_file(req, fsp, ERROR_CLOSE);
6062 reply_nterror(req, status);
6063 goto out;
6066 if (!set_delete_on_close(fsp, true,
6067 conn->session_info->security_token,
6068 conn->session_info->unix_token)) {
6069 close_file(req, fsp, ERROR_CLOSE);
6070 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6071 goto out;
6074 status = close_file(req, fsp, NORMAL_CLOSE);
6075 if (!NT_STATUS_IS_OK(status)) {
6076 reply_nterror(req, status);
6077 } else {
6078 reply_outbuf(req, 0, 0);
6081 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6083 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6084 out:
6085 TALLOC_FREE(smb_dname);
6086 END_PROFILE(SMBrmdir);
6087 return;
6090 /*******************************************************************
6091 Resolve wildcards in a filename rename.
6092 ********************************************************************/
6094 static bool resolve_wildcards(TALLOC_CTX *ctx,
6095 const char *name1,
6096 const char *name2,
6097 char **pp_newname)
6099 char *name2_copy = NULL;
6100 char *root1 = NULL;
6101 char *root2 = NULL;
6102 char *ext1 = NULL;
6103 char *ext2 = NULL;
6104 char *p,*p2, *pname1, *pname2;
6106 name2_copy = talloc_strdup(ctx, name2);
6107 if (!name2_copy) {
6108 return False;
6111 pname1 = strrchr_m(name1,'/');
6112 pname2 = strrchr_m(name2_copy,'/');
6114 if (!pname1 || !pname2) {
6115 return False;
6118 /* Truncate the copy of name2 at the last '/' */
6119 *pname2 = '\0';
6121 /* Now go past the '/' */
6122 pname1++;
6123 pname2++;
6125 root1 = talloc_strdup(ctx, pname1);
6126 root2 = talloc_strdup(ctx, pname2);
6128 if (!root1 || !root2) {
6129 return False;
6132 p = strrchr_m(root1,'.');
6133 if (p) {
6134 *p = 0;
6135 ext1 = talloc_strdup(ctx, p+1);
6136 } else {
6137 ext1 = talloc_strdup(ctx, "");
6139 p = strrchr_m(root2,'.');
6140 if (p) {
6141 *p = 0;
6142 ext2 = talloc_strdup(ctx, p+1);
6143 } else {
6144 ext2 = talloc_strdup(ctx, "");
6147 if (!ext1 || !ext2) {
6148 return False;
6151 p = root1;
6152 p2 = root2;
6153 while (*p2) {
6154 if (*p2 == '?') {
6155 /* Hmmm. Should this be mb-aware ? */
6156 *p2 = *p;
6157 p2++;
6158 } else if (*p2 == '*') {
6159 *p2 = '\0';
6160 root2 = talloc_asprintf(ctx, "%s%s",
6161 root2,
6163 if (!root2) {
6164 return False;
6166 break;
6167 } else {
6168 p2++;
6170 if (*p) {
6171 p++;
6175 p = ext1;
6176 p2 = ext2;
6177 while (*p2) {
6178 if (*p2 == '?') {
6179 /* Hmmm. Should this be mb-aware ? */
6180 *p2 = *p;
6181 p2++;
6182 } else if (*p2 == '*') {
6183 *p2 = '\0';
6184 ext2 = talloc_asprintf(ctx, "%s%s",
6185 ext2,
6187 if (!ext2) {
6188 return False;
6190 break;
6191 } else {
6192 p2++;
6194 if (*p) {
6195 p++;
6199 if (*ext2) {
6200 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6201 name2_copy,
6202 root2,
6203 ext2);
6204 } else {
6205 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6206 name2_copy,
6207 root2);
6210 if (!*pp_newname) {
6211 return False;
6214 return True;
6217 /****************************************************************************
6218 Ensure open files have their names updated. Updated to notify other smbd's
6219 asynchronously.
6220 ****************************************************************************/
6222 static void rename_open_files(connection_struct *conn,
6223 struct share_mode_lock *lck,
6224 struct file_id id,
6225 uint32_t orig_name_hash,
6226 const struct smb_filename *smb_fname_dst)
6228 files_struct *fsp;
6229 bool did_rename = False;
6230 NTSTATUS status;
6231 uint32_t new_name_hash = 0;
6233 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6234 fsp = file_find_di_next(fsp)) {
6235 /* fsp_name is a relative path under the fsp. To change this for other
6236 sharepaths we need to manipulate relative paths. */
6237 /* TODO - create the absolute path and manipulate the newname
6238 relative to the sharepath. */
6239 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6240 continue;
6242 if (fsp->name_hash != orig_name_hash) {
6243 continue;
6245 DEBUG(10, ("rename_open_files: renaming file %s "
6246 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6247 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6248 smb_fname_str_dbg(smb_fname_dst)));
6250 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6251 if (NT_STATUS_IS_OK(status)) {
6252 did_rename = True;
6253 new_name_hash = fsp->name_hash;
6257 if (!did_rename) {
6258 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6259 "for %s\n", file_id_string_tos(&id),
6260 smb_fname_str_dbg(smb_fname_dst)));
6263 /* Send messages to all smbd's (not ourself) that the name has changed. */
6264 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6265 orig_name_hash, new_name_hash,
6266 smb_fname_dst);
6270 /****************************************************************************
6271 We need to check if the source path is a parent directory of the destination
6272 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6273 refuse the rename with a sharing violation. Under UNIX the above call can
6274 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6275 probably need to check that the client is a Windows one before disallowing
6276 this as a UNIX client (one with UNIX extensions) can know the source is a
6277 symlink and make this decision intelligently. Found by an excellent bug
6278 report from <AndyLiebman@aol.com>.
6279 ****************************************************************************/
6281 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6282 const struct smb_filename *smb_fname_dst)
6284 const char *psrc = smb_fname_src->base_name;
6285 const char *pdst = smb_fname_dst->base_name;
6286 size_t slen;
6288 if (psrc[0] == '.' && psrc[1] == '/') {
6289 psrc += 2;
6291 if (pdst[0] == '.' && pdst[1] == '/') {
6292 pdst += 2;
6294 if ((slen = strlen(psrc)) > strlen(pdst)) {
6295 return False;
6297 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6301 * Do the notify calls from a rename
6304 static void notify_rename(connection_struct *conn, bool is_dir,
6305 const struct smb_filename *smb_fname_src,
6306 const struct smb_filename *smb_fname_dst)
6308 char *parent_dir_src = NULL;
6309 char *parent_dir_dst = NULL;
6310 uint32 mask;
6312 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6313 : FILE_NOTIFY_CHANGE_FILE_NAME;
6315 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6316 &parent_dir_src, NULL) ||
6317 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6318 &parent_dir_dst, NULL)) {
6319 goto out;
6322 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6323 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6324 smb_fname_src->base_name);
6325 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6326 smb_fname_dst->base_name);
6328 else {
6329 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6330 smb_fname_src->base_name);
6331 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6332 smb_fname_dst->base_name);
6335 /* this is a strange one. w2k3 gives an additional event for
6336 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6337 files, but not directories */
6338 if (!is_dir) {
6339 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6340 FILE_NOTIFY_CHANGE_ATTRIBUTES
6341 |FILE_NOTIFY_CHANGE_CREATION,
6342 smb_fname_dst->base_name);
6344 out:
6345 TALLOC_FREE(parent_dir_src);
6346 TALLOC_FREE(parent_dir_dst);
6349 /****************************************************************************
6350 Returns an error if the parent directory for a filename is open in an
6351 incompatible way.
6352 ****************************************************************************/
6354 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6355 const struct smb_filename *smb_fname_dst_in)
6357 char *parent_dir = NULL;
6358 struct smb_filename smb_fname_parent;
6359 struct file_id id;
6360 files_struct *fsp = NULL;
6361 int ret;
6363 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6364 &parent_dir, NULL)) {
6365 return NT_STATUS_NO_MEMORY;
6367 ZERO_STRUCT(smb_fname_parent);
6368 smb_fname_parent.base_name = parent_dir;
6370 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6371 if (ret == -1) {
6372 return map_nt_error_from_unix(errno);
6376 * We're only checking on this smbd here, mostly good
6377 * enough.. and will pass tests.
6380 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6381 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6382 fsp = file_find_di_next(fsp)) {
6383 if (fsp->access_mask & DELETE_ACCESS) {
6384 return NT_STATUS_SHARING_VIOLATION;
6387 return NT_STATUS_OK;
6390 /****************************************************************************
6391 Rename an open file - given an fsp.
6392 ****************************************************************************/
6394 NTSTATUS rename_internals_fsp(connection_struct *conn,
6395 files_struct *fsp,
6396 const struct smb_filename *smb_fname_dst_in,
6397 uint32 attrs,
6398 bool replace_if_exists)
6400 TALLOC_CTX *ctx = talloc_tos();
6401 struct smb_filename *smb_fname_dst = NULL;
6402 NTSTATUS status = NT_STATUS_OK;
6403 struct share_mode_lock *lck = NULL;
6404 bool dst_exists, old_is_stream, new_is_stream;
6406 status = check_name(conn, smb_fname_dst_in->base_name);
6407 if (!NT_STATUS_IS_OK(status)) {
6408 return status;
6411 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6412 if (!NT_STATUS_IS_OK(status)) {
6413 return status;
6416 /* Make a copy of the dst smb_fname structs */
6418 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6419 if (smb_fname_dst == NULL) {
6420 status = NT_STATUS_NO_MEMORY;
6421 goto out;
6425 * Check for special case with case preserving and not
6426 * case sensitive. If the old last component differs from the original
6427 * last component only by case, then we should allow
6428 * the rename (user is trying to change the case of the
6429 * filename).
6431 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6432 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6433 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6434 char *last_slash;
6435 char *fname_dst_lcomp_base_mod = NULL;
6436 struct smb_filename *smb_fname_orig_lcomp = NULL;
6439 * Get the last component of the destination name.
6441 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6442 if (last_slash) {
6443 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6444 } else {
6445 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6447 if (!fname_dst_lcomp_base_mod) {
6448 status = NT_STATUS_NO_MEMORY;
6449 goto out;
6453 * Create an smb_filename struct using the original last
6454 * component of the destination.
6456 smb_fname_orig_lcomp = synthetic_smb_fname_split(
6457 ctx, smb_fname_dst->original_lcomp, NULL);
6458 if (smb_fname_orig_lcomp == NULL) {
6459 status = NT_STATUS_NO_MEMORY;
6460 TALLOC_FREE(fname_dst_lcomp_base_mod);
6461 goto out;
6464 /* If the base names only differ by case, use original. */
6465 if(!strcsequal(fname_dst_lcomp_base_mod,
6466 smb_fname_orig_lcomp->base_name)) {
6467 char *tmp;
6469 * Replace the modified last component with the
6470 * original.
6472 if (last_slash) {
6473 *last_slash = '\0'; /* Truncate at the '/' */
6474 tmp = talloc_asprintf(smb_fname_dst,
6475 "%s/%s",
6476 smb_fname_dst->base_name,
6477 smb_fname_orig_lcomp->base_name);
6478 } else {
6479 tmp = talloc_asprintf(smb_fname_dst,
6480 "%s",
6481 smb_fname_orig_lcomp->base_name);
6483 if (tmp == NULL) {
6484 status = NT_STATUS_NO_MEMORY;
6485 TALLOC_FREE(fname_dst_lcomp_base_mod);
6486 TALLOC_FREE(smb_fname_orig_lcomp);
6487 goto out;
6489 TALLOC_FREE(smb_fname_dst->base_name);
6490 smb_fname_dst->base_name = tmp;
6493 /* If the stream_names only differ by case, use original. */
6494 if(!strcsequal(smb_fname_dst->stream_name,
6495 smb_fname_orig_lcomp->stream_name)) {
6496 char *tmp = NULL;
6497 /* Use the original stream. */
6498 tmp = talloc_strdup(smb_fname_dst,
6499 smb_fname_orig_lcomp->stream_name);
6500 if (tmp == NULL) {
6501 status = NT_STATUS_NO_MEMORY;
6502 TALLOC_FREE(fname_dst_lcomp_base_mod);
6503 TALLOC_FREE(smb_fname_orig_lcomp);
6504 goto out;
6506 TALLOC_FREE(smb_fname_dst->stream_name);
6507 smb_fname_dst->stream_name = tmp;
6509 TALLOC_FREE(fname_dst_lcomp_base_mod);
6510 TALLOC_FREE(smb_fname_orig_lcomp);
6514 * If the src and dest names are identical - including case,
6515 * don't do the rename, just return success.
6518 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6519 strcsequal(fsp->fsp_name->stream_name,
6520 smb_fname_dst->stream_name)) {
6521 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6522 "- returning success\n",
6523 smb_fname_str_dbg(smb_fname_dst)));
6524 status = NT_STATUS_OK;
6525 goto out;
6528 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6529 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6531 /* Return the correct error code if both names aren't streams. */
6532 if (!old_is_stream && new_is_stream) {
6533 status = NT_STATUS_OBJECT_NAME_INVALID;
6534 goto out;
6537 if (old_is_stream && !new_is_stream) {
6538 status = NT_STATUS_INVALID_PARAMETER;
6539 goto out;
6542 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6544 if(!replace_if_exists && dst_exists) {
6545 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6546 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6547 smb_fname_str_dbg(smb_fname_dst)));
6548 status = NT_STATUS_OBJECT_NAME_COLLISION;
6549 goto out;
6552 if (dst_exists) {
6553 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6554 &smb_fname_dst->st);
6555 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6556 fileid);
6557 /* The file can be open when renaming a stream */
6558 if (dst_fsp && !new_is_stream) {
6559 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6560 status = NT_STATUS_ACCESS_DENIED;
6561 goto out;
6565 /* Ensure we have a valid stat struct for the source. */
6566 status = vfs_stat_fsp(fsp);
6567 if (!NT_STATUS_IS_OK(status)) {
6568 goto out;
6571 status = can_rename(conn, fsp, attrs);
6573 if (!NT_STATUS_IS_OK(status)) {
6574 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6575 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6576 smb_fname_str_dbg(smb_fname_dst)));
6577 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6578 status = NT_STATUS_ACCESS_DENIED;
6579 goto out;
6582 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6583 status = NT_STATUS_ACCESS_DENIED;
6586 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6589 * We have the file open ourselves, so not being able to get the
6590 * corresponding share mode lock is a fatal error.
6593 SMB_ASSERT(lck != NULL);
6595 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6596 uint32 create_options = fsp->fh->private_options;
6598 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6599 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6600 smb_fname_str_dbg(smb_fname_dst)));
6602 if (!fsp->is_directory &&
6603 !lp_posix_pathnames() &&
6604 (lp_map_archive(SNUM(conn)) ||
6605 lp_store_dos_attributes(SNUM(conn)))) {
6606 /* We must set the archive bit on the newly
6607 renamed file. */
6608 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6609 uint32_t old_dosmode = dos_mode(conn,
6610 smb_fname_dst);
6611 file_set_dosmode(conn,
6612 smb_fname_dst,
6613 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6614 NULL,
6615 true);
6619 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6620 smb_fname_dst);
6622 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6623 smb_fname_dst);
6626 * A rename acts as a new file create w.r.t. allowing an initial delete
6627 * on close, probably because in Windows there is a new handle to the
6628 * new file. If initial delete on close was requested but not
6629 * originally set, we need to set it here. This is probably not 100% correct,
6630 * but will work for the CIFSFS client which in non-posix mode
6631 * depends on these semantics. JRA.
6634 if (create_options & FILE_DELETE_ON_CLOSE) {
6635 status = can_set_delete_on_close(fsp, 0);
6637 if (NT_STATUS_IS_OK(status)) {
6638 /* Note that here we set the *inital* delete on close flag,
6639 * not the regular one. The magic gets handled in close. */
6640 fsp->initial_delete_on_close = True;
6643 TALLOC_FREE(lck);
6644 status = NT_STATUS_OK;
6645 goto out;
6648 TALLOC_FREE(lck);
6650 if (errno == ENOTDIR || errno == EISDIR) {
6651 status = NT_STATUS_OBJECT_NAME_COLLISION;
6652 } else {
6653 status = map_nt_error_from_unix(errno);
6656 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6657 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6658 smb_fname_str_dbg(smb_fname_dst)));
6660 out:
6661 TALLOC_FREE(smb_fname_dst);
6663 return status;
6666 /****************************************************************************
6667 The guts of the rename command, split out so it may be called by the NT SMB
6668 code.
6669 ****************************************************************************/
6671 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6672 connection_struct *conn,
6673 struct smb_request *req,
6674 struct smb_filename *smb_fname_src,
6675 struct smb_filename *smb_fname_dst,
6676 uint32 attrs,
6677 bool replace_if_exists,
6678 bool src_has_wild,
6679 bool dest_has_wild,
6680 uint32_t access_mask)
6682 char *fname_src_dir = NULL;
6683 char *fname_src_mask = NULL;
6684 int count=0;
6685 NTSTATUS status = NT_STATUS_OK;
6686 struct smb_Dir *dir_hnd = NULL;
6687 const char *dname = NULL;
6688 char *talloced = NULL;
6689 long offset = 0;
6690 int create_options = 0;
6691 bool posix_pathnames = lp_posix_pathnames();
6692 int rc;
6695 * Split the old name into directory and last component
6696 * strings. Note that unix_convert may have stripped off a
6697 * leading ./ from both name and newname if the rename is
6698 * at the root of the share. We need to make sure either both
6699 * name and newname contain a / character or neither of them do
6700 * as this is checked in resolve_wildcards().
6703 /* Split up the directory from the filename/mask. */
6704 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6705 &fname_src_dir, &fname_src_mask);
6706 if (!NT_STATUS_IS_OK(status)) {
6707 status = NT_STATUS_NO_MEMORY;
6708 goto out;
6712 * We should only check the mangled cache
6713 * here if unix_convert failed. This means
6714 * that the path in 'mask' doesn't exist
6715 * on the file system and so we need to look
6716 * for a possible mangle. This patch from
6717 * Tine Smukavec <valentin.smukavec@hermes.si>.
6720 if (!VALID_STAT(smb_fname_src->st) &&
6721 mangle_is_mangled(fname_src_mask, conn->params)) {
6722 char *new_mask = NULL;
6723 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6724 conn->params);
6725 if (new_mask) {
6726 TALLOC_FREE(fname_src_mask);
6727 fname_src_mask = new_mask;
6731 if (!src_has_wild) {
6732 files_struct *fsp;
6735 * Only one file needs to be renamed. Append the mask back
6736 * onto the directory.
6738 TALLOC_FREE(smb_fname_src->base_name);
6739 if (ISDOT(fname_src_dir)) {
6740 /* Ensure we use canonical names on open. */
6741 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6742 "%s",
6743 fname_src_mask);
6744 } else {
6745 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6746 "%s/%s",
6747 fname_src_dir,
6748 fname_src_mask);
6750 if (!smb_fname_src->base_name) {
6751 status = NT_STATUS_NO_MEMORY;
6752 goto out;
6755 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6756 "case_preserve = %d, short case preserve = %d, "
6757 "directory = %s, newname = %s, "
6758 "last_component_dest = %s\n",
6759 conn->case_sensitive, conn->case_preserve,
6760 conn->short_case_preserve,
6761 smb_fname_str_dbg(smb_fname_src),
6762 smb_fname_str_dbg(smb_fname_dst),
6763 smb_fname_dst->original_lcomp));
6765 /* The dest name still may have wildcards. */
6766 if (dest_has_wild) {
6767 char *fname_dst_mod = NULL;
6768 if (!resolve_wildcards(smb_fname_dst,
6769 smb_fname_src->base_name,
6770 smb_fname_dst->base_name,
6771 &fname_dst_mod)) {
6772 DEBUG(6, ("rename_internals: resolve_wildcards "
6773 "%s %s failed\n",
6774 smb_fname_src->base_name,
6775 smb_fname_dst->base_name));
6776 status = NT_STATUS_NO_MEMORY;
6777 goto out;
6779 TALLOC_FREE(smb_fname_dst->base_name);
6780 smb_fname_dst->base_name = fname_dst_mod;
6783 ZERO_STRUCT(smb_fname_src->st);
6784 if (posix_pathnames) {
6785 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6786 } else {
6787 rc = SMB_VFS_STAT(conn, smb_fname_src);
6789 if (rc == -1) {
6790 status = map_nt_error_from_unix_common(errno);
6791 goto out;
6794 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6795 create_options |= FILE_DIRECTORY_FILE;
6798 status = SMB_VFS_CREATE_FILE(
6799 conn, /* conn */
6800 req, /* req */
6801 0, /* root_dir_fid */
6802 smb_fname_src, /* fname */
6803 access_mask, /* access_mask */
6804 (FILE_SHARE_READ | /* share_access */
6805 FILE_SHARE_WRITE),
6806 FILE_OPEN, /* create_disposition*/
6807 create_options, /* create_options */
6808 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6809 0, /* oplock_request */
6810 NULL, /* lease */
6811 0, /* allocation_size */
6812 0, /* private_flags */
6813 NULL, /* sd */
6814 NULL, /* ea_list */
6815 &fsp, /* result */
6816 NULL, /* pinfo */
6817 NULL, NULL); /* create context */
6819 if (!NT_STATUS_IS_OK(status)) {
6820 DEBUG(3, ("Could not open rename source %s: %s\n",
6821 smb_fname_str_dbg(smb_fname_src),
6822 nt_errstr(status)));
6823 goto out;
6826 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6827 attrs, replace_if_exists);
6829 close_file(req, fsp, NORMAL_CLOSE);
6831 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6832 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6833 smb_fname_str_dbg(smb_fname_dst)));
6835 goto out;
6839 * Wildcards - process each file that matches.
6841 if (strequal(fname_src_mask, "????????.???")) {
6842 TALLOC_FREE(fname_src_mask);
6843 fname_src_mask = talloc_strdup(ctx, "*");
6844 if (!fname_src_mask) {
6845 status = NT_STATUS_NO_MEMORY;
6846 goto out;
6850 status = check_name(conn, fname_src_dir);
6851 if (!NT_STATUS_IS_OK(status)) {
6852 goto out;
6855 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6856 attrs);
6857 if (dir_hnd == NULL) {
6858 status = map_nt_error_from_unix(errno);
6859 goto out;
6862 status = NT_STATUS_NO_SUCH_FILE;
6864 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6865 * - gentest fix. JRA
6868 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6869 &talloced))) {
6870 files_struct *fsp = NULL;
6871 char *destname = NULL;
6872 bool sysdir_entry = False;
6874 /* Quick check for "." and ".." */
6875 if (ISDOT(dname) || ISDOTDOT(dname)) {
6876 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6877 sysdir_entry = True;
6878 } else {
6879 TALLOC_FREE(talloced);
6880 continue;
6884 if (!is_visible_file(conn, fname_src_dir, dname,
6885 &smb_fname_src->st, false)) {
6886 TALLOC_FREE(talloced);
6887 continue;
6890 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6891 TALLOC_FREE(talloced);
6892 continue;
6895 if (sysdir_entry) {
6896 status = NT_STATUS_OBJECT_NAME_INVALID;
6897 break;
6900 TALLOC_FREE(smb_fname_src->base_name);
6901 if (ISDOT(fname_src_dir)) {
6902 /* Ensure we use canonical names on open. */
6903 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6904 "%s",
6905 dname);
6906 } else {
6907 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6908 "%s/%s",
6909 fname_src_dir,
6910 dname);
6912 if (!smb_fname_src->base_name) {
6913 status = NT_STATUS_NO_MEMORY;
6914 goto out;
6917 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6918 smb_fname_dst->base_name,
6919 &destname)) {
6920 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6921 smb_fname_src->base_name, destname));
6922 TALLOC_FREE(talloced);
6923 continue;
6925 if (!destname) {
6926 status = NT_STATUS_NO_MEMORY;
6927 goto out;
6930 TALLOC_FREE(smb_fname_dst->base_name);
6931 smb_fname_dst->base_name = destname;
6933 ZERO_STRUCT(smb_fname_src->st);
6934 if (posix_pathnames) {
6935 SMB_VFS_LSTAT(conn, smb_fname_src);
6936 } else {
6937 SMB_VFS_STAT(conn, smb_fname_src);
6940 create_options = 0;
6942 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6943 create_options |= FILE_DIRECTORY_FILE;
6946 status = SMB_VFS_CREATE_FILE(
6947 conn, /* conn */
6948 req, /* req */
6949 0, /* root_dir_fid */
6950 smb_fname_src, /* fname */
6951 access_mask, /* access_mask */
6952 (FILE_SHARE_READ | /* share_access */
6953 FILE_SHARE_WRITE),
6954 FILE_OPEN, /* create_disposition*/
6955 create_options, /* create_options */
6956 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6957 0, /* oplock_request */
6958 NULL, /* lease */
6959 0, /* allocation_size */
6960 0, /* private_flags */
6961 NULL, /* sd */
6962 NULL, /* ea_list */
6963 &fsp, /* result */
6964 NULL, /* pinfo */
6965 NULL, NULL); /* create context */
6967 if (!NT_STATUS_IS_OK(status)) {
6968 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6969 "returned %s rename %s -> %s\n",
6970 nt_errstr(status),
6971 smb_fname_str_dbg(smb_fname_src),
6972 smb_fname_str_dbg(smb_fname_dst)));
6973 break;
6976 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6977 dname);
6978 if (!smb_fname_dst->original_lcomp) {
6979 status = NT_STATUS_NO_MEMORY;
6980 goto out;
6983 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6984 attrs, replace_if_exists);
6986 close_file(req, fsp, NORMAL_CLOSE);
6988 if (!NT_STATUS_IS_OK(status)) {
6989 DEBUG(3, ("rename_internals_fsp returned %s for "
6990 "rename %s -> %s\n", nt_errstr(status),
6991 smb_fname_str_dbg(smb_fname_src),
6992 smb_fname_str_dbg(smb_fname_dst)));
6993 break;
6996 count++;
6998 DEBUG(3,("rename_internals: doing rename on %s -> "
6999 "%s\n", smb_fname_str_dbg(smb_fname_src),
7000 smb_fname_str_dbg(smb_fname_src)));
7001 TALLOC_FREE(talloced);
7003 TALLOC_FREE(dir_hnd);
7005 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7006 status = map_nt_error_from_unix(errno);
7009 out:
7010 TALLOC_FREE(talloced);
7011 TALLOC_FREE(fname_src_dir);
7012 TALLOC_FREE(fname_src_mask);
7013 return status;
7016 /****************************************************************************
7017 Reply to a mv.
7018 ****************************************************************************/
7020 void reply_mv(struct smb_request *req)
7022 connection_struct *conn = req->conn;
7023 char *name = NULL;
7024 char *newname = NULL;
7025 const char *p;
7026 uint32 attrs;
7027 NTSTATUS status;
7028 bool src_has_wcard = False;
7029 bool dest_has_wcard = False;
7030 TALLOC_CTX *ctx = talloc_tos();
7031 struct smb_filename *smb_fname_src = NULL;
7032 struct smb_filename *smb_fname_dst = NULL;
7033 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
7034 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
7035 bool stream_rename = false;
7037 START_PROFILE(SMBmv);
7039 if (req->wct < 1) {
7040 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7041 goto out;
7044 attrs = SVAL(req->vwv+0, 0);
7046 p = (const char *)req->buf + 1;
7047 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7048 &status, &src_has_wcard);
7049 if (!NT_STATUS_IS_OK(status)) {
7050 reply_nterror(req, status);
7051 goto out;
7053 p++;
7054 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7055 &status, &dest_has_wcard);
7056 if (!NT_STATUS_IS_OK(status)) {
7057 reply_nterror(req, status);
7058 goto out;
7061 if (!lp_posix_pathnames()) {
7062 /* The newname must begin with a ':' if the
7063 name contains a ':'. */
7064 if (strchr_m(name, ':')) {
7065 if (newname[0] != ':') {
7066 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7067 goto out;
7069 stream_rename = true;
7073 status = filename_convert(ctx,
7074 conn,
7075 req->flags2 & FLAGS2_DFS_PATHNAMES,
7076 name,
7077 src_ucf_flags,
7078 &src_has_wcard,
7079 &smb_fname_src);
7081 if (!NT_STATUS_IS_OK(status)) {
7082 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7083 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7084 ERRSRV, ERRbadpath);
7085 goto out;
7087 reply_nterror(req, status);
7088 goto out;
7091 status = filename_convert(ctx,
7092 conn,
7093 req->flags2 & FLAGS2_DFS_PATHNAMES,
7094 newname,
7095 dst_ucf_flags,
7096 &dest_has_wcard,
7097 &smb_fname_dst);
7099 if (!NT_STATUS_IS_OK(status)) {
7100 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7101 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7102 ERRSRV, ERRbadpath);
7103 goto out;
7105 reply_nterror(req, status);
7106 goto out;
7109 if (stream_rename) {
7110 /* smb_fname_dst->base_name must be the same as
7111 smb_fname_src->base_name. */
7112 TALLOC_FREE(smb_fname_dst->base_name);
7113 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7114 smb_fname_src->base_name);
7115 if (!smb_fname_dst->base_name) {
7116 reply_nterror(req, NT_STATUS_NO_MEMORY);
7117 goto out;
7121 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7122 smb_fname_str_dbg(smb_fname_dst)));
7124 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7125 attrs, False, src_has_wcard, dest_has_wcard,
7126 DELETE_ACCESS);
7127 if (!NT_STATUS_IS_OK(status)) {
7128 if (open_was_deferred(req->xconn, req->mid)) {
7129 /* We have re-scheduled this call. */
7130 goto out;
7132 reply_nterror(req, status);
7133 goto out;
7136 reply_outbuf(req, 0, 0);
7137 out:
7138 TALLOC_FREE(smb_fname_src);
7139 TALLOC_FREE(smb_fname_dst);
7140 END_PROFILE(SMBmv);
7141 return;
7144 /*******************************************************************
7145 Copy a file as part of a reply_copy.
7146 ******************************************************************/
7149 * TODO: check error codes on all callers
7152 NTSTATUS copy_file(TALLOC_CTX *ctx,
7153 connection_struct *conn,
7154 struct smb_filename *smb_fname_src,
7155 struct smb_filename *smb_fname_dst,
7156 int ofun,
7157 int count,
7158 bool target_is_directory)
7160 struct smb_filename *smb_fname_dst_tmp = NULL;
7161 off_t ret=-1;
7162 files_struct *fsp1,*fsp2;
7163 uint32 dosattrs;
7164 uint32 new_create_disposition;
7165 NTSTATUS status;
7168 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7169 if (smb_fname_dst_tmp == NULL) {
7170 return NT_STATUS_NO_MEMORY;
7174 * If the target is a directory, extract the last component from the
7175 * src filename and append it to the dst filename
7177 if (target_is_directory) {
7178 const char *p;
7180 /* dest/target can't be a stream if it's a directory. */
7181 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7183 p = strrchr_m(smb_fname_src->base_name,'/');
7184 if (p) {
7185 p++;
7186 } else {
7187 p = smb_fname_src->base_name;
7189 smb_fname_dst_tmp->base_name =
7190 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7192 if (!smb_fname_dst_tmp->base_name) {
7193 status = NT_STATUS_NO_MEMORY;
7194 goto out;
7198 status = vfs_file_exist(conn, smb_fname_src);
7199 if (!NT_STATUS_IS_OK(status)) {
7200 goto out;
7203 if (!target_is_directory && count) {
7204 new_create_disposition = FILE_OPEN;
7205 } else {
7206 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7207 0, ofun,
7208 NULL, NULL,
7209 &new_create_disposition,
7210 NULL,
7211 NULL)) {
7212 status = NT_STATUS_INVALID_PARAMETER;
7213 goto out;
7217 /* Open the src file for reading. */
7218 status = SMB_VFS_CREATE_FILE(
7219 conn, /* conn */
7220 NULL, /* req */
7221 0, /* root_dir_fid */
7222 smb_fname_src, /* fname */
7223 FILE_GENERIC_READ, /* access_mask */
7224 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7225 FILE_OPEN, /* create_disposition*/
7226 0, /* create_options */
7227 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7228 INTERNAL_OPEN_ONLY, /* oplock_request */
7229 NULL, /* lease */
7230 0, /* allocation_size */
7231 0, /* private_flags */
7232 NULL, /* sd */
7233 NULL, /* ea_list */
7234 &fsp1, /* result */
7235 NULL, /* psbuf */
7236 NULL, NULL); /* create context */
7238 if (!NT_STATUS_IS_OK(status)) {
7239 goto out;
7242 dosattrs = dos_mode(conn, smb_fname_src);
7244 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7245 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7248 /* Open the dst file for writing. */
7249 status = SMB_VFS_CREATE_FILE(
7250 conn, /* conn */
7251 NULL, /* req */
7252 0, /* root_dir_fid */
7253 smb_fname_dst, /* fname */
7254 FILE_GENERIC_WRITE, /* access_mask */
7255 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7256 new_create_disposition, /* create_disposition*/
7257 0, /* create_options */
7258 dosattrs, /* file_attributes */
7259 INTERNAL_OPEN_ONLY, /* oplock_request */
7260 NULL, /* lease */
7261 0, /* allocation_size */
7262 0, /* private_flags */
7263 NULL, /* sd */
7264 NULL, /* ea_list */
7265 &fsp2, /* result */
7266 NULL, /* psbuf */
7267 NULL, NULL); /* create context */
7269 if (!NT_STATUS_IS_OK(status)) {
7270 close_file(NULL, fsp1, ERROR_CLOSE);
7271 goto out;
7274 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7275 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7276 if (ret == -1) {
7277 DEBUG(0, ("error - vfs lseek returned error %s\n",
7278 strerror(errno)));
7279 status = map_nt_error_from_unix(errno);
7280 close_file(NULL, fsp1, ERROR_CLOSE);
7281 close_file(NULL, fsp2, ERROR_CLOSE);
7282 goto out;
7286 /* Do the actual copy. */
7287 if (smb_fname_src->st.st_ex_size) {
7288 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7289 } else {
7290 ret = 0;
7293 close_file(NULL, fsp1, NORMAL_CLOSE);
7295 /* Ensure the modtime is set correctly on the destination file. */
7296 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7299 * As we are opening fsp1 read-only we only expect
7300 * an error on close on fsp2 if we are out of space.
7301 * Thus we don't look at the error return from the
7302 * close of fsp1.
7304 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7306 if (!NT_STATUS_IS_OK(status)) {
7307 goto out;
7310 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7311 status = NT_STATUS_DISK_FULL;
7312 goto out;
7315 status = NT_STATUS_OK;
7317 out:
7318 TALLOC_FREE(smb_fname_dst_tmp);
7319 return status;
7322 /****************************************************************************
7323 Reply to a file copy.
7324 ****************************************************************************/
7326 void reply_copy(struct smb_request *req)
7328 connection_struct *conn = req->conn;
7329 struct smb_filename *smb_fname_src = NULL;
7330 struct smb_filename *smb_fname_dst = NULL;
7331 char *fname_src = NULL;
7332 char *fname_dst = NULL;
7333 char *fname_src_mask = NULL;
7334 char *fname_src_dir = NULL;
7335 const char *p;
7336 int count=0;
7337 int error = ERRnoaccess;
7338 int tid2;
7339 int ofun;
7340 int flags;
7341 bool target_is_directory=False;
7342 bool source_has_wild = False;
7343 bool dest_has_wild = False;
7344 NTSTATUS status;
7345 TALLOC_CTX *ctx = talloc_tos();
7347 START_PROFILE(SMBcopy);
7349 if (req->wct < 3) {
7350 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7351 goto out;
7354 tid2 = SVAL(req->vwv+0, 0);
7355 ofun = SVAL(req->vwv+1, 0);
7356 flags = SVAL(req->vwv+2, 0);
7358 p = (const char *)req->buf;
7359 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7360 &status, &source_has_wild);
7361 if (!NT_STATUS_IS_OK(status)) {
7362 reply_nterror(req, status);
7363 goto out;
7365 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7366 &status, &dest_has_wild);
7367 if (!NT_STATUS_IS_OK(status)) {
7368 reply_nterror(req, status);
7369 goto out;
7372 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7374 if (tid2 != conn->cnum) {
7375 /* can't currently handle inter share copies XXXX */
7376 DEBUG(3,("Rejecting inter-share copy\n"));
7377 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7378 goto out;
7381 status = filename_convert(ctx, conn,
7382 req->flags2 & FLAGS2_DFS_PATHNAMES,
7383 fname_src,
7384 UCF_COND_ALLOW_WCARD_LCOMP,
7385 &source_has_wild,
7386 &smb_fname_src);
7387 if (!NT_STATUS_IS_OK(status)) {
7388 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7389 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7390 ERRSRV, ERRbadpath);
7391 goto out;
7393 reply_nterror(req, status);
7394 goto out;
7397 status = filename_convert(ctx, conn,
7398 req->flags2 & FLAGS2_DFS_PATHNAMES,
7399 fname_dst,
7400 UCF_COND_ALLOW_WCARD_LCOMP,
7401 &dest_has_wild,
7402 &smb_fname_dst);
7403 if (!NT_STATUS_IS_OK(status)) {
7404 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7405 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7406 ERRSRV, ERRbadpath);
7407 goto out;
7409 reply_nterror(req, status);
7410 goto out;
7413 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7415 if ((flags&1) && target_is_directory) {
7416 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7417 goto out;
7420 if ((flags&2) && !target_is_directory) {
7421 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7422 goto out;
7425 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7426 /* wants a tree copy! XXXX */
7427 DEBUG(3,("Rejecting tree copy\n"));
7428 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7429 goto out;
7432 /* Split up the directory from the filename/mask. */
7433 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7434 &fname_src_dir, &fname_src_mask);
7435 if (!NT_STATUS_IS_OK(status)) {
7436 reply_nterror(req, NT_STATUS_NO_MEMORY);
7437 goto out;
7441 * We should only check the mangled cache
7442 * here if unix_convert failed. This means
7443 * that the path in 'mask' doesn't exist
7444 * on the file system and so we need to look
7445 * for a possible mangle. This patch from
7446 * Tine Smukavec <valentin.smukavec@hermes.si>.
7448 if (!VALID_STAT(smb_fname_src->st) &&
7449 mangle_is_mangled(fname_src_mask, conn->params)) {
7450 char *new_mask = NULL;
7451 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7452 &new_mask, conn->params);
7454 /* Use demangled name if one was successfully found. */
7455 if (new_mask) {
7456 TALLOC_FREE(fname_src_mask);
7457 fname_src_mask = new_mask;
7461 if (!source_has_wild) {
7464 * Only one file needs to be copied. Append the mask back onto
7465 * the directory.
7467 TALLOC_FREE(smb_fname_src->base_name);
7468 if (ISDOT(fname_src_dir)) {
7469 /* Ensure we use canonical names on open. */
7470 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7471 "%s",
7472 fname_src_mask);
7473 } else {
7474 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7475 "%s/%s",
7476 fname_src_dir,
7477 fname_src_mask);
7479 if (!smb_fname_src->base_name) {
7480 reply_nterror(req, NT_STATUS_NO_MEMORY);
7481 goto out;
7484 if (dest_has_wild) {
7485 char *fname_dst_mod = NULL;
7486 if (!resolve_wildcards(smb_fname_dst,
7487 smb_fname_src->base_name,
7488 smb_fname_dst->base_name,
7489 &fname_dst_mod)) {
7490 reply_nterror(req, NT_STATUS_NO_MEMORY);
7491 goto out;
7493 TALLOC_FREE(smb_fname_dst->base_name);
7494 smb_fname_dst->base_name = fname_dst_mod;
7497 status = check_name(conn, smb_fname_src->base_name);
7498 if (!NT_STATUS_IS_OK(status)) {
7499 reply_nterror(req, status);
7500 goto out;
7503 status = check_name(conn, smb_fname_dst->base_name);
7504 if (!NT_STATUS_IS_OK(status)) {
7505 reply_nterror(req, status);
7506 goto out;
7509 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7510 ofun, count, target_is_directory);
7512 if(!NT_STATUS_IS_OK(status)) {
7513 reply_nterror(req, status);
7514 goto out;
7515 } else {
7516 count++;
7518 } else {
7519 struct smb_Dir *dir_hnd = NULL;
7520 const char *dname = NULL;
7521 char *talloced = NULL;
7522 long offset = 0;
7525 * There is a wildcard that requires us to actually read the
7526 * src dir and copy each file matching the mask to the dst.
7527 * Right now streams won't be copied, but this could
7528 * presumably be added with a nested loop for reach dir entry.
7530 SMB_ASSERT(!smb_fname_src->stream_name);
7531 SMB_ASSERT(!smb_fname_dst->stream_name);
7533 smb_fname_src->stream_name = NULL;
7534 smb_fname_dst->stream_name = NULL;
7536 if (strequal(fname_src_mask,"????????.???")) {
7537 TALLOC_FREE(fname_src_mask);
7538 fname_src_mask = talloc_strdup(ctx, "*");
7539 if (!fname_src_mask) {
7540 reply_nterror(req, NT_STATUS_NO_MEMORY);
7541 goto out;
7545 status = check_name(conn, fname_src_dir);
7546 if (!NT_STATUS_IS_OK(status)) {
7547 reply_nterror(req, status);
7548 goto out;
7551 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7552 if (dir_hnd == NULL) {
7553 status = map_nt_error_from_unix(errno);
7554 reply_nterror(req, status);
7555 goto out;
7558 error = ERRbadfile;
7560 /* Iterate over the src dir copying each entry to the dst. */
7561 while ((dname = ReadDirName(dir_hnd, &offset,
7562 &smb_fname_src->st, &talloced))) {
7563 char *destname = NULL;
7565 if (ISDOT(dname) || ISDOTDOT(dname)) {
7566 TALLOC_FREE(talloced);
7567 continue;
7570 if (!is_visible_file(conn, fname_src_dir, dname,
7571 &smb_fname_src->st, false)) {
7572 TALLOC_FREE(talloced);
7573 continue;
7576 if(!mask_match(dname, fname_src_mask,
7577 conn->case_sensitive)) {
7578 TALLOC_FREE(talloced);
7579 continue;
7582 error = ERRnoaccess;
7584 /* Get the src smb_fname struct setup. */
7585 TALLOC_FREE(smb_fname_src->base_name);
7586 if (ISDOT(fname_src_dir)) {
7587 /* Ensure we use canonical names on open. */
7588 smb_fname_src->base_name =
7589 talloc_asprintf(smb_fname_src, "%s",
7590 dname);
7591 } else {
7592 smb_fname_src->base_name =
7593 talloc_asprintf(smb_fname_src, "%s/%s",
7594 fname_src_dir, dname);
7597 if (!smb_fname_src->base_name) {
7598 TALLOC_FREE(dir_hnd);
7599 TALLOC_FREE(talloced);
7600 reply_nterror(req, NT_STATUS_NO_MEMORY);
7601 goto out;
7604 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7605 smb_fname_dst->base_name,
7606 &destname)) {
7607 TALLOC_FREE(talloced);
7608 continue;
7610 if (!destname) {
7611 TALLOC_FREE(dir_hnd);
7612 TALLOC_FREE(talloced);
7613 reply_nterror(req, NT_STATUS_NO_MEMORY);
7614 goto out;
7617 TALLOC_FREE(smb_fname_dst->base_name);
7618 smb_fname_dst->base_name = destname;
7620 status = check_name(conn, smb_fname_src->base_name);
7621 if (!NT_STATUS_IS_OK(status)) {
7622 TALLOC_FREE(dir_hnd);
7623 TALLOC_FREE(talloced);
7624 reply_nterror(req, status);
7625 goto out;
7628 status = check_name(conn, smb_fname_dst->base_name);
7629 if (!NT_STATUS_IS_OK(status)) {
7630 TALLOC_FREE(dir_hnd);
7631 TALLOC_FREE(talloced);
7632 reply_nterror(req, status);
7633 goto out;
7636 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7637 smb_fname_src->base_name,
7638 smb_fname_dst->base_name));
7640 status = copy_file(ctx, conn, smb_fname_src,
7641 smb_fname_dst, ofun, count,
7642 target_is_directory);
7643 if (NT_STATUS_IS_OK(status)) {
7644 count++;
7647 TALLOC_FREE(talloced);
7649 TALLOC_FREE(dir_hnd);
7652 if (count == 0) {
7653 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7654 goto out;
7657 reply_outbuf(req, 1, 0);
7658 SSVAL(req->outbuf,smb_vwv0,count);
7659 out:
7660 TALLOC_FREE(smb_fname_src);
7661 TALLOC_FREE(smb_fname_dst);
7662 TALLOC_FREE(fname_src);
7663 TALLOC_FREE(fname_dst);
7664 TALLOC_FREE(fname_src_mask);
7665 TALLOC_FREE(fname_src_dir);
7667 END_PROFILE(SMBcopy);
7668 return;
7671 #undef DBGC_CLASS
7672 #define DBGC_CLASS DBGC_LOCKING
7674 /****************************************************************************
7675 Get a lock pid, dealing with large count requests.
7676 ****************************************************************************/
7678 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7679 bool large_file_format)
7681 if(!large_file_format)
7682 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7683 else
7684 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7687 /****************************************************************************
7688 Get a lock count, dealing with large count requests.
7689 ****************************************************************************/
7691 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7692 bool large_file_format)
7694 uint64_t count = 0;
7696 if(!large_file_format) {
7697 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7698 } else {
7700 * No BVAL, this is reversed!
7702 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7703 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7706 return count;
7709 /****************************************************************************
7710 Get a lock offset, dealing with large offset requests.
7711 ****************************************************************************/
7713 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7714 bool large_file_format)
7716 uint64_t offset = 0;
7718 if(!large_file_format) {
7719 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7720 } else {
7722 * No BVAL, this is reversed!
7724 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7725 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7728 return offset;
7731 NTSTATUS smbd_do_locking(struct smb_request *req,
7732 files_struct *fsp,
7733 uint8_t type,
7734 int32_t timeout,
7735 uint16_t num_locks,
7736 struct smbd_lock_element *locks,
7737 bool *async)
7739 connection_struct *conn = req->conn;
7740 int i;
7741 NTSTATUS status = NT_STATUS_OK;
7743 *async = false;
7745 /* Setup the timeout in seconds. */
7747 if (!lp_blocking_locks(SNUM(conn))) {
7748 timeout = 0;
7751 for(i = 0; i < (int)num_locks; i++) {
7752 struct smbd_lock_element *e = &locks[i];
7754 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7755 "%llu, file %s timeout = %d\n",
7756 (double)e->offset,
7757 (double)e->count,
7758 (unsigned long long)e->smblctx,
7759 fsp_str_dbg(fsp),
7760 (int)timeout));
7762 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7763 struct blocking_lock_record *blr = NULL;
7765 if (num_locks > 1) {
7767 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7768 * if the lock vector contains one entry. When given multiple cancel
7769 * requests in a single PDU we expect the server to return an
7770 * error. Windows servers seem to accept the request but only
7771 * cancel the first lock.
7772 * JRA - Do what Windows does (tm) :-).
7775 #if 0
7776 /* MS-CIFS (2.2.4.32.1) behavior. */
7777 return NT_STATUS_DOS(ERRDOS,
7778 ERRcancelviolation);
7779 #else
7780 /* Windows behavior. */
7781 if (i != 0) {
7782 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7783 "cancel request\n"));
7784 continue;
7786 #endif
7789 if (lp_blocking_locks(SNUM(conn))) {
7791 /* Schedule a message to ourselves to
7792 remove the blocking lock record and
7793 return the right error. */
7795 blr = blocking_lock_cancel_smb1(fsp,
7796 e->smblctx,
7797 e->offset,
7798 e->count,
7799 WINDOWS_LOCK,
7800 type,
7801 NT_STATUS_FILE_LOCK_CONFLICT);
7802 if (blr == NULL) {
7803 return NT_STATUS_DOS(
7804 ERRDOS,
7805 ERRcancelviolation);
7808 /* Remove a matching pending lock. */
7809 status = do_lock_cancel(fsp,
7810 e->smblctx,
7811 e->count,
7812 e->offset,
7813 WINDOWS_LOCK);
7814 } else {
7815 bool blocking_lock = timeout ? true : false;
7816 bool defer_lock = false;
7817 struct byte_range_lock *br_lck;
7818 uint64_t block_smblctx;
7820 br_lck = do_lock(req->sconn->msg_ctx,
7821 fsp,
7822 e->smblctx,
7823 e->count,
7824 e->offset,
7825 e->brltype,
7826 WINDOWS_LOCK,
7827 blocking_lock,
7828 &status,
7829 &block_smblctx);
7831 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7832 /* Windows internal resolution for blocking locks seems
7833 to be about 200ms... Don't wait for less than that. JRA. */
7834 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7835 timeout = lp_lock_spin_time();
7837 defer_lock = true;
7840 /* If a lock sent with timeout of zero would fail, and
7841 * this lock has been requested multiple times,
7842 * according to brl_lock_failed() we convert this
7843 * request to a blocking lock with a timeout of between
7844 * 150 - 300 milliseconds.
7846 * If lp_lock_spin_time() has been set to 0, we skip
7847 * this blocking retry and fail immediately.
7849 * Replacement for do_lock_spin(). JRA. */
7851 if (!req->sconn->using_smb2 &&
7852 br_lck && lp_blocking_locks(SNUM(conn)) &&
7853 lp_lock_spin_time() && !blocking_lock &&
7854 NT_STATUS_EQUAL((status),
7855 NT_STATUS_FILE_LOCK_CONFLICT))
7857 defer_lock = true;
7858 timeout = lp_lock_spin_time();
7861 if (br_lck && defer_lock) {
7863 * A blocking lock was requested. Package up
7864 * this smb into a queued request and push it
7865 * onto the blocking lock queue.
7867 if(push_blocking_lock_request(br_lck,
7868 req,
7869 fsp,
7870 timeout,
7872 e->smblctx,
7873 e->brltype,
7874 WINDOWS_LOCK,
7875 e->offset,
7876 e->count,
7877 block_smblctx)) {
7878 TALLOC_FREE(br_lck);
7879 *async = true;
7880 return NT_STATUS_OK;
7884 TALLOC_FREE(br_lck);
7887 if (!NT_STATUS_IS_OK(status)) {
7888 break;
7892 /* If any of the above locks failed, then we must unlock
7893 all of the previous locks (X/Open spec). */
7895 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7897 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7898 i = -1; /* we want to skip the for loop */
7902 * Ensure we don't do a remove on the lock that just failed,
7903 * as under POSIX rules, if we have a lock already there, we
7904 * will delete it (and we shouldn't) .....
7906 for(i--; i >= 0; i--) {
7907 struct smbd_lock_element *e = &locks[i];
7909 do_unlock(req->sconn->msg_ctx,
7910 fsp,
7911 e->smblctx,
7912 e->count,
7913 e->offset,
7914 WINDOWS_LOCK);
7916 return status;
7919 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
7920 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
7922 return NT_STATUS_OK;
7925 NTSTATUS smbd_do_unlocking(struct smb_request *req,
7926 files_struct *fsp,
7927 uint16_t num_ulocks,
7928 struct smbd_lock_element *ulocks)
7930 int i;
7932 for(i = 0; i < (int)num_ulocks; i++) {
7933 struct smbd_lock_element *e = &ulocks[i];
7934 NTSTATUS status;
7936 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
7937 "pid %u, file %s\n", __func__,
7938 (double)e->offset,
7939 (double)e->count,
7940 (unsigned int)e->smblctx,
7941 fsp_str_dbg(fsp)));
7943 if (e->brltype != UNLOCK_LOCK) {
7944 /* this can only happen with SMB2 */
7945 return NT_STATUS_INVALID_PARAMETER;
7948 status = do_unlock(req->sconn->msg_ctx,
7949 fsp,
7950 e->smblctx,
7951 e->count,
7952 e->offset,
7953 WINDOWS_LOCK);
7955 DEBUG(10, ("%s: unlock returned %s\n", __func__,
7956 nt_errstr(status)));
7958 if (!NT_STATUS_IS_OK(status)) {
7959 return status;
7963 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
7964 num_ulocks));
7966 return NT_STATUS_OK;
7969 /****************************************************************************
7970 Reply to a lockingX request.
7971 ****************************************************************************/
7973 void reply_lockingX(struct smb_request *req)
7975 connection_struct *conn = req->conn;
7976 files_struct *fsp;
7977 unsigned char locktype;
7978 unsigned char oplocklevel;
7979 uint16 num_ulocks;
7980 uint16 num_locks;
7981 int32 lock_timeout;
7982 int i;
7983 const uint8_t *data;
7984 bool large_file_format;
7985 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7986 struct smbd_lock_element *ulocks;
7987 struct smbd_lock_element *locks;
7988 bool async = false;
7990 START_PROFILE(SMBlockingX);
7992 if (req->wct < 8) {
7993 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7994 END_PROFILE(SMBlockingX);
7995 return;
7998 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7999 locktype = CVAL(req->vwv+3, 0);
8000 oplocklevel = CVAL(req->vwv+3, 1);
8001 num_ulocks = SVAL(req->vwv+6, 0);
8002 num_locks = SVAL(req->vwv+7, 0);
8003 lock_timeout = IVAL(req->vwv+4, 0);
8004 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8006 if (!check_fsp(conn, req, fsp)) {
8007 END_PROFILE(SMBlockingX);
8008 return;
8011 data = req->buf;
8013 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8014 /* we don't support these - and CANCEL_LOCK makes w2k
8015 and XP reboot so I don't really want to be
8016 compatible! (tridge) */
8017 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8018 END_PROFILE(SMBlockingX);
8019 return;
8022 /* Check if this is an oplock break on a file
8023 we have granted an oplock on.
8025 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8026 /* Client can insist on breaking to none. */
8027 bool break_to_none = (oplocklevel == 0);
8028 bool result;
8030 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8031 "for %s\n", (unsigned int)oplocklevel,
8032 fsp_fnum_dbg(fsp)));
8035 * Make sure we have granted an exclusive or batch oplock on
8036 * this file.
8039 if (fsp->oplock_type == 0) {
8041 /* The Samba4 nbench simulator doesn't understand
8042 the difference between break to level2 and break
8043 to none from level2 - it sends oplock break
8044 replies in both cases. Don't keep logging an error
8045 message here - just ignore it. JRA. */
8047 DEBUG(5,("reply_lockingX: Error : oplock break from "
8048 "client for %s (oplock=%d) and no "
8049 "oplock granted on this file (%s).\n",
8050 fsp_fnum_dbg(fsp), fsp->oplock_type,
8051 fsp_str_dbg(fsp)));
8053 /* if this is a pure oplock break request then don't
8054 * send a reply */
8055 if (num_locks == 0 && num_ulocks == 0) {
8056 END_PROFILE(SMBlockingX);
8057 return;
8058 } else {
8059 END_PROFILE(SMBlockingX);
8060 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8061 return;
8065 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8066 (break_to_none)) {
8067 result = remove_oplock(fsp);
8068 } else {
8069 result = downgrade_oplock(fsp);
8072 if (!result) {
8073 DEBUG(0, ("reply_lockingX: error in removing "
8074 "oplock on file %s\n", fsp_str_dbg(fsp)));
8075 /* Hmmm. Is this panic justified? */
8076 smb_panic("internal tdb error");
8079 /* if this is a pure oplock break request then don't send a
8080 * reply */
8081 if (num_locks == 0 && num_ulocks == 0) {
8082 /* Sanity check - ensure a pure oplock break is not a
8083 chained request. */
8084 if (CVAL(req->vwv+0, 0) != 0xff) {
8085 DEBUG(0,("reply_lockingX: Error : pure oplock "
8086 "break is a chained %d request !\n",
8087 (unsigned int)CVAL(req->vwv+0, 0)));
8089 END_PROFILE(SMBlockingX);
8090 return;
8094 if (req->buflen <
8095 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8096 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8097 END_PROFILE(SMBlockingX);
8098 return;
8101 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8102 if (ulocks == NULL) {
8103 reply_nterror(req, NT_STATUS_NO_MEMORY);
8104 END_PROFILE(SMBlockingX);
8105 return;
8108 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8109 if (locks == NULL) {
8110 reply_nterror(req, NT_STATUS_NO_MEMORY);
8111 END_PROFILE(SMBlockingX);
8112 return;
8115 /* Data now points at the beginning of the list
8116 of smb_unlkrng structs */
8117 for(i = 0; i < (int)num_ulocks; i++) {
8118 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8119 ulocks[i].count = get_lock_count(data, i, large_file_format);
8120 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8121 ulocks[i].brltype = UNLOCK_LOCK;
8124 /* Now do any requested locks */
8125 data += ((large_file_format ? 20 : 10)*num_ulocks);
8127 /* Data now points at the beginning of the list
8128 of smb_lkrng structs */
8130 for(i = 0; i < (int)num_locks; i++) {
8131 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8132 locks[i].count = get_lock_count(data, i, large_file_format);
8133 locks[i].offset = get_lock_offset(data, i, large_file_format);
8135 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8136 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8137 locks[i].brltype = PENDING_READ_LOCK;
8138 } else {
8139 locks[i].brltype = READ_LOCK;
8141 } else {
8142 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8143 locks[i].brltype = PENDING_WRITE_LOCK;
8144 } else {
8145 locks[i].brltype = WRITE_LOCK;
8150 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8151 if (!NT_STATUS_IS_OK(status)) {
8152 END_PROFILE(SMBlockingX);
8153 reply_nterror(req, status);
8154 return;
8157 status = smbd_do_locking(req, fsp,
8158 locktype, lock_timeout,
8159 num_locks, locks,
8160 &async);
8161 if (!NT_STATUS_IS_OK(status)) {
8162 END_PROFILE(SMBlockingX);
8163 reply_nterror(req, status);
8164 return;
8166 if (async) {
8167 END_PROFILE(SMBlockingX);
8168 return;
8171 reply_outbuf(req, 2, 0);
8172 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8173 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8175 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8176 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8178 END_PROFILE(SMBlockingX);
8181 #undef DBGC_CLASS
8182 #define DBGC_CLASS DBGC_ALL
8184 /****************************************************************************
8185 Reply to a SMBreadbmpx (read block multiplex) request.
8186 Always reply with an error, if someone has a platform really needs this,
8187 please contact vl@samba.org
8188 ****************************************************************************/
8190 void reply_readbmpx(struct smb_request *req)
8192 START_PROFILE(SMBreadBmpx);
8193 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8194 END_PROFILE(SMBreadBmpx);
8195 return;
8198 /****************************************************************************
8199 Reply to a SMBreadbs (read block multiplex secondary) request.
8200 Always reply with an error, if someone has a platform really needs this,
8201 please contact vl@samba.org
8202 ****************************************************************************/
8204 void reply_readbs(struct smb_request *req)
8206 START_PROFILE(SMBreadBs);
8207 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8208 END_PROFILE(SMBreadBs);
8209 return;
8212 /****************************************************************************
8213 Reply to a SMBsetattrE.
8214 ****************************************************************************/
8216 void reply_setattrE(struct smb_request *req)
8218 connection_struct *conn = req->conn;
8219 struct smb_file_time ft;
8220 files_struct *fsp;
8221 NTSTATUS status;
8223 START_PROFILE(SMBsetattrE);
8224 ZERO_STRUCT(ft);
8226 if (req->wct < 7) {
8227 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8228 goto out;
8231 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8233 if(!fsp || (fsp->conn != conn)) {
8234 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8235 goto out;
8239 * Convert the DOS times into unix times.
8242 ft.atime = convert_time_t_to_timespec(
8243 srv_make_unix_date2(req->vwv+3));
8244 ft.mtime = convert_time_t_to_timespec(
8245 srv_make_unix_date2(req->vwv+5));
8246 ft.create_time = convert_time_t_to_timespec(
8247 srv_make_unix_date2(req->vwv+1));
8249 reply_outbuf(req, 0, 0);
8252 * Patch from Ray Frush <frush@engr.colostate.edu>
8253 * Sometimes times are sent as zero - ignore them.
8256 /* Ensure we have a valid stat struct for the source. */
8257 status = vfs_stat_fsp(fsp);
8258 if (!NT_STATUS_IS_OK(status)) {
8259 reply_nterror(req, status);
8260 goto out;
8263 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8264 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8265 goto out;
8268 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8269 if (!NT_STATUS_IS_OK(status)) {
8270 reply_nterror(req, status);
8271 goto out;
8274 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8275 " createtime=%u\n",
8276 fsp_fnum_dbg(fsp),
8277 (unsigned int)ft.atime.tv_sec,
8278 (unsigned int)ft.mtime.tv_sec,
8279 (unsigned int)ft.create_time.tv_sec
8281 out:
8282 END_PROFILE(SMBsetattrE);
8283 return;
8287 /* Back from the dead for OS/2..... JRA. */
8289 /****************************************************************************
8290 Reply to a SMBwritebmpx (write block multiplex primary) request.
8291 Always reply with an error, if someone has a platform really needs this,
8292 please contact vl@samba.org
8293 ****************************************************************************/
8295 void reply_writebmpx(struct smb_request *req)
8297 START_PROFILE(SMBwriteBmpx);
8298 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8299 END_PROFILE(SMBwriteBmpx);
8300 return;
8303 /****************************************************************************
8304 Reply to a SMBwritebs (write block multiplex secondary) request.
8305 Always reply with an error, if someone has a platform really needs this,
8306 please contact vl@samba.org
8307 ****************************************************************************/
8309 void reply_writebs(struct smb_request *req)
8311 START_PROFILE(SMBwriteBs);
8312 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8313 END_PROFILE(SMBwriteBs);
8314 return;
8317 /****************************************************************************
8318 Reply to a SMBgetattrE.
8319 ****************************************************************************/
8321 void reply_getattrE(struct smb_request *req)
8323 connection_struct *conn = req->conn;
8324 int mode;
8325 files_struct *fsp;
8326 struct timespec create_ts;
8328 START_PROFILE(SMBgetattrE);
8330 if (req->wct < 1) {
8331 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8332 END_PROFILE(SMBgetattrE);
8333 return;
8336 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8338 if(!fsp || (fsp->conn != conn)) {
8339 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8340 END_PROFILE(SMBgetattrE);
8341 return;
8344 /* Do an fstat on this file */
8345 if(fsp_stat(fsp)) {
8346 reply_nterror(req, map_nt_error_from_unix(errno));
8347 END_PROFILE(SMBgetattrE);
8348 return;
8351 mode = dos_mode(conn, fsp->fsp_name);
8354 * Convert the times into dos times. Set create
8355 * date to be last modify date as UNIX doesn't save
8356 * this.
8359 reply_outbuf(req, 11, 0);
8361 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8362 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8363 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8364 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8365 /* Should we check pending modtime here ? JRA */
8366 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8367 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8369 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8370 SIVAL(req->outbuf, smb_vwv6, 0);
8371 SIVAL(req->outbuf, smb_vwv8, 0);
8372 } else {
8373 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8374 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8375 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8377 SSVAL(req->outbuf,smb_vwv10, mode);
8379 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8381 END_PROFILE(SMBgetattrE);
8382 return;