s3:libsmb: Add in the core of the libsmb client SMB2 functions.
[Samba.git] / source3 / smbd / reply.c
blob2ae3ff4b1e68193fad3ceb8707c7df7fcb495847
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 char *src, int flags)
350 ssize_t bufrem = smbreq_bufrem(req, src);
352 if (bufrem < 0) {
353 return 0;
356 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
357 bufrem, flags);
360 /****************************************************************************
361 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
362 ****************************************************************************/
364 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
365 files_struct *fsp)
367 if ((fsp == NULL) || (conn == NULL)) {
368 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
369 return False;
371 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
372 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
373 return False;
375 return True;
378 /****************************************************************************
379 Check if we have a correct fsp pointing to a file.
380 ****************************************************************************/
382 bool check_fsp(connection_struct *conn, struct smb_request *req,
383 files_struct *fsp)
385 if (!check_fsp_open(conn, req, fsp)) {
386 return False;
388 if (fsp->is_directory) {
389 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
390 return False;
392 if (fsp->fh->fd == -1) {
393 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
394 return False;
396 fsp->num_smb_operations++;
397 return True;
400 /****************************************************************************
401 Check if we have a correct fsp pointing to a quota fake file. Replacement for
402 the CHECK_NTQUOTA_HANDLE_OK macro.
403 ****************************************************************************/
405 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
406 files_struct *fsp)
408 if (!check_fsp_open(conn, req, fsp)) {
409 return false;
412 if (fsp->is_directory) {
413 return false;
416 if (fsp->fake_file_handle == NULL) {
417 return false;
420 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
421 return false;
424 if (fsp->fake_file_handle->private_data == NULL) {
425 return false;
428 return true;
431 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
432 const char *name, int name_type)
434 char *trim_name;
435 char *trim_name_type;
436 const char *retarget_parm;
437 char *retarget;
438 char *p;
439 int retarget_type = 0x20;
440 int retarget_port = NBT_SMB_PORT;
441 struct sockaddr_storage retarget_addr;
442 struct sockaddr_in *in_addr;
443 bool ret = false;
444 uint8_t outbuf[10];
446 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
447 return false;
450 trim_name = talloc_strdup(talloc_tos(), name);
451 if (trim_name == NULL) {
452 goto fail;
454 trim_char(trim_name, ' ', ' ');
456 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
457 name_type);
458 if (trim_name_type == NULL) {
459 goto fail;
462 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
463 trim_name_type, NULL);
464 if (retarget_parm == NULL) {
465 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
466 trim_name, NULL);
468 if (retarget_parm == NULL) {
469 goto fail;
472 retarget = talloc_strdup(trim_name, retarget_parm);
473 if (retarget == NULL) {
474 goto fail;
477 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
479 p = strchr(retarget, ':');
480 if (p != NULL) {
481 *p++ = '\0';
482 retarget_port = atoi(p);
485 p = strchr_m(retarget, '#');
486 if (p != NULL) {
487 *p++ = '\0';
488 if (sscanf(p, "%x", &retarget_type) != 1) {
489 goto fail;
493 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
494 if (!ret) {
495 DEBUG(10, ("could not resolve %s\n", retarget));
496 goto fail;
499 if (retarget_addr.ss_family != AF_INET) {
500 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
501 goto fail;
504 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
506 _smb_setlen(outbuf, 6);
507 SCVAL(outbuf, 0, 0x84);
508 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
509 *(uint16_t *)(outbuf+8) = htons(retarget_port);
511 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
512 NULL)) {
513 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
514 "failed.");
517 ret = true;
518 fail:
519 TALLOC_FREE(trim_name);
520 return ret;
523 static void reply_called_name_not_present(char *outbuf)
525 smb_setlen(outbuf, 1);
526 SCVAL(outbuf, 0, 0x83);
527 SCVAL(outbuf, 4, 0x82);
530 /****************************************************************************
531 Reply to a (netbios-level) special message.
532 ****************************************************************************/
534 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
536 int msg_type = CVAL(inbuf,0);
537 int msg_flags = CVAL(inbuf,1);
539 * We only really use 4 bytes of the outbuf, but for the smb_setlen
540 * calculation & friends (srv_send_smb uses that) we need the full smb
541 * header.
543 char outbuf[smb_size];
545 memset(outbuf, '\0', sizeof(outbuf));
547 smb_setlen(outbuf,0);
549 switch (msg_type) {
550 case NBSSrequest: /* session request */
552 /* inbuf_size is guarenteed to be at least 4. */
553 fstring name1,name2;
554 int name_type1, name_type2;
555 int name_len1, name_len2;
557 *name1 = *name2 = 0;
559 if (sconn->nbt.got_session) {
560 exit_server_cleanly("multiple session request not permitted");
563 SCVAL(outbuf,0,NBSSpositive);
564 SCVAL(outbuf,3,0);
566 /* inbuf_size is guaranteed to be at least 4. */
567 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
568 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
569 DEBUG(0,("Invalid name length in session request\n"));
570 reply_called_name_not_present(outbuf);
571 break;
573 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
574 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
575 DEBUG(0,("Invalid name length in session request\n"));
576 reply_called_name_not_present(outbuf);
577 break;
580 name_type1 = name_extract((unsigned char *)inbuf,
581 inbuf_size,(unsigned int)4,name1);
582 name_type2 = name_extract((unsigned char *)inbuf,
583 inbuf_size,(unsigned int)(4 + name_len1),name2);
585 if (name_type1 == -1 || name_type2 == -1) {
586 DEBUG(0,("Invalid name type in session request\n"));
587 reply_called_name_not_present(outbuf);
588 break;
591 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
592 name1, name_type1, name2, name_type2));
594 if (netbios_session_retarget(sconn, name1, name_type1)) {
595 exit_server_cleanly("retargeted client");
599 * Windows NT/2k uses "*SMBSERVER" and XP uses
600 * "*SMBSERV" arrggg!!!
602 if (strequal(name1, "*SMBSERVER ")
603 || strequal(name1, "*SMBSERV ")) {
604 char *raddr;
606 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
607 talloc_tos());
608 if (raddr == NULL) {
609 exit_server_cleanly("could not allocate raddr");
612 fstrcpy(name1, raddr);
615 set_local_machine_name(name1, True);
616 set_remote_machine_name(name2, True);
618 if (is_ipaddress(sconn->remote_hostname)) {
619 char *p = discard_const_p(char, sconn->remote_hostname);
621 talloc_free(p);
623 sconn->remote_hostname = talloc_strdup(sconn,
624 get_remote_machine_name());
625 if (sconn->remote_hostname == NULL) {
626 exit_server_cleanly("could not copy remote name");
628 sconn->conn->remote_hostname = sconn->remote_hostname;
631 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
632 get_local_machine_name(), get_remote_machine_name(),
633 name_type2));
635 if (name_type2 == 'R') {
636 /* We are being asked for a pathworks session ---
637 no thanks! */
638 reply_called_name_not_present(outbuf);
639 break;
642 reload_services(sconn, conn_snum_used, true);
643 reopen_logs();
645 sconn->nbt.got_session = true;
646 break;
649 case 0x89: /* session keepalive request
650 (some old clients produce this?) */
651 SCVAL(outbuf,0,NBSSkeepalive);
652 SCVAL(outbuf,3,0);
653 break;
655 case NBSSpositive: /* positive session response */
656 case NBSSnegative: /* negative session response */
657 case NBSSretarget: /* retarget session response */
658 DEBUG(0,("Unexpected session response\n"));
659 break;
661 case NBSSkeepalive: /* session keepalive */
662 default:
663 return;
666 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
667 msg_type, msg_flags));
669 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
671 if (CVAL(outbuf, 0) != 0x82) {
672 exit_server_cleanly("invalid netbios session");
674 return;
677 /****************************************************************************
678 Reply to a tcon.
679 conn POINTER CAN BE NULL HERE !
680 ****************************************************************************/
682 void reply_tcon(struct smb_request *req)
684 connection_struct *conn = req->conn;
685 const char *service;
686 char *service_buf = NULL;
687 char *password = NULL;
688 char *dev = NULL;
689 int pwlen=0;
690 NTSTATUS nt_status;
691 const char *p;
692 TALLOC_CTX *ctx = talloc_tos();
693 struct smbd_server_connection *sconn = req->sconn;
694 NTTIME now = timeval_to_nttime(&req->request_time);
696 START_PROFILE(SMBtcon);
698 if (req->buflen < 4) {
699 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
700 END_PROFILE(SMBtcon);
701 return;
704 p = (const char *)req->buf + 1;
705 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
706 p += 1;
707 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
708 p += pwlen+1;
709 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
710 p += 1;
712 if (service_buf == NULL || password == NULL || dev == NULL) {
713 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
714 END_PROFILE(SMBtcon);
715 return;
717 p = strrchr_m(service_buf,'\\');
718 if (p) {
719 service = p+1;
720 } else {
721 service = service_buf;
724 conn = make_connection(sconn, now, service, dev,
725 req->vuid,&nt_status);
726 req->conn = conn;
728 if (!conn) {
729 reply_nterror(req, nt_status);
730 END_PROFILE(SMBtcon);
731 return;
734 reply_outbuf(req, 2, 0);
735 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
736 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
737 SSVAL(req->outbuf,smb_tid,conn->cnum);
739 DEBUG(3,("tcon service=%s cnum=%d\n",
740 service, conn->cnum));
742 END_PROFILE(SMBtcon);
743 return;
746 /****************************************************************************
747 Reply to a tcon and X.
748 conn POINTER CAN BE NULL HERE !
749 ****************************************************************************/
751 void reply_tcon_and_X(struct smb_request *req)
753 connection_struct *conn = req->conn;
754 const char *service = NULL;
755 TALLOC_CTX *ctx = talloc_tos();
756 /* what the cleint thinks the device is */
757 char *client_devicetype = NULL;
758 /* what the server tells the client the share represents */
759 const char *server_devicetype;
760 NTSTATUS nt_status;
761 int passlen;
762 char *path = NULL;
763 const char *p, *q;
764 uint16_t tcon_flags;
765 struct smbXsrv_session *session = NULL;
766 NTTIME now = timeval_to_nttime(&req->request_time);
767 bool session_key_updated = false;
768 uint16_t optional_support = 0;
769 struct smbd_server_connection *sconn = req->sconn;
771 START_PROFILE(SMBtconX);
773 if (req->wct < 4) {
774 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
775 END_PROFILE(SMBtconX);
776 return;
779 passlen = SVAL(req->vwv+3, 0);
780 tcon_flags = SVAL(req->vwv+2, 0);
782 /* we might have to close an old one */
783 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
784 struct smbXsrv_tcon *tcon;
785 NTSTATUS status;
787 tcon = conn->tcon;
788 req->conn = NULL;
789 conn = NULL;
792 * TODO: cancel all outstanding requests on the tcon
794 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
795 if (!NT_STATUS_IS_OK(status)) {
796 DEBUG(0, ("reply_tcon_and_X: "
797 "smbXsrv_tcon_disconnect() failed: %s\n",
798 nt_errstr(status)));
800 * If we hit this case, there is something completely
801 * wrong, so we better disconnect the transport connection.
803 END_PROFILE(SMBtconX);
804 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
805 return;
808 TALLOC_FREE(tcon);
811 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
812 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
813 END_PROFILE(SMBtconX);
814 return;
817 if (sconn->smb1.negprot.encrypted_passwords) {
818 p = (const char *)req->buf + passlen;
819 } else {
820 p = (const char *)req->buf + passlen + 1;
823 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
825 if (path == NULL) {
826 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
827 END_PROFILE(SMBtconX);
828 return;
832 * the service name can be either: \\server\share
833 * or share directly like on the DELL PowerVault 705
835 if (*path=='\\') {
836 q = strchr_m(path+2,'\\');
837 if (!q) {
838 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
839 END_PROFILE(SMBtconX);
840 return;
842 service = q+1;
843 } else {
844 service = path;
847 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
848 &client_devicetype, p,
849 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
851 if (client_devicetype == NULL) {
852 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
853 END_PROFILE(SMBtconX);
854 return;
857 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
859 nt_status = smb1srv_session_lookup(req->sconn->conn,
860 req->vuid, now, &session);
861 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
862 reply_force_doserror(req, ERRSRV, ERRbaduid);
863 END_PROFILE(SMBtconX);
864 return;
866 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
867 reply_nterror(req, nt_status);
868 END_PROFILE(SMBtconX);
869 return;
871 if (!NT_STATUS_IS_OK(nt_status)) {
872 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
873 END_PROFILE(SMBtconX);
874 return;
877 if (session->global->auth_session_info == NULL) {
878 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
879 END_PROFILE(SMBtconX);
880 return;
884 * If there is no application key defined yet
885 * we create one.
887 * This means we setup the application key on the
888 * first tcon that happens via the given session.
890 * Once the application key is defined, it does not
891 * change any more.
893 if (session->global->application_key.length == 0 &&
894 session->global->signing_key.length > 0)
896 struct smbXsrv_session *x = session;
897 struct auth_session_info *session_info =
898 session->global->auth_session_info;
899 uint8_t session_key[16];
901 ZERO_STRUCT(session_key);
902 memcpy(session_key, x->global->signing_key.data,
903 MIN(x->global->signing_key.length, sizeof(session_key)));
906 * The application key is truncated/padded to 16 bytes
908 x->global->application_key = data_blob_talloc(x->global,
909 session_key,
910 sizeof(session_key));
911 ZERO_STRUCT(session_key);
912 if (x->global->application_key.data == NULL) {
913 reply_nterror(req, NT_STATUS_NO_MEMORY);
914 END_PROFILE(SMBtconX);
915 return;
918 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
919 smb_key_derivation(x->global->application_key.data,
920 x->global->application_key.length,
921 x->global->application_key.data);
922 optional_support |= SMB_EXTENDED_SIGNATURES;
926 * Place the application key into the session_info
928 data_blob_clear_free(&session_info->session_key);
929 session_info->session_key = data_blob_dup_talloc(session_info,
930 x->global->application_key);
931 if (session_info->session_key.data == NULL) {
932 data_blob_clear_free(&x->global->application_key);
933 reply_nterror(req, NT_STATUS_NO_MEMORY);
934 END_PROFILE(SMBtconX);
935 return;
937 session_key_updated = true;
940 conn = make_connection(sconn, now, service, client_devicetype,
941 req->vuid, &nt_status);
942 req->conn =conn;
944 if (!conn) {
945 if (session_key_updated) {
946 struct smbXsrv_session *x = session;
947 struct auth_session_info *session_info =
948 session->global->auth_session_info;
949 data_blob_clear_free(&x->global->application_key);
950 data_blob_clear_free(&session_info->session_key);
952 reply_nterror(req, nt_status);
953 END_PROFILE(SMBtconX);
954 return;
957 if ( IS_IPC(conn) )
958 server_devicetype = "IPC";
959 else if ( IS_PRINT(conn) )
960 server_devicetype = "LPT1:";
961 else
962 server_devicetype = "A:";
964 if (get_Protocol() < PROTOCOL_NT1) {
965 reply_outbuf(req, 2, 0);
966 if (message_push_string(&req->outbuf, server_devicetype,
967 STR_TERMINATE|STR_ASCII) == -1) {
968 reply_nterror(req, NT_STATUS_NO_MEMORY);
969 END_PROFILE(SMBtconX);
970 return;
972 } else {
973 /* NT sets the fstype of IPC$ to the null string */
974 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
976 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
977 /* Return permissions. */
978 uint32 perm1 = 0;
979 uint32 perm2 = 0;
981 reply_outbuf(req, 7, 0);
983 if (IS_IPC(conn)) {
984 perm1 = FILE_ALL_ACCESS;
985 perm2 = FILE_ALL_ACCESS;
986 } else {
987 perm1 = conn->share_access;
990 SIVAL(req->outbuf, smb_vwv3, perm1);
991 SIVAL(req->outbuf, smb_vwv5, perm2);
992 } else {
993 reply_outbuf(req, 3, 0);
996 if ((message_push_string(&req->outbuf, server_devicetype,
997 STR_TERMINATE|STR_ASCII) == -1)
998 || (message_push_string(&req->outbuf, fstype,
999 STR_TERMINATE) == -1)) {
1000 reply_nterror(req, NT_STATUS_NO_MEMORY);
1001 END_PROFILE(SMBtconX);
1002 return;
1005 /* what does setting this bit do? It is set by NT4 and
1006 may affect the ability to autorun mounted cdroms */
1007 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1008 optional_support |=
1009 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1011 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1012 DEBUG(2,("Serving %s as a Dfs root\n",
1013 lp_servicename(ctx, SNUM(conn)) ));
1014 optional_support |= SMB_SHARE_IN_DFS;
1017 SSVAL(req->outbuf, smb_vwv2, optional_support);
1020 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1021 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1023 DEBUG(3,("tconX service=%s \n",
1024 service));
1026 /* set the incoming and outgoing tid to the just created one */
1027 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1028 SSVAL(req->outbuf,smb_tid,conn->cnum);
1030 END_PROFILE(SMBtconX);
1032 req->tid = conn->cnum;
1035 /****************************************************************************
1036 Reply to an unknown type.
1037 ****************************************************************************/
1039 void reply_unknown_new(struct smb_request *req, uint8 type)
1041 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1042 smb_fn_name(type), type, type));
1043 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1044 return;
1047 /****************************************************************************
1048 Reply to an ioctl.
1049 conn POINTER CAN BE NULL HERE !
1050 ****************************************************************************/
1052 void reply_ioctl(struct smb_request *req)
1054 connection_struct *conn = req->conn;
1055 uint16 device;
1056 uint16 function;
1057 uint32 ioctl_code;
1058 int replysize;
1059 char *p;
1061 START_PROFILE(SMBioctl);
1063 if (req->wct < 3) {
1064 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1065 END_PROFILE(SMBioctl);
1066 return;
1069 device = SVAL(req->vwv+1, 0);
1070 function = SVAL(req->vwv+2, 0);
1071 ioctl_code = (device << 16) + function;
1073 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1075 switch (ioctl_code) {
1076 case IOCTL_QUERY_JOB_INFO:
1077 replysize = 32;
1078 break;
1079 default:
1080 reply_force_doserror(req, ERRSRV, ERRnosupport);
1081 END_PROFILE(SMBioctl);
1082 return;
1085 reply_outbuf(req, 8, replysize+1);
1086 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1087 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1088 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1089 p = smb_buf(req->outbuf);
1090 memset(p, '\0', replysize+1); /* valgrind-safe. */
1091 p += 1; /* Allow for alignment */
1093 switch (ioctl_code) {
1094 case IOCTL_QUERY_JOB_INFO:
1096 files_struct *fsp = file_fsp(
1097 req, SVAL(req->vwv+0, 0));
1098 if (!fsp) {
1099 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1100 END_PROFILE(SMBioctl);
1101 return;
1103 /* Job number */
1104 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1106 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1107 lp_netbios_name(), 15,
1108 STR_TERMINATE|STR_ASCII);
1109 if (conn) {
1110 srvstr_push((char *)req->outbuf, req->flags2,
1111 p+18,
1112 lp_servicename(talloc_tos(),
1113 SNUM(conn)),
1114 13, STR_TERMINATE|STR_ASCII);
1115 } else {
1116 memset(p+18, 0, 13);
1118 break;
1122 END_PROFILE(SMBioctl);
1123 return;
1126 /****************************************************************************
1127 Strange checkpath NTSTATUS mapping.
1128 ****************************************************************************/
1130 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1132 /* Strange DOS error code semantics only for checkpath... */
1133 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1134 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1135 /* We need to map to ERRbadpath */
1136 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1139 return status;
1142 /****************************************************************************
1143 Reply to a checkpath.
1144 ****************************************************************************/
1146 void reply_checkpath(struct smb_request *req)
1148 connection_struct *conn = req->conn;
1149 struct smb_filename *smb_fname = NULL;
1150 char *name = NULL;
1151 NTSTATUS status;
1152 TALLOC_CTX *ctx = talloc_tos();
1154 START_PROFILE(SMBcheckpath);
1156 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1157 STR_TERMINATE, &status);
1159 if (!NT_STATUS_IS_OK(status)) {
1160 status = map_checkpath_error(req->flags2, status);
1161 reply_nterror(req, status);
1162 END_PROFILE(SMBcheckpath);
1163 return;
1166 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1168 status = filename_convert(ctx,
1169 conn,
1170 req->flags2 & FLAGS2_DFS_PATHNAMES,
1171 name,
1173 NULL,
1174 &smb_fname);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1178 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1179 ERRSRV, ERRbadpath);
1180 END_PROFILE(SMBcheckpath);
1181 return;
1183 goto path_err;
1186 if (!VALID_STAT(smb_fname->st) &&
1187 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1188 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1189 smb_fname_str_dbg(smb_fname), strerror(errno)));
1190 status = map_nt_error_from_unix(errno);
1191 goto path_err;
1194 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1195 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1196 ERRDOS, ERRbadpath);
1197 goto out;
1200 reply_outbuf(req, 0, 0);
1202 path_err:
1203 /* We special case this - as when a Windows machine
1204 is parsing a path is steps through the components
1205 one at a time - if a component fails it expects
1206 ERRbadpath, not ERRbadfile.
1208 status = map_checkpath_error(req->flags2, status);
1209 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1211 * Windows returns different error codes if
1212 * the parent directory is valid but not the
1213 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1214 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1215 * if the path is invalid.
1217 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1218 ERRDOS, ERRbadpath);
1219 goto out;
1222 reply_nterror(req, status);
1224 out:
1225 TALLOC_FREE(smb_fname);
1226 END_PROFILE(SMBcheckpath);
1227 return;
1230 /****************************************************************************
1231 Reply to a getatr.
1232 ****************************************************************************/
1234 void reply_getatr(struct smb_request *req)
1236 connection_struct *conn = req->conn;
1237 struct smb_filename *smb_fname = NULL;
1238 char *fname = NULL;
1239 int mode=0;
1240 off_t size=0;
1241 time_t mtime=0;
1242 const char *p;
1243 NTSTATUS status;
1244 TALLOC_CTX *ctx = talloc_tos();
1245 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1247 START_PROFILE(SMBgetatr);
1249 p = (const char *)req->buf + 1;
1250 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 reply_nterror(req, status);
1253 goto out;
1256 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1257 under WfWg - weird! */
1258 if (*fname == '\0') {
1259 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1260 if (!CAN_WRITE(conn)) {
1261 mode |= FILE_ATTRIBUTE_READONLY;
1263 size = 0;
1264 mtime = 0;
1265 } else {
1266 status = filename_convert(ctx,
1267 conn,
1268 req->flags2 & FLAGS2_DFS_PATHNAMES,
1269 fname,
1271 NULL,
1272 &smb_fname);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1275 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1276 ERRSRV, ERRbadpath);
1277 goto out;
1279 reply_nterror(req, status);
1280 goto out;
1282 if (!VALID_STAT(smb_fname->st) &&
1283 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1284 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1285 smb_fname_str_dbg(smb_fname),
1286 strerror(errno)));
1287 reply_nterror(req, map_nt_error_from_unix(errno));
1288 goto out;
1291 mode = dos_mode(conn, smb_fname);
1292 size = smb_fname->st.st_ex_size;
1294 if (ask_sharemode) {
1295 struct timespec write_time_ts;
1296 struct file_id fileid;
1298 ZERO_STRUCT(write_time_ts);
1299 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1300 get_file_infos(fileid, 0, NULL, &write_time_ts);
1301 if (!null_timespec(write_time_ts)) {
1302 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1306 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1307 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1308 size = 0;
1312 reply_outbuf(req, 10, 0);
1314 SSVAL(req->outbuf,smb_vwv0,mode);
1315 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1316 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1317 } else {
1318 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1320 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1322 if (get_Protocol() >= PROTOCOL_NT1) {
1323 SSVAL(req->outbuf, smb_flg2,
1324 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1327 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1328 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1330 out:
1331 TALLOC_FREE(smb_fname);
1332 TALLOC_FREE(fname);
1333 END_PROFILE(SMBgetatr);
1334 return;
1337 /****************************************************************************
1338 Reply to a setatr.
1339 ****************************************************************************/
1341 void reply_setatr(struct smb_request *req)
1343 struct smb_file_time ft;
1344 connection_struct *conn = req->conn;
1345 struct smb_filename *smb_fname = NULL;
1346 char *fname = NULL;
1347 int mode;
1348 time_t mtime;
1349 const char *p;
1350 NTSTATUS status;
1351 TALLOC_CTX *ctx = talloc_tos();
1353 START_PROFILE(SMBsetatr);
1355 ZERO_STRUCT(ft);
1357 if (req->wct < 2) {
1358 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1359 goto out;
1362 p = (const char *)req->buf + 1;
1363 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1364 if (!NT_STATUS_IS_OK(status)) {
1365 reply_nterror(req, status);
1366 goto out;
1369 status = filename_convert(ctx,
1370 conn,
1371 req->flags2 & FLAGS2_DFS_PATHNAMES,
1372 fname,
1374 NULL,
1375 &smb_fname);
1376 if (!NT_STATUS_IS_OK(status)) {
1377 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1378 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1379 ERRSRV, ERRbadpath);
1380 goto out;
1382 reply_nterror(req, status);
1383 goto out;
1386 if (smb_fname->base_name[0] == '.' &&
1387 smb_fname->base_name[1] == '\0') {
1389 * Not sure here is the right place to catch this
1390 * condition. Might be moved to somewhere else later -- vl
1392 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1393 goto out;
1396 mode = SVAL(req->vwv+0, 0);
1397 mtime = srv_make_unix_date3(req->vwv+1);
1399 if (mode != FILE_ATTRIBUTE_NORMAL) {
1400 if (VALID_STAT_OF_DIR(smb_fname->st))
1401 mode |= FILE_ATTRIBUTE_DIRECTORY;
1402 else
1403 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1405 status = check_access(conn, NULL, smb_fname,
1406 FILE_WRITE_ATTRIBUTES);
1407 if (!NT_STATUS_IS_OK(status)) {
1408 reply_nterror(req, status);
1409 goto out;
1412 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1413 false) != 0) {
1414 reply_nterror(req, map_nt_error_from_unix(errno));
1415 goto out;
1419 ft.mtime = convert_time_t_to_timespec(mtime);
1420 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1421 if (!NT_STATUS_IS_OK(status)) {
1422 reply_nterror(req, status);
1423 goto out;
1426 reply_outbuf(req, 0, 0);
1428 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1429 mode));
1430 out:
1431 TALLOC_FREE(smb_fname);
1432 END_PROFILE(SMBsetatr);
1433 return;
1436 /****************************************************************************
1437 Reply to a dskattr.
1438 ****************************************************************************/
1440 void reply_dskattr(struct smb_request *req)
1442 connection_struct *conn = req->conn;
1443 uint64_t dfree,dsize,bsize;
1444 START_PROFILE(SMBdskattr);
1446 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1447 reply_nterror(req, map_nt_error_from_unix(errno));
1448 END_PROFILE(SMBdskattr);
1449 return;
1452 reply_outbuf(req, 5, 0);
1454 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1455 double total_space, free_space;
1456 /* we need to scale this to a number that DOS6 can handle. We
1457 use floating point so we can handle large drives on systems
1458 that don't have 64 bit integers
1460 we end up displaying a maximum of 2G to DOS systems
1462 total_space = dsize * (double)bsize;
1463 free_space = dfree * (double)bsize;
1465 dsize = (uint64_t)((total_space+63*512) / (64*512));
1466 dfree = (uint64_t)((free_space+63*512) / (64*512));
1468 if (dsize > 0xFFFF) dsize = 0xFFFF;
1469 if (dfree > 0xFFFF) dfree = 0xFFFF;
1471 SSVAL(req->outbuf,smb_vwv0,dsize);
1472 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1473 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1474 SSVAL(req->outbuf,smb_vwv3,dfree);
1475 } else {
1476 SSVAL(req->outbuf,smb_vwv0,dsize);
1477 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1478 SSVAL(req->outbuf,smb_vwv2,512);
1479 SSVAL(req->outbuf,smb_vwv3,dfree);
1482 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1484 END_PROFILE(SMBdskattr);
1485 return;
1489 * Utility function to split the filename from the directory.
1491 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1492 char **fname_dir_out,
1493 char **fname_mask_out)
1495 const char *p = NULL;
1496 char *fname_dir = NULL;
1497 char *fname_mask = NULL;
1499 p = strrchr_m(fname_in, '/');
1500 if (!p) {
1501 fname_dir = talloc_strdup(ctx, ".");
1502 fname_mask = talloc_strdup(ctx, fname_in);
1503 } else {
1504 fname_dir = talloc_strndup(ctx, fname_in,
1505 PTR_DIFF(p, fname_in));
1506 fname_mask = talloc_strdup(ctx, p+1);
1509 if (!fname_dir || !fname_mask) {
1510 TALLOC_FREE(fname_dir);
1511 TALLOC_FREE(fname_mask);
1512 return NT_STATUS_NO_MEMORY;
1515 *fname_dir_out = fname_dir;
1516 *fname_mask_out = fname_mask;
1517 return NT_STATUS_OK;
1520 /****************************************************************************
1521 Reply to a search.
1522 Can be called from SMBsearch, SMBffirst or SMBfunique.
1523 ****************************************************************************/
1525 void reply_search(struct smb_request *req)
1527 connection_struct *conn = req->conn;
1528 char *path = NULL;
1529 const char *mask = NULL;
1530 char *directory = NULL;
1531 struct smb_filename *smb_fname = NULL;
1532 char *fname = NULL;
1533 off_t size;
1534 uint32 mode;
1535 struct timespec date;
1536 uint32 dirtype;
1537 unsigned int numentries = 0;
1538 unsigned int maxentries = 0;
1539 bool finished = False;
1540 const char *p;
1541 int status_len;
1542 char status[21];
1543 int dptr_num= -1;
1544 bool check_descend = False;
1545 bool expect_close = False;
1546 NTSTATUS nt_status;
1547 bool mask_contains_wcard = False;
1548 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1549 TALLOC_CTX *ctx = talloc_tos();
1550 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1551 struct dptr_struct *dirptr = NULL;
1552 struct smbd_server_connection *sconn = req->sconn;
1554 START_PROFILE(SMBsearch);
1556 if (req->wct < 2) {
1557 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1558 goto out;
1561 if (lp_posix_pathnames()) {
1562 reply_unknown_new(req, req->cmd);
1563 goto out;
1566 /* If we were called as SMBffirst then we must expect close. */
1567 if(req->cmd == SMBffirst) {
1568 expect_close = True;
1571 reply_outbuf(req, 1, 3);
1572 maxentries = SVAL(req->vwv+0, 0);
1573 dirtype = SVAL(req->vwv+1, 0);
1574 p = (const char *)req->buf + 1;
1575 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1576 &nt_status, &mask_contains_wcard);
1577 if (!NT_STATUS_IS_OK(nt_status)) {
1578 reply_nterror(req, nt_status);
1579 goto out;
1582 p++;
1583 status_len = SVAL(p, 0);
1584 p += 2;
1586 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1588 if (status_len == 0) {
1589 nt_status = filename_convert(ctx, conn,
1590 req->flags2 & FLAGS2_DFS_PATHNAMES,
1591 path,
1592 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1593 &mask_contains_wcard,
1594 &smb_fname);
1595 if (!NT_STATUS_IS_OK(nt_status)) {
1596 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1597 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1598 ERRSRV, ERRbadpath);
1599 goto out;
1601 reply_nterror(req, nt_status);
1602 goto out;
1605 directory = smb_fname->base_name;
1607 p = strrchr_m(directory,'/');
1608 if ((p != NULL) && (*directory != '/')) {
1609 mask = p + 1;
1610 directory = talloc_strndup(ctx, directory,
1611 PTR_DIFF(p, directory));
1612 } else {
1613 mask = directory;
1614 directory = talloc_strdup(ctx,".");
1617 if (!directory) {
1618 reply_nterror(req, NT_STATUS_NO_MEMORY);
1619 goto out;
1622 memset((char *)status,'\0',21);
1623 SCVAL(status,0,(dirtype & 0x1F));
1625 nt_status = dptr_create(conn,
1626 NULL, /* req */
1627 NULL, /* fsp */
1628 directory,
1629 True,
1630 expect_close,
1631 req->smbpid,
1632 mask,
1633 mask_contains_wcard,
1634 dirtype,
1635 &dirptr);
1636 if (!NT_STATUS_IS_OK(nt_status)) {
1637 reply_nterror(req, nt_status);
1638 goto out;
1640 dptr_num = dptr_dnum(dirptr);
1641 } else {
1642 int status_dirtype;
1643 const char *dirpath;
1645 memcpy(status,p,21);
1646 status_dirtype = CVAL(status,0) & 0x1F;
1647 if (status_dirtype != (dirtype & 0x1F)) {
1648 dirtype = status_dirtype;
1651 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1652 if (!dirptr) {
1653 goto SearchEmpty;
1655 dirpath = dptr_path(sconn, dptr_num);
1656 directory = talloc_strdup(ctx, dirpath);
1657 if (!directory) {
1658 reply_nterror(req, NT_STATUS_NO_MEMORY);
1659 goto out;
1662 mask = dptr_wcard(sconn, dptr_num);
1663 if (!mask) {
1664 goto SearchEmpty;
1667 * For a 'continue' search we have no string. So
1668 * check from the initial saved string.
1670 mask_contains_wcard = ms_has_wild(mask);
1671 dirtype = dptr_attr(sconn, dptr_num);
1674 DEBUG(4,("dptr_num is %d\n",dptr_num));
1676 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1677 dptr_init_search_op(dirptr);
1679 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1680 char buf[DIR_STRUCT_SIZE];
1681 memcpy(buf,status,21);
1682 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1683 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1684 reply_nterror(req, NT_STATUS_NO_MEMORY);
1685 goto out;
1687 dptr_fill(sconn, buf+12,dptr_num);
1688 if (dptr_zero(buf+12) && (status_len==0)) {
1689 numentries = 1;
1690 } else {
1691 numentries = 0;
1693 if (message_push_blob(&req->outbuf,
1694 data_blob_const(buf, sizeof(buf)))
1695 == -1) {
1696 reply_nterror(req, NT_STATUS_NO_MEMORY);
1697 goto out;
1699 } else {
1700 unsigned int i;
1701 maxentries = MIN(
1702 maxentries,
1703 ((BUFFER_SIZE -
1704 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1705 /DIR_STRUCT_SIZE));
1707 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1708 directory,lp_dontdescend(ctx, SNUM(conn))));
1709 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1710 check_descend = True;
1713 for (i=numentries;(i<maxentries) && !finished;i++) {
1714 finished = !get_dir_entry(ctx,
1715 dirptr,
1716 mask,
1717 dirtype,
1718 &fname,
1719 &size,
1720 &mode,
1721 &date,
1722 check_descend,
1723 ask_sharemode);
1724 if (!finished) {
1725 char buf[DIR_STRUCT_SIZE];
1726 memcpy(buf,status,21);
1727 if (!make_dir_struct(ctx,
1728 buf,
1729 mask,
1730 fname,
1731 size,
1732 mode,
1733 convert_timespec_to_time_t(date),
1734 !allow_long_path_components)) {
1735 reply_nterror(req, NT_STATUS_NO_MEMORY);
1736 goto out;
1738 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1739 break;
1741 if (message_push_blob(&req->outbuf,
1742 data_blob_const(buf, sizeof(buf)))
1743 == -1) {
1744 reply_nterror(req, NT_STATUS_NO_MEMORY);
1745 goto out;
1747 numentries++;
1752 SearchEmpty:
1754 /* If we were called as SMBffirst with smb_search_id == NULL
1755 and no entries were found then return error and close dirptr
1756 (X/Open spec) */
1758 if (numentries == 0) {
1759 dptr_close(sconn, &dptr_num);
1760 } else if(expect_close && status_len == 0) {
1761 /* Close the dptr - we know it's gone */
1762 dptr_close(sconn, &dptr_num);
1765 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1766 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1767 dptr_close(sconn, &dptr_num);
1770 if ((numentries == 0) && !mask_contains_wcard) {
1771 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1772 goto out;
1775 SSVAL(req->outbuf,smb_vwv0,numentries);
1776 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1777 SCVAL(smb_buf(req->outbuf),0,5);
1778 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1780 /* The replies here are never long name. */
1781 SSVAL(req->outbuf, smb_flg2,
1782 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1783 if (!allow_long_path_components) {
1784 SSVAL(req->outbuf, smb_flg2,
1785 SVAL(req->outbuf, smb_flg2)
1786 & (~FLAGS2_LONG_PATH_COMPONENTS));
1789 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1790 SSVAL(req->outbuf, smb_flg2,
1791 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1793 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1794 smb_fn_name(req->cmd),
1795 mask,
1796 directory,
1797 dirtype,
1798 numentries,
1799 maxentries ));
1800 out:
1801 TALLOC_FREE(directory);
1802 TALLOC_FREE(smb_fname);
1803 END_PROFILE(SMBsearch);
1804 return;
1807 /****************************************************************************
1808 Reply to a fclose (stop directory search).
1809 ****************************************************************************/
1811 void reply_fclose(struct smb_request *req)
1813 int status_len;
1814 char status[21];
1815 int dptr_num= -2;
1816 const char *p;
1817 char *path = NULL;
1818 NTSTATUS err;
1819 bool path_contains_wcard = False;
1820 TALLOC_CTX *ctx = talloc_tos();
1821 struct smbd_server_connection *sconn = req->sconn;
1823 START_PROFILE(SMBfclose);
1825 if (lp_posix_pathnames()) {
1826 reply_unknown_new(req, req->cmd);
1827 END_PROFILE(SMBfclose);
1828 return;
1831 p = (const char *)req->buf + 1;
1832 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1833 &err, &path_contains_wcard);
1834 if (!NT_STATUS_IS_OK(err)) {
1835 reply_nterror(req, err);
1836 END_PROFILE(SMBfclose);
1837 return;
1839 p++;
1840 status_len = SVAL(p,0);
1841 p += 2;
1843 if (status_len == 0) {
1844 reply_force_doserror(req, ERRSRV, ERRsrverror);
1845 END_PROFILE(SMBfclose);
1846 return;
1849 memcpy(status,p,21);
1851 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1852 /* Close the dptr - we know it's gone */
1853 dptr_close(sconn, &dptr_num);
1856 reply_outbuf(req, 1, 0);
1857 SSVAL(req->outbuf,smb_vwv0,0);
1859 DEBUG(3,("search close\n"));
1861 END_PROFILE(SMBfclose);
1862 return;
1865 /****************************************************************************
1866 Reply to an open.
1867 ****************************************************************************/
1869 void reply_open(struct smb_request *req)
1871 connection_struct *conn = req->conn;
1872 struct smb_filename *smb_fname = NULL;
1873 char *fname = NULL;
1874 uint32 fattr=0;
1875 off_t size = 0;
1876 time_t mtime=0;
1877 int info;
1878 files_struct *fsp;
1879 int oplock_request;
1880 int deny_mode;
1881 uint32 dos_attr;
1882 uint32 access_mask;
1883 uint32 share_mode;
1884 uint32 create_disposition;
1885 uint32 create_options = 0;
1886 uint32_t private_flags = 0;
1887 NTSTATUS status;
1888 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1889 TALLOC_CTX *ctx = talloc_tos();
1891 START_PROFILE(SMBopen);
1893 if (req->wct < 2) {
1894 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1895 goto out;
1898 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1899 deny_mode = SVAL(req->vwv+0, 0);
1900 dos_attr = SVAL(req->vwv+1, 0);
1902 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1903 STR_TERMINATE, &status);
1904 if (!NT_STATUS_IS_OK(status)) {
1905 reply_nterror(req, status);
1906 goto out;
1909 if (!map_open_params_to_ntcreate(fname, deny_mode,
1910 OPENX_FILE_EXISTS_OPEN, &access_mask,
1911 &share_mode, &create_disposition,
1912 &create_options, &private_flags)) {
1913 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1914 goto out;
1917 status = filename_convert(ctx,
1918 conn,
1919 req->flags2 & FLAGS2_DFS_PATHNAMES,
1920 fname,
1921 (create_disposition == FILE_CREATE)
1922 ? UCF_CREATING_FILE : 0,
1923 NULL,
1924 &smb_fname);
1925 if (!NT_STATUS_IS_OK(status)) {
1926 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1927 reply_botherror(req,
1928 NT_STATUS_PATH_NOT_COVERED,
1929 ERRSRV, ERRbadpath);
1930 goto out;
1932 reply_nterror(req, status);
1933 goto out;
1936 status = SMB_VFS_CREATE_FILE(
1937 conn, /* conn */
1938 req, /* req */
1939 0, /* root_dir_fid */
1940 smb_fname, /* fname */
1941 access_mask, /* access_mask */
1942 share_mode, /* share_access */
1943 create_disposition, /* create_disposition*/
1944 create_options, /* create_options */
1945 dos_attr, /* file_attributes */
1946 oplock_request, /* oplock_request */
1947 0, /* allocation_size */
1948 private_flags,
1949 NULL, /* sd */
1950 NULL, /* ea_list */
1951 &fsp, /* result */
1952 &info); /* pinfo */
1954 if (!NT_STATUS_IS_OK(status)) {
1955 if (open_was_deferred(req->sconn, req->mid)) {
1956 /* We have re-scheduled this call. */
1957 goto out;
1959 reply_openerror(req, status);
1960 goto out;
1963 size = smb_fname->st.st_ex_size;
1964 fattr = dos_mode(conn, smb_fname);
1966 /* Deal with other possible opens having a modified
1967 write time. JRA. */
1968 if (ask_sharemode) {
1969 struct timespec write_time_ts;
1971 ZERO_STRUCT(write_time_ts);
1972 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1973 if (!null_timespec(write_time_ts)) {
1974 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1978 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1980 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1981 DEBUG(3,("attempt to open a directory %s\n",
1982 fsp_str_dbg(fsp)));
1983 close_file(req, fsp, ERROR_CLOSE);
1984 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1985 ERRDOS, ERRnoaccess);
1986 goto out;
1989 reply_outbuf(req, 7, 0);
1990 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1991 SSVAL(req->outbuf,smb_vwv1,fattr);
1992 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1993 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1994 } else {
1995 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1997 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1998 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2000 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2001 SCVAL(req->outbuf,smb_flg,
2002 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2005 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2006 SCVAL(req->outbuf,smb_flg,
2007 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2009 out:
2010 TALLOC_FREE(smb_fname);
2011 END_PROFILE(SMBopen);
2012 return;
2015 /****************************************************************************
2016 Reply to an open and X.
2017 ****************************************************************************/
2019 void reply_open_and_X(struct smb_request *req)
2021 connection_struct *conn = req->conn;
2022 struct smb_filename *smb_fname = NULL;
2023 char *fname = NULL;
2024 uint16 open_flags;
2025 int deny_mode;
2026 uint32 smb_attr;
2027 /* Breakout the oplock request bits so we can set the
2028 reply bits separately. */
2029 int ex_oplock_request;
2030 int core_oplock_request;
2031 int oplock_request;
2032 #if 0
2033 int smb_sattr = SVAL(req->vwv+4, 0);
2034 uint32 smb_time = make_unix_date3(req->vwv+6);
2035 #endif
2036 int smb_ofun;
2037 uint32 fattr=0;
2038 int mtime=0;
2039 int smb_action = 0;
2040 files_struct *fsp;
2041 NTSTATUS status;
2042 uint64_t allocation_size;
2043 ssize_t retval = -1;
2044 uint32 access_mask;
2045 uint32 share_mode;
2046 uint32 create_disposition;
2047 uint32 create_options = 0;
2048 uint32_t private_flags = 0;
2049 TALLOC_CTX *ctx = talloc_tos();
2051 START_PROFILE(SMBopenX);
2053 if (req->wct < 15) {
2054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2055 goto out;
2058 open_flags = SVAL(req->vwv+2, 0);
2059 deny_mode = SVAL(req->vwv+3, 0);
2060 smb_attr = SVAL(req->vwv+5, 0);
2061 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2062 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2063 oplock_request = ex_oplock_request | core_oplock_request;
2064 smb_ofun = SVAL(req->vwv+8, 0);
2065 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2067 /* If it's an IPC, pass off the pipe handler. */
2068 if (IS_IPC(conn)) {
2069 if (lp_nt_pipe_support()) {
2070 reply_open_pipe_and_X(conn, req);
2071 } else {
2072 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2074 goto out;
2077 /* XXXX we need to handle passed times, sattr and flags */
2078 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2079 STR_TERMINATE, &status);
2080 if (!NT_STATUS_IS_OK(status)) {
2081 reply_nterror(req, status);
2082 goto out;
2085 if (!map_open_params_to_ntcreate(fname, deny_mode,
2086 smb_ofun,
2087 &access_mask, &share_mode,
2088 &create_disposition,
2089 &create_options,
2090 &private_flags)) {
2091 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2092 goto out;
2095 status = filename_convert(ctx,
2096 conn,
2097 req->flags2 & FLAGS2_DFS_PATHNAMES,
2098 fname,
2099 (create_disposition == FILE_CREATE)
2100 ? UCF_CREATING_FILE : 0,
2101 NULL,
2102 &smb_fname);
2103 if (!NT_STATUS_IS_OK(status)) {
2104 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2105 reply_botherror(req,
2106 NT_STATUS_PATH_NOT_COVERED,
2107 ERRSRV, ERRbadpath);
2108 goto out;
2110 reply_nterror(req, status);
2111 goto out;
2114 status = SMB_VFS_CREATE_FILE(
2115 conn, /* conn */
2116 req, /* req */
2117 0, /* root_dir_fid */
2118 smb_fname, /* fname */
2119 access_mask, /* access_mask */
2120 share_mode, /* share_access */
2121 create_disposition, /* create_disposition*/
2122 create_options, /* create_options */
2123 smb_attr, /* file_attributes */
2124 oplock_request, /* oplock_request */
2125 0, /* allocation_size */
2126 private_flags,
2127 NULL, /* sd */
2128 NULL, /* ea_list */
2129 &fsp, /* result */
2130 &smb_action); /* pinfo */
2132 if (!NT_STATUS_IS_OK(status)) {
2133 if (open_was_deferred(req->sconn, req->mid)) {
2134 /* We have re-scheduled this call. */
2135 goto out;
2137 reply_openerror(req, status);
2138 goto out;
2141 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2142 if the file is truncated or created. */
2143 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2144 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2145 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2146 close_file(req, fsp, ERROR_CLOSE);
2147 reply_nterror(req, NT_STATUS_DISK_FULL);
2148 goto out;
2150 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2151 if (retval < 0) {
2152 close_file(req, fsp, ERROR_CLOSE);
2153 reply_nterror(req, NT_STATUS_DISK_FULL);
2154 goto out;
2156 status = vfs_stat_fsp(fsp);
2157 if (!NT_STATUS_IS_OK(status)) {
2158 close_file(req, fsp, ERROR_CLOSE);
2159 reply_nterror(req, status);
2160 goto out;
2164 fattr = dos_mode(conn, fsp->fsp_name);
2165 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2166 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2167 close_file(req, fsp, ERROR_CLOSE);
2168 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2169 goto out;
2172 /* If the caller set the extended oplock request bit
2173 and we granted one (by whatever means) - set the
2174 correct bit for extended oplock reply.
2177 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2178 smb_action |= EXTENDED_OPLOCK_GRANTED;
2181 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2182 smb_action |= EXTENDED_OPLOCK_GRANTED;
2185 /* If the caller set the core oplock request bit
2186 and we granted one (by whatever means) - set the
2187 correct bit for core oplock reply.
2190 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2191 reply_outbuf(req, 19, 0);
2192 } else {
2193 reply_outbuf(req, 15, 0);
2196 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2197 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2199 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2200 SCVAL(req->outbuf, smb_flg,
2201 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2204 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2205 SCVAL(req->outbuf, smb_flg,
2206 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2209 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2210 SSVAL(req->outbuf,smb_vwv3,fattr);
2211 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2212 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2213 } else {
2214 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2216 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2217 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2218 SSVAL(req->outbuf,smb_vwv11,smb_action);
2220 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2221 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2224 out:
2225 TALLOC_FREE(smb_fname);
2226 END_PROFILE(SMBopenX);
2227 return;
2230 /****************************************************************************
2231 Reply to a SMBulogoffX.
2232 ****************************************************************************/
2234 void reply_ulogoffX(struct smb_request *req)
2236 struct smbd_server_connection *sconn = req->sconn;
2237 struct user_struct *vuser;
2238 struct smbXsrv_session *session = NULL;
2239 NTSTATUS status;
2241 START_PROFILE(SMBulogoffX);
2243 vuser = get_valid_user_struct(sconn, req->vuid);
2245 if(vuser == NULL) {
2246 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2247 (unsigned long long)req->vuid));
2249 req->vuid = UID_FIELD_INVALID;
2250 reply_force_doserror(req, ERRSRV, ERRbaduid);
2251 END_PROFILE(SMBulogoffX);
2252 return;
2255 session = vuser->session;
2256 vuser = NULL;
2259 * TODO: cancel all outstanding requests on the session
2261 status = smbXsrv_session_logoff(session);
2262 if (!NT_STATUS_IS_OK(status)) {
2263 DEBUG(0, ("reply_ulogoff: "
2264 "smbXsrv_session_logoff() failed: %s\n",
2265 nt_errstr(status)));
2267 * If we hit this case, there is something completely
2268 * wrong, so we better disconnect the transport connection.
2270 END_PROFILE(SMBulogoffX);
2271 exit_server(__location__ ": smbXsrv_session_logoff failed");
2272 return;
2275 TALLOC_FREE(session);
2277 reply_outbuf(req, 2, 0);
2278 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2279 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2281 DEBUG(3, ("ulogoffX vuid=%llu\n",
2282 (unsigned long long)req->vuid));
2284 END_PROFILE(SMBulogoffX);
2285 req->vuid = UID_FIELD_INVALID;
2288 /****************************************************************************
2289 Reply to a mknew or a create.
2290 ****************************************************************************/
2292 void reply_mknew(struct smb_request *req)
2294 connection_struct *conn = req->conn;
2295 struct smb_filename *smb_fname = NULL;
2296 char *fname = NULL;
2297 uint32 fattr = 0;
2298 struct smb_file_time ft;
2299 files_struct *fsp;
2300 int oplock_request = 0;
2301 NTSTATUS status;
2302 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2303 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2304 uint32 create_disposition;
2305 uint32 create_options = 0;
2306 TALLOC_CTX *ctx = talloc_tos();
2308 START_PROFILE(SMBcreate);
2309 ZERO_STRUCT(ft);
2311 if (req->wct < 3) {
2312 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2313 goto out;
2316 fattr = SVAL(req->vwv+0, 0);
2317 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2319 /* mtime. */
2320 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2322 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2323 STR_TERMINATE, &status);
2324 if (!NT_STATUS_IS_OK(status)) {
2325 reply_nterror(req, status);
2326 goto out;
2329 status = filename_convert(ctx,
2330 conn,
2331 req->flags2 & FLAGS2_DFS_PATHNAMES,
2332 fname,
2333 UCF_CREATING_FILE,
2334 NULL,
2335 &smb_fname);
2336 if (!NT_STATUS_IS_OK(status)) {
2337 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2338 reply_botherror(req,
2339 NT_STATUS_PATH_NOT_COVERED,
2340 ERRSRV, ERRbadpath);
2341 goto out;
2343 reply_nterror(req, status);
2344 goto out;
2347 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2348 DEBUG(0,("Attempt to create file (%s) with volid set - "
2349 "please report this\n",
2350 smb_fname_str_dbg(smb_fname)));
2353 if(req->cmd == SMBmknew) {
2354 /* We should fail if file exists. */
2355 create_disposition = FILE_CREATE;
2356 } else {
2357 /* Create if file doesn't exist, truncate if it does. */
2358 create_disposition = FILE_OVERWRITE_IF;
2361 status = SMB_VFS_CREATE_FILE(
2362 conn, /* conn */
2363 req, /* req */
2364 0, /* root_dir_fid */
2365 smb_fname, /* fname */
2366 access_mask, /* access_mask */
2367 share_mode, /* share_access */
2368 create_disposition, /* create_disposition*/
2369 create_options, /* create_options */
2370 fattr, /* file_attributes */
2371 oplock_request, /* oplock_request */
2372 0, /* allocation_size */
2373 0, /* private_flags */
2374 NULL, /* sd */
2375 NULL, /* ea_list */
2376 &fsp, /* result */
2377 NULL); /* pinfo */
2379 if (!NT_STATUS_IS_OK(status)) {
2380 if (open_was_deferred(req->sconn, req->mid)) {
2381 /* We have re-scheduled this call. */
2382 goto out;
2384 reply_openerror(req, status);
2385 goto out;
2388 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2389 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2390 if (!NT_STATUS_IS_OK(status)) {
2391 END_PROFILE(SMBcreate);
2392 goto out;
2395 reply_outbuf(req, 1, 0);
2396 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2398 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2399 SCVAL(req->outbuf,smb_flg,
2400 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2403 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2404 SCVAL(req->outbuf,smb_flg,
2405 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2408 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2409 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2410 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2411 (unsigned int)fattr));
2413 out:
2414 TALLOC_FREE(smb_fname);
2415 END_PROFILE(SMBcreate);
2416 return;
2419 /****************************************************************************
2420 Reply to a create temporary file.
2421 ****************************************************************************/
2423 void reply_ctemp(struct smb_request *req)
2425 connection_struct *conn = req->conn;
2426 struct smb_filename *smb_fname = NULL;
2427 char *wire_name = NULL;
2428 char *fname = NULL;
2429 uint32 fattr;
2430 files_struct *fsp;
2431 int oplock_request;
2432 char *s;
2433 NTSTATUS status;
2434 int i;
2435 TALLOC_CTX *ctx = talloc_tos();
2437 START_PROFILE(SMBctemp);
2439 if (req->wct < 3) {
2440 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2441 goto out;
2444 fattr = SVAL(req->vwv+0, 0);
2445 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2447 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2448 STR_TERMINATE, &status);
2449 if (!NT_STATUS_IS_OK(status)) {
2450 reply_nterror(req, status);
2451 goto out;
2454 for (i = 0; i < 10; i++) {
2455 if (*wire_name) {
2456 fname = talloc_asprintf(ctx,
2457 "%s/TMP%s",
2458 wire_name,
2459 generate_random_str_list(ctx, 5, "0123456789"));
2460 } else {
2461 fname = talloc_asprintf(ctx,
2462 "TMP%s",
2463 generate_random_str_list(ctx, 5, "0123456789"));
2466 if (!fname) {
2467 reply_nterror(req, NT_STATUS_NO_MEMORY);
2468 goto out;
2471 status = filename_convert(ctx, conn,
2472 req->flags2 & FLAGS2_DFS_PATHNAMES,
2473 fname,
2474 UCF_CREATING_FILE,
2475 NULL,
2476 &smb_fname);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2479 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2480 ERRSRV, ERRbadpath);
2481 goto out;
2483 reply_nterror(req, status);
2484 goto out;
2487 /* Create the file. */
2488 status = SMB_VFS_CREATE_FILE(
2489 conn, /* conn */
2490 req, /* req */
2491 0, /* root_dir_fid */
2492 smb_fname, /* fname */
2493 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2494 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2495 FILE_CREATE, /* create_disposition*/
2496 0, /* create_options */
2497 fattr, /* file_attributes */
2498 oplock_request, /* oplock_request */
2499 0, /* allocation_size */
2500 0, /* private_flags */
2501 NULL, /* sd */
2502 NULL, /* ea_list */
2503 &fsp, /* result */
2504 NULL); /* pinfo */
2506 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2507 TALLOC_FREE(fname);
2508 TALLOC_FREE(smb_fname);
2509 continue;
2512 if (!NT_STATUS_IS_OK(status)) {
2513 if (open_was_deferred(req->sconn, req->mid)) {
2514 /* We have re-scheduled this call. */
2515 goto out;
2517 reply_openerror(req, status);
2518 goto out;
2521 break;
2524 if (i == 10) {
2525 /* Collision after 10 times... */
2526 reply_nterror(req, status);
2527 goto out;
2530 reply_outbuf(req, 1, 0);
2531 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2533 /* the returned filename is relative to the directory */
2534 s = strrchr_m(fsp->fsp_name->base_name, '/');
2535 if (!s) {
2536 s = fsp->fsp_name->base_name;
2537 } else {
2538 s++;
2541 #if 0
2542 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2543 thing in the byte section. JRA */
2544 SSVALS(p, 0, -1); /* what is this? not in spec */
2545 #endif
2546 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2547 == -1) {
2548 reply_nterror(req, NT_STATUS_NO_MEMORY);
2549 goto out;
2552 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2553 SCVAL(req->outbuf, smb_flg,
2554 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2557 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2558 SCVAL(req->outbuf, smb_flg,
2559 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2562 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2563 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2564 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2565 out:
2566 TALLOC_FREE(smb_fname);
2567 TALLOC_FREE(wire_name);
2568 END_PROFILE(SMBctemp);
2569 return;
2572 /*******************************************************************
2573 Check if a user is allowed to rename a file.
2574 ********************************************************************/
2576 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2577 uint16 dirtype)
2579 if (!CAN_WRITE(conn)) {
2580 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2583 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2584 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2585 /* Only bother to read the DOS attribute if we might deny the
2586 rename on the grounds of attribute missmatch. */
2587 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2588 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2589 return NT_STATUS_NO_SUCH_FILE;
2593 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2594 if (fsp->posix_open) {
2595 return NT_STATUS_OK;
2598 /* If no pathnames are open below this
2599 directory, allow the rename. */
2601 if (file_find_subpath(fsp)) {
2602 return NT_STATUS_ACCESS_DENIED;
2604 return NT_STATUS_OK;
2607 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2608 return NT_STATUS_OK;
2611 return NT_STATUS_ACCESS_DENIED;
2614 /*******************************************************************
2615 * unlink a file with all relevant access checks
2616 *******************************************************************/
2618 static NTSTATUS do_unlink(connection_struct *conn,
2619 struct smb_request *req,
2620 struct smb_filename *smb_fname,
2621 uint32 dirtype)
2623 uint32 fattr;
2624 files_struct *fsp;
2625 uint32 dirtype_orig = dirtype;
2626 NTSTATUS status;
2627 int ret;
2628 bool posix_paths = lp_posix_pathnames();
2630 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2631 smb_fname_str_dbg(smb_fname),
2632 dirtype));
2634 if (!CAN_WRITE(conn)) {
2635 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2638 if (posix_paths) {
2639 ret = SMB_VFS_LSTAT(conn, smb_fname);
2640 } else {
2641 ret = SMB_VFS_STAT(conn, smb_fname);
2643 if (ret != 0) {
2644 return map_nt_error_from_unix(errno);
2647 fattr = dos_mode(conn, smb_fname);
2649 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2650 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2653 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2654 if (!dirtype) {
2655 return NT_STATUS_NO_SUCH_FILE;
2658 if (!dir_check_ftype(conn, fattr, dirtype)) {
2659 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2660 return NT_STATUS_FILE_IS_A_DIRECTORY;
2662 return NT_STATUS_NO_SUCH_FILE;
2665 if (dirtype_orig & 0x8000) {
2666 /* These will never be set for POSIX. */
2667 return NT_STATUS_NO_SUCH_FILE;
2670 #if 0
2671 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2672 return NT_STATUS_FILE_IS_A_DIRECTORY;
2675 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2676 return NT_STATUS_NO_SUCH_FILE;
2679 if (dirtype & 0xFF00) {
2680 /* These will never be set for POSIX. */
2681 return NT_STATUS_NO_SUCH_FILE;
2684 dirtype &= 0xFF;
2685 if (!dirtype) {
2686 return NT_STATUS_NO_SUCH_FILE;
2689 /* Can't delete a directory. */
2690 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2691 return NT_STATUS_FILE_IS_A_DIRECTORY;
2693 #endif
2695 #if 0 /* JRATEST */
2696 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2697 return NT_STATUS_OBJECT_NAME_INVALID;
2698 #endif /* JRATEST */
2700 /* On open checks the open itself will check the share mode, so
2701 don't do it here as we'll get it wrong. */
2703 status = SMB_VFS_CREATE_FILE
2704 (conn, /* conn */
2705 req, /* req */
2706 0, /* root_dir_fid */
2707 smb_fname, /* fname */
2708 DELETE_ACCESS, /* access_mask */
2709 FILE_SHARE_NONE, /* share_access */
2710 FILE_OPEN, /* create_disposition*/
2711 FILE_NON_DIRECTORY_FILE, /* create_options */
2712 /* file_attributes */
2713 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2714 FILE_ATTRIBUTE_NORMAL,
2715 0, /* oplock_request */
2716 0, /* allocation_size */
2717 0, /* private_flags */
2718 NULL, /* sd */
2719 NULL, /* ea_list */
2720 &fsp, /* result */
2721 NULL); /* pinfo */
2723 if (!NT_STATUS_IS_OK(status)) {
2724 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2725 nt_errstr(status)));
2726 return status;
2729 status = can_set_delete_on_close(fsp, fattr);
2730 if (!NT_STATUS_IS_OK(status)) {
2731 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2732 "(%s)\n",
2733 smb_fname_str_dbg(smb_fname),
2734 nt_errstr(status)));
2735 close_file(req, fsp, NORMAL_CLOSE);
2736 return status;
2739 /* The set is across all open files on this dev/inode pair. */
2740 if (!set_delete_on_close(fsp, True,
2741 conn->session_info->security_token,
2742 conn->session_info->unix_token)) {
2743 close_file(req, fsp, NORMAL_CLOSE);
2744 return NT_STATUS_ACCESS_DENIED;
2747 return close_file(req, fsp, NORMAL_CLOSE);
2750 /****************************************************************************
2751 The guts of the unlink command, split out so it may be called by the NT SMB
2752 code.
2753 ****************************************************************************/
2755 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2756 uint32 dirtype, struct smb_filename *smb_fname,
2757 bool has_wild)
2759 char *fname_dir = NULL;
2760 char *fname_mask = NULL;
2761 int count=0;
2762 NTSTATUS status = NT_STATUS_OK;
2763 TALLOC_CTX *ctx = talloc_tos();
2765 /* Split up the directory from the filename/mask. */
2766 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2767 &fname_dir, &fname_mask);
2768 if (!NT_STATUS_IS_OK(status)) {
2769 goto out;
2773 * We should only check the mangled cache
2774 * here if unix_convert failed. This means
2775 * that the path in 'mask' doesn't exist
2776 * on the file system and so we need to look
2777 * for a possible mangle. This patch from
2778 * Tine Smukavec <valentin.smukavec@hermes.si>.
2781 if (!VALID_STAT(smb_fname->st) &&
2782 mangle_is_mangled(fname_mask, conn->params)) {
2783 char *new_mask = NULL;
2784 mangle_lookup_name_from_8_3(ctx, fname_mask,
2785 &new_mask, conn->params);
2786 if (new_mask) {
2787 TALLOC_FREE(fname_mask);
2788 fname_mask = new_mask;
2792 if (!has_wild) {
2795 * Only one file needs to be unlinked. Append the mask back
2796 * onto the directory.
2798 TALLOC_FREE(smb_fname->base_name);
2799 if (ISDOT(fname_dir)) {
2800 /* Ensure we use canonical names on open. */
2801 smb_fname->base_name = talloc_asprintf(smb_fname,
2802 "%s",
2803 fname_mask);
2804 } else {
2805 smb_fname->base_name = talloc_asprintf(smb_fname,
2806 "%s/%s",
2807 fname_dir,
2808 fname_mask);
2810 if (!smb_fname->base_name) {
2811 status = NT_STATUS_NO_MEMORY;
2812 goto out;
2814 if (dirtype == 0) {
2815 dirtype = FILE_ATTRIBUTE_NORMAL;
2818 status = check_name(conn, smb_fname->base_name);
2819 if (!NT_STATUS_IS_OK(status)) {
2820 goto out;
2823 status = do_unlink(conn, req, smb_fname, dirtype);
2824 if (!NT_STATUS_IS_OK(status)) {
2825 goto out;
2828 count++;
2829 } else {
2830 struct smb_Dir *dir_hnd = NULL;
2831 long offset = 0;
2832 const char *dname = NULL;
2833 char *talloced = NULL;
2835 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2836 status = NT_STATUS_OBJECT_NAME_INVALID;
2837 goto out;
2840 if (strequal(fname_mask,"????????.???")) {
2841 TALLOC_FREE(fname_mask);
2842 fname_mask = talloc_strdup(ctx, "*");
2843 if (!fname_mask) {
2844 status = NT_STATUS_NO_MEMORY;
2845 goto out;
2849 status = check_name(conn, fname_dir);
2850 if (!NT_STATUS_IS_OK(status)) {
2851 goto out;
2854 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2855 dirtype);
2856 if (dir_hnd == NULL) {
2857 status = map_nt_error_from_unix(errno);
2858 goto out;
2861 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2862 the pattern matches against the long name, otherwise the short name
2863 We don't implement this yet XXXX
2866 status = NT_STATUS_NO_SUCH_FILE;
2868 while ((dname = ReadDirName(dir_hnd, &offset,
2869 &smb_fname->st, &talloced))) {
2870 TALLOC_CTX *frame = talloc_stackframe();
2872 if (!is_visible_file(conn, fname_dir, dname,
2873 &smb_fname->st, true)) {
2874 TALLOC_FREE(frame);
2875 TALLOC_FREE(talloced);
2876 continue;
2879 /* Quick check for "." and ".." */
2880 if (ISDOT(dname) || ISDOTDOT(dname)) {
2881 TALLOC_FREE(frame);
2882 TALLOC_FREE(talloced);
2883 continue;
2886 if(!mask_match(dname, fname_mask,
2887 conn->case_sensitive)) {
2888 TALLOC_FREE(frame);
2889 TALLOC_FREE(talloced);
2890 continue;
2893 TALLOC_FREE(smb_fname->base_name);
2894 if (ISDOT(fname_dir)) {
2895 /* Ensure we use canonical names on open. */
2896 smb_fname->base_name =
2897 talloc_asprintf(smb_fname, "%s",
2898 dname);
2899 } else {
2900 smb_fname->base_name =
2901 talloc_asprintf(smb_fname, "%s/%s",
2902 fname_dir, dname);
2905 if (!smb_fname->base_name) {
2906 TALLOC_FREE(dir_hnd);
2907 status = NT_STATUS_NO_MEMORY;
2908 TALLOC_FREE(frame);
2909 TALLOC_FREE(talloced);
2910 goto out;
2913 status = check_name(conn, smb_fname->base_name);
2914 if (!NT_STATUS_IS_OK(status)) {
2915 TALLOC_FREE(dir_hnd);
2916 TALLOC_FREE(frame);
2917 TALLOC_FREE(talloced);
2918 goto out;
2921 status = do_unlink(conn, req, smb_fname, dirtype);
2922 if (!NT_STATUS_IS_OK(status)) {
2923 TALLOC_FREE(frame);
2924 TALLOC_FREE(talloced);
2925 continue;
2928 count++;
2929 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2930 smb_fname->base_name));
2932 TALLOC_FREE(frame);
2933 TALLOC_FREE(talloced);
2935 TALLOC_FREE(dir_hnd);
2938 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2939 status = map_nt_error_from_unix(errno);
2942 out:
2943 TALLOC_FREE(fname_dir);
2944 TALLOC_FREE(fname_mask);
2945 return status;
2948 /****************************************************************************
2949 Reply to a unlink
2950 ****************************************************************************/
2952 void reply_unlink(struct smb_request *req)
2954 connection_struct *conn = req->conn;
2955 char *name = NULL;
2956 struct smb_filename *smb_fname = NULL;
2957 uint32 dirtype;
2958 NTSTATUS status;
2959 bool path_contains_wcard = False;
2960 TALLOC_CTX *ctx = talloc_tos();
2962 START_PROFILE(SMBunlink);
2964 if (req->wct < 1) {
2965 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2966 goto out;
2969 dirtype = SVAL(req->vwv+0, 0);
2971 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2972 STR_TERMINATE, &status,
2973 &path_contains_wcard);
2974 if (!NT_STATUS_IS_OK(status)) {
2975 reply_nterror(req, status);
2976 goto out;
2979 status = filename_convert(ctx, conn,
2980 req->flags2 & FLAGS2_DFS_PATHNAMES,
2981 name,
2982 UCF_COND_ALLOW_WCARD_LCOMP,
2983 &path_contains_wcard,
2984 &smb_fname);
2985 if (!NT_STATUS_IS_OK(status)) {
2986 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2987 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2988 ERRSRV, ERRbadpath);
2989 goto out;
2991 reply_nterror(req, status);
2992 goto out;
2995 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2997 status = unlink_internals(conn, req, dirtype, smb_fname,
2998 path_contains_wcard);
2999 if (!NT_STATUS_IS_OK(status)) {
3000 if (open_was_deferred(req->sconn, req->mid)) {
3001 /* We have re-scheduled this call. */
3002 goto out;
3004 reply_nterror(req, status);
3005 goto out;
3008 reply_outbuf(req, 0, 0);
3009 out:
3010 TALLOC_FREE(smb_fname);
3011 END_PROFILE(SMBunlink);
3012 return;
3015 /****************************************************************************
3016 Fail for readbraw.
3017 ****************************************************************************/
3019 static void fail_readraw(void)
3021 const char *errstr = talloc_asprintf(talloc_tos(),
3022 "FAIL ! reply_readbraw: socket write fail (%s)",
3023 strerror(errno));
3024 if (!errstr) {
3025 errstr = "";
3027 exit_server_cleanly(errstr);
3030 /****************************************************************************
3031 Fake (read/write) sendfile. Returns -1 on read or write fail.
3032 ****************************************************************************/
3034 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
3036 size_t bufsize;
3037 size_t tosend = nread;
3038 char *buf;
3040 if (nread == 0) {
3041 return 0;
3044 bufsize = MIN(nread, 65536);
3046 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3047 return -1;
3050 while (tosend > 0) {
3051 ssize_t ret;
3052 size_t cur_read;
3054 if (tosend > bufsize) {
3055 cur_read = bufsize;
3056 } else {
3057 cur_read = tosend;
3059 ret = read_file(fsp,buf,startpos,cur_read);
3060 if (ret == -1) {
3061 SAFE_FREE(buf);
3062 return -1;
3065 /* If we had a short read, fill with zeros. */
3066 if (ret < cur_read) {
3067 memset(buf + ret, '\0', cur_read - ret);
3070 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3071 != cur_read) {
3072 char addr[INET6_ADDRSTRLEN];
3074 * Try and give an error message saying what
3075 * client failed.
3077 DEBUG(0, ("write_data failed for client %s. "
3078 "Error %s\n",
3079 get_peer_addr(fsp->conn->sconn->sock, addr,
3080 sizeof(addr)),
3081 strerror(errno)));
3082 SAFE_FREE(buf);
3083 return -1;
3085 tosend -= cur_read;
3086 startpos += cur_read;
3089 SAFE_FREE(buf);
3090 return (ssize_t)nread;
3093 /****************************************************************************
3094 Deal with the case of sendfile reading less bytes from the file than
3095 requested. Fill with zeros (all we can do).
3096 ****************************************************************************/
3098 void sendfile_short_send(files_struct *fsp,
3099 ssize_t nread,
3100 size_t headersize,
3101 size_t smb_maxcnt)
3103 #define SHORT_SEND_BUFSIZE 1024
3104 if (nread < headersize) {
3105 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3106 "header for file %s (%s). Terminating\n",
3107 fsp_str_dbg(fsp), strerror(errno)));
3108 exit_server_cleanly("sendfile_short_send failed");
3111 nread -= headersize;
3113 if (nread < smb_maxcnt) {
3114 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3115 if (!buf) {
3116 exit_server_cleanly("sendfile_short_send: "
3117 "malloc failed");
3120 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3121 "with zeros !\n", fsp_str_dbg(fsp)));
3123 while (nread < smb_maxcnt) {
3125 * We asked for the real file size and told sendfile
3126 * to not go beyond the end of the file. But it can
3127 * happen that in between our fstat call and the
3128 * sendfile call the file was truncated. This is very
3129 * bad because we have already announced the larger
3130 * number of bytes to the client.
3132 * The best we can do now is to send 0-bytes, just as
3133 * a read from a hole in a sparse file would do.
3135 * This should happen rarely enough that I don't care
3136 * about efficiency here :-)
3138 size_t to_write;
3140 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3141 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3142 != to_write) {
3143 char addr[INET6_ADDRSTRLEN];
3145 * Try and give an error message saying what
3146 * client failed.
3148 DEBUG(0, ("write_data failed for client %s. "
3149 "Error %s\n",
3150 get_peer_addr(
3151 fsp->conn->sconn->sock, addr,
3152 sizeof(addr)),
3153 strerror(errno)));
3154 exit_server_cleanly("sendfile_short_send: "
3155 "write_data failed");
3157 nread += to_write;
3159 SAFE_FREE(buf);
3163 /****************************************************************************
3164 Return a readbraw error (4 bytes of zero).
3165 ****************************************************************************/
3167 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3169 char header[4];
3171 SIVAL(header,0,0);
3173 smbd_lock_socket(sconn);
3174 if (write_data(sconn->sock,header,4) != 4) {
3175 char addr[INET6_ADDRSTRLEN];
3177 * Try and give an error message saying what
3178 * client failed.
3180 DEBUG(0, ("write_data failed for client %s. "
3181 "Error %s\n",
3182 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3183 strerror(errno)));
3185 fail_readraw();
3187 smbd_unlock_socket(sconn);
3190 /****************************************************************************
3191 Use sendfile in readbraw.
3192 ****************************************************************************/
3194 static void send_file_readbraw(connection_struct *conn,
3195 struct smb_request *req,
3196 files_struct *fsp,
3197 off_t startpos,
3198 size_t nread,
3199 ssize_t mincount)
3201 struct smbd_server_connection *sconn = req->sconn;
3202 char *outbuf = NULL;
3203 ssize_t ret=0;
3206 * We can only use sendfile on a non-chained packet
3207 * but we can use on a non-oplocked file. tridge proved this
3208 * on a train in Germany :-). JRA.
3209 * reply_readbraw has already checked the length.
3212 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3213 (fsp->wcp == NULL) &&
3214 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3215 ssize_t sendfile_read = -1;
3216 char header[4];
3217 DATA_BLOB header_blob;
3219 _smb_setlen(header,nread);
3220 header_blob = data_blob_const(header, 4);
3222 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3223 &header_blob, startpos,
3224 nread);
3225 if (sendfile_read == -1) {
3226 /* Returning ENOSYS means no data at all was sent.
3227 * Do this as a normal read. */
3228 if (errno == ENOSYS) {
3229 goto normal_readbraw;
3233 * Special hack for broken Linux with no working sendfile. If we
3234 * return EINTR we sent the header but not the rest of the data.
3235 * Fake this up by doing read/write calls.
3237 if (errno == EINTR) {
3238 /* Ensure we don't do this again. */
3239 set_use_sendfile(SNUM(conn), False);
3240 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3242 if (fake_sendfile(fsp, startpos, nread) == -1) {
3243 DEBUG(0,("send_file_readbraw: "
3244 "fake_sendfile failed for "
3245 "file %s (%s).\n",
3246 fsp_str_dbg(fsp),
3247 strerror(errno)));
3248 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3250 return;
3253 DEBUG(0,("send_file_readbraw: sendfile failed for "
3254 "file %s (%s). Terminating\n",
3255 fsp_str_dbg(fsp), strerror(errno)));
3256 exit_server_cleanly("send_file_readbraw sendfile failed");
3257 } else if (sendfile_read == 0) {
3259 * Some sendfile implementations return 0 to indicate
3260 * that there was a short read, but nothing was
3261 * actually written to the socket. In this case,
3262 * fallback to the normal read path so the header gets
3263 * the correct byte count.
3265 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3266 "bytes falling back to the normal read: "
3267 "%s\n", fsp_str_dbg(fsp)));
3268 goto normal_readbraw;
3271 /* Deal with possible short send. */
3272 if (sendfile_read != 4+nread) {
3273 sendfile_short_send(fsp, sendfile_read, 4, nread);
3275 return;
3278 normal_readbraw:
3280 outbuf = talloc_array(NULL, char, nread+4);
3281 if (!outbuf) {
3282 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3283 (unsigned)(nread+4)));
3284 reply_readbraw_error(sconn);
3285 return;
3288 if (nread > 0) {
3289 ret = read_file(fsp,outbuf+4,startpos,nread);
3290 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3291 if (ret < mincount)
3292 ret = 0;
3293 #else
3294 if (ret < nread)
3295 ret = 0;
3296 #endif
3299 _smb_setlen(outbuf,ret);
3300 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3301 char addr[INET6_ADDRSTRLEN];
3303 * Try and give an error message saying what
3304 * client failed.
3306 DEBUG(0, ("write_data failed for client %s. "
3307 "Error %s\n",
3308 get_peer_addr(fsp->conn->sconn->sock, addr,
3309 sizeof(addr)),
3310 strerror(errno)));
3312 fail_readraw();
3315 TALLOC_FREE(outbuf);
3318 /****************************************************************************
3319 Reply to a readbraw (core+ protocol).
3320 ****************************************************************************/
3322 void reply_readbraw(struct smb_request *req)
3324 connection_struct *conn = req->conn;
3325 struct smbd_server_connection *sconn = req->sconn;
3326 ssize_t maxcount,mincount;
3327 size_t nread = 0;
3328 off_t startpos;
3329 files_struct *fsp;
3330 struct lock_struct lock;
3331 off_t size = 0;
3333 START_PROFILE(SMBreadbraw);
3335 if (srv_is_signing_active(sconn) || req->encrypted) {
3336 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3337 "raw reads/writes are disallowed.");
3340 if (req->wct < 8) {
3341 reply_readbraw_error(sconn);
3342 END_PROFILE(SMBreadbraw);
3343 return;
3346 if (sconn->smb1.echo_handler.trusted_fde) {
3347 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3348 "'async smb echo handler = yes'\n"));
3349 reply_readbraw_error(sconn);
3350 END_PROFILE(SMBreadbraw);
3351 return;
3355 * Special check if an oplock break has been issued
3356 * and the readraw request croses on the wire, we must
3357 * return a zero length response here.
3360 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3363 * We have to do a check_fsp by hand here, as
3364 * we must always return 4 zero bytes on error,
3365 * not a NTSTATUS.
3368 if (!fsp || !conn || conn != fsp->conn ||
3369 req->vuid != fsp->vuid ||
3370 fsp->is_directory || fsp->fh->fd == -1) {
3372 * fsp could be NULL here so use the value from the packet. JRA.
3374 DEBUG(3,("reply_readbraw: fnum %d not valid "
3375 "- cache prime?\n",
3376 (int)SVAL(req->vwv+0, 0)));
3377 reply_readbraw_error(sconn);
3378 END_PROFILE(SMBreadbraw);
3379 return;
3382 /* Do a "by hand" version of CHECK_READ. */
3383 if (!(fsp->can_read ||
3384 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3385 (fsp->access_mask & FILE_EXECUTE)))) {
3386 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3387 (int)SVAL(req->vwv+0, 0)));
3388 reply_readbraw_error(sconn);
3389 END_PROFILE(SMBreadbraw);
3390 return;
3393 flush_write_cache(fsp, READRAW_FLUSH);
3395 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3396 if(req->wct == 10) {
3398 * This is a large offset (64 bit) read.
3401 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3403 if(startpos < 0) {
3404 DEBUG(0,("reply_readbraw: negative 64 bit "
3405 "readraw offset (%.0f) !\n",
3406 (double)startpos ));
3407 reply_readbraw_error(sconn);
3408 END_PROFILE(SMBreadbraw);
3409 return;
3413 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3414 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3416 /* ensure we don't overrun the packet size */
3417 maxcount = MIN(65535,maxcount);
3419 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3420 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3421 &lock);
3423 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3424 reply_readbraw_error(sconn);
3425 END_PROFILE(SMBreadbraw);
3426 return;
3429 if (fsp_stat(fsp) == 0) {
3430 size = fsp->fsp_name->st.st_ex_size;
3433 if (startpos >= size) {
3434 nread = 0;
3435 } else {
3436 nread = MIN(maxcount,(size - startpos));
3439 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3440 if (nread < mincount)
3441 nread = 0;
3442 #endif
3444 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3445 "min=%lu nread=%lu\n",
3446 fsp_fnum_dbg(fsp), (double)startpos,
3447 (unsigned long)maxcount,
3448 (unsigned long)mincount,
3449 (unsigned long)nread ) );
3451 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3453 DEBUG(5,("reply_readbraw finished\n"));
3455 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3457 END_PROFILE(SMBreadbraw);
3458 return;
3461 #undef DBGC_CLASS
3462 #define DBGC_CLASS DBGC_LOCKING
3464 /****************************************************************************
3465 Reply to a lockread (core+ protocol).
3466 ****************************************************************************/
3468 void reply_lockread(struct smb_request *req)
3470 connection_struct *conn = req->conn;
3471 ssize_t nread = -1;
3472 char *data;
3473 off_t startpos;
3474 size_t numtoread;
3475 NTSTATUS status;
3476 files_struct *fsp;
3477 struct byte_range_lock *br_lck = NULL;
3478 char *p = NULL;
3479 struct smbd_server_connection *sconn = req->sconn;
3481 START_PROFILE(SMBlockread);
3483 if (req->wct < 5) {
3484 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3485 END_PROFILE(SMBlockread);
3486 return;
3489 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3491 if (!check_fsp(conn, req, fsp)) {
3492 END_PROFILE(SMBlockread);
3493 return;
3496 if (!CHECK_READ(fsp,req)) {
3497 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3498 END_PROFILE(SMBlockread);
3499 return;
3502 numtoread = SVAL(req->vwv+1, 0);
3503 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3505 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3507 reply_outbuf(req, 5, numtoread + 3);
3509 data = smb_buf(req->outbuf) + 3;
3512 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3513 * protocol request that predates the read/write lock concept.
3514 * Thus instead of asking for a read lock here we need to ask
3515 * for a write lock. JRA.
3516 * Note that the requested lock size is unaffected by max_recv.
3519 br_lck = do_lock(req->sconn->msg_ctx,
3520 fsp,
3521 (uint64_t)req->smbpid,
3522 (uint64_t)numtoread,
3523 (uint64_t)startpos,
3524 WRITE_LOCK,
3525 WINDOWS_LOCK,
3526 False, /* Non-blocking lock. */
3527 &status,
3528 NULL,
3529 NULL);
3530 TALLOC_FREE(br_lck);
3532 if (NT_STATUS_V(status)) {
3533 reply_nterror(req, status);
3534 END_PROFILE(SMBlockread);
3535 return;
3539 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3542 if (numtoread > sconn->smb1.negprot.max_recv) {
3543 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3544 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3545 (unsigned int)numtoread,
3546 (unsigned int)sconn->smb1.negprot.max_recv));
3547 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3549 nread = read_file(fsp,data,startpos,numtoread);
3551 if (nread < 0) {
3552 reply_nterror(req, map_nt_error_from_unix(errno));
3553 END_PROFILE(SMBlockread);
3554 return;
3557 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3559 SSVAL(req->outbuf,smb_vwv0,nread);
3560 SSVAL(req->outbuf,smb_vwv5,nread+3);
3561 p = smb_buf(req->outbuf);
3562 SCVAL(p,0,0); /* pad byte. */
3563 SSVAL(p,1,nread);
3565 DEBUG(3,("lockread %s num=%d nread=%d\n",
3566 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3568 END_PROFILE(SMBlockread);
3569 return;
3572 #undef DBGC_CLASS
3573 #define DBGC_CLASS DBGC_ALL
3575 /****************************************************************************
3576 Reply to a read.
3577 ****************************************************************************/
3579 void reply_read(struct smb_request *req)
3581 connection_struct *conn = req->conn;
3582 size_t numtoread;
3583 ssize_t nread = 0;
3584 char *data;
3585 off_t startpos;
3586 int outsize = 0;
3587 files_struct *fsp;
3588 struct lock_struct lock;
3589 struct smbd_server_connection *sconn = req->sconn;
3591 START_PROFILE(SMBread);
3593 if (req->wct < 3) {
3594 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3595 END_PROFILE(SMBread);
3596 return;
3599 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3601 if (!check_fsp(conn, req, fsp)) {
3602 END_PROFILE(SMBread);
3603 return;
3606 if (!CHECK_READ(fsp,req)) {
3607 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3608 END_PROFILE(SMBread);
3609 return;
3612 numtoread = SVAL(req->vwv+1, 0);
3613 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3615 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3618 * The requested read size cannot be greater than max_recv. JRA.
3620 if (numtoread > sconn->smb1.negprot.max_recv) {
3621 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3622 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3623 (unsigned int)numtoread,
3624 (unsigned int)sconn->smb1.negprot.max_recv));
3625 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3628 reply_outbuf(req, 5, numtoread+3);
3630 data = smb_buf(req->outbuf) + 3;
3632 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3633 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3634 &lock);
3636 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3637 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3638 END_PROFILE(SMBread);
3639 return;
3642 if (numtoread > 0)
3643 nread = read_file(fsp,data,startpos,numtoread);
3645 if (nread < 0) {
3646 reply_nterror(req, map_nt_error_from_unix(errno));
3647 goto strict_unlock;
3650 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3652 SSVAL(req->outbuf,smb_vwv0,nread);
3653 SSVAL(req->outbuf,smb_vwv5,nread+3);
3654 SCVAL(smb_buf(req->outbuf),0,1);
3655 SSVAL(smb_buf(req->outbuf),1,nread);
3657 DEBUG(3, ("read %s num=%d nread=%d\n",
3658 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3660 strict_unlock:
3661 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3663 END_PROFILE(SMBread);
3664 return;
3667 /****************************************************************************
3668 Setup readX header.
3669 ****************************************************************************/
3671 static int setup_readX_header(struct smb_request *req, char *outbuf,
3672 size_t smb_maxcnt)
3674 int outsize;
3676 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3678 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3680 SCVAL(outbuf,smb_vwv0,0xFF);
3681 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3682 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3683 SSVAL(outbuf,smb_vwv6,
3684 (smb_wct - 4) /* offset from smb header to wct */
3685 + 1 /* the wct field */
3686 + 12 * sizeof(uint16_t) /* vwv */
3687 + 2); /* the buflen field */
3688 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3689 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3690 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3691 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3692 return outsize;
3695 /****************************************************************************
3696 Reply to a read and X - possibly using sendfile.
3697 ****************************************************************************/
3699 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3700 files_struct *fsp, off_t startpos,
3701 size_t smb_maxcnt)
3703 ssize_t nread = -1;
3704 struct lock_struct lock;
3705 int saved_errno = 0;
3707 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3708 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3709 &lock);
3711 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3712 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3713 return;
3717 * We can only use sendfile on a non-chained packet
3718 * but we can use on a non-oplocked file. tridge proved this
3719 * on a train in Germany :-). JRA.
3722 if (!req_is_in_chain(req) &&
3723 !req->encrypted &&
3724 (fsp->base_fsp == NULL) &&
3725 (fsp->wcp == NULL) &&
3726 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3727 uint8 headerbuf[smb_size + 12 * 2];
3728 DATA_BLOB header;
3730 if(fsp_stat(fsp) == -1) {
3731 reply_nterror(req, map_nt_error_from_unix(errno));
3732 goto strict_unlock;
3735 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3736 (startpos > fsp->fsp_name->st.st_ex_size) ||
3737 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3739 * We already know that we would do a short read, so don't
3740 * try the sendfile() path.
3742 goto nosendfile_read;
3746 * Set up the packet header before send. We
3747 * assume here the sendfile will work (get the
3748 * correct amount of data).
3751 header = data_blob_const(headerbuf, sizeof(headerbuf));
3753 construct_reply_common_req(req, (char *)headerbuf);
3754 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3756 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3757 startpos, smb_maxcnt);
3758 if (nread == -1) {
3759 /* Returning ENOSYS means no data at all was sent.
3760 Do this as a normal read. */
3761 if (errno == ENOSYS) {
3762 goto normal_read;
3766 * Special hack for broken Linux with no working sendfile. If we
3767 * return EINTR we sent the header but not the rest of the data.
3768 * Fake this up by doing read/write calls.
3771 if (errno == EINTR) {
3772 /* Ensure we don't do this again. */
3773 set_use_sendfile(SNUM(conn), False);
3774 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3775 nread = fake_sendfile(fsp, startpos,
3776 smb_maxcnt);
3777 if (nread == -1) {
3778 DEBUG(0,("send_file_readX: "
3779 "fake_sendfile failed for "
3780 "file %s (%s).\n",
3781 fsp_str_dbg(fsp),
3782 strerror(errno)));
3783 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3785 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3786 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3787 /* No outbuf here means successful sendfile. */
3788 goto strict_unlock;
3791 DEBUG(0,("send_file_readX: sendfile failed for file "
3792 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3793 strerror(errno)));
3794 exit_server_cleanly("send_file_readX sendfile failed");
3795 } else if (nread == 0) {
3797 * Some sendfile implementations return 0 to indicate
3798 * that there was a short read, but nothing was
3799 * actually written to the socket. In this case,
3800 * fallback to the normal read path so the header gets
3801 * the correct byte count.
3803 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3804 "falling back to the normal read: %s\n",
3805 fsp_str_dbg(fsp)));
3806 goto normal_read;
3809 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3810 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3812 /* Deal with possible short send. */
3813 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3814 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3816 /* No outbuf here means successful sendfile. */
3817 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3818 SMB_PERFCOUNT_END(&req->pcd);
3819 goto strict_unlock;
3822 normal_read:
3824 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3825 uint8 headerbuf[smb_size + 2*12];
3827 construct_reply_common_req(req, (char *)headerbuf);
3828 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3830 /* Send out the header. */
3831 if (write_data(req->sconn->sock, (char *)headerbuf,
3832 sizeof(headerbuf)) != sizeof(headerbuf)) {
3834 char addr[INET6_ADDRSTRLEN];
3836 * Try and give an error message saying what
3837 * client failed.
3839 DEBUG(0, ("write_data failed for client %s. "
3840 "Error %s\n",
3841 get_peer_addr(req->sconn->sock, addr,
3842 sizeof(addr)),
3843 strerror(errno)));
3845 DEBUG(0,("send_file_readX: write_data failed for file "
3846 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3847 strerror(errno)));
3848 exit_server_cleanly("send_file_readX sendfile failed");
3850 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3851 if (nread == -1) {
3852 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3853 "file %s (%s).\n", fsp_str_dbg(fsp),
3854 strerror(errno)));
3855 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3857 goto strict_unlock;
3860 nosendfile_read:
3862 reply_outbuf(req, 12, smb_maxcnt);
3863 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3864 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3866 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3867 saved_errno = errno;
3869 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3871 if (nread < 0) {
3872 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3873 return;
3876 setup_readX_header(req, (char *)req->outbuf, nread);
3878 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3879 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3880 return;
3882 strict_unlock:
3883 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3884 TALLOC_FREE(req->outbuf);
3885 return;
3888 /****************************************************************************
3889 Work out how much space we have for a read return.
3890 ****************************************************************************/
3892 static size_t calc_max_read_pdu(const struct smb_request *req)
3894 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3895 return req->sconn->smb1.sessions.max_send;
3898 if (!lp_large_readwrite()) {
3899 return req->sconn->smb1.sessions.max_send;
3902 if (req_is_in_chain(req)) {
3903 return req->sconn->smb1.sessions.max_send;
3906 if (req->encrypted) {
3908 * Don't take encrypted traffic up to the
3909 * limit. There are padding considerations
3910 * that make that tricky.
3912 return req->sconn->smb1.sessions.max_send;
3915 if (srv_is_signing_active(req->sconn)) {
3916 return 0x1FFFF;
3919 if (!lp_unix_extensions()) {
3920 return 0x1FFFF;
3924 * We can do ultra-large POSIX reads.
3926 return 0xFFFFFF;
3929 /****************************************************************************
3930 Calculate how big a read can be. Copes with all clients. It's always
3931 safe to return a short read - Windows does this.
3932 ****************************************************************************/
3934 static size_t calc_read_size(const struct smb_request *req,
3935 size_t upper_size,
3936 size_t lower_size)
3938 size_t max_pdu = calc_max_read_pdu(req);
3939 size_t total_size = 0;
3940 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3941 size_t max_len = max_pdu - hdr_len;
3944 * Windows explicitly ignores upper size of 0xFFFF.
3945 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3946 * We must do the same as these will never fit even in
3947 * an extended size NetBIOS packet.
3949 if (upper_size == 0xFFFF) {
3950 upper_size = 0;
3953 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3954 upper_size = 0;
3957 total_size = ((upper_size<<16) | lower_size);
3960 * LARGE_READX test shows it's always safe to return
3961 * a short read. Windows does so.
3963 return MIN(total_size, max_len);
3966 /****************************************************************************
3967 Reply to a read and X.
3968 ****************************************************************************/
3970 void reply_read_and_X(struct smb_request *req)
3972 connection_struct *conn = req->conn;
3973 files_struct *fsp;
3974 off_t startpos;
3975 size_t smb_maxcnt;
3976 size_t upper_size;
3977 bool big_readX = False;
3978 #if 0
3979 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3980 #endif
3982 START_PROFILE(SMBreadX);
3984 if ((req->wct != 10) && (req->wct != 12)) {
3985 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3986 return;
3989 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3990 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3991 smb_maxcnt = SVAL(req->vwv+5, 0);
3993 /* If it's an IPC, pass off the pipe handler. */
3994 if (IS_IPC(conn)) {
3995 reply_pipe_read_and_X(req);
3996 END_PROFILE(SMBreadX);
3997 return;
4000 if (!check_fsp(conn, req, fsp)) {
4001 END_PROFILE(SMBreadX);
4002 return;
4005 if (!CHECK_READ(fsp,req)) {
4006 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4007 END_PROFILE(SMBreadX);
4008 return;
4011 upper_size = SVAL(req->vwv+7, 0);
4012 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4013 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4015 * This is a heuristic to avoid keeping large
4016 * outgoing buffers around over long-lived aio
4017 * requests.
4019 big_readX = True;
4022 if (req->wct == 12) {
4024 * This is a large offset (64 bit) read.
4026 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4030 if (!big_readX) {
4031 NTSTATUS status = schedule_aio_read_and_X(conn,
4032 req,
4033 fsp,
4034 startpos,
4035 smb_maxcnt);
4036 if (NT_STATUS_IS_OK(status)) {
4037 /* Read scheduled - we're done. */
4038 goto out;
4040 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4041 /* Real error - report to client. */
4042 END_PROFILE(SMBreadX);
4043 reply_nterror(req, status);
4044 return;
4046 /* NT_STATUS_RETRY - fall back to sync read. */
4049 smbd_lock_socket(req->sconn);
4050 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4051 smbd_unlock_socket(req->sconn);
4053 out:
4054 END_PROFILE(SMBreadX);
4055 return;
4058 /****************************************************************************
4059 Error replies to writebraw must have smb_wct == 1. Fix this up.
4060 ****************************************************************************/
4062 void error_to_writebrawerr(struct smb_request *req)
4064 uint8 *old_outbuf = req->outbuf;
4066 reply_outbuf(req, 1, 0);
4068 memcpy(req->outbuf, old_outbuf, smb_size);
4069 TALLOC_FREE(old_outbuf);
4072 /****************************************************************************
4073 Read 4 bytes of a smb packet and return the smb length of the packet.
4074 Store the result in the buffer. This version of the function will
4075 never return a session keepalive (length of zero).
4076 Timeout is in milliseconds.
4077 ****************************************************************************/
4079 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4080 size_t *len)
4082 uint8_t msgtype = NBSSkeepalive;
4084 while (msgtype == NBSSkeepalive) {
4085 NTSTATUS status;
4087 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4088 len);
4089 if (!NT_STATUS_IS_OK(status)) {
4090 char addr[INET6_ADDRSTRLEN];
4091 /* Try and give an error message
4092 * saying what client failed. */
4093 DEBUG(0, ("read_fd_with_timeout failed for "
4094 "client %s read error = %s.\n",
4095 get_peer_addr(fd,addr,sizeof(addr)),
4096 nt_errstr(status)));
4097 return status;
4100 msgtype = CVAL(inbuf, 0);
4103 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4104 (unsigned long)len));
4106 return NT_STATUS_OK;
4109 /****************************************************************************
4110 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4111 ****************************************************************************/
4113 void reply_writebraw(struct smb_request *req)
4115 connection_struct *conn = req->conn;
4116 char *buf = NULL;
4117 ssize_t nwritten=0;
4118 ssize_t total_written=0;
4119 size_t numtowrite=0;
4120 size_t tcount;
4121 off_t startpos;
4122 const char *data=NULL;
4123 bool write_through;
4124 files_struct *fsp;
4125 struct lock_struct lock;
4126 NTSTATUS status;
4128 START_PROFILE(SMBwritebraw);
4131 * If we ever reply with an error, it must have the SMB command
4132 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4133 * we're finished.
4135 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4137 if (srv_is_signing_active(req->sconn)) {
4138 END_PROFILE(SMBwritebraw);
4139 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4140 "raw reads/writes are disallowed.");
4143 if (req->wct < 12) {
4144 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4145 error_to_writebrawerr(req);
4146 END_PROFILE(SMBwritebraw);
4147 return;
4150 if (req->sconn->smb1.echo_handler.trusted_fde) {
4151 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4152 "'async smb echo handler = yes'\n"));
4153 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4154 error_to_writebrawerr(req);
4155 END_PROFILE(SMBwritebraw);
4156 return;
4159 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4160 if (!check_fsp(conn, req, fsp)) {
4161 error_to_writebrawerr(req);
4162 END_PROFILE(SMBwritebraw);
4163 return;
4166 if (!CHECK_WRITE(fsp)) {
4167 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4168 error_to_writebrawerr(req);
4169 END_PROFILE(SMBwritebraw);
4170 return;
4173 tcount = IVAL(req->vwv+1, 0);
4174 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4175 write_through = BITSETW(req->vwv+7,0);
4177 /* We have to deal with slightly different formats depending
4178 on whether we are using the core+ or lanman1.0 protocol */
4180 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4181 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4182 data = smb_buf_const(req->inbuf);
4183 } else {
4184 numtowrite = SVAL(req->vwv+10, 0);
4185 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4188 /* Ensure we don't write bytes past the end of this packet. */
4189 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4190 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4191 error_to_writebrawerr(req);
4192 END_PROFILE(SMBwritebraw);
4193 return;
4196 if (!fsp->print_file) {
4197 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4198 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4199 &lock);
4201 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4202 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4203 error_to_writebrawerr(req);
4204 END_PROFILE(SMBwritebraw);
4205 return;
4209 if (numtowrite>0) {
4210 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4213 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4214 "wrote=%d sync=%d\n",
4215 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4216 (int)nwritten, (int)write_through));
4218 if (nwritten < (ssize_t)numtowrite) {
4219 reply_nterror(req, NT_STATUS_DISK_FULL);
4220 error_to_writebrawerr(req);
4221 goto strict_unlock;
4224 total_written = nwritten;
4226 /* Allocate a buffer of 64k + length. */
4227 buf = talloc_array(NULL, char, 65540);
4228 if (!buf) {
4229 reply_nterror(req, NT_STATUS_NO_MEMORY);
4230 error_to_writebrawerr(req);
4231 goto strict_unlock;
4234 /* Return a SMBwritebraw message to the redirector to tell
4235 * it to send more bytes */
4237 memcpy(buf, req->inbuf, smb_size);
4238 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4239 SCVAL(buf,smb_com,SMBwritebraw);
4240 SSVALS(buf,smb_vwv0,0xFFFF);
4241 show_msg(buf);
4242 if (!srv_send_smb(req->sconn,
4243 buf,
4244 false, 0, /* no signing */
4245 IS_CONN_ENCRYPTED(conn),
4246 &req->pcd)) {
4247 exit_server_cleanly("reply_writebraw: srv_send_smb "
4248 "failed.");
4251 /* Now read the raw data into the buffer and write it */
4252 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4253 &numtowrite);
4254 if (!NT_STATUS_IS_OK(status)) {
4255 exit_server_cleanly("secondary writebraw failed");
4258 /* Set up outbuf to return the correct size */
4259 reply_outbuf(req, 1, 0);
4261 if (numtowrite != 0) {
4263 if (numtowrite > 0xFFFF) {
4264 DEBUG(0,("reply_writebraw: Oversize secondary write "
4265 "raw requested (%u). Terminating\n",
4266 (unsigned int)numtowrite ));
4267 exit_server_cleanly("secondary writebraw failed");
4270 if (tcount > nwritten+numtowrite) {
4271 DEBUG(3,("reply_writebraw: Client overestimated the "
4272 "write %d %d %d\n",
4273 (int)tcount,(int)nwritten,(int)numtowrite));
4276 status = read_data(req->sconn->sock, buf+4, numtowrite);
4278 if (!NT_STATUS_IS_OK(status)) {
4279 char addr[INET6_ADDRSTRLEN];
4280 /* Try and give an error message
4281 * saying what client failed. */
4282 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4283 "raw read failed (%s) for client %s. "
4284 "Terminating\n", nt_errstr(status),
4285 get_peer_addr(req->sconn->sock, addr,
4286 sizeof(addr))));
4287 exit_server_cleanly("secondary writebraw failed");
4290 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4291 if (nwritten == -1) {
4292 TALLOC_FREE(buf);
4293 reply_nterror(req, map_nt_error_from_unix(errno));
4294 error_to_writebrawerr(req);
4295 goto strict_unlock;
4298 if (nwritten < (ssize_t)numtowrite) {
4299 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4300 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4303 if (nwritten > 0) {
4304 total_written += nwritten;
4308 TALLOC_FREE(buf);
4309 SSVAL(req->outbuf,smb_vwv0,total_written);
4311 status = sync_file(conn, fsp, write_through);
4312 if (!NT_STATUS_IS_OK(status)) {
4313 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4314 fsp_str_dbg(fsp), nt_errstr(status)));
4315 reply_nterror(req, status);
4316 error_to_writebrawerr(req);
4317 goto strict_unlock;
4320 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4321 "wrote=%d\n",
4322 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4323 (int)total_written));
4325 if (!fsp->print_file) {
4326 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4329 /* We won't return a status if write through is not selected - this
4330 * follows what WfWg does */
4331 END_PROFILE(SMBwritebraw);
4333 if (!write_through && total_written==tcount) {
4335 #if RABBIT_PELLET_FIX
4337 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4338 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4339 * JRA.
4341 if (!send_keepalive(req->sconn->sock)) {
4342 exit_server_cleanly("reply_writebraw: send of "
4343 "keepalive failed");
4345 #endif
4346 TALLOC_FREE(req->outbuf);
4348 return;
4350 strict_unlock:
4351 if (!fsp->print_file) {
4352 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4355 END_PROFILE(SMBwritebraw);
4356 return;
4359 #undef DBGC_CLASS
4360 #define DBGC_CLASS DBGC_LOCKING
4362 /****************************************************************************
4363 Reply to a writeunlock (core+).
4364 ****************************************************************************/
4366 void reply_writeunlock(struct smb_request *req)
4368 connection_struct *conn = req->conn;
4369 ssize_t nwritten = -1;
4370 size_t numtowrite;
4371 off_t startpos;
4372 const char *data;
4373 NTSTATUS status = NT_STATUS_OK;
4374 files_struct *fsp;
4375 struct lock_struct lock;
4376 int saved_errno = 0;
4378 START_PROFILE(SMBwriteunlock);
4380 if (req->wct < 5) {
4381 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4382 END_PROFILE(SMBwriteunlock);
4383 return;
4386 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4388 if (!check_fsp(conn, req, fsp)) {
4389 END_PROFILE(SMBwriteunlock);
4390 return;
4393 if (!CHECK_WRITE(fsp)) {
4394 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4395 END_PROFILE(SMBwriteunlock);
4396 return;
4399 numtowrite = SVAL(req->vwv+1, 0);
4400 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4401 data = (const char *)req->buf + 3;
4403 if (!fsp->print_file && numtowrite > 0) {
4404 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4405 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4406 &lock);
4408 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4409 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4410 END_PROFILE(SMBwriteunlock);
4411 return;
4415 /* The special X/Open SMB protocol handling of
4416 zero length writes is *NOT* done for
4417 this call */
4418 if(numtowrite == 0) {
4419 nwritten = 0;
4420 } else {
4421 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4422 saved_errno = errno;
4425 status = sync_file(conn, fsp, False /* write through */);
4426 if (!NT_STATUS_IS_OK(status)) {
4427 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4428 fsp_str_dbg(fsp), nt_errstr(status)));
4429 reply_nterror(req, status);
4430 goto strict_unlock;
4433 if(nwritten < 0) {
4434 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4435 goto strict_unlock;
4438 if((nwritten < numtowrite) && (numtowrite != 0)) {
4439 reply_nterror(req, NT_STATUS_DISK_FULL);
4440 goto strict_unlock;
4443 if (numtowrite && !fsp->print_file) {
4444 status = do_unlock(req->sconn->msg_ctx,
4445 fsp,
4446 (uint64_t)req->smbpid,
4447 (uint64_t)numtowrite,
4448 (uint64_t)startpos,
4449 WINDOWS_LOCK);
4451 if (NT_STATUS_V(status)) {
4452 reply_nterror(req, status);
4453 goto strict_unlock;
4457 reply_outbuf(req, 1, 0);
4459 SSVAL(req->outbuf,smb_vwv0,nwritten);
4461 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4462 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4464 strict_unlock:
4465 if (numtowrite && !fsp->print_file) {
4466 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4469 END_PROFILE(SMBwriteunlock);
4470 return;
4473 #undef DBGC_CLASS
4474 #define DBGC_CLASS DBGC_ALL
4476 /****************************************************************************
4477 Reply to a write.
4478 ****************************************************************************/
4480 void reply_write(struct smb_request *req)
4482 connection_struct *conn = req->conn;
4483 size_t numtowrite;
4484 ssize_t nwritten = -1;
4485 off_t startpos;
4486 const char *data;
4487 files_struct *fsp;
4488 struct lock_struct lock;
4489 NTSTATUS status;
4490 int saved_errno = 0;
4492 START_PROFILE(SMBwrite);
4494 if (req->wct < 5) {
4495 END_PROFILE(SMBwrite);
4496 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4497 return;
4500 /* If it's an IPC, pass off the pipe handler. */
4501 if (IS_IPC(conn)) {
4502 reply_pipe_write(req);
4503 END_PROFILE(SMBwrite);
4504 return;
4507 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4509 if (!check_fsp(conn, req, fsp)) {
4510 END_PROFILE(SMBwrite);
4511 return;
4514 if (!CHECK_WRITE(fsp)) {
4515 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4516 END_PROFILE(SMBwrite);
4517 return;
4520 numtowrite = SVAL(req->vwv+1, 0);
4521 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4522 data = (const char *)req->buf + 3;
4524 if (!fsp->print_file) {
4525 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4526 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4527 &lock);
4529 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4530 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4531 END_PROFILE(SMBwrite);
4532 return;
4537 * X/Open SMB protocol says that if smb_vwv1 is
4538 * zero then the file size should be extended or
4539 * truncated to the size given in smb_vwv[2-3].
4542 if(numtowrite == 0) {
4544 * This is actually an allocate call, and set EOF. JRA.
4546 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4547 if (nwritten < 0) {
4548 reply_nterror(req, NT_STATUS_DISK_FULL);
4549 goto strict_unlock;
4551 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4552 if (nwritten < 0) {
4553 reply_nterror(req, NT_STATUS_DISK_FULL);
4554 goto strict_unlock;
4556 trigger_write_time_update_immediate(fsp);
4557 } else {
4558 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4561 status = sync_file(conn, fsp, False);
4562 if (!NT_STATUS_IS_OK(status)) {
4563 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4564 fsp_str_dbg(fsp), nt_errstr(status)));
4565 reply_nterror(req, status);
4566 goto strict_unlock;
4569 if(nwritten < 0) {
4570 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4571 goto strict_unlock;
4574 if((nwritten == 0) && (numtowrite != 0)) {
4575 reply_nterror(req, NT_STATUS_DISK_FULL);
4576 goto strict_unlock;
4579 reply_outbuf(req, 1, 0);
4581 SSVAL(req->outbuf,smb_vwv0,nwritten);
4583 if (nwritten < (ssize_t)numtowrite) {
4584 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4585 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4588 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4590 strict_unlock:
4591 if (!fsp->print_file) {
4592 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4595 END_PROFILE(SMBwrite);
4596 return;
4599 /****************************************************************************
4600 Ensure a buffer is a valid writeX for recvfile purposes.
4601 ****************************************************************************/
4603 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4604 (2*14) + /* word count (including bcc) */ \
4605 1 /* pad byte */)
4607 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4608 const uint8_t *inbuf)
4610 size_t numtowrite;
4611 connection_struct *conn = NULL;
4612 unsigned int doff = 0;
4613 size_t len = smb_len_large(inbuf);
4614 struct smbXsrv_tcon *tcon;
4615 NTSTATUS status;
4616 NTTIME now = 0;
4618 if (is_encrypted_packet(sconn, inbuf)) {
4619 /* Can't do this on encrypted
4620 * connections. */
4621 return false;
4624 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4625 return false;
4628 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4629 CVAL(inbuf,smb_wct) != 14) {
4630 DEBUG(10,("is_valid_writeX_buffer: chained or "
4631 "invalid word length.\n"));
4632 return false;
4635 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4636 now, &tcon);
4637 if (!NT_STATUS_IS_OK(status)) {
4638 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4639 return false;
4641 conn = tcon->compat;
4643 if (IS_IPC(conn)) {
4644 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4645 return false;
4647 if (IS_PRINT(conn)) {
4648 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4649 return false;
4651 doff = SVAL(inbuf,smb_vwv11);
4653 numtowrite = SVAL(inbuf,smb_vwv10);
4655 if (len > doff && len - doff > 0xFFFF) {
4656 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4659 if (numtowrite == 0) {
4660 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4661 return false;
4664 /* Ensure the sizes match up. */
4665 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4666 /* no pad byte...old smbclient :-( */
4667 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4668 (unsigned int)doff,
4669 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4670 return false;
4673 if (len - doff != numtowrite) {
4674 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4675 "len = %u, doff = %u, numtowrite = %u\n",
4676 (unsigned int)len,
4677 (unsigned int)doff,
4678 (unsigned int)numtowrite ));
4679 return false;
4682 DEBUG(10,("is_valid_writeX_buffer: true "
4683 "len = %u, doff = %u, numtowrite = %u\n",
4684 (unsigned int)len,
4685 (unsigned int)doff,
4686 (unsigned int)numtowrite ));
4688 return true;
4691 /****************************************************************************
4692 Reply to a write and X.
4693 ****************************************************************************/
4695 void reply_write_and_X(struct smb_request *req)
4697 connection_struct *conn = req->conn;
4698 files_struct *fsp;
4699 struct lock_struct lock;
4700 off_t startpos;
4701 size_t numtowrite;
4702 bool write_through;
4703 ssize_t nwritten;
4704 unsigned int smb_doff;
4705 unsigned int smblen;
4706 const char *data;
4707 NTSTATUS status;
4708 int saved_errno = 0;
4710 START_PROFILE(SMBwriteX);
4712 if ((req->wct != 12) && (req->wct != 14)) {
4713 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4714 goto out;
4717 numtowrite = SVAL(req->vwv+10, 0);
4718 smb_doff = SVAL(req->vwv+11, 0);
4719 smblen = smb_len(req->inbuf);
4721 if (req->unread_bytes > 0xFFFF ||
4722 (smblen > smb_doff &&
4723 smblen - smb_doff > 0xFFFF)) {
4724 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4727 if (req->unread_bytes) {
4728 /* Can't do a recvfile write on IPC$ */
4729 if (IS_IPC(conn)) {
4730 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4731 goto out;
4733 if (numtowrite != req->unread_bytes) {
4734 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4735 goto out;
4737 } else {
4738 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4739 smb_doff + numtowrite > smblen) {
4740 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4741 goto out;
4745 /* If it's an IPC, pass off the pipe handler. */
4746 if (IS_IPC(conn)) {
4747 if (req->unread_bytes) {
4748 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4749 goto out;
4751 reply_pipe_write_and_X(req);
4752 goto out;
4755 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4756 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4757 write_through = BITSETW(req->vwv+7,0);
4759 if (!check_fsp(conn, req, fsp)) {
4760 goto out;
4763 if (!CHECK_WRITE(fsp)) {
4764 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4765 goto out;
4768 data = smb_base(req->inbuf) + smb_doff;
4770 if(req->wct == 14) {
4772 * This is a large offset (64 bit) write.
4774 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4778 /* X/Open SMB protocol says that, unlike SMBwrite
4779 if the length is zero then NO truncation is
4780 done, just a write of zero. To truncate a file,
4781 use SMBwrite. */
4783 if(numtowrite == 0) {
4784 nwritten = 0;
4785 } else {
4786 if (req->unread_bytes == 0) {
4787 status = schedule_aio_write_and_X(conn,
4788 req,
4789 fsp,
4790 data,
4791 startpos,
4792 numtowrite);
4794 if (NT_STATUS_IS_OK(status)) {
4795 /* write scheduled - we're done. */
4796 goto out;
4798 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4799 /* Real error - report to client. */
4800 reply_nterror(req, status);
4801 goto out;
4803 /* NT_STATUS_RETRY - fall through to sync write. */
4806 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4807 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4808 &lock);
4810 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4811 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4812 goto out;
4815 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4816 saved_errno = errno;
4818 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4821 if(nwritten < 0) {
4822 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4823 goto out;
4826 if((nwritten == 0) && (numtowrite != 0)) {
4827 reply_nterror(req, NT_STATUS_DISK_FULL);
4828 goto out;
4831 reply_outbuf(req, 6, 0);
4832 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4833 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4834 SSVAL(req->outbuf,smb_vwv2,nwritten);
4835 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4837 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4838 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4840 status = sync_file(conn, fsp, write_through);
4841 if (!NT_STATUS_IS_OK(status)) {
4842 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4843 fsp_str_dbg(fsp), nt_errstr(status)));
4844 reply_nterror(req, status);
4845 goto out;
4848 END_PROFILE(SMBwriteX);
4849 return;
4851 out:
4852 if (req->unread_bytes) {
4853 /* writeX failed. drain socket. */
4854 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4855 req->unread_bytes) {
4856 smb_panic("failed to drain pending bytes");
4858 req->unread_bytes = 0;
4861 END_PROFILE(SMBwriteX);
4862 return;
4865 /****************************************************************************
4866 Reply to a lseek.
4867 ****************************************************************************/
4869 void reply_lseek(struct smb_request *req)
4871 connection_struct *conn = req->conn;
4872 off_t startpos;
4873 off_t res= -1;
4874 int mode,umode;
4875 files_struct *fsp;
4877 START_PROFILE(SMBlseek);
4879 if (req->wct < 4) {
4880 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4881 END_PROFILE(SMBlseek);
4882 return;
4885 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4887 if (!check_fsp(conn, req, fsp)) {
4888 return;
4891 flush_write_cache(fsp, SEEK_FLUSH);
4893 mode = SVAL(req->vwv+1, 0) & 3;
4894 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4895 startpos = (off_t)IVALS(req->vwv+2, 0);
4897 switch (mode) {
4898 case 0:
4899 umode = SEEK_SET;
4900 res = startpos;
4901 break;
4902 case 1:
4903 umode = SEEK_CUR;
4904 res = fsp->fh->pos + startpos;
4905 break;
4906 case 2:
4907 umode = SEEK_END;
4908 break;
4909 default:
4910 umode = SEEK_SET;
4911 res = startpos;
4912 break;
4915 if (umode == SEEK_END) {
4916 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4917 if(errno == EINVAL) {
4918 off_t current_pos = startpos;
4920 if(fsp_stat(fsp) == -1) {
4921 reply_nterror(req,
4922 map_nt_error_from_unix(errno));
4923 END_PROFILE(SMBlseek);
4924 return;
4927 current_pos += fsp->fsp_name->st.st_ex_size;
4928 if(current_pos < 0)
4929 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4933 if(res == -1) {
4934 reply_nterror(req, map_nt_error_from_unix(errno));
4935 END_PROFILE(SMBlseek);
4936 return;
4940 fsp->fh->pos = res;
4942 reply_outbuf(req, 2, 0);
4943 SIVAL(req->outbuf,smb_vwv0,res);
4945 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4946 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4948 END_PROFILE(SMBlseek);
4949 return;
4952 /****************************************************************************
4953 Reply to a flush.
4954 ****************************************************************************/
4956 void reply_flush(struct smb_request *req)
4958 connection_struct *conn = req->conn;
4959 uint16 fnum;
4960 files_struct *fsp;
4962 START_PROFILE(SMBflush);
4964 if (req->wct < 1) {
4965 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4966 return;
4969 fnum = SVAL(req->vwv+0, 0);
4970 fsp = file_fsp(req, fnum);
4972 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4973 return;
4976 if (!fsp) {
4977 file_sync_all(conn);
4978 } else {
4979 NTSTATUS status = sync_file(conn, fsp, True);
4980 if (!NT_STATUS_IS_OK(status)) {
4981 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4982 fsp_str_dbg(fsp), nt_errstr(status)));
4983 reply_nterror(req, status);
4984 END_PROFILE(SMBflush);
4985 return;
4989 reply_outbuf(req, 0, 0);
4991 DEBUG(3,("flush\n"));
4992 END_PROFILE(SMBflush);
4993 return;
4996 /****************************************************************************
4997 Reply to a exit.
4998 conn POINTER CAN BE NULL HERE !
4999 ****************************************************************************/
5001 void reply_exit(struct smb_request *req)
5003 START_PROFILE(SMBexit);
5005 file_close_pid(req->sconn, req->smbpid, req->vuid);
5007 reply_outbuf(req, 0, 0);
5009 DEBUG(3,("exit\n"));
5011 END_PROFILE(SMBexit);
5012 return;
5015 struct reply_close_state {
5016 files_struct *fsp;
5017 struct smb_request *smbreq;
5020 static void do_smb1_close(struct tevent_req *req);
5022 void reply_close(struct smb_request *req)
5024 connection_struct *conn = req->conn;
5025 NTSTATUS status = NT_STATUS_OK;
5026 files_struct *fsp = NULL;
5027 START_PROFILE(SMBclose);
5029 if (req->wct < 3) {
5030 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5031 END_PROFILE(SMBclose);
5032 return;
5035 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5038 * We can only use check_fsp if we know it's not a directory.
5041 if (!check_fsp_open(conn, req, fsp)) {
5042 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5043 END_PROFILE(SMBclose);
5044 return;
5047 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5048 fsp->is_directory ? "directory" : "file",
5049 fsp->fh->fd, fsp_fnum_dbg(fsp),
5050 conn->num_files_open));
5052 if (!fsp->is_directory) {
5053 time_t t;
5056 * Take care of any time sent in the close.
5059 t = srv_make_unix_date3(req->vwv+1);
5060 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5063 if (fsp->num_aio_requests != 0) {
5065 struct reply_close_state *state;
5067 DEBUG(10, ("closing with aio %u requests pending\n",
5068 fsp->num_aio_requests));
5071 * We depend on the aio_extra destructor to take care of this
5072 * close request once fsp->num_aio_request drops to 0.
5075 fsp->deferred_close = tevent_wait_send(
5076 fsp, fsp->conn->sconn->ev_ctx);
5077 if (fsp->deferred_close == NULL) {
5078 status = NT_STATUS_NO_MEMORY;
5079 goto done;
5082 state = talloc(fsp, struct reply_close_state);
5083 if (state == NULL) {
5084 TALLOC_FREE(fsp->deferred_close);
5085 status = NT_STATUS_NO_MEMORY;
5086 goto done;
5088 state->fsp = fsp;
5089 state->smbreq = talloc_move(fsp, &req);
5090 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5091 state);
5092 END_PROFILE(SMBclose);
5093 return;
5097 * close_file() returns the unix errno if an error was detected on
5098 * close - normally this is due to a disk full error. If not then it
5099 * was probably an I/O error.
5102 status = close_file(req, fsp, NORMAL_CLOSE);
5103 done:
5104 if (!NT_STATUS_IS_OK(status)) {
5105 reply_nterror(req, status);
5106 END_PROFILE(SMBclose);
5107 return;
5110 reply_outbuf(req, 0, 0);
5111 END_PROFILE(SMBclose);
5112 return;
5115 static void do_smb1_close(struct tevent_req *req)
5117 struct reply_close_state *state = tevent_req_callback_data(
5118 req, struct reply_close_state);
5119 struct smb_request *smbreq;
5120 NTSTATUS status;
5121 int ret;
5123 ret = tevent_wait_recv(req);
5124 TALLOC_FREE(req);
5125 if (ret != 0) {
5126 DEBUG(10, ("tevent_wait_recv returned %s\n",
5127 strerror(ret)));
5129 * Continue anyway, this should never happen
5134 * fsp->smb2_close_request right now is a talloc grandchild of
5135 * fsp. When we close_file(fsp), it would go with it. No chance to
5136 * reply...
5138 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5140 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5141 if (NT_STATUS_IS_OK(status)) {
5142 reply_outbuf(smbreq, 0, 0);
5143 } else {
5144 reply_nterror(smbreq, status);
5146 if (!srv_send_smb(smbreq->sconn,
5147 (char *)smbreq->outbuf,
5148 true,
5149 smbreq->seqnum+1,
5150 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5151 NULL)) {
5152 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5153 "failed.");
5155 TALLOC_FREE(smbreq);
5158 /****************************************************************************
5159 Reply to a writeclose (Core+ protocol).
5160 ****************************************************************************/
5162 void reply_writeclose(struct smb_request *req)
5164 connection_struct *conn = req->conn;
5165 size_t numtowrite;
5166 ssize_t nwritten = -1;
5167 NTSTATUS close_status = NT_STATUS_OK;
5168 off_t startpos;
5169 const char *data;
5170 struct timespec mtime;
5171 files_struct *fsp;
5172 struct lock_struct lock;
5174 START_PROFILE(SMBwriteclose);
5176 if (req->wct < 6) {
5177 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5178 END_PROFILE(SMBwriteclose);
5179 return;
5182 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5184 if (!check_fsp(conn, req, fsp)) {
5185 END_PROFILE(SMBwriteclose);
5186 return;
5188 if (!CHECK_WRITE(fsp)) {
5189 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5190 END_PROFILE(SMBwriteclose);
5191 return;
5194 numtowrite = SVAL(req->vwv+1, 0);
5195 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5196 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5197 data = (const char *)req->buf + 1;
5199 if (!fsp->print_file) {
5200 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5201 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5202 &lock);
5204 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5205 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5206 END_PROFILE(SMBwriteclose);
5207 return;
5211 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5213 set_close_write_time(fsp, mtime);
5216 * More insanity. W2K only closes the file if writelen > 0.
5217 * JRA.
5220 if (numtowrite) {
5221 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5222 "file %s\n", fsp_str_dbg(fsp)));
5223 close_status = close_file(req, fsp, NORMAL_CLOSE);
5226 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5227 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5228 conn->num_files_open));
5230 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5231 reply_nterror(req, NT_STATUS_DISK_FULL);
5232 goto strict_unlock;
5235 if(!NT_STATUS_IS_OK(close_status)) {
5236 reply_nterror(req, close_status);
5237 goto strict_unlock;
5240 reply_outbuf(req, 1, 0);
5242 SSVAL(req->outbuf,smb_vwv0,nwritten);
5244 strict_unlock:
5245 if (numtowrite && !fsp->print_file) {
5246 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5249 END_PROFILE(SMBwriteclose);
5250 return;
5253 #undef DBGC_CLASS
5254 #define DBGC_CLASS DBGC_LOCKING
5256 /****************************************************************************
5257 Reply to a lock.
5258 ****************************************************************************/
5260 void reply_lock(struct smb_request *req)
5262 connection_struct *conn = req->conn;
5263 uint64_t count,offset;
5264 NTSTATUS status;
5265 files_struct *fsp;
5266 struct byte_range_lock *br_lck = NULL;
5268 START_PROFILE(SMBlock);
5270 if (req->wct < 5) {
5271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5272 END_PROFILE(SMBlock);
5273 return;
5276 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5278 if (!check_fsp(conn, req, fsp)) {
5279 END_PROFILE(SMBlock);
5280 return;
5283 count = (uint64_t)IVAL(req->vwv+1, 0);
5284 offset = (uint64_t)IVAL(req->vwv+3, 0);
5286 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5287 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5289 br_lck = do_lock(req->sconn->msg_ctx,
5290 fsp,
5291 (uint64_t)req->smbpid,
5292 count,
5293 offset,
5294 WRITE_LOCK,
5295 WINDOWS_LOCK,
5296 False, /* Non-blocking lock. */
5297 &status,
5298 NULL,
5299 NULL);
5301 TALLOC_FREE(br_lck);
5303 if (NT_STATUS_V(status)) {
5304 reply_nterror(req, status);
5305 END_PROFILE(SMBlock);
5306 return;
5309 reply_outbuf(req, 0, 0);
5311 END_PROFILE(SMBlock);
5312 return;
5315 /****************************************************************************
5316 Reply to a unlock.
5317 ****************************************************************************/
5319 void reply_unlock(struct smb_request *req)
5321 connection_struct *conn = req->conn;
5322 uint64_t count,offset;
5323 NTSTATUS status;
5324 files_struct *fsp;
5326 START_PROFILE(SMBunlock);
5328 if (req->wct < 5) {
5329 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5330 END_PROFILE(SMBunlock);
5331 return;
5334 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5336 if (!check_fsp(conn, req, fsp)) {
5337 END_PROFILE(SMBunlock);
5338 return;
5341 count = (uint64_t)IVAL(req->vwv+1, 0);
5342 offset = (uint64_t)IVAL(req->vwv+3, 0);
5344 status = do_unlock(req->sconn->msg_ctx,
5345 fsp,
5346 (uint64_t)req->smbpid,
5347 count,
5348 offset,
5349 WINDOWS_LOCK);
5351 if (NT_STATUS_V(status)) {
5352 reply_nterror(req, status);
5353 END_PROFILE(SMBunlock);
5354 return;
5357 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5358 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5360 reply_outbuf(req, 0, 0);
5362 END_PROFILE(SMBunlock);
5363 return;
5366 #undef DBGC_CLASS
5367 #define DBGC_CLASS DBGC_ALL
5369 /****************************************************************************
5370 Reply to a tdis.
5371 conn POINTER CAN BE NULL HERE !
5372 ****************************************************************************/
5374 void reply_tdis(struct smb_request *req)
5376 NTSTATUS status;
5377 connection_struct *conn = req->conn;
5378 struct smbXsrv_tcon *tcon;
5380 START_PROFILE(SMBtdis);
5382 if (!conn) {
5383 DEBUG(4,("Invalid connection in tdis\n"));
5384 reply_force_doserror(req, ERRSRV, ERRinvnid);
5385 END_PROFILE(SMBtdis);
5386 return;
5389 tcon = conn->tcon;
5390 req->conn = NULL;
5393 * TODO: cancel all outstanding requests on the tcon
5395 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5396 if (!NT_STATUS_IS_OK(status)) {
5397 DEBUG(0, ("reply_tdis: "
5398 "smbXsrv_tcon_disconnect() failed: %s\n",
5399 nt_errstr(status)));
5401 * If we hit this case, there is something completely
5402 * wrong, so we better disconnect the transport connection.
5404 END_PROFILE(SMBtdis);
5405 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5406 return;
5409 TALLOC_FREE(tcon);
5411 reply_outbuf(req, 0, 0);
5412 END_PROFILE(SMBtdis);
5413 return;
5416 /****************************************************************************
5417 Reply to a echo.
5418 conn POINTER CAN BE NULL HERE !
5419 ****************************************************************************/
5421 void reply_echo(struct smb_request *req)
5423 connection_struct *conn = req->conn;
5424 struct smb_perfcount_data local_pcd;
5425 struct smb_perfcount_data *cur_pcd;
5426 int smb_reverb;
5427 int seq_num;
5429 START_PROFILE(SMBecho);
5431 smb_init_perfcount_data(&local_pcd);
5433 if (req->wct < 1) {
5434 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5435 END_PROFILE(SMBecho);
5436 return;
5439 smb_reverb = SVAL(req->vwv+0, 0);
5441 reply_outbuf(req, 1, req->buflen);
5443 /* copy any incoming data back out */
5444 if (req->buflen > 0) {
5445 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5448 if (smb_reverb > 100) {
5449 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5450 smb_reverb = 100;
5453 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5455 /* this makes sure we catch the request pcd */
5456 if (seq_num == smb_reverb) {
5457 cur_pcd = &req->pcd;
5458 } else {
5459 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5460 cur_pcd = &local_pcd;
5463 SSVAL(req->outbuf,smb_vwv0,seq_num);
5465 show_msg((char *)req->outbuf);
5466 if (!srv_send_smb(req->sconn,
5467 (char *)req->outbuf,
5468 true, req->seqnum+1,
5469 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5470 cur_pcd))
5471 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5474 DEBUG(3,("echo %d times\n", smb_reverb));
5476 TALLOC_FREE(req->outbuf);
5478 END_PROFILE(SMBecho);
5479 return;
5482 /****************************************************************************
5483 Reply to a printopen.
5484 ****************************************************************************/
5486 void reply_printopen(struct smb_request *req)
5488 connection_struct *conn = req->conn;
5489 files_struct *fsp;
5490 NTSTATUS status;
5492 START_PROFILE(SMBsplopen);
5494 if (req->wct < 2) {
5495 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5496 END_PROFILE(SMBsplopen);
5497 return;
5500 if (!CAN_PRINT(conn)) {
5501 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5502 END_PROFILE(SMBsplopen);
5503 return;
5506 status = file_new(req, conn, &fsp);
5507 if(!NT_STATUS_IS_OK(status)) {
5508 reply_nterror(req, status);
5509 END_PROFILE(SMBsplopen);
5510 return;
5513 /* Open for exclusive use, write only. */
5514 status = print_spool_open(fsp, NULL, req->vuid);
5516 if (!NT_STATUS_IS_OK(status)) {
5517 file_free(req, fsp);
5518 reply_nterror(req, status);
5519 END_PROFILE(SMBsplopen);
5520 return;
5523 reply_outbuf(req, 1, 0);
5524 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5526 DEBUG(3,("openprint fd=%d %s\n",
5527 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5529 END_PROFILE(SMBsplopen);
5530 return;
5533 /****************************************************************************
5534 Reply to a printclose.
5535 ****************************************************************************/
5537 void reply_printclose(struct smb_request *req)
5539 connection_struct *conn = req->conn;
5540 files_struct *fsp;
5541 NTSTATUS status;
5543 START_PROFILE(SMBsplclose);
5545 if (req->wct < 1) {
5546 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5547 END_PROFILE(SMBsplclose);
5548 return;
5551 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5553 if (!check_fsp(conn, req, fsp)) {
5554 END_PROFILE(SMBsplclose);
5555 return;
5558 if (!CAN_PRINT(conn)) {
5559 reply_force_doserror(req, ERRSRV, ERRerror);
5560 END_PROFILE(SMBsplclose);
5561 return;
5564 DEBUG(3,("printclose fd=%d %s\n",
5565 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5567 status = close_file(req, fsp, NORMAL_CLOSE);
5569 if(!NT_STATUS_IS_OK(status)) {
5570 reply_nterror(req, status);
5571 END_PROFILE(SMBsplclose);
5572 return;
5575 reply_outbuf(req, 0, 0);
5577 END_PROFILE(SMBsplclose);
5578 return;
5581 /****************************************************************************
5582 Reply to a printqueue.
5583 ****************************************************************************/
5585 void reply_printqueue(struct smb_request *req)
5587 connection_struct *conn = req->conn;
5588 int max_count;
5589 int start_index;
5591 START_PROFILE(SMBsplretq);
5593 if (req->wct < 2) {
5594 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5595 END_PROFILE(SMBsplretq);
5596 return;
5599 max_count = SVAL(req->vwv+0, 0);
5600 start_index = SVAL(req->vwv+1, 0);
5602 /* we used to allow the client to get the cnum wrong, but that
5603 is really quite gross and only worked when there was only
5604 one printer - I think we should now only accept it if they
5605 get it right (tridge) */
5606 if (!CAN_PRINT(conn)) {
5607 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5608 END_PROFILE(SMBsplretq);
5609 return;
5612 reply_outbuf(req, 2, 3);
5613 SSVAL(req->outbuf,smb_vwv0,0);
5614 SSVAL(req->outbuf,smb_vwv1,0);
5615 SCVAL(smb_buf(req->outbuf),0,1);
5616 SSVAL(smb_buf(req->outbuf),1,0);
5618 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5619 start_index, max_count));
5622 TALLOC_CTX *mem_ctx = talloc_tos();
5623 NTSTATUS status;
5624 WERROR werr;
5625 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5626 struct rpc_pipe_client *cli = NULL;
5627 struct dcerpc_binding_handle *b = NULL;
5628 struct policy_handle handle;
5629 struct spoolss_DevmodeContainer devmode_ctr;
5630 union spoolss_JobInfo *info;
5631 uint32_t count;
5632 uint32_t num_to_get;
5633 uint32_t first;
5634 uint32_t i;
5636 ZERO_STRUCT(handle);
5638 status = rpc_pipe_open_interface(conn,
5639 &ndr_table_spoolss.syntax_id,
5640 conn->session_info,
5641 conn->sconn->remote_address,
5642 conn->sconn->msg_ctx,
5643 &cli);
5644 if (!NT_STATUS_IS_OK(status)) {
5645 DEBUG(0, ("reply_printqueue: "
5646 "could not connect to spoolss: %s\n",
5647 nt_errstr(status)));
5648 reply_nterror(req, status);
5649 goto out;
5651 b = cli->binding_handle;
5653 ZERO_STRUCT(devmode_ctr);
5655 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5656 sharename,
5657 NULL, devmode_ctr,
5658 SEC_FLAG_MAXIMUM_ALLOWED,
5659 &handle,
5660 &werr);
5661 if (!NT_STATUS_IS_OK(status)) {
5662 reply_nterror(req, status);
5663 goto out;
5665 if (!W_ERROR_IS_OK(werr)) {
5666 reply_nterror(req, werror_to_ntstatus(werr));
5667 goto out;
5670 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5671 &handle,
5672 0, /* firstjob */
5673 0xff, /* numjobs */
5674 2, /* level */
5675 0, /* offered */
5676 &count,
5677 &info);
5678 if (!W_ERROR_IS_OK(werr)) {
5679 reply_nterror(req, werror_to_ntstatus(werr));
5680 goto out;
5683 if (max_count > 0) {
5684 first = start_index;
5685 } else {
5686 first = start_index + max_count + 1;
5689 if (first >= count) {
5690 num_to_get = first;
5691 } else {
5692 num_to_get = first + MIN(ABS(max_count), count - first);
5695 for (i = first; i < num_to_get; i++) {
5696 char blob[28];
5697 char *p = blob;
5698 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5699 int qstatus;
5700 uint16_t qrapjobid = pjobid_to_rap(sharename,
5701 info[i].info2.job_id);
5703 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5704 qstatus = 2;
5705 } else {
5706 qstatus = 3;
5709 srv_put_dos_date2(p, 0, qtime);
5710 SCVAL(p, 4, qstatus);
5711 SSVAL(p, 5, qrapjobid);
5712 SIVAL(p, 7, info[i].info2.size);
5713 SCVAL(p, 11, 0);
5714 srvstr_push(blob, req->flags2, p+12,
5715 info[i].info2.notify_name, 16, STR_ASCII);
5717 if (message_push_blob(
5718 &req->outbuf,
5719 data_blob_const(
5720 blob, sizeof(blob))) == -1) {
5721 reply_nterror(req, NT_STATUS_NO_MEMORY);
5722 goto out;
5726 if (count > 0) {
5727 SSVAL(req->outbuf,smb_vwv0,count);
5728 SSVAL(req->outbuf,smb_vwv1,
5729 (max_count>0?first+count:first-1));
5730 SCVAL(smb_buf(req->outbuf),0,1);
5731 SSVAL(smb_buf(req->outbuf),1,28*count);
5735 DEBUG(3, ("%u entries returned in queue\n",
5736 (unsigned)count));
5738 out:
5739 if (b && is_valid_policy_hnd(&handle)) {
5740 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5745 END_PROFILE(SMBsplretq);
5746 return;
5749 /****************************************************************************
5750 Reply to a printwrite.
5751 ****************************************************************************/
5753 void reply_printwrite(struct smb_request *req)
5755 connection_struct *conn = req->conn;
5756 int numtowrite;
5757 const char *data;
5758 files_struct *fsp;
5760 START_PROFILE(SMBsplwr);
5762 if (req->wct < 1) {
5763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5764 END_PROFILE(SMBsplwr);
5765 return;
5768 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5770 if (!check_fsp(conn, req, fsp)) {
5771 END_PROFILE(SMBsplwr);
5772 return;
5775 if (!fsp->print_file) {
5776 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5777 END_PROFILE(SMBsplwr);
5778 return;
5781 if (!CHECK_WRITE(fsp)) {
5782 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5783 END_PROFILE(SMBsplwr);
5784 return;
5787 numtowrite = SVAL(req->buf, 1);
5789 if (req->buflen < numtowrite + 3) {
5790 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5791 END_PROFILE(SMBsplwr);
5792 return;
5795 data = (const char *)req->buf + 3;
5797 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5798 reply_nterror(req, map_nt_error_from_unix(errno));
5799 END_PROFILE(SMBsplwr);
5800 return;
5803 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5805 END_PROFILE(SMBsplwr);
5806 return;
5809 /****************************************************************************
5810 Reply to a mkdir.
5811 ****************************************************************************/
5813 void reply_mkdir(struct smb_request *req)
5815 connection_struct *conn = req->conn;
5816 struct smb_filename *smb_dname = NULL;
5817 char *directory = NULL;
5818 NTSTATUS status;
5819 TALLOC_CTX *ctx = talloc_tos();
5821 START_PROFILE(SMBmkdir);
5823 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5824 STR_TERMINATE, &status);
5825 if (!NT_STATUS_IS_OK(status)) {
5826 reply_nterror(req, status);
5827 goto out;
5830 status = filename_convert(ctx, conn,
5831 req->flags2 & FLAGS2_DFS_PATHNAMES,
5832 directory,
5833 UCF_CREATING_FILE,
5834 NULL,
5835 &smb_dname);
5836 if (!NT_STATUS_IS_OK(status)) {
5837 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5838 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5839 ERRSRV, ERRbadpath);
5840 goto out;
5842 reply_nterror(req, status);
5843 goto out;
5846 status = create_directory(conn, req, smb_dname);
5848 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5850 if (!NT_STATUS_IS_OK(status)) {
5852 if (!use_nt_status()
5853 && NT_STATUS_EQUAL(status,
5854 NT_STATUS_OBJECT_NAME_COLLISION)) {
5856 * Yes, in the DOS error code case we get a
5857 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5858 * samba4 torture test.
5860 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5863 reply_nterror(req, status);
5864 goto out;
5867 reply_outbuf(req, 0, 0);
5869 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5870 out:
5871 TALLOC_FREE(smb_dname);
5872 END_PROFILE(SMBmkdir);
5873 return;
5876 /****************************************************************************
5877 Reply to a rmdir.
5878 ****************************************************************************/
5880 void reply_rmdir(struct smb_request *req)
5882 connection_struct *conn = req->conn;
5883 struct smb_filename *smb_dname = NULL;
5884 char *directory = NULL;
5885 NTSTATUS status;
5886 TALLOC_CTX *ctx = talloc_tos();
5887 files_struct *fsp = NULL;
5888 int info = 0;
5889 struct smbd_server_connection *sconn = req->sconn;
5891 START_PROFILE(SMBrmdir);
5893 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5894 STR_TERMINATE, &status);
5895 if (!NT_STATUS_IS_OK(status)) {
5896 reply_nterror(req, status);
5897 goto out;
5900 status = filename_convert(ctx, conn,
5901 req->flags2 & FLAGS2_DFS_PATHNAMES,
5902 directory,
5904 NULL,
5905 &smb_dname);
5906 if (!NT_STATUS_IS_OK(status)) {
5907 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5908 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5909 ERRSRV, ERRbadpath);
5910 goto out;
5912 reply_nterror(req, status);
5913 goto out;
5916 if (is_ntfs_stream_smb_fname(smb_dname)) {
5917 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5918 goto out;
5921 status = SMB_VFS_CREATE_FILE(
5922 conn, /* conn */
5923 req, /* req */
5924 0, /* root_dir_fid */
5925 smb_dname, /* fname */
5926 DELETE_ACCESS, /* access_mask */
5927 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5928 FILE_SHARE_DELETE),
5929 FILE_OPEN, /* create_disposition*/
5930 FILE_DIRECTORY_FILE, /* create_options */
5931 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5932 0, /* oplock_request */
5933 0, /* allocation_size */
5934 0, /* private_flags */
5935 NULL, /* sd */
5936 NULL, /* ea_list */
5937 &fsp, /* result */
5938 &info); /* pinfo */
5940 if (!NT_STATUS_IS_OK(status)) {
5941 if (open_was_deferred(req->sconn, req->mid)) {
5942 /* We have re-scheduled this call. */
5943 goto out;
5945 reply_nterror(req, status);
5946 goto out;
5949 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5950 if (!NT_STATUS_IS_OK(status)) {
5951 close_file(req, fsp, ERROR_CLOSE);
5952 reply_nterror(req, status);
5953 goto out;
5956 if (!set_delete_on_close(fsp, true,
5957 conn->session_info->security_token,
5958 conn->session_info->unix_token)) {
5959 close_file(req, fsp, ERROR_CLOSE);
5960 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5961 goto out;
5964 status = close_file(req, fsp, NORMAL_CLOSE);
5965 if (!NT_STATUS_IS_OK(status)) {
5966 reply_nterror(req, status);
5967 } else {
5968 reply_outbuf(req, 0, 0);
5971 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5973 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5974 out:
5975 TALLOC_FREE(smb_dname);
5976 END_PROFILE(SMBrmdir);
5977 return;
5980 /*******************************************************************
5981 Resolve wildcards in a filename rename.
5982 ********************************************************************/
5984 static bool resolve_wildcards(TALLOC_CTX *ctx,
5985 const char *name1,
5986 const char *name2,
5987 char **pp_newname)
5989 char *name2_copy = NULL;
5990 char *root1 = NULL;
5991 char *root2 = NULL;
5992 char *ext1 = NULL;
5993 char *ext2 = NULL;
5994 char *p,*p2, *pname1, *pname2;
5996 name2_copy = talloc_strdup(ctx, name2);
5997 if (!name2_copy) {
5998 return False;
6001 pname1 = strrchr_m(name1,'/');
6002 pname2 = strrchr_m(name2_copy,'/');
6004 if (!pname1 || !pname2) {
6005 return False;
6008 /* Truncate the copy of name2 at the last '/' */
6009 *pname2 = '\0';
6011 /* Now go past the '/' */
6012 pname1++;
6013 pname2++;
6015 root1 = talloc_strdup(ctx, pname1);
6016 root2 = talloc_strdup(ctx, pname2);
6018 if (!root1 || !root2) {
6019 return False;
6022 p = strrchr_m(root1,'.');
6023 if (p) {
6024 *p = 0;
6025 ext1 = talloc_strdup(ctx, p+1);
6026 } else {
6027 ext1 = talloc_strdup(ctx, "");
6029 p = strrchr_m(root2,'.');
6030 if (p) {
6031 *p = 0;
6032 ext2 = talloc_strdup(ctx, p+1);
6033 } else {
6034 ext2 = talloc_strdup(ctx, "");
6037 if (!ext1 || !ext2) {
6038 return False;
6041 p = root1;
6042 p2 = root2;
6043 while (*p2) {
6044 if (*p2 == '?') {
6045 /* Hmmm. Should this be mb-aware ? */
6046 *p2 = *p;
6047 p2++;
6048 } else if (*p2 == '*') {
6049 *p2 = '\0';
6050 root2 = talloc_asprintf(ctx, "%s%s",
6051 root2,
6053 if (!root2) {
6054 return False;
6056 break;
6057 } else {
6058 p2++;
6060 if (*p) {
6061 p++;
6065 p = ext1;
6066 p2 = ext2;
6067 while (*p2) {
6068 if (*p2 == '?') {
6069 /* Hmmm. Should this be mb-aware ? */
6070 *p2 = *p;
6071 p2++;
6072 } else if (*p2 == '*') {
6073 *p2 = '\0';
6074 ext2 = talloc_asprintf(ctx, "%s%s",
6075 ext2,
6077 if (!ext2) {
6078 return False;
6080 break;
6081 } else {
6082 p2++;
6084 if (*p) {
6085 p++;
6089 if (*ext2) {
6090 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6091 name2_copy,
6092 root2,
6093 ext2);
6094 } else {
6095 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6096 name2_copy,
6097 root2);
6100 if (!*pp_newname) {
6101 return False;
6104 return True;
6107 /****************************************************************************
6108 Ensure open files have their names updated. Updated to notify other smbd's
6109 asynchronously.
6110 ****************************************************************************/
6112 static void rename_open_files(connection_struct *conn,
6113 struct share_mode_lock *lck,
6114 uint32_t orig_name_hash,
6115 const struct smb_filename *smb_fname_dst)
6117 files_struct *fsp;
6118 bool did_rename = False;
6119 NTSTATUS status;
6120 uint32_t new_name_hash = 0;
6122 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6123 fsp = file_find_di_next(fsp)) {
6124 /* fsp_name is a relative path under the fsp. To change this for other
6125 sharepaths we need to manipulate relative paths. */
6126 /* TODO - create the absolute path and manipulate the newname
6127 relative to the sharepath. */
6128 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6129 continue;
6131 if (fsp->name_hash != orig_name_hash) {
6132 continue;
6134 DEBUG(10, ("rename_open_files: renaming file %s "
6135 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6136 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6137 smb_fname_str_dbg(smb_fname_dst)));
6139 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6140 if (NT_STATUS_IS_OK(status)) {
6141 did_rename = True;
6142 new_name_hash = fsp->name_hash;
6146 if (!did_rename) {
6147 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6148 "for %s\n", file_id_string_tos(&lck->data->id),
6149 smb_fname_str_dbg(smb_fname_dst)));
6152 /* Send messages to all smbd's (not ourself) that the name has changed. */
6153 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6154 orig_name_hash, new_name_hash,
6155 smb_fname_dst);
6159 /****************************************************************************
6160 We need to check if the source path is a parent directory of the destination
6161 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6162 refuse the rename with a sharing violation. Under UNIX the above call can
6163 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6164 probably need to check that the client is a Windows one before disallowing
6165 this as a UNIX client (one with UNIX extensions) can know the source is a
6166 symlink and make this decision intelligently. Found by an excellent bug
6167 report from <AndyLiebman@aol.com>.
6168 ****************************************************************************/
6170 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6171 const struct smb_filename *smb_fname_dst)
6173 const char *psrc = smb_fname_src->base_name;
6174 const char *pdst = smb_fname_dst->base_name;
6175 size_t slen;
6177 if (psrc[0] == '.' && psrc[1] == '/') {
6178 psrc += 2;
6180 if (pdst[0] == '.' && pdst[1] == '/') {
6181 pdst += 2;
6183 if ((slen = strlen(psrc)) > strlen(pdst)) {
6184 return False;
6186 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6190 * Do the notify calls from a rename
6193 static void notify_rename(connection_struct *conn, bool is_dir,
6194 const struct smb_filename *smb_fname_src,
6195 const struct smb_filename *smb_fname_dst)
6197 char *parent_dir_src = NULL;
6198 char *parent_dir_dst = NULL;
6199 uint32 mask;
6201 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6202 : FILE_NOTIFY_CHANGE_FILE_NAME;
6204 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6205 &parent_dir_src, NULL) ||
6206 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6207 &parent_dir_dst, NULL)) {
6208 goto out;
6211 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6212 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6213 smb_fname_src->base_name);
6214 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6215 smb_fname_dst->base_name);
6217 else {
6218 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6219 smb_fname_src->base_name);
6220 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6221 smb_fname_dst->base_name);
6224 /* this is a strange one. w2k3 gives an additional event for
6225 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6226 files, but not directories */
6227 if (!is_dir) {
6228 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6229 FILE_NOTIFY_CHANGE_ATTRIBUTES
6230 |FILE_NOTIFY_CHANGE_CREATION,
6231 smb_fname_dst->base_name);
6233 out:
6234 TALLOC_FREE(parent_dir_src);
6235 TALLOC_FREE(parent_dir_dst);
6238 /****************************************************************************
6239 Returns an error if the parent directory for a filename is open in an
6240 incompatible way.
6241 ****************************************************************************/
6243 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6244 const struct smb_filename *smb_fname_dst_in)
6246 char *parent_dir = NULL;
6247 struct smb_filename smb_fname_parent;
6248 struct file_id id;
6249 files_struct *fsp = NULL;
6250 int ret;
6252 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6253 &parent_dir, NULL)) {
6254 return NT_STATUS_NO_MEMORY;
6256 ZERO_STRUCT(smb_fname_parent);
6257 smb_fname_parent.base_name = parent_dir;
6259 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6260 if (ret == -1) {
6261 return map_nt_error_from_unix(errno);
6265 * We're only checking on this smbd here, mostly good
6266 * enough.. and will pass tests.
6269 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6270 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6271 fsp = file_find_di_next(fsp)) {
6272 if (fsp->access_mask & DELETE_ACCESS) {
6273 return NT_STATUS_SHARING_VIOLATION;
6276 return NT_STATUS_OK;
6279 /****************************************************************************
6280 Rename an open file - given an fsp.
6281 ****************************************************************************/
6283 NTSTATUS rename_internals_fsp(connection_struct *conn,
6284 files_struct *fsp,
6285 const struct smb_filename *smb_fname_dst_in,
6286 uint32 attrs,
6287 bool replace_if_exists)
6289 TALLOC_CTX *ctx = talloc_tos();
6290 struct smb_filename *smb_fname_dst = NULL;
6291 NTSTATUS status = NT_STATUS_OK;
6292 struct share_mode_lock *lck = NULL;
6293 bool dst_exists, old_is_stream, new_is_stream;
6295 status = check_name(conn, smb_fname_dst_in->base_name);
6296 if (!NT_STATUS_IS_OK(status)) {
6297 return status;
6300 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6301 if (!NT_STATUS_IS_OK(status)) {
6302 return status;
6305 /* Make a copy of the dst smb_fname structs */
6307 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6308 if (smb_fname_dst == NULL) {
6309 status = NT_STATUS_NO_MEMORY;
6310 goto out;
6314 * Check for special case with case preserving and not
6315 * case sensitive. If the old last component differs from the original
6316 * last component only by case, then we should allow
6317 * the rename (user is trying to change the case of the
6318 * filename).
6320 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6321 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6322 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6323 char *last_slash;
6324 char *fname_dst_lcomp_base_mod = NULL;
6325 struct smb_filename *smb_fname_orig_lcomp = NULL;
6328 * Get the last component of the destination name.
6330 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6331 if (last_slash) {
6332 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6333 } else {
6334 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6336 if (!fname_dst_lcomp_base_mod) {
6337 status = NT_STATUS_NO_MEMORY;
6338 goto out;
6342 * Create an smb_filename struct using the original last
6343 * component of the destination.
6345 smb_fname_orig_lcomp = synthetic_smb_fname_split(
6346 ctx, smb_fname_dst->original_lcomp, NULL);
6347 if (smb_fname_orig_lcomp == NULL) {
6348 status = NT_STATUS_NO_MEMORY;
6349 TALLOC_FREE(fname_dst_lcomp_base_mod);
6350 goto out;
6353 /* If the base names only differ by case, use original. */
6354 if(!strcsequal(fname_dst_lcomp_base_mod,
6355 smb_fname_orig_lcomp->base_name)) {
6356 char *tmp;
6358 * Replace the modified last component with the
6359 * original.
6361 if (last_slash) {
6362 *last_slash = '\0'; /* Truncate at the '/' */
6363 tmp = talloc_asprintf(smb_fname_dst,
6364 "%s/%s",
6365 smb_fname_dst->base_name,
6366 smb_fname_orig_lcomp->base_name);
6367 } else {
6368 tmp = talloc_asprintf(smb_fname_dst,
6369 "%s",
6370 smb_fname_orig_lcomp->base_name);
6372 if (tmp == NULL) {
6373 status = NT_STATUS_NO_MEMORY;
6374 TALLOC_FREE(fname_dst_lcomp_base_mod);
6375 TALLOC_FREE(smb_fname_orig_lcomp);
6376 goto out;
6378 TALLOC_FREE(smb_fname_dst->base_name);
6379 smb_fname_dst->base_name = tmp;
6382 /* If the stream_names only differ by case, use original. */
6383 if(!strcsequal(smb_fname_dst->stream_name,
6384 smb_fname_orig_lcomp->stream_name)) {
6385 char *tmp = NULL;
6386 /* Use the original stream. */
6387 tmp = talloc_strdup(smb_fname_dst,
6388 smb_fname_orig_lcomp->stream_name);
6389 if (tmp == NULL) {
6390 status = NT_STATUS_NO_MEMORY;
6391 TALLOC_FREE(fname_dst_lcomp_base_mod);
6392 TALLOC_FREE(smb_fname_orig_lcomp);
6393 goto out;
6395 TALLOC_FREE(smb_fname_dst->stream_name);
6396 smb_fname_dst->stream_name = tmp;
6398 TALLOC_FREE(fname_dst_lcomp_base_mod);
6399 TALLOC_FREE(smb_fname_orig_lcomp);
6403 * If the src and dest names are identical - including case,
6404 * don't do the rename, just return success.
6407 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6408 strcsequal(fsp->fsp_name->stream_name,
6409 smb_fname_dst->stream_name)) {
6410 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6411 "- returning success\n",
6412 smb_fname_str_dbg(smb_fname_dst)));
6413 status = NT_STATUS_OK;
6414 goto out;
6417 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6418 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6420 /* Return the correct error code if both names aren't streams. */
6421 if (!old_is_stream && new_is_stream) {
6422 status = NT_STATUS_OBJECT_NAME_INVALID;
6423 goto out;
6426 if (old_is_stream && !new_is_stream) {
6427 status = NT_STATUS_INVALID_PARAMETER;
6428 goto out;
6431 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6433 if(!replace_if_exists && dst_exists) {
6434 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6435 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6436 smb_fname_str_dbg(smb_fname_dst)));
6437 status = NT_STATUS_OBJECT_NAME_COLLISION;
6438 goto out;
6441 if (dst_exists) {
6442 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6443 &smb_fname_dst->st);
6444 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6445 fileid);
6446 /* The file can be open when renaming a stream */
6447 if (dst_fsp && !new_is_stream) {
6448 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6449 status = NT_STATUS_ACCESS_DENIED;
6450 goto out;
6454 /* Ensure we have a valid stat struct for the source. */
6455 status = vfs_stat_fsp(fsp);
6456 if (!NT_STATUS_IS_OK(status)) {
6457 goto out;
6460 status = can_rename(conn, fsp, attrs);
6462 if (!NT_STATUS_IS_OK(status)) {
6463 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6464 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6465 smb_fname_str_dbg(smb_fname_dst)));
6466 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6467 status = NT_STATUS_ACCESS_DENIED;
6468 goto out;
6471 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6472 status = NT_STATUS_ACCESS_DENIED;
6475 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6478 * We have the file open ourselves, so not being able to get the
6479 * corresponding share mode lock is a fatal error.
6482 SMB_ASSERT(lck != NULL);
6484 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6485 uint32 create_options = fsp->fh->private_options;
6487 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6488 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6489 smb_fname_str_dbg(smb_fname_dst)));
6491 if (!fsp->is_directory &&
6492 !lp_posix_pathnames() &&
6493 (lp_map_archive(SNUM(conn)) ||
6494 lp_store_dos_attributes(SNUM(conn)))) {
6495 /* We must set the archive bit on the newly
6496 renamed file. */
6497 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6498 uint32_t old_dosmode = dos_mode(conn,
6499 smb_fname_dst);
6500 file_set_dosmode(conn,
6501 smb_fname_dst,
6502 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6503 NULL,
6504 true);
6508 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6509 smb_fname_dst);
6511 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6514 * A rename acts as a new file create w.r.t. allowing an initial delete
6515 * on close, probably because in Windows there is a new handle to the
6516 * new file. If initial delete on close was requested but not
6517 * originally set, we need to set it here. This is probably not 100% correct,
6518 * but will work for the CIFSFS client which in non-posix mode
6519 * depends on these semantics. JRA.
6522 if (create_options & FILE_DELETE_ON_CLOSE) {
6523 status = can_set_delete_on_close(fsp, 0);
6525 if (NT_STATUS_IS_OK(status)) {
6526 /* Note that here we set the *inital* delete on close flag,
6527 * not the regular one. The magic gets handled in close. */
6528 fsp->initial_delete_on_close = True;
6531 TALLOC_FREE(lck);
6532 status = NT_STATUS_OK;
6533 goto out;
6536 TALLOC_FREE(lck);
6538 if (errno == ENOTDIR || errno == EISDIR) {
6539 status = NT_STATUS_OBJECT_NAME_COLLISION;
6540 } else {
6541 status = map_nt_error_from_unix(errno);
6544 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6545 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6546 smb_fname_str_dbg(smb_fname_dst)));
6548 out:
6549 TALLOC_FREE(smb_fname_dst);
6551 return status;
6554 /****************************************************************************
6555 The guts of the rename command, split out so it may be called by the NT SMB
6556 code.
6557 ****************************************************************************/
6559 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6560 connection_struct *conn,
6561 struct smb_request *req,
6562 struct smb_filename *smb_fname_src,
6563 struct smb_filename *smb_fname_dst,
6564 uint32 attrs,
6565 bool replace_if_exists,
6566 bool src_has_wild,
6567 bool dest_has_wild,
6568 uint32_t access_mask)
6570 char *fname_src_dir = NULL;
6571 char *fname_src_mask = NULL;
6572 int count=0;
6573 NTSTATUS status = NT_STATUS_OK;
6574 struct smb_Dir *dir_hnd = NULL;
6575 const char *dname = NULL;
6576 char *talloced = NULL;
6577 long offset = 0;
6578 int create_options = 0;
6579 bool posix_pathnames = lp_posix_pathnames();
6580 int rc;
6583 * Split the old name into directory and last component
6584 * strings. Note that unix_convert may have stripped off a
6585 * leading ./ from both name and newname if the rename is
6586 * at the root of the share. We need to make sure either both
6587 * name and newname contain a / character or neither of them do
6588 * as this is checked in resolve_wildcards().
6591 /* Split up the directory from the filename/mask. */
6592 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6593 &fname_src_dir, &fname_src_mask);
6594 if (!NT_STATUS_IS_OK(status)) {
6595 status = NT_STATUS_NO_MEMORY;
6596 goto out;
6600 * We should only check the mangled cache
6601 * here if unix_convert failed. This means
6602 * that the path in 'mask' doesn't exist
6603 * on the file system and so we need to look
6604 * for a possible mangle. This patch from
6605 * Tine Smukavec <valentin.smukavec@hermes.si>.
6608 if (!VALID_STAT(smb_fname_src->st) &&
6609 mangle_is_mangled(fname_src_mask, conn->params)) {
6610 char *new_mask = NULL;
6611 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6612 conn->params);
6613 if (new_mask) {
6614 TALLOC_FREE(fname_src_mask);
6615 fname_src_mask = new_mask;
6619 if (!src_has_wild) {
6620 files_struct *fsp;
6623 * Only one file needs to be renamed. Append the mask back
6624 * onto the directory.
6626 TALLOC_FREE(smb_fname_src->base_name);
6627 if (ISDOT(fname_src_dir)) {
6628 /* Ensure we use canonical names on open. */
6629 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6630 "%s",
6631 fname_src_mask);
6632 } else {
6633 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6634 "%s/%s",
6635 fname_src_dir,
6636 fname_src_mask);
6638 if (!smb_fname_src->base_name) {
6639 status = NT_STATUS_NO_MEMORY;
6640 goto out;
6643 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6644 "case_preserve = %d, short case preserve = %d, "
6645 "directory = %s, newname = %s, "
6646 "last_component_dest = %s\n",
6647 conn->case_sensitive, conn->case_preserve,
6648 conn->short_case_preserve,
6649 smb_fname_str_dbg(smb_fname_src),
6650 smb_fname_str_dbg(smb_fname_dst),
6651 smb_fname_dst->original_lcomp));
6653 /* The dest name still may have wildcards. */
6654 if (dest_has_wild) {
6655 char *fname_dst_mod = NULL;
6656 if (!resolve_wildcards(smb_fname_dst,
6657 smb_fname_src->base_name,
6658 smb_fname_dst->base_name,
6659 &fname_dst_mod)) {
6660 DEBUG(6, ("rename_internals: resolve_wildcards "
6661 "%s %s failed\n",
6662 smb_fname_src->base_name,
6663 smb_fname_dst->base_name));
6664 status = NT_STATUS_NO_MEMORY;
6665 goto out;
6667 TALLOC_FREE(smb_fname_dst->base_name);
6668 smb_fname_dst->base_name = fname_dst_mod;
6671 ZERO_STRUCT(smb_fname_src->st);
6672 if (posix_pathnames) {
6673 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6674 } else {
6675 rc = SMB_VFS_STAT(conn, smb_fname_src);
6677 if (rc == -1) {
6678 status = map_nt_error_from_unix_common(errno);
6679 goto out;
6682 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6683 create_options |= FILE_DIRECTORY_FILE;
6686 status = SMB_VFS_CREATE_FILE(
6687 conn, /* conn */
6688 req, /* req */
6689 0, /* root_dir_fid */
6690 smb_fname_src, /* fname */
6691 access_mask, /* access_mask */
6692 (FILE_SHARE_READ | /* share_access */
6693 FILE_SHARE_WRITE),
6694 FILE_OPEN, /* create_disposition*/
6695 create_options, /* create_options */
6696 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6697 0, /* oplock_request */
6698 0, /* allocation_size */
6699 0, /* private_flags */
6700 NULL, /* sd */
6701 NULL, /* ea_list */
6702 &fsp, /* result */
6703 NULL); /* pinfo */
6705 if (!NT_STATUS_IS_OK(status)) {
6706 DEBUG(3, ("Could not open rename source %s: %s\n",
6707 smb_fname_str_dbg(smb_fname_src),
6708 nt_errstr(status)));
6709 goto out;
6712 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6713 attrs, replace_if_exists);
6715 close_file(req, fsp, NORMAL_CLOSE);
6717 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6718 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6719 smb_fname_str_dbg(smb_fname_dst)));
6721 goto out;
6725 * Wildcards - process each file that matches.
6727 if (strequal(fname_src_mask, "????????.???")) {
6728 TALLOC_FREE(fname_src_mask);
6729 fname_src_mask = talloc_strdup(ctx, "*");
6730 if (!fname_src_mask) {
6731 status = NT_STATUS_NO_MEMORY;
6732 goto out;
6736 status = check_name(conn, fname_src_dir);
6737 if (!NT_STATUS_IS_OK(status)) {
6738 goto out;
6741 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6742 attrs);
6743 if (dir_hnd == NULL) {
6744 status = map_nt_error_from_unix(errno);
6745 goto out;
6748 status = NT_STATUS_NO_SUCH_FILE;
6750 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6751 * - gentest fix. JRA
6754 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6755 &talloced))) {
6756 files_struct *fsp = NULL;
6757 char *destname = NULL;
6758 bool sysdir_entry = False;
6760 /* Quick check for "." and ".." */
6761 if (ISDOT(dname) || ISDOTDOT(dname)) {
6762 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6763 sysdir_entry = True;
6764 } else {
6765 TALLOC_FREE(talloced);
6766 continue;
6770 if (!is_visible_file(conn, fname_src_dir, dname,
6771 &smb_fname_src->st, false)) {
6772 TALLOC_FREE(talloced);
6773 continue;
6776 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6777 TALLOC_FREE(talloced);
6778 continue;
6781 if (sysdir_entry) {
6782 status = NT_STATUS_OBJECT_NAME_INVALID;
6783 break;
6786 TALLOC_FREE(smb_fname_src->base_name);
6787 if (ISDOT(fname_src_dir)) {
6788 /* Ensure we use canonical names on open. */
6789 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6790 "%s",
6791 dname);
6792 } else {
6793 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6794 "%s/%s",
6795 fname_src_dir,
6796 dname);
6798 if (!smb_fname_src->base_name) {
6799 status = NT_STATUS_NO_MEMORY;
6800 goto out;
6803 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6804 smb_fname_dst->base_name,
6805 &destname)) {
6806 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6807 smb_fname_src->base_name, destname));
6808 TALLOC_FREE(talloced);
6809 continue;
6811 if (!destname) {
6812 status = NT_STATUS_NO_MEMORY;
6813 goto out;
6816 TALLOC_FREE(smb_fname_dst->base_name);
6817 smb_fname_dst->base_name = destname;
6819 ZERO_STRUCT(smb_fname_src->st);
6820 if (posix_pathnames) {
6821 SMB_VFS_LSTAT(conn, smb_fname_src);
6822 } else {
6823 SMB_VFS_STAT(conn, smb_fname_src);
6826 create_options = 0;
6828 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6829 create_options |= FILE_DIRECTORY_FILE;
6832 status = SMB_VFS_CREATE_FILE(
6833 conn, /* conn */
6834 req, /* req */
6835 0, /* root_dir_fid */
6836 smb_fname_src, /* fname */
6837 access_mask, /* access_mask */
6838 (FILE_SHARE_READ | /* share_access */
6839 FILE_SHARE_WRITE),
6840 FILE_OPEN, /* create_disposition*/
6841 create_options, /* create_options */
6842 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6843 0, /* oplock_request */
6844 0, /* allocation_size */
6845 0, /* private_flags */
6846 NULL, /* sd */
6847 NULL, /* ea_list */
6848 &fsp, /* result */
6849 NULL); /* pinfo */
6851 if (!NT_STATUS_IS_OK(status)) {
6852 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6853 "returned %s rename %s -> %s\n",
6854 nt_errstr(status),
6855 smb_fname_str_dbg(smb_fname_src),
6856 smb_fname_str_dbg(smb_fname_dst)));
6857 break;
6860 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6861 dname);
6862 if (!smb_fname_dst->original_lcomp) {
6863 status = NT_STATUS_NO_MEMORY;
6864 goto out;
6867 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6868 attrs, replace_if_exists);
6870 close_file(req, fsp, NORMAL_CLOSE);
6872 if (!NT_STATUS_IS_OK(status)) {
6873 DEBUG(3, ("rename_internals_fsp returned %s for "
6874 "rename %s -> %s\n", nt_errstr(status),
6875 smb_fname_str_dbg(smb_fname_src),
6876 smb_fname_str_dbg(smb_fname_dst)));
6877 break;
6880 count++;
6882 DEBUG(3,("rename_internals: doing rename on %s -> "
6883 "%s\n", smb_fname_str_dbg(smb_fname_src),
6884 smb_fname_str_dbg(smb_fname_src)));
6885 TALLOC_FREE(talloced);
6887 TALLOC_FREE(dir_hnd);
6889 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6890 status = map_nt_error_from_unix(errno);
6893 out:
6894 TALLOC_FREE(talloced);
6895 TALLOC_FREE(fname_src_dir);
6896 TALLOC_FREE(fname_src_mask);
6897 return status;
6900 /****************************************************************************
6901 Reply to a mv.
6902 ****************************************************************************/
6904 void reply_mv(struct smb_request *req)
6906 connection_struct *conn = req->conn;
6907 char *name = NULL;
6908 char *newname = NULL;
6909 const char *p;
6910 uint32 attrs;
6911 NTSTATUS status;
6912 bool src_has_wcard = False;
6913 bool dest_has_wcard = False;
6914 TALLOC_CTX *ctx = talloc_tos();
6915 struct smb_filename *smb_fname_src = NULL;
6916 struct smb_filename *smb_fname_dst = NULL;
6917 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6918 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6919 bool stream_rename = false;
6921 START_PROFILE(SMBmv);
6923 if (req->wct < 1) {
6924 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6925 goto out;
6928 attrs = SVAL(req->vwv+0, 0);
6930 p = (const char *)req->buf + 1;
6931 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6932 &status, &src_has_wcard);
6933 if (!NT_STATUS_IS_OK(status)) {
6934 reply_nterror(req, status);
6935 goto out;
6937 p++;
6938 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6939 &status, &dest_has_wcard);
6940 if (!NT_STATUS_IS_OK(status)) {
6941 reply_nterror(req, status);
6942 goto out;
6945 if (!lp_posix_pathnames()) {
6946 /* The newname must begin with a ':' if the
6947 name contains a ':'. */
6948 if (strchr_m(name, ':')) {
6949 if (newname[0] != ':') {
6950 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6951 goto out;
6953 stream_rename = true;
6957 status = filename_convert(ctx,
6958 conn,
6959 req->flags2 & FLAGS2_DFS_PATHNAMES,
6960 name,
6961 src_ucf_flags,
6962 &src_has_wcard,
6963 &smb_fname_src);
6965 if (!NT_STATUS_IS_OK(status)) {
6966 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6967 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6968 ERRSRV, ERRbadpath);
6969 goto out;
6971 reply_nterror(req, status);
6972 goto out;
6975 status = filename_convert(ctx,
6976 conn,
6977 req->flags2 & FLAGS2_DFS_PATHNAMES,
6978 newname,
6979 dst_ucf_flags,
6980 &dest_has_wcard,
6981 &smb_fname_dst);
6983 if (!NT_STATUS_IS_OK(status)) {
6984 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6985 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6986 ERRSRV, ERRbadpath);
6987 goto out;
6989 reply_nterror(req, status);
6990 goto out;
6993 if (stream_rename) {
6994 /* smb_fname_dst->base_name must be the same as
6995 smb_fname_src->base_name. */
6996 TALLOC_FREE(smb_fname_dst->base_name);
6997 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6998 smb_fname_src->base_name);
6999 if (!smb_fname_dst->base_name) {
7000 reply_nterror(req, NT_STATUS_NO_MEMORY);
7001 goto out;
7005 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7006 smb_fname_str_dbg(smb_fname_dst)));
7008 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7009 attrs, False, src_has_wcard, dest_has_wcard,
7010 DELETE_ACCESS);
7011 if (!NT_STATUS_IS_OK(status)) {
7012 if (open_was_deferred(req->sconn, req->mid)) {
7013 /* We have re-scheduled this call. */
7014 goto out;
7016 reply_nterror(req, status);
7017 goto out;
7020 reply_outbuf(req, 0, 0);
7021 out:
7022 TALLOC_FREE(smb_fname_src);
7023 TALLOC_FREE(smb_fname_dst);
7024 END_PROFILE(SMBmv);
7025 return;
7028 /*******************************************************************
7029 Copy a file as part of a reply_copy.
7030 ******************************************************************/
7033 * TODO: check error codes on all callers
7036 NTSTATUS copy_file(TALLOC_CTX *ctx,
7037 connection_struct *conn,
7038 struct smb_filename *smb_fname_src,
7039 struct smb_filename *smb_fname_dst,
7040 int ofun,
7041 int count,
7042 bool target_is_directory)
7044 struct smb_filename *smb_fname_dst_tmp = NULL;
7045 off_t ret=-1;
7046 files_struct *fsp1,*fsp2;
7047 uint32 dosattrs;
7048 uint32 new_create_disposition;
7049 NTSTATUS status;
7052 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7053 if (smb_fname_dst_tmp == NULL) {
7054 return NT_STATUS_NO_MEMORY;
7058 * If the target is a directory, extract the last component from the
7059 * src filename and append it to the dst filename
7061 if (target_is_directory) {
7062 const char *p;
7064 /* dest/target can't be a stream if it's a directory. */
7065 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7067 p = strrchr_m(smb_fname_src->base_name,'/');
7068 if (p) {
7069 p++;
7070 } else {
7071 p = smb_fname_src->base_name;
7073 smb_fname_dst_tmp->base_name =
7074 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7076 if (!smb_fname_dst_tmp->base_name) {
7077 status = NT_STATUS_NO_MEMORY;
7078 goto out;
7082 status = vfs_file_exist(conn, smb_fname_src);
7083 if (!NT_STATUS_IS_OK(status)) {
7084 goto out;
7087 if (!target_is_directory && count) {
7088 new_create_disposition = FILE_OPEN;
7089 } else {
7090 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7091 0, ofun,
7092 NULL, NULL,
7093 &new_create_disposition,
7094 NULL,
7095 NULL)) {
7096 status = NT_STATUS_INVALID_PARAMETER;
7097 goto out;
7101 /* Open the src file for reading. */
7102 status = SMB_VFS_CREATE_FILE(
7103 conn, /* conn */
7104 NULL, /* req */
7105 0, /* root_dir_fid */
7106 smb_fname_src, /* fname */
7107 FILE_GENERIC_READ, /* access_mask */
7108 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7109 FILE_OPEN, /* create_disposition*/
7110 0, /* create_options */
7111 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7112 INTERNAL_OPEN_ONLY, /* oplock_request */
7113 0, /* allocation_size */
7114 0, /* private_flags */
7115 NULL, /* sd */
7116 NULL, /* ea_list */
7117 &fsp1, /* result */
7118 NULL); /* psbuf */
7120 if (!NT_STATUS_IS_OK(status)) {
7121 goto out;
7124 dosattrs = dos_mode(conn, smb_fname_src);
7126 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7127 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7130 /* Open the dst file for writing. */
7131 status = SMB_VFS_CREATE_FILE(
7132 conn, /* conn */
7133 NULL, /* req */
7134 0, /* root_dir_fid */
7135 smb_fname_dst, /* fname */
7136 FILE_GENERIC_WRITE, /* access_mask */
7137 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7138 new_create_disposition, /* create_disposition*/
7139 0, /* create_options */
7140 dosattrs, /* file_attributes */
7141 INTERNAL_OPEN_ONLY, /* oplock_request */
7142 0, /* allocation_size */
7143 0, /* private_flags */
7144 NULL, /* sd */
7145 NULL, /* ea_list */
7146 &fsp2, /* result */
7147 NULL); /* psbuf */
7149 if (!NT_STATUS_IS_OK(status)) {
7150 close_file(NULL, fsp1, ERROR_CLOSE);
7151 goto out;
7154 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7155 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7156 if (ret == -1) {
7157 DEBUG(0, ("error - vfs lseek returned error %s\n",
7158 strerror(errno)));
7159 status = map_nt_error_from_unix(errno);
7160 close_file(NULL, fsp1, ERROR_CLOSE);
7161 close_file(NULL, fsp2, ERROR_CLOSE);
7162 goto out;
7166 /* Do the actual copy. */
7167 if (smb_fname_src->st.st_ex_size) {
7168 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7169 } else {
7170 ret = 0;
7173 close_file(NULL, fsp1, NORMAL_CLOSE);
7175 /* Ensure the modtime is set correctly on the destination file. */
7176 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7179 * As we are opening fsp1 read-only we only expect
7180 * an error on close on fsp2 if we are out of space.
7181 * Thus we don't look at the error return from the
7182 * close of fsp1.
7184 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7186 if (!NT_STATUS_IS_OK(status)) {
7187 goto out;
7190 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7191 status = NT_STATUS_DISK_FULL;
7192 goto out;
7195 status = NT_STATUS_OK;
7197 out:
7198 TALLOC_FREE(smb_fname_dst_tmp);
7199 return status;
7202 /****************************************************************************
7203 Reply to a file copy.
7204 ****************************************************************************/
7206 void reply_copy(struct smb_request *req)
7208 connection_struct *conn = req->conn;
7209 struct smb_filename *smb_fname_src = NULL;
7210 struct smb_filename *smb_fname_dst = NULL;
7211 char *fname_src = NULL;
7212 char *fname_dst = NULL;
7213 char *fname_src_mask = NULL;
7214 char *fname_src_dir = NULL;
7215 const char *p;
7216 int count=0;
7217 int error = ERRnoaccess;
7218 int tid2;
7219 int ofun;
7220 int flags;
7221 bool target_is_directory=False;
7222 bool source_has_wild = False;
7223 bool dest_has_wild = False;
7224 NTSTATUS status;
7225 TALLOC_CTX *ctx = talloc_tos();
7227 START_PROFILE(SMBcopy);
7229 if (req->wct < 3) {
7230 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7231 goto out;
7234 tid2 = SVAL(req->vwv+0, 0);
7235 ofun = SVAL(req->vwv+1, 0);
7236 flags = SVAL(req->vwv+2, 0);
7238 p = (const char *)req->buf;
7239 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7240 &status, &source_has_wild);
7241 if (!NT_STATUS_IS_OK(status)) {
7242 reply_nterror(req, status);
7243 goto out;
7245 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7246 &status, &dest_has_wild);
7247 if (!NT_STATUS_IS_OK(status)) {
7248 reply_nterror(req, status);
7249 goto out;
7252 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7254 if (tid2 != conn->cnum) {
7255 /* can't currently handle inter share copies XXXX */
7256 DEBUG(3,("Rejecting inter-share copy\n"));
7257 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7258 goto out;
7261 status = filename_convert(ctx, conn,
7262 req->flags2 & FLAGS2_DFS_PATHNAMES,
7263 fname_src,
7264 UCF_COND_ALLOW_WCARD_LCOMP,
7265 &source_has_wild,
7266 &smb_fname_src);
7267 if (!NT_STATUS_IS_OK(status)) {
7268 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7269 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7270 ERRSRV, ERRbadpath);
7271 goto out;
7273 reply_nterror(req, status);
7274 goto out;
7277 status = filename_convert(ctx, conn,
7278 req->flags2 & FLAGS2_DFS_PATHNAMES,
7279 fname_dst,
7280 UCF_COND_ALLOW_WCARD_LCOMP,
7281 &dest_has_wild,
7282 &smb_fname_dst);
7283 if (!NT_STATUS_IS_OK(status)) {
7284 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7285 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7286 ERRSRV, ERRbadpath);
7287 goto out;
7289 reply_nterror(req, status);
7290 goto out;
7293 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7295 if ((flags&1) && target_is_directory) {
7296 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7297 goto out;
7300 if ((flags&2) && !target_is_directory) {
7301 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7302 goto out;
7305 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7306 /* wants a tree copy! XXXX */
7307 DEBUG(3,("Rejecting tree copy\n"));
7308 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7309 goto out;
7312 /* Split up the directory from the filename/mask. */
7313 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7314 &fname_src_dir, &fname_src_mask);
7315 if (!NT_STATUS_IS_OK(status)) {
7316 reply_nterror(req, NT_STATUS_NO_MEMORY);
7317 goto out;
7321 * We should only check the mangled cache
7322 * here if unix_convert failed. This means
7323 * that the path in 'mask' doesn't exist
7324 * on the file system and so we need to look
7325 * for a possible mangle. This patch from
7326 * Tine Smukavec <valentin.smukavec@hermes.si>.
7328 if (!VALID_STAT(smb_fname_src->st) &&
7329 mangle_is_mangled(fname_src_mask, conn->params)) {
7330 char *new_mask = NULL;
7331 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7332 &new_mask, conn->params);
7334 /* Use demangled name if one was successfully found. */
7335 if (new_mask) {
7336 TALLOC_FREE(fname_src_mask);
7337 fname_src_mask = new_mask;
7341 if (!source_has_wild) {
7344 * Only one file needs to be copied. Append the mask back onto
7345 * the directory.
7347 TALLOC_FREE(smb_fname_src->base_name);
7348 if (ISDOT(fname_src_dir)) {
7349 /* Ensure we use canonical names on open. */
7350 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7351 "%s",
7352 fname_src_mask);
7353 } else {
7354 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7355 "%s/%s",
7356 fname_src_dir,
7357 fname_src_mask);
7359 if (!smb_fname_src->base_name) {
7360 reply_nterror(req, NT_STATUS_NO_MEMORY);
7361 goto out;
7364 if (dest_has_wild) {
7365 char *fname_dst_mod = NULL;
7366 if (!resolve_wildcards(smb_fname_dst,
7367 smb_fname_src->base_name,
7368 smb_fname_dst->base_name,
7369 &fname_dst_mod)) {
7370 reply_nterror(req, NT_STATUS_NO_MEMORY);
7371 goto out;
7373 TALLOC_FREE(smb_fname_dst->base_name);
7374 smb_fname_dst->base_name = fname_dst_mod;
7377 status = check_name(conn, smb_fname_src->base_name);
7378 if (!NT_STATUS_IS_OK(status)) {
7379 reply_nterror(req, status);
7380 goto out;
7383 status = check_name(conn, smb_fname_dst->base_name);
7384 if (!NT_STATUS_IS_OK(status)) {
7385 reply_nterror(req, status);
7386 goto out;
7389 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7390 ofun, count, target_is_directory);
7392 if(!NT_STATUS_IS_OK(status)) {
7393 reply_nterror(req, status);
7394 goto out;
7395 } else {
7396 count++;
7398 } else {
7399 struct smb_Dir *dir_hnd = NULL;
7400 const char *dname = NULL;
7401 char *talloced = NULL;
7402 long offset = 0;
7405 * There is a wildcard that requires us to actually read the
7406 * src dir and copy each file matching the mask to the dst.
7407 * Right now streams won't be copied, but this could
7408 * presumably be added with a nested loop for reach dir entry.
7410 SMB_ASSERT(!smb_fname_src->stream_name);
7411 SMB_ASSERT(!smb_fname_dst->stream_name);
7413 smb_fname_src->stream_name = NULL;
7414 smb_fname_dst->stream_name = NULL;
7416 if (strequal(fname_src_mask,"????????.???")) {
7417 TALLOC_FREE(fname_src_mask);
7418 fname_src_mask = talloc_strdup(ctx, "*");
7419 if (!fname_src_mask) {
7420 reply_nterror(req, NT_STATUS_NO_MEMORY);
7421 goto out;
7425 status = check_name(conn, fname_src_dir);
7426 if (!NT_STATUS_IS_OK(status)) {
7427 reply_nterror(req, status);
7428 goto out;
7431 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7432 if (dir_hnd == NULL) {
7433 status = map_nt_error_from_unix(errno);
7434 reply_nterror(req, status);
7435 goto out;
7438 error = ERRbadfile;
7440 /* Iterate over the src dir copying each entry to the dst. */
7441 while ((dname = ReadDirName(dir_hnd, &offset,
7442 &smb_fname_src->st, &talloced))) {
7443 char *destname = NULL;
7445 if (ISDOT(dname) || ISDOTDOT(dname)) {
7446 TALLOC_FREE(talloced);
7447 continue;
7450 if (!is_visible_file(conn, fname_src_dir, dname,
7451 &smb_fname_src->st, false)) {
7452 TALLOC_FREE(talloced);
7453 continue;
7456 if(!mask_match(dname, fname_src_mask,
7457 conn->case_sensitive)) {
7458 TALLOC_FREE(talloced);
7459 continue;
7462 error = ERRnoaccess;
7464 /* Get the src smb_fname struct setup. */
7465 TALLOC_FREE(smb_fname_src->base_name);
7466 if (ISDOT(fname_src_dir)) {
7467 /* Ensure we use canonical names on open. */
7468 smb_fname_src->base_name =
7469 talloc_asprintf(smb_fname_src, "%s",
7470 dname);
7471 } else {
7472 smb_fname_src->base_name =
7473 talloc_asprintf(smb_fname_src, "%s/%s",
7474 fname_src_dir, dname);
7477 if (!smb_fname_src->base_name) {
7478 TALLOC_FREE(dir_hnd);
7479 TALLOC_FREE(talloced);
7480 reply_nterror(req, NT_STATUS_NO_MEMORY);
7481 goto out;
7484 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7485 smb_fname_dst->base_name,
7486 &destname)) {
7487 TALLOC_FREE(talloced);
7488 continue;
7490 if (!destname) {
7491 TALLOC_FREE(dir_hnd);
7492 TALLOC_FREE(talloced);
7493 reply_nterror(req, NT_STATUS_NO_MEMORY);
7494 goto out;
7497 TALLOC_FREE(smb_fname_dst->base_name);
7498 smb_fname_dst->base_name = destname;
7500 status = check_name(conn, smb_fname_src->base_name);
7501 if (!NT_STATUS_IS_OK(status)) {
7502 TALLOC_FREE(dir_hnd);
7503 TALLOC_FREE(talloced);
7504 reply_nterror(req, status);
7505 goto out;
7508 status = check_name(conn, smb_fname_dst->base_name);
7509 if (!NT_STATUS_IS_OK(status)) {
7510 TALLOC_FREE(dir_hnd);
7511 TALLOC_FREE(talloced);
7512 reply_nterror(req, status);
7513 goto out;
7516 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7517 smb_fname_src->base_name,
7518 smb_fname_dst->base_name));
7520 status = copy_file(ctx, conn, smb_fname_src,
7521 smb_fname_dst, ofun, count,
7522 target_is_directory);
7523 if (NT_STATUS_IS_OK(status)) {
7524 count++;
7527 TALLOC_FREE(talloced);
7529 TALLOC_FREE(dir_hnd);
7532 if (count == 0) {
7533 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7534 goto out;
7537 reply_outbuf(req, 1, 0);
7538 SSVAL(req->outbuf,smb_vwv0,count);
7539 out:
7540 TALLOC_FREE(smb_fname_src);
7541 TALLOC_FREE(smb_fname_dst);
7542 TALLOC_FREE(fname_src);
7543 TALLOC_FREE(fname_dst);
7544 TALLOC_FREE(fname_src_mask);
7545 TALLOC_FREE(fname_src_dir);
7547 END_PROFILE(SMBcopy);
7548 return;
7551 #undef DBGC_CLASS
7552 #define DBGC_CLASS DBGC_LOCKING
7554 /****************************************************************************
7555 Get a lock pid, dealing with large count requests.
7556 ****************************************************************************/
7558 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7559 bool large_file_format)
7561 if(!large_file_format)
7562 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7563 else
7564 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7567 /****************************************************************************
7568 Get a lock count, dealing with large count requests.
7569 ****************************************************************************/
7571 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7572 bool large_file_format)
7574 uint64_t count = 0;
7576 if(!large_file_format) {
7577 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7578 } else {
7580 #if defined(HAVE_LONGLONG)
7581 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7582 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7583 #else /* HAVE_LONGLONG */
7586 * NT4.x seems to be broken in that it sends large file (64 bit)
7587 * lockingX calls even if the CAP_LARGE_FILES was *not*
7588 * negotiated. For boxes without large unsigned ints truncate the
7589 * lock count by dropping the top 32 bits.
7592 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7593 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7594 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7595 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7596 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7599 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7600 #endif /* HAVE_LONGLONG */
7603 return count;
7606 #if !defined(HAVE_LONGLONG)
7607 /****************************************************************************
7608 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7609 ****************************************************************************/
7611 static uint32 map_lock_offset(uint32 high, uint32 low)
7613 unsigned int i;
7614 uint32 mask = 0;
7615 uint32 highcopy = high;
7618 * Try and find out how many significant bits there are in high.
7621 for(i = 0; highcopy; i++)
7622 highcopy >>= 1;
7625 * We use 31 bits not 32 here as POSIX
7626 * lock offsets may not be negative.
7629 mask = (~0) << (31 - i);
7631 if(low & mask)
7632 return 0; /* Fail. */
7634 high <<= (31 - i);
7636 return (high|low);
7638 #endif /* !defined(HAVE_LONGLONG) */
7640 /****************************************************************************
7641 Get a lock offset, dealing with large offset requests.
7642 ****************************************************************************/
7644 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7645 bool large_file_format, bool *err)
7647 uint64_t offset = 0;
7649 *err = False;
7651 if(!large_file_format) {
7652 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7653 } else {
7655 #if defined(HAVE_LONGLONG)
7656 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7657 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7658 #else /* HAVE_LONGLONG */
7661 * NT4.x seems to be broken in that it sends large file (64 bit)
7662 * lockingX calls even if the CAP_LARGE_FILES was *not*
7663 * negotiated. For boxes without large unsigned ints mangle the
7664 * lock offset by mapping the top 32 bits onto the lower 32.
7667 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7668 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7669 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7670 uint32 new_low = 0;
7672 if((new_low = map_lock_offset(high, low)) == 0) {
7673 *err = True;
7674 return (uint64_t)-1;
7677 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7678 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7679 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7680 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7683 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7684 #endif /* HAVE_LONGLONG */
7687 return offset;
7690 NTSTATUS smbd_do_locking(struct smb_request *req,
7691 files_struct *fsp,
7692 uint8_t type,
7693 int32_t timeout,
7694 uint16_t num_ulocks,
7695 struct smbd_lock_element *ulocks,
7696 uint16_t num_locks,
7697 struct smbd_lock_element *locks,
7698 bool *async)
7700 connection_struct *conn = req->conn;
7701 int i;
7702 NTSTATUS status = NT_STATUS_OK;
7704 *async = false;
7706 /* Data now points at the beginning of the list
7707 of smb_unlkrng structs */
7708 for(i = 0; i < (int)num_ulocks; i++) {
7709 struct smbd_lock_element *e = &ulocks[i];
7711 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7712 "pid %u, file %s\n",
7713 (double)e->offset,
7714 (double)e->count,
7715 (unsigned int)e->smblctx,
7716 fsp_str_dbg(fsp)));
7718 if (e->brltype != UNLOCK_LOCK) {
7719 /* this can only happen with SMB2 */
7720 return NT_STATUS_INVALID_PARAMETER;
7723 status = do_unlock(req->sconn->msg_ctx,
7724 fsp,
7725 e->smblctx,
7726 e->count,
7727 e->offset,
7728 WINDOWS_LOCK);
7730 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7731 nt_errstr(status)));
7733 if (!NT_STATUS_IS_OK(status)) {
7734 return status;
7738 /* Setup the timeout in seconds. */
7740 if (!lp_blocking_locks(SNUM(conn))) {
7741 timeout = 0;
7744 /* Data now points at the beginning of the list
7745 of smb_lkrng structs */
7747 for(i = 0; i < (int)num_locks; i++) {
7748 struct smbd_lock_element *e = &locks[i];
7750 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7751 "%llu, file %s timeout = %d\n",
7752 (double)e->offset,
7753 (double)e->count,
7754 (unsigned long long)e->smblctx,
7755 fsp_str_dbg(fsp),
7756 (int)timeout));
7758 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7759 struct blocking_lock_record *blr = NULL;
7761 if (num_locks > 1) {
7763 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7764 * if the lock vector contains one entry. When given mutliple cancel
7765 * requests in a single PDU we expect the server to return an
7766 * error. Windows servers seem to accept the request but only
7767 * cancel the first lock.
7768 * JRA - Do what Windows does (tm) :-).
7771 #if 0
7772 /* MS-CIFS (2.2.4.32.1) behavior. */
7773 return NT_STATUS_DOS(ERRDOS,
7774 ERRcancelviolation);
7775 #else
7776 /* Windows behavior. */
7777 if (i != 0) {
7778 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7779 "cancel request\n"));
7780 continue;
7782 #endif
7785 if (lp_blocking_locks(SNUM(conn))) {
7787 /* Schedule a message to ourselves to
7788 remove the blocking lock record and
7789 return the right error. */
7791 blr = blocking_lock_cancel_smb1(fsp,
7792 e->smblctx,
7793 e->offset,
7794 e->count,
7795 WINDOWS_LOCK,
7796 type,
7797 NT_STATUS_FILE_LOCK_CONFLICT);
7798 if (blr == NULL) {
7799 return NT_STATUS_DOS(
7800 ERRDOS,
7801 ERRcancelviolation);
7804 /* Remove a matching pending lock. */
7805 status = do_lock_cancel(fsp,
7806 e->smblctx,
7807 e->count,
7808 e->offset,
7809 WINDOWS_LOCK,
7810 blr);
7811 } else {
7812 bool blocking_lock = timeout ? true : false;
7813 bool defer_lock = false;
7814 struct byte_range_lock *br_lck;
7815 uint64_t block_smblctx;
7817 br_lck = do_lock(req->sconn->msg_ctx,
7818 fsp,
7819 e->smblctx,
7820 e->count,
7821 e->offset,
7822 e->brltype,
7823 WINDOWS_LOCK,
7824 blocking_lock,
7825 &status,
7826 &block_smblctx,
7827 NULL);
7829 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7830 /* Windows internal resolution for blocking locks seems
7831 to be about 200ms... Don't wait for less than that. JRA. */
7832 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7833 timeout = lp_lock_spin_time();
7835 defer_lock = true;
7838 /* If a lock sent with timeout of zero would fail, and
7839 * this lock has been requested multiple times,
7840 * according to brl_lock_failed() we convert this
7841 * request to a blocking lock with a timeout of between
7842 * 150 - 300 milliseconds.
7844 * If lp_lock_spin_time() has been set to 0, we skip
7845 * this blocking retry and fail immediately.
7847 * Replacement for do_lock_spin(). JRA. */
7849 if (!req->sconn->using_smb2 &&
7850 br_lck && lp_blocking_locks(SNUM(conn)) &&
7851 lp_lock_spin_time() && !blocking_lock &&
7852 NT_STATUS_EQUAL((status),
7853 NT_STATUS_FILE_LOCK_CONFLICT))
7855 defer_lock = true;
7856 timeout = lp_lock_spin_time();
7859 if (br_lck && defer_lock) {
7861 * A blocking lock was requested. Package up
7862 * this smb into a queued request and push it
7863 * onto the blocking lock queue.
7865 if(push_blocking_lock_request(br_lck,
7866 req,
7867 fsp,
7868 timeout,
7870 e->smblctx,
7871 e->brltype,
7872 WINDOWS_LOCK,
7873 e->offset,
7874 e->count,
7875 block_smblctx)) {
7876 TALLOC_FREE(br_lck);
7877 *async = true;
7878 return NT_STATUS_OK;
7882 TALLOC_FREE(br_lck);
7885 if (!NT_STATUS_IS_OK(status)) {
7886 break;
7890 /* If any of the above locks failed, then we must unlock
7891 all of the previous locks (X/Open spec). */
7893 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7895 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7896 i = -1; /* we want to skip the for loop */
7900 * Ensure we don't do a remove on the lock that just failed,
7901 * as under POSIX rules, if we have a lock already there, we
7902 * will delete it (and we shouldn't) .....
7904 for(i--; i >= 0; i--) {
7905 struct smbd_lock_element *e = &locks[i];
7907 do_unlock(req->sconn->msg_ctx,
7908 fsp,
7909 e->smblctx,
7910 e->count,
7911 e->offset,
7912 WINDOWS_LOCK);
7914 return status;
7917 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7918 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7920 return NT_STATUS_OK;
7923 /****************************************************************************
7924 Reply to a lockingX request.
7925 ****************************************************************************/
7927 void reply_lockingX(struct smb_request *req)
7929 connection_struct *conn = req->conn;
7930 files_struct *fsp;
7931 unsigned char locktype;
7932 unsigned char oplocklevel;
7933 uint16 num_ulocks;
7934 uint16 num_locks;
7935 int32 lock_timeout;
7936 int i;
7937 const uint8_t *data;
7938 bool large_file_format;
7939 bool err;
7940 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7941 struct smbd_lock_element *ulocks;
7942 struct smbd_lock_element *locks;
7943 bool async = false;
7945 START_PROFILE(SMBlockingX);
7947 if (req->wct < 8) {
7948 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7949 END_PROFILE(SMBlockingX);
7950 return;
7953 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7954 locktype = CVAL(req->vwv+3, 0);
7955 oplocklevel = CVAL(req->vwv+3, 1);
7956 num_ulocks = SVAL(req->vwv+6, 0);
7957 num_locks = SVAL(req->vwv+7, 0);
7958 lock_timeout = IVAL(req->vwv+4, 0);
7959 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7961 if (!check_fsp(conn, req, fsp)) {
7962 END_PROFILE(SMBlockingX);
7963 return;
7966 data = req->buf;
7968 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7969 /* we don't support these - and CANCEL_LOCK makes w2k
7970 and XP reboot so I don't really want to be
7971 compatible! (tridge) */
7972 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7973 END_PROFILE(SMBlockingX);
7974 return;
7977 /* Check if this is an oplock break on a file
7978 we have granted an oplock on.
7980 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7981 /* Client can insist on breaking to none. */
7982 bool break_to_none = (oplocklevel == 0);
7983 bool result;
7985 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7986 "for %s\n", (unsigned int)oplocklevel,
7987 fsp_fnum_dbg(fsp)));
7990 * Make sure we have granted an exclusive or batch oplock on
7991 * this file.
7994 if (fsp->oplock_type == 0) {
7996 /* The Samba4 nbench simulator doesn't understand
7997 the difference between break to level2 and break
7998 to none from level2 - it sends oplock break
7999 replies in both cases. Don't keep logging an error
8000 message here - just ignore it. JRA. */
8002 DEBUG(5,("reply_lockingX: Error : oplock break from "
8003 "client for %s (oplock=%d) and no "
8004 "oplock granted on this file (%s).\n",
8005 fsp_fnum_dbg(fsp), fsp->oplock_type,
8006 fsp_str_dbg(fsp)));
8008 /* if this is a pure oplock break request then don't
8009 * send a reply */
8010 if (num_locks == 0 && num_ulocks == 0) {
8011 END_PROFILE(SMBlockingX);
8012 return;
8013 } else {
8014 END_PROFILE(SMBlockingX);
8015 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8016 return;
8020 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8021 (break_to_none)) {
8022 result = remove_oplock(fsp);
8023 } else {
8024 result = downgrade_oplock(fsp);
8027 if (!result) {
8028 DEBUG(0, ("reply_lockingX: error in removing "
8029 "oplock on file %s\n", fsp_str_dbg(fsp)));
8030 /* Hmmm. Is this panic justified? */
8031 smb_panic("internal tdb error");
8034 /* if this is a pure oplock break request then don't send a
8035 * reply */
8036 if (num_locks == 0 && num_ulocks == 0) {
8037 /* Sanity check - ensure a pure oplock break is not a
8038 chained request. */
8039 if(CVAL(req->vwv+0, 0) != 0xff)
8040 DEBUG(0,("reply_lockingX: Error : pure oplock "
8041 "break is a chained %d request !\n",
8042 (unsigned int)CVAL(req->vwv+0, 0)));
8043 END_PROFILE(SMBlockingX);
8044 return;
8048 if (req->buflen <
8049 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8050 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8051 END_PROFILE(SMBlockingX);
8052 return;
8055 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8056 if (ulocks == NULL) {
8057 reply_nterror(req, NT_STATUS_NO_MEMORY);
8058 END_PROFILE(SMBlockingX);
8059 return;
8062 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8063 if (locks == NULL) {
8064 reply_nterror(req, NT_STATUS_NO_MEMORY);
8065 END_PROFILE(SMBlockingX);
8066 return;
8069 /* Data now points at the beginning of the list
8070 of smb_unlkrng structs */
8071 for(i = 0; i < (int)num_ulocks; i++) {
8072 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8073 ulocks[i].count = get_lock_count(data, i, large_file_format);
8074 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8075 ulocks[i].brltype = UNLOCK_LOCK;
8078 * There is no error code marked "stupid client bug".... :-).
8080 if(err) {
8081 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8082 END_PROFILE(SMBlockingX);
8083 return;
8087 /* Now do any requested locks */
8088 data += ((large_file_format ? 20 : 10)*num_ulocks);
8090 /* Data now points at the beginning of the list
8091 of smb_lkrng structs */
8093 for(i = 0; i < (int)num_locks; i++) {
8094 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8095 locks[i].count = get_lock_count(data, i, large_file_format);
8096 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8098 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8099 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8100 locks[i].brltype = PENDING_READ_LOCK;
8101 } else {
8102 locks[i].brltype = READ_LOCK;
8104 } else {
8105 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8106 locks[i].brltype = PENDING_WRITE_LOCK;
8107 } else {
8108 locks[i].brltype = WRITE_LOCK;
8113 * There is no error code marked "stupid client bug".... :-).
8115 if(err) {
8116 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8117 END_PROFILE(SMBlockingX);
8118 return;
8122 status = smbd_do_locking(req, fsp,
8123 locktype, lock_timeout,
8124 num_ulocks, ulocks,
8125 num_locks, locks,
8126 &async);
8127 if (!NT_STATUS_IS_OK(status)) {
8128 END_PROFILE(SMBlockingX);
8129 reply_nterror(req, status);
8130 return;
8132 if (async) {
8133 END_PROFILE(SMBlockingX);
8134 return;
8137 reply_outbuf(req, 2, 0);
8138 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8139 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8141 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8142 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8144 END_PROFILE(SMBlockingX);
8147 #undef DBGC_CLASS
8148 #define DBGC_CLASS DBGC_ALL
8150 /****************************************************************************
8151 Reply to a SMBreadbmpx (read block multiplex) request.
8152 Always reply with an error, if someone has a platform really needs this,
8153 please contact vl@samba.org
8154 ****************************************************************************/
8156 void reply_readbmpx(struct smb_request *req)
8158 START_PROFILE(SMBreadBmpx);
8159 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8160 END_PROFILE(SMBreadBmpx);
8161 return;
8164 /****************************************************************************
8165 Reply to a SMBreadbs (read block multiplex secondary) request.
8166 Always reply with an error, if someone has a platform really needs this,
8167 please contact vl@samba.org
8168 ****************************************************************************/
8170 void reply_readbs(struct smb_request *req)
8172 START_PROFILE(SMBreadBs);
8173 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8174 END_PROFILE(SMBreadBs);
8175 return;
8178 /****************************************************************************
8179 Reply to a SMBsetattrE.
8180 ****************************************************************************/
8182 void reply_setattrE(struct smb_request *req)
8184 connection_struct *conn = req->conn;
8185 struct smb_file_time ft;
8186 files_struct *fsp;
8187 NTSTATUS status;
8189 START_PROFILE(SMBsetattrE);
8190 ZERO_STRUCT(ft);
8192 if (req->wct < 7) {
8193 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8194 goto out;
8197 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8199 if(!fsp || (fsp->conn != conn)) {
8200 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8201 goto out;
8205 * Convert the DOS times into unix times.
8208 ft.atime = convert_time_t_to_timespec(
8209 srv_make_unix_date2(req->vwv+3));
8210 ft.mtime = convert_time_t_to_timespec(
8211 srv_make_unix_date2(req->vwv+5));
8212 ft.create_time = convert_time_t_to_timespec(
8213 srv_make_unix_date2(req->vwv+1));
8215 reply_outbuf(req, 0, 0);
8218 * Patch from Ray Frush <frush@engr.colostate.edu>
8219 * Sometimes times are sent as zero - ignore them.
8222 /* Ensure we have a valid stat struct for the source. */
8223 status = vfs_stat_fsp(fsp);
8224 if (!NT_STATUS_IS_OK(status)) {
8225 reply_nterror(req, status);
8226 goto out;
8229 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8230 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8231 goto out;
8234 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8235 if (!NT_STATUS_IS_OK(status)) {
8236 reply_nterror(req, status);
8237 goto out;
8240 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8241 " createtime=%u\n",
8242 fsp_fnum_dbg(fsp),
8243 (unsigned int)ft.atime.tv_sec,
8244 (unsigned int)ft.mtime.tv_sec,
8245 (unsigned int)ft.create_time.tv_sec
8247 out:
8248 END_PROFILE(SMBsetattrE);
8249 return;
8253 /* Back from the dead for OS/2..... JRA. */
8255 /****************************************************************************
8256 Reply to a SMBwritebmpx (write block multiplex primary) request.
8257 Always reply with an error, if someone has a platform really needs this,
8258 please contact vl@samba.org
8259 ****************************************************************************/
8261 void reply_writebmpx(struct smb_request *req)
8263 START_PROFILE(SMBwriteBmpx);
8264 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8265 END_PROFILE(SMBwriteBmpx);
8266 return;
8269 /****************************************************************************
8270 Reply to a SMBwritebs (write block multiplex secondary) request.
8271 Always reply with an error, if someone has a platform really needs this,
8272 please contact vl@samba.org
8273 ****************************************************************************/
8275 void reply_writebs(struct smb_request *req)
8277 START_PROFILE(SMBwriteBs);
8278 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8279 END_PROFILE(SMBwriteBs);
8280 return;
8283 /****************************************************************************
8284 Reply to a SMBgetattrE.
8285 ****************************************************************************/
8287 void reply_getattrE(struct smb_request *req)
8289 connection_struct *conn = req->conn;
8290 int mode;
8291 files_struct *fsp;
8292 struct timespec create_ts;
8294 START_PROFILE(SMBgetattrE);
8296 if (req->wct < 1) {
8297 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8298 END_PROFILE(SMBgetattrE);
8299 return;
8302 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8304 if(!fsp || (fsp->conn != conn)) {
8305 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8306 END_PROFILE(SMBgetattrE);
8307 return;
8310 /* Do an fstat on this file */
8311 if(fsp_stat(fsp)) {
8312 reply_nterror(req, map_nt_error_from_unix(errno));
8313 END_PROFILE(SMBgetattrE);
8314 return;
8317 mode = dos_mode(conn, fsp->fsp_name);
8320 * Convert the times into dos times. Set create
8321 * date to be last modify date as UNIX doesn't save
8322 * this.
8325 reply_outbuf(req, 11, 0);
8327 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8328 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8329 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8330 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8331 /* Should we check pending modtime here ? JRA */
8332 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8333 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8335 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8336 SIVAL(req->outbuf, smb_vwv6, 0);
8337 SIVAL(req->outbuf, smb_vwv8, 0);
8338 } else {
8339 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8340 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8341 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8343 SSVAL(req->outbuf,smb_vwv10, mode);
8345 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8347 END_PROFILE(SMBgetattrE);
8348 return;