s3:smbd: use 'struct user_struct' instead of typedef'ed 'user_struct'
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blobf89631707b7df149c7eedba7e2d093614b5df8fc
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));
863 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
864 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
866 DEBUG(3,("tconX service=%s \n",
867 service));
869 /* set the incoming and outgoing tid to the just created one */
870 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
871 SSVAL(req->outbuf,smb_tid,conn->cnum);
873 END_PROFILE(SMBtconX);
875 req->tid = conn->cnum;
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 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
949 srvstr_push((char *)req->outbuf, req->flags2, p+2,
950 lp_netbios_name(), 15,
951 STR_TERMINATE|STR_ASCII);
952 if (conn) {
953 srvstr_push((char *)req->outbuf, req->flags2,
954 p+18, lp_servicename(SNUM(conn)),
955 13, STR_TERMINATE|STR_ASCII);
956 } else {
957 memset(p+18, 0, 13);
959 break;
963 END_PROFILE(SMBioctl);
964 return;
967 /****************************************************************************
968 Strange checkpath NTSTATUS mapping.
969 ****************************************************************************/
971 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
973 /* Strange DOS error code semantics only for checkpath... */
974 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
975 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
976 /* We need to map to ERRbadpath */
977 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
980 return status;
983 /****************************************************************************
984 Reply to a checkpath.
985 ****************************************************************************/
987 void reply_checkpath(struct smb_request *req)
989 connection_struct *conn = req->conn;
990 struct smb_filename *smb_fname = NULL;
991 char *name = NULL;
992 NTSTATUS status;
993 TALLOC_CTX *ctx = talloc_tos();
995 START_PROFILE(SMBcheckpath);
997 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
998 STR_TERMINATE, &status);
1000 if (!NT_STATUS_IS_OK(status)) {
1001 status = map_checkpath_error(req->flags2, status);
1002 reply_nterror(req, status);
1003 END_PROFILE(SMBcheckpath);
1004 return;
1007 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1009 status = filename_convert(ctx,
1010 conn,
1011 req->flags2 & FLAGS2_DFS_PATHNAMES,
1012 name,
1014 NULL,
1015 &smb_fname);
1017 if (!NT_STATUS_IS_OK(status)) {
1018 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1019 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1020 ERRSRV, ERRbadpath);
1021 END_PROFILE(SMBcheckpath);
1022 return;
1024 goto path_err;
1027 if (!VALID_STAT(smb_fname->st) &&
1028 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1029 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1030 smb_fname_str_dbg(smb_fname), strerror(errno)));
1031 status = map_nt_error_from_unix(errno);
1032 goto path_err;
1035 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1036 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1037 ERRDOS, ERRbadpath);
1038 goto out;
1041 reply_outbuf(req, 0, 0);
1043 path_err:
1044 /* We special case this - as when a Windows machine
1045 is parsing a path is steps through the components
1046 one at a time - if a component fails it expects
1047 ERRbadpath, not ERRbadfile.
1049 status = map_checkpath_error(req->flags2, status);
1050 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1052 * Windows returns different error codes if
1053 * the parent directory is valid but not the
1054 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1055 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1056 * if the path is invalid.
1058 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1059 ERRDOS, ERRbadpath);
1060 goto out;
1063 reply_nterror(req, status);
1065 out:
1066 TALLOC_FREE(smb_fname);
1067 END_PROFILE(SMBcheckpath);
1068 return;
1071 /****************************************************************************
1072 Reply to a getatr.
1073 ****************************************************************************/
1075 void reply_getatr(struct smb_request *req)
1077 connection_struct *conn = req->conn;
1078 struct smb_filename *smb_fname = NULL;
1079 char *fname = NULL;
1080 int mode=0;
1081 off_t size=0;
1082 time_t mtime=0;
1083 const char *p;
1084 NTSTATUS status;
1085 TALLOC_CTX *ctx = talloc_tos();
1086 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1088 START_PROFILE(SMBgetatr);
1090 p = (const char *)req->buf + 1;
1091 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1092 if (!NT_STATUS_IS_OK(status)) {
1093 reply_nterror(req, status);
1094 goto out;
1097 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1098 under WfWg - weird! */
1099 if (*fname == '\0') {
1100 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1101 if (!CAN_WRITE(conn)) {
1102 mode |= FILE_ATTRIBUTE_READONLY;
1104 size = 0;
1105 mtime = 0;
1106 } else {
1107 status = filename_convert(ctx,
1108 conn,
1109 req->flags2 & FLAGS2_DFS_PATHNAMES,
1110 fname,
1112 NULL,
1113 &smb_fname);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1116 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1117 ERRSRV, ERRbadpath);
1118 goto out;
1120 reply_nterror(req, status);
1121 goto out;
1123 if (!VALID_STAT(smb_fname->st) &&
1124 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1125 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1126 smb_fname_str_dbg(smb_fname),
1127 strerror(errno)));
1128 reply_nterror(req, map_nt_error_from_unix(errno));
1129 goto out;
1132 mode = dos_mode(conn, smb_fname);
1133 size = smb_fname->st.st_ex_size;
1135 if (ask_sharemode) {
1136 struct timespec write_time_ts;
1137 struct file_id fileid;
1139 ZERO_STRUCT(write_time_ts);
1140 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1141 get_file_infos(fileid, 0, NULL, &write_time_ts);
1142 if (!null_timespec(write_time_ts)) {
1143 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1147 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1148 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1149 size = 0;
1153 reply_outbuf(req, 10, 0);
1155 SSVAL(req->outbuf,smb_vwv0,mode);
1156 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1157 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1158 } else {
1159 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1161 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1163 if (get_Protocol() >= PROTOCOL_NT1) {
1164 SSVAL(req->outbuf, smb_flg2,
1165 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1168 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1169 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1171 out:
1172 TALLOC_FREE(smb_fname);
1173 TALLOC_FREE(fname);
1174 END_PROFILE(SMBgetatr);
1175 return;
1178 /****************************************************************************
1179 Reply to a setatr.
1180 ****************************************************************************/
1182 void reply_setatr(struct smb_request *req)
1184 struct smb_file_time ft;
1185 connection_struct *conn = req->conn;
1186 struct smb_filename *smb_fname = NULL;
1187 char *fname = NULL;
1188 int mode;
1189 time_t mtime;
1190 const char *p;
1191 NTSTATUS status;
1192 TALLOC_CTX *ctx = talloc_tos();
1194 START_PROFILE(SMBsetatr);
1196 ZERO_STRUCT(ft);
1198 if (req->wct < 2) {
1199 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1200 goto out;
1203 p = (const char *)req->buf + 1;
1204 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1205 if (!NT_STATUS_IS_OK(status)) {
1206 reply_nterror(req, status);
1207 goto out;
1210 status = filename_convert(ctx,
1211 conn,
1212 req->flags2 & FLAGS2_DFS_PATHNAMES,
1213 fname,
1215 NULL,
1216 &smb_fname);
1217 if (!NT_STATUS_IS_OK(status)) {
1218 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1219 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1220 ERRSRV, ERRbadpath);
1221 goto out;
1223 reply_nterror(req, status);
1224 goto out;
1227 if (smb_fname->base_name[0] == '.' &&
1228 smb_fname->base_name[1] == '\0') {
1230 * Not sure here is the right place to catch this
1231 * condition. Might be moved to somewhere else later -- vl
1233 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1234 goto out;
1237 mode = SVAL(req->vwv+0, 0);
1238 mtime = srv_make_unix_date3(req->vwv+1);
1240 if (mode != FILE_ATTRIBUTE_NORMAL) {
1241 if (VALID_STAT_OF_DIR(smb_fname->st))
1242 mode |= FILE_ATTRIBUTE_DIRECTORY;
1243 else
1244 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1246 status = check_access(conn, NULL, smb_fname,
1247 FILE_WRITE_ATTRIBUTES);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 reply_nterror(req, status);
1250 goto out;
1253 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1254 false) != 0) {
1255 reply_nterror(req, map_nt_error_from_unix(errno));
1256 goto out;
1260 ft.mtime = convert_time_t_to_timespec(mtime);
1261 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1262 if (!NT_STATUS_IS_OK(status)) {
1263 reply_nterror(req, status);
1264 goto out;
1267 reply_outbuf(req, 0, 0);
1269 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1270 mode));
1271 out:
1272 TALLOC_FREE(smb_fname);
1273 END_PROFILE(SMBsetatr);
1274 return;
1277 /****************************************************************************
1278 Reply to a dskattr.
1279 ****************************************************************************/
1281 void reply_dskattr(struct smb_request *req)
1283 connection_struct *conn = req->conn;
1284 uint64_t dfree,dsize,bsize;
1285 START_PROFILE(SMBdskattr);
1287 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1288 reply_nterror(req, map_nt_error_from_unix(errno));
1289 END_PROFILE(SMBdskattr);
1290 return;
1293 reply_outbuf(req, 5, 0);
1295 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1296 double total_space, free_space;
1297 /* we need to scale this to a number that DOS6 can handle. We
1298 use floating point so we can handle large drives on systems
1299 that don't have 64 bit integers
1301 we end up displaying a maximum of 2G to DOS systems
1303 total_space = dsize * (double)bsize;
1304 free_space = dfree * (double)bsize;
1306 dsize = (uint64_t)((total_space+63*512) / (64*512));
1307 dfree = (uint64_t)((free_space+63*512) / (64*512));
1309 if (dsize > 0xFFFF) dsize = 0xFFFF;
1310 if (dfree > 0xFFFF) dfree = 0xFFFF;
1312 SSVAL(req->outbuf,smb_vwv0,dsize);
1313 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1314 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1315 SSVAL(req->outbuf,smb_vwv3,dfree);
1316 } else {
1317 SSVAL(req->outbuf,smb_vwv0,dsize);
1318 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1319 SSVAL(req->outbuf,smb_vwv2,512);
1320 SSVAL(req->outbuf,smb_vwv3,dfree);
1323 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1325 END_PROFILE(SMBdskattr);
1326 return;
1330 * Utility function to split the filename from the directory.
1332 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1333 char **fname_dir_out,
1334 char **fname_mask_out)
1336 const char *p = NULL;
1337 char *fname_dir = NULL;
1338 char *fname_mask = NULL;
1340 p = strrchr_m(fname_in, '/');
1341 if (!p) {
1342 fname_dir = talloc_strdup(ctx, ".");
1343 fname_mask = talloc_strdup(ctx, fname_in);
1344 } else {
1345 fname_dir = talloc_strndup(ctx, fname_in,
1346 PTR_DIFF(p, fname_in));
1347 fname_mask = talloc_strdup(ctx, p+1);
1350 if (!fname_dir || !fname_mask) {
1351 TALLOC_FREE(fname_dir);
1352 TALLOC_FREE(fname_mask);
1353 return NT_STATUS_NO_MEMORY;
1356 *fname_dir_out = fname_dir;
1357 *fname_mask_out = fname_mask;
1358 return NT_STATUS_OK;
1361 /****************************************************************************
1362 Reply to a search.
1363 Can be called from SMBsearch, SMBffirst or SMBfunique.
1364 ****************************************************************************/
1366 void reply_search(struct smb_request *req)
1368 connection_struct *conn = req->conn;
1369 char *path = NULL;
1370 const char *mask = NULL;
1371 char *directory = NULL;
1372 struct smb_filename *smb_fname = NULL;
1373 char *fname = NULL;
1374 off_t size;
1375 uint32 mode;
1376 struct timespec date;
1377 uint32 dirtype;
1378 unsigned int numentries = 0;
1379 unsigned int maxentries = 0;
1380 bool finished = False;
1381 const char *p;
1382 int status_len;
1383 char status[21];
1384 int dptr_num= -1;
1385 bool check_descend = False;
1386 bool expect_close = False;
1387 NTSTATUS nt_status;
1388 bool mask_contains_wcard = False;
1389 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1390 TALLOC_CTX *ctx = talloc_tos();
1391 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1392 struct dptr_struct *dirptr = NULL;
1393 struct smbd_server_connection *sconn = req->sconn;
1395 START_PROFILE(SMBsearch);
1397 if (req->wct < 2) {
1398 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1399 goto out;
1402 if (lp_posix_pathnames()) {
1403 reply_unknown_new(req, req->cmd);
1404 goto out;
1407 /* If we were called as SMBffirst then we must expect close. */
1408 if(req->cmd == SMBffirst) {
1409 expect_close = True;
1412 reply_outbuf(req, 1, 3);
1413 maxentries = SVAL(req->vwv+0, 0);
1414 dirtype = SVAL(req->vwv+1, 0);
1415 p = (const char *)req->buf + 1;
1416 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1417 &nt_status, &mask_contains_wcard);
1418 if (!NT_STATUS_IS_OK(nt_status)) {
1419 reply_nterror(req, nt_status);
1420 goto out;
1423 p++;
1424 status_len = SVAL(p, 0);
1425 p += 2;
1427 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1429 if (status_len == 0) {
1430 nt_status = filename_convert(ctx, conn,
1431 req->flags2 & FLAGS2_DFS_PATHNAMES,
1432 path,
1433 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1434 &mask_contains_wcard,
1435 &smb_fname);
1436 if (!NT_STATUS_IS_OK(nt_status)) {
1437 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1438 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1439 ERRSRV, ERRbadpath);
1440 goto out;
1442 reply_nterror(req, nt_status);
1443 goto out;
1446 directory = smb_fname->base_name;
1448 p = strrchr_m(directory,'/');
1449 if ((p != NULL) && (*directory != '/')) {
1450 mask = p + 1;
1451 directory = talloc_strndup(ctx, directory,
1452 PTR_DIFF(p, directory));
1453 } else {
1454 mask = directory;
1455 directory = talloc_strdup(ctx,".");
1458 if (!directory) {
1459 reply_nterror(req, NT_STATUS_NO_MEMORY);
1460 goto out;
1463 memset((char *)status,'\0',21);
1464 SCVAL(status,0,(dirtype & 0x1F));
1466 nt_status = dptr_create(conn,
1467 NULL, /* req */
1468 NULL, /* fsp */
1469 directory,
1470 True,
1471 expect_close,
1472 req->smbpid,
1473 mask,
1474 mask_contains_wcard,
1475 dirtype,
1476 &dirptr);
1477 if (!NT_STATUS_IS_OK(nt_status)) {
1478 reply_nterror(req, nt_status);
1479 goto out;
1481 dptr_num = dptr_dnum(dirptr);
1482 } else {
1483 int status_dirtype;
1484 const char *dirpath;
1486 memcpy(status,p,21);
1487 status_dirtype = CVAL(status,0) & 0x1F;
1488 if (status_dirtype != (dirtype & 0x1F)) {
1489 dirtype = status_dirtype;
1492 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1493 if (!dirptr) {
1494 goto SearchEmpty;
1496 dirpath = dptr_path(sconn, dptr_num);
1497 directory = talloc_strdup(ctx, dirpath);
1498 if (!directory) {
1499 reply_nterror(req, NT_STATUS_NO_MEMORY);
1500 goto out;
1503 mask = dptr_wcard(sconn, dptr_num);
1504 if (!mask) {
1505 goto SearchEmpty;
1508 * For a 'continue' search we have no string. So
1509 * check from the initial saved string.
1511 mask_contains_wcard = ms_has_wild(mask);
1512 dirtype = dptr_attr(sconn, dptr_num);
1515 DEBUG(4,("dptr_num is %d\n",dptr_num));
1517 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1518 dptr_init_search_op(dirptr);
1520 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1521 char buf[DIR_STRUCT_SIZE];
1522 memcpy(buf,status,21);
1523 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1524 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1525 reply_nterror(req, NT_STATUS_NO_MEMORY);
1526 goto out;
1528 dptr_fill(sconn, buf+12,dptr_num);
1529 if (dptr_zero(buf+12) && (status_len==0)) {
1530 numentries = 1;
1531 } else {
1532 numentries = 0;
1534 if (message_push_blob(&req->outbuf,
1535 data_blob_const(buf, sizeof(buf)))
1536 == -1) {
1537 reply_nterror(req, NT_STATUS_NO_MEMORY);
1538 goto out;
1540 } else {
1541 unsigned int i;
1542 maxentries = MIN(
1543 maxentries,
1544 ((BUFFER_SIZE -
1545 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1546 /DIR_STRUCT_SIZE));
1548 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1549 directory,lp_dontdescend(SNUM(conn))));
1550 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1551 check_descend = True;
1554 for (i=numentries;(i<maxentries) && !finished;i++) {
1555 finished = !get_dir_entry(ctx,
1556 dirptr,
1557 mask,
1558 dirtype,
1559 &fname,
1560 &size,
1561 &mode,
1562 &date,
1563 check_descend,
1564 ask_sharemode);
1565 if (!finished) {
1566 char buf[DIR_STRUCT_SIZE];
1567 memcpy(buf,status,21);
1568 if (!make_dir_struct(ctx,
1569 buf,
1570 mask,
1571 fname,
1572 size,
1573 mode,
1574 convert_timespec_to_time_t(date),
1575 !allow_long_path_components)) {
1576 reply_nterror(req, NT_STATUS_NO_MEMORY);
1577 goto out;
1579 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1580 break;
1582 if (message_push_blob(&req->outbuf,
1583 data_blob_const(buf, sizeof(buf)))
1584 == -1) {
1585 reply_nterror(req, NT_STATUS_NO_MEMORY);
1586 goto out;
1588 numentries++;
1593 SearchEmpty:
1595 /* If we were called as SMBffirst with smb_search_id == NULL
1596 and no entries were found then return error and close dirptr
1597 (X/Open spec) */
1599 if (numentries == 0) {
1600 dptr_close(sconn, &dptr_num);
1601 } else if(expect_close && status_len == 0) {
1602 /* Close the dptr - we know it's gone */
1603 dptr_close(sconn, &dptr_num);
1606 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1607 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1608 dptr_close(sconn, &dptr_num);
1611 if ((numentries == 0) && !mask_contains_wcard) {
1612 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1613 goto out;
1616 SSVAL(req->outbuf,smb_vwv0,numentries);
1617 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1618 SCVAL(smb_buf(req->outbuf),0,5);
1619 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1621 /* The replies here are never long name. */
1622 SSVAL(req->outbuf, smb_flg2,
1623 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1624 if (!allow_long_path_components) {
1625 SSVAL(req->outbuf, smb_flg2,
1626 SVAL(req->outbuf, smb_flg2)
1627 & (~FLAGS2_LONG_PATH_COMPONENTS));
1630 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1631 SSVAL(req->outbuf, smb_flg2,
1632 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1634 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1635 smb_fn_name(req->cmd),
1636 mask,
1637 directory,
1638 dirtype,
1639 numentries,
1640 maxentries ));
1641 out:
1642 TALLOC_FREE(directory);
1643 TALLOC_FREE(smb_fname);
1644 END_PROFILE(SMBsearch);
1645 return;
1648 /****************************************************************************
1649 Reply to a fclose (stop directory search).
1650 ****************************************************************************/
1652 void reply_fclose(struct smb_request *req)
1654 int status_len;
1655 char status[21];
1656 int dptr_num= -2;
1657 const char *p;
1658 char *path = NULL;
1659 NTSTATUS err;
1660 bool path_contains_wcard = False;
1661 TALLOC_CTX *ctx = talloc_tos();
1662 struct smbd_server_connection *sconn = req->sconn;
1664 START_PROFILE(SMBfclose);
1666 if (lp_posix_pathnames()) {
1667 reply_unknown_new(req, req->cmd);
1668 END_PROFILE(SMBfclose);
1669 return;
1672 p = (const char *)req->buf + 1;
1673 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1674 &err, &path_contains_wcard);
1675 if (!NT_STATUS_IS_OK(err)) {
1676 reply_nterror(req, err);
1677 END_PROFILE(SMBfclose);
1678 return;
1680 p++;
1681 status_len = SVAL(p,0);
1682 p += 2;
1684 if (status_len == 0) {
1685 reply_force_doserror(req, ERRSRV, ERRsrverror);
1686 END_PROFILE(SMBfclose);
1687 return;
1690 memcpy(status,p,21);
1692 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1693 /* Close the dptr - we know it's gone */
1694 dptr_close(sconn, &dptr_num);
1697 reply_outbuf(req, 1, 0);
1698 SSVAL(req->outbuf,smb_vwv0,0);
1700 DEBUG(3,("search close\n"));
1702 END_PROFILE(SMBfclose);
1703 return;
1706 /****************************************************************************
1707 Reply to an open.
1708 ****************************************************************************/
1710 void reply_open(struct smb_request *req)
1712 connection_struct *conn = req->conn;
1713 struct smb_filename *smb_fname = NULL;
1714 char *fname = NULL;
1715 uint32 fattr=0;
1716 off_t size = 0;
1717 time_t mtime=0;
1718 int info;
1719 files_struct *fsp;
1720 int oplock_request;
1721 int deny_mode;
1722 uint32 dos_attr;
1723 uint32 access_mask;
1724 uint32 share_mode;
1725 uint32 create_disposition;
1726 uint32 create_options = 0;
1727 uint32_t private_flags = 0;
1728 NTSTATUS status;
1729 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1730 TALLOC_CTX *ctx = talloc_tos();
1732 START_PROFILE(SMBopen);
1734 if (req->wct < 2) {
1735 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1736 goto out;
1739 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1740 deny_mode = SVAL(req->vwv+0, 0);
1741 dos_attr = SVAL(req->vwv+1, 0);
1743 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1744 STR_TERMINATE, &status);
1745 if (!NT_STATUS_IS_OK(status)) {
1746 reply_nterror(req, status);
1747 goto out;
1750 status = filename_convert(ctx,
1751 conn,
1752 req->flags2 & FLAGS2_DFS_PATHNAMES,
1753 fname,
1755 NULL,
1756 &smb_fname);
1757 if (!NT_STATUS_IS_OK(status)) {
1758 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1759 reply_botherror(req,
1760 NT_STATUS_PATH_NOT_COVERED,
1761 ERRSRV, ERRbadpath);
1762 goto out;
1764 reply_nterror(req, status);
1765 goto out;
1768 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1769 OPENX_FILE_EXISTS_OPEN, &access_mask,
1770 &share_mode, &create_disposition,
1771 &create_options, &private_flags)) {
1772 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1773 goto out;
1776 status = SMB_VFS_CREATE_FILE(
1777 conn, /* conn */
1778 req, /* req */
1779 0, /* root_dir_fid */
1780 smb_fname, /* fname */
1781 access_mask, /* access_mask */
1782 share_mode, /* share_access */
1783 create_disposition, /* create_disposition*/
1784 create_options, /* create_options */
1785 dos_attr, /* file_attributes */
1786 oplock_request, /* oplock_request */
1787 0, /* allocation_size */
1788 private_flags,
1789 NULL, /* sd */
1790 NULL, /* ea_list */
1791 &fsp, /* result */
1792 &info); /* pinfo */
1794 if (!NT_STATUS_IS_OK(status)) {
1795 if (open_was_deferred(req->sconn, req->mid)) {
1796 /* We have re-scheduled this call. */
1797 goto out;
1799 reply_openerror(req, status);
1800 goto out;
1803 size = smb_fname->st.st_ex_size;
1804 fattr = dos_mode(conn, smb_fname);
1806 /* Deal with other possible opens having a modified
1807 write time. JRA. */
1808 if (ask_sharemode) {
1809 struct timespec write_time_ts;
1811 ZERO_STRUCT(write_time_ts);
1812 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1813 if (!null_timespec(write_time_ts)) {
1814 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1818 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1820 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1821 DEBUG(3,("attempt to open a directory %s\n",
1822 fsp_str_dbg(fsp)));
1823 close_file(req, fsp, ERROR_CLOSE);
1824 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1825 ERRDOS, ERRnoaccess);
1826 goto out;
1829 reply_outbuf(req, 7, 0);
1830 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1831 SSVAL(req->outbuf,smb_vwv1,fattr);
1832 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1833 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1834 } else {
1835 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1837 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1838 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1840 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1841 SCVAL(req->outbuf,smb_flg,
1842 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1845 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1846 SCVAL(req->outbuf,smb_flg,
1847 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1849 out:
1850 TALLOC_FREE(smb_fname);
1851 END_PROFILE(SMBopen);
1852 return;
1855 /****************************************************************************
1856 Reply to an open and X.
1857 ****************************************************************************/
1859 void reply_open_and_X(struct smb_request *req)
1861 connection_struct *conn = req->conn;
1862 struct smb_filename *smb_fname = NULL;
1863 char *fname = NULL;
1864 uint16 open_flags;
1865 int deny_mode;
1866 uint32 smb_attr;
1867 /* Breakout the oplock request bits so we can set the
1868 reply bits separately. */
1869 int ex_oplock_request;
1870 int core_oplock_request;
1871 int oplock_request;
1872 #if 0
1873 int smb_sattr = SVAL(req->vwv+4, 0);
1874 uint32 smb_time = make_unix_date3(req->vwv+6);
1875 #endif
1876 int smb_ofun;
1877 uint32 fattr=0;
1878 int mtime=0;
1879 int smb_action = 0;
1880 files_struct *fsp;
1881 NTSTATUS status;
1882 uint64_t allocation_size;
1883 ssize_t retval = -1;
1884 uint32 access_mask;
1885 uint32 share_mode;
1886 uint32 create_disposition;
1887 uint32 create_options = 0;
1888 uint32_t private_flags = 0;
1889 TALLOC_CTX *ctx = talloc_tos();
1891 START_PROFILE(SMBopenX);
1893 if (req->wct < 15) {
1894 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1895 goto out;
1898 open_flags = SVAL(req->vwv+2, 0);
1899 deny_mode = SVAL(req->vwv+3, 0);
1900 smb_attr = SVAL(req->vwv+5, 0);
1901 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1902 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1903 oplock_request = ex_oplock_request | core_oplock_request;
1904 smb_ofun = SVAL(req->vwv+8, 0);
1905 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1907 /* If it's an IPC, pass off the pipe handler. */
1908 if (IS_IPC(conn)) {
1909 if (lp_nt_pipe_support()) {
1910 reply_open_pipe_and_X(conn, req);
1911 } else {
1912 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1914 goto out;
1917 /* XXXX we need to handle passed times, sattr and flags */
1918 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1919 STR_TERMINATE, &status);
1920 if (!NT_STATUS_IS_OK(status)) {
1921 reply_nterror(req, status);
1922 goto out;
1925 status = filename_convert(ctx,
1926 conn,
1927 req->flags2 & FLAGS2_DFS_PATHNAMES,
1928 fname,
1930 NULL,
1931 &smb_fname);
1932 if (!NT_STATUS_IS_OK(status)) {
1933 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1934 reply_botherror(req,
1935 NT_STATUS_PATH_NOT_COVERED,
1936 ERRSRV, ERRbadpath);
1937 goto out;
1939 reply_nterror(req, status);
1940 goto out;
1943 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1944 smb_ofun,
1945 &access_mask, &share_mode,
1946 &create_disposition,
1947 &create_options,
1948 &private_flags)) {
1949 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1950 goto out;
1953 status = SMB_VFS_CREATE_FILE(
1954 conn, /* conn */
1955 req, /* req */
1956 0, /* root_dir_fid */
1957 smb_fname, /* fname */
1958 access_mask, /* access_mask */
1959 share_mode, /* share_access */
1960 create_disposition, /* create_disposition*/
1961 create_options, /* create_options */
1962 smb_attr, /* file_attributes */
1963 oplock_request, /* oplock_request */
1964 0, /* allocation_size */
1965 private_flags,
1966 NULL, /* sd */
1967 NULL, /* ea_list */
1968 &fsp, /* result */
1969 &smb_action); /* pinfo */
1971 if (!NT_STATUS_IS_OK(status)) {
1972 if (open_was_deferred(req->sconn, req->mid)) {
1973 /* We have re-scheduled this call. */
1974 goto out;
1976 reply_openerror(req, status);
1977 goto out;
1980 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1981 if the file is truncated or created. */
1982 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1983 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1984 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1985 close_file(req, fsp, ERROR_CLOSE);
1986 reply_nterror(req, NT_STATUS_DISK_FULL);
1987 goto out;
1989 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
1990 if (retval < 0) {
1991 close_file(req, fsp, ERROR_CLOSE);
1992 reply_nterror(req, NT_STATUS_DISK_FULL);
1993 goto out;
1995 status = vfs_stat_fsp(fsp);
1996 if (!NT_STATUS_IS_OK(status)) {
1997 close_file(req, fsp, ERROR_CLOSE);
1998 reply_nterror(req, status);
1999 goto out;
2003 fattr = dos_mode(conn, fsp->fsp_name);
2004 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2005 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2006 close_file(req, fsp, ERROR_CLOSE);
2007 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2008 goto out;
2011 /* If the caller set the extended oplock request bit
2012 and we granted one (by whatever means) - set the
2013 correct bit for extended oplock reply.
2016 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2017 smb_action |= EXTENDED_OPLOCK_GRANTED;
2020 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2021 smb_action |= EXTENDED_OPLOCK_GRANTED;
2024 /* If the caller set the core oplock request bit
2025 and we granted one (by whatever means) - set the
2026 correct bit for core oplock reply.
2029 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2030 reply_outbuf(req, 19, 0);
2031 } else {
2032 reply_outbuf(req, 15, 0);
2035 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2036 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
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 out:
2064 TALLOC_FREE(smb_fname);
2065 END_PROFILE(SMBopenX);
2066 return;
2069 /****************************************************************************
2070 Reply to a SMBulogoffX.
2071 ****************************************************************************/
2073 void reply_ulogoffX(struct smb_request *req)
2075 struct smbd_server_connection *sconn = req->sconn;
2076 struct user_struct *vuser;
2078 START_PROFILE(SMBulogoffX);
2080 vuser = get_valid_user_struct(sconn, req->vuid);
2082 if(vuser == NULL) {
2083 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2084 req->vuid));
2086 req->vuid = UID_FIELD_INVALID;
2087 reply_force_doserror(req, ERRSRV, ERRbaduid);
2088 END_PROFILE(SMBulogoffX);
2089 return;
2092 /* in user level security we are supposed to close any files
2093 open by this user */
2094 if (vuser != NULL) {
2095 file_close_user(sconn, req->vuid);
2098 invalidate_vuid(sconn, req->vuid);
2100 reply_outbuf(req, 2, 0);
2101 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2102 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2104 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2106 END_PROFILE(SMBulogoffX);
2107 req->vuid = UID_FIELD_INVALID;
2110 /****************************************************************************
2111 Reply to a mknew or a create.
2112 ****************************************************************************/
2114 void reply_mknew(struct smb_request *req)
2116 connection_struct *conn = req->conn;
2117 struct smb_filename *smb_fname = NULL;
2118 char *fname = NULL;
2119 uint32 fattr = 0;
2120 struct smb_file_time ft;
2121 files_struct *fsp;
2122 int oplock_request = 0;
2123 NTSTATUS status;
2124 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2125 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2126 uint32 create_disposition;
2127 uint32 create_options = 0;
2128 TALLOC_CTX *ctx = talloc_tos();
2130 START_PROFILE(SMBcreate);
2131 ZERO_STRUCT(ft);
2133 if (req->wct < 3) {
2134 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2135 goto out;
2138 fattr = SVAL(req->vwv+0, 0);
2139 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2141 /* mtime. */
2142 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2144 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2145 STR_TERMINATE, &status);
2146 if (!NT_STATUS_IS_OK(status)) {
2147 reply_nterror(req, status);
2148 goto out;
2151 status = filename_convert(ctx,
2152 conn,
2153 req->flags2 & FLAGS2_DFS_PATHNAMES,
2154 fname,
2156 NULL,
2157 &smb_fname);
2158 if (!NT_STATUS_IS_OK(status)) {
2159 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2160 reply_botherror(req,
2161 NT_STATUS_PATH_NOT_COVERED,
2162 ERRSRV, ERRbadpath);
2163 goto out;
2165 reply_nterror(req, status);
2166 goto out;
2169 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2170 DEBUG(0,("Attempt to create file (%s) with volid set - "
2171 "please report this\n",
2172 smb_fname_str_dbg(smb_fname)));
2175 if(req->cmd == SMBmknew) {
2176 /* We should fail if file exists. */
2177 create_disposition = FILE_CREATE;
2178 } else {
2179 /* Create if file doesn't exist, truncate if it does. */
2180 create_disposition = FILE_OVERWRITE_IF;
2183 status = SMB_VFS_CREATE_FILE(
2184 conn, /* conn */
2185 req, /* req */
2186 0, /* root_dir_fid */
2187 smb_fname, /* fname */
2188 access_mask, /* access_mask */
2189 share_mode, /* share_access */
2190 create_disposition, /* create_disposition*/
2191 create_options, /* create_options */
2192 fattr, /* file_attributes */
2193 oplock_request, /* oplock_request */
2194 0, /* allocation_size */
2195 0, /* private_flags */
2196 NULL, /* sd */
2197 NULL, /* ea_list */
2198 &fsp, /* result */
2199 NULL); /* pinfo */
2201 if (!NT_STATUS_IS_OK(status)) {
2202 if (open_was_deferred(req->sconn, req->mid)) {
2203 /* We have re-scheduled this call. */
2204 goto out;
2206 reply_openerror(req, status);
2207 goto out;
2210 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2211 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2212 if (!NT_STATUS_IS_OK(status)) {
2213 END_PROFILE(SMBcreate);
2214 goto out;
2217 reply_outbuf(req, 1, 0);
2218 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2220 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2221 SCVAL(req->outbuf,smb_flg,
2222 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2225 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2226 SCVAL(req->outbuf,smb_flg,
2227 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2230 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2231 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2232 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2233 (unsigned int)fattr));
2235 out:
2236 TALLOC_FREE(smb_fname);
2237 END_PROFILE(SMBcreate);
2238 return;
2241 /****************************************************************************
2242 Reply to a create temporary file.
2243 ****************************************************************************/
2245 void reply_ctemp(struct smb_request *req)
2247 connection_struct *conn = req->conn;
2248 struct smb_filename *smb_fname = NULL;
2249 char *fname = NULL;
2250 uint32 fattr;
2251 files_struct *fsp;
2252 int oplock_request;
2253 int tmpfd;
2254 char *s;
2255 NTSTATUS status;
2256 TALLOC_CTX *ctx = talloc_tos();
2258 START_PROFILE(SMBctemp);
2260 if (req->wct < 3) {
2261 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2262 goto out;
2265 fattr = SVAL(req->vwv+0, 0);
2266 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2268 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2269 STR_TERMINATE, &status);
2270 if (!NT_STATUS_IS_OK(status)) {
2271 reply_nterror(req, status);
2272 goto out;
2274 if (*fname) {
2275 fname = talloc_asprintf(ctx,
2276 "%s/TMXXXXXX",
2277 fname);
2278 } else {
2279 fname = talloc_strdup(ctx, "TMXXXXXX");
2282 if (!fname) {
2283 reply_nterror(req, NT_STATUS_NO_MEMORY);
2284 goto out;
2287 status = filename_convert(ctx, conn,
2288 req->flags2 & FLAGS2_DFS_PATHNAMES,
2289 fname,
2291 NULL,
2292 &smb_fname);
2293 if (!NT_STATUS_IS_OK(status)) {
2294 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2295 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2296 ERRSRV, ERRbadpath);
2297 goto out;
2299 reply_nterror(req, status);
2300 goto out;
2303 tmpfd = mkstemp(smb_fname->base_name);
2304 if (tmpfd == -1) {
2305 reply_nterror(req, map_nt_error_from_unix(errno));
2306 goto out;
2309 SMB_VFS_STAT(conn, smb_fname);
2311 /* We should fail if file does not exist. */
2312 status = SMB_VFS_CREATE_FILE(
2313 conn, /* conn */
2314 req, /* req */
2315 0, /* root_dir_fid */
2316 smb_fname, /* fname */
2317 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2318 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2319 FILE_OPEN, /* create_disposition*/
2320 0, /* create_options */
2321 fattr, /* file_attributes */
2322 oplock_request, /* oplock_request */
2323 0, /* allocation_size */
2324 0, /* private_flags */
2325 NULL, /* sd */
2326 NULL, /* ea_list */
2327 &fsp, /* result */
2328 NULL); /* pinfo */
2330 /* close fd from mkstemp() */
2331 close(tmpfd);
2333 if (!NT_STATUS_IS_OK(status)) {
2334 if (open_was_deferred(req->sconn, req->mid)) {
2335 /* We have re-scheduled this call. */
2336 goto out;
2338 reply_openerror(req, status);
2339 goto out;
2342 reply_outbuf(req, 1, 0);
2343 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2345 /* the returned filename is relative to the directory */
2346 s = strrchr_m(fsp->fsp_name->base_name, '/');
2347 if (!s) {
2348 s = fsp->fsp_name->base_name;
2349 } else {
2350 s++;
2353 #if 0
2354 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2355 thing in the byte section. JRA */
2356 SSVALS(p, 0, -1); /* what is this? not in spec */
2357 #endif
2358 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2359 == -1) {
2360 reply_nterror(req, NT_STATUS_NO_MEMORY);
2361 goto out;
2364 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2365 SCVAL(req->outbuf, smb_flg,
2366 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2369 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2370 SCVAL(req->outbuf, smb_flg,
2371 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2374 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2375 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2376 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2377 out:
2378 TALLOC_FREE(smb_fname);
2379 END_PROFILE(SMBctemp);
2380 return;
2383 /*******************************************************************
2384 Check if a user is allowed to rename a file.
2385 ********************************************************************/
2387 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2388 uint16 dirtype)
2390 if (!CAN_WRITE(conn)) {
2391 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2394 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2395 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2396 /* Only bother to read the DOS attribute if we might deny the
2397 rename on the grounds of attribute missmatch. */
2398 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2399 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2400 return NT_STATUS_NO_SUCH_FILE;
2404 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2405 if (fsp->posix_open) {
2406 return NT_STATUS_OK;
2409 /* If no pathnames are open below this
2410 directory, allow the rename. */
2412 if (file_find_subpath(fsp)) {
2413 return NT_STATUS_ACCESS_DENIED;
2415 return NT_STATUS_OK;
2418 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2419 return NT_STATUS_OK;
2422 return NT_STATUS_ACCESS_DENIED;
2425 /*******************************************************************
2426 * unlink a file with all relevant access checks
2427 *******************************************************************/
2429 static NTSTATUS do_unlink(connection_struct *conn,
2430 struct smb_request *req,
2431 struct smb_filename *smb_fname,
2432 uint32 dirtype)
2434 uint32 fattr;
2435 files_struct *fsp;
2436 uint32 dirtype_orig = dirtype;
2437 NTSTATUS status;
2438 int ret;
2439 bool posix_paths = lp_posix_pathnames();
2441 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2442 smb_fname_str_dbg(smb_fname),
2443 dirtype));
2445 if (!CAN_WRITE(conn)) {
2446 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2449 if (posix_paths) {
2450 ret = SMB_VFS_LSTAT(conn, smb_fname);
2451 } else {
2452 ret = SMB_VFS_STAT(conn, smb_fname);
2454 if (ret != 0) {
2455 return map_nt_error_from_unix(errno);
2458 fattr = dos_mode(conn, smb_fname);
2460 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2461 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2464 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2465 if (!dirtype) {
2466 return NT_STATUS_NO_SUCH_FILE;
2469 if (!dir_check_ftype(conn, fattr, dirtype)) {
2470 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2471 return NT_STATUS_FILE_IS_A_DIRECTORY;
2473 return NT_STATUS_NO_SUCH_FILE;
2476 if (dirtype_orig & 0x8000) {
2477 /* These will never be set for POSIX. */
2478 return NT_STATUS_NO_SUCH_FILE;
2481 #if 0
2482 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2483 return NT_STATUS_FILE_IS_A_DIRECTORY;
2486 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2487 return NT_STATUS_NO_SUCH_FILE;
2490 if (dirtype & 0xFF00) {
2491 /* These will never be set for POSIX. */
2492 return NT_STATUS_NO_SUCH_FILE;
2495 dirtype &= 0xFF;
2496 if (!dirtype) {
2497 return NT_STATUS_NO_SUCH_FILE;
2500 /* Can't delete a directory. */
2501 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2502 return NT_STATUS_FILE_IS_A_DIRECTORY;
2504 #endif
2506 #if 0 /* JRATEST */
2507 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2508 return NT_STATUS_OBJECT_NAME_INVALID;
2509 #endif /* JRATEST */
2511 /* On open checks the open itself will check the share mode, so
2512 don't do it here as we'll get it wrong. */
2514 status = SMB_VFS_CREATE_FILE
2515 (conn, /* conn */
2516 req, /* req */
2517 0, /* root_dir_fid */
2518 smb_fname, /* fname */
2519 DELETE_ACCESS, /* access_mask */
2520 FILE_SHARE_NONE, /* share_access */
2521 FILE_OPEN, /* create_disposition*/
2522 FILE_NON_DIRECTORY_FILE, /* create_options */
2523 /* file_attributes */
2524 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2525 FILE_ATTRIBUTE_NORMAL,
2526 0, /* oplock_request */
2527 0, /* allocation_size */
2528 0, /* private_flags */
2529 NULL, /* sd */
2530 NULL, /* ea_list */
2531 &fsp, /* result */
2532 NULL); /* pinfo */
2534 if (!NT_STATUS_IS_OK(status)) {
2535 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2536 nt_errstr(status)));
2537 return status;
2540 status = can_set_delete_on_close(fsp, fattr);
2541 if (!NT_STATUS_IS_OK(status)) {
2542 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2543 "(%s)\n",
2544 smb_fname_str_dbg(smb_fname),
2545 nt_errstr(status)));
2546 close_file(req, fsp, NORMAL_CLOSE);
2547 return status;
2550 /* The set is across all open files on this dev/inode pair. */
2551 if (!set_delete_on_close(fsp, True,
2552 conn->session_info->security_token,
2553 conn->session_info->unix_token)) {
2554 close_file(req, fsp, NORMAL_CLOSE);
2555 return NT_STATUS_ACCESS_DENIED;
2558 return close_file(req, fsp, NORMAL_CLOSE);
2561 /****************************************************************************
2562 The guts of the unlink command, split out so it may be called by the NT SMB
2563 code.
2564 ****************************************************************************/
2566 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2567 uint32 dirtype, struct smb_filename *smb_fname,
2568 bool has_wild)
2570 char *fname_dir = NULL;
2571 char *fname_mask = NULL;
2572 int count=0;
2573 NTSTATUS status = NT_STATUS_OK;
2574 TALLOC_CTX *ctx = talloc_tos();
2576 /* Split up the directory from the filename/mask. */
2577 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2578 &fname_dir, &fname_mask);
2579 if (!NT_STATUS_IS_OK(status)) {
2580 goto out;
2584 * We should only check the mangled cache
2585 * here if unix_convert failed. This means
2586 * that the path in 'mask' doesn't exist
2587 * on the file system and so we need to look
2588 * for a possible mangle. This patch from
2589 * Tine Smukavec <valentin.smukavec@hermes.si>.
2592 if (!VALID_STAT(smb_fname->st) &&
2593 mangle_is_mangled(fname_mask, conn->params)) {
2594 char *new_mask = NULL;
2595 mangle_lookup_name_from_8_3(ctx, fname_mask,
2596 &new_mask, conn->params);
2597 if (new_mask) {
2598 TALLOC_FREE(fname_mask);
2599 fname_mask = new_mask;
2603 if (!has_wild) {
2606 * Only one file needs to be unlinked. Append the mask back
2607 * onto the directory.
2609 TALLOC_FREE(smb_fname->base_name);
2610 if (ISDOT(fname_dir)) {
2611 /* Ensure we use canonical names on open. */
2612 smb_fname->base_name = talloc_asprintf(smb_fname,
2613 "%s",
2614 fname_mask);
2615 } else {
2616 smb_fname->base_name = talloc_asprintf(smb_fname,
2617 "%s/%s",
2618 fname_dir,
2619 fname_mask);
2621 if (!smb_fname->base_name) {
2622 status = NT_STATUS_NO_MEMORY;
2623 goto out;
2625 if (dirtype == 0) {
2626 dirtype = FILE_ATTRIBUTE_NORMAL;
2629 status = check_name(conn, smb_fname->base_name);
2630 if (!NT_STATUS_IS_OK(status)) {
2631 goto out;
2634 status = do_unlink(conn, req, smb_fname, dirtype);
2635 if (!NT_STATUS_IS_OK(status)) {
2636 goto out;
2639 count++;
2640 } else {
2641 struct smb_Dir *dir_hnd = NULL;
2642 long offset = 0;
2643 const char *dname = NULL;
2644 char *talloced = NULL;
2646 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2647 status = NT_STATUS_OBJECT_NAME_INVALID;
2648 goto out;
2651 if (strequal(fname_mask,"????????.???")) {
2652 TALLOC_FREE(fname_mask);
2653 fname_mask = talloc_strdup(ctx, "*");
2654 if (!fname_mask) {
2655 status = NT_STATUS_NO_MEMORY;
2656 goto out;
2660 status = check_name(conn, fname_dir);
2661 if (!NT_STATUS_IS_OK(status)) {
2662 goto out;
2665 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2666 dirtype);
2667 if (dir_hnd == NULL) {
2668 status = map_nt_error_from_unix(errno);
2669 goto out;
2672 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2673 the pattern matches against the long name, otherwise the short name
2674 We don't implement this yet XXXX
2677 status = NT_STATUS_NO_SUCH_FILE;
2679 while ((dname = ReadDirName(dir_hnd, &offset,
2680 &smb_fname->st, &talloced))) {
2681 TALLOC_CTX *frame = talloc_stackframe();
2683 if (!is_visible_file(conn, fname_dir, dname,
2684 &smb_fname->st, true)) {
2685 TALLOC_FREE(frame);
2686 TALLOC_FREE(talloced);
2687 continue;
2690 /* Quick check for "." and ".." */
2691 if (ISDOT(dname) || ISDOTDOT(dname)) {
2692 TALLOC_FREE(frame);
2693 TALLOC_FREE(talloced);
2694 continue;
2697 if(!mask_match(dname, fname_mask,
2698 conn->case_sensitive)) {
2699 TALLOC_FREE(frame);
2700 TALLOC_FREE(talloced);
2701 continue;
2704 TALLOC_FREE(smb_fname->base_name);
2705 if (ISDOT(fname_dir)) {
2706 /* Ensure we use canonical names on open. */
2707 smb_fname->base_name =
2708 talloc_asprintf(smb_fname, "%s",
2709 dname);
2710 } else {
2711 smb_fname->base_name =
2712 talloc_asprintf(smb_fname, "%s/%s",
2713 fname_dir, dname);
2716 if (!smb_fname->base_name) {
2717 TALLOC_FREE(dir_hnd);
2718 status = NT_STATUS_NO_MEMORY;
2719 TALLOC_FREE(frame);
2720 TALLOC_FREE(talloced);
2721 goto out;
2724 status = check_name(conn, smb_fname->base_name);
2725 if (!NT_STATUS_IS_OK(status)) {
2726 TALLOC_FREE(dir_hnd);
2727 TALLOC_FREE(frame);
2728 TALLOC_FREE(talloced);
2729 goto out;
2732 status = do_unlink(conn, req, smb_fname, dirtype);
2733 if (!NT_STATUS_IS_OK(status)) {
2734 TALLOC_FREE(frame);
2735 TALLOC_FREE(talloced);
2736 continue;
2739 count++;
2740 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2741 smb_fname->base_name));
2743 TALLOC_FREE(frame);
2744 TALLOC_FREE(talloced);
2746 TALLOC_FREE(dir_hnd);
2749 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2750 status = map_nt_error_from_unix(errno);
2753 out:
2754 TALLOC_FREE(fname_dir);
2755 TALLOC_FREE(fname_mask);
2756 return status;
2759 /****************************************************************************
2760 Reply to a unlink
2761 ****************************************************************************/
2763 void reply_unlink(struct smb_request *req)
2765 connection_struct *conn = req->conn;
2766 char *name = NULL;
2767 struct smb_filename *smb_fname = NULL;
2768 uint32 dirtype;
2769 NTSTATUS status;
2770 bool path_contains_wcard = False;
2771 TALLOC_CTX *ctx = talloc_tos();
2773 START_PROFILE(SMBunlink);
2775 if (req->wct < 1) {
2776 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2777 goto out;
2780 dirtype = SVAL(req->vwv+0, 0);
2782 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2783 STR_TERMINATE, &status,
2784 &path_contains_wcard);
2785 if (!NT_STATUS_IS_OK(status)) {
2786 reply_nterror(req, status);
2787 goto out;
2790 status = filename_convert(ctx, conn,
2791 req->flags2 & FLAGS2_DFS_PATHNAMES,
2792 name,
2793 UCF_COND_ALLOW_WCARD_LCOMP,
2794 &path_contains_wcard,
2795 &smb_fname);
2796 if (!NT_STATUS_IS_OK(status)) {
2797 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2798 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2799 ERRSRV, ERRbadpath);
2800 goto out;
2802 reply_nterror(req, status);
2803 goto out;
2806 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2808 status = unlink_internals(conn, req, dirtype, smb_fname,
2809 path_contains_wcard);
2810 if (!NT_STATUS_IS_OK(status)) {
2811 if (open_was_deferred(req->sconn, req->mid)) {
2812 /* We have re-scheduled this call. */
2813 goto out;
2815 reply_nterror(req, status);
2816 goto out;
2819 reply_outbuf(req, 0, 0);
2820 out:
2821 TALLOC_FREE(smb_fname);
2822 END_PROFILE(SMBunlink);
2823 return;
2826 /****************************************************************************
2827 Fail for readbraw.
2828 ****************************************************************************/
2830 static void fail_readraw(void)
2832 const char *errstr = talloc_asprintf(talloc_tos(),
2833 "FAIL ! reply_readbraw: socket write fail (%s)",
2834 strerror(errno));
2835 if (!errstr) {
2836 errstr = "";
2838 exit_server_cleanly(errstr);
2841 /****************************************************************************
2842 Fake (read/write) sendfile. Returns -1 on read or write fail.
2843 ****************************************************************************/
2845 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
2847 size_t bufsize;
2848 size_t tosend = nread;
2849 char *buf;
2851 if (nread == 0) {
2852 return 0;
2855 bufsize = MIN(nread, 65536);
2857 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2858 return -1;
2861 while (tosend > 0) {
2862 ssize_t ret;
2863 size_t cur_read;
2865 if (tosend > bufsize) {
2866 cur_read = bufsize;
2867 } else {
2868 cur_read = tosend;
2870 ret = read_file(fsp,buf,startpos,cur_read);
2871 if (ret == -1) {
2872 SAFE_FREE(buf);
2873 return -1;
2876 /* If we had a short read, fill with zeros. */
2877 if (ret < cur_read) {
2878 memset(buf + ret, '\0', cur_read - ret);
2881 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2882 != cur_read) {
2883 char addr[INET6_ADDRSTRLEN];
2885 * Try and give an error message saying what
2886 * client failed.
2888 DEBUG(0, ("write_data failed for client %s. "
2889 "Error %s\n",
2890 get_peer_addr(fsp->conn->sconn->sock, addr,
2891 sizeof(addr)),
2892 strerror(errno)));
2893 SAFE_FREE(buf);
2894 return -1;
2896 tosend -= cur_read;
2897 startpos += cur_read;
2900 SAFE_FREE(buf);
2901 return (ssize_t)nread;
2904 /****************************************************************************
2905 Deal with the case of sendfile reading less bytes from the file than
2906 requested. Fill with zeros (all we can do).
2907 ****************************************************************************/
2909 void sendfile_short_send(files_struct *fsp,
2910 ssize_t nread,
2911 size_t headersize,
2912 size_t smb_maxcnt)
2914 #define SHORT_SEND_BUFSIZE 1024
2915 if (nread < headersize) {
2916 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2917 "header for file %s (%s). Terminating\n",
2918 fsp_str_dbg(fsp), strerror(errno)));
2919 exit_server_cleanly("sendfile_short_send failed");
2922 nread -= headersize;
2924 if (nread < smb_maxcnt) {
2925 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2926 if (!buf) {
2927 exit_server_cleanly("sendfile_short_send: "
2928 "malloc failed");
2931 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2932 "with zeros !\n", fsp_str_dbg(fsp)));
2934 while (nread < smb_maxcnt) {
2936 * We asked for the real file size and told sendfile
2937 * to not go beyond the end of the file. But it can
2938 * happen that in between our fstat call and the
2939 * sendfile call the file was truncated. This is very
2940 * bad because we have already announced the larger
2941 * number of bytes to the client.
2943 * The best we can do now is to send 0-bytes, just as
2944 * a read from a hole in a sparse file would do.
2946 * This should happen rarely enough that I don't care
2947 * about efficiency here :-)
2949 size_t to_write;
2951 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2952 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2953 != to_write) {
2954 char addr[INET6_ADDRSTRLEN];
2956 * Try and give an error message saying what
2957 * client failed.
2959 DEBUG(0, ("write_data failed for client %s. "
2960 "Error %s\n",
2961 get_peer_addr(
2962 fsp->conn->sconn->sock, addr,
2963 sizeof(addr)),
2964 strerror(errno)));
2965 exit_server_cleanly("sendfile_short_send: "
2966 "write_data failed");
2968 nread += to_write;
2970 SAFE_FREE(buf);
2974 /****************************************************************************
2975 Return a readbraw error (4 bytes of zero).
2976 ****************************************************************************/
2978 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2980 char header[4];
2982 SIVAL(header,0,0);
2984 smbd_lock_socket(sconn);
2985 if (write_data(sconn->sock,header,4) != 4) {
2986 char addr[INET6_ADDRSTRLEN];
2988 * Try and give an error message saying what
2989 * client failed.
2991 DEBUG(0, ("write_data failed for client %s. "
2992 "Error %s\n",
2993 get_peer_addr(sconn->sock, addr, sizeof(addr)),
2994 strerror(errno)));
2996 fail_readraw();
2998 smbd_unlock_socket(sconn);
3001 /****************************************************************************
3002 Use sendfile in readbraw.
3003 ****************************************************************************/
3005 static void send_file_readbraw(connection_struct *conn,
3006 struct smb_request *req,
3007 files_struct *fsp,
3008 off_t startpos,
3009 size_t nread,
3010 ssize_t mincount)
3012 struct smbd_server_connection *sconn = req->sconn;
3013 char *outbuf = NULL;
3014 ssize_t ret=0;
3017 * We can only use sendfile on a non-chained packet
3018 * but we can use on a non-oplocked file. tridge proved this
3019 * on a train in Germany :-). JRA.
3020 * reply_readbraw has already checked the length.
3023 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3024 (fsp->wcp == NULL) &&
3025 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3026 ssize_t sendfile_read = -1;
3027 char header[4];
3028 DATA_BLOB header_blob;
3030 _smb_setlen(header,nread);
3031 header_blob = data_blob_const(header, 4);
3033 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3034 &header_blob, startpos,
3035 nread);
3036 if (sendfile_read == -1) {
3037 /* Returning ENOSYS means no data at all was sent.
3038 * Do this as a normal read. */
3039 if (errno == ENOSYS) {
3040 goto normal_readbraw;
3044 * Special hack for broken Linux with no working sendfile. If we
3045 * return EINTR we sent the header but not the rest of the data.
3046 * Fake this up by doing read/write calls.
3048 if (errno == EINTR) {
3049 /* Ensure we don't do this again. */
3050 set_use_sendfile(SNUM(conn), False);
3051 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3053 if (fake_sendfile(fsp, startpos, nread) == -1) {
3054 DEBUG(0,("send_file_readbraw: "
3055 "fake_sendfile failed for "
3056 "file %s (%s).\n",
3057 fsp_str_dbg(fsp),
3058 strerror(errno)));
3059 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3061 return;
3064 DEBUG(0,("send_file_readbraw: sendfile failed for "
3065 "file %s (%s). Terminating\n",
3066 fsp_str_dbg(fsp), strerror(errno)));
3067 exit_server_cleanly("send_file_readbraw sendfile failed");
3068 } else if (sendfile_read == 0) {
3070 * Some sendfile implementations return 0 to indicate
3071 * that there was a short read, but nothing was
3072 * actually written to the socket. In this case,
3073 * fallback to the normal read path so the header gets
3074 * the correct byte count.
3076 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3077 "bytes falling back to the normal read: "
3078 "%s\n", fsp_str_dbg(fsp)));
3079 goto normal_readbraw;
3082 /* Deal with possible short send. */
3083 if (sendfile_read != 4+nread) {
3084 sendfile_short_send(fsp, sendfile_read, 4, nread);
3086 return;
3089 normal_readbraw:
3091 outbuf = talloc_array(NULL, char, nread+4);
3092 if (!outbuf) {
3093 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3094 (unsigned)(nread+4)));
3095 reply_readbraw_error(sconn);
3096 return;
3099 if (nread > 0) {
3100 ret = read_file(fsp,outbuf+4,startpos,nread);
3101 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3102 if (ret < mincount)
3103 ret = 0;
3104 #else
3105 if (ret < nread)
3106 ret = 0;
3107 #endif
3110 _smb_setlen(outbuf,ret);
3111 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3112 char addr[INET6_ADDRSTRLEN];
3114 * Try and give an error message saying what
3115 * client failed.
3117 DEBUG(0, ("write_data failed for client %s. "
3118 "Error %s\n",
3119 get_peer_addr(fsp->conn->sconn->sock, addr,
3120 sizeof(addr)),
3121 strerror(errno)));
3123 fail_readraw();
3126 TALLOC_FREE(outbuf);
3129 /****************************************************************************
3130 Reply to a readbraw (core+ protocol).
3131 ****************************************************************************/
3133 void reply_readbraw(struct smb_request *req)
3135 connection_struct *conn = req->conn;
3136 struct smbd_server_connection *sconn = req->sconn;
3137 ssize_t maxcount,mincount;
3138 size_t nread = 0;
3139 off_t startpos;
3140 files_struct *fsp;
3141 struct lock_struct lock;
3142 off_t size = 0;
3144 START_PROFILE(SMBreadbraw);
3146 if (srv_is_signing_active(sconn) ||
3147 is_encrypted_packet(sconn, req->inbuf)) {
3148 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3149 "raw reads/writes are disallowed.");
3152 if (req->wct < 8) {
3153 reply_readbraw_error(sconn);
3154 END_PROFILE(SMBreadbraw);
3155 return;
3158 if (sconn->smb1.echo_handler.trusted_fde) {
3159 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3160 "'async smb echo handler = yes'\n"));
3161 reply_readbraw_error(sconn);
3162 END_PROFILE(SMBreadbraw);
3163 return;
3167 * Special check if an oplock break has been issued
3168 * and the readraw request croses on the wire, we must
3169 * return a zero length response here.
3172 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3175 * We have to do a check_fsp by hand here, as
3176 * we must always return 4 zero bytes on error,
3177 * not a NTSTATUS.
3180 if (!fsp || !conn || conn != fsp->conn ||
3181 req->vuid != fsp->vuid ||
3182 fsp->is_directory || fsp->fh->fd == -1) {
3184 * fsp could be NULL here so use the value from the packet. JRA.
3186 DEBUG(3,("reply_readbraw: fnum %d not valid "
3187 "- cache prime?\n",
3188 (int)SVAL(req->vwv+0, 0)));
3189 reply_readbraw_error(sconn);
3190 END_PROFILE(SMBreadbraw);
3191 return;
3194 /* Do a "by hand" version of CHECK_READ. */
3195 if (!(fsp->can_read ||
3196 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3197 (fsp->access_mask & FILE_EXECUTE)))) {
3198 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3199 (int)SVAL(req->vwv+0, 0)));
3200 reply_readbraw_error(sconn);
3201 END_PROFILE(SMBreadbraw);
3202 return;
3205 flush_write_cache(fsp, READRAW_FLUSH);
3207 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3208 if(req->wct == 10) {
3210 * This is a large offset (64 bit) read.
3213 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3215 if(startpos < 0) {
3216 DEBUG(0,("reply_readbraw: negative 64 bit "
3217 "readraw offset (%.0f) !\n",
3218 (double)startpos ));
3219 reply_readbraw_error(sconn);
3220 END_PROFILE(SMBreadbraw);
3221 return;
3225 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3226 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3228 /* ensure we don't overrun the packet size */
3229 maxcount = MIN(65535,maxcount);
3231 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3232 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3233 &lock);
3235 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3236 reply_readbraw_error(sconn);
3237 END_PROFILE(SMBreadbraw);
3238 return;
3241 if (fsp_stat(fsp) == 0) {
3242 size = fsp->fsp_name->st.st_ex_size;
3245 if (startpos >= size) {
3246 nread = 0;
3247 } else {
3248 nread = MIN(maxcount,(size - startpos));
3251 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3252 if (nread < mincount)
3253 nread = 0;
3254 #endif
3256 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3257 "min=%lu nread=%lu\n",
3258 fsp->fnum, (double)startpos,
3259 (unsigned long)maxcount,
3260 (unsigned long)mincount,
3261 (unsigned long)nread ) );
3263 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3265 DEBUG(5,("reply_readbraw finished\n"));
3267 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3269 END_PROFILE(SMBreadbraw);
3270 return;
3273 #undef DBGC_CLASS
3274 #define DBGC_CLASS DBGC_LOCKING
3276 /****************************************************************************
3277 Reply to a lockread (core+ protocol).
3278 ****************************************************************************/
3280 void reply_lockread(struct smb_request *req)
3282 connection_struct *conn = req->conn;
3283 ssize_t nread = -1;
3284 char *data;
3285 off_t startpos;
3286 size_t numtoread;
3287 NTSTATUS status;
3288 files_struct *fsp;
3289 struct byte_range_lock *br_lck = NULL;
3290 char *p = NULL;
3291 struct smbd_server_connection *sconn = req->sconn;
3293 START_PROFILE(SMBlockread);
3295 if (req->wct < 5) {
3296 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3297 END_PROFILE(SMBlockread);
3298 return;
3301 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3303 if (!check_fsp(conn, req, fsp)) {
3304 END_PROFILE(SMBlockread);
3305 return;
3308 if (!CHECK_READ(fsp,req)) {
3309 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3310 END_PROFILE(SMBlockread);
3311 return;
3314 numtoread = SVAL(req->vwv+1, 0);
3315 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3317 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3319 reply_outbuf(req, 5, numtoread + 3);
3321 data = smb_buf(req->outbuf) + 3;
3324 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3325 * protocol request that predates the read/write lock concept.
3326 * Thus instead of asking for a read lock here we need to ask
3327 * for a write lock. JRA.
3328 * Note that the requested lock size is unaffected by max_recv.
3331 br_lck = do_lock(req->sconn->msg_ctx,
3332 fsp,
3333 (uint64_t)req->smbpid,
3334 (uint64_t)numtoread,
3335 (uint64_t)startpos,
3336 WRITE_LOCK,
3337 WINDOWS_LOCK,
3338 False, /* Non-blocking lock. */
3339 &status,
3340 NULL,
3341 NULL);
3342 TALLOC_FREE(br_lck);
3344 if (NT_STATUS_V(status)) {
3345 reply_nterror(req, status);
3346 END_PROFILE(SMBlockread);
3347 return;
3351 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3354 if (numtoread > sconn->smb1.negprot.max_recv) {
3355 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3356 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3357 (unsigned int)numtoread,
3358 (unsigned int)sconn->smb1.negprot.max_recv));
3359 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3361 nread = read_file(fsp,data,startpos,numtoread);
3363 if (nread < 0) {
3364 reply_nterror(req, map_nt_error_from_unix(errno));
3365 END_PROFILE(SMBlockread);
3366 return;
3369 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3371 SSVAL(req->outbuf,smb_vwv0,nread);
3372 SSVAL(req->outbuf,smb_vwv5,nread+3);
3373 p = smb_buf(req->outbuf);
3374 SCVAL(p,0,0); /* pad byte. */
3375 SSVAL(p,1,nread);
3377 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3378 fsp->fnum, (int)numtoread, (int)nread));
3380 END_PROFILE(SMBlockread);
3381 return;
3384 #undef DBGC_CLASS
3385 #define DBGC_CLASS DBGC_ALL
3387 /****************************************************************************
3388 Reply to a read.
3389 ****************************************************************************/
3391 void reply_read(struct smb_request *req)
3393 connection_struct *conn = req->conn;
3394 size_t numtoread;
3395 ssize_t nread = 0;
3396 char *data;
3397 off_t startpos;
3398 int outsize = 0;
3399 files_struct *fsp;
3400 struct lock_struct lock;
3401 struct smbd_server_connection *sconn = req->sconn;
3403 START_PROFILE(SMBread);
3405 if (req->wct < 3) {
3406 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3407 END_PROFILE(SMBread);
3408 return;
3411 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3413 if (!check_fsp(conn, req, fsp)) {
3414 END_PROFILE(SMBread);
3415 return;
3418 if (!CHECK_READ(fsp,req)) {
3419 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3420 END_PROFILE(SMBread);
3421 return;
3424 numtoread = SVAL(req->vwv+1, 0);
3425 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3427 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3430 * The requested read size cannot be greater than max_recv. JRA.
3432 if (numtoread > sconn->smb1.negprot.max_recv) {
3433 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3434 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3435 (unsigned int)numtoread,
3436 (unsigned int)sconn->smb1.negprot.max_recv));
3437 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3440 reply_outbuf(req, 5, numtoread+3);
3442 data = smb_buf(req->outbuf) + 3;
3444 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3445 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3446 &lock);
3448 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3449 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3450 END_PROFILE(SMBread);
3451 return;
3454 if (numtoread > 0)
3455 nread = read_file(fsp,data,startpos,numtoread);
3457 if (nread < 0) {
3458 reply_nterror(req, map_nt_error_from_unix(errno));
3459 goto strict_unlock;
3462 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3464 SSVAL(req->outbuf,smb_vwv0,nread);
3465 SSVAL(req->outbuf,smb_vwv5,nread+3);
3466 SCVAL(smb_buf(req->outbuf),0,1);
3467 SSVAL(smb_buf(req->outbuf),1,nread);
3469 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3470 fsp->fnum, (int)numtoread, (int)nread ) );
3472 strict_unlock:
3473 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3475 END_PROFILE(SMBread);
3476 return;
3479 /****************************************************************************
3480 Setup readX header.
3481 ****************************************************************************/
3483 static int setup_readX_header(struct smb_request *req, char *outbuf,
3484 size_t smb_maxcnt)
3486 int outsize;
3488 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3490 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3492 SCVAL(outbuf,smb_vwv0,0xFF);
3493 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3494 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3495 SSVAL(outbuf,smb_vwv6,
3496 (smb_wct - 4) /* offset from smb header to wct */
3497 + 1 /* the wct field */
3498 + 12 * sizeof(uint16_t) /* vwv */
3499 + 2); /* the buflen field */
3500 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3501 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3502 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3503 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3504 return outsize;
3507 /****************************************************************************
3508 Reply to a read and X - possibly using sendfile.
3509 ****************************************************************************/
3511 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3512 files_struct *fsp, off_t startpos,
3513 size_t smb_maxcnt)
3515 ssize_t nread = -1;
3516 struct lock_struct lock;
3517 int saved_errno = 0;
3519 if(fsp_stat(fsp) == -1) {
3520 reply_nterror(req, map_nt_error_from_unix(errno));
3521 return;
3524 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3525 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3526 &lock);
3528 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3529 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3530 return;
3533 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3534 (startpos > fsp->fsp_name->st.st_ex_size)
3535 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3537 * We already know that we would do a short read, so don't
3538 * try the sendfile() path.
3540 goto nosendfile_read;
3544 * We can only use sendfile on a non-chained packet
3545 * but we can use on a non-oplocked file. tridge proved this
3546 * on a train in Germany :-). JRA.
3549 if (!req_is_in_chain(req) &&
3550 !is_encrypted_packet(req->sconn, req->inbuf) &&
3551 (fsp->base_fsp == NULL) &&
3552 (fsp->wcp == NULL) &&
3553 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3554 uint8 headerbuf[smb_size + 12 * 2];
3555 DATA_BLOB header;
3558 * Set up the packet header before send. We
3559 * assume here the sendfile will work (get the
3560 * correct amount of data).
3563 header = data_blob_const(headerbuf, sizeof(headerbuf));
3565 construct_reply_common_req(req, (char *)headerbuf);
3566 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3568 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3569 startpos, smb_maxcnt);
3570 if (nread == -1) {
3571 /* Returning ENOSYS means no data at all was sent.
3572 Do this as a normal read. */
3573 if (errno == ENOSYS) {
3574 goto normal_read;
3578 * Special hack for broken Linux with no working sendfile. If we
3579 * return EINTR we sent the header but not the rest of the data.
3580 * Fake this up by doing read/write calls.
3583 if (errno == EINTR) {
3584 /* Ensure we don't do this again. */
3585 set_use_sendfile(SNUM(conn), False);
3586 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3587 nread = fake_sendfile(fsp, startpos,
3588 smb_maxcnt);
3589 if (nread == -1) {
3590 DEBUG(0,("send_file_readX: "
3591 "fake_sendfile failed for "
3592 "file %s (%s).\n",
3593 fsp_str_dbg(fsp),
3594 strerror(errno)));
3595 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3597 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3598 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3599 /* No outbuf here means successful sendfile. */
3600 goto strict_unlock;
3603 DEBUG(0,("send_file_readX: sendfile failed for file "
3604 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3605 strerror(errno)));
3606 exit_server_cleanly("send_file_readX sendfile failed");
3607 } else if (nread == 0) {
3609 * Some sendfile implementations return 0 to indicate
3610 * that there was a short read, but nothing was
3611 * actually written to the socket. In this case,
3612 * fallback to the normal read path so the header gets
3613 * the correct byte count.
3615 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3616 "falling back to the normal read: %s\n",
3617 fsp_str_dbg(fsp)));
3618 goto normal_read;
3621 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3622 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3624 /* Deal with possible short send. */
3625 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3626 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3628 /* No outbuf here means successful sendfile. */
3629 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3630 SMB_PERFCOUNT_END(&req->pcd);
3631 goto strict_unlock;
3634 normal_read:
3636 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3637 uint8 headerbuf[smb_size + 2*12];
3639 construct_reply_common_req(req, (char *)headerbuf);
3640 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3642 /* Send out the header. */
3643 if (write_data(req->sconn->sock, (char *)headerbuf,
3644 sizeof(headerbuf)) != sizeof(headerbuf)) {
3646 char addr[INET6_ADDRSTRLEN];
3648 * Try and give an error message saying what
3649 * client failed.
3651 DEBUG(0, ("write_data failed for client %s. "
3652 "Error %s\n",
3653 get_peer_addr(req->sconn->sock, addr,
3654 sizeof(addr)),
3655 strerror(errno)));
3657 DEBUG(0,("send_file_readX: write_data failed for file "
3658 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3659 strerror(errno)));
3660 exit_server_cleanly("send_file_readX sendfile failed");
3662 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3663 if (nread == -1) {
3664 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3665 "file %s (%s).\n", fsp_str_dbg(fsp),
3666 strerror(errno)));
3667 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3669 goto strict_unlock;
3672 nosendfile_read:
3674 reply_outbuf(req, 12, smb_maxcnt);
3675 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3676 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3678 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3679 saved_errno = errno;
3681 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3683 if (nread < 0) {
3684 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3685 return;
3688 setup_readX_header(req, (char *)req->outbuf, nread);
3690 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3691 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3692 return;
3694 strict_unlock:
3695 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3696 TALLOC_FREE(req->outbuf);
3697 return;
3700 /****************************************************************************
3701 Reply to a read and X.
3702 ****************************************************************************/
3704 void reply_read_and_X(struct smb_request *req)
3706 struct smbd_server_connection *sconn = req->sconn;
3707 connection_struct *conn = req->conn;
3708 files_struct *fsp;
3709 off_t startpos;
3710 size_t smb_maxcnt;
3711 bool big_readX = False;
3712 #if 0
3713 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3714 #endif
3716 START_PROFILE(SMBreadX);
3718 if ((req->wct != 10) && (req->wct != 12)) {
3719 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3720 return;
3723 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3724 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3725 smb_maxcnt = SVAL(req->vwv+5, 0);
3727 /* If it's an IPC, pass off the pipe handler. */
3728 if (IS_IPC(conn)) {
3729 reply_pipe_read_and_X(req);
3730 END_PROFILE(SMBreadX);
3731 return;
3734 if (!check_fsp(conn, req, fsp)) {
3735 END_PROFILE(SMBreadX);
3736 return;
3739 if (!CHECK_READ(fsp,req)) {
3740 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3741 END_PROFILE(SMBreadX);
3742 return;
3745 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3746 (get_remote_arch() == RA_SAMBA)) {
3748 * This is Samba only behavior (up to Samba 3.6)!
3750 * Windows 2008 R2 ignores the upper_size,
3751 * so we do unless unix extentions are active
3752 * or "smbclient" is talking to us.
3754 size_t upper_size = SVAL(req->vwv+7, 0);
3755 smb_maxcnt |= (upper_size<<16);
3756 if (upper_size > 1) {
3757 /* Can't do this on a chained packet. */
3758 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3759 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3760 END_PROFILE(SMBreadX);
3761 return;
3763 /* We currently don't do this on signed or sealed data. */
3764 if (srv_is_signing_active(req->sconn) ||
3765 is_encrypted_packet(req->sconn, req->inbuf)) {
3766 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3767 END_PROFILE(SMBreadX);
3768 return;
3770 /* Is there room in the reply for this data ? */
3771 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3772 reply_nterror(req,
3773 NT_STATUS_INVALID_PARAMETER);
3774 END_PROFILE(SMBreadX);
3775 return;
3777 big_readX = True;
3781 if (req->wct == 12) {
3783 * This is a large offset (64 bit) read.
3785 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3789 if (!big_readX) {
3790 NTSTATUS status = schedule_aio_read_and_X(conn,
3791 req,
3792 fsp,
3793 startpos,
3794 smb_maxcnt);
3795 if (NT_STATUS_IS_OK(status)) {
3796 /* Read scheduled - we're done. */
3797 goto out;
3799 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3800 /* Real error - report to client. */
3801 END_PROFILE(SMBreadX);
3802 reply_nterror(req, status);
3803 return;
3805 /* NT_STATUS_RETRY - fall back to sync read. */
3808 smbd_lock_socket(req->sconn);
3809 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3810 smbd_unlock_socket(req->sconn);
3812 out:
3813 END_PROFILE(SMBreadX);
3814 return;
3817 /****************************************************************************
3818 Error replies to writebraw must have smb_wct == 1. Fix this up.
3819 ****************************************************************************/
3821 void error_to_writebrawerr(struct smb_request *req)
3823 uint8 *old_outbuf = req->outbuf;
3825 reply_outbuf(req, 1, 0);
3827 memcpy(req->outbuf, old_outbuf, smb_size);
3828 TALLOC_FREE(old_outbuf);
3831 /****************************************************************************
3832 Read 4 bytes of a smb packet and return the smb length of the packet.
3833 Store the result in the buffer. This version of the function will
3834 never return a session keepalive (length of zero).
3835 Timeout is in milliseconds.
3836 ****************************************************************************/
3838 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3839 size_t *len)
3841 uint8_t msgtype = NBSSkeepalive;
3843 while (msgtype == NBSSkeepalive) {
3844 NTSTATUS status;
3846 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3847 len);
3848 if (!NT_STATUS_IS_OK(status)) {
3849 char addr[INET6_ADDRSTRLEN];
3850 /* Try and give an error message
3851 * saying what client failed. */
3852 DEBUG(0, ("read_fd_with_timeout failed for "
3853 "client %s read error = %s.\n",
3854 get_peer_addr(fd,addr,sizeof(addr)),
3855 nt_errstr(status)));
3856 return status;
3859 msgtype = CVAL(inbuf, 0);
3862 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3863 (unsigned long)len));
3865 return NT_STATUS_OK;
3868 /****************************************************************************
3869 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3870 ****************************************************************************/
3872 void reply_writebraw(struct smb_request *req)
3874 connection_struct *conn = req->conn;
3875 char *buf = NULL;
3876 ssize_t nwritten=0;
3877 ssize_t total_written=0;
3878 size_t numtowrite=0;
3879 size_t tcount;
3880 off_t startpos;
3881 const char *data=NULL;
3882 bool write_through;
3883 files_struct *fsp;
3884 struct lock_struct lock;
3885 NTSTATUS status;
3887 START_PROFILE(SMBwritebraw);
3890 * If we ever reply with an error, it must have the SMB command
3891 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3892 * we're finished.
3894 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3896 if (srv_is_signing_active(req->sconn)) {
3897 END_PROFILE(SMBwritebraw);
3898 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3899 "raw reads/writes are disallowed.");
3902 if (req->wct < 12) {
3903 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3904 error_to_writebrawerr(req);
3905 END_PROFILE(SMBwritebraw);
3906 return;
3909 if (req->sconn->smb1.echo_handler.trusted_fde) {
3910 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3911 "'async smb echo handler = yes'\n"));
3912 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3913 error_to_writebrawerr(req);
3914 END_PROFILE(SMBwritebraw);
3915 return;
3918 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3919 if (!check_fsp(conn, req, fsp)) {
3920 error_to_writebrawerr(req);
3921 END_PROFILE(SMBwritebraw);
3922 return;
3925 if (!CHECK_WRITE(fsp)) {
3926 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3927 error_to_writebrawerr(req);
3928 END_PROFILE(SMBwritebraw);
3929 return;
3932 tcount = IVAL(req->vwv+1, 0);
3933 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3934 write_through = BITSETW(req->vwv+7,0);
3936 /* We have to deal with slightly different formats depending
3937 on whether we are using the core+ or lanman1.0 protocol */
3939 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3940 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
3941 data = smb_buf_const(req->inbuf);
3942 } else {
3943 numtowrite = SVAL(req->vwv+10, 0);
3944 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3947 /* Ensure we don't write bytes past the end of this packet. */
3948 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3949 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3950 error_to_writebrawerr(req);
3951 END_PROFILE(SMBwritebraw);
3952 return;
3955 if (!fsp->print_file) {
3956 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3957 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3958 &lock);
3960 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3961 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3962 error_to_writebrawerr(req);
3963 END_PROFILE(SMBwritebraw);
3964 return;
3968 if (numtowrite>0) {
3969 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3972 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3973 "wrote=%d sync=%d\n",
3974 fsp->fnum, (double)startpos, (int)numtowrite,
3975 (int)nwritten, (int)write_through));
3977 if (nwritten < (ssize_t)numtowrite) {
3978 reply_nterror(req, NT_STATUS_DISK_FULL);
3979 error_to_writebrawerr(req);
3980 goto strict_unlock;
3983 total_written = nwritten;
3985 /* Allocate a buffer of 64k + length. */
3986 buf = talloc_array(NULL, char, 65540);
3987 if (!buf) {
3988 reply_nterror(req, NT_STATUS_NO_MEMORY);
3989 error_to_writebrawerr(req);
3990 goto strict_unlock;
3993 /* Return a SMBwritebraw message to the redirector to tell
3994 * it to send more bytes */
3996 memcpy(buf, req->inbuf, smb_size);
3997 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
3998 SCVAL(buf,smb_com,SMBwritebraw);
3999 SSVALS(buf,smb_vwv0,0xFFFF);
4000 show_msg(buf);
4001 if (!srv_send_smb(req->sconn,
4002 buf,
4003 false, 0, /* no signing */
4004 IS_CONN_ENCRYPTED(conn),
4005 &req->pcd)) {
4006 exit_server_cleanly("reply_writebraw: srv_send_smb "
4007 "failed.");
4010 /* Now read the raw data into the buffer and write it */
4011 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4012 &numtowrite);
4013 if (!NT_STATUS_IS_OK(status)) {
4014 exit_server_cleanly("secondary writebraw failed");
4017 /* Set up outbuf to return the correct size */
4018 reply_outbuf(req, 1, 0);
4020 if (numtowrite != 0) {
4022 if (numtowrite > 0xFFFF) {
4023 DEBUG(0,("reply_writebraw: Oversize secondary write "
4024 "raw requested (%u). Terminating\n",
4025 (unsigned int)numtowrite ));
4026 exit_server_cleanly("secondary writebraw failed");
4029 if (tcount > nwritten+numtowrite) {
4030 DEBUG(3,("reply_writebraw: Client overestimated the "
4031 "write %d %d %d\n",
4032 (int)tcount,(int)nwritten,(int)numtowrite));
4035 status = read_data(req->sconn->sock, buf+4, numtowrite);
4037 if (!NT_STATUS_IS_OK(status)) {
4038 char addr[INET6_ADDRSTRLEN];
4039 /* Try and give an error message
4040 * saying what client failed. */
4041 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4042 "raw read failed (%s) for client %s. "
4043 "Terminating\n", nt_errstr(status),
4044 get_peer_addr(req->sconn->sock, addr,
4045 sizeof(addr))));
4046 exit_server_cleanly("secondary writebraw failed");
4049 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4050 if (nwritten == -1) {
4051 TALLOC_FREE(buf);
4052 reply_nterror(req, map_nt_error_from_unix(errno));
4053 error_to_writebrawerr(req);
4054 goto strict_unlock;
4057 if (nwritten < (ssize_t)numtowrite) {
4058 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4059 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4062 if (nwritten > 0) {
4063 total_written += nwritten;
4067 TALLOC_FREE(buf);
4068 SSVAL(req->outbuf,smb_vwv0,total_written);
4070 status = sync_file(conn, fsp, write_through);
4071 if (!NT_STATUS_IS_OK(status)) {
4072 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4073 fsp_str_dbg(fsp), nt_errstr(status)));
4074 reply_nterror(req, status);
4075 error_to_writebrawerr(req);
4076 goto strict_unlock;
4079 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4080 "wrote=%d\n",
4081 fsp->fnum, (double)startpos, (int)numtowrite,
4082 (int)total_written));
4084 if (!fsp->print_file) {
4085 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4088 /* We won't return a status if write through is not selected - this
4089 * follows what WfWg does */
4090 END_PROFILE(SMBwritebraw);
4092 if (!write_through && total_written==tcount) {
4094 #if RABBIT_PELLET_FIX
4096 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4097 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4098 * JRA.
4100 if (!send_keepalive(req->sconn->sock)) {
4101 exit_server_cleanly("reply_writebraw: send of "
4102 "keepalive failed");
4104 #endif
4105 TALLOC_FREE(req->outbuf);
4107 return;
4109 strict_unlock:
4110 if (!fsp->print_file) {
4111 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4114 END_PROFILE(SMBwritebraw);
4115 return;
4118 #undef DBGC_CLASS
4119 #define DBGC_CLASS DBGC_LOCKING
4121 /****************************************************************************
4122 Reply to a writeunlock (core+).
4123 ****************************************************************************/
4125 void reply_writeunlock(struct smb_request *req)
4127 connection_struct *conn = req->conn;
4128 ssize_t nwritten = -1;
4129 size_t numtowrite;
4130 off_t startpos;
4131 const char *data;
4132 NTSTATUS status = NT_STATUS_OK;
4133 files_struct *fsp;
4134 struct lock_struct lock;
4135 int saved_errno = 0;
4137 START_PROFILE(SMBwriteunlock);
4139 if (req->wct < 5) {
4140 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4141 END_PROFILE(SMBwriteunlock);
4142 return;
4145 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4147 if (!check_fsp(conn, req, fsp)) {
4148 END_PROFILE(SMBwriteunlock);
4149 return;
4152 if (!CHECK_WRITE(fsp)) {
4153 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4154 END_PROFILE(SMBwriteunlock);
4155 return;
4158 numtowrite = SVAL(req->vwv+1, 0);
4159 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4160 data = (const char *)req->buf + 3;
4162 if (!fsp->print_file && numtowrite > 0) {
4163 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4164 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4165 &lock);
4167 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4168 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4169 END_PROFILE(SMBwriteunlock);
4170 return;
4174 /* The special X/Open SMB protocol handling of
4175 zero length writes is *NOT* done for
4176 this call */
4177 if(numtowrite == 0) {
4178 nwritten = 0;
4179 } else {
4180 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4181 saved_errno = errno;
4184 status = sync_file(conn, fsp, False /* write through */);
4185 if (!NT_STATUS_IS_OK(status)) {
4186 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4187 fsp_str_dbg(fsp), nt_errstr(status)));
4188 reply_nterror(req, status);
4189 goto strict_unlock;
4192 if(nwritten < 0) {
4193 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4194 goto strict_unlock;
4197 if((nwritten < numtowrite) && (numtowrite != 0)) {
4198 reply_nterror(req, NT_STATUS_DISK_FULL);
4199 goto strict_unlock;
4202 if (numtowrite && !fsp->print_file) {
4203 status = do_unlock(req->sconn->msg_ctx,
4204 fsp,
4205 (uint64_t)req->smbpid,
4206 (uint64_t)numtowrite,
4207 (uint64_t)startpos,
4208 WINDOWS_LOCK);
4210 if (NT_STATUS_V(status)) {
4211 reply_nterror(req, status);
4212 goto strict_unlock;
4216 reply_outbuf(req, 1, 0);
4218 SSVAL(req->outbuf,smb_vwv0,nwritten);
4220 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4221 fsp->fnum, (int)numtowrite, (int)nwritten));
4223 strict_unlock:
4224 if (numtowrite && !fsp->print_file) {
4225 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4228 END_PROFILE(SMBwriteunlock);
4229 return;
4232 #undef DBGC_CLASS
4233 #define DBGC_CLASS DBGC_ALL
4235 /****************************************************************************
4236 Reply to a write.
4237 ****************************************************************************/
4239 void reply_write(struct smb_request *req)
4241 connection_struct *conn = req->conn;
4242 size_t numtowrite;
4243 ssize_t nwritten = -1;
4244 off_t startpos;
4245 const char *data;
4246 files_struct *fsp;
4247 struct lock_struct lock;
4248 NTSTATUS status;
4249 int saved_errno = 0;
4251 START_PROFILE(SMBwrite);
4253 if (req->wct < 5) {
4254 END_PROFILE(SMBwrite);
4255 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4256 return;
4259 /* If it's an IPC, pass off the pipe handler. */
4260 if (IS_IPC(conn)) {
4261 reply_pipe_write(req);
4262 END_PROFILE(SMBwrite);
4263 return;
4266 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4268 if (!check_fsp(conn, req, fsp)) {
4269 END_PROFILE(SMBwrite);
4270 return;
4273 if (!CHECK_WRITE(fsp)) {
4274 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4275 END_PROFILE(SMBwrite);
4276 return;
4279 numtowrite = SVAL(req->vwv+1, 0);
4280 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4281 data = (const char *)req->buf + 3;
4283 if (!fsp->print_file) {
4284 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4285 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4286 &lock);
4288 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4289 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4290 END_PROFILE(SMBwrite);
4291 return;
4296 * X/Open SMB protocol says that if smb_vwv1 is
4297 * zero then the file size should be extended or
4298 * truncated to the size given in smb_vwv[2-3].
4301 if(numtowrite == 0) {
4303 * This is actually an allocate call, and set EOF. JRA.
4305 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4306 if (nwritten < 0) {
4307 reply_nterror(req, NT_STATUS_DISK_FULL);
4308 goto strict_unlock;
4310 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4311 if (nwritten < 0) {
4312 reply_nterror(req, NT_STATUS_DISK_FULL);
4313 goto strict_unlock;
4315 trigger_write_time_update_immediate(fsp);
4316 } else {
4317 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4320 status = sync_file(conn, fsp, False);
4321 if (!NT_STATUS_IS_OK(status)) {
4322 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4323 fsp_str_dbg(fsp), nt_errstr(status)));
4324 reply_nterror(req, status);
4325 goto strict_unlock;
4328 if(nwritten < 0) {
4329 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4330 goto strict_unlock;
4333 if((nwritten == 0) && (numtowrite != 0)) {
4334 reply_nterror(req, NT_STATUS_DISK_FULL);
4335 goto strict_unlock;
4338 reply_outbuf(req, 1, 0);
4340 SSVAL(req->outbuf,smb_vwv0,nwritten);
4342 if (nwritten < (ssize_t)numtowrite) {
4343 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4344 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4347 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4349 strict_unlock:
4350 if (!fsp->print_file) {
4351 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4354 END_PROFILE(SMBwrite);
4355 return;
4358 /****************************************************************************
4359 Ensure a buffer is a valid writeX for recvfile purposes.
4360 ****************************************************************************/
4362 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4363 (2*14) + /* word count (including bcc) */ \
4364 1 /* pad byte */)
4366 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4367 const uint8_t *inbuf)
4369 size_t numtowrite;
4370 connection_struct *conn = NULL;
4371 unsigned int doff = 0;
4372 size_t len = smb_len_large(inbuf);
4374 if (is_encrypted_packet(sconn, inbuf)) {
4375 /* Can't do this on encrypted
4376 * connections. */
4377 return false;
4380 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4381 return false;
4384 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4385 CVAL(inbuf,smb_wct) != 14) {
4386 DEBUG(10,("is_valid_writeX_buffer: chained or "
4387 "invalid word length.\n"));
4388 return false;
4391 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4392 if (conn == NULL) {
4393 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4394 return false;
4396 if (IS_IPC(conn)) {
4397 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4398 return false;
4400 if (IS_PRINT(conn)) {
4401 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4402 return false;
4404 doff = SVAL(inbuf,smb_vwv11);
4406 numtowrite = SVAL(inbuf,smb_vwv10);
4408 if (len > doff && len - doff > 0xFFFF) {
4409 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4412 if (numtowrite == 0) {
4413 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4414 return false;
4417 /* Ensure the sizes match up. */
4418 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4419 /* no pad byte...old smbclient :-( */
4420 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4421 (unsigned int)doff,
4422 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4423 return false;
4426 if (len - doff != numtowrite) {
4427 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4428 "len = %u, doff = %u, numtowrite = %u\n",
4429 (unsigned int)len,
4430 (unsigned int)doff,
4431 (unsigned int)numtowrite ));
4432 return false;
4435 DEBUG(10,("is_valid_writeX_buffer: true "
4436 "len = %u, doff = %u, numtowrite = %u\n",
4437 (unsigned int)len,
4438 (unsigned int)doff,
4439 (unsigned int)numtowrite ));
4441 return true;
4444 /****************************************************************************
4445 Reply to a write and X.
4446 ****************************************************************************/
4448 void reply_write_and_X(struct smb_request *req)
4450 connection_struct *conn = req->conn;
4451 files_struct *fsp;
4452 struct lock_struct lock;
4453 off_t startpos;
4454 size_t numtowrite;
4455 bool write_through;
4456 ssize_t nwritten;
4457 unsigned int smb_doff;
4458 unsigned int smblen;
4459 const char *data;
4460 NTSTATUS status;
4461 int saved_errno = 0;
4463 START_PROFILE(SMBwriteX);
4465 if ((req->wct != 12) && (req->wct != 14)) {
4466 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4467 goto out;
4470 numtowrite = SVAL(req->vwv+10, 0);
4471 smb_doff = SVAL(req->vwv+11, 0);
4472 smblen = smb_len(req->inbuf);
4474 if (req->unread_bytes > 0xFFFF ||
4475 (smblen > smb_doff &&
4476 smblen - smb_doff > 0xFFFF)) {
4477 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4480 if (req->unread_bytes) {
4481 /* Can't do a recvfile write on IPC$ */
4482 if (IS_IPC(conn)) {
4483 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4484 goto out;
4486 if (numtowrite != req->unread_bytes) {
4487 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4488 goto out;
4490 } else {
4491 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4492 smb_doff + numtowrite > smblen) {
4493 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4494 goto out;
4498 /* If it's an IPC, pass off the pipe handler. */
4499 if (IS_IPC(conn)) {
4500 if (req->unread_bytes) {
4501 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4502 goto out;
4504 reply_pipe_write_and_X(req);
4505 goto out;
4508 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4509 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4510 write_through = BITSETW(req->vwv+7,0);
4512 if (!check_fsp(conn, req, fsp)) {
4513 goto out;
4516 if (!CHECK_WRITE(fsp)) {
4517 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4518 goto out;
4521 data = smb_base(req->inbuf) + smb_doff;
4523 if(req->wct == 14) {
4525 * This is a large offset (64 bit) write.
4527 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4531 /* X/Open SMB protocol says that, unlike SMBwrite
4532 if the length is zero then NO truncation is
4533 done, just a write of zero. To truncate a file,
4534 use SMBwrite. */
4536 if(numtowrite == 0) {
4537 nwritten = 0;
4538 } else {
4539 if (req->unread_bytes == 0) {
4540 status = schedule_aio_write_and_X(conn,
4541 req,
4542 fsp,
4543 data,
4544 startpos,
4545 numtowrite);
4547 if (NT_STATUS_IS_OK(status)) {
4548 /* write scheduled - we're done. */
4549 goto out;
4551 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4552 /* Real error - report to client. */
4553 reply_nterror(req, status);
4554 goto out;
4556 /* NT_STATUS_RETRY - fall through to sync write. */
4559 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4560 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4561 &lock);
4563 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4564 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4565 goto out;
4568 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4569 saved_errno = errno;
4571 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4574 if(nwritten < 0) {
4575 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4576 goto out;
4579 if((nwritten == 0) && (numtowrite != 0)) {
4580 reply_nterror(req, NT_STATUS_DISK_FULL);
4581 goto out;
4584 reply_outbuf(req, 6, 0);
4585 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4586 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4587 SSVAL(req->outbuf,smb_vwv2,nwritten);
4588 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4590 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4591 fsp->fnum, (int)numtowrite, (int)nwritten));
4593 status = sync_file(conn, fsp, write_through);
4594 if (!NT_STATUS_IS_OK(status)) {
4595 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4596 fsp_str_dbg(fsp), nt_errstr(status)));
4597 reply_nterror(req, status);
4598 goto out;
4601 END_PROFILE(SMBwriteX);
4602 return;
4604 out:
4605 if (req->unread_bytes) {
4606 /* writeX failed. drain socket. */
4607 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4608 req->unread_bytes) {
4609 smb_panic("failed to drain pending bytes");
4611 req->unread_bytes = 0;
4614 END_PROFILE(SMBwriteX);
4615 return;
4618 /****************************************************************************
4619 Reply to a lseek.
4620 ****************************************************************************/
4622 void reply_lseek(struct smb_request *req)
4624 connection_struct *conn = req->conn;
4625 off_t startpos;
4626 off_t res= -1;
4627 int mode,umode;
4628 files_struct *fsp;
4630 START_PROFILE(SMBlseek);
4632 if (req->wct < 4) {
4633 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4634 END_PROFILE(SMBlseek);
4635 return;
4638 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4640 if (!check_fsp(conn, req, fsp)) {
4641 return;
4644 flush_write_cache(fsp, SEEK_FLUSH);
4646 mode = SVAL(req->vwv+1, 0) & 3;
4647 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4648 startpos = (off_t)IVALS(req->vwv+2, 0);
4650 switch (mode) {
4651 case 0:
4652 umode = SEEK_SET;
4653 res = startpos;
4654 break;
4655 case 1:
4656 umode = SEEK_CUR;
4657 res = fsp->fh->pos + startpos;
4658 break;
4659 case 2:
4660 umode = SEEK_END;
4661 break;
4662 default:
4663 umode = SEEK_SET;
4664 res = startpos;
4665 break;
4668 if (umode == SEEK_END) {
4669 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4670 if(errno == EINVAL) {
4671 off_t current_pos = startpos;
4673 if(fsp_stat(fsp) == -1) {
4674 reply_nterror(req,
4675 map_nt_error_from_unix(errno));
4676 END_PROFILE(SMBlseek);
4677 return;
4680 current_pos += fsp->fsp_name->st.st_ex_size;
4681 if(current_pos < 0)
4682 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4686 if(res == -1) {
4687 reply_nterror(req, map_nt_error_from_unix(errno));
4688 END_PROFILE(SMBlseek);
4689 return;
4693 fsp->fh->pos = res;
4695 reply_outbuf(req, 2, 0);
4696 SIVAL(req->outbuf,smb_vwv0,res);
4698 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4699 fsp->fnum, (double)startpos, (double)res, mode));
4701 END_PROFILE(SMBlseek);
4702 return;
4705 /****************************************************************************
4706 Reply to a flush.
4707 ****************************************************************************/
4709 void reply_flush(struct smb_request *req)
4711 connection_struct *conn = req->conn;
4712 uint16 fnum;
4713 files_struct *fsp;
4715 START_PROFILE(SMBflush);
4717 if (req->wct < 1) {
4718 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4719 return;
4722 fnum = SVAL(req->vwv+0, 0);
4723 fsp = file_fsp(req, fnum);
4725 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4726 return;
4729 if (!fsp) {
4730 file_sync_all(conn);
4731 } else {
4732 NTSTATUS status = sync_file(conn, fsp, True);
4733 if (!NT_STATUS_IS_OK(status)) {
4734 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4735 fsp_str_dbg(fsp), nt_errstr(status)));
4736 reply_nterror(req, status);
4737 END_PROFILE(SMBflush);
4738 return;
4742 reply_outbuf(req, 0, 0);
4744 DEBUG(3,("flush\n"));
4745 END_PROFILE(SMBflush);
4746 return;
4749 /****************************************************************************
4750 Reply to a exit.
4751 conn POINTER CAN BE NULL HERE !
4752 ****************************************************************************/
4754 void reply_exit(struct smb_request *req)
4756 START_PROFILE(SMBexit);
4758 file_close_pid(req->sconn, req->smbpid, req->vuid);
4760 reply_outbuf(req, 0, 0);
4762 DEBUG(3,("exit\n"));
4764 END_PROFILE(SMBexit);
4765 return;
4768 /****************************************************************************
4769 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4770 ****************************************************************************/
4772 void reply_close(struct smb_request *req)
4774 connection_struct *conn = req->conn;
4775 NTSTATUS status = NT_STATUS_OK;
4776 files_struct *fsp = NULL;
4777 START_PROFILE(SMBclose);
4779 if (req->wct < 3) {
4780 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4781 END_PROFILE(SMBclose);
4782 return;
4785 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4788 * We can only use check_fsp if we know it's not a directory.
4791 if (!check_fsp_open(conn, req, fsp)) {
4792 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4793 END_PROFILE(SMBclose);
4794 return;
4797 if(fsp->is_directory) {
4799 * Special case - close NT SMB directory handle.
4801 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4802 status = close_file(req, fsp, NORMAL_CLOSE);
4803 } else {
4804 time_t t;
4806 * Close ordinary file.
4809 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4810 fsp->fh->fd, fsp->fnum,
4811 conn->num_files_open));
4814 * Take care of any time sent in the close.
4817 t = srv_make_unix_date3(req->vwv+1);
4818 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4821 * close_file() returns the unix errno if an error
4822 * was detected on close - normally this is due to
4823 * a disk full error. If not then it was probably an I/O error.
4826 status = close_file(req, fsp, NORMAL_CLOSE);
4829 if (!NT_STATUS_IS_OK(status)) {
4830 reply_nterror(req, status);
4831 END_PROFILE(SMBclose);
4832 return;
4835 reply_outbuf(req, 0, 0);
4836 END_PROFILE(SMBclose);
4837 return;
4840 /****************************************************************************
4841 Reply to a writeclose (Core+ protocol).
4842 ****************************************************************************/
4844 void reply_writeclose(struct smb_request *req)
4846 connection_struct *conn = req->conn;
4847 size_t numtowrite;
4848 ssize_t nwritten = -1;
4849 NTSTATUS close_status = NT_STATUS_OK;
4850 off_t startpos;
4851 const char *data;
4852 struct timespec mtime;
4853 files_struct *fsp;
4854 struct lock_struct lock;
4856 START_PROFILE(SMBwriteclose);
4858 if (req->wct < 6) {
4859 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4860 END_PROFILE(SMBwriteclose);
4861 return;
4864 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4866 if (!check_fsp(conn, req, fsp)) {
4867 END_PROFILE(SMBwriteclose);
4868 return;
4870 if (!CHECK_WRITE(fsp)) {
4871 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4872 END_PROFILE(SMBwriteclose);
4873 return;
4876 numtowrite = SVAL(req->vwv+1, 0);
4877 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4878 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4879 data = (const char *)req->buf + 1;
4881 if (!fsp->print_file) {
4882 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4883 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4884 &lock);
4886 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4887 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4888 END_PROFILE(SMBwriteclose);
4889 return;
4893 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4895 set_close_write_time(fsp, mtime);
4898 * More insanity. W2K only closes the file if writelen > 0.
4899 * JRA.
4902 if (numtowrite) {
4903 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4904 "file %s\n", fsp_str_dbg(fsp)));
4905 close_status = close_file(req, fsp, NORMAL_CLOSE);
4908 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4909 fsp->fnum, (int)numtowrite, (int)nwritten,
4910 conn->num_files_open));
4912 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4913 reply_nterror(req, NT_STATUS_DISK_FULL);
4914 goto strict_unlock;
4917 if(!NT_STATUS_IS_OK(close_status)) {
4918 reply_nterror(req, close_status);
4919 goto strict_unlock;
4922 reply_outbuf(req, 1, 0);
4924 SSVAL(req->outbuf,smb_vwv0,nwritten);
4926 strict_unlock:
4927 if (numtowrite && !fsp->print_file) {
4928 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4931 END_PROFILE(SMBwriteclose);
4932 return;
4935 #undef DBGC_CLASS
4936 #define DBGC_CLASS DBGC_LOCKING
4938 /****************************************************************************
4939 Reply to a lock.
4940 ****************************************************************************/
4942 void reply_lock(struct smb_request *req)
4944 connection_struct *conn = req->conn;
4945 uint64_t count,offset;
4946 NTSTATUS status;
4947 files_struct *fsp;
4948 struct byte_range_lock *br_lck = NULL;
4950 START_PROFILE(SMBlock);
4952 if (req->wct < 5) {
4953 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4954 END_PROFILE(SMBlock);
4955 return;
4958 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4960 if (!check_fsp(conn, req, fsp)) {
4961 END_PROFILE(SMBlock);
4962 return;
4965 count = (uint64_t)IVAL(req->vwv+1, 0);
4966 offset = (uint64_t)IVAL(req->vwv+3, 0);
4968 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4969 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4971 br_lck = do_lock(req->sconn->msg_ctx,
4972 fsp,
4973 (uint64_t)req->smbpid,
4974 count,
4975 offset,
4976 WRITE_LOCK,
4977 WINDOWS_LOCK,
4978 False, /* Non-blocking lock. */
4979 &status,
4980 NULL,
4981 NULL);
4983 TALLOC_FREE(br_lck);
4985 if (NT_STATUS_V(status)) {
4986 reply_nterror(req, status);
4987 END_PROFILE(SMBlock);
4988 return;
4991 reply_outbuf(req, 0, 0);
4993 END_PROFILE(SMBlock);
4994 return;
4997 /****************************************************************************
4998 Reply to a unlock.
4999 ****************************************************************************/
5001 void reply_unlock(struct smb_request *req)
5003 connection_struct *conn = req->conn;
5004 uint64_t count,offset;
5005 NTSTATUS status;
5006 files_struct *fsp;
5008 START_PROFILE(SMBunlock);
5010 if (req->wct < 5) {
5011 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5012 END_PROFILE(SMBunlock);
5013 return;
5016 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5018 if (!check_fsp(conn, req, fsp)) {
5019 END_PROFILE(SMBunlock);
5020 return;
5023 count = (uint64_t)IVAL(req->vwv+1, 0);
5024 offset = (uint64_t)IVAL(req->vwv+3, 0);
5026 status = do_unlock(req->sconn->msg_ctx,
5027 fsp,
5028 (uint64_t)req->smbpid,
5029 count,
5030 offset,
5031 WINDOWS_LOCK);
5033 if (NT_STATUS_V(status)) {
5034 reply_nterror(req, status);
5035 END_PROFILE(SMBunlock);
5036 return;
5039 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5040 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5042 reply_outbuf(req, 0, 0);
5044 END_PROFILE(SMBunlock);
5045 return;
5048 #undef DBGC_CLASS
5049 #define DBGC_CLASS DBGC_ALL
5051 /****************************************************************************
5052 Reply to a tdis.
5053 conn POINTER CAN BE NULL HERE !
5054 ****************************************************************************/
5056 void reply_tdis(struct smb_request *req)
5058 connection_struct *conn = req->conn;
5059 START_PROFILE(SMBtdis);
5061 if (!conn) {
5062 DEBUG(4,("Invalid connection in tdis\n"));
5063 reply_force_doserror(req, ERRSRV, ERRinvnid);
5064 END_PROFILE(SMBtdis);
5065 return;
5068 close_cnum(conn,req->vuid);
5069 req->conn = NULL;
5071 reply_outbuf(req, 0, 0);
5072 END_PROFILE(SMBtdis);
5073 return;
5076 /****************************************************************************
5077 Reply to a echo.
5078 conn POINTER CAN BE NULL HERE !
5079 ****************************************************************************/
5081 void reply_echo(struct smb_request *req)
5083 connection_struct *conn = req->conn;
5084 struct smb_perfcount_data local_pcd;
5085 struct smb_perfcount_data *cur_pcd;
5086 int smb_reverb;
5087 int seq_num;
5089 START_PROFILE(SMBecho);
5091 smb_init_perfcount_data(&local_pcd);
5093 if (req->wct < 1) {
5094 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5095 END_PROFILE(SMBecho);
5096 return;
5099 smb_reverb = SVAL(req->vwv+0, 0);
5101 reply_outbuf(req, 1, req->buflen);
5103 /* copy any incoming data back out */
5104 if (req->buflen > 0) {
5105 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5108 if (smb_reverb > 100) {
5109 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5110 smb_reverb = 100;
5113 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5115 /* this makes sure we catch the request pcd */
5116 if (seq_num == smb_reverb) {
5117 cur_pcd = &req->pcd;
5118 } else {
5119 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5120 cur_pcd = &local_pcd;
5123 SSVAL(req->outbuf,smb_vwv0,seq_num);
5125 show_msg((char *)req->outbuf);
5126 if (!srv_send_smb(req->sconn,
5127 (char *)req->outbuf,
5128 true, req->seqnum+1,
5129 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5130 cur_pcd))
5131 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5134 DEBUG(3,("echo %d times\n", smb_reverb));
5136 TALLOC_FREE(req->outbuf);
5138 END_PROFILE(SMBecho);
5139 return;
5142 /****************************************************************************
5143 Reply to a printopen.
5144 ****************************************************************************/
5146 void reply_printopen(struct smb_request *req)
5148 connection_struct *conn = req->conn;
5149 files_struct *fsp;
5150 NTSTATUS status;
5152 START_PROFILE(SMBsplopen);
5154 if (req->wct < 2) {
5155 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5156 END_PROFILE(SMBsplopen);
5157 return;
5160 if (!CAN_PRINT(conn)) {
5161 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5162 END_PROFILE(SMBsplopen);
5163 return;
5166 status = file_new(req, conn, &fsp);
5167 if(!NT_STATUS_IS_OK(status)) {
5168 reply_nterror(req, status);
5169 END_PROFILE(SMBsplopen);
5170 return;
5173 /* Open for exclusive use, write only. */
5174 status = print_spool_open(fsp, NULL, req->vuid);
5176 if (!NT_STATUS_IS_OK(status)) {
5177 file_free(req, fsp);
5178 reply_nterror(req, status);
5179 END_PROFILE(SMBsplopen);
5180 return;
5183 reply_outbuf(req, 1, 0);
5184 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5186 DEBUG(3,("openprint fd=%d fnum=%d\n",
5187 fsp->fh->fd, fsp->fnum));
5189 END_PROFILE(SMBsplopen);
5190 return;
5193 /****************************************************************************
5194 Reply to a printclose.
5195 ****************************************************************************/
5197 void reply_printclose(struct smb_request *req)
5199 connection_struct *conn = req->conn;
5200 files_struct *fsp;
5201 NTSTATUS status;
5203 START_PROFILE(SMBsplclose);
5205 if (req->wct < 1) {
5206 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5207 END_PROFILE(SMBsplclose);
5208 return;
5211 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5213 if (!check_fsp(conn, req, fsp)) {
5214 END_PROFILE(SMBsplclose);
5215 return;
5218 if (!CAN_PRINT(conn)) {
5219 reply_force_doserror(req, ERRSRV, ERRerror);
5220 END_PROFILE(SMBsplclose);
5221 return;
5224 DEBUG(3,("printclose fd=%d fnum=%d\n",
5225 fsp->fh->fd,fsp->fnum));
5227 status = close_file(req, fsp, NORMAL_CLOSE);
5229 if(!NT_STATUS_IS_OK(status)) {
5230 reply_nterror(req, status);
5231 END_PROFILE(SMBsplclose);
5232 return;
5235 reply_outbuf(req, 0, 0);
5237 END_PROFILE(SMBsplclose);
5238 return;
5241 /****************************************************************************
5242 Reply to a printqueue.
5243 ****************************************************************************/
5245 void reply_printqueue(struct smb_request *req)
5247 connection_struct *conn = req->conn;
5248 int max_count;
5249 int start_index;
5251 START_PROFILE(SMBsplretq);
5253 if (req->wct < 2) {
5254 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5255 END_PROFILE(SMBsplretq);
5256 return;
5259 max_count = SVAL(req->vwv+0, 0);
5260 start_index = SVAL(req->vwv+1, 0);
5262 /* we used to allow the client to get the cnum wrong, but that
5263 is really quite gross and only worked when there was only
5264 one printer - I think we should now only accept it if they
5265 get it right (tridge) */
5266 if (!CAN_PRINT(conn)) {
5267 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5268 END_PROFILE(SMBsplretq);
5269 return;
5272 reply_outbuf(req, 2, 3);
5273 SSVAL(req->outbuf,smb_vwv0,0);
5274 SSVAL(req->outbuf,smb_vwv1,0);
5275 SCVAL(smb_buf(req->outbuf),0,1);
5276 SSVAL(smb_buf(req->outbuf),1,0);
5278 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5279 start_index, max_count));
5282 TALLOC_CTX *mem_ctx = talloc_tos();
5283 NTSTATUS status;
5284 WERROR werr;
5285 const char *sharename = lp_servicename(SNUM(conn));
5286 struct rpc_pipe_client *cli = NULL;
5287 struct dcerpc_binding_handle *b = NULL;
5288 struct policy_handle handle;
5289 struct spoolss_DevmodeContainer devmode_ctr;
5290 union spoolss_JobInfo *info;
5291 uint32_t count;
5292 uint32_t num_to_get;
5293 uint32_t first;
5294 uint32_t i;
5296 ZERO_STRUCT(handle);
5298 status = rpc_pipe_open_interface(conn,
5299 &ndr_table_spoolss.syntax_id,
5300 conn->session_info,
5301 conn->sconn->remote_address,
5302 conn->sconn->msg_ctx,
5303 &cli);
5304 if (!NT_STATUS_IS_OK(status)) {
5305 DEBUG(0, ("reply_printqueue: "
5306 "could not connect to spoolss: %s\n",
5307 nt_errstr(status)));
5308 reply_nterror(req, status);
5309 goto out;
5311 b = cli->binding_handle;
5313 ZERO_STRUCT(devmode_ctr);
5315 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5316 sharename,
5317 NULL, devmode_ctr,
5318 SEC_FLAG_MAXIMUM_ALLOWED,
5319 &handle,
5320 &werr);
5321 if (!NT_STATUS_IS_OK(status)) {
5322 reply_nterror(req, status);
5323 goto out;
5325 if (!W_ERROR_IS_OK(werr)) {
5326 reply_nterror(req, werror_to_ntstatus(werr));
5327 goto out;
5330 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5331 &handle,
5332 0, /* firstjob */
5333 0xff, /* numjobs */
5334 2, /* level */
5335 0, /* offered */
5336 &count,
5337 &info);
5338 if (!W_ERROR_IS_OK(werr)) {
5339 reply_nterror(req, werror_to_ntstatus(werr));
5340 goto out;
5343 if (max_count > 0) {
5344 first = start_index;
5345 } else {
5346 first = start_index + max_count + 1;
5349 if (first >= count) {
5350 num_to_get = first;
5351 } else {
5352 num_to_get = first + MIN(ABS(max_count), count - first);
5355 for (i = first; i < num_to_get; i++) {
5356 char blob[28];
5357 char *p = blob;
5358 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5359 int qstatus;
5360 uint16_t qrapjobid = pjobid_to_rap(sharename,
5361 info[i].info2.job_id);
5363 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5364 qstatus = 2;
5365 } else {
5366 qstatus = 3;
5369 srv_put_dos_date2(p, 0, qtime);
5370 SCVAL(p, 4, qstatus);
5371 SSVAL(p, 5, qrapjobid);
5372 SIVAL(p, 7, info[i].info2.size);
5373 SCVAL(p, 11, 0);
5374 srvstr_push(blob, req->flags2, p+12,
5375 info[i].info2.notify_name, 16, STR_ASCII);
5377 if (message_push_blob(
5378 &req->outbuf,
5379 data_blob_const(
5380 blob, sizeof(blob))) == -1) {
5381 reply_nterror(req, NT_STATUS_NO_MEMORY);
5382 goto out;
5386 if (count > 0) {
5387 SSVAL(req->outbuf,smb_vwv0,count);
5388 SSVAL(req->outbuf,smb_vwv1,
5389 (max_count>0?first+count:first-1));
5390 SCVAL(smb_buf(req->outbuf),0,1);
5391 SSVAL(smb_buf(req->outbuf),1,28*count);
5395 DEBUG(3, ("%u entries returned in queue\n",
5396 (unsigned)count));
5398 out:
5399 if (b && is_valid_policy_hnd(&handle)) {
5400 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5405 END_PROFILE(SMBsplretq);
5406 return;
5409 /****************************************************************************
5410 Reply to a printwrite.
5411 ****************************************************************************/
5413 void reply_printwrite(struct smb_request *req)
5415 connection_struct *conn = req->conn;
5416 int numtowrite;
5417 const char *data;
5418 files_struct *fsp;
5420 START_PROFILE(SMBsplwr);
5422 if (req->wct < 1) {
5423 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5424 END_PROFILE(SMBsplwr);
5425 return;
5428 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5430 if (!check_fsp(conn, req, fsp)) {
5431 END_PROFILE(SMBsplwr);
5432 return;
5435 if (!fsp->print_file) {
5436 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5437 END_PROFILE(SMBsplwr);
5438 return;
5441 if (!CHECK_WRITE(fsp)) {
5442 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5443 END_PROFILE(SMBsplwr);
5444 return;
5447 numtowrite = SVAL(req->buf, 1);
5449 if (req->buflen < numtowrite + 3) {
5450 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5451 END_PROFILE(SMBsplwr);
5452 return;
5455 data = (const char *)req->buf + 3;
5457 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5458 reply_nterror(req, map_nt_error_from_unix(errno));
5459 END_PROFILE(SMBsplwr);
5460 return;
5463 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5465 END_PROFILE(SMBsplwr);
5466 return;
5469 /****************************************************************************
5470 Reply to a mkdir.
5471 ****************************************************************************/
5473 void reply_mkdir(struct smb_request *req)
5475 connection_struct *conn = req->conn;
5476 struct smb_filename *smb_dname = NULL;
5477 char *directory = NULL;
5478 NTSTATUS status;
5479 TALLOC_CTX *ctx = talloc_tos();
5481 START_PROFILE(SMBmkdir);
5483 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5484 STR_TERMINATE, &status);
5485 if (!NT_STATUS_IS_OK(status)) {
5486 reply_nterror(req, status);
5487 goto out;
5490 status = filename_convert(ctx, conn,
5491 req->flags2 & FLAGS2_DFS_PATHNAMES,
5492 directory,
5494 NULL,
5495 &smb_dname);
5496 if (!NT_STATUS_IS_OK(status)) {
5497 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5498 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5499 ERRSRV, ERRbadpath);
5500 goto out;
5502 reply_nterror(req, status);
5503 goto out;
5506 status = create_directory(conn, req, smb_dname);
5508 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5510 if (!NT_STATUS_IS_OK(status)) {
5512 if (!use_nt_status()
5513 && NT_STATUS_EQUAL(status,
5514 NT_STATUS_OBJECT_NAME_COLLISION)) {
5516 * Yes, in the DOS error code case we get a
5517 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5518 * samba4 torture test.
5520 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5523 reply_nterror(req, status);
5524 goto out;
5527 reply_outbuf(req, 0, 0);
5529 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5530 out:
5531 TALLOC_FREE(smb_dname);
5532 END_PROFILE(SMBmkdir);
5533 return;
5536 /****************************************************************************
5537 Reply to a rmdir.
5538 ****************************************************************************/
5540 void reply_rmdir(struct smb_request *req)
5542 connection_struct *conn = req->conn;
5543 struct smb_filename *smb_dname = NULL;
5544 char *directory = NULL;
5545 NTSTATUS status;
5546 TALLOC_CTX *ctx = talloc_tos();
5547 files_struct *fsp = NULL;
5548 int info = 0;
5549 struct smbd_server_connection *sconn = req->sconn;
5551 START_PROFILE(SMBrmdir);
5553 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5554 STR_TERMINATE, &status);
5555 if (!NT_STATUS_IS_OK(status)) {
5556 reply_nterror(req, status);
5557 goto out;
5560 status = filename_convert(ctx, conn,
5561 req->flags2 & FLAGS2_DFS_PATHNAMES,
5562 directory,
5564 NULL,
5565 &smb_dname);
5566 if (!NT_STATUS_IS_OK(status)) {
5567 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5568 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5569 ERRSRV, ERRbadpath);
5570 goto out;
5572 reply_nterror(req, status);
5573 goto out;
5576 if (is_ntfs_stream_smb_fname(smb_dname)) {
5577 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5578 goto out;
5581 status = SMB_VFS_CREATE_FILE(
5582 conn, /* conn */
5583 req, /* req */
5584 0, /* root_dir_fid */
5585 smb_dname, /* fname */
5586 DELETE_ACCESS, /* access_mask */
5587 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5588 FILE_SHARE_DELETE),
5589 FILE_OPEN, /* create_disposition*/
5590 FILE_DIRECTORY_FILE, /* create_options */
5591 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5592 0, /* oplock_request */
5593 0, /* allocation_size */
5594 0, /* private_flags */
5595 NULL, /* sd */
5596 NULL, /* ea_list */
5597 &fsp, /* result */
5598 &info); /* pinfo */
5600 if (!NT_STATUS_IS_OK(status)) {
5601 if (open_was_deferred(req->sconn, req->mid)) {
5602 /* We have re-scheduled this call. */
5603 goto out;
5605 reply_nterror(req, status);
5606 goto out;
5609 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5610 if (!NT_STATUS_IS_OK(status)) {
5611 close_file(req, fsp, ERROR_CLOSE);
5612 reply_nterror(req, status);
5613 goto out;
5616 if (!set_delete_on_close(fsp, true,
5617 conn->session_info->security_token,
5618 conn->session_info->unix_token)) {
5619 close_file(req, fsp, ERROR_CLOSE);
5620 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5621 goto out;
5624 status = close_file(req, fsp, NORMAL_CLOSE);
5625 if (!NT_STATUS_IS_OK(status)) {
5626 reply_nterror(req, status);
5627 } else {
5628 reply_outbuf(req, 0, 0);
5631 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5633 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5634 out:
5635 TALLOC_FREE(smb_dname);
5636 END_PROFILE(SMBrmdir);
5637 return;
5640 /*******************************************************************
5641 Resolve wildcards in a filename rename.
5642 ********************************************************************/
5644 static bool resolve_wildcards(TALLOC_CTX *ctx,
5645 const char *name1,
5646 const char *name2,
5647 char **pp_newname)
5649 char *name2_copy = NULL;
5650 char *root1 = NULL;
5651 char *root2 = NULL;
5652 char *ext1 = NULL;
5653 char *ext2 = NULL;
5654 char *p,*p2, *pname1, *pname2;
5656 name2_copy = talloc_strdup(ctx, name2);
5657 if (!name2_copy) {
5658 return False;
5661 pname1 = strrchr_m(name1,'/');
5662 pname2 = strrchr_m(name2_copy,'/');
5664 if (!pname1 || !pname2) {
5665 return False;
5668 /* Truncate the copy of name2 at the last '/' */
5669 *pname2 = '\0';
5671 /* Now go past the '/' */
5672 pname1++;
5673 pname2++;
5675 root1 = talloc_strdup(ctx, pname1);
5676 root2 = talloc_strdup(ctx, pname2);
5678 if (!root1 || !root2) {
5679 return False;
5682 p = strrchr_m(root1,'.');
5683 if (p) {
5684 *p = 0;
5685 ext1 = talloc_strdup(ctx, p+1);
5686 } else {
5687 ext1 = talloc_strdup(ctx, "");
5689 p = strrchr_m(root2,'.');
5690 if (p) {
5691 *p = 0;
5692 ext2 = talloc_strdup(ctx, p+1);
5693 } else {
5694 ext2 = talloc_strdup(ctx, "");
5697 if (!ext1 || !ext2) {
5698 return False;
5701 p = root1;
5702 p2 = root2;
5703 while (*p2) {
5704 if (*p2 == '?') {
5705 /* Hmmm. Should this be mb-aware ? */
5706 *p2 = *p;
5707 p2++;
5708 } else if (*p2 == '*') {
5709 *p2 = '\0';
5710 root2 = talloc_asprintf(ctx, "%s%s",
5711 root2,
5713 if (!root2) {
5714 return False;
5716 break;
5717 } else {
5718 p2++;
5720 if (*p) {
5721 p++;
5725 p = ext1;
5726 p2 = ext2;
5727 while (*p2) {
5728 if (*p2 == '?') {
5729 /* Hmmm. Should this be mb-aware ? */
5730 *p2 = *p;
5731 p2++;
5732 } else if (*p2 == '*') {
5733 *p2 = '\0';
5734 ext2 = talloc_asprintf(ctx, "%s%s",
5735 ext2,
5737 if (!ext2) {
5738 return False;
5740 break;
5741 } else {
5742 p2++;
5744 if (*p) {
5745 p++;
5749 if (*ext2) {
5750 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5751 name2_copy,
5752 root2,
5753 ext2);
5754 } else {
5755 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5756 name2_copy,
5757 root2);
5760 if (!*pp_newname) {
5761 return False;
5764 return True;
5767 /****************************************************************************
5768 Ensure open files have their names updated. Updated to notify other smbd's
5769 asynchronously.
5770 ****************************************************************************/
5772 static void rename_open_files(connection_struct *conn,
5773 struct share_mode_lock *lck,
5774 uint32_t orig_name_hash,
5775 const struct smb_filename *smb_fname_dst)
5777 files_struct *fsp;
5778 bool did_rename = False;
5779 NTSTATUS status;
5780 uint32_t new_name_hash = 0;
5782 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
5783 fsp = file_find_di_next(fsp)) {
5784 /* fsp_name is a relative path under the fsp. To change this for other
5785 sharepaths we need to manipulate relative paths. */
5786 /* TODO - create the absolute path and manipulate the newname
5787 relative to the sharepath. */
5788 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5789 continue;
5791 if (fsp->name_hash != orig_name_hash) {
5792 continue;
5794 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5795 "(file_id %s) from %s -> %s\n", fsp->fnum,
5796 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5797 smb_fname_str_dbg(smb_fname_dst)));
5799 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5800 if (NT_STATUS_IS_OK(status)) {
5801 did_rename = True;
5802 new_name_hash = fsp->name_hash;
5806 if (!did_rename) {
5807 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5808 "for %s\n", file_id_string_tos(&lck->data->id),
5809 smb_fname_str_dbg(smb_fname_dst)));
5812 /* Send messages to all smbd's (not ourself) that the name has changed. */
5813 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5814 orig_name_hash, new_name_hash,
5815 smb_fname_dst);
5819 /****************************************************************************
5820 We need to check if the source path is a parent directory of the destination
5821 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5822 refuse the rename with a sharing violation. Under UNIX the above call can
5823 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5824 probably need to check that the client is a Windows one before disallowing
5825 this as a UNIX client (one with UNIX extensions) can know the source is a
5826 symlink and make this decision intelligently. Found by an excellent bug
5827 report from <AndyLiebman@aol.com>.
5828 ****************************************************************************/
5830 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5831 const struct smb_filename *smb_fname_dst)
5833 const char *psrc = smb_fname_src->base_name;
5834 const char *pdst = smb_fname_dst->base_name;
5835 size_t slen;
5837 if (psrc[0] == '.' && psrc[1] == '/') {
5838 psrc += 2;
5840 if (pdst[0] == '.' && pdst[1] == '/') {
5841 pdst += 2;
5843 if ((slen = strlen(psrc)) > strlen(pdst)) {
5844 return False;
5846 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5850 * Do the notify calls from a rename
5853 static void notify_rename(connection_struct *conn, bool is_dir,
5854 const struct smb_filename *smb_fname_src,
5855 const struct smb_filename *smb_fname_dst)
5857 char *parent_dir_src = NULL;
5858 char *parent_dir_dst = NULL;
5859 uint32 mask;
5861 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5862 : FILE_NOTIFY_CHANGE_FILE_NAME;
5864 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5865 &parent_dir_src, NULL) ||
5866 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5867 &parent_dir_dst, NULL)) {
5868 goto out;
5871 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5872 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5873 smb_fname_src->base_name);
5874 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5875 smb_fname_dst->base_name);
5877 else {
5878 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5879 smb_fname_src->base_name);
5880 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5881 smb_fname_dst->base_name);
5884 /* this is a strange one. w2k3 gives an additional event for
5885 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5886 files, but not directories */
5887 if (!is_dir) {
5888 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5889 FILE_NOTIFY_CHANGE_ATTRIBUTES
5890 |FILE_NOTIFY_CHANGE_CREATION,
5891 smb_fname_dst->base_name);
5893 out:
5894 TALLOC_FREE(parent_dir_src);
5895 TALLOC_FREE(parent_dir_dst);
5898 /****************************************************************************
5899 Returns an error if the parent directory for a filename is open in an
5900 incompatible way.
5901 ****************************************************************************/
5903 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
5904 const struct smb_filename *smb_fname_dst_in)
5906 char *parent_dir = NULL;
5907 struct smb_filename smb_fname_parent;
5908 struct file_id id;
5909 files_struct *fsp = NULL;
5910 int ret;
5912 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
5913 &parent_dir, NULL)) {
5914 return NT_STATUS_NO_MEMORY;
5916 ZERO_STRUCT(smb_fname_parent);
5917 smb_fname_parent.base_name = parent_dir;
5919 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
5920 if (ret == -1) {
5921 return map_nt_error_from_unix(errno);
5925 * We're only checking on this smbd here, mostly good
5926 * enough.. and will pass tests.
5929 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
5930 for (fsp = file_find_di_first(conn->sconn, id); fsp;
5931 fsp = file_find_di_next(fsp)) {
5932 if (fsp->access_mask & DELETE_ACCESS) {
5933 return NT_STATUS_SHARING_VIOLATION;
5936 return NT_STATUS_OK;
5939 /****************************************************************************
5940 Rename an open file - given an fsp.
5941 ****************************************************************************/
5943 NTSTATUS rename_internals_fsp(connection_struct *conn,
5944 files_struct *fsp,
5945 const struct smb_filename *smb_fname_dst_in,
5946 uint32 attrs,
5947 bool replace_if_exists)
5949 TALLOC_CTX *ctx = talloc_tos();
5950 struct smb_filename *smb_fname_dst = NULL;
5951 NTSTATUS status = NT_STATUS_OK;
5952 struct share_mode_lock *lck = NULL;
5953 bool dst_exists, old_is_stream, new_is_stream;
5955 status = check_name(conn, smb_fname_dst_in->base_name);
5956 if (!NT_STATUS_IS_OK(status)) {
5957 return status;
5960 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
5961 if (!NT_STATUS_IS_OK(status)) {
5962 return status;
5965 /* Make a copy of the dst smb_fname structs */
5967 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5968 if (!NT_STATUS_IS_OK(status)) {
5969 goto out;
5973 * Check for special case with case preserving and not
5974 * case sensitive. If the old last component differs from the original
5975 * last component only by case, then we should allow
5976 * the rename (user is trying to change the case of the
5977 * filename).
5979 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5980 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5981 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5982 char *last_slash;
5983 char *fname_dst_lcomp_base_mod = NULL;
5984 struct smb_filename *smb_fname_orig_lcomp = NULL;
5987 * Get the last component of the destination name.
5989 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5990 if (last_slash) {
5991 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5992 } else {
5993 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
5995 if (!fname_dst_lcomp_base_mod) {
5996 status = NT_STATUS_NO_MEMORY;
5997 goto out;
6001 * Create an smb_filename struct using the original last
6002 * component of the destination.
6004 status = create_synthetic_smb_fname_split(ctx,
6005 smb_fname_dst->original_lcomp, NULL,
6006 &smb_fname_orig_lcomp);
6007 if (!NT_STATUS_IS_OK(status)) {
6008 TALLOC_FREE(fname_dst_lcomp_base_mod);
6009 goto out;
6012 /* If the base names only differ by case, use original. */
6013 if(!strcsequal(fname_dst_lcomp_base_mod,
6014 smb_fname_orig_lcomp->base_name)) {
6015 char *tmp;
6017 * Replace the modified last component with the
6018 * original.
6020 if (last_slash) {
6021 *last_slash = '\0'; /* Truncate at the '/' */
6022 tmp = talloc_asprintf(smb_fname_dst,
6023 "%s/%s",
6024 smb_fname_dst->base_name,
6025 smb_fname_orig_lcomp->base_name);
6026 } else {
6027 tmp = talloc_asprintf(smb_fname_dst,
6028 "%s",
6029 smb_fname_orig_lcomp->base_name);
6031 if (tmp == NULL) {
6032 status = NT_STATUS_NO_MEMORY;
6033 TALLOC_FREE(fname_dst_lcomp_base_mod);
6034 TALLOC_FREE(smb_fname_orig_lcomp);
6035 goto out;
6037 TALLOC_FREE(smb_fname_dst->base_name);
6038 smb_fname_dst->base_name = tmp;
6041 /* If the stream_names only differ by case, use original. */
6042 if(!strcsequal(smb_fname_dst->stream_name,
6043 smb_fname_orig_lcomp->stream_name)) {
6044 char *tmp = NULL;
6045 /* Use the original stream. */
6046 tmp = talloc_strdup(smb_fname_dst,
6047 smb_fname_orig_lcomp->stream_name);
6048 if (tmp == NULL) {
6049 status = NT_STATUS_NO_MEMORY;
6050 TALLOC_FREE(fname_dst_lcomp_base_mod);
6051 TALLOC_FREE(smb_fname_orig_lcomp);
6052 goto out;
6054 TALLOC_FREE(smb_fname_dst->stream_name);
6055 smb_fname_dst->stream_name = tmp;
6057 TALLOC_FREE(fname_dst_lcomp_base_mod);
6058 TALLOC_FREE(smb_fname_orig_lcomp);
6062 * If the src and dest names are identical - including case,
6063 * don't do the rename, just return success.
6066 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6067 strcsequal(fsp->fsp_name->stream_name,
6068 smb_fname_dst->stream_name)) {
6069 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6070 "- returning success\n",
6071 smb_fname_str_dbg(smb_fname_dst)));
6072 status = NT_STATUS_OK;
6073 goto out;
6076 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6077 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6079 /* Return the correct error code if both names aren't streams. */
6080 if (!old_is_stream && new_is_stream) {
6081 status = NT_STATUS_OBJECT_NAME_INVALID;
6082 goto out;
6085 if (old_is_stream && !new_is_stream) {
6086 status = NT_STATUS_INVALID_PARAMETER;
6087 goto out;
6090 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6092 if(!replace_if_exists && dst_exists) {
6093 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6094 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6095 smb_fname_str_dbg(smb_fname_dst)));
6096 status = NT_STATUS_OBJECT_NAME_COLLISION;
6097 goto out;
6100 if (dst_exists) {
6101 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6102 &smb_fname_dst->st);
6103 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6104 fileid);
6105 /* The file can be open when renaming a stream */
6106 if (dst_fsp && !new_is_stream) {
6107 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6108 status = NT_STATUS_ACCESS_DENIED;
6109 goto out;
6113 /* Ensure we have a valid stat struct for the source. */
6114 status = vfs_stat_fsp(fsp);
6115 if (!NT_STATUS_IS_OK(status)) {
6116 goto out;
6119 status = can_rename(conn, fsp, attrs);
6121 if (!NT_STATUS_IS_OK(status)) {
6122 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6123 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6124 smb_fname_str_dbg(smb_fname_dst)));
6125 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6126 status = NT_STATUS_ACCESS_DENIED;
6127 goto out;
6130 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6131 status = NT_STATUS_ACCESS_DENIED;
6134 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6137 * We have the file open ourselves, so not being able to get the
6138 * corresponding share mode lock is a fatal error.
6141 SMB_ASSERT(lck != NULL);
6143 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6144 uint32 create_options = fsp->fh->private_options;
6146 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6147 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6148 smb_fname_str_dbg(smb_fname_dst)));
6150 if (!lp_posix_pathnames() &&
6151 (lp_map_archive(SNUM(conn)) ||
6152 lp_store_dos_attributes(SNUM(conn)))) {
6153 /* We must set the archive bit on the newly
6154 renamed file. */
6155 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6156 uint32_t old_dosmode = dos_mode(conn,
6157 smb_fname_dst);
6158 file_set_dosmode(conn,
6159 smb_fname_dst,
6160 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6161 NULL,
6162 true);
6166 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6167 smb_fname_dst);
6169 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6172 * A rename acts as a new file create w.r.t. allowing an initial delete
6173 * on close, probably because in Windows there is a new handle to the
6174 * new file. If initial delete on close was requested but not
6175 * originally set, we need to set it here. This is probably not 100% correct,
6176 * but will work for the CIFSFS client which in non-posix mode
6177 * depends on these semantics. JRA.
6180 if (create_options & FILE_DELETE_ON_CLOSE) {
6181 status = can_set_delete_on_close(fsp, 0);
6183 if (NT_STATUS_IS_OK(status)) {
6184 /* Note that here we set the *inital* delete on close flag,
6185 * not the regular one. The magic gets handled in close. */
6186 fsp->initial_delete_on_close = True;
6189 TALLOC_FREE(lck);
6190 status = NT_STATUS_OK;
6191 goto out;
6194 TALLOC_FREE(lck);
6196 if (errno == ENOTDIR || errno == EISDIR) {
6197 status = NT_STATUS_OBJECT_NAME_COLLISION;
6198 } else {
6199 status = map_nt_error_from_unix(errno);
6202 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6203 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6204 smb_fname_str_dbg(smb_fname_dst)));
6206 out:
6207 TALLOC_FREE(smb_fname_dst);
6209 return status;
6212 /****************************************************************************
6213 The guts of the rename command, split out so it may be called by the NT SMB
6214 code.
6215 ****************************************************************************/
6217 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6218 connection_struct *conn,
6219 struct smb_request *req,
6220 struct smb_filename *smb_fname_src,
6221 struct smb_filename *smb_fname_dst,
6222 uint32 attrs,
6223 bool replace_if_exists,
6224 bool src_has_wild,
6225 bool dest_has_wild,
6226 uint32_t access_mask)
6228 char *fname_src_dir = NULL;
6229 char *fname_src_mask = NULL;
6230 int count=0;
6231 NTSTATUS status = NT_STATUS_OK;
6232 struct smb_Dir *dir_hnd = NULL;
6233 const char *dname = NULL;
6234 char *talloced = NULL;
6235 long offset = 0;
6236 int create_options = 0;
6237 bool posix_pathnames = lp_posix_pathnames();
6240 * Split the old name into directory and last component
6241 * strings. Note that unix_convert may have stripped off a
6242 * leading ./ from both name and newname if the rename is
6243 * at the root of the share. We need to make sure either both
6244 * name and newname contain a / character or neither of them do
6245 * as this is checked in resolve_wildcards().
6248 /* Split up the directory from the filename/mask. */
6249 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6250 &fname_src_dir, &fname_src_mask);
6251 if (!NT_STATUS_IS_OK(status)) {
6252 status = NT_STATUS_NO_MEMORY;
6253 goto out;
6257 * We should only check the mangled cache
6258 * here if unix_convert failed. This means
6259 * that the path in 'mask' doesn't exist
6260 * on the file system and so we need to look
6261 * for a possible mangle. This patch from
6262 * Tine Smukavec <valentin.smukavec@hermes.si>.
6265 if (!VALID_STAT(smb_fname_src->st) &&
6266 mangle_is_mangled(fname_src_mask, conn->params)) {
6267 char *new_mask = NULL;
6268 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6269 conn->params);
6270 if (new_mask) {
6271 TALLOC_FREE(fname_src_mask);
6272 fname_src_mask = new_mask;
6276 if (!src_has_wild) {
6277 files_struct *fsp;
6280 * Only one file needs to be renamed. Append the mask back
6281 * onto the directory.
6283 TALLOC_FREE(smb_fname_src->base_name);
6284 if (ISDOT(fname_src_dir)) {
6285 /* Ensure we use canonical names on open. */
6286 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6287 "%s",
6288 fname_src_mask);
6289 } else {
6290 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6291 "%s/%s",
6292 fname_src_dir,
6293 fname_src_mask);
6295 if (!smb_fname_src->base_name) {
6296 status = NT_STATUS_NO_MEMORY;
6297 goto out;
6300 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6301 "case_preserve = %d, short case preserve = %d, "
6302 "directory = %s, newname = %s, "
6303 "last_component_dest = %s\n",
6304 conn->case_sensitive, conn->case_preserve,
6305 conn->short_case_preserve,
6306 smb_fname_str_dbg(smb_fname_src),
6307 smb_fname_str_dbg(smb_fname_dst),
6308 smb_fname_dst->original_lcomp));
6310 /* The dest name still may have wildcards. */
6311 if (dest_has_wild) {
6312 char *fname_dst_mod = NULL;
6313 if (!resolve_wildcards(smb_fname_dst,
6314 smb_fname_src->base_name,
6315 smb_fname_dst->base_name,
6316 &fname_dst_mod)) {
6317 DEBUG(6, ("rename_internals: resolve_wildcards "
6318 "%s %s failed\n",
6319 smb_fname_src->base_name,
6320 smb_fname_dst->base_name));
6321 status = NT_STATUS_NO_MEMORY;
6322 goto out;
6324 TALLOC_FREE(smb_fname_dst->base_name);
6325 smb_fname_dst->base_name = fname_dst_mod;
6328 ZERO_STRUCT(smb_fname_src->st);
6329 if (posix_pathnames) {
6330 SMB_VFS_LSTAT(conn, smb_fname_src);
6331 } else {
6332 SMB_VFS_STAT(conn, smb_fname_src);
6335 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6336 create_options |= FILE_DIRECTORY_FILE;
6339 status = SMB_VFS_CREATE_FILE(
6340 conn, /* conn */
6341 req, /* req */
6342 0, /* root_dir_fid */
6343 smb_fname_src, /* fname */
6344 access_mask, /* access_mask */
6345 (FILE_SHARE_READ | /* share_access */
6346 FILE_SHARE_WRITE),
6347 FILE_OPEN, /* create_disposition*/
6348 create_options, /* create_options */
6349 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6350 0, /* oplock_request */
6351 0, /* allocation_size */
6352 0, /* private_flags */
6353 NULL, /* sd */
6354 NULL, /* ea_list */
6355 &fsp, /* result */
6356 NULL); /* pinfo */
6358 if (!NT_STATUS_IS_OK(status)) {
6359 DEBUG(3, ("Could not open rename source %s: %s\n",
6360 smb_fname_str_dbg(smb_fname_src),
6361 nt_errstr(status)));
6362 goto out;
6365 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6366 attrs, replace_if_exists);
6368 close_file(req, fsp, NORMAL_CLOSE);
6370 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6371 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6372 smb_fname_str_dbg(smb_fname_dst)));
6374 goto out;
6378 * Wildcards - process each file that matches.
6380 if (strequal(fname_src_mask, "????????.???")) {
6381 TALLOC_FREE(fname_src_mask);
6382 fname_src_mask = talloc_strdup(ctx, "*");
6383 if (!fname_src_mask) {
6384 status = NT_STATUS_NO_MEMORY;
6385 goto out;
6389 status = check_name(conn, fname_src_dir);
6390 if (!NT_STATUS_IS_OK(status)) {
6391 goto out;
6394 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6395 attrs);
6396 if (dir_hnd == NULL) {
6397 status = map_nt_error_from_unix(errno);
6398 goto out;
6401 status = NT_STATUS_NO_SUCH_FILE;
6403 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6404 * - gentest fix. JRA
6407 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6408 &talloced))) {
6409 files_struct *fsp = NULL;
6410 char *destname = NULL;
6411 bool sysdir_entry = False;
6413 /* Quick check for "." and ".." */
6414 if (ISDOT(dname) || ISDOTDOT(dname)) {
6415 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6416 sysdir_entry = True;
6417 } else {
6418 TALLOC_FREE(talloced);
6419 continue;
6423 if (!is_visible_file(conn, fname_src_dir, dname,
6424 &smb_fname_src->st, false)) {
6425 TALLOC_FREE(talloced);
6426 continue;
6429 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6430 TALLOC_FREE(talloced);
6431 continue;
6434 if (sysdir_entry) {
6435 status = NT_STATUS_OBJECT_NAME_INVALID;
6436 break;
6439 TALLOC_FREE(smb_fname_src->base_name);
6440 if (ISDOT(fname_src_dir)) {
6441 /* Ensure we use canonical names on open. */
6442 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6443 "%s",
6444 dname);
6445 } else {
6446 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6447 "%s/%s",
6448 fname_src_dir,
6449 dname);
6451 if (!smb_fname_src->base_name) {
6452 status = NT_STATUS_NO_MEMORY;
6453 goto out;
6456 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6457 smb_fname_dst->base_name,
6458 &destname)) {
6459 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6460 smb_fname_src->base_name, destname));
6461 TALLOC_FREE(talloced);
6462 continue;
6464 if (!destname) {
6465 status = NT_STATUS_NO_MEMORY;
6466 goto out;
6469 TALLOC_FREE(smb_fname_dst->base_name);
6470 smb_fname_dst->base_name = destname;
6472 ZERO_STRUCT(smb_fname_src->st);
6473 if (posix_pathnames) {
6474 SMB_VFS_LSTAT(conn, smb_fname_src);
6475 } else {
6476 SMB_VFS_STAT(conn, smb_fname_src);
6479 create_options = 0;
6481 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6482 create_options |= FILE_DIRECTORY_FILE;
6485 status = SMB_VFS_CREATE_FILE(
6486 conn, /* conn */
6487 req, /* req */
6488 0, /* root_dir_fid */
6489 smb_fname_src, /* fname */
6490 access_mask, /* access_mask */
6491 (FILE_SHARE_READ | /* share_access */
6492 FILE_SHARE_WRITE),
6493 FILE_OPEN, /* create_disposition*/
6494 create_options, /* create_options */
6495 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6496 0, /* oplock_request */
6497 0, /* allocation_size */
6498 0, /* private_flags */
6499 NULL, /* sd */
6500 NULL, /* ea_list */
6501 &fsp, /* result */
6502 NULL); /* pinfo */
6504 if (!NT_STATUS_IS_OK(status)) {
6505 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6506 "returned %s rename %s -> %s\n",
6507 nt_errstr(status),
6508 smb_fname_str_dbg(smb_fname_src),
6509 smb_fname_str_dbg(smb_fname_dst)));
6510 break;
6513 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6514 dname);
6515 if (!smb_fname_dst->original_lcomp) {
6516 status = NT_STATUS_NO_MEMORY;
6517 goto out;
6520 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6521 attrs, replace_if_exists);
6523 close_file(req, fsp, NORMAL_CLOSE);
6525 if (!NT_STATUS_IS_OK(status)) {
6526 DEBUG(3, ("rename_internals_fsp returned %s for "
6527 "rename %s -> %s\n", nt_errstr(status),
6528 smb_fname_str_dbg(smb_fname_src),
6529 smb_fname_str_dbg(smb_fname_dst)));
6530 break;
6533 count++;
6535 DEBUG(3,("rename_internals: doing rename on %s -> "
6536 "%s\n", smb_fname_str_dbg(smb_fname_src),
6537 smb_fname_str_dbg(smb_fname_src)));
6538 TALLOC_FREE(talloced);
6540 TALLOC_FREE(dir_hnd);
6542 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6543 status = map_nt_error_from_unix(errno);
6546 out:
6547 TALLOC_FREE(talloced);
6548 TALLOC_FREE(fname_src_dir);
6549 TALLOC_FREE(fname_src_mask);
6550 return status;
6553 /****************************************************************************
6554 Reply to a mv.
6555 ****************************************************************************/
6557 void reply_mv(struct smb_request *req)
6559 connection_struct *conn = req->conn;
6560 char *name = NULL;
6561 char *newname = NULL;
6562 const char *p;
6563 uint32 attrs;
6564 NTSTATUS status;
6565 bool src_has_wcard = False;
6566 bool dest_has_wcard = False;
6567 TALLOC_CTX *ctx = talloc_tos();
6568 struct smb_filename *smb_fname_src = NULL;
6569 struct smb_filename *smb_fname_dst = NULL;
6570 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6571 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6572 bool stream_rename = false;
6574 START_PROFILE(SMBmv);
6576 if (req->wct < 1) {
6577 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6578 goto out;
6581 attrs = SVAL(req->vwv+0, 0);
6583 p = (const char *)req->buf + 1;
6584 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6585 &status, &src_has_wcard);
6586 if (!NT_STATUS_IS_OK(status)) {
6587 reply_nterror(req, status);
6588 goto out;
6590 p++;
6591 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6592 &status, &dest_has_wcard);
6593 if (!NT_STATUS_IS_OK(status)) {
6594 reply_nterror(req, status);
6595 goto out;
6598 if (!lp_posix_pathnames()) {
6599 /* The newname must begin with a ':' if the
6600 name contains a ':'. */
6601 if (strchr_m(name, ':')) {
6602 if (newname[0] != ':') {
6603 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6604 goto out;
6606 stream_rename = true;
6610 status = filename_convert(ctx,
6611 conn,
6612 req->flags2 & FLAGS2_DFS_PATHNAMES,
6613 name,
6614 src_ucf_flags,
6615 &src_has_wcard,
6616 &smb_fname_src);
6618 if (!NT_STATUS_IS_OK(status)) {
6619 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6620 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6621 ERRSRV, ERRbadpath);
6622 goto out;
6624 reply_nterror(req, status);
6625 goto out;
6628 status = filename_convert(ctx,
6629 conn,
6630 req->flags2 & FLAGS2_DFS_PATHNAMES,
6631 newname,
6632 dst_ucf_flags,
6633 &dest_has_wcard,
6634 &smb_fname_dst);
6636 if (!NT_STATUS_IS_OK(status)) {
6637 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6638 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6639 ERRSRV, ERRbadpath);
6640 goto out;
6642 reply_nterror(req, status);
6643 goto out;
6646 if (stream_rename) {
6647 /* smb_fname_dst->base_name must be the same as
6648 smb_fname_src->base_name. */
6649 TALLOC_FREE(smb_fname_dst->base_name);
6650 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6651 smb_fname_src->base_name);
6652 if (!smb_fname_dst->base_name) {
6653 reply_nterror(req, NT_STATUS_NO_MEMORY);
6654 goto out;
6658 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6659 smb_fname_str_dbg(smb_fname_dst)));
6661 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6662 attrs, False, src_has_wcard, dest_has_wcard,
6663 DELETE_ACCESS);
6664 if (!NT_STATUS_IS_OK(status)) {
6665 if (open_was_deferred(req->sconn, req->mid)) {
6666 /* We have re-scheduled this call. */
6667 goto out;
6669 reply_nterror(req, status);
6670 goto out;
6673 reply_outbuf(req, 0, 0);
6674 out:
6675 TALLOC_FREE(smb_fname_src);
6676 TALLOC_FREE(smb_fname_dst);
6677 END_PROFILE(SMBmv);
6678 return;
6681 /*******************************************************************
6682 Copy a file as part of a reply_copy.
6683 ******************************************************************/
6686 * TODO: check error codes on all callers
6689 NTSTATUS copy_file(TALLOC_CTX *ctx,
6690 connection_struct *conn,
6691 struct smb_filename *smb_fname_src,
6692 struct smb_filename *smb_fname_dst,
6693 int ofun,
6694 int count,
6695 bool target_is_directory)
6697 struct smb_filename *smb_fname_dst_tmp = NULL;
6698 off_t ret=-1;
6699 files_struct *fsp1,*fsp2;
6700 uint32 dosattrs;
6701 uint32 new_create_disposition;
6702 NTSTATUS status;
6705 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6706 if (!NT_STATUS_IS_OK(status)) {
6707 return status;
6711 * If the target is a directory, extract the last component from the
6712 * src filename and append it to the dst filename
6714 if (target_is_directory) {
6715 const char *p;
6717 /* dest/target can't be a stream if it's a directory. */
6718 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6720 p = strrchr_m(smb_fname_src->base_name,'/');
6721 if (p) {
6722 p++;
6723 } else {
6724 p = smb_fname_src->base_name;
6726 smb_fname_dst_tmp->base_name =
6727 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6729 if (!smb_fname_dst_tmp->base_name) {
6730 status = NT_STATUS_NO_MEMORY;
6731 goto out;
6735 status = vfs_file_exist(conn, smb_fname_src);
6736 if (!NT_STATUS_IS_OK(status)) {
6737 goto out;
6740 if (!target_is_directory && count) {
6741 new_create_disposition = FILE_OPEN;
6742 } else {
6743 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6744 0, ofun,
6745 NULL, NULL,
6746 &new_create_disposition,
6747 NULL,
6748 NULL)) {
6749 status = NT_STATUS_INVALID_PARAMETER;
6750 goto out;
6754 /* Open the src file for reading. */
6755 status = SMB_VFS_CREATE_FILE(
6756 conn, /* conn */
6757 NULL, /* req */
6758 0, /* root_dir_fid */
6759 smb_fname_src, /* fname */
6760 FILE_GENERIC_READ, /* access_mask */
6761 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6762 FILE_OPEN, /* create_disposition*/
6763 0, /* create_options */
6764 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6765 INTERNAL_OPEN_ONLY, /* oplock_request */
6766 0, /* allocation_size */
6767 0, /* private_flags */
6768 NULL, /* sd */
6769 NULL, /* ea_list */
6770 &fsp1, /* result */
6771 NULL); /* psbuf */
6773 if (!NT_STATUS_IS_OK(status)) {
6774 goto out;
6777 dosattrs = dos_mode(conn, smb_fname_src);
6779 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6780 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6783 /* Open the dst file for writing. */
6784 status = SMB_VFS_CREATE_FILE(
6785 conn, /* conn */
6786 NULL, /* req */
6787 0, /* root_dir_fid */
6788 smb_fname_dst, /* fname */
6789 FILE_GENERIC_WRITE, /* access_mask */
6790 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6791 new_create_disposition, /* create_disposition*/
6792 0, /* create_options */
6793 dosattrs, /* file_attributes */
6794 INTERNAL_OPEN_ONLY, /* oplock_request */
6795 0, /* allocation_size */
6796 0, /* private_flags */
6797 NULL, /* sd */
6798 NULL, /* ea_list */
6799 &fsp2, /* result */
6800 NULL); /* psbuf */
6802 if (!NT_STATUS_IS_OK(status)) {
6803 close_file(NULL, fsp1, ERROR_CLOSE);
6804 goto out;
6807 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6808 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6809 if (ret == -1) {
6810 DEBUG(0, ("error - vfs lseek returned error %s\n",
6811 strerror(errno)));
6812 status = map_nt_error_from_unix(errno);
6813 close_file(NULL, fsp1, ERROR_CLOSE);
6814 close_file(NULL, fsp2, ERROR_CLOSE);
6815 goto out;
6819 /* Do the actual copy. */
6820 if (smb_fname_src->st.st_ex_size) {
6821 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6822 } else {
6823 ret = 0;
6826 close_file(NULL, fsp1, NORMAL_CLOSE);
6828 /* Ensure the modtime is set correctly on the destination file. */
6829 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6832 * As we are opening fsp1 read-only we only expect
6833 * an error on close on fsp2 if we are out of space.
6834 * Thus we don't look at the error return from the
6835 * close of fsp1.
6837 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6839 if (!NT_STATUS_IS_OK(status)) {
6840 goto out;
6843 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
6844 status = NT_STATUS_DISK_FULL;
6845 goto out;
6848 status = NT_STATUS_OK;
6850 out:
6851 TALLOC_FREE(smb_fname_dst_tmp);
6852 return status;
6855 /****************************************************************************
6856 Reply to a file copy.
6857 ****************************************************************************/
6859 void reply_copy(struct smb_request *req)
6861 connection_struct *conn = req->conn;
6862 struct smb_filename *smb_fname_src = NULL;
6863 struct smb_filename *smb_fname_dst = NULL;
6864 char *fname_src = NULL;
6865 char *fname_dst = NULL;
6866 char *fname_src_mask = NULL;
6867 char *fname_src_dir = NULL;
6868 const char *p;
6869 int count=0;
6870 int error = ERRnoaccess;
6871 int tid2;
6872 int ofun;
6873 int flags;
6874 bool target_is_directory=False;
6875 bool source_has_wild = False;
6876 bool dest_has_wild = False;
6877 NTSTATUS status;
6878 TALLOC_CTX *ctx = talloc_tos();
6880 START_PROFILE(SMBcopy);
6882 if (req->wct < 3) {
6883 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6884 goto out;
6887 tid2 = SVAL(req->vwv+0, 0);
6888 ofun = SVAL(req->vwv+1, 0);
6889 flags = SVAL(req->vwv+2, 0);
6891 p = (const char *)req->buf;
6892 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6893 &status, &source_has_wild);
6894 if (!NT_STATUS_IS_OK(status)) {
6895 reply_nterror(req, status);
6896 goto out;
6898 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6899 &status, &dest_has_wild);
6900 if (!NT_STATUS_IS_OK(status)) {
6901 reply_nterror(req, status);
6902 goto out;
6905 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6907 if (tid2 != conn->cnum) {
6908 /* can't currently handle inter share copies XXXX */
6909 DEBUG(3,("Rejecting inter-share copy\n"));
6910 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6911 goto out;
6914 status = filename_convert(ctx, conn,
6915 req->flags2 & FLAGS2_DFS_PATHNAMES,
6916 fname_src,
6917 UCF_COND_ALLOW_WCARD_LCOMP,
6918 &source_has_wild,
6919 &smb_fname_src);
6920 if (!NT_STATUS_IS_OK(status)) {
6921 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6922 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6923 ERRSRV, ERRbadpath);
6924 goto out;
6926 reply_nterror(req, status);
6927 goto out;
6930 status = filename_convert(ctx, conn,
6931 req->flags2 & FLAGS2_DFS_PATHNAMES,
6932 fname_dst,
6933 UCF_COND_ALLOW_WCARD_LCOMP,
6934 &dest_has_wild,
6935 &smb_fname_dst);
6936 if (!NT_STATUS_IS_OK(status)) {
6937 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6938 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6939 ERRSRV, ERRbadpath);
6940 goto out;
6942 reply_nterror(req, status);
6943 goto out;
6946 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6948 if ((flags&1) && target_is_directory) {
6949 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6950 goto out;
6953 if ((flags&2) && !target_is_directory) {
6954 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6955 goto out;
6958 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6959 /* wants a tree copy! XXXX */
6960 DEBUG(3,("Rejecting tree copy\n"));
6961 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6962 goto out;
6965 /* Split up the directory from the filename/mask. */
6966 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6967 &fname_src_dir, &fname_src_mask);
6968 if (!NT_STATUS_IS_OK(status)) {
6969 reply_nterror(req, NT_STATUS_NO_MEMORY);
6970 goto out;
6974 * We should only check the mangled cache
6975 * here if unix_convert failed. This means
6976 * that the path in 'mask' doesn't exist
6977 * on the file system and so we need to look
6978 * for a possible mangle. This patch from
6979 * Tine Smukavec <valentin.smukavec@hermes.si>.
6981 if (!VALID_STAT(smb_fname_src->st) &&
6982 mangle_is_mangled(fname_src_mask, conn->params)) {
6983 char *new_mask = NULL;
6984 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6985 &new_mask, conn->params);
6987 /* Use demangled name if one was successfully found. */
6988 if (new_mask) {
6989 TALLOC_FREE(fname_src_mask);
6990 fname_src_mask = new_mask;
6994 if (!source_has_wild) {
6997 * Only one file needs to be copied. Append the mask back onto
6998 * the directory.
7000 TALLOC_FREE(smb_fname_src->base_name);
7001 if (ISDOT(fname_src_dir)) {
7002 /* Ensure we use canonical names on open. */
7003 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7004 "%s",
7005 fname_src_mask);
7006 } else {
7007 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7008 "%s/%s",
7009 fname_src_dir,
7010 fname_src_mask);
7012 if (!smb_fname_src->base_name) {
7013 reply_nterror(req, NT_STATUS_NO_MEMORY);
7014 goto out;
7017 if (dest_has_wild) {
7018 char *fname_dst_mod = NULL;
7019 if (!resolve_wildcards(smb_fname_dst,
7020 smb_fname_src->base_name,
7021 smb_fname_dst->base_name,
7022 &fname_dst_mod)) {
7023 reply_nterror(req, NT_STATUS_NO_MEMORY);
7024 goto out;
7026 TALLOC_FREE(smb_fname_dst->base_name);
7027 smb_fname_dst->base_name = fname_dst_mod;
7030 status = check_name(conn, smb_fname_src->base_name);
7031 if (!NT_STATUS_IS_OK(status)) {
7032 reply_nterror(req, status);
7033 goto out;
7036 status = check_name(conn, smb_fname_dst->base_name);
7037 if (!NT_STATUS_IS_OK(status)) {
7038 reply_nterror(req, status);
7039 goto out;
7042 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7043 ofun, count, target_is_directory);
7045 if(!NT_STATUS_IS_OK(status)) {
7046 reply_nterror(req, status);
7047 goto out;
7048 } else {
7049 count++;
7051 } else {
7052 struct smb_Dir *dir_hnd = NULL;
7053 const char *dname = NULL;
7054 char *talloced = NULL;
7055 long offset = 0;
7058 * There is a wildcard that requires us to actually read the
7059 * src dir and copy each file matching the mask to the dst.
7060 * Right now streams won't be copied, but this could
7061 * presumably be added with a nested loop for reach dir entry.
7063 SMB_ASSERT(!smb_fname_src->stream_name);
7064 SMB_ASSERT(!smb_fname_dst->stream_name);
7066 smb_fname_src->stream_name = NULL;
7067 smb_fname_dst->stream_name = NULL;
7069 if (strequal(fname_src_mask,"????????.???")) {
7070 TALLOC_FREE(fname_src_mask);
7071 fname_src_mask = talloc_strdup(ctx, "*");
7072 if (!fname_src_mask) {
7073 reply_nterror(req, NT_STATUS_NO_MEMORY);
7074 goto out;
7078 status = check_name(conn, fname_src_dir);
7079 if (!NT_STATUS_IS_OK(status)) {
7080 reply_nterror(req, status);
7081 goto out;
7084 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7085 if (dir_hnd == NULL) {
7086 status = map_nt_error_from_unix(errno);
7087 reply_nterror(req, status);
7088 goto out;
7091 error = ERRbadfile;
7093 /* Iterate over the src dir copying each entry to the dst. */
7094 while ((dname = ReadDirName(dir_hnd, &offset,
7095 &smb_fname_src->st, &talloced))) {
7096 char *destname = NULL;
7098 if (ISDOT(dname) || ISDOTDOT(dname)) {
7099 TALLOC_FREE(talloced);
7100 continue;
7103 if (!is_visible_file(conn, fname_src_dir, dname,
7104 &smb_fname_src->st, false)) {
7105 TALLOC_FREE(talloced);
7106 continue;
7109 if(!mask_match(dname, fname_src_mask,
7110 conn->case_sensitive)) {
7111 TALLOC_FREE(talloced);
7112 continue;
7115 error = ERRnoaccess;
7117 /* Get the src smb_fname struct setup. */
7118 TALLOC_FREE(smb_fname_src->base_name);
7119 if (ISDOT(fname_src_dir)) {
7120 /* Ensure we use canonical names on open. */
7121 smb_fname_src->base_name =
7122 talloc_asprintf(smb_fname_src, "%s",
7123 dname);
7124 } else {
7125 smb_fname_src->base_name =
7126 talloc_asprintf(smb_fname_src, "%s/%s",
7127 fname_src_dir, dname);
7130 if (!smb_fname_src->base_name) {
7131 TALLOC_FREE(dir_hnd);
7132 TALLOC_FREE(talloced);
7133 reply_nterror(req, NT_STATUS_NO_MEMORY);
7134 goto out;
7137 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7138 smb_fname_dst->base_name,
7139 &destname)) {
7140 TALLOC_FREE(talloced);
7141 continue;
7143 if (!destname) {
7144 TALLOC_FREE(dir_hnd);
7145 TALLOC_FREE(talloced);
7146 reply_nterror(req, NT_STATUS_NO_MEMORY);
7147 goto out;
7150 TALLOC_FREE(smb_fname_dst->base_name);
7151 smb_fname_dst->base_name = destname;
7153 status = check_name(conn, smb_fname_src->base_name);
7154 if (!NT_STATUS_IS_OK(status)) {
7155 TALLOC_FREE(dir_hnd);
7156 TALLOC_FREE(talloced);
7157 reply_nterror(req, status);
7158 goto out;
7161 status = check_name(conn, smb_fname_dst->base_name);
7162 if (!NT_STATUS_IS_OK(status)) {
7163 TALLOC_FREE(dir_hnd);
7164 TALLOC_FREE(talloced);
7165 reply_nterror(req, status);
7166 goto out;
7169 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7170 smb_fname_src->base_name,
7171 smb_fname_dst->base_name));
7173 status = copy_file(ctx, conn, smb_fname_src,
7174 smb_fname_dst, ofun, count,
7175 target_is_directory);
7176 if (NT_STATUS_IS_OK(status)) {
7177 count++;
7180 TALLOC_FREE(talloced);
7182 TALLOC_FREE(dir_hnd);
7185 if (count == 0) {
7186 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7187 goto out;
7190 reply_outbuf(req, 1, 0);
7191 SSVAL(req->outbuf,smb_vwv0,count);
7192 out:
7193 TALLOC_FREE(smb_fname_src);
7194 TALLOC_FREE(smb_fname_dst);
7195 TALLOC_FREE(fname_src);
7196 TALLOC_FREE(fname_dst);
7197 TALLOC_FREE(fname_src_mask);
7198 TALLOC_FREE(fname_src_dir);
7200 END_PROFILE(SMBcopy);
7201 return;
7204 #undef DBGC_CLASS
7205 #define DBGC_CLASS DBGC_LOCKING
7207 /****************************************************************************
7208 Get a lock pid, dealing with large count requests.
7209 ****************************************************************************/
7211 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7212 bool large_file_format)
7214 if(!large_file_format)
7215 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7216 else
7217 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7220 /****************************************************************************
7221 Get a lock count, dealing with large count requests.
7222 ****************************************************************************/
7224 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7225 bool large_file_format)
7227 uint64_t count = 0;
7229 if(!large_file_format) {
7230 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7231 } else {
7233 #if defined(HAVE_LONGLONG)
7234 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7235 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7236 #else /* HAVE_LONGLONG */
7239 * NT4.x seems to be broken in that it sends large file (64 bit)
7240 * lockingX calls even if the CAP_LARGE_FILES was *not*
7241 * negotiated. For boxes without large unsigned ints truncate the
7242 * lock count by dropping the top 32 bits.
7245 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7246 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7247 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7248 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7249 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7252 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7253 #endif /* HAVE_LONGLONG */
7256 return count;
7259 #if !defined(HAVE_LONGLONG)
7260 /****************************************************************************
7261 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7262 ****************************************************************************/
7264 static uint32 map_lock_offset(uint32 high, uint32 low)
7266 unsigned int i;
7267 uint32 mask = 0;
7268 uint32 highcopy = high;
7271 * Try and find out how many significant bits there are in high.
7274 for(i = 0; highcopy; i++)
7275 highcopy >>= 1;
7278 * We use 31 bits not 32 here as POSIX
7279 * lock offsets may not be negative.
7282 mask = (~0) << (31 - i);
7284 if(low & mask)
7285 return 0; /* Fail. */
7287 high <<= (31 - i);
7289 return (high|low);
7291 #endif /* !defined(HAVE_LONGLONG) */
7293 /****************************************************************************
7294 Get a lock offset, dealing with large offset requests.
7295 ****************************************************************************/
7297 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7298 bool large_file_format, bool *err)
7300 uint64_t offset = 0;
7302 *err = False;
7304 if(!large_file_format) {
7305 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7306 } else {
7308 #if defined(HAVE_LONGLONG)
7309 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7310 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7311 #else /* HAVE_LONGLONG */
7314 * NT4.x seems to be broken in that it sends large file (64 bit)
7315 * lockingX calls even if the CAP_LARGE_FILES was *not*
7316 * negotiated. For boxes without large unsigned ints mangle the
7317 * lock offset by mapping the top 32 bits onto the lower 32.
7320 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7321 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7322 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7323 uint32 new_low = 0;
7325 if((new_low = map_lock_offset(high, low)) == 0) {
7326 *err = True;
7327 return (uint64_t)-1;
7330 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7331 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7332 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7333 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7336 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7337 #endif /* HAVE_LONGLONG */
7340 return offset;
7343 NTSTATUS smbd_do_locking(struct smb_request *req,
7344 files_struct *fsp,
7345 uint8_t type,
7346 int32_t timeout,
7347 uint16_t num_ulocks,
7348 struct smbd_lock_element *ulocks,
7349 uint16_t num_locks,
7350 struct smbd_lock_element *locks,
7351 bool *async)
7353 connection_struct *conn = req->conn;
7354 int i;
7355 NTSTATUS status = NT_STATUS_OK;
7357 *async = false;
7359 /* Data now points at the beginning of the list
7360 of smb_unlkrng structs */
7361 for(i = 0; i < (int)num_ulocks; i++) {
7362 struct smbd_lock_element *e = &ulocks[i];
7364 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7365 "pid %u, file %s\n",
7366 (double)e->offset,
7367 (double)e->count,
7368 (unsigned int)e->smblctx,
7369 fsp_str_dbg(fsp)));
7371 if (e->brltype != UNLOCK_LOCK) {
7372 /* this can only happen with SMB2 */
7373 return NT_STATUS_INVALID_PARAMETER;
7376 status = do_unlock(req->sconn->msg_ctx,
7377 fsp,
7378 e->smblctx,
7379 e->count,
7380 e->offset,
7381 WINDOWS_LOCK);
7383 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7384 nt_errstr(status)));
7386 if (!NT_STATUS_IS_OK(status)) {
7387 return status;
7391 /* Setup the timeout in seconds. */
7393 if (!lp_blocking_locks(SNUM(conn))) {
7394 timeout = 0;
7397 /* Data now points at the beginning of the list
7398 of smb_lkrng structs */
7400 for(i = 0; i < (int)num_locks; i++) {
7401 struct smbd_lock_element *e = &locks[i];
7403 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7404 "%llu, file %s timeout = %d\n",
7405 (double)e->offset,
7406 (double)e->count,
7407 (unsigned long long)e->smblctx,
7408 fsp_str_dbg(fsp),
7409 (int)timeout));
7411 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7412 struct blocking_lock_record *blr = NULL;
7414 if (num_locks > 1) {
7416 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7417 * if the lock vector contains one entry. When given mutliple cancel
7418 * requests in a single PDU we expect the server to return an
7419 * error. Windows servers seem to accept the request but only
7420 * cancel the first lock.
7421 * JRA - Do what Windows does (tm) :-).
7424 #if 0
7425 /* MS-CIFS (2.2.4.32.1) behavior. */
7426 return NT_STATUS_DOS(ERRDOS,
7427 ERRcancelviolation);
7428 #else
7429 /* Windows behavior. */
7430 if (i != 0) {
7431 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7432 "cancel request\n"));
7433 continue;
7435 #endif
7438 if (lp_blocking_locks(SNUM(conn))) {
7440 /* Schedule a message to ourselves to
7441 remove the blocking lock record and
7442 return the right error. */
7444 blr = blocking_lock_cancel_smb1(fsp,
7445 e->smblctx,
7446 e->offset,
7447 e->count,
7448 WINDOWS_LOCK,
7449 type,
7450 NT_STATUS_FILE_LOCK_CONFLICT);
7451 if (blr == NULL) {
7452 return NT_STATUS_DOS(
7453 ERRDOS,
7454 ERRcancelviolation);
7457 /* Remove a matching pending lock. */
7458 status = do_lock_cancel(fsp,
7459 e->smblctx,
7460 e->count,
7461 e->offset,
7462 WINDOWS_LOCK,
7463 blr);
7464 } else {
7465 bool blocking_lock = timeout ? true : false;
7466 bool defer_lock = false;
7467 struct byte_range_lock *br_lck;
7468 uint64_t block_smblctx;
7470 br_lck = do_lock(req->sconn->msg_ctx,
7471 fsp,
7472 e->smblctx,
7473 e->count,
7474 e->offset,
7475 e->brltype,
7476 WINDOWS_LOCK,
7477 blocking_lock,
7478 &status,
7479 &block_smblctx,
7480 NULL);
7482 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7483 /* Windows internal resolution for blocking locks seems
7484 to be about 200ms... Don't wait for less than that. JRA. */
7485 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7486 timeout = lp_lock_spin_time();
7488 defer_lock = true;
7491 /* If a lock sent with timeout of zero would fail, and
7492 * this lock has been requested multiple times,
7493 * according to brl_lock_failed() we convert this
7494 * request to a blocking lock with a timeout of between
7495 * 150 - 300 milliseconds.
7497 * If lp_lock_spin_time() has been set to 0, we skip
7498 * this blocking retry and fail immediately.
7500 * Replacement for do_lock_spin(). JRA. */
7502 if (!req->sconn->using_smb2 &&
7503 br_lck && lp_blocking_locks(SNUM(conn)) &&
7504 lp_lock_spin_time() && !blocking_lock &&
7505 NT_STATUS_EQUAL((status),
7506 NT_STATUS_FILE_LOCK_CONFLICT))
7508 defer_lock = true;
7509 timeout = lp_lock_spin_time();
7512 if (br_lck && defer_lock) {
7514 * A blocking lock was requested. Package up
7515 * this smb into a queued request and push it
7516 * onto the blocking lock queue.
7518 if(push_blocking_lock_request(br_lck,
7519 req,
7520 fsp,
7521 timeout,
7523 e->smblctx,
7524 e->brltype,
7525 WINDOWS_LOCK,
7526 e->offset,
7527 e->count,
7528 block_smblctx)) {
7529 TALLOC_FREE(br_lck);
7530 *async = true;
7531 return NT_STATUS_OK;
7535 TALLOC_FREE(br_lck);
7538 if (!NT_STATUS_IS_OK(status)) {
7539 break;
7543 /* If any of the above locks failed, then we must unlock
7544 all of the previous locks (X/Open spec). */
7546 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7548 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7549 i = -1; /* we want to skip the for loop */
7553 * Ensure we don't do a remove on the lock that just failed,
7554 * as under POSIX rules, if we have a lock already there, we
7555 * will delete it (and we shouldn't) .....
7557 for(i--; i >= 0; i--) {
7558 struct smbd_lock_element *e = &locks[i];
7560 do_unlock(req->sconn->msg_ctx,
7561 fsp,
7562 e->smblctx,
7563 e->count,
7564 e->offset,
7565 WINDOWS_LOCK);
7567 return status;
7570 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7571 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7573 return NT_STATUS_OK;
7576 /****************************************************************************
7577 Reply to a lockingX request.
7578 ****************************************************************************/
7580 void reply_lockingX(struct smb_request *req)
7582 connection_struct *conn = req->conn;
7583 files_struct *fsp;
7584 unsigned char locktype;
7585 unsigned char oplocklevel;
7586 uint16 num_ulocks;
7587 uint16 num_locks;
7588 int32 lock_timeout;
7589 int i;
7590 const uint8_t *data;
7591 bool large_file_format;
7592 bool err;
7593 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7594 struct smbd_lock_element *ulocks;
7595 struct smbd_lock_element *locks;
7596 bool async = false;
7598 START_PROFILE(SMBlockingX);
7600 if (req->wct < 8) {
7601 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7602 END_PROFILE(SMBlockingX);
7603 return;
7606 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7607 locktype = CVAL(req->vwv+3, 0);
7608 oplocklevel = CVAL(req->vwv+3, 1);
7609 num_ulocks = SVAL(req->vwv+6, 0);
7610 num_locks = SVAL(req->vwv+7, 0);
7611 lock_timeout = IVAL(req->vwv+4, 0);
7612 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7614 if (!check_fsp(conn, req, fsp)) {
7615 END_PROFILE(SMBlockingX);
7616 return;
7619 data = req->buf;
7621 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7622 /* we don't support these - and CANCEL_LOCK makes w2k
7623 and XP reboot so I don't really want to be
7624 compatible! (tridge) */
7625 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7626 END_PROFILE(SMBlockingX);
7627 return;
7630 /* Check if this is an oplock break on a file
7631 we have granted an oplock on.
7633 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7634 /* Client can insist on breaking to none. */
7635 bool break_to_none = (oplocklevel == 0);
7636 bool result;
7638 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7639 "for fnum = %d\n", (unsigned int)oplocklevel,
7640 fsp->fnum ));
7643 * Make sure we have granted an exclusive or batch oplock on
7644 * this file.
7647 if (fsp->oplock_type == 0) {
7649 /* The Samba4 nbench simulator doesn't understand
7650 the difference between break to level2 and break
7651 to none from level2 - it sends oplock break
7652 replies in both cases. Don't keep logging an error
7653 message here - just ignore it. JRA. */
7655 DEBUG(5,("reply_lockingX: Error : oplock break from "
7656 "client for fnum = %d (oplock=%d) and no "
7657 "oplock granted on this file (%s).\n",
7658 fsp->fnum, fsp->oplock_type,
7659 fsp_str_dbg(fsp)));
7661 /* if this is a pure oplock break request then don't
7662 * send a reply */
7663 if (num_locks == 0 && num_ulocks == 0) {
7664 END_PROFILE(SMBlockingX);
7665 return;
7666 } else {
7667 END_PROFILE(SMBlockingX);
7668 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7669 return;
7673 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7674 (break_to_none)) {
7675 result = remove_oplock(fsp);
7676 } else {
7677 result = downgrade_oplock(fsp);
7680 if (!result) {
7681 DEBUG(0, ("reply_lockingX: error in removing "
7682 "oplock on file %s\n", fsp_str_dbg(fsp)));
7683 /* Hmmm. Is this panic justified? */
7684 smb_panic("internal tdb error");
7687 reply_to_oplock_break_requests(fsp);
7689 /* if this is a pure oplock break request then don't send a
7690 * reply */
7691 if (num_locks == 0 && num_ulocks == 0) {
7692 /* Sanity check - ensure a pure oplock break is not a
7693 chained request. */
7694 if(CVAL(req->vwv+0, 0) != 0xff)
7695 DEBUG(0,("reply_lockingX: Error : pure oplock "
7696 "break is a chained %d request !\n",
7697 (unsigned int)CVAL(req->vwv+0, 0)));
7698 END_PROFILE(SMBlockingX);
7699 return;
7703 if (req->buflen <
7704 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7705 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7706 END_PROFILE(SMBlockingX);
7707 return;
7710 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7711 if (ulocks == NULL) {
7712 reply_nterror(req, NT_STATUS_NO_MEMORY);
7713 END_PROFILE(SMBlockingX);
7714 return;
7717 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7718 if (locks == NULL) {
7719 reply_nterror(req, NT_STATUS_NO_MEMORY);
7720 END_PROFILE(SMBlockingX);
7721 return;
7724 /* Data now points at the beginning of the list
7725 of smb_unlkrng structs */
7726 for(i = 0; i < (int)num_ulocks; i++) {
7727 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7728 ulocks[i].count = get_lock_count(data, i, large_file_format);
7729 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7730 ulocks[i].brltype = UNLOCK_LOCK;
7733 * There is no error code marked "stupid client bug".... :-).
7735 if(err) {
7736 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7737 END_PROFILE(SMBlockingX);
7738 return;
7742 /* Now do any requested locks */
7743 data += ((large_file_format ? 20 : 10)*num_ulocks);
7745 /* Data now points at the beginning of the list
7746 of smb_lkrng structs */
7748 for(i = 0; i < (int)num_locks; i++) {
7749 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7750 locks[i].count = get_lock_count(data, i, large_file_format);
7751 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7753 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7754 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7755 locks[i].brltype = PENDING_READ_LOCK;
7756 } else {
7757 locks[i].brltype = READ_LOCK;
7759 } else {
7760 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7761 locks[i].brltype = PENDING_WRITE_LOCK;
7762 } else {
7763 locks[i].brltype = WRITE_LOCK;
7768 * There is no error code marked "stupid client bug".... :-).
7770 if(err) {
7771 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7772 END_PROFILE(SMBlockingX);
7773 return;
7777 status = smbd_do_locking(req, fsp,
7778 locktype, lock_timeout,
7779 num_ulocks, ulocks,
7780 num_locks, locks,
7781 &async);
7782 if (!NT_STATUS_IS_OK(status)) {
7783 END_PROFILE(SMBlockingX);
7784 reply_nterror(req, status);
7785 return;
7787 if (async) {
7788 END_PROFILE(SMBlockingX);
7789 return;
7792 reply_outbuf(req, 2, 0);
7793 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
7794 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
7796 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7797 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7799 END_PROFILE(SMBlockingX);
7802 #undef DBGC_CLASS
7803 #define DBGC_CLASS DBGC_ALL
7805 /****************************************************************************
7806 Reply to a SMBreadbmpx (read block multiplex) request.
7807 Always reply with an error, if someone has a platform really needs this,
7808 please contact vl@samba.org
7809 ****************************************************************************/
7811 void reply_readbmpx(struct smb_request *req)
7813 START_PROFILE(SMBreadBmpx);
7814 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7815 END_PROFILE(SMBreadBmpx);
7816 return;
7819 /****************************************************************************
7820 Reply to a SMBreadbs (read block multiplex secondary) request.
7821 Always reply with an error, if someone has a platform really needs this,
7822 please contact vl@samba.org
7823 ****************************************************************************/
7825 void reply_readbs(struct smb_request *req)
7827 START_PROFILE(SMBreadBs);
7828 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7829 END_PROFILE(SMBreadBs);
7830 return;
7833 /****************************************************************************
7834 Reply to a SMBsetattrE.
7835 ****************************************************************************/
7837 void reply_setattrE(struct smb_request *req)
7839 connection_struct *conn = req->conn;
7840 struct smb_file_time ft;
7841 files_struct *fsp;
7842 NTSTATUS status;
7844 START_PROFILE(SMBsetattrE);
7845 ZERO_STRUCT(ft);
7847 if (req->wct < 7) {
7848 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7849 goto out;
7852 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7854 if(!fsp || (fsp->conn != conn)) {
7855 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7856 goto out;
7860 * Convert the DOS times into unix times.
7863 ft.atime = convert_time_t_to_timespec(
7864 srv_make_unix_date2(req->vwv+3));
7865 ft.mtime = convert_time_t_to_timespec(
7866 srv_make_unix_date2(req->vwv+5));
7867 ft.create_time = convert_time_t_to_timespec(
7868 srv_make_unix_date2(req->vwv+1));
7870 reply_outbuf(req, 0, 0);
7873 * Patch from Ray Frush <frush@engr.colostate.edu>
7874 * Sometimes times are sent as zero - ignore them.
7877 /* Ensure we have a valid stat struct for the source. */
7878 status = vfs_stat_fsp(fsp);
7879 if (!NT_STATUS_IS_OK(status)) {
7880 reply_nterror(req, status);
7881 goto out;
7884 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
7885 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7886 goto out;
7889 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7890 if (!NT_STATUS_IS_OK(status)) {
7891 reply_nterror(req, status);
7892 goto out;
7895 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7896 " createtime=%u\n",
7897 fsp->fnum,
7898 (unsigned int)ft.atime.tv_sec,
7899 (unsigned int)ft.mtime.tv_sec,
7900 (unsigned int)ft.create_time.tv_sec
7902 out:
7903 END_PROFILE(SMBsetattrE);
7904 return;
7908 /* Back from the dead for OS/2..... JRA. */
7910 /****************************************************************************
7911 Reply to a SMBwritebmpx (write block multiplex primary) request.
7912 Always reply with an error, if someone has a platform really needs this,
7913 please contact vl@samba.org
7914 ****************************************************************************/
7916 void reply_writebmpx(struct smb_request *req)
7918 START_PROFILE(SMBwriteBmpx);
7919 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7920 END_PROFILE(SMBwriteBmpx);
7921 return;
7924 /****************************************************************************
7925 Reply to a SMBwritebs (write block multiplex secondary) request.
7926 Always reply with an error, if someone has a platform really needs this,
7927 please contact vl@samba.org
7928 ****************************************************************************/
7930 void reply_writebs(struct smb_request *req)
7932 START_PROFILE(SMBwriteBs);
7933 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7934 END_PROFILE(SMBwriteBs);
7935 return;
7938 /****************************************************************************
7939 Reply to a SMBgetattrE.
7940 ****************************************************************************/
7942 void reply_getattrE(struct smb_request *req)
7944 connection_struct *conn = req->conn;
7945 int mode;
7946 files_struct *fsp;
7947 struct timespec create_ts;
7949 START_PROFILE(SMBgetattrE);
7951 if (req->wct < 1) {
7952 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7953 END_PROFILE(SMBgetattrE);
7954 return;
7957 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7959 if(!fsp || (fsp->conn != conn)) {
7960 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7961 END_PROFILE(SMBgetattrE);
7962 return;
7965 /* Do an fstat on this file */
7966 if(fsp_stat(fsp)) {
7967 reply_nterror(req, map_nt_error_from_unix(errno));
7968 END_PROFILE(SMBgetattrE);
7969 return;
7972 mode = dos_mode(conn, fsp->fsp_name);
7975 * Convert the times into dos times. Set create
7976 * date to be last modify date as UNIX doesn't save
7977 * this.
7980 reply_outbuf(req, 11, 0);
7982 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7983 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7984 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7985 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7986 /* Should we check pending modtime here ? JRA */
7987 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7988 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7990 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
7991 SIVAL(req->outbuf, smb_vwv6, 0);
7992 SIVAL(req->outbuf, smb_vwv8, 0);
7993 } else {
7994 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7995 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
7996 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7998 SSVAL(req->outbuf,smb_vwv10, mode);
8000 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8002 END_PROFILE(SMBgetattrE);
8003 return;