s3: Move the drain_socket on error to reply_write_and_X
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blobe3a3766239abd3dc40767bb199c5fbfdab16b9b0
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"
45 /****************************************************************************
46 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
47 path or anything including wildcards.
48 We're assuming here that '/' is not the second byte in any multibyte char
49 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
50 set.
51 ****************************************************************************/
53 /* Custom version for processing POSIX paths. */
54 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
56 static NTSTATUS check_path_syntax_internal(char *path,
57 bool posix_path,
58 bool *p_last_component_contains_wcard)
60 char *d = path;
61 const char *s = path;
62 NTSTATUS ret = NT_STATUS_OK;
63 bool start_of_name_component = True;
64 bool stream_started = false;
66 *p_last_component_contains_wcard = False;
68 while (*s) {
69 if (stream_started) {
70 switch (*s) {
71 case '/':
72 case '\\':
73 return NT_STATUS_OBJECT_NAME_INVALID;
74 case ':':
75 if (s[1] == '\0') {
76 return NT_STATUS_OBJECT_NAME_INVALID;
78 if (strchr_m(&s[1], ':')) {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 break;
85 if ((*s == ':') && !posix_path && !stream_started) {
86 if (*p_last_component_contains_wcard) {
87 return NT_STATUS_OBJECT_NAME_INVALID;
89 /* Stream names allow more characters than file names.
90 We're overloading posix_path here to allow a wider
91 range of characters. If stream_started is true this
92 is still a Windows path even if posix_path is true.
93 JRA.
95 stream_started = true;
96 start_of_name_component = false;
97 posix_path = true;
99 if (s[1] == '\0') {
100 return NT_STATUS_OBJECT_NAME_INVALID;
104 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
106 * Safe to assume is not the second part of a mb char
107 * as this is handled below.
109 /* Eat multiple '/' or '\\' */
110 while (IS_PATH_SEP(*s,posix_path)) {
111 s++;
113 if ((d != path) && (*s != '\0')) {
114 /* We only care about non-leading or trailing '/' or '\\' */
115 *d++ = '/';
118 start_of_name_component = True;
119 /* New component. */
120 *p_last_component_contains_wcard = False;
121 continue;
124 if (start_of_name_component) {
125 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
126 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
129 * No mb char starts with '.' so we're safe checking the directory separator here.
132 /* If we just added a '/' - delete it */
133 if ((d > path) && (*(d-1) == '/')) {
134 *(d-1) = '\0';
135 d--;
138 /* Are we at the start ? Can't go back further if so. */
139 if (d <= path) {
140 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
141 break;
143 /* Go back one level... */
144 /* We know this is safe as '/' cannot be part of a mb sequence. */
145 /* NOTE - if this assumption is invalid we are not in good shape... */
146 /* Decrement d first as d points to the *next* char to write into. */
147 for (d--; d > path; d--) {
148 if (*d == '/')
149 break;
151 s += 2; /* Else go past the .. */
152 /* We're still at the start of a name component, just the previous one. */
153 continue;
155 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
156 if (posix_path) {
157 /* Eat the '.' */
158 s++;
159 continue;
165 if (!(*s & 0x80)) {
166 if (!posix_path) {
167 if (*s <= 0x1f || *s == '|') {
168 return NT_STATUS_OBJECT_NAME_INVALID;
170 switch (*s) {
171 case '*':
172 case '?':
173 case '<':
174 case '>':
175 case '"':
176 *p_last_component_contains_wcard = True;
177 break;
178 default:
179 break;
182 *d++ = *s++;
183 } else {
184 size_t siz;
185 /* Get the size of the next MB character. */
186 next_codepoint(s,&siz);
187 switch(siz) {
188 case 5:
189 *d++ = *s++;
190 /*fall through*/
191 case 4:
192 *d++ = *s++;
193 /*fall through*/
194 case 3:
195 *d++ = *s++;
196 /*fall through*/
197 case 2:
198 *d++ = *s++;
199 /*fall through*/
200 case 1:
201 *d++ = *s++;
202 break;
203 default:
204 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
205 *d = '\0';
206 return NT_STATUS_INVALID_PARAMETER;
209 start_of_name_component = False;
212 *d = '\0';
214 return ret;
217 /****************************************************************************
218 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
219 No wildcards allowed.
220 ****************************************************************************/
222 NTSTATUS check_path_syntax(char *path)
224 bool ignore;
225 return check_path_syntax_internal(path, False, &ignore);
228 /****************************************************************************
229 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
230 Wildcards allowed - p_contains_wcard returns true if the last component contained
231 a wildcard.
232 ****************************************************************************/
234 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
236 return check_path_syntax_internal(path, False, p_contains_wcard);
239 /****************************************************************************
240 Check the path for a POSIX client.
241 We're assuming here that '/' is not the second byte in any multibyte char
242 set (a safe assumption).
243 ****************************************************************************/
245 NTSTATUS check_path_syntax_posix(char *path)
247 bool ignore;
248 return check_path_syntax_internal(path, True, &ignore);
251 /****************************************************************************
252 Pull a string and check the path allowing a wilcard - provide for error return.
253 ****************************************************************************/
255 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
256 const char *base_ptr,
257 uint16 smb_flags2,
258 char **pp_dest,
259 const char *src,
260 size_t src_len,
261 int flags,
262 NTSTATUS *err,
263 bool *contains_wcard)
265 size_t ret;
267 *pp_dest = NULL;
269 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
270 src_len, flags);
272 if (!*pp_dest) {
273 *err = NT_STATUS_INVALID_PARAMETER;
274 return ret;
277 *contains_wcard = False;
279 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
281 * For a DFS path the function parse_dfs_path()
282 * will do the path processing, just make a copy.
284 *err = NT_STATUS_OK;
285 return ret;
288 if (lp_posix_pathnames()) {
289 *err = check_path_syntax_posix(*pp_dest);
290 } else {
291 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
294 return ret;
297 /****************************************************************************
298 Pull a string and check the path - provide for error return.
299 ****************************************************************************/
301 size_t srvstr_get_path(TALLOC_CTX *ctx,
302 const char *base_ptr,
303 uint16 smb_flags2,
304 char **pp_dest,
305 const char *src,
306 size_t src_len,
307 int flags,
308 NTSTATUS *err)
310 bool ignore;
311 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
312 src_len, flags, err, &ignore);
315 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
316 char **pp_dest, const char *src, int flags,
317 NTSTATUS *err, bool *contains_wcard)
319 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
320 pp_dest, src, smbreq_bufrem(req, src),
321 flags, err, contains_wcard);
324 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
325 char **pp_dest, const char *src, int flags,
326 NTSTATUS *err)
328 bool ignore;
329 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
330 flags, err, &ignore);
333 /****************************************************************************
334 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
335 ****************************************************************************/
337 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
338 files_struct *fsp)
340 if ((fsp == NULL) || (conn == NULL)) {
341 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
342 return False;
344 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
345 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
346 return False;
348 return True;
351 /****************************************************************************
352 Check if we have a correct fsp pointing to a file.
353 ****************************************************************************/
355 bool check_fsp(connection_struct *conn, struct smb_request *req,
356 files_struct *fsp)
358 if (!check_fsp_open(conn, req, fsp)) {
359 return False;
361 if (fsp->is_directory) {
362 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
363 return False;
365 if (fsp->fh->fd == -1) {
366 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
367 return False;
369 fsp->num_smb_operations++;
370 return True;
373 /****************************************************************************
374 Check if we have a correct fsp pointing to a quota fake file. Replacement for
375 the CHECK_NTQUOTA_HANDLE_OK macro.
376 ****************************************************************************/
378 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
379 files_struct *fsp)
381 if (!check_fsp_open(conn, req, fsp)) {
382 return false;
385 if (fsp->is_directory) {
386 return false;
389 if (fsp->fake_file_handle == NULL) {
390 return false;
393 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
394 return false;
397 if (fsp->fake_file_handle->private_data == NULL) {
398 return false;
401 return true;
404 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
405 const char *name, int name_type)
407 char *trim_name;
408 char *trim_name_type;
409 const char *retarget_parm;
410 char *retarget;
411 char *p;
412 int retarget_type = 0x20;
413 int retarget_port = NBT_SMB_PORT;
414 struct sockaddr_storage retarget_addr;
415 struct sockaddr_in *in_addr;
416 bool ret = false;
417 uint8_t outbuf[10];
419 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
420 return false;
423 trim_name = talloc_strdup(talloc_tos(), name);
424 if (trim_name == NULL) {
425 goto fail;
427 trim_char(trim_name, ' ', ' ');
429 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
430 name_type);
431 if (trim_name_type == NULL) {
432 goto fail;
435 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
436 trim_name_type, NULL);
437 if (retarget_parm == NULL) {
438 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
439 trim_name, NULL);
441 if (retarget_parm == NULL) {
442 goto fail;
445 retarget = talloc_strdup(trim_name, retarget_parm);
446 if (retarget == NULL) {
447 goto fail;
450 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
452 p = strchr(retarget, ':');
453 if (p != NULL) {
454 *p++ = '\0';
455 retarget_port = atoi(p);
458 p = strchr_m(retarget, '#');
459 if (p != NULL) {
460 *p++ = '\0';
461 if (sscanf(p, "%x", &retarget_type) != 1) {
462 goto fail;
466 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
467 if (!ret) {
468 DEBUG(10, ("could not resolve %s\n", retarget));
469 goto fail;
472 if (retarget_addr.ss_family != AF_INET) {
473 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
474 goto fail;
477 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
479 _smb_setlen(outbuf, 6);
480 SCVAL(outbuf, 0, 0x84);
481 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
482 *(uint16_t *)(outbuf+8) = htons(retarget_port);
484 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
485 NULL)) {
486 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
487 "failed.");
490 ret = true;
491 fail:
492 TALLOC_FREE(trim_name);
493 return ret;
496 static void reply_called_name_not_present(char *outbuf)
498 smb_setlen(outbuf, 1);
499 SCVAL(outbuf, 0, 0x83);
500 SCVAL(outbuf, 4, 0x82);
503 /****************************************************************************
504 Reply to a (netbios-level) special message.
505 ****************************************************************************/
507 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
509 int msg_type = CVAL(inbuf,0);
510 int msg_flags = CVAL(inbuf,1);
512 * We only really use 4 bytes of the outbuf, but for the smb_setlen
513 * calculation & friends (srv_send_smb uses that) we need the full smb
514 * header.
516 char outbuf[smb_size];
518 memset(outbuf, '\0', sizeof(outbuf));
520 smb_setlen(outbuf,0);
522 switch (msg_type) {
523 case NBSSrequest: /* session request */
525 /* inbuf_size is guarenteed to be at least 4. */
526 fstring name1,name2;
527 int name_type1, name_type2;
528 int name_len1, name_len2;
530 *name1 = *name2 = 0;
532 if (sconn->nbt.got_session) {
533 exit_server_cleanly("multiple session request not permitted");
536 SCVAL(outbuf,0,NBSSpositive);
537 SCVAL(outbuf,3,0);
539 /* inbuf_size is guaranteed to be at least 4. */
540 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
541 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
542 DEBUG(0,("Invalid name length in session request\n"));
543 reply_called_name_not_present(outbuf);
544 break;
546 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
547 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
548 DEBUG(0,("Invalid name length in session request\n"));
549 reply_called_name_not_present(outbuf);
550 break;
553 name_type1 = name_extract((unsigned char *)inbuf,
554 inbuf_size,(unsigned int)4,name1);
555 name_type2 = name_extract((unsigned char *)inbuf,
556 inbuf_size,(unsigned int)(4 + name_len1),name2);
558 if (name_type1 == -1 || name_type2 == -1) {
559 DEBUG(0,("Invalid name type in session request\n"));
560 reply_called_name_not_present(outbuf);
561 break;
564 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
565 name1, name_type1, name2, name_type2));
567 if (netbios_session_retarget(sconn, name1, name_type1)) {
568 exit_server_cleanly("retargeted client");
572 * Windows NT/2k uses "*SMBSERVER" and XP uses
573 * "*SMBSERV" arrggg!!!
575 if (strequal(name1, "*SMBSERVER ")
576 || strequal(name1, "*SMBSERV ")) {
577 char *raddr;
579 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
580 talloc_tos());
581 if (raddr == NULL) {
582 exit_server_cleanly("could not allocate raddr");
585 fstrcpy(name1, raddr);
588 set_local_machine_name(name1, True);
589 set_remote_machine_name(name2, True);
591 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
592 get_local_machine_name(), get_remote_machine_name(),
593 name_type2));
595 if (name_type2 == 'R') {
596 /* We are being asked for a pathworks session ---
597 no thanks! */
598 reply_called_name_not_present(outbuf);
599 break;
602 reload_services(sconn, conn_snum_used, true);
603 reopen_logs();
605 sconn->nbt.got_session = true;
606 break;
609 case 0x89: /* session keepalive request
610 (some old clients produce this?) */
611 SCVAL(outbuf,0,NBSSkeepalive);
612 SCVAL(outbuf,3,0);
613 break;
615 case NBSSpositive: /* positive session response */
616 case NBSSnegative: /* negative session response */
617 case NBSSretarget: /* retarget session response */
618 DEBUG(0,("Unexpected session response\n"));
619 break;
621 case NBSSkeepalive: /* session keepalive */
622 default:
623 return;
626 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
627 msg_type, msg_flags));
629 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
631 if (CVAL(outbuf, 0) != 0x82) {
632 exit_server_cleanly("invalid netbios session");
634 return;
637 /****************************************************************************
638 Reply to a tcon.
639 conn POINTER CAN BE NULL HERE !
640 ****************************************************************************/
642 void reply_tcon(struct smb_request *req)
644 connection_struct *conn = req->conn;
645 const char *service;
646 char *service_buf = NULL;
647 char *password = NULL;
648 char *dev = NULL;
649 int pwlen=0;
650 NTSTATUS nt_status;
651 const char *p;
652 TALLOC_CTX *ctx = talloc_tos();
653 struct smbd_server_connection *sconn = req->sconn;
655 START_PROFILE(SMBtcon);
657 if (req->buflen < 4) {
658 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
659 END_PROFILE(SMBtcon);
660 return;
663 p = (const char *)req->buf + 1;
664 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
665 p += 1;
666 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
667 p += pwlen+1;
668 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
669 p += 1;
671 if (service_buf == NULL || password == NULL || dev == NULL) {
672 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
673 END_PROFILE(SMBtcon);
674 return;
676 p = strrchr_m(service_buf,'\\');
677 if (p) {
678 service = p+1;
679 } else {
680 service = service_buf;
683 conn = make_connection(sconn,service,dev,
684 req->vuid,&nt_status);
685 req->conn = conn;
687 if (!conn) {
688 reply_nterror(req, nt_status);
689 END_PROFILE(SMBtcon);
690 return;
693 reply_outbuf(req, 2, 0);
694 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
695 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
696 SSVAL(req->outbuf,smb_tid,conn->cnum);
698 DEBUG(3,("tcon service=%s cnum=%d\n",
699 service, conn->cnum));
701 END_PROFILE(SMBtcon);
702 return;
705 /****************************************************************************
706 Reply to a tcon and X.
707 conn POINTER CAN BE NULL HERE !
708 ****************************************************************************/
710 void reply_tcon_and_X(struct smb_request *req)
712 connection_struct *conn = req->conn;
713 const char *service = NULL;
714 TALLOC_CTX *ctx = talloc_tos();
715 /* what the cleint thinks the device is */
716 char *client_devicetype = NULL;
717 /* what the server tells the client the share represents */
718 const char *server_devicetype;
719 NTSTATUS nt_status;
720 int passlen;
721 char *path = NULL;
722 const char *p, *q;
723 uint16 tcon_flags;
724 struct smbd_server_connection *sconn = req->sconn;
726 START_PROFILE(SMBtconX);
728 if (req->wct < 4) {
729 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
730 END_PROFILE(SMBtconX);
731 return;
734 passlen = SVAL(req->vwv+3, 0);
735 tcon_flags = SVAL(req->vwv+2, 0);
737 /* we might have to close an old one */
738 if ((tcon_flags & 0x1) && conn) {
739 close_cnum(conn,req->vuid);
740 req->conn = NULL;
741 conn = NULL;
744 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
745 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
746 END_PROFILE(SMBtconX);
747 return;
750 if (sconn->smb1.negprot.encrypted_passwords) {
751 p = (const char *)req->buf + passlen;
752 } else {
753 p = (const char *)req->buf + passlen + 1;
756 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
758 if (path == NULL) {
759 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
760 END_PROFILE(SMBtconX);
761 return;
765 * the service name can be either: \\server\share
766 * or share directly like on the DELL PowerVault 705
768 if (*path=='\\') {
769 q = strchr_m(path+2,'\\');
770 if (!q) {
771 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
772 END_PROFILE(SMBtconX);
773 return;
775 service = q+1;
776 } else {
777 service = path;
780 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
781 &client_devicetype, p,
782 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
784 if (client_devicetype == NULL) {
785 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
786 END_PROFILE(SMBtconX);
787 return;
790 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
792 conn = make_connection(sconn, service, client_devicetype,
793 req->vuid, &nt_status);
794 req->conn =conn;
796 if (!conn) {
797 reply_nterror(req, nt_status);
798 END_PROFILE(SMBtconX);
799 return;
802 if ( IS_IPC(conn) )
803 server_devicetype = "IPC";
804 else if ( IS_PRINT(conn) )
805 server_devicetype = "LPT1:";
806 else
807 server_devicetype = "A:";
809 if (get_Protocol() < PROTOCOL_NT1) {
810 reply_outbuf(req, 2, 0);
811 if (message_push_string(&req->outbuf, server_devicetype,
812 STR_TERMINATE|STR_ASCII) == -1) {
813 reply_nterror(req, NT_STATUS_NO_MEMORY);
814 END_PROFILE(SMBtconX);
815 return;
817 } else {
818 /* NT sets the fstype of IPC$ to the null string */
819 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
821 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
822 /* Return permissions. */
823 uint32 perm1 = 0;
824 uint32 perm2 = 0;
826 reply_outbuf(req, 7, 0);
828 if (IS_IPC(conn)) {
829 perm1 = FILE_ALL_ACCESS;
830 perm2 = FILE_ALL_ACCESS;
831 } else {
832 perm1 = conn->share_access;
835 SIVAL(req->outbuf, smb_vwv3, perm1);
836 SIVAL(req->outbuf, smb_vwv5, perm2);
837 } else {
838 reply_outbuf(req, 3, 0);
841 if ((message_push_string(&req->outbuf, server_devicetype,
842 STR_TERMINATE|STR_ASCII) == -1)
843 || (message_push_string(&req->outbuf, fstype,
844 STR_TERMINATE) == -1)) {
845 reply_nterror(req, NT_STATUS_NO_MEMORY);
846 END_PROFILE(SMBtconX);
847 return;
850 /* what does setting this bit do? It is set by NT4 and
851 may affect the ability to autorun mounted cdroms */
852 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
853 (lp_csc_policy(SNUM(conn)) << 2));
855 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
856 DEBUG(2,("Serving %s as a Dfs root\n",
857 lp_servicename(SNUM(conn)) ));
858 SSVAL(req->outbuf, smb_vwv2,
859 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
864 DEBUG(3,("tconX service=%s \n",
865 service));
867 /* set the incoming and outgoing tid to the just created one */
868 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
869 SSVAL(req->outbuf,smb_tid,conn->cnum);
871 END_PROFILE(SMBtconX);
873 req->tid = conn->cnum;
874 chain_reply(req);
875 return;
878 /****************************************************************************
879 Reply to an unknown type.
880 ****************************************************************************/
882 void reply_unknown_new(struct smb_request *req, uint8 type)
884 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
885 smb_fn_name(type), type, type));
886 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
887 return;
890 /****************************************************************************
891 Reply to an ioctl.
892 conn POINTER CAN BE NULL HERE !
893 ****************************************************************************/
895 void reply_ioctl(struct smb_request *req)
897 connection_struct *conn = req->conn;
898 uint16 device;
899 uint16 function;
900 uint32 ioctl_code;
901 int replysize;
902 char *p;
904 START_PROFILE(SMBioctl);
906 if (req->wct < 3) {
907 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
908 END_PROFILE(SMBioctl);
909 return;
912 device = SVAL(req->vwv+1, 0);
913 function = SVAL(req->vwv+2, 0);
914 ioctl_code = (device << 16) + function;
916 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
918 switch (ioctl_code) {
919 case IOCTL_QUERY_JOB_INFO:
920 replysize = 32;
921 break;
922 default:
923 reply_force_doserror(req, ERRSRV, ERRnosupport);
924 END_PROFILE(SMBioctl);
925 return;
928 reply_outbuf(req, 8, replysize+1);
929 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
930 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
931 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
932 p = smb_buf(req->outbuf);
933 memset(p, '\0', replysize+1); /* valgrind-safe. */
934 p += 1; /* Allow for alignment */
936 switch (ioctl_code) {
937 case IOCTL_QUERY_JOB_INFO:
939 files_struct *fsp = file_fsp(
940 req, SVAL(req->vwv+0, 0));
941 if (!fsp) {
942 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
943 END_PROFILE(SMBioctl);
944 return;
946 /* Job number */
947 if (fsp->print_file) {
948 SSVAL(p, 0, fsp->print_file->rap_jobid);
949 } else {
950 SSVAL(p, 0, 0);
952 srvstr_push((char *)req->outbuf, req->flags2, p+2,
953 lp_netbios_name(), 15,
954 STR_TERMINATE|STR_ASCII);
955 if (conn) {
956 srvstr_push((char *)req->outbuf, req->flags2,
957 p+18, lp_servicename(SNUM(conn)),
958 13, STR_TERMINATE|STR_ASCII);
959 } else {
960 memset(p+18, 0, 13);
962 break;
966 END_PROFILE(SMBioctl);
967 return;
970 /****************************************************************************
971 Strange checkpath NTSTATUS mapping.
972 ****************************************************************************/
974 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
976 /* Strange DOS error code semantics only for checkpath... */
977 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
978 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
979 /* We need to map to ERRbadpath */
980 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
983 return status;
986 /****************************************************************************
987 Reply to a checkpath.
988 ****************************************************************************/
990 void reply_checkpath(struct smb_request *req)
992 connection_struct *conn = req->conn;
993 struct smb_filename *smb_fname = NULL;
994 char *name = NULL;
995 NTSTATUS status;
996 TALLOC_CTX *ctx = talloc_tos();
998 START_PROFILE(SMBcheckpath);
1000 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1001 STR_TERMINATE, &status);
1003 if (!NT_STATUS_IS_OK(status)) {
1004 status = map_checkpath_error(req->flags2, status);
1005 reply_nterror(req, status);
1006 END_PROFILE(SMBcheckpath);
1007 return;
1010 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1012 status = filename_convert(ctx,
1013 conn,
1014 req->flags2 & FLAGS2_DFS_PATHNAMES,
1015 name,
1017 NULL,
1018 &smb_fname);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1022 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1023 ERRSRV, ERRbadpath);
1024 END_PROFILE(SMBcheckpath);
1025 return;
1027 goto path_err;
1030 if (!VALID_STAT(smb_fname->st) &&
1031 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1032 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1033 smb_fname_str_dbg(smb_fname), strerror(errno)));
1034 status = map_nt_error_from_unix(errno);
1035 goto path_err;
1038 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1039 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1040 ERRDOS, ERRbadpath);
1041 goto out;
1044 reply_outbuf(req, 0, 0);
1046 path_err:
1047 /* We special case this - as when a Windows machine
1048 is parsing a path is steps through the components
1049 one at a time - if a component fails it expects
1050 ERRbadpath, not ERRbadfile.
1052 status = map_checkpath_error(req->flags2, status);
1053 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1055 * Windows returns different error codes if
1056 * the parent directory is valid but not the
1057 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1058 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1059 * if the path is invalid.
1061 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1062 ERRDOS, ERRbadpath);
1063 goto out;
1066 reply_nterror(req, status);
1068 out:
1069 TALLOC_FREE(smb_fname);
1070 END_PROFILE(SMBcheckpath);
1071 return;
1074 /****************************************************************************
1075 Reply to a getatr.
1076 ****************************************************************************/
1078 void reply_getatr(struct smb_request *req)
1080 connection_struct *conn = req->conn;
1081 struct smb_filename *smb_fname = NULL;
1082 char *fname = NULL;
1083 int mode=0;
1084 SMB_OFF_T size=0;
1085 time_t mtime=0;
1086 const char *p;
1087 NTSTATUS status;
1088 TALLOC_CTX *ctx = talloc_tos();
1089 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1091 START_PROFILE(SMBgetatr);
1093 p = (const char *)req->buf + 1;
1094 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1095 if (!NT_STATUS_IS_OK(status)) {
1096 reply_nterror(req, status);
1097 goto out;
1100 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1101 under WfWg - weird! */
1102 if (*fname == '\0') {
1103 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1104 if (!CAN_WRITE(conn)) {
1105 mode |= FILE_ATTRIBUTE_READONLY;
1107 size = 0;
1108 mtime = 0;
1109 } else {
1110 status = filename_convert(ctx,
1111 conn,
1112 req->flags2 & FLAGS2_DFS_PATHNAMES,
1113 fname,
1115 NULL,
1116 &smb_fname);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1119 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1120 ERRSRV, ERRbadpath);
1121 goto out;
1123 reply_nterror(req, status);
1124 goto out;
1126 if (!VALID_STAT(smb_fname->st) &&
1127 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1128 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1129 smb_fname_str_dbg(smb_fname),
1130 strerror(errno)));
1131 reply_nterror(req, map_nt_error_from_unix(errno));
1132 goto out;
1135 mode = dos_mode(conn, smb_fname);
1136 size = smb_fname->st.st_ex_size;
1138 if (ask_sharemode) {
1139 struct timespec write_time_ts;
1140 struct file_id fileid;
1142 ZERO_STRUCT(write_time_ts);
1143 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1144 get_file_infos(fileid, 0, NULL, &write_time_ts);
1145 if (!null_timespec(write_time_ts)) {
1146 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1150 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1151 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1152 size = 0;
1156 reply_outbuf(req, 10, 0);
1158 SSVAL(req->outbuf,smb_vwv0,mode);
1159 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1160 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1161 } else {
1162 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1164 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1166 if (get_Protocol() >= PROTOCOL_NT1) {
1167 SSVAL(req->outbuf, smb_flg2,
1168 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1171 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1172 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1174 out:
1175 TALLOC_FREE(smb_fname);
1176 TALLOC_FREE(fname);
1177 END_PROFILE(SMBgetatr);
1178 return;
1181 /****************************************************************************
1182 Reply to a setatr.
1183 ****************************************************************************/
1185 void reply_setatr(struct smb_request *req)
1187 struct smb_file_time ft;
1188 connection_struct *conn = req->conn;
1189 struct smb_filename *smb_fname = NULL;
1190 char *fname = NULL;
1191 int mode;
1192 time_t mtime;
1193 const char *p;
1194 NTSTATUS status;
1195 TALLOC_CTX *ctx = talloc_tos();
1197 START_PROFILE(SMBsetatr);
1199 ZERO_STRUCT(ft);
1201 if (req->wct < 2) {
1202 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1203 goto out;
1206 p = (const char *)req->buf + 1;
1207 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1208 if (!NT_STATUS_IS_OK(status)) {
1209 reply_nterror(req, status);
1210 goto out;
1213 status = filename_convert(ctx,
1214 conn,
1215 req->flags2 & FLAGS2_DFS_PATHNAMES,
1216 fname,
1218 NULL,
1219 &smb_fname);
1220 if (!NT_STATUS_IS_OK(status)) {
1221 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1222 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1223 ERRSRV, ERRbadpath);
1224 goto out;
1226 reply_nterror(req, status);
1227 goto out;
1230 if (smb_fname->base_name[0] == '.' &&
1231 smb_fname->base_name[1] == '\0') {
1233 * Not sure here is the right place to catch this
1234 * condition. Might be moved to somewhere else later -- vl
1236 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1237 goto out;
1240 mode = SVAL(req->vwv+0, 0);
1241 mtime = srv_make_unix_date3(req->vwv+1);
1243 if (mode != FILE_ATTRIBUTE_NORMAL) {
1244 if (VALID_STAT_OF_DIR(smb_fname->st))
1245 mode |= FILE_ATTRIBUTE_DIRECTORY;
1246 else
1247 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1249 status = check_access(conn, NULL, smb_fname,
1250 FILE_WRITE_ATTRIBUTES);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 reply_nterror(req, status);
1253 goto out;
1256 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1257 false) != 0) {
1258 reply_nterror(req, map_nt_error_from_unix(errno));
1259 goto out;
1263 ft.mtime = convert_time_t_to_timespec(mtime);
1264 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 reply_nterror(req, status);
1267 goto out;
1270 reply_outbuf(req, 0, 0);
1272 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1273 mode));
1274 out:
1275 TALLOC_FREE(smb_fname);
1276 END_PROFILE(SMBsetatr);
1277 return;
1280 /****************************************************************************
1281 Reply to a dskattr.
1282 ****************************************************************************/
1284 void reply_dskattr(struct smb_request *req)
1286 connection_struct *conn = req->conn;
1287 uint64_t dfree,dsize,bsize;
1288 START_PROFILE(SMBdskattr);
1290 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1291 reply_nterror(req, map_nt_error_from_unix(errno));
1292 END_PROFILE(SMBdskattr);
1293 return;
1296 reply_outbuf(req, 5, 0);
1298 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1299 double total_space, free_space;
1300 /* we need to scale this to a number that DOS6 can handle. We
1301 use floating point so we can handle large drives on systems
1302 that don't have 64 bit integers
1304 we end up displaying a maximum of 2G to DOS systems
1306 total_space = dsize * (double)bsize;
1307 free_space = dfree * (double)bsize;
1309 dsize = (uint64_t)((total_space+63*512) / (64*512));
1310 dfree = (uint64_t)((free_space+63*512) / (64*512));
1312 if (dsize > 0xFFFF) dsize = 0xFFFF;
1313 if (dfree > 0xFFFF) dfree = 0xFFFF;
1315 SSVAL(req->outbuf,smb_vwv0,dsize);
1316 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1317 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1318 SSVAL(req->outbuf,smb_vwv3,dfree);
1319 } else {
1320 SSVAL(req->outbuf,smb_vwv0,dsize);
1321 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1322 SSVAL(req->outbuf,smb_vwv2,512);
1323 SSVAL(req->outbuf,smb_vwv3,dfree);
1326 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1328 END_PROFILE(SMBdskattr);
1329 return;
1333 * Utility function to split the filename from the directory.
1335 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1336 char **fname_dir_out,
1337 char **fname_mask_out)
1339 const char *p = NULL;
1340 char *fname_dir = NULL;
1341 char *fname_mask = NULL;
1343 p = strrchr_m(fname_in, '/');
1344 if (!p) {
1345 fname_dir = talloc_strdup(ctx, ".");
1346 fname_mask = talloc_strdup(ctx, fname_in);
1347 } else {
1348 fname_dir = talloc_strndup(ctx, fname_in,
1349 PTR_DIFF(p, fname_in));
1350 fname_mask = talloc_strdup(ctx, p+1);
1353 if (!fname_dir || !fname_mask) {
1354 TALLOC_FREE(fname_dir);
1355 TALLOC_FREE(fname_mask);
1356 return NT_STATUS_NO_MEMORY;
1359 *fname_dir_out = fname_dir;
1360 *fname_mask_out = fname_mask;
1361 return NT_STATUS_OK;
1364 /****************************************************************************
1365 Reply to a search.
1366 Can be called from SMBsearch, SMBffirst or SMBfunique.
1367 ****************************************************************************/
1369 void reply_search(struct smb_request *req)
1371 connection_struct *conn = req->conn;
1372 char *path = NULL;
1373 const char *mask = NULL;
1374 char *directory = NULL;
1375 struct smb_filename *smb_fname = NULL;
1376 char *fname = NULL;
1377 SMB_OFF_T size;
1378 uint32 mode;
1379 struct timespec date;
1380 uint32 dirtype;
1381 unsigned int numentries = 0;
1382 unsigned int maxentries = 0;
1383 bool finished = False;
1384 const char *p;
1385 int status_len;
1386 char status[21];
1387 int dptr_num= -1;
1388 bool check_descend = False;
1389 bool expect_close = False;
1390 NTSTATUS nt_status;
1391 bool mask_contains_wcard = False;
1392 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1393 TALLOC_CTX *ctx = talloc_tos();
1394 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1395 struct dptr_struct *dirptr = NULL;
1396 struct smbd_server_connection *sconn = req->sconn;
1398 START_PROFILE(SMBsearch);
1400 if (req->wct < 2) {
1401 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1402 goto out;
1405 if (lp_posix_pathnames()) {
1406 reply_unknown_new(req, req->cmd);
1407 goto out;
1410 /* If we were called as SMBffirst then we must expect close. */
1411 if(req->cmd == SMBffirst) {
1412 expect_close = True;
1415 reply_outbuf(req, 1, 3);
1416 maxentries = SVAL(req->vwv+0, 0);
1417 dirtype = SVAL(req->vwv+1, 0);
1418 p = (const char *)req->buf + 1;
1419 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1420 &nt_status, &mask_contains_wcard);
1421 if (!NT_STATUS_IS_OK(nt_status)) {
1422 reply_nterror(req, nt_status);
1423 goto out;
1426 p++;
1427 status_len = SVAL(p, 0);
1428 p += 2;
1430 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1432 if (status_len == 0) {
1433 nt_status = filename_convert(ctx, conn,
1434 req->flags2 & FLAGS2_DFS_PATHNAMES,
1435 path,
1436 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1437 &mask_contains_wcard,
1438 &smb_fname);
1439 if (!NT_STATUS_IS_OK(nt_status)) {
1440 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1441 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1442 ERRSRV, ERRbadpath);
1443 goto out;
1445 reply_nterror(req, nt_status);
1446 goto out;
1449 directory = smb_fname->base_name;
1451 p = strrchr_m(directory,'/');
1452 if ((p != NULL) && (*directory != '/')) {
1453 mask = p + 1;
1454 directory = talloc_strndup(ctx, directory,
1455 PTR_DIFF(p, directory));
1456 } else {
1457 mask = directory;
1458 directory = talloc_strdup(ctx,".");
1461 if (!directory) {
1462 reply_nterror(req, NT_STATUS_NO_MEMORY);
1463 goto out;
1466 memset((char *)status,'\0',21);
1467 SCVAL(status,0,(dirtype & 0x1F));
1469 nt_status = dptr_create(conn,
1470 NULL, /* req */
1471 NULL, /* fsp */
1472 directory,
1473 True,
1474 expect_close,
1475 req->smbpid,
1476 mask,
1477 mask_contains_wcard,
1478 dirtype,
1479 &dirptr);
1480 if (!NT_STATUS_IS_OK(nt_status)) {
1481 reply_nterror(req, nt_status);
1482 goto out;
1484 dptr_num = dptr_dnum(dirptr);
1485 } else {
1486 int status_dirtype;
1487 const char *dirpath;
1489 memcpy(status,p,21);
1490 status_dirtype = CVAL(status,0) & 0x1F;
1491 if (status_dirtype != (dirtype & 0x1F)) {
1492 dirtype = status_dirtype;
1495 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1496 if (!dirptr) {
1497 goto SearchEmpty;
1499 dirpath = dptr_path(sconn, dptr_num);
1500 directory = talloc_strdup(ctx, dirpath);
1501 if (!directory) {
1502 reply_nterror(req, NT_STATUS_NO_MEMORY);
1503 goto out;
1506 mask = dptr_wcard(sconn, dptr_num);
1507 if (!mask) {
1508 goto SearchEmpty;
1511 * For a 'continue' search we have no string. So
1512 * check from the initial saved string.
1514 mask_contains_wcard = ms_has_wild(mask);
1515 dirtype = dptr_attr(sconn, dptr_num);
1518 DEBUG(4,("dptr_num is %d\n",dptr_num));
1520 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1521 dptr_init_search_op(dirptr);
1523 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1524 char buf[DIR_STRUCT_SIZE];
1525 memcpy(buf,status,21);
1526 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1527 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1528 reply_nterror(req, NT_STATUS_NO_MEMORY);
1529 goto out;
1531 dptr_fill(sconn, buf+12,dptr_num);
1532 if (dptr_zero(buf+12) && (status_len==0)) {
1533 numentries = 1;
1534 } else {
1535 numentries = 0;
1537 if (message_push_blob(&req->outbuf,
1538 data_blob_const(buf, sizeof(buf)))
1539 == -1) {
1540 reply_nterror(req, NT_STATUS_NO_MEMORY);
1541 goto out;
1543 } else {
1544 unsigned int i;
1545 maxentries = MIN(
1546 maxentries,
1547 ((BUFFER_SIZE -
1548 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1549 /DIR_STRUCT_SIZE));
1551 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1552 directory,lp_dontdescend(SNUM(conn))));
1553 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1554 check_descend = True;
1557 for (i=numentries;(i<maxentries) && !finished;i++) {
1558 finished = !get_dir_entry(ctx,
1559 dirptr,
1560 mask,
1561 dirtype,
1562 &fname,
1563 &size,
1564 &mode,
1565 &date,
1566 check_descend,
1567 ask_sharemode);
1568 if (!finished) {
1569 char buf[DIR_STRUCT_SIZE];
1570 memcpy(buf,status,21);
1571 if (!make_dir_struct(ctx,
1572 buf,
1573 mask,
1574 fname,
1575 size,
1576 mode,
1577 convert_timespec_to_time_t(date),
1578 !allow_long_path_components)) {
1579 reply_nterror(req, NT_STATUS_NO_MEMORY);
1580 goto out;
1582 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1583 break;
1585 if (message_push_blob(&req->outbuf,
1586 data_blob_const(buf, sizeof(buf)))
1587 == -1) {
1588 reply_nterror(req, NT_STATUS_NO_MEMORY);
1589 goto out;
1591 numentries++;
1596 SearchEmpty:
1598 /* If we were called as SMBffirst with smb_search_id == NULL
1599 and no entries were found then return error and close dirptr
1600 (X/Open spec) */
1602 if (numentries == 0) {
1603 dptr_close(sconn, &dptr_num);
1604 } else if(expect_close && status_len == 0) {
1605 /* Close the dptr - we know it's gone */
1606 dptr_close(sconn, &dptr_num);
1609 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1610 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1611 dptr_close(sconn, &dptr_num);
1614 if ((numentries == 0) && !mask_contains_wcard) {
1615 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1616 goto out;
1619 SSVAL(req->outbuf,smb_vwv0,numentries);
1620 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1621 SCVAL(smb_buf(req->outbuf),0,5);
1622 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1624 /* The replies here are never long name. */
1625 SSVAL(req->outbuf, smb_flg2,
1626 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1627 if (!allow_long_path_components) {
1628 SSVAL(req->outbuf, smb_flg2,
1629 SVAL(req->outbuf, smb_flg2)
1630 & (~FLAGS2_LONG_PATH_COMPONENTS));
1633 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1634 SSVAL(req->outbuf, smb_flg2,
1635 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1637 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1638 smb_fn_name(req->cmd),
1639 mask,
1640 directory,
1641 dirtype,
1642 numentries,
1643 maxentries ));
1644 out:
1645 TALLOC_FREE(directory);
1646 TALLOC_FREE(smb_fname);
1647 END_PROFILE(SMBsearch);
1648 return;
1651 /****************************************************************************
1652 Reply to a fclose (stop directory search).
1653 ****************************************************************************/
1655 void reply_fclose(struct smb_request *req)
1657 int status_len;
1658 char status[21];
1659 int dptr_num= -2;
1660 const char *p;
1661 char *path = NULL;
1662 NTSTATUS err;
1663 bool path_contains_wcard = False;
1664 TALLOC_CTX *ctx = talloc_tos();
1665 struct smbd_server_connection *sconn = req->sconn;
1667 START_PROFILE(SMBfclose);
1669 if (lp_posix_pathnames()) {
1670 reply_unknown_new(req, req->cmd);
1671 END_PROFILE(SMBfclose);
1672 return;
1675 p = (const char *)req->buf + 1;
1676 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1677 &err, &path_contains_wcard);
1678 if (!NT_STATUS_IS_OK(err)) {
1679 reply_nterror(req, err);
1680 END_PROFILE(SMBfclose);
1681 return;
1683 p++;
1684 status_len = SVAL(p,0);
1685 p += 2;
1687 if (status_len == 0) {
1688 reply_force_doserror(req, ERRSRV, ERRsrverror);
1689 END_PROFILE(SMBfclose);
1690 return;
1693 memcpy(status,p,21);
1695 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1696 /* Close the dptr - we know it's gone */
1697 dptr_close(sconn, &dptr_num);
1700 reply_outbuf(req, 1, 0);
1701 SSVAL(req->outbuf,smb_vwv0,0);
1703 DEBUG(3,("search close\n"));
1705 END_PROFILE(SMBfclose);
1706 return;
1709 /****************************************************************************
1710 Reply to an open.
1711 ****************************************************************************/
1713 void reply_open(struct smb_request *req)
1715 connection_struct *conn = req->conn;
1716 struct smb_filename *smb_fname = NULL;
1717 char *fname = NULL;
1718 uint32 fattr=0;
1719 SMB_OFF_T size = 0;
1720 time_t mtime=0;
1721 int info;
1722 files_struct *fsp;
1723 int oplock_request;
1724 int deny_mode;
1725 uint32 dos_attr;
1726 uint32 access_mask;
1727 uint32 share_mode;
1728 uint32 create_disposition;
1729 uint32 create_options = 0;
1730 uint32_t private_flags = 0;
1731 NTSTATUS status;
1732 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1733 TALLOC_CTX *ctx = talloc_tos();
1735 START_PROFILE(SMBopen);
1737 if (req->wct < 2) {
1738 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1739 goto out;
1742 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1743 deny_mode = SVAL(req->vwv+0, 0);
1744 dos_attr = SVAL(req->vwv+1, 0);
1746 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1747 STR_TERMINATE, &status);
1748 if (!NT_STATUS_IS_OK(status)) {
1749 reply_nterror(req, status);
1750 goto out;
1753 status = filename_convert(ctx,
1754 conn,
1755 req->flags2 & FLAGS2_DFS_PATHNAMES,
1756 fname,
1758 NULL,
1759 &smb_fname);
1760 if (!NT_STATUS_IS_OK(status)) {
1761 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1762 reply_botherror(req,
1763 NT_STATUS_PATH_NOT_COVERED,
1764 ERRSRV, ERRbadpath);
1765 goto out;
1767 reply_nterror(req, status);
1768 goto out;
1771 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1772 OPENX_FILE_EXISTS_OPEN, &access_mask,
1773 &share_mode, &create_disposition,
1774 &create_options, &private_flags)) {
1775 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1776 goto out;
1779 status = SMB_VFS_CREATE_FILE(
1780 conn, /* conn */
1781 req, /* req */
1782 0, /* root_dir_fid */
1783 smb_fname, /* fname */
1784 access_mask, /* access_mask */
1785 share_mode, /* share_access */
1786 create_disposition, /* create_disposition*/
1787 create_options, /* create_options */
1788 dos_attr, /* file_attributes */
1789 oplock_request, /* oplock_request */
1790 0, /* allocation_size */
1791 private_flags,
1792 NULL, /* sd */
1793 NULL, /* ea_list */
1794 &fsp, /* result */
1795 &info); /* pinfo */
1797 if (!NT_STATUS_IS_OK(status)) {
1798 if (open_was_deferred(req->sconn, req->mid)) {
1799 /* We have re-scheduled this call. */
1800 goto out;
1802 reply_openerror(req, status);
1803 goto out;
1806 size = smb_fname->st.st_ex_size;
1807 fattr = dos_mode(conn, smb_fname);
1809 /* Deal with other possible opens having a modified
1810 write time. JRA. */
1811 if (ask_sharemode) {
1812 struct timespec write_time_ts;
1814 ZERO_STRUCT(write_time_ts);
1815 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1816 if (!null_timespec(write_time_ts)) {
1817 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1821 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1823 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1824 DEBUG(3,("attempt to open a directory %s\n",
1825 fsp_str_dbg(fsp)));
1826 close_file(req, fsp, ERROR_CLOSE);
1827 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1828 ERRDOS, ERRnoaccess);
1829 goto out;
1832 reply_outbuf(req, 7, 0);
1833 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1834 SSVAL(req->outbuf,smb_vwv1,fattr);
1835 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1836 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1837 } else {
1838 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1840 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1841 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1843 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1844 SCVAL(req->outbuf,smb_flg,
1845 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1848 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1849 SCVAL(req->outbuf,smb_flg,
1850 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1852 out:
1853 TALLOC_FREE(smb_fname);
1854 END_PROFILE(SMBopen);
1855 return;
1858 /****************************************************************************
1859 Reply to an open and X.
1860 ****************************************************************************/
1862 void reply_open_and_X(struct smb_request *req)
1864 connection_struct *conn = req->conn;
1865 struct smb_filename *smb_fname = NULL;
1866 char *fname = NULL;
1867 uint16 open_flags;
1868 int deny_mode;
1869 uint32 smb_attr;
1870 /* Breakout the oplock request bits so we can set the
1871 reply bits separately. */
1872 int ex_oplock_request;
1873 int core_oplock_request;
1874 int oplock_request;
1875 #if 0
1876 int smb_sattr = SVAL(req->vwv+4, 0);
1877 uint32 smb_time = make_unix_date3(req->vwv+6);
1878 #endif
1879 int smb_ofun;
1880 uint32 fattr=0;
1881 int mtime=0;
1882 int smb_action = 0;
1883 files_struct *fsp;
1884 NTSTATUS status;
1885 uint64_t allocation_size;
1886 ssize_t retval = -1;
1887 uint32 access_mask;
1888 uint32 share_mode;
1889 uint32 create_disposition;
1890 uint32 create_options = 0;
1891 uint32_t private_flags = 0;
1892 TALLOC_CTX *ctx = talloc_tos();
1894 START_PROFILE(SMBopenX);
1896 if (req->wct < 15) {
1897 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1898 goto out;
1901 open_flags = SVAL(req->vwv+2, 0);
1902 deny_mode = SVAL(req->vwv+3, 0);
1903 smb_attr = SVAL(req->vwv+5, 0);
1904 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1905 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1906 oplock_request = ex_oplock_request | core_oplock_request;
1907 smb_ofun = SVAL(req->vwv+8, 0);
1908 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1910 /* If it's an IPC, pass off the pipe handler. */
1911 if (IS_IPC(conn)) {
1912 if (lp_nt_pipe_support()) {
1913 reply_open_pipe_and_X(conn, req);
1914 } else {
1915 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1917 goto out;
1920 /* XXXX we need to handle passed times, sattr and flags */
1921 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1922 STR_TERMINATE, &status);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 reply_nterror(req, status);
1925 goto out;
1928 status = filename_convert(ctx,
1929 conn,
1930 req->flags2 & FLAGS2_DFS_PATHNAMES,
1931 fname,
1933 NULL,
1934 &smb_fname);
1935 if (!NT_STATUS_IS_OK(status)) {
1936 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1937 reply_botherror(req,
1938 NT_STATUS_PATH_NOT_COVERED,
1939 ERRSRV, ERRbadpath);
1940 goto out;
1942 reply_nterror(req, status);
1943 goto out;
1946 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1947 smb_ofun,
1948 &access_mask, &share_mode,
1949 &create_disposition,
1950 &create_options,
1951 &private_flags)) {
1952 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1953 goto out;
1956 status = SMB_VFS_CREATE_FILE(
1957 conn, /* conn */
1958 req, /* req */
1959 0, /* root_dir_fid */
1960 smb_fname, /* fname */
1961 access_mask, /* access_mask */
1962 share_mode, /* share_access */
1963 create_disposition, /* create_disposition*/
1964 create_options, /* create_options */
1965 smb_attr, /* file_attributes */
1966 oplock_request, /* oplock_request */
1967 0, /* allocation_size */
1968 private_flags,
1969 NULL, /* sd */
1970 NULL, /* ea_list */
1971 &fsp, /* result */
1972 &smb_action); /* pinfo */
1974 if (!NT_STATUS_IS_OK(status)) {
1975 if (open_was_deferred(req->sconn, req->mid)) {
1976 /* We have re-scheduled this call. */
1977 goto out;
1979 reply_openerror(req, status);
1980 goto out;
1983 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1984 if the file is truncated or created. */
1985 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1986 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1987 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1988 close_file(req, fsp, ERROR_CLOSE);
1989 reply_nterror(req, NT_STATUS_DISK_FULL);
1990 goto out;
1992 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1993 if (retval < 0) {
1994 close_file(req, fsp, ERROR_CLOSE);
1995 reply_nterror(req, NT_STATUS_DISK_FULL);
1996 goto out;
1998 status = vfs_stat_fsp(fsp);
1999 if (!NT_STATUS_IS_OK(status)) {
2000 close_file(req, fsp, ERROR_CLOSE);
2001 reply_nterror(req, status);
2002 goto out;
2006 fattr = dos_mode(conn, fsp->fsp_name);
2007 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2008 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2009 close_file(req, fsp, ERROR_CLOSE);
2010 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2011 goto out;
2014 /* If the caller set the extended oplock request bit
2015 and we granted one (by whatever means) - set the
2016 correct bit for extended oplock reply.
2019 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2020 smb_action |= EXTENDED_OPLOCK_GRANTED;
2023 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2024 smb_action |= EXTENDED_OPLOCK_GRANTED;
2027 /* If the caller set the core oplock request bit
2028 and we granted one (by whatever means) - set the
2029 correct bit for core oplock reply.
2032 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2033 reply_outbuf(req, 19, 0);
2034 } else {
2035 reply_outbuf(req, 15, 0);
2038 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2039 SCVAL(req->outbuf, smb_flg,
2040 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2043 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2044 SCVAL(req->outbuf, smb_flg,
2045 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2048 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2049 SSVAL(req->outbuf,smb_vwv3,fattr);
2050 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2051 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2052 } else {
2053 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2055 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2056 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2057 SSVAL(req->outbuf,smb_vwv11,smb_action);
2059 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2060 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2063 chain_reply(req);
2064 out:
2065 TALLOC_FREE(smb_fname);
2066 END_PROFILE(SMBopenX);
2067 return;
2070 /****************************************************************************
2071 Reply to a SMBulogoffX.
2072 ****************************************************************************/
2074 void reply_ulogoffX(struct smb_request *req)
2076 struct smbd_server_connection *sconn = req->sconn;
2077 user_struct *vuser;
2079 START_PROFILE(SMBulogoffX);
2081 vuser = get_valid_user_struct(sconn, req->vuid);
2083 if(vuser == NULL) {
2084 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2085 req->vuid));
2088 /* in user level security we are supposed to close any files
2089 open by this user */
2090 if (vuser != NULL) {
2091 file_close_user(sconn, req->vuid);
2094 invalidate_vuid(sconn, req->vuid);
2096 reply_outbuf(req, 2, 0);
2098 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2100 END_PROFILE(SMBulogoffX);
2101 req->vuid = UID_FIELD_INVALID;
2102 chain_reply(req);
2105 /****************************************************************************
2106 Reply to a mknew or a create.
2107 ****************************************************************************/
2109 void reply_mknew(struct smb_request *req)
2111 connection_struct *conn = req->conn;
2112 struct smb_filename *smb_fname = NULL;
2113 char *fname = NULL;
2114 uint32 fattr = 0;
2115 struct smb_file_time ft;
2116 files_struct *fsp;
2117 int oplock_request = 0;
2118 NTSTATUS status;
2119 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2120 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2121 uint32 create_disposition;
2122 uint32 create_options = 0;
2123 TALLOC_CTX *ctx = talloc_tos();
2125 START_PROFILE(SMBcreate);
2126 ZERO_STRUCT(ft);
2128 if (req->wct < 3) {
2129 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2130 goto out;
2133 fattr = SVAL(req->vwv+0, 0);
2134 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2136 /* mtime. */
2137 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2139 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2140 STR_TERMINATE, &status);
2141 if (!NT_STATUS_IS_OK(status)) {
2142 reply_nterror(req, status);
2143 goto out;
2146 status = filename_convert(ctx,
2147 conn,
2148 req->flags2 & FLAGS2_DFS_PATHNAMES,
2149 fname,
2151 NULL,
2152 &smb_fname);
2153 if (!NT_STATUS_IS_OK(status)) {
2154 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2155 reply_botherror(req,
2156 NT_STATUS_PATH_NOT_COVERED,
2157 ERRSRV, ERRbadpath);
2158 goto out;
2160 reply_nterror(req, status);
2161 goto out;
2164 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2165 DEBUG(0,("Attempt to create file (%s) with volid set - "
2166 "please report this\n",
2167 smb_fname_str_dbg(smb_fname)));
2170 if(req->cmd == SMBmknew) {
2171 /* We should fail if file exists. */
2172 create_disposition = FILE_CREATE;
2173 } else {
2174 /* Create if file doesn't exist, truncate if it does. */
2175 create_disposition = FILE_OVERWRITE_IF;
2178 status = SMB_VFS_CREATE_FILE(
2179 conn, /* conn */
2180 req, /* req */
2181 0, /* root_dir_fid */
2182 smb_fname, /* fname */
2183 access_mask, /* access_mask */
2184 share_mode, /* share_access */
2185 create_disposition, /* create_disposition*/
2186 create_options, /* create_options */
2187 fattr, /* file_attributes */
2188 oplock_request, /* oplock_request */
2189 0, /* allocation_size */
2190 0, /* private_flags */
2191 NULL, /* sd */
2192 NULL, /* ea_list */
2193 &fsp, /* result */
2194 NULL); /* pinfo */
2196 if (!NT_STATUS_IS_OK(status)) {
2197 if (open_was_deferred(req->sconn, req->mid)) {
2198 /* We have re-scheduled this call. */
2199 goto out;
2201 reply_openerror(req, status);
2202 goto out;
2205 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2206 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2207 if (!NT_STATUS_IS_OK(status)) {
2208 END_PROFILE(SMBcreate);
2209 goto out;
2212 reply_outbuf(req, 1, 0);
2213 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2215 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2216 SCVAL(req->outbuf,smb_flg,
2217 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2220 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2221 SCVAL(req->outbuf,smb_flg,
2222 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2225 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2226 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2227 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2228 (unsigned int)fattr));
2230 out:
2231 TALLOC_FREE(smb_fname);
2232 END_PROFILE(SMBcreate);
2233 return;
2236 /****************************************************************************
2237 Reply to a create temporary file.
2238 ****************************************************************************/
2240 void reply_ctemp(struct smb_request *req)
2242 connection_struct *conn = req->conn;
2243 struct smb_filename *smb_fname = NULL;
2244 char *fname = NULL;
2245 uint32 fattr;
2246 files_struct *fsp;
2247 int oplock_request;
2248 int tmpfd;
2249 char *s;
2250 NTSTATUS status;
2251 TALLOC_CTX *ctx = talloc_tos();
2253 START_PROFILE(SMBctemp);
2255 if (req->wct < 3) {
2256 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2257 goto out;
2260 fattr = SVAL(req->vwv+0, 0);
2261 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2263 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2264 STR_TERMINATE, &status);
2265 if (!NT_STATUS_IS_OK(status)) {
2266 reply_nterror(req, status);
2267 goto out;
2269 if (*fname) {
2270 fname = talloc_asprintf(ctx,
2271 "%s/TMXXXXXX",
2272 fname);
2273 } else {
2274 fname = talloc_strdup(ctx, "TMXXXXXX");
2277 if (!fname) {
2278 reply_nterror(req, NT_STATUS_NO_MEMORY);
2279 goto out;
2282 status = filename_convert(ctx, conn,
2283 req->flags2 & FLAGS2_DFS_PATHNAMES,
2284 fname,
2286 NULL,
2287 &smb_fname);
2288 if (!NT_STATUS_IS_OK(status)) {
2289 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2290 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2291 ERRSRV, ERRbadpath);
2292 goto out;
2294 reply_nterror(req, status);
2295 goto out;
2298 tmpfd = mkstemp(smb_fname->base_name);
2299 if (tmpfd == -1) {
2300 reply_nterror(req, map_nt_error_from_unix(errno));
2301 goto out;
2304 SMB_VFS_STAT(conn, smb_fname);
2306 /* We should fail if file does not exist. */
2307 status = SMB_VFS_CREATE_FILE(
2308 conn, /* conn */
2309 req, /* req */
2310 0, /* root_dir_fid */
2311 smb_fname, /* fname */
2312 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2313 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2314 FILE_OPEN, /* create_disposition*/
2315 0, /* create_options */
2316 fattr, /* file_attributes */
2317 oplock_request, /* oplock_request */
2318 0, /* allocation_size */
2319 0, /* private_flags */
2320 NULL, /* sd */
2321 NULL, /* ea_list */
2322 &fsp, /* result */
2323 NULL); /* pinfo */
2325 /* close fd from mkstemp() */
2326 close(tmpfd);
2328 if (!NT_STATUS_IS_OK(status)) {
2329 if (open_was_deferred(req->sconn, req->mid)) {
2330 /* We have re-scheduled this call. */
2331 goto out;
2333 reply_openerror(req, status);
2334 goto out;
2337 reply_outbuf(req, 1, 0);
2338 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2340 /* the returned filename is relative to the directory */
2341 s = strrchr_m(fsp->fsp_name->base_name, '/');
2342 if (!s) {
2343 s = fsp->fsp_name->base_name;
2344 } else {
2345 s++;
2348 #if 0
2349 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2350 thing in the byte section. JRA */
2351 SSVALS(p, 0, -1); /* what is this? not in spec */
2352 #endif
2353 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2354 == -1) {
2355 reply_nterror(req, NT_STATUS_NO_MEMORY);
2356 goto out;
2359 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2360 SCVAL(req->outbuf, smb_flg,
2361 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2364 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2365 SCVAL(req->outbuf, smb_flg,
2366 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2369 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2370 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2371 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2372 out:
2373 TALLOC_FREE(smb_fname);
2374 END_PROFILE(SMBctemp);
2375 return;
2378 /*******************************************************************
2379 Check if a user is allowed to rename a file.
2380 ********************************************************************/
2382 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2383 uint16 dirtype)
2385 if (!CAN_WRITE(conn)) {
2386 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2389 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2390 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2391 /* Only bother to read the DOS attribute if we might deny the
2392 rename on the grounds of attribute missmatch. */
2393 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2394 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2395 return NT_STATUS_NO_SUCH_FILE;
2399 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2400 if (fsp->posix_open) {
2401 return NT_STATUS_OK;
2404 /* If no pathnames are open below this
2405 directory, allow the rename. */
2407 if (file_find_subpath(fsp)) {
2408 return NT_STATUS_ACCESS_DENIED;
2410 return NT_STATUS_OK;
2413 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2414 return NT_STATUS_OK;
2417 return NT_STATUS_ACCESS_DENIED;
2420 /*******************************************************************
2421 * unlink a file with all relevant access checks
2422 *******************************************************************/
2424 static NTSTATUS do_unlink(connection_struct *conn,
2425 struct smb_request *req,
2426 struct smb_filename *smb_fname,
2427 uint32 dirtype)
2429 uint32 fattr;
2430 files_struct *fsp;
2431 uint32 dirtype_orig = dirtype;
2432 NTSTATUS status;
2433 int ret;
2434 bool posix_paths = lp_posix_pathnames();
2436 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2437 smb_fname_str_dbg(smb_fname),
2438 dirtype));
2440 if (!CAN_WRITE(conn)) {
2441 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2444 if (posix_paths) {
2445 ret = SMB_VFS_LSTAT(conn, smb_fname);
2446 } else {
2447 ret = SMB_VFS_STAT(conn, smb_fname);
2449 if (ret != 0) {
2450 return map_nt_error_from_unix(errno);
2453 fattr = dos_mode(conn, smb_fname);
2455 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2456 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2459 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2460 if (!dirtype) {
2461 return NT_STATUS_NO_SUCH_FILE;
2464 if (!dir_check_ftype(conn, fattr, dirtype)) {
2465 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2466 return NT_STATUS_FILE_IS_A_DIRECTORY;
2468 return NT_STATUS_NO_SUCH_FILE;
2471 if (dirtype_orig & 0x8000) {
2472 /* These will never be set for POSIX. */
2473 return NT_STATUS_NO_SUCH_FILE;
2476 #if 0
2477 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2478 return NT_STATUS_FILE_IS_A_DIRECTORY;
2481 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2482 return NT_STATUS_NO_SUCH_FILE;
2485 if (dirtype & 0xFF00) {
2486 /* These will never be set for POSIX. */
2487 return NT_STATUS_NO_SUCH_FILE;
2490 dirtype &= 0xFF;
2491 if (!dirtype) {
2492 return NT_STATUS_NO_SUCH_FILE;
2495 /* Can't delete a directory. */
2496 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2497 return NT_STATUS_FILE_IS_A_DIRECTORY;
2499 #endif
2501 #if 0 /* JRATEST */
2502 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2503 return NT_STATUS_OBJECT_NAME_INVALID;
2504 #endif /* JRATEST */
2506 /* On open checks the open itself will check the share mode, so
2507 don't do it here as we'll get it wrong. */
2509 status = SMB_VFS_CREATE_FILE
2510 (conn, /* conn */
2511 req, /* req */
2512 0, /* root_dir_fid */
2513 smb_fname, /* fname */
2514 DELETE_ACCESS, /* access_mask */
2515 FILE_SHARE_NONE, /* share_access */
2516 FILE_OPEN, /* create_disposition*/
2517 FILE_NON_DIRECTORY_FILE, /* create_options */
2518 /* file_attributes */
2519 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2520 FILE_ATTRIBUTE_NORMAL,
2521 0, /* oplock_request */
2522 0, /* allocation_size */
2523 0, /* private_flags */
2524 NULL, /* sd */
2525 NULL, /* ea_list */
2526 &fsp, /* result */
2527 NULL); /* pinfo */
2529 if (!NT_STATUS_IS_OK(status)) {
2530 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2531 nt_errstr(status)));
2532 return status;
2535 status = can_set_delete_on_close(fsp, fattr);
2536 if (!NT_STATUS_IS_OK(status)) {
2537 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2538 "(%s)\n",
2539 smb_fname_str_dbg(smb_fname),
2540 nt_errstr(status)));
2541 close_file(req, fsp, NORMAL_CLOSE);
2542 return status;
2545 /* The set is across all open files on this dev/inode pair. */
2546 if (!set_delete_on_close(fsp, True, conn->session_info->unix_token)) {
2547 close_file(req, fsp, NORMAL_CLOSE);
2548 return NT_STATUS_ACCESS_DENIED;
2551 return close_file(req, fsp, NORMAL_CLOSE);
2554 /****************************************************************************
2555 The guts of the unlink command, split out so it may be called by the NT SMB
2556 code.
2557 ****************************************************************************/
2559 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2560 uint32 dirtype, struct smb_filename *smb_fname,
2561 bool has_wild)
2563 char *fname_dir = NULL;
2564 char *fname_mask = NULL;
2565 int count=0;
2566 NTSTATUS status = NT_STATUS_OK;
2567 TALLOC_CTX *ctx = talloc_tos();
2569 /* Split up the directory from the filename/mask. */
2570 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2571 &fname_dir, &fname_mask);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 goto out;
2577 * We should only check the mangled cache
2578 * here if unix_convert failed. This means
2579 * that the path in 'mask' doesn't exist
2580 * on the file system and so we need to look
2581 * for a possible mangle. This patch from
2582 * Tine Smukavec <valentin.smukavec@hermes.si>.
2585 if (!VALID_STAT(smb_fname->st) &&
2586 mangle_is_mangled(fname_mask, conn->params)) {
2587 char *new_mask = NULL;
2588 mangle_lookup_name_from_8_3(ctx, fname_mask,
2589 &new_mask, conn->params);
2590 if (new_mask) {
2591 TALLOC_FREE(fname_mask);
2592 fname_mask = new_mask;
2596 if (!has_wild) {
2599 * Only one file needs to be unlinked. Append the mask back
2600 * onto the directory.
2602 TALLOC_FREE(smb_fname->base_name);
2603 if (ISDOT(fname_dir)) {
2604 /* Ensure we use canonical names on open. */
2605 smb_fname->base_name = talloc_asprintf(smb_fname,
2606 "%s",
2607 fname_mask);
2608 } else {
2609 smb_fname->base_name = talloc_asprintf(smb_fname,
2610 "%s/%s",
2611 fname_dir,
2612 fname_mask);
2614 if (!smb_fname->base_name) {
2615 status = NT_STATUS_NO_MEMORY;
2616 goto out;
2618 if (dirtype == 0) {
2619 dirtype = FILE_ATTRIBUTE_NORMAL;
2622 status = check_name(conn, smb_fname->base_name);
2623 if (!NT_STATUS_IS_OK(status)) {
2624 goto out;
2627 status = do_unlink(conn, req, smb_fname, dirtype);
2628 if (!NT_STATUS_IS_OK(status)) {
2629 goto out;
2632 count++;
2633 } else {
2634 struct smb_Dir *dir_hnd = NULL;
2635 long offset = 0;
2636 const char *dname = NULL;
2637 char *talloced = NULL;
2639 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2640 status = NT_STATUS_OBJECT_NAME_INVALID;
2641 goto out;
2644 if (strequal(fname_mask,"????????.???")) {
2645 TALLOC_FREE(fname_mask);
2646 fname_mask = talloc_strdup(ctx, "*");
2647 if (!fname_mask) {
2648 status = NT_STATUS_NO_MEMORY;
2649 goto out;
2653 status = check_name(conn, fname_dir);
2654 if (!NT_STATUS_IS_OK(status)) {
2655 goto out;
2658 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2659 dirtype);
2660 if (dir_hnd == NULL) {
2661 status = map_nt_error_from_unix(errno);
2662 goto out;
2665 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2666 the pattern matches against the long name, otherwise the short name
2667 We don't implement this yet XXXX
2670 status = NT_STATUS_NO_SUCH_FILE;
2672 while ((dname = ReadDirName(dir_hnd, &offset,
2673 &smb_fname->st, &talloced))) {
2674 TALLOC_CTX *frame = talloc_stackframe();
2676 if (!is_visible_file(conn, fname_dir, dname,
2677 &smb_fname->st, true)) {
2678 TALLOC_FREE(frame);
2679 TALLOC_FREE(talloced);
2680 continue;
2683 /* Quick check for "." and ".." */
2684 if (ISDOT(dname) || ISDOTDOT(dname)) {
2685 TALLOC_FREE(frame);
2686 TALLOC_FREE(talloced);
2687 continue;
2690 if(!mask_match(dname, fname_mask,
2691 conn->case_sensitive)) {
2692 TALLOC_FREE(frame);
2693 TALLOC_FREE(talloced);
2694 continue;
2697 TALLOC_FREE(smb_fname->base_name);
2698 if (ISDOT(fname_dir)) {
2699 /* Ensure we use canonical names on open. */
2700 smb_fname->base_name =
2701 talloc_asprintf(smb_fname, "%s",
2702 dname);
2703 } else {
2704 smb_fname->base_name =
2705 talloc_asprintf(smb_fname, "%s/%s",
2706 fname_dir, dname);
2709 if (!smb_fname->base_name) {
2710 TALLOC_FREE(dir_hnd);
2711 status = NT_STATUS_NO_MEMORY;
2712 TALLOC_FREE(frame);
2713 TALLOC_FREE(talloced);
2714 goto out;
2717 status = check_name(conn, smb_fname->base_name);
2718 if (!NT_STATUS_IS_OK(status)) {
2719 TALLOC_FREE(dir_hnd);
2720 TALLOC_FREE(frame);
2721 TALLOC_FREE(talloced);
2722 goto out;
2725 status = do_unlink(conn, req, smb_fname, dirtype);
2726 if (!NT_STATUS_IS_OK(status)) {
2727 TALLOC_FREE(frame);
2728 TALLOC_FREE(talloced);
2729 continue;
2732 count++;
2733 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2734 smb_fname->base_name));
2736 TALLOC_FREE(frame);
2737 TALLOC_FREE(talloced);
2739 TALLOC_FREE(dir_hnd);
2742 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2743 status = map_nt_error_from_unix(errno);
2746 out:
2747 TALLOC_FREE(fname_dir);
2748 TALLOC_FREE(fname_mask);
2749 return status;
2752 /****************************************************************************
2753 Reply to a unlink
2754 ****************************************************************************/
2756 void reply_unlink(struct smb_request *req)
2758 connection_struct *conn = req->conn;
2759 char *name = NULL;
2760 struct smb_filename *smb_fname = NULL;
2761 uint32 dirtype;
2762 NTSTATUS status;
2763 bool path_contains_wcard = False;
2764 TALLOC_CTX *ctx = talloc_tos();
2766 START_PROFILE(SMBunlink);
2768 if (req->wct < 1) {
2769 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2770 goto out;
2773 dirtype = SVAL(req->vwv+0, 0);
2775 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2776 STR_TERMINATE, &status,
2777 &path_contains_wcard);
2778 if (!NT_STATUS_IS_OK(status)) {
2779 reply_nterror(req, status);
2780 goto out;
2783 status = filename_convert(ctx, conn,
2784 req->flags2 & FLAGS2_DFS_PATHNAMES,
2785 name,
2786 UCF_COND_ALLOW_WCARD_LCOMP,
2787 &path_contains_wcard,
2788 &smb_fname);
2789 if (!NT_STATUS_IS_OK(status)) {
2790 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2791 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2792 ERRSRV, ERRbadpath);
2793 goto out;
2795 reply_nterror(req, status);
2796 goto out;
2799 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2801 status = unlink_internals(conn, req, dirtype, smb_fname,
2802 path_contains_wcard);
2803 if (!NT_STATUS_IS_OK(status)) {
2804 if (open_was_deferred(req->sconn, req->mid)) {
2805 /* We have re-scheduled this call. */
2806 goto out;
2808 reply_nterror(req, status);
2809 goto out;
2812 reply_outbuf(req, 0, 0);
2813 out:
2814 TALLOC_FREE(smb_fname);
2815 END_PROFILE(SMBunlink);
2816 return;
2819 /****************************************************************************
2820 Fail for readbraw.
2821 ****************************************************************************/
2823 static void fail_readraw(void)
2825 const char *errstr = talloc_asprintf(talloc_tos(),
2826 "FAIL ! reply_readbraw: socket write fail (%s)",
2827 strerror(errno));
2828 if (!errstr) {
2829 errstr = "";
2831 exit_server_cleanly(errstr);
2834 /****************************************************************************
2835 Fake (read/write) sendfile. Returns -1 on read or write fail.
2836 ****************************************************************************/
2838 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2840 size_t bufsize;
2841 size_t tosend = nread;
2842 char *buf;
2844 if (nread == 0) {
2845 return 0;
2848 bufsize = MIN(nread, 65536);
2850 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2851 return -1;
2854 while (tosend > 0) {
2855 ssize_t ret;
2856 size_t cur_read;
2858 if (tosend > bufsize) {
2859 cur_read = bufsize;
2860 } else {
2861 cur_read = tosend;
2863 ret = read_file(fsp,buf,startpos,cur_read);
2864 if (ret == -1) {
2865 SAFE_FREE(buf);
2866 return -1;
2869 /* If we had a short read, fill with zeros. */
2870 if (ret < cur_read) {
2871 memset(buf + ret, '\0', cur_read - ret);
2874 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2875 != cur_read) {
2876 char addr[INET6_ADDRSTRLEN];
2878 * Try and give an error message saying what
2879 * client failed.
2881 DEBUG(0, ("write_data failed for client %s. "
2882 "Error %s\n",
2883 get_peer_addr(fsp->conn->sconn->sock, addr,
2884 sizeof(addr)),
2885 strerror(errno)));
2886 SAFE_FREE(buf);
2887 return -1;
2889 tosend -= cur_read;
2890 startpos += cur_read;
2893 SAFE_FREE(buf);
2894 return (ssize_t)nread;
2897 /****************************************************************************
2898 Deal with the case of sendfile reading less bytes from the file than
2899 requested. Fill with zeros (all we can do).
2900 ****************************************************************************/
2902 void sendfile_short_send(files_struct *fsp,
2903 ssize_t nread,
2904 size_t headersize,
2905 size_t smb_maxcnt)
2907 #define SHORT_SEND_BUFSIZE 1024
2908 if (nread < headersize) {
2909 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2910 "header for file %s (%s). Terminating\n",
2911 fsp_str_dbg(fsp), strerror(errno)));
2912 exit_server_cleanly("sendfile_short_send failed");
2915 nread -= headersize;
2917 if (nread < smb_maxcnt) {
2918 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2919 if (!buf) {
2920 exit_server_cleanly("sendfile_short_send: "
2921 "malloc failed");
2924 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2925 "with zeros !\n", fsp_str_dbg(fsp)));
2927 while (nread < smb_maxcnt) {
2929 * We asked for the real file size and told sendfile
2930 * to not go beyond the end of the file. But it can
2931 * happen that in between our fstat call and the
2932 * sendfile call the file was truncated. This is very
2933 * bad because we have already announced the larger
2934 * number of bytes to the client.
2936 * The best we can do now is to send 0-bytes, just as
2937 * a read from a hole in a sparse file would do.
2939 * This should happen rarely enough that I don't care
2940 * about efficiency here :-)
2942 size_t to_write;
2944 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2945 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2946 != to_write) {
2947 char addr[INET6_ADDRSTRLEN];
2949 * Try and give an error message saying what
2950 * client failed.
2952 DEBUG(0, ("write_data failed for client %s. "
2953 "Error %s\n",
2954 get_peer_addr(
2955 fsp->conn->sconn->sock, addr,
2956 sizeof(addr)),
2957 strerror(errno)));
2958 exit_server_cleanly("sendfile_short_send: "
2959 "write_data failed");
2961 nread += to_write;
2963 SAFE_FREE(buf);
2967 /****************************************************************************
2968 Return a readbraw error (4 bytes of zero).
2969 ****************************************************************************/
2971 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2973 char header[4];
2975 SIVAL(header,0,0);
2977 smbd_lock_socket(sconn);
2978 if (write_data(sconn->sock,header,4) != 4) {
2979 char addr[INET6_ADDRSTRLEN];
2981 * Try and give an error message saying what
2982 * client failed.
2984 DEBUG(0, ("write_data failed for client %s. "
2985 "Error %s\n",
2986 get_peer_addr(sconn->sock, addr, sizeof(addr)),
2987 strerror(errno)));
2989 fail_readraw();
2991 smbd_unlock_socket(sconn);
2994 /****************************************************************************
2995 Use sendfile in readbraw.
2996 ****************************************************************************/
2998 static void send_file_readbraw(connection_struct *conn,
2999 struct smb_request *req,
3000 files_struct *fsp,
3001 SMB_OFF_T startpos,
3002 size_t nread,
3003 ssize_t mincount)
3005 struct smbd_server_connection *sconn = req->sconn;
3006 char *outbuf = NULL;
3007 ssize_t ret=0;
3010 * We can only use sendfile on a non-chained packet
3011 * but we can use on a non-oplocked file. tridge proved this
3012 * on a train in Germany :-). JRA.
3013 * reply_readbraw has already checked the length.
3016 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3017 (fsp->wcp == NULL) &&
3018 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3019 ssize_t sendfile_read = -1;
3020 char header[4];
3021 DATA_BLOB header_blob;
3023 _smb_setlen(header,nread);
3024 header_blob = data_blob_const(header, 4);
3026 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3027 &header_blob, startpos,
3028 nread);
3029 if (sendfile_read == -1) {
3030 /* Returning ENOSYS means no data at all was sent.
3031 * Do this as a normal read. */
3032 if (errno == ENOSYS) {
3033 goto normal_readbraw;
3037 * Special hack for broken Linux with no working sendfile. If we
3038 * return EINTR we sent the header but not the rest of the data.
3039 * Fake this up by doing read/write calls.
3041 if (errno == EINTR) {
3042 /* Ensure we don't do this again. */
3043 set_use_sendfile(SNUM(conn), False);
3044 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3046 if (fake_sendfile(fsp, startpos, nread) == -1) {
3047 DEBUG(0,("send_file_readbraw: "
3048 "fake_sendfile failed for "
3049 "file %s (%s).\n",
3050 fsp_str_dbg(fsp),
3051 strerror(errno)));
3052 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3054 return;
3057 DEBUG(0,("send_file_readbraw: sendfile failed for "
3058 "file %s (%s). Terminating\n",
3059 fsp_str_dbg(fsp), strerror(errno)));
3060 exit_server_cleanly("send_file_readbraw sendfile failed");
3061 } else if (sendfile_read == 0) {
3063 * Some sendfile implementations return 0 to indicate
3064 * that there was a short read, but nothing was
3065 * actually written to the socket. In this case,
3066 * fallback to the normal read path so the header gets
3067 * the correct byte count.
3069 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3070 "bytes falling back to the normal read: "
3071 "%s\n", fsp_str_dbg(fsp)));
3072 goto normal_readbraw;
3075 /* Deal with possible short send. */
3076 if (sendfile_read != 4+nread) {
3077 sendfile_short_send(fsp, sendfile_read, 4, nread);
3079 return;
3082 normal_readbraw:
3084 outbuf = talloc_array(NULL, char, nread+4);
3085 if (!outbuf) {
3086 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3087 (unsigned)(nread+4)));
3088 reply_readbraw_error(sconn);
3089 return;
3092 if (nread > 0) {
3093 ret = read_file(fsp,outbuf+4,startpos,nread);
3094 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3095 if (ret < mincount)
3096 ret = 0;
3097 #else
3098 if (ret < nread)
3099 ret = 0;
3100 #endif
3103 _smb_setlen(outbuf,ret);
3104 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3105 char addr[INET6_ADDRSTRLEN];
3107 * Try and give an error message saying what
3108 * client failed.
3110 DEBUG(0, ("write_data failed for client %s. "
3111 "Error %s\n",
3112 get_peer_addr(fsp->conn->sconn->sock, addr,
3113 sizeof(addr)),
3114 strerror(errno)));
3116 fail_readraw();
3119 TALLOC_FREE(outbuf);
3122 /****************************************************************************
3123 Reply to a readbraw (core+ protocol).
3124 ****************************************************************************/
3126 void reply_readbraw(struct smb_request *req)
3128 connection_struct *conn = req->conn;
3129 struct smbd_server_connection *sconn = req->sconn;
3130 ssize_t maxcount,mincount;
3131 size_t nread = 0;
3132 SMB_OFF_T startpos;
3133 files_struct *fsp;
3134 struct lock_struct lock;
3135 SMB_OFF_T size = 0;
3137 START_PROFILE(SMBreadbraw);
3139 if (srv_is_signing_active(sconn) ||
3140 is_encrypted_packet(sconn, req->inbuf)) {
3141 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3142 "raw reads/writes are disallowed.");
3145 if (req->wct < 8) {
3146 reply_readbraw_error(sconn);
3147 END_PROFILE(SMBreadbraw);
3148 return;
3151 if (sconn->smb1.echo_handler.trusted_fde) {
3152 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3153 "'async smb echo handler = yes'\n"));
3154 reply_readbraw_error(sconn);
3155 END_PROFILE(SMBreadbraw);
3156 return;
3160 * Special check if an oplock break has been issued
3161 * and the readraw request croses on the wire, we must
3162 * return a zero length response here.
3165 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3168 * We have to do a check_fsp by hand here, as
3169 * we must always return 4 zero bytes on error,
3170 * not a NTSTATUS.
3173 if (!fsp || !conn || conn != fsp->conn ||
3174 req->vuid != fsp->vuid ||
3175 fsp->is_directory || fsp->fh->fd == -1) {
3177 * fsp could be NULL here so use the value from the packet. JRA.
3179 DEBUG(3,("reply_readbraw: fnum %d not valid "
3180 "- cache prime?\n",
3181 (int)SVAL(req->vwv+0, 0)));
3182 reply_readbraw_error(sconn);
3183 END_PROFILE(SMBreadbraw);
3184 return;
3187 /* Do a "by hand" version of CHECK_READ. */
3188 if (!(fsp->can_read ||
3189 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3190 (fsp->access_mask & FILE_EXECUTE)))) {
3191 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3192 (int)SVAL(req->vwv+0, 0)));
3193 reply_readbraw_error(sconn);
3194 END_PROFILE(SMBreadbraw);
3195 return;
3198 flush_write_cache(fsp, READRAW_FLUSH);
3200 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3201 if(req->wct == 10) {
3203 * This is a large offset (64 bit) read.
3205 #ifdef LARGE_SMB_OFF_T
3207 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3209 #else /* !LARGE_SMB_OFF_T */
3212 * Ensure we haven't been sent a >32 bit offset.
3215 if(IVAL(req->vwv+8, 0) != 0) {
3216 DEBUG(0,("reply_readbraw: large offset "
3217 "(%x << 32) used and we don't support "
3218 "64 bit offsets.\n",
3219 (unsigned int)IVAL(req->vwv+8, 0) ));
3220 reply_readbraw_error(sconn);
3221 END_PROFILE(SMBreadbraw);
3222 return;
3225 #endif /* LARGE_SMB_OFF_T */
3227 if(startpos < 0) {
3228 DEBUG(0,("reply_readbraw: negative 64 bit "
3229 "readraw offset (%.0f) !\n",
3230 (double)startpos ));
3231 reply_readbraw_error(sconn);
3232 END_PROFILE(SMBreadbraw);
3233 return;
3237 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3238 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3240 /* ensure we don't overrun the packet size */
3241 maxcount = MIN(65535,maxcount);
3243 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3244 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3245 &lock);
3247 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3248 reply_readbraw_error(sconn);
3249 END_PROFILE(SMBreadbraw);
3250 return;
3253 if (fsp_stat(fsp) == 0) {
3254 size = fsp->fsp_name->st.st_ex_size;
3257 if (startpos >= size) {
3258 nread = 0;
3259 } else {
3260 nread = MIN(maxcount,(size - startpos));
3263 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3264 if (nread < mincount)
3265 nread = 0;
3266 #endif
3268 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3269 "min=%lu nread=%lu\n",
3270 fsp->fnum, (double)startpos,
3271 (unsigned long)maxcount,
3272 (unsigned long)mincount,
3273 (unsigned long)nread ) );
3275 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3277 DEBUG(5,("reply_readbraw finished\n"));
3279 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3281 END_PROFILE(SMBreadbraw);
3282 return;
3285 #undef DBGC_CLASS
3286 #define DBGC_CLASS DBGC_LOCKING
3288 /****************************************************************************
3289 Reply to a lockread (core+ protocol).
3290 ****************************************************************************/
3292 void reply_lockread(struct smb_request *req)
3294 connection_struct *conn = req->conn;
3295 ssize_t nread = -1;
3296 char *data;
3297 SMB_OFF_T startpos;
3298 size_t numtoread;
3299 NTSTATUS status;
3300 files_struct *fsp;
3301 struct byte_range_lock *br_lck = NULL;
3302 char *p = NULL;
3303 struct smbd_server_connection *sconn = req->sconn;
3305 START_PROFILE(SMBlockread);
3307 if (req->wct < 5) {
3308 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3309 END_PROFILE(SMBlockread);
3310 return;
3313 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3315 if (!check_fsp(conn, req, fsp)) {
3316 END_PROFILE(SMBlockread);
3317 return;
3320 if (!CHECK_READ(fsp,req)) {
3321 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3322 END_PROFILE(SMBlockread);
3323 return;
3326 numtoread = SVAL(req->vwv+1, 0);
3327 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3329 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3331 reply_outbuf(req, 5, numtoread + 3);
3333 data = smb_buf(req->outbuf) + 3;
3336 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3337 * protocol request that predates the read/write lock concept.
3338 * Thus instead of asking for a read lock here we need to ask
3339 * for a write lock. JRA.
3340 * Note that the requested lock size is unaffected by max_recv.
3343 br_lck = do_lock(req->sconn->msg_ctx,
3344 fsp,
3345 (uint64_t)req->smbpid,
3346 (uint64_t)numtoread,
3347 (uint64_t)startpos,
3348 WRITE_LOCK,
3349 WINDOWS_LOCK,
3350 False, /* Non-blocking lock. */
3351 &status,
3352 NULL,
3353 NULL);
3354 TALLOC_FREE(br_lck);
3356 if (NT_STATUS_V(status)) {
3357 reply_nterror(req, status);
3358 END_PROFILE(SMBlockread);
3359 return;
3363 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3366 if (numtoread > sconn->smb1.negprot.max_recv) {
3367 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3368 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3369 (unsigned int)numtoread,
3370 (unsigned int)sconn->smb1.negprot.max_recv));
3371 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3373 nread = read_file(fsp,data,startpos,numtoread);
3375 if (nread < 0) {
3376 reply_nterror(req, map_nt_error_from_unix(errno));
3377 END_PROFILE(SMBlockread);
3378 return;
3381 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3383 SSVAL(req->outbuf,smb_vwv0,nread);
3384 SSVAL(req->outbuf,smb_vwv5,nread+3);
3385 p = smb_buf(req->outbuf);
3386 SCVAL(p,0,0); /* pad byte. */
3387 SSVAL(p,1,nread);
3389 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3390 fsp->fnum, (int)numtoread, (int)nread));
3392 END_PROFILE(SMBlockread);
3393 return;
3396 #undef DBGC_CLASS
3397 #define DBGC_CLASS DBGC_ALL
3399 /****************************************************************************
3400 Reply to a read.
3401 ****************************************************************************/
3403 void reply_read(struct smb_request *req)
3405 connection_struct *conn = req->conn;
3406 size_t numtoread;
3407 ssize_t nread = 0;
3408 char *data;
3409 SMB_OFF_T startpos;
3410 int outsize = 0;
3411 files_struct *fsp;
3412 struct lock_struct lock;
3413 struct smbd_server_connection *sconn = req->sconn;
3415 START_PROFILE(SMBread);
3417 if (req->wct < 3) {
3418 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3419 END_PROFILE(SMBread);
3420 return;
3423 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3425 if (!check_fsp(conn, req, fsp)) {
3426 END_PROFILE(SMBread);
3427 return;
3430 if (!CHECK_READ(fsp,req)) {
3431 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3432 END_PROFILE(SMBread);
3433 return;
3436 numtoread = SVAL(req->vwv+1, 0);
3437 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3439 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3442 * The requested read size cannot be greater than max_recv. JRA.
3444 if (numtoread > sconn->smb1.negprot.max_recv) {
3445 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3446 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3447 (unsigned int)numtoread,
3448 (unsigned int)sconn->smb1.negprot.max_recv));
3449 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3452 reply_outbuf(req, 5, numtoread+3);
3454 data = smb_buf(req->outbuf) + 3;
3456 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3457 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3458 &lock);
3460 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3461 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3462 END_PROFILE(SMBread);
3463 return;
3466 if (numtoread > 0)
3467 nread = read_file(fsp,data,startpos,numtoread);
3469 if (nread < 0) {
3470 reply_nterror(req, map_nt_error_from_unix(errno));
3471 goto strict_unlock;
3474 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3476 SSVAL(req->outbuf,smb_vwv0,nread);
3477 SSVAL(req->outbuf,smb_vwv5,nread+3);
3478 SCVAL(smb_buf(req->outbuf),0,1);
3479 SSVAL(smb_buf(req->outbuf),1,nread);
3481 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3482 fsp->fnum, (int)numtoread, (int)nread ) );
3484 strict_unlock:
3485 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3487 END_PROFILE(SMBread);
3488 return;
3491 /****************************************************************************
3492 Setup readX header.
3493 ****************************************************************************/
3495 static int setup_readX_header(struct smb_request *req, char *outbuf,
3496 size_t smb_maxcnt)
3498 int outsize;
3500 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3502 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3504 SCVAL(outbuf,smb_vwv0,0xFF);
3505 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3506 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3507 SSVAL(outbuf,smb_vwv6,
3508 req_wct_ofs(req)
3509 + 1 /* the wct field */
3510 + 12 * sizeof(uint16_t) /* vwv */
3511 + 2); /* the buflen field */
3512 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3513 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3514 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3515 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3516 return outsize;
3519 /****************************************************************************
3520 Reply to a read and X - possibly using sendfile.
3521 ****************************************************************************/
3523 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3524 files_struct *fsp, SMB_OFF_T startpos,
3525 size_t smb_maxcnt)
3527 ssize_t nread = -1;
3528 struct lock_struct lock;
3529 int saved_errno = 0;
3531 if(fsp_stat(fsp) == -1) {
3532 reply_nterror(req, map_nt_error_from_unix(errno));
3533 return;
3536 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3537 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3538 &lock);
3540 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3541 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3542 return;
3545 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3546 (startpos > fsp->fsp_name->st.st_ex_size)
3547 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3549 * We already know that we would do a short read, so don't
3550 * try the sendfile() path.
3552 goto nosendfile_read;
3556 * We can only use sendfile on a non-chained packet
3557 * but we can use on a non-oplocked file. tridge proved this
3558 * on a train in Germany :-). JRA.
3561 if (!req_is_in_chain(req) &&
3562 !is_encrypted_packet(req->sconn, req->inbuf) &&
3563 (fsp->base_fsp == NULL) &&
3564 (fsp->wcp == NULL) &&
3565 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3566 uint8 headerbuf[smb_size + 12 * 2];
3567 DATA_BLOB header;
3570 * Set up the packet header before send. We
3571 * assume here the sendfile will work (get the
3572 * correct amount of data).
3575 header = data_blob_const(headerbuf, sizeof(headerbuf));
3577 construct_reply_common_req(req, (char *)headerbuf);
3578 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3580 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3581 startpos, smb_maxcnt);
3582 if (nread == -1) {
3583 /* Returning ENOSYS means no data at all was sent.
3584 Do this as a normal read. */
3585 if (errno == ENOSYS) {
3586 goto normal_read;
3590 * Special hack for broken Linux with no working sendfile. If we
3591 * return EINTR we sent the header but not the rest of the data.
3592 * Fake this up by doing read/write calls.
3595 if (errno == EINTR) {
3596 /* Ensure we don't do this again. */
3597 set_use_sendfile(SNUM(conn), False);
3598 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3599 nread = fake_sendfile(fsp, startpos,
3600 smb_maxcnt);
3601 if (nread == -1) {
3602 DEBUG(0,("send_file_readX: "
3603 "fake_sendfile failed for "
3604 "file %s (%s).\n",
3605 fsp_str_dbg(fsp),
3606 strerror(errno)));
3607 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3609 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3610 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3611 /* No outbuf here means successful sendfile. */
3612 goto strict_unlock;
3615 DEBUG(0,("send_file_readX: sendfile failed for file "
3616 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3617 strerror(errno)));
3618 exit_server_cleanly("send_file_readX sendfile failed");
3619 } else if (nread == 0) {
3621 * Some sendfile implementations return 0 to indicate
3622 * that there was a short read, but nothing was
3623 * actually written to the socket. In this case,
3624 * fallback to the normal read path so the header gets
3625 * the correct byte count.
3627 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3628 "falling back to the normal read: %s\n",
3629 fsp_str_dbg(fsp)));
3630 goto normal_read;
3633 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3634 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3636 /* Deal with possible short send. */
3637 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3638 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3640 /* No outbuf here means successful sendfile. */
3641 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3642 SMB_PERFCOUNT_END(&req->pcd);
3643 goto strict_unlock;
3646 normal_read:
3648 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3649 uint8 headerbuf[smb_size + 2*12];
3651 construct_reply_common_req(req, (char *)headerbuf);
3652 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3654 /* Send out the header. */
3655 if (write_data(req->sconn->sock, (char *)headerbuf,
3656 sizeof(headerbuf)) != sizeof(headerbuf)) {
3658 char addr[INET6_ADDRSTRLEN];
3660 * Try and give an error message saying what
3661 * client failed.
3663 DEBUG(0, ("write_data failed for client %s. "
3664 "Error %s\n",
3665 get_peer_addr(req->sconn->sock, addr,
3666 sizeof(addr)),
3667 strerror(errno)));
3669 DEBUG(0,("send_file_readX: write_data failed for file "
3670 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3671 strerror(errno)));
3672 exit_server_cleanly("send_file_readX sendfile failed");
3674 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3675 if (nread == -1) {
3676 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3677 "file %s (%s).\n", fsp_str_dbg(fsp),
3678 strerror(errno)));
3679 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3681 goto strict_unlock;
3684 nosendfile_read:
3686 reply_outbuf(req, 12, smb_maxcnt);
3688 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3689 saved_errno = errno;
3691 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3693 if (nread < 0) {
3694 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3695 return;
3698 setup_readX_header(req, (char *)req->outbuf, nread);
3700 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3701 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3703 chain_reply(req);
3704 return;
3706 strict_unlock:
3707 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3708 TALLOC_FREE(req->outbuf);
3709 return;
3712 /****************************************************************************
3713 Reply to a read and X.
3714 ****************************************************************************/
3716 void reply_read_and_X(struct smb_request *req)
3718 struct smbd_server_connection *sconn = req->sconn;
3719 connection_struct *conn = req->conn;
3720 files_struct *fsp;
3721 SMB_OFF_T startpos;
3722 size_t smb_maxcnt;
3723 bool big_readX = False;
3724 #if 0
3725 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3726 #endif
3728 START_PROFILE(SMBreadX);
3730 if ((req->wct != 10) && (req->wct != 12)) {
3731 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3732 return;
3735 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3736 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3737 smb_maxcnt = SVAL(req->vwv+5, 0);
3739 /* If it's an IPC, pass off the pipe handler. */
3740 if (IS_IPC(conn)) {
3741 reply_pipe_read_and_X(req);
3742 END_PROFILE(SMBreadX);
3743 return;
3746 if (!check_fsp(conn, req, fsp)) {
3747 END_PROFILE(SMBreadX);
3748 return;
3751 if (!CHECK_READ(fsp,req)) {
3752 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3753 END_PROFILE(SMBreadX);
3754 return;
3757 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3758 (get_remote_arch() == RA_SAMBA)) {
3760 * This is Samba only behavior (up to Samba 3.6)!
3762 * Windows 2008 R2 ignores the upper_size,
3763 * so we do unless unix extentions are active
3764 * or "smbclient" is talking to us.
3766 size_t upper_size = SVAL(req->vwv+7, 0);
3767 smb_maxcnt |= (upper_size<<16);
3768 if (upper_size > 1) {
3769 /* Can't do this on a chained packet. */
3770 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3771 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3772 END_PROFILE(SMBreadX);
3773 return;
3775 /* We currently don't do this on signed or sealed data. */
3776 if (srv_is_signing_active(req->sconn) ||
3777 is_encrypted_packet(req->sconn, req->inbuf)) {
3778 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3779 END_PROFILE(SMBreadX);
3780 return;
3782 /* Is there room in the reply for this data ? */
3783 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3784 reply_nterror(req,
3785 NT_STATUS_INVALID_PARAMETER);
3786 END_PROFILE(SMBreadX);
3787 return;
3789 big_readX = True;
3793 if (req->wct == 12) {
3794 #ifdef LARGE_SMB_OFF_T
3796 * This is a large offset (64 bit) read.
3798 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3800 #else /* !LARGE_SMB_OFF_T */
3803 * Ensure we haven't been sent a >32 bit offset.
3806 if(IVAL(req->vwv+10, 0) != 0) {
3807 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3808 "used and we don't support 64 bit offsets.\n",
3809 (unsigned int)IVAL(req->vwv+10, 0) ));
3810 END_PROFILE(SMBreadX);
3811 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3812 return;
3815 #endif /* LARGE_SMB_OFF_T */
3819 if (!big_readX) {
3820 NTSTATUS status = schedule_aio_read_and_X(conn,
3821 req,
3822 fsp,
3823 startpos,
3824 smb_maxcnt);
3825 if (NT_STATUS_IS_OK(status)) {
3826 /* Read scheduled - we're done. */
3827 goto out;
3829 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3830 /* Real error - report to client. */
3831 END_PROFILE(SMBreadX);
3832 reply_nterror(req, status);
3833 return;
3835 /* NT_STATUS_RETRY - fall back to sync read. */
3838 smbd_lock_socket(req->sconn);
3839 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3840 smbd_unlock_socket(req->sconn);
3842 out:
3843 END_PROFILE(SMBreadX);
3844 return;
3847 /****************************************************************************
3848 Error replies to writebraw must have smb_wct == 1. Fix this up.
3849 ****************************************************************************/
3851 void error_to_writebrawerr(struct smb_request *req)
3853 uint8 *old_outbuf = req->outbuf;
3855 reply_outbuf(req, 1, 0);
3857 memcpy(req->outbuf, old_outbuf, smb_size);
3858 TALLOC_FREE(old_outbuf);
3861 /****************************************************************************
3862 Read 4 bytes of a smb packet and return the smb length of the packet.
3863 Store the result in the buffer. This version of the function will
3864 never return a session keepalive (length of zero).
3865 Timeout is in milliseconds.
3866 ****************************************************************************/
3868 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3869 size_t *len)
3871 uint8_t msgtype = NBSSkeepalive;
3873 while (msgtype == NBSSkeepalive) {
3874 NTSTATUS status;
3876 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3877 len);
3878 if (!NT_STATUS_IS_OK(status)) {
3879 char addr[INET6_ADDRSTRLEN];
3880 /* Try and give an error message
3881 * saying what client failed. */
3882 DEBUG(0, ("read_fd_with_timeout failed for "
3883 "client %s read error = %s.\n",
3884 get_peer_addr(fd,addr,sizeof(addr)),
3885 nt_errstr(status)));
3886 return status;
3889 msgtype = CVAL(inbuf, 0);
3892 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3893 (unsigned long)len));
3895 return NT_STATUS_OK;
3898 /****************************************************************************
3899 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3900 ****************************************************************************/
3902 void reply_writebraw(struct smb_request *req)
3904 connection_struct *conn = req->conn;
3905 char *buf = NULL;
3906 ssize_t nwritten=0;
3907 ssize_t total_written=0;
3908 size_t numtowrite=0;
3909 size_t tcount;
3910 SMB_OFF_T startpos;
3911 const char *data=NULL;
3912 bool write_through;
3913 files_struct *fsp;
3914 struct lock_struct lock;
3915 NTSTATUS status;
3917 START_PROFILE(SMBwritebraw);
3920 * If we ever reply with an error, it must have the SMB command
3921 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3922 * we're finished.
3924 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3926 if (srv_is_signing_active(req->sconn)) {
3927 END_PROFILE(SMBwritebraw);
3928 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3929 "raw reads/writes are disallowed.");
3932 if (req->wct < 12) {
3933 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3934 error_to_writebrawerr(req);
3935 END_PROFILE(SMBwritebraw);
3936 return;
3939 if (req->sconn->smb1.echo_handler.trusted_fde) {
3940 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3941 "'async smb echo handler = yes'\n"));
3942 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3943 error_to_writebrawerr(req);
3944 END_PROFILE(SMBwritebraw);
3945 return;
3948 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3949 if (!check_fsp(conn, req, fsp)) {
3950 error_to_writebrawerr(req);
3951 END_PROFILE(SMBwritebraw);
3952 return;
3955 if (!CHECK_WRITE(fsp)) {
3956 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3957 error_to_writebrawerr(req);
3958 END_PROFILE(SMBwritebraw);
3959 return;
3962 tcount = IVAL(req->vwv+1, 0);
3963 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3964 write_through = BITSETW(req->vwv+7,0);
3966 /* We have to deal with slightly different formats depending
3967 on whether we are using the core+ or lanman1.0 protocol */
3969 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3970 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
3971 data = smb_buf_const(req->inbuf);
3972 } else {
3973 numtowrite = SVAL(req->vwv+10, 0);
3974 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3977 /* Ensure we don't write bytes past the end of this packet. */
3978 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3979 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3980 error_to_writebrawerr(req);
3981 END_PROFILE(SMBwritebraw);
3982 return;
3985 if (!fsp->print_file) {
3986 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3987 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3988 &lock);
3990 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3991 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3992 error_to_writebrawerr(req);
3993 END_PROFILE(SMBwritebraw);
3994 return;
3998 if (numtowrite>0) {
3999 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4002 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
4003 "wrote=%d sync=%d\n",
4004 fsp->fnum, (double)startpos, (int)numtowrite,
4005 (int)nwritten, (int)write_through));
4007 if (nwritten < (ssize_t)numtowrite) {
4008 reply_nterror(req, NT_STATUS_DISK_FULL);
4009 error_to_writebrawerr(req);
4010 goto strict_unlock;
4013 total_written = nwritten;
4015 /* Allocate a buffer of 64k + length. */
4016 buf = talloc_array(NULL, char, 65540);
4017 if (!buf) {
4018 reply_nterror(req, NT_STATUS_NO_MEMORY);
4019 error_to_writebrawerr(req);
4020 goto strict_unlock;
4023 /* Return a SMBwritebraw message to the redirector to tell
4024 * it to send more bytes */
4026 memcpy(buf, req->inbuf, smb_size);
4027 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4028 SCVAL(buf,smb_com,SMBwritebraw);
4029 SSVALS(buf,smb_vwv0,0xFFFF);
4030 show_msg(buf);
4031 if (!srv_send_smb(req->sconn,
4032 buf,
4033 false, 0, /* no signing */
4034 IS_CONN_ENCRYPTED(conn),
4035 &req->pcd)) {
4036 exit_server_cleanly("reply_writebraw: srv_send_smb "
4037 "failed.");
4040 /* Now read the raw data into the buffer and write it */
4041 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4042 &numtowrite);
4043 if (!NT_STATUS_IS_OK(status)) {
4044 exit_server_cleanly("secondary writebraw failed");
4047 /* Set up outbuf to return the correct size */
4048 reply_outbuf(req, 1, 0);
4050 if (numtowrite != 0) {
4052 if (numtowrite > 0xFFFF) {
4053 DEBUG(0,("reply_writebraw: Oversize secondary write "
4054 "raw requested (%u). Terminating\n",
4055 (unsigned int)numtowrite ));
4056 exit_server_cleanly("secondary writebraw failed");
4059 if (tcount > nwritten+numtowrite) {
4060 DEBUG(3,("reply_writebraw: Client overestimated the "
4061 "write %d %d %d\n",
4062 (int)tcount,(int)nwritten,(int)numtowrite));
4065 status = read_data(req->sconn->sock, buf+4, numtowrite);
4067 if (!NT_STATUS_IS_OK(status)) {
4068 char addr[INET6_ADDRSTRLEN];
4069 /* Try and give an error message
4070 * saying what client failed. */
4071 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4072 "raw read failed (%s) for client %s. "
4073 "Terminating\n", nt_errstr(status),
4074 get_peer_addr(req->sconn->sock, addr,
4075 sizeof(addr))));
4076 exit_server_cleanly("secondary writebraw failed");
4079 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4080 if (nwritten == -1) {
4081 TALLOC_FREE(buf);
4082 reply_nterror(req, map_nt_error_from_unix(errno));
4083 error_to_writebrawerr(req);
4084 goto strict_unlock;
4087 if (nwritten < (ssize_t)numtowrite) {
4088 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4089 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4092 if (nwritten > 0) {
4093 total_written += nwritten;
4097 TALLOC_FREE(buf);
4098 SSVAL(req->outbuf,smb_vwv0,total_written);
4100 status = sync_file(conn, fsp, write_through);
4101 if (!NT_STATUS_IS_OK(status)) {
4102 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4103 fsp_str_dbg(fsp), nt_errstr(status)));
4104 reply_nterror(req, status);
4105 error_to_writebrawerr(req);
4106 goto strict_unlock;
4109 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4110 "wrote=%d\n",
4111 fsp->fnum, (double)startpos, (int)numtowrite,
4112 (int)total_written));
4114 if (!fsp->print_file) {
4115 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4118 /* We won't return a status if write through is not selected - this
4119 * follows what WfWg does */
4120 END_PROFILE(SMBwritebraw);
4122 if (!write_through && total_written==tcount) {
4124 #if RABBIT_PELLET_FIX
4126 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4127 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4128 * JRA.
4130 if (!send_keepalive(req->sconn->sock)) {
4131 exit_server_cleanly("reply_writebraw: send of "
4132 "keepalive failed");
4134 #endif
4135 TALLOC_FREE(req->outbuf);
4137 return;
4139 strict_unlock:
4140 if (!fsp->print_file) {
4141 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4144 END_PROFILE(SMBwritebraw);
4145 return;
4148 #undef DBGC_CLASS
4149 #define DBGC_CLASS DBGC_LOCKING
4151 /****************************************************************************
4152 Reply to a writeunlock (core+).
4153 ****************************************************************************/
4155 void reply_writeunlock(struct smb_request *req)
4157 connection_struct *conn = req->conn;
4158 ssize_t nwritten = -1;
4159 size_t numtowrite;
4160 SMB_OFF_T startpos;
4161 const char *data;
4162 NTSTATUS status = NT_STATUS_OK;
4163 files_struct *fsp;
4164 struct lock_struct lock;
4165 int saved_errno = 0;
4167 START_PROFILE(SMBwriteunlock);
4169 if (req->wct < 5) {
4170 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4171 END_PROFILE(SMBwriteunlock);
4172 return;
4175 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4177 if (!check_fsp(conn, req, fsp)) {
4178 END_PROFILE(SMBwriteunlock);
4179 return;
4182 if (!CHECK_WRITE(fsp)) {
4183 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4184 END_PROFILE(SMBwriteunlock);
4185 return;
4188 numtowrite = SVAL(req->vwv+1, 0);
4189 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4190 data = (const char *)req->buf + 3;
4192 if (!fsp->print_file && numtowrite > 0) {
4193 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4194 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4195 &lock);
4197 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4198 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4199 END_PROFILE(SMBwriteunlock);
4200 return;
4204 /* The special X/Open SMB protocol handling of
4205 zero length writes is *NOT* done for
4206 this call */
4207 if(numtowrite == 0) {
4208 nwritten = 0;
4209 } else {
4210 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4211 saved_errno = errno;
4214 status = sync_file(conn, fsp, False /* write through */);
4215 if (!NT_STATUS_IS_OK(status)) {
4216 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4217 fsp_str_dbg(fsp), nt_errstr(status)));
4218 reply_nterror(req, status);
4219 goto strict_unlock;
4222 if(nwritten < 0) {
4223 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4224 goto strict_unlock;
4227 if((nwritten < numtowrite) && (numtowrite != 0)) {
4228 reply_nterror(req, NT_STATUS_DISK_FULL);
4229 goto strict_unlock;
4232 if (numtowrite && !fsp->print_file) {
4233 status = do_unlock(req->sconn->msg_ctx,
4234 fsp,
4235 (uint64_t)req->smbpid,
4236 (uint64_t)numtowrite,
4237 (uint64_t)startpos,
4238 WINDOWS_LOCK);
4240 if (NT_STATUS_V(status)) {
4241 reply_nterror(req, status);
4242 goto strict_unlock;
4246 reply_outbuf(req, 1, 0);
4248 SSVAL(req->outbuf,smb_vwv0,nwritten);
4250 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4251 fsp->fnum, (int)numtowrite, (int)nwritten));
4253 strict_unlock:
4254 if (numtowrite && !fsp->print_file) {
4255 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4258 END_PROFILE(SMBwriteunlock);
4259 return;
4262 #undef DBGC_CLASS
4263 #define DBGC_CLASS DBGC_ALL
4265 /****************************************************************************
4266 Reply to a write.
4267 ****************************************************************************/
4269 void reply_write(struct smb_request *req)
4271 connection_struct *conn = req->conn;
4272 size_t numtowrite;
4273 ssize_t nwritten = -1;
4274 SMB_OFF_T startpos;
4275 const char *data;
4276 files_struct *fsp;
4277 struct lock_struct lock;
4278 NTSTATUS status;
4279 int saved_errno = 0;
4281 START_PROFILE(SMBwrite);
4283 if (req->wct < 5) {
4284 END_PROFILE(SMBwrite);
4285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4286 return;
4289 /* If it's an IPC, pass off the pipe handler. */
4290 if (IS_IPC(conn)) {
4291 reply_pipe_write(req);
4292 END_PROFILE(SMBwrite);
4293 return;
4296 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4298 if (!check_fsp(conn, req, fsp)) {
4299 END_PROFILE(SMBwrite);
4300 return;
4303 if (!CHECK_WRITE(fsp)) {
4304 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4305 END_PROFILE(SMBwrite);
4306 return;
4309 numtowrite = SVAL(req->vwv+1, 0);
4310 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4311 data = (const char *)req->buf + 3;
4313 if (!fsp->print_file) {
4314 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4315 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4316 &lock);
4318 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4319 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4320 END_PROFILE(SMBwrite);
4321 return;
4326 * X/Open SMB protocol says that if smb_vwv1 is
4327 * zero then the file size should be extended or
4328 * truncated to the size given in smb_vwv[2-3].
4331 if(numtowrite == 0) {
4333 * This is actually an allocate call, and set EOF. JRA.
4335 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4336 if (nwritten < 0) {
4337 reply_nterror(req, NT_STATUS_DISK_FULL);
4338 goto strict_unlock;
4340 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4341 if (nwritten < 0) {
4342 reply_nterror(req, NT_STATUS_DISK_FULL);
4343 goto strict_unlock;
4345 trigger_write_time_update_immediate(fsp);
4346 } else {
4347 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4350 status = sync_file(conn, fsp, False);
4351 if (!NT_STATUS_IS_OK(status)) {
4352 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4353 fsp_str_dbg(fsp), nt_errstr(status)));
4354 reply_nterror(req, status);
4355 goto strict_unlock;
4358 if(nwritten < 0) {
4359 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4360 goto strict_unlock;
4363 if((nwritten == 0) && (numtowrite != 0)) {
4364 reply_nterror(req, NT_STATUS_DISK_FULL);
4365 goto strict_unlock;
4368 reply_outbuf(req, 1, 0);
4370 SSVAL(req->outbuf,smb_vwv0,nwritten);
4372 if (nwritten < (ssize_t)numtowrite) {
4373 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4374 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4377 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4379 strict_unlock:
4380 if (!fsp->print_file) {
4381 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4384 END_PROFILE(SMBwrite);
4385 return;
4388 /****************************************************************************
4389 Ensure a buffer is a valid writeX for recvfile purposes.
4390 ****************************************************************************/
4392 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4393 (2*14) + /* word count (including bcc) */ \
4394 1 /* pad byte */)
4396 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4397 const uint8_t *inbuf)
4399 size_t numtowrite;
4400 connection_struct *conn = NULL;
4401 unsigned int doff = 0;
4402 size_t len = smb_len_large(inbuf);
4404 if (is_encrypted_packet(sconn, inbuf)) {
4405 /* Can't do this on encrypted
4406 * connections. */
4407 return false;
4410 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4411 return false;
4414 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4415 CVAL(inbuf,smb_wct) != 14) {
4416 DEBUG(10,("is_valid_writeX_buffer: chained or "
4417 "invalid word length.\n"));
4418 return false;
4421 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4422 if (conn == NULL) {
4423 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4424 return false;
4426 if (IS_IPC(conn)) {
4427 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4428 return false;
4430 if (IS_PRINT(conn)) {
4431 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4432 return false;
4434 doff = SVAL(inbuf,smb_vwv11);
4436 numtowrite = SVAL(inbuf,smb_vwv10);
4438 if (len > doff && len - doff > 0xFFFF) {
4439 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4442 if (numtowrite == 0) {
4443 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4444 return false;
4447 /* Ensure the sizes match up. */
4448 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4449 /* no pad byte...old smbclient :-( */
4450 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4451 (unsigned int)doff,
4452 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4453 return false;
4456 if (len - doff != numtowrite) {
4457 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4458 "len = %u, doff = %u, numtowrite = %u\n",
4459 (unsigned int)len,
4460 (unsigned int)doff,
4461 (unsigned int)numtowrite ));
4462 return false;
4465 DEBUG(10,("is_valid_writeX_buffer: true "
4466 "len = %u, doff = %u, numtowrite = %u\n",
4467 (unsigned int)len,
4468 (unsigned int)doff,
4469 (unsigned int)numtowrite ));
4471 return true;
4474 /****************************************************************************
4475 Reply to a write and X.
4476 ****************************************************************************/
4478 void reply_write_and_X(struct smb_request *req)
4480 connection_struct *conn = req->conn;
4481 files_struct *fsp;
4482 struct lock_struct lock;
4483 SMB_OFF_T startpos;
4484 size_t numtowrite;
4485 bool write_through;
4486 ssize_t nwritten;
4487 unsigned int smb_doff;
4488 unsigned int smblen;
4489 const char *data;
4490 NTSTATUS status;
4491 int saved_errno = 0;
4493 START_PROFILE(SMBwriteX);
4495 if ((req->wct != 12) && (req->wct != 14)) {
4496 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4497 goto out;
4500 numtowrite = SVAL(req->vwv+10, 0);
4501 smb_doff = SVAL(req->vwv+11, 0);
4502 smblen = smb_len(req->inbuf);
4504 if (req->unread_bytes > 0xFFFF ||
4505 (smblen > smb_doff &&
4506 smblen - smb_doff > 0xFFFF)) {
4507 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4510 if (req->unread_bytes) {
4511 /* Can't do a recvfile write on IPC$ */
4512 if (IS_IPC(conn)) {
4513 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4514 goto out;
4516 if (numtowrite != req->unread_bytes) {
4517 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4518 goto out;
4520 } else {
4521 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4522 smb_doff + numtowrite > smblen) {
4523 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4524 goto out;
4528 /* If it's an IPC, pass off the pipe handler. */
4529 if (IS_IPC(conn)) {
4530 if (req->unread_bytes) {
4531 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4532 goto out;
4534 reply_pipe_write_and_X(req);
4535 goto out;
4538 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4539 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4540 write_through = BITSETW(req->vwv+7,0);
4542 if (!check_fsp(conn, req, fsp)) {
4543 goto out;
4546 if (!CHECK_WRITE(fsp)) {
4547 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4548 goto out;
4551 data = smb_base(req->inbuf) + smb_doff;
4553 if(req->wct == 14) {
4554 #ifdef LARGE_SMB_OFF_T
4556 * This is a large offset (64 bit) write.
4558 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4560 #else /* !LARGE_SMB_OFF_T */
4563 * Ensure we haven't been sent a >32 bit offset.
4566 if(IVAL(req->vwv+12, 0) != 0) {
4567 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4568 "used and we don't support 64 bit offsets.\n",
4569 (unsigned int)IVAL(req->vwv+12, 0) ));
4570 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4571 goto out;
4574 #endif /* LARGE_SMB_OFF_T */
4577 /* X/Open SMB protocol says that, unlike SMBwrite
4578 if the length is zero then NO truncation is
4579 done, just a write of zero. To truncate a file,
4580 use SMBwrite. */
4582 if(numtowrite == 0) {
4583 nwritten = 0;
4584 } else {
4585 if (req->unread_bytes == 0) {
4586 status = schedule_aio_write_and_X(conn,
4587 req,
4588 fsp,
4589 data,
4590 startpos,
4591 numtowrite);
4593 if (NT_STATUS_IS_OK(status)) {
4594 /* write scheduled - we're done. */
4595 goto out;
4597 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4598 /* Real error - report to client. */
4599 reply_nterror(req, status);
4600 goto out;
4602 /* NT_STATUS_RETRY - fall through to sync write. */
4605 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4606 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4607 &lock);
4609 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4610 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4611 goto out;
4614 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4615 saved_errno = errno;
4617 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4620 if(nwritten < 0) {
4621 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4622 goto out;
4625 if((nwritten == 0) && (numtowrite != 0)) {
4626 reply_nterror(req, NT_STATUS_DISK_FULL);
4627 goto out;
4630 reply_outbuf(req, 6, 0);
4631 SSVAL(req->outbuf,smb_vwv2,nwritten);
4632 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4634 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4635 fsp->fnum, (int)numtowrite, (int)nwritten));
4637 status = sync_file(conn, fsp, write_through);
4638 if (!NT_STATUS_IS_OK(status)) {
4639 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4640 fsp_str_dbg(fsp), nt_errstr(status)));
4641 reply_nterror(req, status);
4642 goto out;
4645 END_PROFILE(SMBwriteX);
4646 chain_reply(req);
4647 return;
4649 out:
4650 if (req->unread_bytes) {
4651 /* writeX failed. drain socket. */
4652 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4653 req->unread_bytes) {
4654 smb_panic("failed to drain pending bytes");
4656 req->unread_bytes = 0;
4659 END_PROFILE(SMBwriteX);
4660 return;
4663 /****************************************************************************
4664 Reply to a lseek.
4665 ****************************************************************************/
4667 void reply_lseek(struct smb_request *req)
4669 connection_struct *conn = req->conn;
4670 SMB_OFF_T startpos;
4671 SMB_OFF_T res= -1;
4672 int mode,umode;
4673 files_struct *fsp;
4675 START_PROFILE(SMBlseek);
4677 if (req->wct < 4) {
4678 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4679 END_PROFILE(SMBlseek);
4680 return;
4683 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4685 if (!check_fsp(conn, req, fsp)) {
4686 return;
4689 flush_write_cache(fsp, SEEK_FLUSH);
4691 mode = SVAL(req->vwv+1, 0) & 3;
4692 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4693 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4695 switch (mode) {
4696 case 0:
4697 umode = SEEK_SET;
4698 res = startpos;
4699 break;
4700 case 1:
4701 umode = SEEK_CUR;
4702 res = fsp->fh->pos + startpos;
4703 break;
4704 case 2:
4705 umode = SEEK_END;
4706 break;
4707 default:
4708 umode = SEEK_SET;
4709 res = startpos;
4710 break;
4713 if (umode == SEEK_END) {
4714 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4715 if(errno == EINVAL) {
4716 SMB_OFF_T current_pos = startpos;
4718 if(fsp_stat(fsp) == -1) {
4719 reply_nterror(req,
4720 map_nt_error_from_unix(errno));
4721 END_PROFILE(SMBlseek);
4722 return;
4725 current_pos += fsp->fsp_name->st.st_ex_size;
4726 if(current_pos < 0)
4727 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4731 if(res == -1) {
4732 reply_nterror(req, map_nt_error_from_unix(errno));
4733 END_PROFILE(SMBlseek);
4734 return;
4738 fsp->fh->pos = res;
4740 reply_outbuf(req, 2, 0);
4741 SIVAL(req->outbuf,smb_vwv0,res);
4743 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4744 fsp->fnum, (double)startpos, (double)res, mode));
4746 END_PROFILE(SMBlseek);
4747 return;
4750 /****************************************************************************
4751 Reply to a flush.
4752 ****************************************************************************/
4754 void reply_flush(struct smb_request *req)
4756 connection_struct *conn = req->conn;
4757 uint16 fnum;
4758 files_struct *fsp;
4760 START_PROFILE(SMBflush);
4762 if (req->wct < 1) {
4763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4764 return;
4767 fnum = SVAL(req->vwv+0, 0);
4768 fsp = file_fsp(req, fnum);
4770 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4771 return;
4774 if (!fsp) {
4775 file_sync_all(conn);
4776 } else {
4777 NTSTATUS status = sync_file(conn, fsp, True);
4778 if (!NT_STATUS_IS_OK(status)) {
4779 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4780 fsp_str_dbg(fsp), nt_errstr(status)));
4781 reply_nterror(req, status);
4782 END_PROFILE(SMBflush);
4783 return;
4787 reply_outbuf(req, 0, 0);
4789 DEBUG(3,("flush\n"));
4790 END_PROFILE(SMBflush);
4791 return;
4794 /****************************************************************************
4795 Reply to a exit.
4796 conn POINTER CAN BE NULL HERE !
4797 ****************************************************************************/
4799 void reply_exit(struct smb_request *req)
4801 START_PROFILE(SMBexit);
4803 file_close_pid(req->sconn, req->smbpid, req->vuid);
4805 reply_outbuf(req, 0, 0);
4807 DEBUG(3,("exit\n"));
4809 END_PROFILE(SMBexit);
4810 return;
4813 /****************************************************************************
4814 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4815 ****************************************************************************/
4817 void reply_close(struct smb_request *req)
4819 connection_struct *conn = req->conn;
4820 NTSTATUS status = NT_STATUS_OK;
4821 files_struct *fsp = NULL;
4822 START_PROFILE(SMBclose);
4824 if (req->wct < 3) {
4825 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4826 END_PROFILE(SMBclose);
4827 return;
4830 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4833 * We can only use check_fsp if we know it's not a directory.
4836 if (!check_fsp_open(conn, req, fsp)) {
4837 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4838 END_PROFILE(SMBclose);
4839 return;
4842 if(fsp->is_directory) {
4844 * Special case - close NT SMB directory handle.
4846 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4847 status = close_file(req, fsp, NORMAL_CLOSE);
4848 } else {
4849 time_t t;
4851 * Close ordinary file.
4854 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4855 fsp->fh->fd, fsp->fnum,
4856 conn->num_files_open));
4859 * Take care of any time sent in the close.
4862 t = srv_make_unix_date3(req->vwv+1);
4863 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4866 * close_file() returns the unix errno if an error
4867 * was detected on close - normally this is due to
4868 * a disk full error. If not then it was probably an I/O error.
4871 status = close_file(req, fsp, NORMAL_CLOSE);
4874 if (!NT_STATUS_IS_OK(status)) {
4875 reply_nterror(req, status);
4876 END_PROFILE(SMBclose);
4877 return;
4880 reply_outbuf(req, 0, 0);
4881 END_PROFILE(SMBclose);
4882 return;
4885 /****************************************************************************
4886 Reply to a writeclose (Core+ protocol).
4887 ****************************************************************************/
4889 void reply_writeclose(struct smb_request *req)
4891 connection_struct *conn = req->conn;
4892 size_t numtowrite;
4893 ssize_t nwritten = -1;
4894 NTSTATUS close_status = NT_STATUS_OK;
4895 SMB_OFF_T startpos;
4896 const char *data;
4897 struct timespec mtime;
4898 files_struct *fsp;
4899 struct lock_struct lock;
4901 START_PROFILE(SMBwriteclose);
4903 if (req->wct < 6) {
4904 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4905 END_PROFILE(SMBwriteclose);
4906 return;
4909 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4911 if (!check_fsp(conn, req, fsp)) {
4912 END_PROFILE(SMBwriteclose);
4913 return;
4915 if (!CHECK_WRITE(fsp)) {
4916 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4917 END_PROFILE(SMBwriteclose);
4918 return;
4921 numtowrite = SVAL(req->vwv+1, 0);
4922 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4923 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4924 data = (const char *)req->buf + 1;
4926 if (!fsp->print_file) {
4927 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4928 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4929 &lock);
4931 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4932 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4933 END_PROFILE(SMBwriteclose);
4934 return;
4938 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4940 set_close_write_time(fsp, mtime);
4943 * More insanity. W2K only closes the file if writelen > 0.
4944 * JRA.
4947 if (numtowrite) {
4948 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4949 "file %s\n", fsp_str_dbg(fsp)));
4950 close_status = close_file(req, fsp, NORMAL_CLOSE);
4953 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4954 fsp->fnum, (int)numtowrite, (int)nwritten,
4955 conn->num_files_open));
4957 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4958 reply_nterror(req, NT_STATUS_DISK_FULL);
4959 goto strict_unlock;
4962 if(!NT_STATUS_IS_OK(close_status)) {
4963 reply_nterror(req, close_status);
4964 goto strict_unlock;
4967 reply_outbuf(req, 1, 0);
4969 SSVAL(req->outbuf,smb_vwv0,nwritten);
4971 strict_unlock:
4972 if (numtowrite && !fsp->print_file) {
4973 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4976 END_PROFILE(SMBwriteclose);
4977 return;
4980 #undef DBGC_CLASS
4981 #define DBGC_CLASS DBGC_LOCKING
4983 /****************************************************************************
4984 Reply to a lock.
4985 ****************************************************************************/
4987 void reply_lock(struct smb_request *req)
4989 connection_struct *conn = req->conn;
4990 uint64_t count,offset;
4991 NTSTATUS status;
4992 files_struct *fsp;
4993 struct byte_range_lock *br_lck = NULL;
4995 START_PROFILE(SMBlock);
4997 if (req->wct < 5) {
4998 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4999 END_PROFILE(SMBlock);
5000 return;
5003 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5005 if (!check_fsp(conn, req, fsp)) {
5006 END_PROFILE(SMBlock);
5007 return;
5010 count = (uint64_t)IVAL(req->vwv+1, 0);
5011 offset = (uint64_t)IVAL(req->vwv+3, 0);
5013 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5014 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5016 br_lck = do_lock(req->sconn->msg_ctx,
5017 fsp,
5018 (uint64_t)req->smbpid,
5019 count,
5020 offset,
5021 WRITE_LOCK,
5022 WINDOWS_LOCK,
5023 False, /* Non-blocking lock. */
5024 &status,
5025 NULL,
5026 NULL);
5028 TALLOC_FREE(br_lck);
5030 if (NT_STATUS_V(status)) {
5031 reply_nterror(req, status);
5032 END_PROFILE(SMBlock);
5033 return;
5036 reply_outbuf(req, 0, 0);
5038 END_PROFILE(SMBlock);
5039 return;
5042 /****************************************************************************
5043 Reply to a unlock.
5044 ****************************************************************************/
5046 void reply_unlock(struct smb_request *req)
5048 connection_struct *conn = req->conn;
5049 uint64_t count,offset;
5050 NTSTATUS status;
5051 files_struct *fsp;
5053 START_PROFILE(SMBunlock);
5055 if (req->wct < 5) {
5056 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5057 END_PROFILE(SMBunlock);
5058 return;
5061 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5063 if (!check_fsp(conn, req, fsp)) {
5064 END_PROFILE(SMBunlock);
5065 return;
5068 count = (uint64_t)IVAL(req->vwv+1, 0);
5069 offset = (uint64_t)IVAL(req->vwv+3, 0);
5071 status = do_unlock(req->sconn->msg_ctx,
5072 fsp,
5073 (uint64_t)req->smbpid,
5074 count,
5075 offset,
5076 WINDOWS_LOCK);
5078 if (NT_STATUS_V(status)) {
5079 reply_nterror(req, status);
5080 END_PROFILE(SMBunlock);
5081 return;
5084 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5085 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5087 reply_outbuf(req, 0, 0);
5089 END_PROFILE(SMBunlock);
5090 return;
5093 #undef DBGC_CLASS
5094 #define DBGC_CLASS DBGC_ALL
5096 /****************************************************************************
5097 Reply to a tdis.
5098 conn POINTER CAN BE NULL HERE !
5099 ****************************************************************************/
5101 void reply_tdis(struct smb_request *req)
5103 connection_struct *conn = req->conn;
5104 START_PROFILE(SMBtdis);
5106 if (!conn) {
5107 DEBUG(4,("Invalid connection in tdis\n"));
5108 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5109 END_PROFILE(SMBtdis);
5110 return;
5113 conn->used = False;
5115 close_cnum(conn,req->vuid);
5116 req->conn = NULL;
5118 reply_outbuf(req, 0, 0);
5119 END_PROFILE(SMBtdis);
5120 return;
5123 /****************************************************************************
5124 Reply to a echo.
5125 conn POINTER CAN BE NULL HERE !
5126 ****************************************************************************/
5128 void reply_echo(struct smb_request *req)
5130 connection_struct *conn = req->conn;
5131 struct smb_perfcount_data local_pcd;
5132 struct smb_perfcount_data *cur_pcd;
5133 int smb_reverb;
5134 int seq_num;
5136 START_PROFILE(SMBecho);
5138 smb_init_perfcount_data(&local_pcd);
5140 if (req->wct < 1) {
5141 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5142 END_PROFILE(SMBecho);
5143 return;
5146 smb_reverb = SVAL(req->vwv+0, 0);
5148 reply_outbuf(req, 1, req->buflen);
5150 /* copy any incoming data back out */
5151 if (req->buflen > 0) {
5152 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5155 if (smb_reverb > 100) {
5156 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5157 smb_reverb = 100;
5160 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5162 /* this makes sure we catch the request pcd */
5163 if (seq_num == smb_reverb) {
5164 cur_pcd = &req->pcd;
5165 } else {
5166 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5167 cur_pcd = &local_pcd;
5170 SSVAL(req->outbuf,smb_vwv0,seq_num);
5172 show_msg((char *)req->outbuf);
5173 if (!srv_send_smb(req->sconn,
5174 (char *)req->outbuf,
5175 true, req->seqnum+1,
5176 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5177 cur_pcd))
5178 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5181 DEBUG(3,("echo %d times\n", smb_reverb));
5183 TALLOC_FREE(req->outbuf);
5185 END_PROFILE(SMBecho);
5186 return;
5189 /****************************************************************************
5190 Reply to a printopen.
5191 ****************************************************************************/
5193 void reply_printopen(struct smb_request *req)
5195 connection_struct *conn = req->conn;
5196 files_struct *fsp;
5197 NTSTATUS status;
5199 START_PROFILE(SMBsplopen);
5201 if (req->wct < 2) {
5202 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5203 END_PROFILE(SMBsplopen);
5204 return;
5207 if (!CAN_PRINT(conn)) {
5208 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5209 END_PROFILE(SMBsplopen);
5210 return;
5213 status = file_new(req, conn, &fsp);
5214 if(!NT_STATUS_IS_OK(status)) {
5215 reply_nterror(req, status);
5216 END_PROFILE(SMBsplopen);
5217 return;
5220 /* Open for exclusive use, write only. */
5221 status = print_spool_open(fsp, NULL, req->vuid);
5223 if (!NT_STATUS_IS_OK(status)) {
5224 file_free(req, fsp);
5225 reply_nterror(req, status);
5226 END_PROFILE(SMBsplopen);
5227 return;
5230 reply_outbuf(req, 1, 0);
5231 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5233 DEBUG(3,("openprint fd=%d fnum=%d\n",
5234 fsp->fh->fd, fsp->fnum));
5236 END_PROFILE(SMBsplopen);
5237 return;
5240 /****************************************************************************
5241 Reply to a printclose.
5242 ****************************************************************************/
5244 void reply_printclose(struct smb_request *req)
5246 connection_struct *conn = req->conn;
5247 files_struct *fsp;
5248 NTSTATUS status;
5250 START_PROFILE(SMBsplclose);
5252 if (req->wct < 1) {
5253 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5254 END_PROFILE(SMBsplclose);
5255 return;
5258 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5260 if (!check_fsp(conn, req, fsp)) {
5261 END_PROFILE(SMBsplclose);
5262 return;
5265 if (!CAN_PRINT(conn)) {
5266 reply_force_doserror(req, ERRSRV, ERRerror);
5267 END_PROFILE(SMBsplclose);
5268 return;
5271 DEBUG(3,("printclose fd=%d fnum=%d\n",
5272 fsp->fh->fd,fsp->fnum));
5274 status = close_file(req, fsp, NORMAL_CLOSE);
5276 if(!NT_STATUS_IS_OK(status)) {
5277 reply_nterror(req, status);
5278 END_PROFILE(SMBsplclose);
5279 return;
5282 reply_outbuf(req, 0, 0);
5284 END_PROFILE(SMBsplclose);
5285 return;
5288 /****************************************************************************
5289 Reply to a printqueue.
5290 ****************************************************************************/
5292 void reply_printqueue(struct smb_request *req)
5294 connection_struct *conn = req->conn;
5295 int max_count;
5296 int start_index;
5298 START_PROFILE(SMBsplretq);
5300 if (req->wct < 2) {
5301 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5302 END_PROFILE(SMBsplretq);
5303 return;
5306 max_count = SVAL(req->vwv+0, 0);
5307 start_index = SVAL(req->vwv+1, 0);
5309 /* we used to allow the client to get the cnum wrong, but that
5310 is really quite gross and only worked when there was only
5311 one printer - I think we should now only accept it if they
5312 get it right (tridge) */
5313 if (!CAN_PRINT(conn)) {
5314 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5315 END_PROFILE(SMBsplretq);
5316 return;
5319 reply_outbuf(req, 2, 3);
5320 SSVAL(req->outbuf,smb_vwv0,0);
5321 SSVAL(req->outbuf,smb_vwv1,0);
5322 SCVAL(smb_buf(req->outbuf),0,1);
5323 SSVAL(smb_buf(req->outbuf),1,0);
5325 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5326 start_index, max_count));
5329 TALLOC_CTX *mem_ctx = talloc_tos();
5330 NTSTATUS status;
5331 WERROR werr;
5332 const char *sharename = lp_servicename(SNUM(conn));
5333 struct rpc_pipe_client *cli = NULL;
5334 struct dcerpc_binding_handle *b = NULL;
5335 struct policy_handle handle;
5336 struct spoolss_DevmodeContainer devmode_ctr;
5337 union spoolss_JobInfo *info;
5338 uint32_t count;
5339 uint32_t num_to_get;
5340 uint32_t first;
5341 uint32_t i;
5343 ZERO_STRUCT(handle);
5345 status = rpc_pipe_open_interface(conn,
5346 &ndr_table_spoolss.syntax_id,
5347 conn->session_info,
5348 conn->sconn->remote_address,
5349 conn->sconn->msg_ctx,
5350 &cli);
5351 if (!NT_STATUS_IS_OK(status)) {
5352 DEBUG(0, ("reply_printqueue: "
5353 "could not connect to spoolss: %s\n",
5354 nt_errstr(status)));
5355 reply_nterror(req, status);
5356 goto out;
5358 b = cli->binding_handle;
5360 ZERO_STRUCT(devmode_ctr);
5362 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5363 sharename,
5364 NULL, devmode_ctr,
5365 SEC_FLAG_MAXIMUM_ALLOWED,
5366 &handle,
5367 &werr);
5368 if (!NT_STATUS_IS_OK(status)) {
5369 reply_nterror(req, status);
5370 goto out;
5372 if (!W_ERROR_IS_OK(werr)) {
5373 reply_nterror(req, werror_to_ntstatus(werr));
5374 goto out;
5377 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5378 &handle,
5379 0, /* firstjob */
5380 0xff, /* numjobs */
5381 2, /* level */
5382 0, /* offered */
5383 &count,
5384 &info);
5385 if (!W_ERROR_IS_OK(werr)) {
5386 reply_nterror(req, werror_to_ntstatus(werr));
5387 goto out;
5390 if (max_count > 0) {
5391 first = start_index;
5392 } else {
5393 first = start_index + max_count + 1;
5396 if (first >= count) {
5397 num_to_get = first;
5398 } else {
5399 num_to_get = first + MIN(ABS(max_count), count - first);
5402 for (i = first; i < num_to_get; i++) {
5403 char blob[28];
5404 char *p = blob;
5405 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5406 int qstatus;
5407 uint16_t qrapjobid = pjobid_to_rap(sharename,
5408 info[i].info2.job_id);
5410 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5411 qstatus = 2;
5412 } else {
5413 qstatus = 3;
5416 srv_put_dos_date2(p, 0, qtime);
5417 SCVAL(p, 4, qstatus);
5418 SSVAL(p, 5, qrapjobid);
5419 SIVAL(p, 7, info[i].info2.size);
5420 SCVAL(p, 11, 0);
5421 srvstr_push(blob, req->flags2, p+12,
5422 info[i].info2.notify_name, 16, STR_ASCII);
5424 if (message_push_blob(
5425 &req->outbuf,
5426 data_blob_const(
5427 blob, sizeof(blob))) == -1) {
5428 reply_nterror(req, NT_STATUS_NO_MEMORY);
5429 goto out;
5433 if (count > 0) {
5434 SSVAL(req->outbuf,smb_vwv0,count);
5435 SSVAL(req->outbuf,smb_vwv1,
5436 (max_count>0?first+count:first-1));
5437 SCVAL(smb_buf(req->outbuf),0,1);
5438 SSVAL(smb_buf(req->outbuf),1,28*count);
5442 DEBUG(3, ("%u entries returned in queue\n",
5443 (unsigned)count));
5445 out:
5446 if (b && is_valid_policy_hnd(&handle)) {
5447 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5452 END_PROFILE(SMBsplretq);
5453 return;
5456 /****************************************************************************
5457 Reply to a printwrite.
5458 ****************************************************************************/
5460 void reply_printwrite(struct smb_request *req)
5462 connection_struct *conn = req->conn;
5463 int numtowrite;
5464 const char *data;
5465 files_struct *fsp;
5467 START_PROFILE(SMBsplwr);
5469 if (req->wct < 1) {
5470 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5471 END_PROFILE(SMBsplwr);
5472 return;
5475 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5477 if (!check_fsp(conn, req, fsp)) {
5478 END_PROFILE(SMBsplwr);
5479 return;
5482 if (!fsp->print_file) {
5483 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5484 END_PROFILE(SMBsplwr);
5485 return;
5488 if (!CHECK_WRITE(fsp)) {
5489 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5490 END_PROFILE(SMBsplwr);
5491 return;
5494 numtowrite = SVAL(req->buf, 1);
5496 if (req->buflen < numtowrite + 3) {
5497 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5498 END_PROFILE(SMBsplwr);
5499 return;
5502 data = (const char *)req->buf + 3;
5504 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5505 reply_nterror(req, map_nt_error_from_unix(errno));
5506 END_PROFILE(SMBsplwr);
5507 return;
5510 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5512 END_PROFILE(SMBsplwr);
5513 return;
5516 /****************************************************************************
5517 Reply to a mkdir.
5518 ****************************************************************************/
5520 void reply_mkdir(struct smb_request *req)
5522 connection_struct *conn = req->conn;
5523 struct smb_filename *smb_dname = NULL;
5524 char *directory = NULL;
5525 NTSTATUS status;
5526 TALLOC_CTX *ctx = talloc_tos();
5528 START_PROFILE(SMBmkdir);
5530 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5531 STR_TERMINATE, &status);
5532 if (!NT_STATUS_IS_OK(status)) {
5533 reply_nterror(req, status);
5534 goto out;
5537 status = filename_convert(ctx, conn,
5538 req->flags2 & FLAGS2_DFS_PATHNAMES,
5539 directory,
5541 NULL,
5542 &smb_dname);
5543 if (!NT_STATUS_IS_OK(status)) {
5544 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5545 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5546 ERRSRV, ERRbadpath);
5547 goto out;
5549 reply_nterror(req, status);
5550 goto out;
5553 status = create_directory(conn, req, smb_dname);
5555 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5557 if (!NT_STATUS_IS_OK(status)) {
5559 if (!use_nt_status()
5560 && NT_STATUS_EQUAL(status,
5561 NT_STATUS_OBJECT_NAME_COLLISION)) {
5563 * Yes, in the DOS error code case we get a
5564 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5565 * samba4 torture test.
5567 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5570 reply_nterror(req, status);
5571 goto out;
5574 reply_outbuf(req, 0, 0);
5576 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5577 out:
5578 TALLOC_FREE(smb_dname);
5579 END_PROFILE(SMBmkdir);
5580 return;
5583 /****************************************************************************
5584 Reply to a rmdir.
5585 ****************************************************************************/
5587 void reply_rmdir(struct smb_request *req)
5589 connection_struct *conn = req->conn;
5590 struct smb_filename *smb_dname = NULL;
5591 char *directory = NULL;
5592 NTSTATUS status;
5593 TALLOC_CTX *ctx = talloc_tos();
5594 files_struct *fsp = NULL;
5595 int info = 0;
5596 struct smbd_server_connection *sconn = req->sconn;
5598 START_PROFILE(SMBrmdir);
5600 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5601 STR_TERMINATE, &status);
5602 if (!NT_STATUS_IS_OK(status)) {
5603 reply_nterror(req, status);
5604 goto out;
5607 status = filename_convert(ctx, conn,
5608 req->flags2 & FLAGS2_DFS_PATHNAMES,
5609 directory,
5611 NULL,
5612 &smb_dname);
5613 if (!NT_STATUS_IS_OK(status)) {
5614 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5615 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5616 ERRSRV, ERRbadpath);
5617 goto out;
5619 reply_nterror(req, status);
5620 goto out;
5623 if (is_ntfs_stream_smb_fname(smb_dname)) {
5624 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5625 goto out;
5628 status = SMB_VFS_CREATE_FILE(
5629 conn, /* conn */
5630 req, /* req */
5631 0, /* root_dir_fid */
5632 smb_dname, /* fname */
5633 DELETE_ACCESS, /* access_mask */
5634 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5635 FILE_SHARE_DELETE),
5636 FILE_OPEN, /* create_disposition*/
5637 FILE_DIRECTORY_FILE, /* create_options */
5638 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5639 0, /* oplock_request */
5640 0, /* allocation_size */
5641 0, /* private_flags */
5642 NULL, /* sd */
5643 NULL, /* ea_list */
5644 &fsp, /* result */
5645 &info); /* pinfo */
5647 if (!NT_STATUS_IS_OK(status)) {
5648 if (open_was_deferred(req->sconn, req->mid)) {
5649 /* We have re-scheduled this call. */
5650 goto out;
5652 reply_nterror(req, status);
5653 goto out;
5656 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5657 if (!NT_STATUS_IS_OK(status)) {
5658 close_file(req, fsp, ERROR_CLOSE);
5659 reply_nterror(req, status);
5660 goto out;
5663 if (!set_delete_on_close(fsp, true, conn->session_info->unix_token)) {
5664 close_file(req, fsp, ERROR_CLOSE);
5665 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5666 goto out;
5669 status = close_file(req, fsp, NORMAL_CLOSE);
5670 if (!NT_STATUS_IS_OK(status)) {
5671 reply_nterror(req, status);
5672 } else {
5673 reply_outbuf(req, 0, 0);
5676 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5678 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5679 out:
5680 TALLOC_FREE(smb_dname);
5681 END_PROFILE(SMBrmdir);
5682 return;
5685 /*******************************************************************
5686 Resolve wildcards in a filename rename.
5687 ********************************************************************/
5689 static bool resolve_wildcards(TALLOC_CTX *ctx,
5690 const char *name1,
5691 const char *name2,
5692 char **pp_newname)
5694 char *name2_copy = NULL;
5695 char *root1 = NULL;
5696 char *root2 = NULL;
5697 char *ext1 = NULL;
5698 char *ext2 = NULL;
5699 char *p,*p2, *pname1, *pname2;
5701 name2_copy = talloc_strdup(ctx, name2);
5702 if (!name2_copy) {
5703 return False;
5706 pname1 = strrchr_m(name1,'/');
5707 pname2 = strrchr_m(name2_copy,'/');
5709 if (!pname1 || !pname2) {
5710 return False;
5713 /* Truncate the copy of name2 at the last '/' */
5714 *pname2 = '\0';
5716 /* Now go past the '/' */
5717 pname1++;
5718 pname2++;
5720 root1 = talloc_strdup(ctx, pname1);
5721 root2 = talloc_strdup(ctx, pname2);
5723 if (!root1 || !root2) {
5724 return False;
5727 p = strrchr_m(root1,'.');
5728 if (p) {
5729 *p = 0;
5730 ext1 = talloc_strdup(ctx, p+1);
5731 } else {
5732 ext1 = talloc_strdup(ctx, "");
5734 p = strrchr_m(root2,'.');
5735 if (p) {
5736 *p = 0;
5737 ext2 = talloc_strdup(ctx, p+1);
5738 } else {
5739 ext2 = talloc_strdup(ctx, "");
5742 if (!ext1 || !ext2) {
5743 return False;
5746 p = root1;
5747 p2 = root2;
5748 while (*p2) {
5749 if (*p2 == '?') {
5750 /* Hmmm. Should this be mb-aware ? */
5751 *p2 = *p;
5752 p2++;
5753 } else if (*p2 == '*') {
5754 *p2 = '\0';
5755 root2 = talloc_asprintf(ctx, "%s%s",
5756 root2,
5758 if (!root2) {
5759 return False;
5761 break;
5762 } else {
5763 p2++;
5765 if (*p) {
5766 p++;
5770 p = ext1;
5771 p2 = ext2;
5772 while (*p2) {
5773 if (*p2 == '?') {
5774 /* Hmmm. Should this be mb-aware ? */
5775 *p2 = *p;
5776 p2++;
5777 } else if (*p2 == '*') {
5778 *p2 = '\0';
5779 ext2 = talloc_asprintf(ctx, "%s%s",
5780 ext2,
5782 if (!ext2) {
5783 return False;
5785 break;
5786 } else {
5787 p2++;
5789 if (*p) {
5790 p++;
5794 if (*ext2) {
5795 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5796 name2_copy,
5797 root2,
5798 ext2);
5799 } else {
5800 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5801 name2_copy,
5802 root2);
5805 if (!*pp_newname) {
5806 return False;
5809 return True;
5812 /****************************************************************************
5813 Ensure open files have their names updated. Updated to notify other smbd's
5814 asynchronously.
5815 ****************************************************************************/
5817 static void rename_open_files(connection_struct *conn,
5818 struct share_mode_lock *lck,
5819 uint32_t orig_name_hash,
5820 const struct smb_filename *smb_fname_dst)
5822 files_struct *fsp;
5823 bool did_rename = False;
5824 NTSTATUS status;
5825 uint32_t new_name_hash = 0;
5827 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
5828 fsp = file_find_di_next(fsp)) {
5829 /* fsp_name is a relative path under the fsp. To change this for other
5830 sharepaths we need to manipulate relative paths. */
5831 /* TODO - create the absolute path and manipulate the newname
5832 relative to the sharepath. */
5833 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5834 continue;
5836 if (fsp->name_hash != orig_name_hash) {
5837 continue;
5839 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5840 "(file_id %s) from %s -> %s\n", fsp->fnum,
5841 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5842 smb_fname_str_dbg(smb_fname_dst)));
5844 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5845 if (NT_STATUS_IS_OK(status)) {
5846 did_rename = True;
5847 new_name_hash = fsp->name_hash;
5851 if (!did_rename) {
5852 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5853 "for %s\n", file_id_string_tos(&lck->data->id),
5854 smb_fname_str_dbg(smb_fname_dst)));
5857 /* Send messages to all smbd's (not ourself) that the name has changed. */
5858 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5859 orig_name_hash, new_name_hash,
5860 smb_fname_dst);
5864 /****************************************************************************
5865 We need to check if the source path is a parent directory of the destination
5866 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5867 refuse the rename with a sharing violation. Under UNIX the above call can
5868 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5869 probably need to check that the client is a Windows one before disallowing
5870 this as a UNIX client (one with UNIX extensions) can know the source is a
5871 symlink and make this decision intelligently. Found by an excellent bug
5872 report from <AndyLiebman@aol.com>.
5873 ****************************************************************************/
5875 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5876 const struct smb_filename *smb_fname_dst)
5878 const char *psrc = smb_fname_src->base_name;
5879 const char *pdst = smb_fname_dst->base_name;
5880 size_t slen;
5882 if (psrc[0] == '.' && psrc[1] == '/') {
5883 psrc += 2;
5885 if (pdst[0] == '.' && pdst[1] == '/') {
5886 pdst += 2;
5888 if ((slen = strlen(psrc)) > strlen(pdst)) {
5889 return False;
5891 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5895 * Do the notify calls from a rename
5898 static void notify_rename(connection_struct *conn, bool is_dir,
5899 const struct smb_filename *smb_fname_src,
5900 const struct smb_filename *smb_fname_dst)
5902 char *parent_dir_src = NULL;
5903 char *parent_dir_dst = NULL;
5904 uint32 mask;
5906 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5907 : FILE_NOTIFY_CHANGE_FILE_NAME;
5909 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5910 &parent_dir_src, NULL) ||
5911 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5912 &parent_dir_dst, NULL)) {
5913 goto out;
5916 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5917 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5918 smb_fname_src->base_name);
5919 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5920 smb_fname_dst->base_name);
5922 else {
5923 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5924 smb_fname_src->base_name);
5925 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5926 smb_fname_dst->base_name);
5929 /* this is a strange one. w2k3 gives an additional event for
5930 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5931 files, but not directories */
5932 if (!is_dir) {
5933 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5934 FILE_NOTIFY_CHANGE_ATTRIBUTES
5935 |FILE_NOTIFY_CHANGE_CREATION,
5936 smb_fname_dst->base_name);
5938 out:
5939 TALLOC_FREE(parent_dir_src);
5940 TALLOC_FREE(parent_dir_dst);
5943 /****************************************************************************
5944 Returns an error if the parent directory for a filename is open in an
5945 incompatible way.
5946 ****************************************************************************/
5948 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
5949 const struct smb_filename *smb_fname_dst_in)
5951 char *parent_dir = NULL;
5952 struct smb_filename smb_fname_parent;
5953 struct file_id id;
5954 files_struct *fsp = NULL;
5955 int ret;
5957 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
5958 &parent_dir, NULL)) {
5959 return NT_STATUS_NO_MEMORY;
5961 ZERO_STRUCT(smb_fname_parent);
5962 smb_fname_parent.base_name = parent_dir;
5964 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
5965 if (ret == -1) {
5966 return map_nt_error_from_unix(errno);
5970 * We're only checking on this smbd here, mostly good
5971 * enough.. and will pass tests.
5974 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
5975 for (fsp = file_find_di_first(conn->sconn, id); fsp;
5976 fsp = file_find_di_next(fsp)) {
5977 if (fsp->access_mask & DELETE_ACCESS) {
5978 return NT_STATUS_SHARING_VIOLATION;
5981 return NT_STATUS_OK;
5984 /****************************************************************************
5985 Rename an open file - given an fsp.
5986 ****************************************************************************/
5988 NTSTATUS rename_internals_fsp(connection_struct *conn,
5989 files_struct *fsp,
5990 const struct smb_filename *smb_fname_dst_in,
5991 uint32 attrs,
5992 bool replace_if_exists)
5994 TALLOC_CTX *ctx = talloc_tos();
5995 struct smb_filename *smb_fname_dst = NULL;
5996 NTSTATUS status = NT_STATUS_OK;
5997 struct share_mode_lock *lck = NULL;
5998 bool dst_exists, old_is_stream, new_is_stream;
6000 status = check_name(conn, smb_fname_dst_in->base_name);
6001 if (!NT_STATUS_IS_OK(status)) {
6002 return status;
6005 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6006 if (!NT_STATUS_IS_OK(status)) {
6007 return status;
6010 /* Make a copy of the dst smb_fname structs */
6012 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6013 if (!NT_STATUS_IS_OK(status)) {
6014 goto out;
6018 * Check for special case with case preserving and not
6019 * case sensitive. If the old last component differs from the original
6020 * last component only by case, then we should allow
6021 * the rename (user is trying to change the case of the
6022 * filename).
6024 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6025 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6026 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6027 char *last_slash;
6028 char *fname_dst_lcomp_base_mod = NULL;
6029 struct smb_filename *smb_fname_orig_lcomp = NULL;
6032 * Get the last component of the destination name.
6034 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6035 if (last_slash) {
6036 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6037 } else {
6038 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6040 if (!fname_dst_lcomp_base_mod) {
6041 status = NT_STATUS_NO_MEMORY;
6042 goto out;
6046 * Create an smb_filename struct using the original last
6047 * component of the destination.
6049 status = create_synthetic_smb_fname_split(ctx,
6050 smb_fname_dst->original_lcomp, NULL,
6051 &smb_fname_orig_lcomp);
6052 if (!NT_STATUS_IS_OK(status)) {
6053 TALLOC_FREE(fname_dst_lcomp_base_mod);
6054 goto out;
6057 /* If the base names only differ by case, use original. */
6058 if(!strcsequal(fname_dst_lcomp_base_mod,
6059 smb_fname_orig_lcomp->base_name)) {
6060 char *tmp;
6062 * Replace the modified last component with the
6063 * original.
6065 if (last_slash) {
6066 *last_slash = '\0'; /* Truncate at the '/' */
6067 tmp = talloc_asprintf(smb_fname_dst,
6068 "%s/%s",
6069 smb_fname_dst->base_name,
6070 smb_fname_orig_lcomp->base_name);
6071 } else {
6072 tmp = talloc_asprintf(smb_fname_dst,
6073 "%s",
6074 smb_fname_orig_lcomp->base_name);
6076 if (tmp == NULL) {
6077 status = NT_STATUS_NO_MEMORY;
6078 TALLOC_FREE(fname_dst_lcomp_base_mod);
6079 TALLOC_FREE(smb_fname_orig_lcomp);
6080 goto out;
6082 TALLOC_FREE(smb_fname_dst->base_name);
6083 smb_fname_dst->base_name = tmp;
6086 /* If the stream_names only differ by case, use original. */
6087 if(!strcsequal(smb_fname_dst->stream_name,
6088 smb_fname_orig_lcomp->stream_name)) {
6089 char *tmp = NULL;
6090 /* Use the original stream. */
6091 tmp = talloc_strdup(smb_fname_dst,
6092 smb_fname_orig_lcomp->stream_name);
6093 if (tmp == NULL) {
6094 status = NT_STATUS_NO_MEMORY;
6095 TALLOC_FREE(fname_dst_lcomp_base_mod);
6096 TALLOC_FREE(smb_fname_orig_lcomp);
6097 goto out;
6099 TALLOC_FREE(smb_fname_dst->stream_name);
6100 smb_fname_dst->stream_name = tmp;
6102 TALLOC_FREE(fname_dst_lcomp_base_mod);
6103 TALLOC_FREE(smb_fname_orig_lcomp);
6107 * If the src and dest names are identical - including case,
6108 * don't do the rename, just return success.
6111 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6112 strcsequal(fsp->fsp_name->stream_name,
6113 smb_fname_dst->stream_name)) {
6114 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6115 "- returning success\n",
6116 smb_fname_str_dbg(smb_fname_dst)));
6117 status = NT_STATUS_OK;
6118 goto out;
6121 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6122 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6124 /* Return the correct error code if both names aren't streams. */
6125 if (!old_is_stream && new_is_stream) {
6126 status = NT_STATUS_OBJECT_NAME_INVALID;
6127 goto out;
6130 if (old_is_stream && !new_is_stream) {
6131 status = NT_STATUS_INVALID_PARAMETER;
6132 goto out;
6135 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6137 if(!replace_if_exists && dst_exists) {
6138 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6139 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6140 smb_fname_str_dbg(smb_fname_dst)));
6141 status = NT_STATUS_OBJECT_NAME_COLLISION;
6142 goto out;
6145 if (dst_exists) {
6146 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6147 &smb_fname_dst->st);
6148 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6149 fileid);
6150 /* The file can be open when renaming a stream */
6151 if (dst_fsp && !new_is_stream) {
6152 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6153 status = NT_STATUS_ACCESS_DENIED;
6154 goto out;
6158 /* Ensure we have a valid stat struct for the source. */
6159 status = vfs_stat_fsp(fsp);
6160 if (!NT_STATUS_IS_OK(status)) {
6161 goto out;
6164 status = can_rename(conn, fsp, attrs);
6166 if (!NT_STATUS_IS_OK(status)) {
6167 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6168 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6169 smb_fname_str_dbg(smb_fname_dst)));
6170 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6171 status = NT_STATUS_ACCESS_DENIED;
6172 goto out;
6175 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6176 status = NT_STATUS_ACCESS_DENIED;
6179 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6182 * We have the file open ourselves, so not being able to get the
6183 * corresponding share mode lock is a fatal error.
6186 SMB_ASSERT(lck != NULL);
6188 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6189 uint32 create_options = fsp->fh->private_options;
6191 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6192 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6193 smb_fname_str_dbg(smb_fname_dst)));
6195 if (!lp_posix_pathnames() &&
6196 (lp_map_archive(SNUM(conn)) ||
6197 lp_store_dos_attributes(SNUM(conn)))) {
6198 /* We must set the archive bit on the newly
6199 renamed file. */
6200 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6201 uint32_t old_dosmode = dos_mode(conn,
6202 smb_fname_dst);
6203 file_set_dosmode(conn,
6204 smb_fname_dst,
6205 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6206 NULL,
6207 true);
6211 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6212 smb_fname_dst);
6214 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6217 * A rename acts as a new file create w.r.t. allowing an initial delete
6218 * on close, probably because in Windows there is a new handle to the
6219 * new file. If initial delete on close was requested but not
6220 * originally set, we need to set it here. This is probably not 100% correct,
6221 * but will work for the CIFSFS client which in non-posix mode
6222 * depends on these semantics. JRA.
6225 if (create_options & FILE_DELETE_ON_CLOSE) {
6226 status = can_set_delete_on_close(fsp, 0);
6228 if (NT_STATUS_IS_OK(status)) {
6229 /* Note that here we set the *inital* delete on close flag,
6230 * not the regular one. The magic gets handled in close. */
6231 fsp->initial_delete_on_close = True;
6234 TALLOC_FREE(lck);
6235 status = NT_STATUS_OK;
6236 goto out;
6239 TALLOC_FREE(lck);
6241 if (errno == ENOTDIR || errno == EISDIR) {
6242 status = NT_STATUS_OBJECT_NAME_COLLISION;
6243 } else {
6244 status = map_nt_error_from_unix(errno);
6247 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6248 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6249 smb_fname_str_dbg(smb_fname_dst)));
6251 out:
6252 TALLOC_FREE(smb_fname_dst);
6254 return status;
6257 /****************************************************************************
6258 The guts of the rename command, split out so it may be called by the NT SMB
6259 code.
6260 ****************************************************************************/
6262 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6263 connection_struct *conn,
6264 struct smb_request *req,
6265 struct smb_filename *smb_fname_src,
6266 struct smb_filename *smb_fname_dst,
6267 uint32 attrs,
6268 bool replace_if_exists,
6269 bool src_has_wild,
6270 bool dest_has_wild,
6271 uint32_t access_mask)
6273 char *fname_src_dir = NULL;
6274 char *fname_src_mask = NULL;
6275 int count=0;
6276 NTSTATUS status = NT_STATUS_OK;
6277 struct smb_Dir *dir_hnd = NULL;
6278 const char *dname = NULL;
6279 char *talloced = NULL;
6280 long offset = 0;
6281 int create_options = 0;
6282 bool posix_pathnames = lp_posix_pathnames();
6285 * Split the old name into directory and last component
6286 * strings. Note that unix_convert may have stripped off a
6287 * leading ./ from both name and newname if the rename is
6288 * at the root of the share. We need to make sure either both
6289 * name and newname contain a / character or neither of them do
6290 * as this is checked in resolve_wildcards().
6293 /* Split up the directory from the filename/mask. */
6294 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6295 &fname_src_dir, &fname_src_mask);
6296 if (!NT_STATUS_IS_OK(status)) {
6297 status = NT_STATUS_NO_MEMORY;
6298 goto out;
6302 * We should only check the mangled cache
6303 * here if unix_convert failed. This means
6304 * that the path in 'mask' doesn't exist
6305 * on the file system and so we need to look
6306 * for a possible mangle. This patch from
6307 * Tine Smukavec <valentin.smukavec@hermes.si>.
6310 if (!VALID_STAT(smb_fname_src->st) &&
6311 mangle_is_mangled(fname_src_mask, conn->params)) {
6312 char *new_mask = NULL;
6313 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6314 conn->params);
6315 if (new_mask) {
6316 TALLOC_FREE(fname_src_mask);
6317 fname_src_mask = new_mask;
6321 if (!src_has_wild) {
6322 files_struct *fsp;
6325 * Only one file needs to be renamed. Append the mask back
6326 * onto the directory.
6328 TALLOC_FREE(smb_fname_src->base_name);
6329 if (ISDOT(fname_src_dir)) {
6330 /* Ensure we use canonical names on open. */
6331 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6332 "%s",
6333 fname_src_mask);
6334 } else {
6335 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6336 "%s/%s",
6337 fname_src_dir,
6338 fname_src_mask);
6340 if (!smb_fname_src->base_name) {
6341 status = NT_STATUS_NO_MEMORY;
6342 goto out;
6345 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6346 "case_preserve = %d, short case preserve = %d, "
6347 "directory = %s, newname = %s, "
6348 "last_component_dest = %s\n",
6349 conn->case_sensitive, conn->case_preserve,
6350 conn->short_case_preserve,
6351 smb_fname_str_dbg(smb_fname_src),
6352 smb_fname_str_dbg(smb_fname_dst),
6353 smb_fname_dst->original_lcomp));
6355 /* The dest name still may have wildcards. */
6356 if (dest_has_wild) {
6357 char *fname_dst_mod = NULL;
6358 if (!resolve_wildcards(smb_fname_dst,
6359 smb_fname_src->base_name,
6360 smb_fname_dst->base_name,
6361 &fname_dst_mod)) {
6362 DEBUG(6, ("rename_internals: resolve_wildcards "
6363 "%s %s failed\n",
6364 smb_fname_src->base_name,
6365 smb_fname_dst->base_name));
6366 status = NT_STATUS_NO_MEMORY;
6367 goto out;
6369 TALLOC_FREE(smb_fname_dst->base_name);
6370 smb_fname_dst->base_name = fname_dst_mod;
6373 ZERO_STRUCT(smb_fname_src->st);
6374 if (posix_pathnames) {
6375 SMB_VFS_LSTAT(conn, smb_fname_src);
6376 } else {
6377 SMB_VFS_STAT(conn, smb_fname_src);
6380 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6381 create_options |= FILE_DIRECTORY_FILE;
6384 status = SMB_VFS_CREATE_FILE(
6385 conn, /* conn */
6386 req, /* req */
6387 0, /* root_dir_fid */
6388 smb_fname_src, /* fname */
6389 access_mask, /* access_mask */
6390 (FILE_SHARE_READ | /* share_access */
6391 FILE_SHARE_WRITE),
6392 FILE_OPEN, /* create_disposition*/
6393 create_options, /* create_options */
6394 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6395 0, /* oplock_request */
6396 0, /* allocation_size */
6397 0, /* private_flags */
6398 NULL, /* sd */
6399 NULL, /* ea_list */
6400 &fsp, /* result */
6401 NULL); /* pinfo */
6403 if (!NT_STATUS_IS_OK(status)) {
6404 DEBUG(3, ("Could not open rename source %s: %s\n",
6405 smb_fname_str_dbg(smb_fname_src),
6406 nt_errstr(status)));
6407 goto out;
6410 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6411 attrs, replace_if_exists);
6413 close_file(req, fsp, NORMAL_CLOSE);
6415 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6416 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6417 smb_fname_str_dbg(smb_fname_dst)));
6419 goto out;
6423 * Wildcards - process each file that matches.
6425 if (strequal(fname_src_mask, "????????.???")) {
6426 TALLOC_FREE(fname_src_mask);
6427 fname_src_mask = talloc_strdup(ctx, "*");
6428 if (!fname_src_mask) {
6429 status = NT_STATUS_NO_MEMORY;
6430 goto out;
6434 status = check_name(conn, fname_src_dir);
6435 if (!NT_STATUS_IS_OK(status)) {
6436 goto out;
6439 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6440 attrs);
6441 if (dir_hnd == NULL) {
6442 status = map_nt_error_from_unix(errno);
6443 goto out;
6446 status = NT_STATUS_NO_SUCH_FILE;
6448 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6449 * - gentest fix. JRA
6452 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6453 &talloced))) {
6454 files_struct *fsp = NULL;
6455 char *destname = NULL;
6456 bool sysdir_entry = False;
6458 /* Quick check for "." and ".." */
6459 if (ISDOT(dname) || ISDOTDOT(dname)) {
6460 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6461 sysdir_entry = True;
6462 } else {
6463 TALLOC_FREE(talloced);
6464 continue;
6468 if (!is_visible_file(conn, fname_src_dir, dname,
6469 &smb_fname_src->st, false)) {
6470 TALLOC_FREE(talloced);
6471 continue;
6474 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6475 TALLOC_FREE(talloced);
6476 continue;
6479 if (sysdir_entry) {
6480 status = NT_STATUS_OBJECT_NAME_INVALID;
6481 break;
6484 TALLOC_FREE(smb_fname_src->base_name);
6485 if (ISDOT(fname_src_dir)) {
6486 /* Ensure we use canonical names on open. */
6487 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6488 "%s",
6489 dname);
6490 } else {
6491 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6492 "%s/%s",
6493 fname_src_dir,
6494 dname);
6496 if (!smb_fname_src->base_name) {
6497 status = NT_STATUS_NO_MEMORY;
6498 goto out;
6501 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6502 smb_fname_dst->base_name,
6503 &destname)) {
6504 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6505 smb_fname_src->base_name, destname));
6506 TALLOC_FREE(talloced);
6507 continue;
6509 if (!destname) {
6510 status = NT_STATUS_NO_MEMORY;
6511 goto out;
6514 TALLOC_FREE(smb_fname_dst->base_name);
6515 smb_fname_dst->base_name = destname;
6517 ZERO_STRUCT(smb_fname_src->st);
6518 if (posix_pathnames) {
6519 SMB_VFS_LSTAT(conn, smb_fname_src);
6520 } else {
6521 SMB_VFS_STAT(conn, smb_fname_src);
6524 create_options = 0;
6526 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6527 create_options |= FILE_DIRECTORY_FILE;
6530 status = SMB_VFS_CREATE_FILE(
6531 conn, /* conn */
6532 req, /* req */
6533 0, /* root_dir_fid */
6534 smb_fname_src, /* fname */
6535 access_mask, /* access_mask */
6536 (FILE_SHARE_READ | /* share_access */
6537 FILE_SHARE_WRITE),
6538 FILE_OPEN, /* create_disposition*/
6539 create_options, /* create_options */
6540 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6541 0, /* oplock_request */
6542 0, /* allocation_size */
6543 0, /* private_flags */
6544 NULL, /* sd */
6545 NULL, /* ea_list */
6546 &fsp, /* result */
6547 NULL); /* pinfo */
6549 if (!NT_STATUS_IS_OK(status)) {
6550 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6551 "returned %s rename %s -> %s\n",
6552 nt_errstr(status),
6553 smb_fname_str_dbg(smb_fname_src),
6554 smb_fname_str_dbg(smb_fname_dst)));
6555 break;
6558 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6559 dname);
6560 if (!smb_fname_dst->original_lcomp) {
6561 status = NT_STATUS_NO_MEMORY;
6562 goto out;
6565 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6566 attrs, replace_if_exists);
6568 close_file(req, fsp, NORMAL_CLOSE);
6570 if (!NT_STATUS_IS_OK(status)) {
6571 DEBUG(3, ("rename_internals_fsp returned %s for "
6572 "rename %s -> %s\n", nt_errstr(status),
6573 smb_fname_str_dbg(smb_fname_src),
6574 smb_fname_str_dbg(smb_fname_dst)));
6575 break;
6578 count++;
6580 DEBUG(3,("rename_internals: doing rename on %s -> "
6581 "%s\n", smb_fname_str_dbg(smb_fname_src),
6582 smb_fname_str_dbg(smb_fname_src)));
6583 TALLOC_FREE(talloced);
6585 TALLOC_FREE(dir_hnd);
6587 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6588 status = map_nt_error_from_unix(errno);
6591 out:
6592 TALLOC_FREE(talloced);
6593 TALLOC_FREE(fname_src_dir);
6594 TALLOC_FREE(fname_src_mask);
6595 return status;
6598 /****************************************************************************
6599 Reply to a mv.
6600 ****************************************************************************/
6602 void reply_mv(struct smb_request *req)
6604 connection_struct *conn = req->conn;
6605 char *name = NULL;
6606 char *newname = NULL;
6607 const char *p;
6608 uint32 attrs;
6609 NTSTATUS status;
6610 bool src_has_wcard = False;
6611 bool dest_has_wcard = False;
6612 TALLOC_CTX *ctx = talloc_tos();
6613 struct smb_filename *smb_fname_src = NULL;
6614 struct smb_filename *smb_fname_dst = NULL;
6615 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6616 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6617 bool stream_rename = false;
6619 START_PROFILE(SMBmv);
6621 if (req->wct < 1) {
6622 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6623 goto out;
6626 attrs = SVAL(req->vwv+0, 0);
6628 p = (const char *)req->buf + 1;
6629 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6630 &status, &src_has_wcard);
6631 if (!NT_STATUS_IS_OK(status)) {
6632 reply_nterror(req, status);
6633 goto out;
6635 p++;
6636 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6637 &status, &dest_has_wcard);
6638 if (!NT_STATUS_IS_OK(status)) {
6639 reply_nterror(req, status);
6640 goto out;
6643 if (!lp_posix_pathnames()) {
6644 /* The newname must begin with a ':' if the
6645 name contains a ':'. */
6646 if (strchr_m(name, ':')) {
6647 if (newname[0] != ':') {
6648 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6649 goto out;
6651 stream_rename = true;
6655 status = filename_convert(ctx,
6656 conn,
6657 req->flags2 & FLAGS2_DFS_PATHNAMES,
6658 name,
6659 src_ucf_flags,
6660 &src_has_wcard,
6661 &smb_fname_src);
6663 if (!NT_STATUS_IS_OK(status)) {
6664 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6665 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6666 ERRSRV, ERRbadpath);
6667 goto out;
6669 reply_nterror(req, status);
6670 goto out;
6673 status = filename_convert(ctx,
6674 conn,
6675 req->flags2 & FLAGS2_DFS_PATHNAMES,
6676 newname,
6677 dst_ucf_flags,
6678 &dest_has_wcard,
6679 &smb_fname_dst);
6681 if (!NT_STATUS_IS_OK(status)) {
6682 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6683 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6684 ERRSRV, ERRbadpath);
6685 goto out;
6687 reply_nterror(req, status);
6688 goto out;
6691 if (stream_rename) {
6692 /* smb_fname_dst->base_name must be the same as
6693 smb_fname_src->base_name. */
6694 TALLOC_FREE(smb_fname_dst->base_name);
6695 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6696 smb_fname_src->base_name);
6697 if (!smb_fname_dst->base_name) {
6698 reply_nterror(req, NT_STATUS_NO_MEMORY);
6699 goto out;
6703 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6704 smb_fname_str_dbg(smb_fname_dst)));
6706 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6707 attrs, False, src_has_wcard, dest_has_wcard,
6708 DELETE_ACCESS);
6709 if (!NT_STATUS_IS_OK(status)) {
6710 if (open_was_deferred(req->sconn, req->mid)) {
6711 /* We have re-scheduled this call. */
6712 goto out;
6714 reply_nterror(req, status);
6715 goto out;
6718 reply_outbuf(req, 0, 0);
6719 out:
6720 TALLOC_FREE(smb_fname_src);
6721 TALLOC_FREE(smb_fname_dst);
6722 END_PROFILE(SMBmv);
6723 return;
6726 /*******************************************************************
6727 Copy a file as part of a reply_copy.
6728 ******************************************************************/
6731 * TODO: check error codes on all callers
6734 NTSTATUS copy_file(TALLOC_CTX *ctx,
6735 connection_struct *conn,
6736 struct smb_filename *smb_fname_src,
6737 struct smb_filename *smb_fname_dst,
6738 int ofun,
6739 int count,
6740 bool target_is_directory)
6742 struct smb_filename *smb_fname_dst_tmp = NULL;
6743 SMB_OFF_T ret=-1;
6744 files_struct *fsp1,*fsp2;
6745 uint32 dosattrs;
6746 uint32 new_create_disposition;
6747 NTSTATUS status;
6750 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6751 if (!NT_STATUS_IS_OK(status)) {
6752 return status;
6756 * If the target is a directory, extract the last component from the
6757 * src filename and append it to the dst filename
6759 if (target_is_directory) {
6760 const char *p;
6762 /* dest/target can't be a stream if it's a directory. */
6763 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6765 p = strrchr_m(smb_fname_src->base_name,'/');
6766 if (p) {
6767 p++;
6768 } else {
6769 p = smb_fname_src->base_name;
6771 smb_fname_dst_tmp->base_name =
6772 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6774 if (!smb_fname_dst_tmp->base_name) {
6775 status = NT_STATUS_NO_MEMORY;
6776 goto out;
6780 status = vfs_file_exist(conn, smb_fname_src);
6781 if (!NT_STATUS_IS_OK(status)) {
6782 goto out;
6785 if (!target_is_directory && count) {
6786 new_create_disposition = FILE_OPEN;
6787 } else {
6788 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6789 0, ofun,
6790 NULL, NULL,
6791 &new_create_disposition,
6792 NULL,
6793 NULL)) {
6794 status = NT_STATUS_INVALID_PARAMETER;
6795 goto out;
6799 /* Open the src file for reading. */
6800 status = SMB_VFS_CREATE_FILE(
6801 conn, /* conn */
6802 NULL, /* req */
6803 0, /* root_dir_fid */
6804 smb_fname_src, /* fname */
6805 FILE_GENERIC_READ, /* access_mask */
6806 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6807 FILE_OPEN, /* create_disposition*/
6808 0, /* create_options */
6809 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6810 INTERNAL_OPEN_ONLY, /* oplock_request */
6811 0, /* allocation_size */
6812 0, /* private_flags */
6813 NULL, /* sd */
6814 NULL, /* ea_list */
6815 &fsp1, /* result */
6816 NULL); /* psbuf */
6818 if (!NT_STATUS_IS_OK(status)) {
6819 goto out;
6822 dosattrs = dos_mode(conn, smb_fname_src);
6824 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6825 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6828 /* Open the dst file for writing. */
6829 status = SMB_VFS_CREATE_FILE(
6830 conn, /* conn */
6831 NULL, /* req */
6832 0, /* root_dir_fid */
6833 smb_fname_dst, /* fname */
6834 FILE_GENERIC_WRITE, /* access_mask */
6835 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6836 new_create_disposition, /* create_disposition*/
6837 0, /* create_options */
6838 dosattrs, /* file_attributes */
6839 INTERNAL_OPEN_ONLY, /* oplock_request */
6840 0, /* allocation_size */
6841 0, /* private_flags */
6842 NULL, /* sd */
6843 NULL, /* ea_list */
6844 &fsp2, /* result */
6845 NULL); /* psbuf */
6847 if (!NT_STATUS_IS_OK(status)) {
6848 close_file(NULL, fsp1, ERROR_CLOSE);
6849 goto out;
6852 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6853 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6854 if (ret == -1) {
6855 DEBUG(0, ("error - vfs lseek returned error %s\n",
6856 strerror(errno)));
6857 status = map_nt_error_from_unix(errno);
6858 close_file(NULL, fsp1, ERROR_CLOSE);
6859 close_file(NULL, fsp2, ERROR_CLOSE);
6860 goto out;
6864 /* Do the actual copy. */
6865 if (smb_fname_src->st.st_ex_size) {
6866 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6867 } else {
6868 ret = 0;
6871 close_file(NULL, fsp1, NORMAL_CLOSE);
6873 /* Ensure the modtime is set correctly on the destination file. */
6874 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6877 * As we are opening fsp1 read-only we only expect
6878 * an error on close on fsp2 if we are out of space.
6879 * Thus we don't look at the error return from the
6880 * close of fsp1.
6882 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6884 if (!NT_STATUS_IS_OK(status)) {
6885 goto out;
6888 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6889 status = NT_STATUS_DISK_FULL;
6890 goto out;
6893 status = NT_STATUS_OK;
6895 out:
6896 TALLOC_FREE(smb_fname_dst_tmp);
6897 return status;
6900 /****************************************************************************
6901 Reply to a file copy.
6902 ****************************************************************************/
6904 void reply_copy(struct smb_request *req)
6906 connection_struct *conn = req->conn;
6907 struct smb_filename *smb_fname_src = NULL;
6908 struct smb_filename *smb_fname_dst = NULL;
6909 char *fname_src = NULL;
6910 char *fname_dst = NULL;
6911 char *fname_src_mask = NULL;
6912 char *fname_src_dir = NULL;
6913 const char *p;
6914 int count=0;
6915 int error = ERRnoaccess;
6916 int tid2;
6917 int ofun;
6918 int flags;
6919 bool target_is_directory=False;
6920 bool source_has_wild = False;
6921 bool dest_has_wild = False;
6922 NTSTATUS status;
6923 TALLOC_CTX *ctx = talloc_tos();
6925 START_PROFILE(SMBcopy);
6927 if (req->wct < 3) {
6928 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6929 goto out;
6932 tid2 = SVAL(req->vwv+0, 0);
6933 ofun = SVAL(req->vwv+1, 0);
6934 flags = SVAL(req->vwv+2, 0);
6936 p = (const char *)req->buf;
6937 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6938 &status, &source_has_wild);
6939 if (!NT_STATUS_IS_OK(status)) {
6940 reply_nterror(req, status);
6941 goto out;
6943 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6944 &status, &dest_has_wild);
6945 if (!NT_STATUS_IS_OK(status)) {
6946 reply_nterror(req, status);
6947 goto out;
6950 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6952 if (tid2 != conn->cnum) {
6953 /* can't currently handle inter share copies XXXX */
6954 DEBUG(3,("Rejecting inter-share copy\n"));
6955 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6956 goto out;
6959 status = filename_convert(ctx, conn,
6960 req->flags2 & FLAGS2_DFS_PATHNAMES,
6961 fname_src,
6962 UCF_COND_ALLOW_WCARD_LCOMP,
6963 &source_has_wild,
6964 &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, conn,
6976 req->flags2 & FLAGS2_DFS_PATHNAMES,
6977 fname_dst,
6978 UCF_COND_ALLOW_WCARD_LCOMP,
6979 &dest_has_wild,
6980 &smb_fname_dst);
6981 if (!NT_STATUS_IS_OK(status)) {
6982 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6983 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6984 ERRSRV, ERRbadpath);
6985 goto out;
6987 reply_nterror(req, status);
6988 goto out;
6991 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6993 if ((flags&1) && target_is_directory) {
6994 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6995 goto out;
6998 if ((flags&2) && !target_is_directory) {
6999 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7000 goto out;
7003 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7004 /* wants a tree copy! XXXX */
7005 DEBUG(3,("Rejecting tree copy\n"));
7006 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7007 goto out;
7010 /* Split up the directory from the filename/mask. */
7011 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7012 &fname_src_dir, &fname_src_mask);
7013 if (!NT_STATUS_IS_OK(status)) {
7014 reply_nterror(req, NT_STATUS_NO_MEMORY);
7015 goto out;
7019 * We should only check the mangled cache
7020 * here if unix_convert failed. This means
7021 * that the path in 'mask' doesn't exist
7022 * on the file system and so we need to look
7023 * for a possible mangle. This patch from
7024 * Tine Smukavec <valentin.smukavec@hermes.si>.
7026 if (!VALID_STAT(smb_fname_src->st) &&
7027 mangle_is_mangled(fname_src_mask, conn->params)) {
7028 char *new_mask = NULL;
7029 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7030 &new_mask, conn->params);
7032 /* Use demangled name if one was successfully found. */
7033 if (new_mask) {
7034 TALLOC_FREE(fname_src_mask);
7035 fname_src_mask = new_mask;
7039 if (!source_has_wild) {
7042 * Only one file needs to be copied. Append the mask back onto
7043 * the directory.
7045 TALLOC_FREE(smb_fname_src->base_name);
7046 if (ISDOT(fname_src_dir)) {
7047 /* Ensure we use canonical names on open. */
7048 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7049 "%s",
7050 fname_src_mask);
7051 } else {
7052 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7053 "%s/%s",
7054 fname_src_dir,
7055 fname_src_mask);
7057 if (!smb_fname_src->base_name) {
7058 reply_nterror(req, NT_STATUS_NO_MEMORY);
7059 goto out;
7062 if (dest_has_wild) {
7063 char *fname_dst_mod = NULL;
7064 if (!resolve_wildcards(smb_fname_dst,
7065 smb_fname_src->base_name,
7066 smb_fname_dst->base_name,
7067 &fname_dst_mod)) {
7068 reply_nterror(req, NT_STATUS_NO_MEMORY);
7069 goto out;
7071 TALLOC_FREE(smb_fname_dst->base_name);
7072 smb_fname_dst->base_name = fname_dst_mod;
7075 status = check_name(conn, smb_fname_src->base_name);
7076 if (!NT_STATUS_IS_OK(status)) {
7077 reply_nterror(req, status);
7078 goto out;
7081 status = check_name(conn, smb_fname_dst->base_name);
7082 if (!NT_STATUS_IS_OK(status)) {
7083 reply_nterror(req, status);
7084 goto out;
7087 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7088 ofun, count, target_is_directory);
7090 if(!NT_STATUS_IS_OK(status)) {
7091 reply_nterror(req, status);
7092 goto out;
7093 } else {
7094 count++;
7096 } else {
7097 struct smb_Dir *dir_hnd = NULL;
7098 const char *dname = NULL;
7099 char *talloced = NULL;
7100 long offset = 0;
7103 * There is a wildcard that requires us to actually read the
7104 * src dir and copy each file matching the mask to the dst.
7105 * Right now streams won't be copied, but this could
7106 * presumably be added with a nested loop for reach dir entry.
7108 SMB_ASSERT(!smb_fname_src->stream_name);
7109 SMB_ASSERT(!smb_fname_dst->stream_name);
7111 smb_fname_src->stream_name = NULL;
7112 smb_fname_dst->stream_name = NULL;
7114 if (strequal(fname_src_mask,"????????.???")) {
7115 TALLOC_FREE(fname_src_mask);
7116 fname_src_mask = talloc_strdup(ctx, "*");
7117 if (!fname_src_mask) {
7118 reply_nterror(req, NT_STATUS_NO_MEMORY);
7119 goto out;
7123 status = check_name(conn, fname_src_dir);
7124 if (!NT_STATUS_IS_OK(status)) {
7125 reply_nterror(req, status);
7126 goto out;
7129 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7130 if (dir_hnd == NULL) {
7131 status = map_nt_error_from_unix(errno);
7132 reply_nterror(req, status);
7133 goto out;
7136 error = ERRbadfile;
7138 /* Iterate over the src dir copying each entry to the dst. */
7139 while ((dname = ReadDirName(dir_hnd, &offset,
7140 &smb_fname_src->st, &talloced))) {
7141 char *destname = NULL;
7143 if (ISDOT(dname) || ISDOTDOT(dname)) {
7144 TALLOC_FREE(talloced);
7145 continue;
7148 if (!is_visible_file(conn, fname_src_dir, dname,
7149 &smb_fname_src->st, false)) {
7150 TALLOC_FREE(talloced);
7151 continue;
7154 if(!mask_match(dname, fname_src_mask,
7155 conn->case_sensitive)) {
7156 TALLOC_FREE(talloced);
7157 continue;
7160 error = ERRnoaccess;
7162 /* Get the src smb_fname struct setup. */
7163 TALLOC_FREE(smb_fname_src->base_name);
7164 if (ISDOT(fname_src_dir)) {
7165 /* Ensure we use canonical names on open. */
7166 smb_fname_src->base_name =
7167 talloc_asprintf(smb_fname_src, "%s",
7168 dname);
7169 } else {
7170 smb_fname_src->base_name =
7171 talloc_asprintf(smb_fname_src, "%s/%s",
7172 fname_src_dir, dname);
7175 if (!smb_fname_src->base_name) {
7176 TALLOC_FREE(dir_hnd);
7177 TALLOC_FREE(talloced);
7178 reply_nterror(req, NT_STATUS_NO_MEMORY);
7179 goto out;
7182 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7183 smb_fname_dst->base_name,
7184 &destname)) {
7185 TALLOC_FREE(talloced);
7186 continue;
7188 if (!destname) {
7189 TALLOC_FREE(dir_hnd);
7190 TALLOC_FREE(talloced);
7191 reply_nterror(req, NT_STATUS_NO_MEMORY);
7192 goto out;
7195 TALLOC_FREE(smb_fname_dst->base_name);
7196 smb_fname_dst->base_name = destname;
7198 status = check_name(conn, smb_fname_src->base_name);
7199 if (!NT_STATUS_IS_OK(status)) {
7200 TALLOC_FREE(dir_hnd);
7201 TALLOC_FREE(talloced);
7202 reply_nterror(req, status);
7203 goto out;
7206 status = check_name(conn, smb_fname_dst->base_name);
7207 if (!NT_STATUS_IS_OK(status)) {
7208 TALLOC_FREE(dir_hnd);
7209 TALLOC_FREE(talloced);
7210 reply_nterror(req, status);
7211 goto out;
7214 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7215 smb_fname_src->base_name,
7216 smb_fname_dst->base_name));
7218 status = copy_file(ctx, conn, smb_fname_src,
7219 smb_fname_dst, ofun, count,
7220 target_is_directory);
7221 if (NT_STATUS_IS_OK(status)) {
7222 count++;
7225 TALLOC_FREE(talloced);
7227 TALLOC_FREE(dir_hnd);
7230 if (count == 0) {
7231 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7232 goto out;
7235 reply_outbuf(req, 1, 0);
7236 SSVAL(req->outbuf,smb_vwv0,count);
7237 out:
7238 TALLOC_FREE(smb_fname_src);
7239 TALLOC_FREE(smb_fname_dst);
7240 TALLOC_FREE(fname_src);
7241 TALLOC_FREE(fname_dst);
7242 TALLOC_FREE(fname_src_mask);
7243 TALLOC_FREE(fname_src_dir);
7245 END_PROFILE(SMBcopy);
7246 return;
7249 #undef DBGC_CLASS
7250 #define DBGC_CLASS DBGC_LOCKING
7252 /****************************************************************************
7253 Get a lock pid, dealing with large count requests.
7254 ****************************************************************************/
7256 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7257 bool large_file_format)
7259 if(!large_file_format)
7260 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7261 else
7262 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7265 /****************************************************************************
7266 Get a lock count, dealing with large count requests.
7267 ****************************************************************************/
7269 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7270 bool large_file_format)
7272 uint64_t count = 0;
7274 if(!large_file_format) {
7275 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7276 } else {
7278 #if defined(HAVE_LONGLONG)
7279 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7280 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7281 #else /* HAVE_LONGLONG */
7284 * NT4.x seems to be broken in that it sends large file (64 bit)
7285 * lockingX calls even if the CAP_LARGE_FILES was *not*
7286 * negotiated. For boxes without large unsigned ints truncate the
7287 * lock count by dropping the top 32 bits.
7290 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7291 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7292 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7293 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7294 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7297 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7298 #endif /* HAVE_LONGLONG */
7301 return count;
7304 #if !defined(HAVE_LONGLONG)
7305 /****************************************************************************
7306 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7307 ****************************************************************************/
7309 static uint32 map_lock_offset(uint32 high, uint32 low)
7311 unsigned int i;
7312 uint32 mask = 0;
7313 uint32 highcopy = high;
7316 * Try and find out how many significant bits there are in high.
7319 for(i = 0; highcopy; i++)
7320 highcopy >>= 1;
7323 * We use 31 bits not 32 here as POSIX
7324 * lock offsets may not be negative.
7327 mask = (~0) << (31 - i);
7329 if(low & mask)
7330 return 0; /* Fail. */
7332 high <<= (31 - i);
7334 return (high|low);
7336 #endif /* !defined(HAVE_LONGLONG) */
7338 /****************************************************************************
7339 Get a lock offset, dealing with large offset requests.
7340 ****************************************************************************/
7342 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7343 bool large_file_format, bool *err)
7345 uint64_t offset = 0;
7347 *err = False;
7349 if(!large_file_format) {
7350 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7351 } else {
7353 #if defined(HAVE_LONGLONG)
7354 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7355 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7356 #else /* HAVE_LONGLONG */
7359 * NT4.x seems to be broken in that it sends large file (64 bit)
7360 * lockingX calls even if the CAP_LARGE_FILES was *not*
7361 * negotiated. For boxes without large unsigned ints mangle the
7362 * lock offset by mapping the top 32 bits onto the lower 32.
7365 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7366 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7367 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7368 uint32 new_low = 0;
7370 if((new_low = map_lock_offset(high, low)) == 0) {
7371 *err = True;
7372 return (uint64_t)-1;
7375 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7376 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7377 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7378 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7381 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7382 #endif /* HAVE_LONGLONG */
7385 return offset;
7388 NTSTATUS smbd_do_locking(struct smb_request *req,
7389 files_struct *fsp,
7390 uint8_t type,
7391 int32_t timeout,
7392 uint16_t num_ulocks,
7393 struct smbd_lock_element *ulocks,
7394 uint16_t num_locks,
7395 struct smbd_lock_element *locks,
7396 bool *async)
7398 connection_struct *conn = req->conn;
7399 int i;
7400 NTSTATUS status = NT_STATUS_OK;
7402 *async = false;
7404 /* Data now points at the beginning of the list
7405 of smb_unlkrng structs */
7406 for(i = 0; i < (int)num_ulocks; i++) {
7407 struct smbd_lock_element *e = &ulocks[i];
7409 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7410 "pid %u, file %s\n",
7411 (double)e->offset,
7412 (double)e->count,
7413 (unsigned int)e->smblctx,
7414 fsp_str_dbg(fsp)));
7416 if (e->brltype != UNLOCK_LOCK) {
7417 /* this can only happen with SMB2 */
7418 return NT_STATUS_INVALID_PARAMETER;
7421 status = do_unlock(req->sconn->msg_ctx,
7422 fsp,
7423 e->smblctx,
7424 e->count,
7425 e->offset,
7426 WINDOWS_LOCK);
7428 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7429 nt_errstr(status)));
7431 if (!NT_STATUS_IS_OK(status)) {
7432 return status;
7436 /* Setup the timeout in seconds. */
7438 if (!lp_blocking_locks(SNUM(conn))) {
7439 timeout = 0;
7442 /* Data now points at the beginning of the list
7443 of smb_lkrng structs */
7445 for(i = 0; i < (int)num_locks; i++) {
7446 struct smbd_lock_element *e = &locks[i];
7448 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7449 "%llu, file %s timeout = %d\n",
7450 (double)e->offset,
7451 (double)e->count,
7452 (unsigned long long)e->smblctx,
7453 fsp_str_dbg(fsp),
7454 (int)timeout));
7456 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7457 struct blocking_lock_record *blr = NULL;
7459 if (num_locks > 1) {
7461 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7462 * if the lock vector contains one entry. When given mutliple cancel
7463 * requests in a single PDU we expect the server to return an
7464 * error. Windows servers seem to accept the request but only
7465 * cancel the first lock.
7466 * JRA - Do what Windows does (tm) :-).
7469 #if 0
7470 /* MS-CIFS (2.2.4.32.1) behavior. */
7471 return NT_STATUS_DOS(ERRDOS,
7472 ERRcancelviolation);
7473 #else
7474 /* Windows behavior. */
7475 if (i != 0) {
7476 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7477 "cancel request\n"));
7478 continue;
7480 #endif
7483 if (lp_blocking_locks(SNUM(conn))) {
7485 /* Schedule a message to ourselves to
7486 remove the blocking lock record and
7487 return the right error. */
7489 blr = blocking_lock_cancel_smb1(fsp,
7490 e->smblctx,
7491 e->offset,
7492 e->count,
7493 WINDOWS_LOCK,
7494 type,
7495 NT_STATUS_FILE_LOCK_CONFLICT);
7496 if (blr == NULL) {
7497 return NT_STATUS_DOS(
7498 ERRDOS,
7499 ERRcancelviolation);
7502 /* Remove a matching pending lock. */
7503 status = do_lock_cancel(fsp,
7504 e->smblctx,
7505 e->count,
7506 e->offset,
7507 WINDOWS_LOCK,
7508 blr);
7509 } else {
7510 bool blocking_lock = timeout ? true : false;
7511 bool defer_lock = false;
7512 struct byte_range_lock *br_lck;
7513 uint64_t block_smblctx;
7515 br_lck = do_lock(req->sconn->msg_ctx,
7516 fsp,
7517 e->smblctx,
7518 e->count,
7519 e->offset,
7520 e->brltype,
7521 WINDOWS_LOCK,
7522 blocking_lock,
7523 &status,
7524 &block_smblctx,
7525 NULL);
7527 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7528 /* Windows internal resolution for blocking locks seems
7529 to be about 200ms... Don't wait for less than that. JRA. */
7530 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7531 timeout = lp_lock_spin_time();
7533 defer_lock = true;
7536 /* If a lock sent with timeout of zero would fail, and
7537 * this lock has been requested multiple times,
7538 * according to brl_lock_failed() we convert this
7539 * request to a blocking lock with a timeout of between
7540 * 150 - 300 milliseconds.
7542 * If lp_lock_spin_time() has been set to 0, we skip
7543 * this blocking retry and fail immediately.
7545 * Replacement for do_lock_spin(). JRA. */
7547 if (!req->sconn->using_smb2 &&
7548 br_lck && lp_blocking_locks(SNUM(conn)) &&
7549 lp_lock_spin_time() && !blocking_lock &&
7550 NT_STATUS_EQUAL((status),
7551 NT_STATUS_FILE_LOCK_CONFLICT))
7553 defer_lock = true;
7554 timeout = lp_lock_spin_time();
7557 if (br_lck && defer_lock) {
7559 * A blocking lock was requested. Package up
7560 * this smb into a queued request and push it
7561 * onto the blocking lock queue.
7563 if(push_blocking_lock_request(br_lck,
7564 req,
7565 fsp,
7566 timeout,
7568 e->smblctx,
7569 e->brltype,
7570 WINDOWS_LOCK,
7571 e->offset,
7572 e->count,
7573 block_smblctx)) {
7574 TALLOC_FREE(br_lck);
7575 *async = true;
7576 return NT_STATUS_OK;
7580 TALLOC_FREE(br_lck);
7583 if (!NT_STATUS_IS_OK(status)) {
7584 break;
7588 /* If any of the above locks failed, then we must unlock
7589 all of the previous locks (X/Open spec). */
7591 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7593 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7594 i = -1; /* we want to skip the for loop */
7598 * Ensure we don't do a remove on the lock that just failed,
7599 * as under POSIX rules, if we have a lock already there, we
7600 * will delete it (and we shouldn't) .....
7602 for(i--; i >= 0; i--) {
7603 struct smbd_lock_element *e = &locks[i];
7605 do_unlock(req->sconn->msg_ctx,
7606 fsp,
7607 e->smblctx,
7608 e->count,
7609 e->offset,
7610 WINDOWS_LOCK);
7612 return status;
7615 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7616 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7618 return NT_STATUS_OK;
7621 /****************************************************************************
7622 Reply to a lockingX request.
7623 ****************************************************************************/
7625 void reply_lockingX(struct smb_request *req)
7627 connection_struct *conn = req->conn;
7628 files_struct *fsp;
7629 unsigned char locktype;
7630 unsigned char oplocklevel;
7631 uint16 num_ulocks;
7632 uint16 num_locks;
7633 int32 lock_timeout;
7634 int i;
7635 const uint8_t *data;
7636 bool large_file_format;
7637 bool err;
7638 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7639 struct smbd_lock_element *ulocks;
7640 struct smbd_lock_element *locks;
7641 bool async = false;
7643 START_PROFILE(SMBlockingX);
7645 if (req->wct < 8) {
7646 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7647 END_PROFILE(SMBlockingX);
7648 return;
7651 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7652 locktype = CVAL(req->vwv+3, 0);
7653 oplocklevel = CVAL(req->vwv+3, 1);
7654 num_ulocks = SVAL(req->vwv+6, 0);
7655 num_locks = SVAL(req->vwv+7, 0);
7656 lock_timeout = IVAL(req->vwv+4, 0);
7657 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7659 if (!check_fsp(conn, req, fsp)) {
7660 END_PROFILE(SMBlockingX);
7661 return;
7664 data = req->buf;
7666 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7667 /* we don't support these - and CANCEL_LOCK makes w2k
7668 and XP reboot so I don't really want to be
7669 compatible! (tridge) */
7670 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7671 END_PROFILE(SMBlockingX);
7672 return;
7675 /* Check if this is an oplock break on a file
7676 we have granted an oplock on.
7678 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7679 /* Client can insist on breaking to none. */
7680 bool break_to_none = (oplocklevel == 0);
7681 bool result;
7683 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7684 "for fnum = %d\n", (unsigned int)oplocklevel,
7685 fsp->fnum ));
7688 * Make sure we have granted an exclusive or batch oplock on
7689 * this file.
7692 if (fsp->oplock_type == 0) {
7694 /* The Samba4 nbench simulator doesn't understand
7695 the difference between break to level2 and break
7696 to none from level2 - it sends oplock break
7697 replies in both cases. Don't keep logging an error
7698 message here - just ignore it. JRA. */
7700 DEBUG(5,("reply_lockingX: Error : oplock break from "
7701 "client for fnum = %d (oplock=%d) and no "
7702 "oplock granted on this file (%s).\n",
7703 fsp->fnum, fsp->oplock_type,
7704 fsp_str_dbg(fsp)));
7706 /* if this is a pure oplock break request then don't
7707 * send a reply */
7708 if (num_locks == 0 && num_ulocks == 0) {
7709 END_PROFILE(SMBlockingX);
7710 return;
7711 } else {
7712 END_PROFILE(SMBlockingX);
7713 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7714 return;
7718 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7719 (break_to_none)) {
7720 result = remove_oplock(fsp);
7721 } else {
7722 result = downgrade_oplock(fsp);
7725 if (!result) {
7726 DEBUG(0, ("reply_lockingX: error in removing "
7727 "oplock on file %s\n", fsp_str_dbg(fsp)));
7728 /* Hmmm. Is this panic justified? */
7729 smb_panic("internal tdb error");
7732 reply_to_oplock_break_requests(fsp);
7734 /* if this is a pure oplock break request then don't send a
7735 * reply */
7736 if (num_locks == 0 && num_ulocks == 0) {
7737 /* Sanity check - ensure a pure oplock break is not a
7738 chained request. */
7739 if(CVAL(req->vwv+0, 0) != 0xff)
7740 DEBUG(0,("reply_lockingX: Error : pure oplock "
7741 "break is a chained %d request !\n",
7742 (unsigned int)CVAL(req->vwv+0, 0)));
7743 END_PROFILE(SMBlockingX);
7744 return;
7748 if (req->buflen <
7749 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7750 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7751 END_PROFILE(SMBlockingX);
7752 return;
7755 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7756 if (ulocks == NULL) {
7757 reply_nterror(req, NT_STATUS_NO_MEMORY);
7758 END_PROFILE(SMBlockingX);
7759 return;
7762 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7763 if (locks == NULL) {
7764 reply_nterror(req, NT_STATUS_NO_MEMORY);
7765 END_PROFILE(SMBlockingX);
7766 return;
7769 /* Data now points at the beginning of the list
7770 of smb_unlkrng structs */
7771 for(i = 0; i < (int)num_ulocks; i++) {
7772 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7773 ulocks[i].count = get_lock_count(data, i, large_file_format);
7774 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7775 ulocks[i].brltype = UNLOCK_LOCK;
7778 * There is no error code marked "stupid client bug".... :-).
7780 if(err) {
7781 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7782 END_PROFILE(SMBlockingX);
7783 return;
7787 /* Now do any requested locks */
7788 data += ((large_file_format ? 20 : 10)*num_ulocks);
7790 /* Data now points at the beginning of the list
7791 of smb_lkrng structs */
7793 for(i = 0; i < (int)num_locks; i++) {
7794 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7795 locks[i].count = get_lock_count(data, i, large_file_format);
7796 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7798 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7799 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7800 locks[i].brltype = PENDING_READ_LOCK;
7801 } else {
7802 locks[i].brltype = READ_LOCK;
7804 } else {
7805 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7806 locks[i].brltype = PENDING_WRITE_LOCK;
7807 } else {
7808 locks[i].brltype = WRITE_LOCK;
7813 * There is no error code marked "stupid client bug".... :-).
7815 if(err) {
7816 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7817 END_PROFILE(SMBlockingX);
7818 return;
7822 status = smbd_do_locking(req, fsp,
7823 locktype, lock_timeout,
7824 num_ulocks, ulocks,
7825 num_locks, locks,
7826 &async);
7827 if (!NT_STATUS_IS_OK(status)) {
7828 END_PROFILE(SMBlockingX);
7829 reply_nterror(req, status);
7830 return;
7832 if (async) {
7833 END_PROFILE(SMBlockingX);
7834 return;
7837 reply_outbuf(req, 2, 0);
7839 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7840 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7842 END_PROFILE(SMBlockingX);
7843 chain_reply(req);
7846 #undef DBGC_CLASS
7847 #define DBGC_CLASS DBGC_ALL
7849 /****************************************************************************
7850 Reply to a SMBreadbmpx (read block multiplex) request.
7851 Always reply with an error, if someone has a platform really needs this,
7852 please contact vl@samba.org
7853 ****************************************************************************/
7855 void reply_readbmpx(struct smb_request *req)
7857 START_PROFILE(SMBreadBmpx);
7858 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7859 END_PROFILE(SMBreadBmpx);
7860 return;
7863 /****************************************************************************
7864 Reply to a SMBreadbs (read block multiplex secondary) request.
7865 Always reply with an error, if someone has a platform really needs this,
7866 please contact vl@samba.org
7867 ****************************************************************************/
7869 void reply_readbs(struct smb_request *req)
7871 START_PROFILE(SMBreadBs);
7872 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7873 END_PROFILE(SMBreadBs);
7874 return;
7877 /****************************************************************************
7878 Reply to a SMBsetattrE.
7879 ****************************************************************************/
7881 void reply_setattrE(struct smb_request *req)
7883 connection_struct *conn = req->conn;
7884 struct smb_file_time ft;
7885 files_struct *fsp;
7886 NTSTATUS status;
7888 START_PROFILE(SMBsetattrE);
7889 ZERO_STRUCT(ft);
7891 if (req->wct < 7) {
7892 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7893 goto out;
7896 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7898 if(!fsp || (fsp->conn != conn)) {
7899 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7900 goto out;
7904 * Convert the DOS times into unix times.
7907 ft.atime = convert_time_t_to_timespec(
7908 srv_make_unix_date2(req->vwv+3));
7909 ft.mtime = convert_time_t_to_timespec(
7910 srv_make_unix_date2(req->vwv+5));
7911 ft.create_time = convert_time_t_to_timespec(
7912 srv_make_unix_date2(req->vwv+1));
7914 reply_outbuf(req, 0, 0);
7917 * Patch from Ray Frush <frush@engr.colostate.edu>
7918 * Sometimes times are sent as zero - ignore them.
7921 /* Ensure we have a valid stat struct for the source. */
7922 status = vfs_stat_fsp(fsp);
7923 if (!NT_STATUS_IS_OK(status)) {
7924 reply_nterror(req, status);
7925 goto out;
7928 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
7929 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7930 goto out;
7933 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7934 if (!NT_STATUS_IS_OK(status)) {
7935 reply_nterror(req, status);
7936 goto out;
7939 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7940 " createtime=%u\n",
7941 fsp->fnum,
7942 (unsigned int)ft.atime.tv_sec,
7943 (unsigned int)ft.mtime.tv_sec,
7944 (unsigned int)ft.create_time.tv_sec
7946 out:
7947 END_PROFILE(SMBsetattrE);
7948 return;
7952 /* Back from the dead for OS/2..... JRA. */
7954 /****************************************************************************
7955 Reply to a SMBwritebmpx (write block multiplex primary) request.
7956 Always reply with an error, if someone has a platform really needs this,
7957 please contact vl@samba.org
7958 ****************************************************************************/
7960 void reply_writebmpx(struct smb_request *req)
7962 START_PROFILE(SMBwriteBmpx);
7963 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7964 END_PROFILE(SMBwriteBmpx);
7965 return;
7968 /****************************************************************************
7969 Reply to a SMBwritebs (write block multiplex secondary) request.
7970 Always reply with an error, if someone has a platform really needs this,
7971 please contact vl@samba.org
7972 ****************************************************************************/
7974 void reply_writebs(struct smb_request *req)
7976 START_PROFILE(SMBwriteBs);
7977 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7978 END_PROFILE(SMBwriteBs);
7979 return;
7982 /****************************************************************************
7983 Reply to a SMBgetattrE.
7984 ****************************************************************************/
7986 void reply_getattrE(struct smb_request *req)
7988 connection_struct *conn = req->conn;
7989 int mode;
7990 files_struct *fsp;
7991 struct timespec create_ts;
7993 START_PROFILE(SMBgetattrE);
7995 if (req->wct < 1) {
7996 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7997 END_PROFILE(SMBgetattrE);
7998 return;
8001 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8003 if(!fsp || (fsp->conn != conn)) {
8004 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8005 END_PROFILE(SMBgetattrE);
8006 return;
8009 /* Do an fstat on this file */
8010 if(fsp_stat(fsp)) {
8011 reply_nterror(req, map_nt_error_from_unix(errno));
8012 END_PROFILE(SMBgetattrE);
8013 return;
8016 mode = dos_mode(conn, fsp->fsp_name);
8019 * Convert the times into dos times. Set create
8020 * date to be last modify date as UNIX doesn't save
8021 * this.
8024 reply_outbuf(req, 11, 0);
8026 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8027 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8028 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8029 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8030 /* Should we check pending modtime here ? JRA */
8031 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8032 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8034 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8035 SIVAL(req->outbuf, smb_vwv6, 0);
8036 SIVAL(req->outbuf, smb_vwv8, 0);
8037 } else {
8038 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8039 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8040 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8042 SSVAL(req->outbuf,smb_vwv10, mode);
8044 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8046 END_PROFILE(SMBgetattrE);
8047 return;