s3-torture/denytest.c: replace cli_read_old() with cli_read()
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blobe740fb4c570e69ac3254d24a954d0640eb6bc3e3
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 "rpc_client/cli_spoolss.h"
36 #include "rpc_client/init_spoolss.h"
37 #include "rpc_server/rpc_ncacn_np.h"
38 #include "libcli/security/security.h"
39 #include "libsmb/nmblib.h"
40 #include "auth.h"
41 #include "smbprofile.h"
42 #include "../lib/tsocket/tsocket.h"
44 /****************************************************************************
45 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
46 path or anything including wildcards.
47 We're assuming here that '/' is not the second byte in any multibyte char
48 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
49 set.
50 ****************************************************************************/
52 /* Custom version for processing POSIX paths. */
53 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
55 static NTSTATUS check_path_syntax_internal(char *path,
56 bool posix_path,
57 bool *p_last_component_contains_wcard)
59 char *d = path;
60 const char *s = path;
61 NTSTATUS ret = NT_STATUS_OK;
62 bool start_of_name_component = True;
63 bool stream_started = false;
65 *p_last_component_contains_wcard = False;
67 while (*s) {
68 if (stream_started) {
69 switch (*s) {
70 case '/':
71 case '\\':
72 return NT_STATUS_OBJECT_NAME_INVALID;
73 case ':':
74 if (s[1] == '\0') {
75 return NT_STATUS_OBJECT_NAME_INVALID;
77 if (strchr_m(&s[1], ':')) {
78 return NT_STATUS_OBJECT_NAME_INVALID;
80 break;
84 if ((*s == ':') && !posix_path && !stream_started) {
85 if (*p_last_component_contains_wcard) {
86 return NT_STATUS_OBJECT_NAME_INVALID;
88 /* Stream names allow more characters than file names.
89 We're overloading posix_path here to allow a wider
90 range of characters. If stream_started is true this
91 is still a Windows path even if posix_path is true.
92 JRA.
94 stream_started = true;
95 start_of_name_component = false;
96 posix_path = true;
98 if (s[1] == '\0') {
99 return NT_STATUS_OBJECT_NAME_INVALID;
103 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
105 * Safe to assume is not the second part of a mb char
106 * as this is handled below.
108 /* Eat multiple '/' or '\\' */
109 while (IS_PATH_SEP(*s,posix_path)) {
110 s++;
112 if ((d != path) && (*s != '\0')) {
113 /* We only care about non-leading or trailing '/' or '\\' */
114 *d++ = '/';
117 start_of_name_component = True;
118 /* New component. */
119 *p_last_component_contains_wcard = False;
120 continue;
123 if (start_of_name_component) {
124 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
125 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
128 * No mb char starts with '.' so we're safe checking the directory separator here.
131 /* If we just added a '/' - delete it */
132 if ((d > path) && (*(d-1) == '/')) {
133 *(d-1) = '\0';
134 d--;
137 /* Are we at the start ? Can't go back further if so. */
138 if (d <= path) {
139 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
140 break;
142 /* Go back one level... */
143 /* We know this is safe as '/' cannot be part of a mb sequence. */
144 /* NOTE - if this assumption is invalid we are not in good shape... */
145 /* Decrement d first as d points to the *next* char to write into. */
146 for (d--; d > path; d--) {
147 if (*d == '/')
148 break;
150 s += 2; /* Else go past the .. */
151 /* We're still at the start of a name component, just the previous one. */
152 continue;
154 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
155 if (posix_path) {
156 /* Eat the '.' */
157 s++;
158 continue;
164 if (!(*s & 0x80)) {
165 if (!posix_path) {
166 if (*s <= 0x1f || *s == '|') {
167 return NT_STATUS_OBJECT_NAME_INVALID;
169 switch (*s) {
170 case '*':
171 case '?':
172 case '<':
173 case '>':
174 case '"':
175 *p_last_component_contains_wcard = True;
176 break;
177 default:
178 break;
181 *d++ = *s++;
182 } else {
183 size_t siz;
184 /* Get the size of the next MB character. */
185 next_codepoint(s,&siz);
186 switch(siz) {
187 case 5:
188 *d++ = *s++;
189 /*fall through*/
190 case 4:
191 *d++ = *s++;
192 /*fall through*/
193 case 3:
194 *d++ = *s++;
195 /*fall through*/
196 case 2:
197 *d++ = *s++;
198 /*fall through*/
199 case 1:
200 *d++ = *s++;
201 break;
202 default:
203 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
204 *d = '\0';
205 return NT_STATUS_INVALID_PARAMETER;
208 start_of_name_component = False;
211 *d = '\0';
213 return ret;
216 /****************************************************************************
217 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
218 No wildcards allowed.
219 ****************************************************************************/
221 NTSTATUS check_path_syntax(char *path)
223 bool ignore;
224 return check_path_syntax_internal(path, False, &ignore);
227 /****************************************************************************
228 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
229 Wildcards allowed - p_contains_wcard returns true if the last component contained
230 a wildcard.
231 ****************************************************************************/
233 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
235 return check_path_syntax_internal(path, False, p_contains_wcard);
238 /****************************************************************************
239 Check the path for a POSIX client.
240 We're assuming here that '/' is not the second byte in any multibyte char
241 set (a safe assumption).
242 ****************************************************************************/
244 NTSTATUS check_path_syntax_posix(char *path)
246 bool ignore;
247 return check_path_syntax_internal(path, True, &ignore);
250 /****************************************************************************
251 Pull a string and check the path allowing a wilcard - provide for error return.
252 ****************************************************************************/
254 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
255 const char *base_ptr,
256 uint16 smb_flags2,
257 char **pp_dest,
258 const char *src,
259 size_t src_len,
260 int flags,
261 NTSTATUS *err,
262 bool *contains_wcard)
264 size_t ret;
266 *pp_dest = NULL;
268 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
269 src_len, flags);
271 if (!*pp_dest) {
272 *err = NT_STATUS_INVALID_PARAMETER;
273 return ret;
276 *contains_wcard = False;
278 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
280 * For a DFS path the function parse_dfs_path()
281 * will do the path processing, just make a copy.
283 *err = NT_STATUS_OK;
284 return ret;
287 if (lp_posix_pathnames()) {
288 *err = check_path_syntax_posix(*pp_dest);
289 } else {
290 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
293 return ret;
296 /****************************************************************************
297 Pull a string and check the path - provide for error return.
298 ****************************************************************************/
300 size_t srvstr_get_path(TALLOC_CTX *ctx,
301 const char *base_ptr,
302 uint16 smb_flags2,
303 char **pp_dest,
304 const char *src,
305 size_t src_len,
306 int flags,
307 NTSTATUS *err)
309 bool ignore;
310 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
311 src_len, flags, err, &ignore);
314 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
315 char **pp_dest, const char *src, int flags,
316 NTSTATUS *err, bool *contains_wcard)
318 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
319 pp_dest, src, smbreq_bufrem(req, src),
320 flags, err, contains_wcard);
323 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
324 char **pp_dest, const char *src, int flags,
325 NTSTATUS *err)
327 bool ignore;
328 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
329 flags, err, &ignore);
332 /****************************************************************************
333 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
334 ****************************************************************************/
336 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
337 files_struct *fsp)
339 if ((fsp == NULL) || (conn == NULL)) {
340 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
341 return False;
343 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
344 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
345 return False;
347 return True;
350 /****************************************************************************
351 Check if we have a correct fsp pointing to a file.
352 ****************************************************************************/
354 bool check_fsp(connection_struct *conn, struct smb_request *req,
355 files_struct *fsp)
357 if (!check_fsp_open(conn, req, fsp)) {
358 return False;
360 if (fsp->is_directory) {
361 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
362 return False;
364 if (fsp->fh->fd == -1) {
365 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
366 return False;
368 fsp->num_smb_operations++;
369 return True;
372 /****************************************************************************
373 Check if we have a correct fsp pointing to a quota fake file. Replacement for
374 the CHECK_NTQUOTA_HANDLE_OK macro.
375 ****************************************************************************/
377 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
378 files_struct *fsp)
380 if (!check_fsp_open(conn, req, fsp)) {
381 return false;
384 if (fsp->is_directory) {
385 return false;
388 if (fsp->fake_file_handle == NULL) {
389 return false;
392 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
393 return false;
396 if (fsp->fake_file_handle->private_data == NULL) {
397 return false;
400 return true;
403 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
404 const char *name, int name_type)
406 char *trim_name;
407 char *trim_name_type;
408 const char *retarget_parm;
409 char *retarget;
410 char *p;
411 int retarget_type = 0x20;
412 int retarget_port = 139;
413 struct sockaddr_storage retarget_addr;
414 struct sockaddr_in *in_addr;
415 bool ret = false;
416 uint8_t outbuf[10];
418 if (get_socket_port(sconn->sock) != 139) {
419 return false;
422 trim_name = talloc_strdup(talloc_tos(), name);
423 if (trim_name == NULL) {
424 goto fail;
426 trim_char(trim_name, ' ', ' ');
428 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
429 name_type);
430 if (trim_name_type == NULL) {
431 goto fail;
434 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
435 trim_name_type, NULL);
436 if (retarget_parm == NULL) {
437 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
438 trim_name, NULL);
440 if (retarget_parm == NULL) {
441 goto fail;
444 retarget = talloc_strdup(trim_name, retarget_parm);
445 if (retarget == NULL) {
446 goto fail;
449 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
451 p = strchr(retarget, ':');
452 if (p != NULL) {
453 *p++ = '\0';
454 retarget_port = atoi(p);
457 p = strchr_m(retarget, '#');
458 if (p != NULL) {
459 *p++ = '\0';
460 if (sscanf(p, "%x", &retarget_type) != 1) {
461 goto fail;
465 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
466 if (!ret) {
467 DEBUG(10, ("could not resolve %s\n", retarget));
468 goto fail;
471 if (retarget_addr.ss_family != AF_INET) {
472 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
473 goto fail;
476 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
478 _smb_setlen(outbuf, 6);
479 SCVAL(outbuf, 0, 0x84);
480 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
481 *(uint16_t *)(outbuf+8) = htons(retarget_port);
483 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
484 NULL)) {
485 exit_server_cleanly("netbios_session_regarget: srv_send_smb "
486 "failed.");
489 ret = true;
490 fail:
491 TALLOC_FREE(trim_name);
492 return ret;
495 static void reply_called_name_not_present(char *outbuf)
497 smb_setlen(outbuf, 1);
498 SCVAL(outbuf, 0, 0x83);
499 SCVAL(outbuf, 4, 0x82);
502 /****************************************************************************
503 Reply to a (netbios-level) special message.
504 ****************************************************************************/
506 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
508 int msg_type = CVAL(inbuf,0);
509 int msg_flags = CVAL(inbuf,1);
511 * We only really use 4 bytes of the outbuf, but for the smb_setlen
512 * calculation & friends (srv_send_smb uses that) we need the full smb
513 * header.
515 char outbuf[smb_size];
517 memset(outbuf, '\0', sizeof(outbuf));
519 smb_setlen(outbuf,0);
521 switch (msg_type) {
522 case NBSSrequest: /* session request */
524 /* inbuf_size is guarenteed to be at least 4. */
525 fstring name1,name2;
526 int name_type1, name_type2;
527 int name_len1, name_len2;
529 *name1 = *name2 = 0;
531 if (sconn->nbt.got_session) {
532 exit_server_cleanly("multiple session request not permitted");
535 SCVAL(outbuf,0,NBSSpositive);
536 SCVAL(outbuf,3,0);
538 /* inbuf_size is guaranteed to be at least 4. */
539 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
540 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
541 DEBUG(0,("Invalid name length in session request\n"));
542 reply_called_name_not_present(outbuf);
543 break;
545 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
546 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
547 DEBUG(0,("Invalid name length in session request\n"));
548 reply_called_name_not_present(outbuf);
549 break;
552 name_type1 = name_extract((unsigned char *)inbuf,
553 inbuf_size,(unsigned int)4,name1);
554 name_type2 = name_extract((unsigned char *)inbuf,
555 inbuf_size,(unsigned int)(4 + name_len1),name2);
557 if (name_type1 == -1 || name_type2 == -1) {
558 DEBUG(0,("Invalid name type in session request\n"));
559 reply_called_name_not_present(outbuf);
560 break;
563 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
564 name1, name_type1, name2, name_type2));
566 if (netbios_session_retarget(sconn, name1, name_type1)) {
567 exit_server_cleanly("retargeted client");
571 * Windows NT/2k uses "*SMBSERVER" and XP uses
572 * "*SMBSERV" arrggg!!!
574 if (strequal(name1, "*SMBSERVER ")
575 || strequal(name1, "*SMBSERV ")) {
576 char *raddr;
578 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
579 talloc_tos());
580 if (raddr == NULL) {
581 exit_server_cleanly("could not allocate raddr");
584 fstrcpy(name1, raddr);
587 set_local_machine_name(name1, True);
588 set_remote_machine_name(name2, True);
590 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
591 get_local_machine_name(), get_remote_machine_name(),
592 name_type2));
594 if (name_type2 == 'R') {
595 /* We are being asked for a pathworks session ---
596 no thanks! */
597 reply_called_name_not_present(outbuf);
598 break;
601 /* only add the client's machine name to the list
602 of possibly valid usernames if we are operating
603 in share mode security */
604 if (lp_security() == SEC_SHARE) {
605 add_session_user(sconn, get_remote_machine_name());
608 reload_services(sconn->msg_ctx, sconn->sock, True);
609 reopen_logs();
611 sconn->nbt.got_session = true;
612 break;
615 case 0x89: /* session keepalive request
616 (some old clients produce this?) */
617 SCVAL(outbuf,0,NBSSkeepalive);
618 SCVAL(outbuf,3,0);
619 break;
621 case NBSSpositive: /* positive session response */
622 case NBSSnegative: /* negative session response */
623 case NBSSretarget: /* retarget session response */
624 DEBUG(0,("Unexpected session response\n"));
625 break;
627 case NBSSkeepalive: /* session keepalive */
628 default:
629 return;
632 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
633 msg_type, msg_flags));
635 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
637 if (CVAL(outbuf, 0) != 0x82) {
638 exit_server_cleanly("invalid netbios session");
640 return;
643 /****************************************************************************
644 Reply to a tcon.
645 conn POINTER CAN BE NULL HERE !
646 ****************************************************************************/
648 void reply_tcon(struct smb_request *req)
650 connection_struct *conn = req->conn;
651 const char *service;
652 char *service_buf = NULL;
653 char *password = NULL;
654 char *dev = NULL;
655 int pwlen=0;
656 NTSTATUS nt_status;
657 const char *p;
658 DATA_BLOB password_blob;
659 TALLOC_CTX *ctx = talloc_tos();
660 struct smbd_server_connection *sconn = req->sconn;
662 START_PROFILE(SMBtcon);
664 if (req->buflen < 4) {
665 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
666 END_PROFILE(SMBtcon);
667 return;
670 p = (const char *)req->buf + 1;
671 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
672 p += 1;
673 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
674 p += pwlen+1;
675 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
676 p += 1;
678 if (service_buf == NULL || password == NULL || dev == NULL) {
679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
680 END_PROFILE(SMBtcon);
681 return;
683 p = strrchr_m(service_buf,'\\');
684 if (p) {
685 service = p+1;
686 } else {
687 service = service_buf;
690 password_blob = data_blob(password, pwlen+1);
692 conn = make_connection(sconn,service,password_blob,dev,
693 req->vuid,&nt_status);
694 req->conn = conn;
696 data_blob_clear_free(&password_blob);
698 if (!conn) {
699 reply_nterror(req, nt_status);
700 END_PROFILE(SMBtcon);
701 return;
704 reply_outbuf(req, 2, 0);
705 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
706 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
707 SSVAL(req->outbuf,smb_tid,conn->cnum);
709 DEBUG(3,("tcon service=%s cnum=%d\n",
710 service, conn->cnum));
712 END_PROFILE(SMBtcon);
713 return;
716 /****************************************************************************
717 Reply to a tcon and X.
718 conn POINTER CAN BE NULL HERE !
719 ****************************************************************************/
721 void reply_tcon_and_X(struct smb_request *req)
723 connection_struct *conn = req->conn;
724 const char *service = NULL;
725 DATA_BLOB password;
726 TALLOC_CTX *ctx = talloc_tos();
727 /* what the cleint thinks the device is */
728 char *client_devicetype = NULL;
729 /* what the server tells the client the share represents */
730 const char *server_devicetype;
731 NTSTATUS nt_status;
732 int passlen;
733 char *path = NULL;
734 const char *p, *q;
735 uint16 tcon_flags;
736 struct smbd_server_connection *sconn = req->sconn;
738 START_PROFILE(SMBtconX);
740 if (req->wct < 4) {
741 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
742 END_PROFILE(SMBtconX);
743 return;
746 passlen = SVAL(req->vwv+3, 0);
747 tcon_flags = SVAL(req->vwv+2, 0);
749 /* we might have to close an old one */
750 if ((tcon_flags & 0x1) && conn) {
751 close_cnum(conn,req->vuid);
752 req->conn = NULL;
753 conn = NULL;
756 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
757 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
758 END_PROFILE(SMBtconX);
759 return;
762 if (sconn->smb1.negprot.encrypted_passwords) {
763 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
764 if (lp_security() == SEC_SHARE) {
766 * Security = share always has a pad byte
767 * after the password.
769 p = (const char *)req->buf + passlen + 1;
770 } else {
771 p = (const char *)req->buf + passlen;
773 } else {
774 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
775 /* Ensure correct termination */
776 password.data[passlen]=0;
777 p = (const char *)req->buf + passlen + 1;
780 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
782 if (path == NULL) {
783 data_blob_clear_free(&password);
784 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
785 END_PROFILE(SMBtconX);
786 return;
790 * the service name can be either: \\server\share
791 * or share directly like on the DELL PowerVault 705
793 if (*path=='\\') {
794 q = strchr_m(path+2,'\\');
795 if (!q) {
796 data_blob_clear_free(&password);
797 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
798 END_PROFILE(SMBtconX);
799 return;
801 service = q+1;
802 } else {
803 service = path;
806 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
807 &client_devicetype, p,
808 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
810 if (client_devicetype == NULL) {
811 data_blob_clear_free(&password);
812 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
813 END_PROFILE(SMBtconX);
814 return;
817 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
819 conn = make_connection(sconn, service, password, client_devicetype,
820 req->vuid, &nt_status);
821 req->conn =conn;
823 data_blob_clear_free(&password);
825 if (!conn) {
826 reply_nterror(req, nt_status);
827 END_PROFILE(SMBtconX);
828 return;
831 if ( IS_IPC(conn) )
832 server_devicetype = "IPC";
833 else if ( IS_PRINT(conn) )
834 server_devicetype = "LPT1:";
835 else
836 server_devicetype = "A:";
838 if (get_Protocol() < PROTOCOL_NT1) {
839 reply_outbuf(req, 2, 0);
840 if (message_push_string(&req->outbuf, server_devicetype,
841 STR_TERMINATE|STR_ASCII) == -1) {
842 reply_nterror(req, NT_STATUS_NO_MEMORY);
843 END_PROFILE(SMBtconX);
844 return;
846 } else {
847 /* NT sets the fstype of IPC$ to the null string */
848 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
850 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
851 /* Return permissions. */
852 uint32 perm1 = 0;
853 uint32 perm2 = 0;
855 reply_outbuf(req, 7, 0);
857 if (IS_IPC(conn)) {
858 perm1 = FILE_ALL_ACCESS;
859 perm2 = FILE_ALL_ACCESS;
860 } else {
861 perm1 = conn->share_access;
864 SIVAL(req->outbuf, smb_vwv3, perm1);
865 SIVAL(req->outbuf, smb_vwv5, perm2);
866 } else {
867 reply_outbuf(req, 3, 0);
870 if ((message_push_string(&req->outbuf, server_devicetype,
871 STR_TERMINATE|STR_ASCII) == -1)
872 || (message_push_string(&req->outbuf, fstype,
873 STR_TERMINATE) == -1)) {
874 reply_nterror(req, NT_STATUS_NO_MEMORY);
875 END_PROFILE(SMBtconX);
876 return;
879 /* what does setting this bit do? It is set by NT4 and
880 may affect the ability to autorun mounted cdroms */
881 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
882 (lp_csc_policy(SNUM(conn)) << 2));
884 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
885 DEBUG(2,("Serving %s as a Dfs root\n",
886 lp_servicename(SNUM(conn)) ));
887 SSVAL(req->outbuf, smb_vwv2,
888 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
893 DEBUG(3,("tconX service=%s \n",
894 service));
896 /* set the incoming and outgoing tid to the just created one */
897 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
898 SSVAL(req->outbuf,smb_tid,conn->cnum);
900 END_PROFILE(SMBtconX);
902 req->tid = conn->cnum;
903 chain_reply(req);
904 return;
907 /****************************************************************************
908 Reply to an unknown type.
909 ****************************************************************************/
911 void reply_unknown_new(struct smb_request *req, uint8 type)
913 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
914 smb_fn_name(type), type, type));
915 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
916 return;
919 /****************************************************************************
920 Reply to an ioctl.
921 conn POINTER CAN BE NULL HERE !
922 ****************************************************************************/
924 void reply_ioctl(struct smb_request *req)
926 connection_struct *conn = req->conn;
927 uint16 device;
928 uint16 function;
929 uint32 ioctl_code;
930 int replysize;
931 char *p;
933 START_PROFILE(SMBioctl);
935 if (req->wct < 3) {
936 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
937 END_PROFILE(SMBioctl);
938 return;
941 device = SVAL(req->vwv+1, 0);
942 function = SVAL(req->vwv+2, 0);
943 ioctl_code = (device << 16) + function;
945 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
947 switch (ioctl_code) {
948 case IOCTL_QUERY_JOB_INFO:
949 replysize = 32;
950 break;
951 default:
952 reply_force_doserror(req, ERRSRV, ERRnosupport);
953 END_PROFILE(SMBioctl);
954 return;
957 reply_outbuf(req, 8, replysize+1);
958 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
959 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
960 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
961 p = smb_buf(req->outbuf);
962 memset(p, '\0', replysize+1); /* valgrind-safe. */
963 p += 1; /* Allow for alignment */
965 switch (ioctl_code) {
966 case IOCTL_QUERY_JOB_INFO:
968 files_struct *fsp = file_fsp(
969 req, SVAL(req->vwv+0, 0));
970 if (!fsp) {
971 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
972 END_PROFILE(SMBioctl);
973 return;
975 /* Job number */
976 if (fsp->print_file) {
977 SSVAL(p, 0, fsp->print_file->rap_jobid);
978 } else {
979 SSVAL(p, 0, 0);
981 srvstr_push((char *)req->outbuf, req->flags2, p+2,
982 lp_netbios_name(), 15,
983 STR_TERMINATE|STR_ASCII);
984 if (conn) {
985 srvstr_push((char *)req->outbuf, req->flags2,
986 p+18, lp_servicename(SNUM(conn)),
987 13, STR_TERMINATE|STR_ASCII);
988 } else {
989 memset(p+18, 0, 13);
991 break;
995 END_PROFILE(SMBioctl);
996 return;
999 /****************************************************************************
1000 Strange checkpath NTSTATUS mapping.
1001 ****************************************************************************/
1003 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1005 /* Strange DOS error code semantics only for checkpath... */
1006 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1007 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1008 /* We need to map to ERRbadpath */
1009 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1012 return status;
1015 /****************************************************************************
1016 Reply to a checkpath.
1017 ****************************************************************************/
1019 void reply_checkpath(struct smb_request *req)
1021 connection_struct *conn = req->conn;
1022 struct smb_filename *smb_fname = NULL;
1023 char *name = NULL;
1024 NTSTATUS status;
1025 TALLOC_CTX *ctx = talloc_tos();
1027 START_PROFILE(SMBcheckpath);
1029 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1030 STR_TERMINATE, &status);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 status = map_checkpath_error(req->flags2, status);
1034 reply_nterror(req, status);
1035 END_PROFILE(SMBcheckpath);
1036 return;
1039 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1041 status = filename_convert(ctx,
1042 conn,
1043 req->flags2 & FLAGS2_DFS_PATHNAMES,
1044 name,
1046 NULL,
1047 &smb_fname);
1049 if (!NT_STATUS_IS_OK(status)) {
1050 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1051 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1052 ERRSRV, ERRbadpath);
1053 END_PROFILE(SMBcheckpath);
1054 return;
1056 goto path_err;
1059 if (!VALID_STAT(smb_fname->st) &&
1060 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1061 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1062 smb_fname_str_dbg(smb_fname), strerror(errno)));
1063 status = map_nt_error_from_unix(errno);
1064 goto path_err;
1067 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1068 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1069 ERRDOS, ERRbadpath);
1070 goto out;
1073 reply_outbuf(req, 0, 0);
1075 path_err:
1076 /* We special case this - as when a Windows machine
1077 is parsing a path is steps through the components
1078 one at a time - if a component fails it expects
1079 ERRbadpath, not ERRbadfile.
1081 status = map_checkpath_error(req->flags2, status);
1082 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1084 * Windows returns different error codes if
1085 * the parent directory is valid but not the
1086 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1087 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1088 * if the path is invalid.
1090 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1091 ERRDOS, ERRbadpath);
1092 goto out;
1095 reply_nterror(req, status);
1097 out:
1098 TALLOC_FREE(smb_fname);
1099 END_PROFILE(SMBcheckpath);
1100 return;
1103 /****************************************************************************
1104 Reply to a getatr.
1105 ****************************************************************************/
1107 void reply_getatr(struct smb_request *req)
1109 connection_struct *conn = req->conn;
1110 struct smb_filename *smb_fname = NULL;
1111 char *fname = NULL;
1112 int mode=0;
1113 SMB_OFF_T size=0;
1114 time_t mtime=0;
1115 const char *p;
1116 NTSTATUS status;
1117 TALLOC_CTX *ctx = talloc_tos();
1118 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1120 START_PROFILE(SMBgetatr);
1122 p = (const char *)req->buf + 1;
1123 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1124 if (!NT_STATUS_IS_OK(status)) {
1125 reply_nterror(req, status);
1126 goto out;
1129 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1130 under WfWg - weird! */
1131 if (*fname == '\0') {
1132 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1133 if (!CAN_WRITE(conn)) {
1134 mode |= FILE_ATTRIBUTE_READONLY;
1136 size = 0;
1137 mtime = 0;
1138 } else {
1139 status = filename_convert(ctx,
1140 conn,
1141 req->flags2 & FLAGS2_DFS_PATHNAMES,
1142 fname,
1144 NULL,
1145 &smb_fname);
1146 if (!NT_STATUS_IS_OK(status)) {
1147 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1148 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1149 ERRSRV, ERRbadpath);
1150 goto out;
1152 reply_nterror(req, status);
1153 goto out;
1155 if (!VALID_STAT(smb_fname->st) &&
1156 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1157 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1158 smb_fname_str_dbg(smb_fname),
1159 strerror(errno)));
1160 reply_nterror(req, map_nt_error_from_unix(errno));
1161 goto out;
1164 mode = dos_mode(conn, smb_fname);
1165 size = smb_fname->st.st_ex_size;
1167 if (ask_sharemode) {
1168 struct timespec write_time_ts;
1169 struct file_id fileid;
1171 ZERO_STRUCT(write_time_ts);
1172 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1173 get_file_infos(fileid, 0, NULL, &write_time_ts);
1174 if (!null_timespec(write_time_ts)) {
1175 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1179 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1180 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1181 size = 0;
1185 reply_outbuf(req, 10, 0);
1187 SSVAL(req->outbuf,smb_vwv0,mode);
1188 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1189 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1190 } else {
1191 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1193 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1195 if (get_Protocol() >= PROTOCOL_NT1) {
1196 SSVAL(req->outbuf, smb_flg2,
1197 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1200 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1201 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1203 out:
1204 TALLOC_FREE(smb_fname);
1205 TALLOC_FREE(fname);
1206 END_PROFILE(SMBgetatr);
1207 return;
1210 /****************************************************************************
1211 Reply to a setatr.
1212 ****************************************************************************/
1214 void reply_setatr(struct smb_request *req)
1216 struct smb_file_time ft;
1217 connection_struct *conn = req->conn;
1218 struct smb_filename *smb_fname = NULL;
1219 char *fname = NULL;
1220 int mode;
1221 time_t mtime;
1222 const char *p;
1223 NTSTATUS status;
1224 TALLOC_CTX *ctx = talloc_tos();
1226 START_PROFILE(SMBsetatr);
1228 ZERO_STRUCT(ft);
1230 if (req->wct < 2) {
1231 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1232 goto out;
1235 p = (const char *)req->buf + 1;
1236 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 reply_nterror(req, status);
1239 goto out;
1242 status = filename_convert(ctx,
1243 conn,
1244 req->flags2 & FLAGS2_DFS_PATHNAMES,
1245 fname,
1247 NULL,
1248 &smb_fname);
1249 if (!NT_STATUS_IS_OK(status)) {
1250 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1251 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1252 ERRSRV, ERRbadpath);
1253 goto out;
1255 reply_nterror(req, status);
1256 goto out;
1259 if (smb_fname->base_name[0] == '.' &&
1260 smb_fname->base_name[1] == '\0') {
1262 * Not sure here is the right place to catch this
1263 * condition. Might be moved to somewhere else later -- vl
1265 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1266 goto out;
1269 mode = SVAL(req->vwv+0, 0);
1270 mtime = srv_make_unix_date3(req->vwv+1);
1272 ft.mtime = convert_time_t_to_timespec(mtime);
1273 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 reply_nterror(req, status);
1276 goto out;
1279 if (mode != FILE_ATTRIBUTE_NORMAL) {
1280 if (VALID_STAT_OF_DIR(smb_fname->st))
1281 mode |= FILE_ATTRIBUTE_DIRECTORY;
1282 else
1283 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1285 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1286 false) != 0) {
1287 reply_nterror(req, map_nt_error_from_unix(errno));
1288 goto out;
1292 reply_outbuf(req, 0, 0);
1294 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1295 mode));
1296 out:
1297 TALLOC_FREE(smb_fname);
1298 END_PROFILE(SMBsetatr);
1299 return;
1302 /****************************************************************************
1303 Reply to a dskattr.
1304 ****************************************************************************/
1306 void reply_dskattr(struct smb_request *req)
1308 connection_struct *conn = req->conn;
1309 uint64_t dfree,dsize,bsize;
1310 START_PROFILE(SMBdskattr);
1312 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1313 reply_nterror(req, map_nt_error_from_unix(errno));
1314 END_PROFILE(SMBdskattr);
1315 return;
1318 reply_outbuf(req, 5, 0);
1320 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1321 double total_space, free_space;
1322 /* we need to scale this to a number that DOS6 can handle. We
1323 use floating point so we can handle large drives on systems
1324 that don't have 64 bit integers
1326 we end up displaying a maximum of 2G to DOS systems
1328 total_space = dsize * (double)bsize;
1329 free_space = dfree * (double)bsize;
1331 dsize = (uint64_t)((total_space+63*512) / (64*512));
1332 dfree = (uint64_t)((free_space+63*512) / (64*512));
1334 if (dsize > 0xFFFF) dsize = 0xFFFF;
1335 if (dfree > 0xFFFF) dfree = 0xFFFF;
1337 SSVAL(req->outbuf,smb_vwv0,dsize);
1338 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1339 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1340 SSVAL(req->outbuf,smb_vwv3,dfree);
1341 } else {
1342 SSVAL(req->outbuf,smb_vwv0,dsize);
1343 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1344 SSVAL(req->outbuf,smb_vwv2,512);
1345 SSVAL(req->outbuf,smb_vwv3,dfree);
1348 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1350 END_PROFILE(SMBdskattr);
1351 return;
1355 * Utility function to split the filename from the directory.
1357 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1358 char **fname_dir_out,
1359 char **fname_mask_out)
1361 const char *p = NULL;
1362 char *fname_dir = NULL;
1363 char *fname_mask = NULL;
1365 p = strrchr_m(fname_in, '/');
1366 if (!p) {
1367 fname_dir = talloc_strdup(ctx, ".");
1368 fname_mask = talloc_strdup(ctx, fname_in);
1369 } else {
1370 fname_dir = talloc_strndup(ctx, fname_in,
1371 PTR_DIFF(p, fname_in));
1372 fname_mask = talloc_strdup(ctx, p+1);
1375 if (!fname_dir || !fname_mask) {
1376 TALLOC_FREE(fname_dir);
1377 TALLOC_FREE(fname_mask);
1378 return NT_STATUS_NO_MEMORY;
1381 *fname_dir_out = fname_dir;
1382 *fname_mask_out = fname_mask;
1383 return NT_STATUS_OK;
1386 /****************************************************************************
1387 Reply to a search.
1388 Can be called from SMBsearch, SMBffirst or SMBfunique.
1389 ****************************************************************************/
1391 void reply_search(struct smb_request *req)
1393 connection_struct *conn = req->conn;
1394 char *path = NULL;
1395 const char *mask = NULL;
1396 char *directory = NULL;
1397 struct smb_filename *smb_fname = NULL;
1398 char *fname = NULL;
1399 SMB_OFF_T size;
1400 uint32 mode;
1401 struct timespec date;
1402 uint32 dirtype;
1403 unsigned int numentries = 0;
1404 unsigned int maxentries = 0;
1405 bool finished = False;
1406 const char *p;
1407 int status_len;
1408 char status[21];
1409 int dptr_num= -1;
1410 bool check_descend = False;
1411 bool expect_close = False;
1412 NTSTATUS nt_status;
1413 bool mask_contains_wcard = False;
1414 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1415 TALLOC_CTX *ctx = talloc_tos();
1416 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1417 struct dptr_struct *dirptr = NULL;
1418 struct smbd_server_connection *sconn = req->sconn;
1420 START_PROFILE(SMBsearch);
1422 if (req->wct < 2) {
1423 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1424 goto out;
1427 if (lp_posix_pathnames()) {
1428 reply_unknown_new(req, req->cmd);
1429 goto out;
1432 /* If we were called as SMBffirst then we must expect close. */
1433 if(req->cmd == SMBffirst) {
1434 expect_close = True;
1437 reply_outbuf(req, 1, 3);
1438 maxentries = SVAL(req->vwv+0, 0);
1439 dirtype = SVAL(req->vwv+1, 0);
1440 p = (const char *)req->buf + 1;
1441 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1442 &nt_status, &mask_contains_wcard);
1443 if (!NT_STATUS_IS_OK(nt_status)) {
1444 reply_nterror(req, nt_status);
1445 goto out;
1448 p++;
1449 status_len = SVAL(p, 0);
1450 p += 2;
1452 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1454 if (status_len == 0) {
1455 nt_status = filename_convert(ctx, conn,
1456 req->flags2 & FLAGS2_DFS_PATHNAMES,
1457 path,
1458 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1459 &mask_contains_wcard,
1460 &smb_fname);
1461 if (!NT_STATUS_IS_OK(nt_status)) {
1462 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1463 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1464 ERRSRV, ERRbadpath);
1465 goto out;
1467 reply_nterror(req, nt_status);
1468 goto out;
1471 directory = smb_fname->base_name;
1473 p = strrchr_m(directory,'/');
1474 if ((p != NULL) && (*directory != '/')) {
1475 mask = p + 1;
1476 directory = talloc_strndup(ctx, directory,
1477 PTR_DIFF(p, directory));
1478 } else {
1479 mask = directory;
1480 directory = talloc_strdup(ctx,".");
1483 if (!directory) {
1484 reply_nterror(req, NT_STATUS_NO_MEMORY);
1485 goto out;
1488 memset((char *)status,'\0',21);
1489 SCVAL(status,0,(dirtype & 0x1F));
1491 nt_status = dptr_create(conn,
1492 NULL, /* fsp */
1493 directory,
1494 True,
1495 expect_close,
1496 req->smbpid,
1497 mask,
1498 mask_contains_wcard,
1499 dirtype,
1500 &dirptr);
1501 if (!NT_STATUS_IS_OK(nt_status)) {
1502 reply_nterror(req, nt_status);
1503 goto out;
1505 dptr_num = dptr_dnum(dirptr);
1506 } else {
1507 int status_dirtype;
1508 const char *dirpath;
1510 memcpy(status,p,21);
1511 status_dirtype = CVAL(status,0) & 0x1F;
1512 if (status_dirtype != (dirtype & 0x1F)) {
1513 dirtype = status_dirtype;
1516 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1517 if (!dirptr) {
1518 goto SearchEmpty;
1520 dirpath = dptr_path(sconn, dptr_num);
1521 directory = talloc_strdup(ctx, dirpath);
1522 if (!directory) {
1523 reply_nterror(req, NT_STATUS_NO_MEMORY);
1524 goto out;
1527 mask = dptr_wcard(sconn, dptr_num);
1528 if (!mask) {
1529 goto SearchEmpty;
1532 * For a 'continue' search we have no string. So
1533 * check from the initial saved string.
1535 mask_contains_wcard = ms_has_wild(mask);
1536 dirtype = dptr_attr(sconn, dptr_num);
1539 DEBUG(4,("dptr_num is %d\n",dptr_num));
1541 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1542 dptr_init_search_op(dirptr);
1544 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1545 char buf[DIR_STRUCT_SIZE];
1546 memcpy(buf,status,21);
1547 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1548 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1549 reply_nterror(req, NT_STATUS_NO_MEMORY);
1550 goto out;
1552 dptr_fill(sconn, buf+12,dptr_num);
1553 if (dptr_zero(buf+12) && (status_len==0)) {
1554 numentries = 1;
1555 } else {
1556 numentries = 0;
1558 if (message_push_blob(&req->outbuf,
1559 data_blob_const(buf, sizeof(buf)))
1560 == -1) {
1561 reply_nterror(req, NT_STATUS_NO_MEMORY);
1562 goto out;
1564 } else {
1565 unsigned int i;
1566 maxentries = MIN(
1567 maxentries,
1568 ((BUFFER_SIZE -
1569 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1570 /DIR_STRUCT_SIZE));
1572 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1573 directory,lp_dontdescend(SNUM(conn))));
1574 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1575 check_descend = True;
1578 for (i=numentries;(i<maxentries) && !finished;i++) {
1579 finished = !get_dir_entry(ctx,
1580 dirptr,
1581 mask,
1582 dirtype,
1583 &fname,
1584 &size,
1585 &mode,
1586 &date,
1587 check_descend,
1588 ask_sharemode);
1589 if (!finished) {
1590 char buf[DIR_STRUCT_SIZE];
1591 memcpy(buf,status,21);
1592 if (!make_dir_struct(ctx,
1593 buf,
1594 mask,
1595 fname,
1596 size,
1597 mode,
1598 convert_timespec_to_time_t(date),
1599 !allow_long_path_components)) {
1600 reply_nterror(req, NT_STATUS_NO_MEMORY);
1601 goto out;
1603 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1604 break;
1606 if (message_push_blob(&req->outbuf,
1607 data_blob_const(buf, sizeof(buf)))
1608 == -1) {
1609 reply_nterror(req, NT_STATUS_NO_MEMORY);
1610 goto out;
1612 numentries++;
1617 SearchEmpty:
1619 /* If we were called as SMBffirst with smb_search_id == NULL
1620 and no entries were found then return error and close dirptr
1621 (X/Open spec) */
1623 if (numentries == 0) {
1624 dptr_close(sconn, &dptr_num);
1625 } else if(expect_close && status_len == 0) {
1626 /* Close the dptr - we know it's gone */
1627 dptr_close(sconn, &dptr_num);
1630 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1631 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1632 dptr_close(sconn, &dptr_num);
1635 if ((numentries == 0) && !mask_contains_wcard) {
1636 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1637 goto out;
1640 SSVAL(req->outbuf,smb_vwv0,numentries);
1641 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1642 SCVAL(smb_buf(req->outbuf),0,5);
1643 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1645 /* The replies here are never long name. */
1646 SSVAL(req->outbuf, smb_flg2,
1647 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1648 if (!allow_long_path_components) {
1649 SSVAL(req->outbuf, smb_flg2,
1650 SVAL(req->outbuf, smb_flg2)
1651 & (~FLAGS2_LONG_PATH_COMPONENTS));
1654 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1655 SSVAL(req->outbuf, smb_flg2,
1656 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1658 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1659 smb_fn_name(req->cmd),
1660 mask,
1661 directory,
1662 dirtype,
1663 numentries,
1664 maxentries ));
1665 out:
1666 TALLOC_FREE(directory);
1667 TALLOC_FREE(smb_fname);
1668 END_PROFILE(SMBsearch);
1669 return;
1672 /****************************************************************************
1673 Reply to a fclose (stop directory search).
1674 ****************************************************************************/
1676 void reply_fclose(struct smb_request *req)
1678 int status_len;
1679 char status[21];
1680 int dptr_num= -2;
1681 const char *p;
1682 char *path = NULL;
1683 NTSTATUS err;
1684 bool path_contains_wcard = False;
1685 TALLOC_CTX *ctx = talloc_tos();
1686 struct smbd_server_connection *sconn = req->sconn;
1688 START_PROFILE(SMBfclose);
1690 if (lp_posix_pathnames()) {
1691 reply_unknown_new(req, req->cmd);
1692 END_PROFILE(SMBfclose);
1693 return;
1696 p = (const char *)req->buf + 1;
1697 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1698 &err, &path_contains_wcard);
1699 if (!NT_STATUS_IS_OK(err)) {
1700 reply_nterror(req, err);
1701 END_PROFILE(SMBfclose);
1702 return;
1704 p++;
1705 status_len = SVAL(p,0);
1706 p += 2;
1708 if (status_len == 0) {
1709 reply_force_doserror(req, ERRSRV, ERRsrverror);
1710 END_PROFILE(SMBfclose);
1711 return;
1714 memcpy(status,p,21);
1716 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1717 /* Close the dptr - we know it's gone */
1718 dptr_close(sconn, &dptr_num);
1721 reply_outbuf(req, 1, 0);
1722 SSVAL(req->outbuf,smb_vwv0,0);
1724 DEBUG(3,("search close\n"));
1726 END_PROFILE(SMBfclose);
1727 return;
1730 /****************************************************************************
1731 Reply to an open.
1732 ****************************************************************************/
1734 void reply_open(struct smb_request *req)
1736 connection_struct *conn = req->conn;
1737 struct smb_filename *smb_fname = NULL;
1738 char *fname = NULL;
1739 uint32 fattr=0;
1740 SMB_OFF_T size = 0;
1741 time_t mtime=0;
1742 int info;
1743 files_struct *fsp;
1744 int oplock_request;
1745 int deny_mode;
1746 uint32 dos_attr;
1747 uint32 access_mask;
1748 uint32 share_mode;
1749 uint32 create_disposition;
1750 uint32 create_options = 0;
1751 uint32_t private_flags = 0;
1752 NTSTATUS status;
1753 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1754 TALLOC_CTX *ctx = talloc_tos();
1756 START_PROFILE(SMBopen);
1758 if (req->wct < 2) {
1759 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1760 goto out;
1763 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1764 deny_mode = SVAL(req->vwv+0, 0);
1765 dos_attr = SVAL(req->vwv+1, 0);
1767 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1768 STR_TERMINATE, &status);
1769 if (!NT_STATUS_IS_OK(status)) {
1770 reply_nterror(req, status);
1771 goto out;
1774 status = filename_convert(ctx,
1775 conn,
1776 req->flags2 & FLAGS2_DFS_PATHNAMES,
1777 fname,
1779 NULL,
1780 &smb_fname);
1781 if (!NT_STATUS_IS_OK(status)) {
1782 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1783 reply_botherror(req,
1784 NT_STATUS_PATH_NOT_COVERED,
1785 ERRSRV, ERRbadpath);
1786 goto out;
1788 reply_nterror(req, status);
1789 goto out;
1792 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1793 OPENX_FILE_EXISTS_OPEN, &access_mask,
1794 &share_mode, &create_disposition,
1795 &create_options, &private_flags)) {
1796 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1797 goto out;
1800 status = SMB_VFS_CREATE_FILE(
1801 conn, /* conn */
1802 req, /* req */
1803 0, /* root_dir_fid */
1804 smb_fname, /* fname */
1805 access_mask, /* access_mask */
1806 share_mode, /* share_access */
1807 create_disposition, /* create_disposition*/
1808 create_options, /* create_options */
1809 dos_attr, /* file_attributes */
1810 oplock_request, /* oplock_request */
1811 0, /* allocation_size */
1812 private_flags,
1813 NULL, /* sd */
1814 NULL, /* ea_list */
1815 &fsp, /* result */
1816 &info); /* pinfo */
1818 if (!NT_STATUS_IS_OK(status)) {
1819 if (open_was_deferred(req->mid)) {
1820 /* We have re-scheduled this call. */
1821 goto out;
1823 reply_openerror(req, status);
1824 goto out;
1827 size = smb_fname->st.st_ex_size;
1828 fattr = dos_mode(conn, smb_fname);
1830 /* Deal with other possible opens having a modified
1831 write time. JRA. */
1832 if (ask_sharemode) {
1833 struct timespec write_time_ts;
1835 ZERO_STRUCT(write_time_ts);
1836 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1837 if (!null_timespec(write_time_ts)) {
1838 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1842 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1844 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1845 DEBUG(3,("attempt to open a directory %s\n",
1846 fsp_str_dbg(fsp)));
1847 close_file(req, fsp, ERROR_CLOSE);
1848 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1849 ERRDOS, ERRnoaccess);
1850 goto out;
1853 reply_outbuf(req, 7, 0);
1854 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1855 SSVAL(req->outbuf,smb_vwv1,fattr);
1856 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1857 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1858 } else {
1859 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1861 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1862 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1864 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1865 SCVAL(req->outbuf,smb_flg,
1866 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1869 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1870 SCVAL(req->outbuf,smb_flg,
1871 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1873 out:
1874 TALLOC_FREE(smb_fname);
1875 END_PROFILE(SMBopen);
1876 return;
1879 /****************************************************************************
1880 Reply to an open and X.
1881 ****************************************************************************/
1883 void reply_open_and_X(struct smb_request *req)
1885 connection_struct *conn = req->conn;
1886 struct smb_filename *smb_fname = NULL;
1887 char *fname = NULL;
1888 uint16 open_flags;
1889 int deny_mode;
1890 uint32 smb_attr;
1891 /* Breakout the oplock request bits so we can set the
1892 reply bits separately. */
1893 int ex_oplock_request;
1894 int core_oplock_request;
1895 int oplock_request;
1896 #if 0
1897 int smb_sattr = SVAL(req->vwv+4, 0);
1898 uint32 smb_time = make_unix_date3(req->vwv+6);
1899 #endif
1900 int smb_ofun;
1901 uint32 fattr=0;
1902 int mtime=0;
1903 int smb_action = 0;
1904 files_struct *fsp;
1905 NTSTATUS status;
1906 uint64_t allocation_size;
1907 ssize_t retval = -1;
1908 uint32 access_mask;
1909 uint32 share_mode;
1910 uint32 create_disposition;
1911 uint32 create_options = 0;
1912 uint32_t private_flags = 0;
1913 TALLOC_CTX *ctx = talloc_tos();
1915 START_PROFILE(SMBopenX);
1917 if (req->wct < 15) {
1918 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1919 goto out;
1922 open_flags = SVAL(req->vwv+2, 0);
1923 deny_mode = SVAL(req->vwv+3, 0);
1924 smb_attr = SVAL(req->vwv+5, 0);
1925 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1926 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1927 oplock_request = ex_oplock_request | core_oplock_request;
1928 smb_ofun = SVAL(req->vwv+8, 0);
1929 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1931 /* If it's an IPC, pass off the pipe handler. */
1932 if (IS_IPC(conn)) {
1933 if (lp_nt_pipe_support()) {
1934 reply_open_pipe_and_X(conn, req);
1935 } else {
1936 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1938 goto out;
1941 /* XXXX we need to handle passed times, sattr and flags */
1942 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1943 STR_TERMINATE, &status);
1944 if (!NT_STATUS_IS_OK(status)) {
1945 reply_nterror(req, status);
1946 goto out;
1949 status = filename_convert(ctx,
1950 conn,
1951 req->flags2 & FLAGS2_DFS_PATHNAMES,
1952 fname,
1954 NULL,
1955 &smb_fname);
1956 if (!NT_STATUS_IS_OK(status)) {
1957 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1958 reply_botherror(req,
1959 NT_STATUS_PATH_NOT_COVERED,
1960 ERRSRV, ERRbadpath);
1961 goto out;
1963 reply_nterror(req, status);
1964 goto out;
1967 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1968 &access_mask, &share_mode,
1969 &create_disposition,
1970 &create_options,
1971 &private_flags)) {
1972 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1973 goto out;
1976 status = SMB_VFS_CREATE_FILE(
1977 conn, /* conn */
1978 req, /* req */
1979 0, /* root_dir_fid */
1980 smb_fname, /* fname */
1981 access_mask, /* access_mask */
1982 share_mode, /* share_access */
1983 create_disposition, /* create_disposition*/
1984 create_options, /* create_options */
1985 smb_attr, /* file_attributes */
1986 oplock_request, /* oplock_request */
1987 0, /* allocation_size */
1988 private_flags,
1989 NULL, /* sd */
1990 NULL, /* ea_list */
1991 &fsp, /* result */
1992 &smb_action); /* pinfo */
1994 if (!NT_STATUS_IS_OK(status)) {
1995 if (open_was_deferred(req->mid)) {
1996 /* We have re-scheduled this call. */
1997 goto out;
1999 reply_openerror(req, status);
2000 goto out;
2003 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2004 if the file is truncated or created. */
2005 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2006 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2007 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2008 close_file(req, fsp, ERROR_CLOSE);
2009 reply_nterror(req, NT_STATUS_DISK_FULL);
2010 goto out;
2012 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
2013 if (retval < 0) {
2014 close_file(req, fsp, ERROR_CLOSE);
2015 reply_nterror(req, NT_STATUS_DISK_FULL);
2016 goto out;
2018 status = vfs_stat_fsp(fsp);
2019 if (!NT_STATUS_IS_OK(status)) {
2020 close_file(req, fsp, ERROR_CLOSE);
2021 reply_nterror(req, status);
2022 goto out;
2026 fattr = dos_mode(conn, fsp->fsp_name);
2027 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2028 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2029 close_file(req, fsp, ERROR_CLOSE);
2030 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2031 goto out;
2034 /* If the caller set the extended oplock request bit
2035 and we granted one (by whatever means) - set the
2036 correct bit for extended oplock reply.
2039 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2040 smb_action |= EXTENDED_OPLOCK_GRANTED;
2043 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2044 smb_action |= EXTENDED_OPLOCK_GRANTED;
2047 /* If the caller set the core oplock request bit
2048 and we granted one (by whatever means) - set the
2049 correct bit for core oplock reply.
2052 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2053 reply_outbuf(req, 19, 0);
2054 } else {
2055 reply_outbuf(req, 15, 0);
2058 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2059 SCVAL(req->outbuf, smb_flg,
2060 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2063 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2064 SCVAL(req->outbuf, smb_flg,
2065 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2068 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2069 SSVAL(req->outbuf,smb_vwv3,fattr);
2070 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2071 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2072 } else {
2073 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2075 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2076 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2077 SSVAL(req->outbuf,smb_vwv11,smb_action);
2079 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2080 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2083 chain_reply(req);
2084 out:
2085 TALLOC_FREE(smb_fname);
2086 END_PROFILE(SMBopenX);
2087 return;
2090 /****************************************************************************
2091 Reply to a SMBulogoffX.
2092 ****************************************************************************/
2094 void reply_ulogoffX(struct smb_request *req)
2096 struct smbd_server_connection *sconn = req->sconn;
2097 user_struct *vuser;
2099 START_PROFILE(SMBulogoffX);
2101 vuser = get_valid_user_struct(sconn, req->vuid);
2103 if(vuser == NULL) {
2104 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2105 req->vuid));
2108 /* in user level security we are supposed to close any files
2109 open by this user */
2110 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2111 file_close_user(sconn, req->vuid);
2114 invalidate_vuid(sconn, req->vuid);
2116 reply_outbuf(req, 2, 0);
2118 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2120 END_PROFILE(SMBulogoffX);
2121 req->vuid = UID_FIELD_INVALID;
2122 chain_reply(req);
2125 /****************************************************************************
2126 Reply to a mknew or a create.
2127 ****************************************************************************/
2129 void reply_mknew(struct smb_request *req)
2131 connection_struct *conn = req->conn;
2132 struct smb_filename *smb_fname = NULL;
2133 char *fname = NULL;
2134 uint32 fattr = 0;
2135 struct smb_file_time ft;
2136 files_struct *fsp;
2137 int oplock_request = 0;
2138 NTSTATUS status;
2139 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2140 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2141 uint32 create_disposition;
2142 uint32 create_options = 0;
2143 TALLOC_CTX *ctx = talloc_tos();
2145 START_PROFILE(SMBcreate);
2146 ZERO_STRUCT(ft);
2148 if (req->wct < 3) {
2149 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2150 goto out;
2153 fattr = SVAL(req->vwv+0, 0);
2154 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2156 /* mtime. */
2157 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2159 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2160 STR_TERMINATE, &status);
2161 if (!NT_STATUS_IS_OK(status)) {
2162 reply_nterror(req, status);
2163 goto out;
2166 status = filename_convert(ctx,
2167 conn,
2168 req->flags2 & FLAGS2_DFS_PATHNAMES,
2169 fname,
2171 NULL,
2172 &smb_fname);
2173 if (!NT_STATUS_IS_OK(status)) {
2174 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2175 reply_botherror(req,
2176 NT_STATUS_PATH_NOT_COVERED,
2177 ERRSRV, ERRbadpath);
2178 goto out;
2180 reply_nterror(req, status);
2181 goto out;
2184 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2185 DEBUG(0,("Attempt to create file (%s) with volid set - "
2186 "please report this\n",
2187 smb_fname_str_dbg(smb_fname)));
2190 if(req->cmd == SMBmknew) {
2191 /* We should fail if file exists. */
2192 create_disposition = FILE_CREATE;
2193 } else {
2194 /* Create if file doesn't exist, truncate if it does. */
2195 create_disposition = FILE_OVERWRITE_IF;
2198 status = SMB_VFS_CREATE_FILE(
2199 conn, /* conn */
2200 req, /* req */
2201 0, /* root_dir_fid */
2202 smb_fname, /* fname */
2203 access_mask, /* access_mask */
2204 share_mode, /* share_access */
2205 create_disposition, /* create_disposition*/
2206 create_options, /* create_options */
2207 fattr, /* file_attributes */
2208 oplock_request, /* oplock_request */
2209 0, /* allocation_size */
2210 0, /* private_flags */
2211 NULL, /* sd */
2212 NULL, /* ea_list */
2213 &fsp, /* result */
2214 NULL); /* pinfo */
2216 if (!NT_STATUS_IS_OK(status)) {
2217 if (open_was_deferred(req->mid)) {
2218 /* We have re-scheduled this call. */
2219 goto out;
2221 reply_openerror(req, status);
2222 goto out;
2225 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2226 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2227 if (!NT_STATUS_IS_OK(status)) {
2228 END_PROFILE(SMBcreate);
2229 goto out;
2232 reply_outbuf(req, 1, 0);
2233 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2235 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2236 SCVAL(req->outbuf,smb_flg,
2237 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2240 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2241 SCVAL(req->outbuf,smb_flg,
2242 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2245 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2246 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2247 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2248 (unsigned int)fattr));
2250 out:
2251 TALLOC_FREE(smb_fname);
2252 END_PROFILE(SMBcreate);
2253 return;
2256 /****************************************************************************
2257 Reply to a create temporary file.
2258 ****************************************************************************/
2260 void reply_ctemp(struct smb_request *req)
2262 connection_struct *conn = req->conn;
2263 struct smb_filename *smb_fname = NULL;
2264 char *fname = NULL;
2265 uint32 fattr;
2266 files_struct *fsp;
2267 int oplock_request;
2268 int tmpfd;
2269 char *s;
2270 NTSTATUS status;
2271 TALLOC_CTX *ctx = talloc_tos();
2273 START_PROFILE(SMBctemp);
2275 if (req->wct < 3) {
2276 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2277 goto out;
2280 fattr = SVAL(req->vwv+0, 0);
2281 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2283 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2284 STR_TERMINATE, &status);
2285 if (!NT_STATUS_IS_OK(status)) {
2286 reply_nterror(req, status);
2287 goto out;
2289 if (*fname) {
2290 fname = talloc_asprintf(ctx,
2291 "%s/TMXXXXXX",
2292 fname);
2293 } else {
2294 fname = talloc_strdup(ctx, "TMXXXXXX");
2297 if (!fname) {
2298 reply_nterror(req, NT_STATUS_NO_MEMORY);
2299 goto out;
2302 status = filename_convert(ctx, conn,
2303 req->flags2 & FLAGS2_DFS_PATHNAMES,
2304 fname,
2306 NULL,
2307 &smb_fname);
2308 if (!NT_STATUS_IS_OK(status)) {
2309 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2310 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2311 ERRSRV, ERRbadpath);
2312 goto out;
2314 reply_nterror(req, status);
2315 goto out;
2318 tmpfd = mkstemp(smb_fname->base_name);
2319 if (tmpfd == -1) {
2320 reply_nterror(req, map_nt_error_from_unix(errno));
2321 goto out;
2324 SMB_VFS_STAT(conn, smb_fname);
2326 /* We should fail if file does not exist. */
2327 status = SMB_VFS_CREATE_FILE(
2328 conn, /* conn */
2329 req, /* req */
2330 0, /* root_dir_fid */
2331 smb_fname, /* fname */
2332 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2333 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2334 FILE_OPEN, /* create_disposition*/
2335 0, /* create_options */
2336 fattr, /* file_attributes */
2337 oplock_request, /* oplock_request */
2338 0, /* allocation_size */
2339 0, /* private_flags */
2340 NULL, /* sd */
2341 NULL, /* ea_list */
2342 &fsp, /* result */
2343 NULL); /* pinfo */
2345 /* close fd from mkstemp() */
2346 close(tmpfd);
2348 if (!NT_STATUS_IS_OK(status)) {
2349 if (open_was_deferred(req->mid)) {
2350 /* We have re-scheduled this call. */
2351 goto out;
2353 reply_openerror(req, status);
2354 goto out;
2357 reply_outbuf(req, 1, 0);
2358 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2360 /* the returned filename is relative to the directory */
2361 s = strrchr_m(fsp->fsp_name->base_name, '/');
2362 if (!s) {
2363 s = fsp->fsp_name->base_name;
2364 } else {
2365 s++;
2368 #if 0
2369 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2370 thing in the byte section. JRA */
2371 SSVALS(p, 0, -1); /* what is this? not in spec */
2372 #endif
2373 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2374 == -1) {
2375 reply_nterror(req, NT_STATUS_NO_MEMORY);
2376 goto out;
2379 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2380 SCVAL(req->outbuf, smb_flg,
2381 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2384 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2385 SCVAL(req->outbuf, smb_flg,
2386 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2389 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2390 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2391 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2392 out:
2393 TALLOC_FREE(smb_fname);
2394 END_PROFILE(SMBctemp);
2395 return;
2398 /*******************************************************************
2399 Check if a user is allowed to rename a file.
2400 ********************************************************************/
2402 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2403 uint16 dirtype)
2405 if (!CAN_WRITE(conn)) {
2406 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2409 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2410 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2411 /* Only bother to read the DOS attribute if we might deny the
2412 rename on the grounds of attribute missmatch. */
2413 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2414 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2415 return NT_STATUS_NO_SUCH_FILE;
2419 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2420 if (fsp->posix_open) {
2421 return NT_STATUS_OK;
2424 /* If no pathnames are open below this
2425 directory, allow the rename. */
2427 if (file_find_subpath(fsp)) {
2428 return NT_STATUS_ACCESS_DENIED;
2430 return NT_STATUS_OK;
2433 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2434 return NT_STATUS_OK;
2437 return NT_STATUS_ACCESS_DENIED;
2440 /*******************************************************************
2441 * unlink a file with all relevant access checks
2442 *******************************************************************/
2444 static NTSTATUS do_unlink(connection_struct *conn,
2445 struct smb_request *req,
2446 struct smb_filename *smb_fname,
2447 uint32 dirtype)
2449 uint32 fattr;
2450 files_struct *fsp;
2451 uint32 dirtype_orig = dirtype;
2452 NTSTATUS status;
2453 int ret;
2454 bool posix_paths = lp_posix_pathnames();
2456 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2457 smb_fname_str_dbg(smb_fname),
2458 dirtype));
2460 if (!CAN_WRITE(conn)) {
2461 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2464 if (posix_paths) {
2465 ret = SMB_VFS_LSTAT(conn, smb_fname);
2466 } else {
2467 ret = SMB_VFS_STAT(conn, smb_fname);
2469 if (ret != 0) {
2470 return map_nt_error_from_unix(errno);
2473 fattr = dos_mode(conn, smb_fname);
2475 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2476 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2479 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2480 if (!dirtype) {
2481 return NT_STATUS_NO_SUCH_FILE;
2484 if (!dir_check_ftype(conn, fattr, dirtype)) {
2485 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2486 return NT_STATUS_FILE_IS_A_DIRECTORY;
2488 return NT_STATUS_NO_SUCH_FILE;
2491 if (dirtype_orig & 0x8000) {
2492 /* These will never be set for POSIX. */
2493 return NT_STATUS_NO_SUCH_FILE;
2496 #if 0
2497 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2498 return NT_STATUS_FILE_IS_A_DIRECTORY;
2501 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2502 return NT_STATUS_NO_SUCH_FILE;
2505 if (dirtype & 0xFF00) {
2506 /* These will never be set for POSIX. */
2507 return NT_STATUS_NO_SUCH_FILE;
2510 dirtype &= 0xFF;
2511 if (!dirtype) {
2512 return NT_STATUS_NO_SUCH_FILE;
2515 /* Can't delete a directory. */
2516 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2517 return NT_STATUS_FILE_IS_A_DIRECTORY;
2519 #endif
2521 #if 0 /* JRATEST */
2522 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2523 return NT_STATUS_OBJECT_NAME_INVALID;
2524 #endif /* JRATEST */
2526 /* On open checks the open itself will check the share mode, so
2527 don't do it here as we'll get it wrong. */
2529 status = SMB_VFS_CREATE_FILE
2530 (conn, /* conn */
2531 req, /* req */
2532 0, /* root_dir_fid */
2533 smb_fname, /* fname */
2534 DELETE_ACCESS, /* access_mask */
2535 FILE_SHARE_NONE, /* share_access */
2536 FILE_OPEN, /* create_disposition*/
2537 FILE_NON_DIRECTORY_FILE, /* create_options */
2538 /* file_attributes */
2539 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2540 FILE_ATTRIBUTE_NORMAL,
2541 0, /* oplock_request */
2542 0, /* allocation_size */
2543 0, /* private_flags */
2544 NULL, /* sd */
2545 NULL, /* ea_list */
2546 &fsp, /* result */
2547 NULL); /* pinfo */
2549 if (!NT_STATUS_IS_OK(status)) {
2550 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2551 nt_errstr(status)));
2552 return status;
2555 status = can_set_delete_on_close(fsp, fattr);
2556 if (!NT_STATUS_IS_OK(status)) {
2557 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2558 "(%s)\n",
2559 smb_fname_str_dbg(smb_fname),
2560 nt_errstr(status)));
2561 close_file(req, fsp, NORMAL_CLOSE);
2562 return status;
2565 /* The set is across all open files on this dev/inode pair. */
2566 if (!set_delete_on_close(fsp, True, conn->session_info->unix_token)) {
2567 close_file(req, fsp, NORMAL_CLOSE);
2568 return NT_STATUS_ACCESS_DENIED;
2571 return close_file(req, fsp, NORMAL_CLOSE);
2574 /****************************************************************************
2575 The guts of the unlink command, split out so it may be called by the NT SMB
2576 code.
2577 ****************************************************************************/
2579 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2580 uint32 dirtype, struct smb_filename *smb_fname,
2581 bool has_wild)
2583 char *fname_dir = NULL;
2584 char *fname_mask = NULL;
2585 int count=0;
2586 NTSTATUS status = NT_STATUS_OK;
2587 TALLOC_CTX *ctx = talloc_tos();
2589 /* Split up the directory from the filename/mask. */
2590 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2591 &fname_dir, &fname_mask);
2592 if (!NT_STATUS_IS_OK(status)) {
2593 goto out;
2597 * We should only check the mangled cache
2598 * here if unix_convert failed. This means
2599 * that the path in 'mask' doesn't exist
2600 * on the file system and so we need to look
2601 * for a possible mangle. This patch from
2602 * Tine Smukavec <valentin.smukavec@hermes.si>.
2605 if (!VALID_STAT(smb_fname->st) &&
2606 mangle_is_mangled(fname_mask, conn->params)) {
2607 char *new_mask = NULL;
2608 mangle_lookup_name_from_8_3(ctx, fname_mask,
2609 &new_mask, conn->params);
2610 if (new_mask) {
2611 TALLOC_FREE(fname_mask);
2612 fname_mask = new_mask;
2616 if (!has_wild) {
2619 * Only one file needs to be unlinked. Append the mask back
2620 * onto the directory.
2622 TALLOC_FREE(smb_fname->base_name);
2623 if (ISDOT(fname_dir)) {
2624 /* Ensure we use canonical names on open. */
2625 smb_fname->base_name = talloc_asprintf(smb_fname,
2626 "%s",
2627 fname_mask);
2628 } else {
2629 smb_fname->base_name = talloc_asprintf(smb_fname,
2630 "%s/%s",
2631 fname_dir,
2632 fname_mask);
2634 if (!smb_fname->base_name) {
2635 status = NT_STATUS_NO_MEMORY;
2636 goto out;
2638 if (dirtype == 0) {
2639 dirtype = FILE_ATTRIBUTE_NORMAL;
2642 status = check_name(conn, smb_fname->base_name);
2643 if (!NT_STATUS_IS_OK(status)) {
2644 goto out;
2647 status = do_unlink(conn, req, smb_fname, dirtype);
2648 if (!NT_STATUS_IS_OK(status)) {
2649 goto out;
2652 count++;
2653 } else {
2654 struct smb_Dir *dir_hnd = NULL;
2655 long offset = 0;
2656 const char *dname = NULL;
2657 char *talloced = NULL;
2659 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2660 status = NT_STATUS_OBJECT_NAME_INVALID;
2661 goto out;
2664 if (strequal(fname_mask,"????????.???")) {
2665 TALLOC_FREE(fname_mask);
2666 fname_mask = talloc_strdup(ctx, "*");
2667 if (!fname_mask) {
2668 status = NT_STATUS_NO_MEMORY;
2669 goto out;
2673 status = check_name(conn, fname_dir);
2674 if (!NT_STATUS_IS_OK(status)) {
2675 goto out;
2678 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2679 dirtype);
2680 if (dir_hnd == NULL) {
2681 status = map_nt_error_from_unix(errno);
2682 goto out;
2685 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2686 the pattern matches against the long name, otherwise the short name
2687 We don't implement this yet XXXX
2690 status = NT_STATUS_NO_SUCH_FILE;
2692 while ((dname = ReadDirName(dir_hnd, &offset,
2693 &smb_fname->st, &talloced))) {
2694 TALLOC_CTX *frame = talloc_stackframe();
2696 if (!is_visible_file(conn, fname_dir, dname,
2697 &smb_fname->st, true)) {
2698 TALLOC_FREE(frame);
2699 TALLOC_FREE(talloced);
2700 continue;
2703 /* Quick check for "." and ".." */
2704 if (ISDOT(dname) || ISDOTDOT(dname)) {
2705 TALLOC_FREE(frame);
2706 TALLOC_FREE(talloced);
2707 continue;
2710 if(!mask_match(dname, fname_mask,
2711 conn->case_sensitive)) {
2712 TALLOC_FREE(frame);
2713 TALLOC_FREE(talloced);
2714 continue;
2717 TALLOC_FREE(smb_fname->base_name);
2718 if (ISDOT(fname_dir)) {
2719 /* Ensure we use canonical names on open. */
2720 smb_fname->base_name =
2721 talloc_asprintf(smb_fname, "%s",
2722 dname);
2723 } else {
2724 smb_fname->base_name =
2725 talloc_asprintf(smb_fname, "%s/%s",
2726 fname_dir, dname);
2729 if (!smb_fname->base_name) {
2730 TALLOC_FREE(dir_hnd);
2731 status = NT_STATUS_NO_MEMORY;
2732 TALLOC_FREE(frame);
2733 TALLOC_FREE(talloced);
2734 goto out;
2737 status = check_name(conn, smb_fname->base_name);
2738 if (!NT_STATUS_IS_OK(status)) {
2739 TALLOC_FREE(dir_hnd);
2740 TALLOC_FREE(frame);
2741 TALLOC_FREE(talloced);
2742 goto out;
2745 status = do_unlink(conn, req, smb_fname, dirtype);
2746 if (!NT_STATUS_IS_OK(status)) {
2747 TALLOC_FREE(frame);
2748 TALLOC_FREE(talloced);
2749 continue;
2752 count++;
2753 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2754 smb_fname->base_name));
2756 TALLOC_FREE(frame);
2757 TALLOC_FREE(talloced);
2759 TALLOC_FREE(dir_hnd);
2762 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2763 status = map_nt_error_from_unix(errno);
2766 out:
2767 TALLOC_FREE(fname_dir);
2768 TALLOC_FREE(fname_mask);
2769 return status;
2772 /****************************************************************************
2773 Reply to a unlink
2774 ****************************************************************************/
2776 void reply_unlink(struct smb_request *req)
2778 connection_struct *conn = req->conn;
2779 char *name = NULL;
2780 struct smb_filename *smb_fname = NULL;
2781 uint32 dirtype;
2782 NTSTATUS status;
2783 bool path_contains_wcard = False;
2784 TALLOC_CTX *ctx = talloc_tos();
2786 START_PROFILE(SMBunlink);
2788 if (req->wct < 1) {
2789 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2790 goto out;
2793 dirtype = SVAL(req->vwv+0, 0);
2795 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2796 STR_TERMINATE, &status,
2797 &path_contains_wcard);
2798 if (!NT_STATUS_IS_OK(status)) {
2799 reply_nterror(req, status);
2800 goto out;
2803 status = filename_convert(ctx, conn,
2804 req->flags2 & FLAGS2_DFS_PATHNAMES,
2805 name,
2806 UCF_COND_ALLOW_WCARD_LCOMP,
2807 &path_contains_wcard,
2808 &smb_fname);
2809 if (!NT_STATUS_IS_OK(status)) {
2810 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2811 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2812 ERRSRV, ERRbadpath);
2813 goto out;
2815 reply_nterror(req, status);
2816 goto out;
2819 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2821 status = unlink_internals(conn, req, dirtype, smb_fname,
2822 path_contains_wcard);
2823 if (!NT_STATUS_IS_OK(status)) {
2824 if (open_was_deferred(req->mid)) {
2825 /* We have re-scheduled this call. */
2826 goto out;
2828 reply_nterror(req, status);
2829 goto out;
2832 reply_outbuf(req, 0, 0);
2833 out:
2834 TALLOC_FREE(smb_fname);
2835 END_PROFILE(SMBunlink);
2836 return;
2839 /****************************************************************************
2840 Fail for readbraw.
2841 ****************************************************************************/
2843 static void fail_readraw(void)
2845 const char *errstr = talloc_asprintf(talloc_tos(),
2846 "FAIL ! reply_readbraw: socket write fail (%s)",
2847 strerror(errno));
2848 if (!errstr) {
2849 errstr = "";
2851 exit_server_cleanly(errstr);
2854 /****************************************************************************
2855 Fake (read/write) sendfile. Returns -1 on read or write fail.
2856 ****************************************************************************/
2858 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2860 size_t bufsize;
2861 size_t tosend = nread;
2862 char *buf;
2864 if (nread == 0) {
2865 return 0;
2868 bufsize = MIN(nread, 65536);
2870 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2871 return -1;
2874 while (tosend > 0) {
2875 ssize_t ret;
2876 size_t cur_read;
2878 if (tosend > bufsize) {
2879 cur_read = bufsize;
2880 } else {
2881 cur_read = tosend;
2883 ret = read_file(fsp,buf,startpos,cur_read);
2884 if (ret == -1) {
2885 SAFE_FREE(buf);
2886 return -1;
2889 /* If we had a short read, fill with zeros. */
2890 if (ret < cur_read) {
2891 memset(buf + ret, '\0', cur_read - ret);
2894 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2895 != cur_read) {
2896 char addr[INET6_ADDRSTRLEN];
2898 * Try and give an error message saying what
2899 * client failed.
2901 DEBUG(0, ("write_data failed for client %s. "
2902 "Error %s\n",
2903 get_peer_addr(fsp->conn->sconn->sock, addr,
2904 sizeof(addr)),
2905 strerror(errno)));
2906 SAFE_FREE(buf);
2907 return -1;
2909 tosend -= cur_read;
2910 startpos += cur_read;
2913 SAFE_FREE(buf);
2914 return (ssize_t)nread;
2917 /****************************************************************************
2918 Deal with the case of sendfile reading less bytes from the file than
2919 requested. Fill with zeros (all we can do).
2920 ****************************************************************************/
2922 void sendfile_short_send(files_struct *fsp,
2923 ssize_t nread,
2924 size_t headersize,
2925 size_t smb_maxcnt)
2927 #define SHORT_SEND_BUFSIZE 1024
2928 if (nread < headersize) {
2929 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2930 "header for file %s (%s). Terminating\n",
2931 fsp_str_dbg(fsp), strerror(errno)));
2932 exit_server_cleanly("sendfile_short_send failed");
2935 nread -= headersize;
2937 if (nread < smb_maxcnt) {
2938 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2939 if (!buf) {
2940 exit_server_cleanly("sendfile_short_send: "
2941 "malloc failed");
2944 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2945 "with zeros !\n", fsp_str_dbg(fsp)));
2947 while (nread < smb_maxcnt) {
2949 * We asked for the real file size and told sendfile
2950 * to not go beyond the end of the file. But it can
2951 * happen that in between our fstat call and the
2952 * sendfile call the file was truncated. This is very
2953 * bad because we have already announced the larger
2954 * number of bytes to the client.
2956 * The best we can do now is to send 0-bytes, just as
2957 * a read from a hole in a sparse file would do.
2959 * This should happen rarely enough that I don't care
2960 * about efficiency here :-)
2962 size_t to_write;
2964 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2965 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2966 != to_write) {
2967 char addr[INET6_ADDRSTRLEN];
2969 * Try and give an error message saying what
2970 * client failed.
2972 DEBUG(0, ("write_data failed for client %s. "
2973 "Error %s\n",
2974 get_peer_addr(
2975 fsp->conn->sconn->sock, addr,
2976 sizeof(addr)),
2977 strerror(errno)));
2978 exit_server_cleanly("sendfile_short_send: "
2979 "write_data failed");
2981 nread += to_write;
2983 SAFE_FREE(buf);
2987 /****************************************************************************
2988 Return a readbraw error (4 bytes of zero).
2989 ****************************************************************************/
2991 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2993 char header[4];
2995 SIVAL(header,0,0);
2997 smbd_lock_socket(sconn);
2998 if (write_data(sconn->sock,header,4) != 4) {
2999 char addr[INET6_ADDRSTRLEN];
3001 * Try and give an error message saying what
3002 * client failed.
3004 DEBUG(0, ("write_data failed for client %s. "
3005 "Error %s\n",
3006 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3007 strerror(errno)));
3009 fail_readraw();
3011 smbd_unlock_socket(sconn);
3014 /****************************************************************************
3015 Use sendfile in readbraw.
3016 ****************************************************************************/
3018 static void send_file_readbraw(connection_struct *conn,
3019 struct smb_request *req,
3020 files_struct *fsp,
3021 SMB_OFF_T startpos,
3022 size_t nread,
3023 ssize_t mincount)
3025 struct smbd_server_connection *sconn = req->sconn;
3026 char *outbuf = NULL;
3027 ssize_t ret=0;
3030 * We can only use sendfile on a non-chained packet
3031 * but we can use on a non-oplocked file. tridge proved this
3032 * on a train in Germany :-). JRA.
3033 * reply_readbraw has already checked the length.
3036 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3037 (fsp->wcp == NULL) &&
3038 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3039 ssize_t sendfile_read = -1;
3040 char header[4];
3041 DATA_BLOB header_blob;
3043 _smb_setlen(header,nread);
3044 header_blob = data_blob_const(header, 4);
3046 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3047 &header_blob, startpos,
3048 nread);
3049 if (sendfile_read == -1) {
3050 /* Returning ENOSYS means no data at all was sent.
3051 * Do this as a normal read. */
3052 if (errno == ENOSYS) {
3053 goto normal_readbraw;
3057 * Special hack for broken Linux with no working sendfile. If we
3058 * return EINTR we sent the header but not the rest of the data.
3059 * Fake this up by doing read/write calls.
3061 if (errno == EINTR) {
3062 /* Ensure we don't do this again. */
3063 set_use_sendfile(SNUM(conn), False);
3064 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3066 if (fake_sendfile(fsp, startpos, nread) == -1) {
3067 DEBUG(0,("send_file_readbraw: "
3068 "fake_sendfile failed for "
3069 "file %s (%s).\n",
3070 fsp_str_dbg(fsp),
3071 strerror(errno)));
3072 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3074 return;
3077 DEBUG(0,("send_file_readbraw: sendfile failed for "
3078 "file %s (%s). Terminating\n",
3079 fsp_str_dbg(fsp), strerror(errno)));
3080 exit_server_cleanly("send_file_readbraw sendfile failed");
3081 } else if (sendfile_read == 0) {
3083 * Some sendfile implementations return 0 to indicate
3084 * that there was a short read, but nothing was
3085 * actually written to the socket. In this case,
3086 * fallback to the normal read path so the header gets
3087 * the correct byte count.
3089 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3090 "bytes falling back to the normal read: "
3091 "%s\n", fsp_str_dbg(fsp)));
3092 goto normal_readbraw;
3095 /* Deal with possible short send. */
3096 if (sendfile_read != 4+nread) {
3097 sendfile_short_send(fsp, sendfile_read, 4, nread);
3099 return;
3102 normal_readbraw:
3104 outbuf = talloc_array(NULL, char, nread+4);
3105 if (!outbuf) {
3106 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3107 (unsigned)(nread+4)));
3108 reply_readbraw_error(sconn);
3109 return;
3112 if (nread > 0) {
3113 ret = read_file(fsp,outbuf+4,startpos,nread);
3114 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3115 if (ret < mincount)
3116 ret = 0;
3117 #else
3118 if (ret < nread)
3119 ret = 0;
3120 #endif
3123 _smb_setlen(outbuf,ret);
3124 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3125 char addr[INET6_ADDRSTRLEN];
3127 * Try and give an error message saying what
3128 * client failed.
3130 DEBUG(0, ("write_data failed for client %s. "
3131 "Error %s\n",
3132 get_peer_addr(fsp->conn->sconn->sock, addr,
3133 sizeof(addr)),
3134 strerror(errno)));
3136 fail_readraw();
3139 TALLOC_FREE(outbuf);
3142 /****************************************************************************
3143 Reply to a readbraw (core+ protocol).
3144 ****************************************************************************/
3146 void reply_readbraw(struct smb_request *req)
3148 connection_struct *conn = req->conn;
3149 struct smbd_server_connection *sconn = req->sconn;
3150 ssize_t maxcount,mincount;
3151 size_t nread = 0;
3152 SMB_OFF_T startpos;
3153 files_struct *fsp;
3154 struct lock_struct lock;
3155 SMB_OFF_T size = 0;
3157 START_PROFILE(SMBreadbraw);
3159 if (srv_is_signing_active(sconn) ||
3160 is_encrypted_packet(req->inbuf)) {
3161 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3162 "raw reads/writes are disallowed.");
3165 if (req->wct < 8) {
3166 reply_readbraw_error(sconn);
3167 END_PROFILE(SMBreadbraw);
3168 return;
3171 if (sconn->smb1.echo_handler.trusted_fde) {
3172 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3173 "'async smb echo handler = yes'\n"));
3174 reply_readbraw_error(sconn);
3175 END_PROFILE(SMBreadbraw);
3176 return;
3180 * Special check if an oplock break has been issued
3181 * and the readraw request croses on the wire, we must
3182 * return a zero length response here.
3185 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3188 * We have to do a check_fsp by hand here, as
3189 * we must always return 4 zero bytes on error,
3190 * not a NTSTATUS.
3193 if (!fsp || !conn || conn != fsp->conn ||
3194 req->vuid != fsp->vuid ||
3195 fsp->is_directory || fsp->fh->fd == -1) {
3197 * fsp could be NULL here so use the value from the packet. JRA.
3199 DEBUG(3,("reply_readbraw: fnum %d not valid "
3200 "- cache prime?\n",
3201 (int)SVAL(req->vwv+0, 0)));
3202 reply_readbraw_error(sconn);
3203 END_PROFILE(SMBreadbraw);
3204 return;
3207 /* Do a "by hand" version of CHECK_READ. */
3208 if (!(fsp->can_read ||
3209 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3210 (fsp->access_mask & FILE_EXECUTE)))) {
3211 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3212 (int)SVAL(req->vwv+0, 0)));
3213 reply_readbraw_error(sconn);
3214 END_PROFILE(SMBreadbraw);
3215 return;
3218 flush_write_cache(fsp, READRAW_FLUSH);
3220 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3221 if(req->wct == 10) {
3223 * This is a large offset (64 bit) read.
3225 #ifdef LARGE_SMB_OFF_T
3227 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3229 #else /* !LARGE_SMB_OFF_T */
3232 * Ensure we haven't been sent a >32 bit offset.
3235 if(IVAL(req->vwv+8, 0) != 0) {
3236 DEBUG(0,("reply_readbraw: large offset "
3237 "(%x << 32) used and we don't support "
3238 "64 bit offsets.\n",
3239 (unsigned int)IVAL(req->vwv+8, 0) ));
3240 reply_readbraw_error(sconn);
3241 END_PROFILE(SMBreadbraw);
3242 return;
3245 #endif /* LARGE_SMB_OFF_T */
3247 if(startpos < 0) {
3248 DEBUG(0,("reply_readbraw: negative 64 bit "
3249 "readraw offset (%.0f) !\n",
3250 (double)startpos ));
3251 reply_readbraw_error(sconn);
3252 END_PROFILE(SMBreadbraw);
3253 return;
3257 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3258 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3260 /* ensure we don't overrun the packet size */
3261 maxcount = MIN(65535,maxcount);
3263 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3264 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3265 &lock);
3267 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3268 reply_readbraw_error(sconn);
3269 END_PROFILE(SMBreadbraw);
3270 return;
3273 if (fsp_stat(fsp) == 0) {
3274 size = fsp->fsp_name->st.st_ex_size;
3277 if (startpos >= size) {
3278 nread = 0;
3279 } else {
3280 nread = MIN(maxcount,(size - startpos));
3283 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3284 if (nread < mincount)
3285 nread = 0;
3286 #endif
3288 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3289 "min=%lu nread=%lu\n",
3290 fsp->fnum, (double)startpos,
3291 (unsigned long)maxcount,
3292 (unsigned long)mincount,
3293 (unsigned long)nread ) );
3295 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3297 DEBUG(5,("reply_readbraw finished\n"));
3299 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3301 END_PROFILE(SMBreadbraw);
3302 return;
3305 #undef DBGC_CLASS
3306 #define DBGC_CLASS DBGC_LOCKING
3308 /****************************************************************************
3309 Reply to a lockread (core+ protocol).
3310 ****************************************************************************/
3312 void reply_lockread(struct smb_request *req)
3314 connection_struct *conn = req->conn;
3315 ssize_t nread = -1;
3316 char *data;
3317 SMB_OFF_T startpos;
3318 size_t numtoread;
3319 NTSTATUS status;
3320 files_struct *fsp;
3321 struct byte_range_lock *br_lck = NULL;
3322 char *p = NULL;
3323 struct smbd_server_connection *sconn = req->sconn;
3325 START_PROFILE(SMBlockread);
3327 if (req->wct < 5) {
3328 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3329 END_PROFILE(SMBlockread);
3330 return;
3333 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3335 if (!check_fsp(conn, req, fsp)) {
3336 END_PROFILE(SMBlockread);
3337 return;
3340 if (!CHECK_READ(fsp,req)) {
3341 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3342 END_PROFILE(SMBlockread);
3343 return;
3346 numtoread = SVAL(req->vwv+1, 0);
3347 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3349 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3351 reply_outbuf(req, 5, numtoread + 3);
3353 data = smb_buf(req->outbuf) + 3;
3356 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3357 * protocol request that predates the read/write lock concept.
3358 * Thus instead of asking for a read lock here we need to ask
3359 * for a write lock. JRA.
3360 * Note that the requested lock size is unaffected by max_recv.
3363 br_lck = do_lock(req->sconn->msg_ctx,
3364 fsp,
3365 (uint64_t)req->smbpid,
3366 (uint64_t)numtoread,
3367 (uint64_t)startpos,
3368 WRITE_LOCK,
3369 WINDOWS_LOCK,
3370 False, /* Non-blocking lock. */
3371 &status,
3372 NULL,
3373 NULL);
3374 TALLOC_FREE(br_lck);
3376 if (NT_STATUS_V(status)) {
3377 reply_nterror(req, status);
3378 END_PROFILE(SMBlockread);
3379 return;
3383 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3386 if (numtoread > sconn->smb1.negprot.max_recv) {
3387 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3388 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3389 (unsigned int)numtoread,
3390 (unsigned int)sconn->smb1.negprot.max_recv));
3391 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3393 nread = read_file(fsp,data,startpos,numtoread);
3395 if (nread < 0) {
3396 reply_nterror(req, map_nt_error_from_unix(errno));
3397 END_PROFILE(SMBlockread);
3398 return;
3401 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3403 SSVAL(req->outbuf,smb_vwv0,nread);
3404 SSVAL(req->outbuf,smb_vwv5,nread+3);
3405 p = smb_buf(req->outbuf);
3406 SCVAL(p,0,0); /* pad byte. */
3407 SSVAL(p,1,nread);
3409 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3410 fsp->fnum, (int)numtoread, (int)nread));
3412 END_PROFILE(SMBlockread);
3413 return;
3416 #undef DBGC_CLASS
3417 #define DBGC_CLASS DBGC_ALL
3419 /****************************************************************************
3420 Reply to a read.
3421 ****************************************************************************/
3423 void reply_read(struct smb_request *req)
3425 connection_struct *conn = req->conn;
3426 size_t numtoread;
3427 ssize_t nread = 0;
3428 char *data;
3429 SMB_OFF_T startpos;
3430 int outsize = 0;
3431 files_struct *fsp;
3432 struct lock_struct lock;
3433 struct smbd_server_connection *sconn = req->sconn;
3435 START_PROFILE(SMBread);
3437 if (req->wct < 3) {
3438 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3439 END_PROFILE(SMBread);
3440 return;
3443 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3445 if (!check_fsp(conn, req, fsp)) {
3446 END_PROFILE(SMBread);
3447 return;
3450 if (!CHECK_READ(fsp,req)) {
3451 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3452 END_PROFILE(SMBread);
3453 return;
3456 numtoread = SVAL(req->vwv+1, 0);
3457 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3459 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3462 * The requested read size cannot be greater than max_recv. JRA.
3464 if (numtoread > sconn->smb1.negprot.max_recv) {
3465 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3466 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3467 (unsigned int)numtoread,
3468 (unsigned int)sconn->smb1.negprot.max_recv));
3469 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3472 reply_outbuf(req, 5, numtoread+3);
3474 data = smb_buf(req->outbuf) + 3;
3476 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3477 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3478 &lock);
3480 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3481 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3482 END_PROFILE(SMBread);
3483 return;
3486 if (numtoread > 0)
3487 nread = read_file(fsp,data,startpos,numtoread);
3489 if (nread < 0) {
3490 reply_nterror(req, map_nt_error_from_unix(errno));
3491 goto strict_unlock;
3494 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3496 SSVAL(req->outbuf,smb_vwv0,nread);
3497 SSVAL(req->outbuf,smb_vwv5,nread+3);
3498 SCVAL(smb_buf(req->outbuf),0,1);
3499 SSVAL(smb_buf(req->outbuf),1,nread);
3501 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3502 fsp->fnum, (int)numtoread, (int)nread ) );
3504 strict_unlock:
3505 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3507 END_PROFILE(SMBread);
3508 return;
3511 /****************************************************************************
3512 Setup readX header.
3513 ****************************************************************************/
3515 static int setup_readX_header(struct smb_request *req, char *outbuf,
3516 size_t smb_maxcnt)
3518 int outsize;
3519 char *data;
3521 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3522 data = smb_buf(outbuf);
3524 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3526 SCVAL(outbuf,smb_vwv0,0xFF);
3527 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3528 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3529 SSVAL(outbuf,smb_vwv6,
3530 req_wct_ofs(req)
3531 + 1 /* the wct field */
3532 + 12 * sizeof(uint16_t) /* vwv */
3533 + 2); /* the buflen field */
3534 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3535 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3536 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3537 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3538 return outsize;
3541 /****************************************************************************
3542 Reply to a read and X - possibly using sendfile.
3543 ****************************************************************************/
3545 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3546 files_struct *fsp, SMB_OFF_T startpos,
3547 size_t smb_maxcnt)
3549 ssize_t nread = -1;
3550 struct lock_struct lock;
3551 int saved_errno = 0;
3553 if(fsp_stat(fsp) == -1) {
3554 reply_nterror(req, map_nt_error_from_unix(errno));
3555 return;
3558 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3559 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3560 &lock);
3562 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3563 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3564 return;
3567 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3568 (startpos > fsp->fsp_name->st.st_ex_size)
3569 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3571 * We already know that we would do a short read, so don't
3572 * try the sendfile() path.
3574 goto nosendfile_read;
3578 * We can only use sendfile on a non-chained packet
3579 * but we can use on a non-oplocked file. tridge proved this
3580 * on a train in Germany :-). JRA.
3583 if (!req_is_in_chain(req) &&
3584 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3585 (fsp->wcp == NULL) &&
3586 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3587 uint8 headerbuf[smb_size + 12 * 2];
3588 DATA_BLOB header;
3591 * Set up the packet header before send. We
3592 * assume here the sendfile will work (get the
3593 * correct amount of data).
3596 header = data_blob_const(headerbuf, sizeof(headerbuf));
3598 construct_reply_common_req(req, (char *)headerbuf);
3599 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3601 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3602 startpos, smb_maxcnt);
3603 if (nread == -1) {
3604 /* Returning ENOSYS means no data at all was sent.
3605 Do this as a normal read. */
3606 if (errno == ENOSYS) {
3607 goto normal_read;
3611 * Special hack for broken Linux with no working sendfile. If we
3612 * return EINTR we sent the header but not the rest of the data.
3613 * Fake this up by doing read/write calls.
3616 if (errno == EINTR) {
3617 /* Ensure we don't do this again. */
3618 set_use_sendfile(SNUM(conn), False);
3619 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3620 nread = fake_sendfile(fsp, startpos,
3621 smb_maxcnt);
3622 if (nread == -1) {
3623 DEBUG(0,("send_file_readX: "
3624 "fake_sendfile failed for "
3625 "file %s (%s).\n",
3626 fsp_str_dbg(fsp),
3627 strerror(errno)));
3628 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3630 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3631 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3632 /* No outbuf here means successful sendfile. */
3633 goto strict_unlock;
3636 DEBUG(0,("send_file_readX: sendfile failed for file "
3637 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3638 strerror(errno)));
3639 exit_server_cleanly("send_file_readX sendfile failed");
3640 } else if (nread == 0) {
3642 * Some sendfile implementations return 0 to indicate
3643 * that there was a short read, but nothing was
3644 * actually written to the socket. In this case,
3645 * fallback to the normal read path so the header gets
3646 * the correct byte count.
3648 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3649 "falling back to the normal read: %s\n",
3650 fsp_str_dbg(fsp)));
3651 goto normal_read;
3654 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3655 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3657 /* Deal with possible short send. */
3658 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3659 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3661 /* No outbuf here means successful sendfile. */
3662 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3663 SMB_PERFCOUNT_END(&req->pcd);
3664 goto strict_unlock;
3667 normal_read:
3669 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3670 uint8 headerbuf[smb_size + 2*12];
3672 construct_reply_common_req(req, (char *)headerbuf);
3673 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3675 /* Send out the header. */
3676 if (write_data(req->sconn->sock, (char *)headerbuf,
3677 sizeof(headerbuf)) != sizeof(headerbuf)) {
3679 char addr[INET6_ADDRSTRLEN];
3681 * Try and give an error message saying what
3682 * client failed.
3684 DEBUG(0, ("write_data failed for client %s. "
3685 "Error %s\n",
3686 get_peer_addr(req->sconn->sock, addr,
3687 sizeof(addr)),
3688 strerror(errno)));
3690 DEBUG(0,("send_file_readX: write_data failed for file "
3691 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3692 strerror(errno)));
3693 exit_server_cleanly("send_file_readX sendfile failed");
3695 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3696 if (nread == -1) {
3697 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3698 "file %s (%s).\n", fsp_str_dbg(fsp),
3699 strerror(errno)));
3700 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3702 goto strict_unlock;
3705 nosendfile_read:
3707 reply_outbuf(req, 12, smb_maxcnt);
3709 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3710 saved_errno = errno;
3712 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3714 if (nread < 0) {
3715 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3716 return;
3719 setup_readX_header(req, (char *)req->outbuf, nread);
3721 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3722 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3724 chain_reply(req);
3725 return;
3727 strict_unlock:
3728 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3729 TALLOC_FREE(req->outbuf);
3730 return;
3733 /****************************************************************************
3734 Reply to a read and X.
3735 ****************************************************************************/
3737 void reply_read_and_X(struct smb_request *req)
3739 connection_struct *conn = req->conn;
3740 files_struct *fsp;
3741 SMB_OFF_T startpos;
3742 size_t smb_maxcnt;
3743 bool big_readX = False;
3744 #if 0
3745 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3746 #endif
3748 START_PROFILE(SMBreadX);
3750 if ((req->wct != 10) && (req->wct != 12)) {
3751 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3752 return;
3755 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3756 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3757 smb_maxcnt = SVAL(req->vwv+5, 0);
3759 /* If it's an IPC, pass off the pipe handler. */
3760 if (IS_IPC(conn)) {
3761 reply_pipe_read_and_X(req);
3762 END_PROFILE(SMBreadX);
3763 return;
3766 if (!check_fsp(conn, req, fsp)) {
3767 END_PROFILE(SMBreadX);
3768 return;
3771 if (!CHECK_READ(fsp,req)) {
3772 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3773 END_PROFILE(SMBreadX);
3774 return;
3777 if (global_client_caps & CAP_LARGE_READX) {
3778 size_t upper_size = SVAL(req->vwv+7, 0);
3779 smb_maxcnt |= (upper_size<<16);
3780 if (upper_size > 1) {
3781 /* Can't do this on a chained packet. */
3782 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3783 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3784 END_PROFILE(SMBreadX);
3785 return;
3787 /* We currently don't do this on signed or sealed data. */
3788 if (srv_is_signing_active(req->sconn) ||
3789 is_encrypted_packet(req->inbuf)) {
3790 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3791 END_PROFILE(SMBreadX);
3792 return;
3794 /* Is there room in the reply for this data ? */
3795 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3796 reply_nterror(req,
3797 NT_STATUS_INVALID_PARAMETER);
3798 END_PROFILE(SMBreadX);
3799 return;
3801 big_readX = True;
3805 if (req->wct == 12) {
3806 #ifdef LARGE_SMB_OFF_T
3808 * This is a large offset (64 bit) read.
3810 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3812 #else /* !LARGE_SMB_OFF_T */
3815 * Ensure we haven't been sent a >32 bit offset.
3818 if(IVAL(req->vwv+10, 0) != 0) {
3819 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3820 "used and we don't support 64 bit offsets.\n",
3821 (unsigned int)IVAL(req->vwv+10, 0) ));
3822 END_PROFILE(SMBreadX);
3823 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3824 return;
3827 #endif /* LARGE_SMB_OFF_T */
3831 if (!big_readX) {
3832 NTSTATUS status = schedule_aio_read_and_X(conn,
3833 req,
3834 fsp,
3835 startpos,
3836 smb_maxcnt);
3837 if (NT_STATUS_IS_OK(status)) {
3838 /* Read scheduled - we're done. */
3839 goto out;
3841 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3842 /* Real error - report to client. */
3843 END_PROFILE(SMBreadX);
3844 reply_nterror(req, status);
3845 return;
3847 /* NT_STATUS_RETRY - fall back to sync read. */
3850 smbd_lock_socket(req->sconn);
3851 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3852 smbd_unlock_socket(req->sconn);
3854 out:
3855 END_PROFILE(SMBreadX);
3856 return;
3859 /****************************************************************************
3860 Error replies to writebraw must have smb_wct == 1. Fix this up.
3861 ****************************************************************************/
3863 void error_to_writebrawerr(struct smb_request *req)
3865 uint8 *old_outbuf = req->outbuf;
3867 reply_outbuf(req, 1, 0);
3869 memcpy(req->outbuf, old_outbuf, smb_size);
3870 TALLOC_FREE(old_outbuf);
3873 /****************************************************************************
3874 Read 4 bytes of a smb packet and return the smb length of the packet.
3875 Store the result in the buffer. This version of the function will
3876 never return a session keepalive (length of zero).
3877 Timeout is in milliseconds.
3878 ****************************************************************************/
3880 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3881 size_t *len)
3883 uint8_t msgtype = NBSSkeepalive;
3885 while (msgtype == NBSSkeepalive) {
3886 NTSTATUS status;
3888 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3889 len);
3890 if (!NT_STATUS_IS_OK(status)) {
3891 char addr[INET6_ADDRSTRLEN];
3892 /* Try and give an error message
3893 * saying what client failed. */
3894 DEBUG(0, ("read_fd_with_timeout failed for "
3895 "client %s read error = %s.\n",
3896 get_peer_addr(fd,addr,sizeof(addr)),
3897 nt_errstr(status)));
3898 return status;
3901 msgtype = CVAL(inbuf, 0);
3904 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3905 (unsigned long)len));
3907 return NT_STATUS_OK;
3910 /****************************************************************************
3911 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3912 ****************************************************************************/
3914 void reply_writebraw(struct smb_request *req)
3916 connection_struct *conn = req->conn;
3917 char *buf = NULL;
3918 ssize_t nwritten=0;
3919 ssize_t total_written=0;
3920 size_t numtowrite=0;
3921 size_t tcount;
3922 SMB_OFF_T startpos;
3923 const char *data=NULL;
3924 bool write_through;
3925 files_struct *fsp;
3926 struct lock_struct lock;
3927 NTSTATUS status;
3929 START_PROFILE(SMBwritebraw);
3932 * If we ever reply with an error, it must have the SMB command
3933 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3934 * we're finished.
3936 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3938 if (srv_is_signing_active(req->sconn)) {
3939 END_PROFILE(SMBwritebraw);
3940 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3941 "raw reads/writes are disallowed.");
3944 if (req->wct < 12) {
3945 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3946 error_to_writebrawerr(req);
3947 END_PROFILE(SMBwritebraw);
3948 return;
3951 if (req->sconn->smb1.echo_handler.trusted_fde) {
3952 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3953 "'async smb echo handler = yes'\n"));
3954 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3955 error_to_writebrawerr(req);
3956 END_PROFILE(SMBwritebraw);
3957 return;
3960 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3961 if (!check_fsp(conn, req, fsp)) {
3962 error_to_writebrawerr(req);
3963 END_PROFILE(SMBwritebraw);
3964 return;
3967 if (!CHECK_WRITE(fsp)) {
3968 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3969 error_to_writebrawerr(req);
3970 END_PROFILE(SMBwritebraw);
3971 return;
3974 tcount = IVAL(req->vwv+1, 0);
3975 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3976 write_through = BITSETW(req->vwv+7,0);
3978 /* We have to deal with slightly different formats depending
3979 on whether we are using the core+ or lanman1.0 protocol */
3981 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3982 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
3983 data = smb_buf_const(req->inbuf);
3984 } else {
3985 numtowrite = SVAL(req->vwv+10, 0);
3986 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3989 /* Ensure we don't write bytes past the end of this packet. */
3990 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3991 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3992 error_to_writebrawerr(req);
3993 END_PROFILE(SMBwritebraw);
3994 return;
3997 if (!fsp->print_file) {
3998 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3999 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4000 &lock);
4002 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4003 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4004 error_to_writebrawerr(req);
4005 END_PROFILE(SMBwritebraw);
4006 return;
4010 if (numtowrite>0) {
4011 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4014 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
4015 "wrote=%d sync=%d\n",
4016 fsp->fnum, (double)startpos, (int)numtowrite,
4017 (int)nwritten, (int)write_through));
4019 if (nwritten < (ssize_t)numtowrite) {
4020 reply_nterror(req, NT_STATUS_DISK_FULL);
4021 error_to_writebrawerr(req);
4022 goto strict_unlock;
4025 total_written = nwritten;
4027 /* Allocate a buffer of 64k + length. */
4028 buf = talloc_array(NULL, char, 65540);
4029 if (!buf) {
4030 reply_nterror(req, NT_STATUS_NO_MEMORY);
4031 error_to_writebrawerr(req);
4032 goto strict_unlock;
4035 /* Return a SMBwritebraw message to the redirector to tell
4036 * it to send more bytes */
4038 memcpy(buf, req->inbuf, smb_size);
4039 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4040 SCVAL(buf,smb_com,SMBwritebraw);
4041 SSVALS(buf,smb_vwv0,0xFFFF);
4042 show_msg(buf);
4043 if (!srv_send_smb(req->sconn,
4044 buf,
4045 false, 0, /* no signing */
4046 IS_CONN_ENCRYPTED(conn),
4047 &req->pcd)) {
4048 exit_server_cleanly("reply_writebraw: srv_send_smb "
4049 "failed.");
4052 /* Now read the raw data into the buffer and write it */
4053 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4054 &numtowrite);
4055 if (!NT_STATUS_IS_OK(status)) {
4056 exit_server_cleanly("secondary writebraw failed");
4059 /* Set up outbuf to return the correct size */
4060 reply_outbuf(req, 1, 0);
4062 if (numtowrite != 0) {
4064 if (numtowrite > 0xFFFF) {
4065 DEBUG(0,("reply_writebraw: Oversize secondary write "
4066 "raw requested (%u). Terminating\n",
4067 (unsigned int)numtowrite ));
4068 exit_server_cleanly("secondary writebraw failed");
4071 if (tcount > nwritten+numtowrite) {
4072 DEBUG(3,("reply_writebraw: Client overestimated the "
4073 "write %d %d %d\n",
4074 (int)tcount,(int)nwritten,(int)numtowrite));
4077 status = read_data(req->sconn->sock, buf+4, numtowrite);
4079 if (!NT_STATUS_IS_OK(status)) {
4080 char addr[INET6_ADDRSTRLEN];
4081 /* Try and give an error message
4082 * saying what client failed. */
4083 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4084 "raw read failed (%s) for client %s. "
4085 "Terminating\n", nt_errstr(status),
4086 get_peer_addr(req->sconn->sock, addr,
4087 sizeof(addr))));
4088 exit_server_cleanly("secondary writebraw failed");
4091 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4092 if (nwritten == -1) {
4093 TALLOC_FREE(buf);
4094 reply_nterror(req, map_nt_error_from_unix(errno));
4095 error_to_writebrawerr(req);
4096 goto strict_unlock;
4099 if (nwritten < (ssize_t)numtowrite) {
4100 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4101 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4104 if (nwritten > 0) {
4105 total_written += nwritten;
4109 TALLOC_FREE(buf);
4110 SSVAL(req->outbuf,smb_vwv0,total_written);
4112 status = sync_file(conn, fsp, write_through);
4113 if (!NT_STATUS_IS_OK(status)) {
4114 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4115 fsp_str_dbg(fsp), nt_errstr(status)));
4116 reply_nterror(req, status);
4117 error_to_writebrawerr(req);
4118 goto strict_unlock;
4121 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4122 "wrote=%d\n",
4123 fsp->fnum, (double)startpos, (int)numtowrite,
4124 (int)total_written));
4126 if (!fsp->print_file) {
4127 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4130 /* We won't return a status if write through is not selected - this
4131 * follows what WfWg does */
4132 END_PROFILE(SMBwritebraw);
4134 if (!write_through && total_written==tcount) {
4136 #if RABBIT_PELLET_FIX
4138 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4139 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4140 * JRA.
4142 if (!send_keepalive(req->sconn->sock)) {
4143 exit_server_cleanly("reply_writebraw: send of "
4144 "keepalive failed");
4146 #endif
4147 TALLOC_FREE(req->outbuf);
4149 return;
4151 strict_unlock:
4152 if (!fsp->print_file) {
4153 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4156 END_PROFILE(SMBwritebraw);
4157 return;
4160 #undef DBGC_CLASS
4161 #define DBGC_CLASS DBGC_LOCKING
4163 /****************************************************************************
4164 Reply to a writeunlock (core+).
4165 ****************************************************************************/
4167 void reply_writeunlock(struct smb_request *req)
4169 connection_struct *conn = req->conn;
4170 ssize_t nwritten = -1;
4171 size_t numtowrite;
4172 SMB_OFF_T startpos;
4173 const char *data;
4174 NTSTATUS status = NT_STATUS_OK;
4175 files_struct *fsp;
4176 struct lock_struct lock;
4177 int saved_errno = 0;
4179 START_PROFILE(SMBwriteunlock);
4181 if (req->wct < 5) {
4182 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4183 END_PROFILE(SMBwriteunlock);
4184 return;
4187 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4189 if (!check_fsp(conn, req, fsp)) {
4190 END_PROFILE(SMBwriteunlock);
4191 return;
4194 if (!CHECK_WRITE(fsp)) {
4195 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4196 END_PROFILE(SMBwriteunlock);
4197 return;
4200 numtowrite = SVAL(req->vwv+1, 0);
4201 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4202 data = (const char *)req->buf + 3;
4204 if (!fsp->print_file && numtowrite > 0) {
4205 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4206 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4207 &lock);
4209 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4210 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4211 END_PROFILE(SMBwriteunlock);
4212 return;
4216 /* The special X/Open SMB protocol handling of
4217 zero length writes is *NOT* done for
4218 this call */
4219 if(numtowrite == 0) {
4220 nwritten = 0;
4221 } else {
4222 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4223 saved_errno = errno;
4226 status = sync_file(conn, fsp, False /* write through */);
4227 if (!NT_STATUS_IS_OK(status)) {
4228 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4229 fsp_str_dbg(fsp), nt_errstr(status)));
4230 reply_nterror(req, status);
4231 goto strict_unlock;
4234 if(nwritten < 0) {
4235 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4236 goto strict_unlock;
4239 if((nwritten < numtowrite) && (numtowrite != 0)) {
4240 reply_nterror(req, NT_STATUS_DISK_FULL);
4241 goto strict_unlock;
4244 if (numtowrite && !fsp->print_file) {
4245 status = do_unlock(req->sconn->msg_ctx,
4246 fsp,
4247 (uint64_t)req->smbpid,
4248 (uint64_t)numtowrite,
4249 (uint64_t)startpos,
4250 WINDOWS_LOCK);
4252 if (NT_STATUS_V(status)) {
4253 reply_nterror(req, status);
4254 goto strict_unlock;
4258 reply_outbuf(req, 1, 0);
4260 SSVAL(req->outbuf,smb_vwv0,nwritten);
4262 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4263 fsp->fnum, (int)numtowrite, (int)nwritten));
4265 strict_unlock:
4266 if (numtowrite && !fsp->print_file) {
4267 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4270 END_PROFILE(SMBwriteunlock);
4271 return;
4274 #undef DBGC_CLASS
4275 #define DBGC_CLASS DBGC_ALL
4277 /****************************************************************************
4278 Reply to a write.
4279 ****************************************************************************/
4281 void reply_write(struct smb_request *req)
4283 connection_struct *conn = req->conn;
4284 size_t numtowrite;
4285 ssize_t nwritten = -1;
4286 SMB_OFF_T startpos;
4287 const char *data;
4288 files_struct *fsp;
4289 struct lock_struct lock;
4290 NTSTATUS status;
4291 int saved_errno = 0;
4293 START_PROFILE(SMBwrite);
4295 if (req->wct < 5) {
4296 END_PROFILE(SMBwrite);
4297 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4298 return;
4301 /* If it's an IPC, pass off the pipe handler. */
4302 if (IS_IPC(conn)) {
4303 reply_pipe_write(req);
4304 END_PROFILE(SMBwrite);
4305 return;
4308 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4310 if (!check_fsp(conn, req, fsp)) {
4311 END_PROFILE(SMBwrite);
4312 return;
4315 if (!CHECK_WRITE(fsp)) {
4316 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4317 END_PROFILE(SMBwrite);
4318 return;
4321 numtowrite = SVAL(req->vwv+1, 0);
4322 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4323 data = (const char *)req->buf + 3;
4325 if (!fsp->print_file) {
4326 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4327 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4328 &lock);
4330 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4331 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4332 END_PROFILE(SMBwrite);
4333 return;
4338 * X/Open SMB protocol says that if smb_vwv1 is
4339 * zero then the file size should be extended or
4340 * truncated to the size given in smb_vwv[2-3].
4343 if(numtowrite == 0) {
4345 * This is actually an allocate call, and set EOF. JRA.
4347 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4348 if (nwritten < 0) {
4349 reply_nterror(req, NT_STATUS_DISK_FULL);
4350 goto strict_unlock;
4352 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4353 if (nwritten < 0) {
4354 reply_nterror(req, NT_STATUS_DISK_FULL);
4355 goto strict_unlock;
4357 trigger_write_time_update_immediate(fsp);
4358 } else {
4359 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4362 status = sync_file(conn, fsp, False);
4363 if (!NT_STATUS_IS_OK(status)) {
4364 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4365 fsp_str_dbg(fsp), nt_errstr(status)));
4366 reply_nterror(req, status);
4367 goto strict_unlock;
4370 if(nwritten < 0) {
4371 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4372 goto strict_unlock;
4375 if((nwritten == 0) && (numtowrite != 0)) {
4376 reply_nterror(req, NT_STATUS_DISK_FULL);
4377 goto strict_unlock;
4380 reply_outbuf(req, 1, 0);
4382 SSVAL(req->outbuf,smb_vwv0,nwritten);
4384 if (nwritten < (ssize_t)numtowrite) {
4385 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4386 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4389 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4391 strict_unlock:
4392 if (!fsp->print_file) {
4393 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4396 END_PROFILE(SMBwrite);
4397 return;
4400 /****************************************************************************
4401 Ensure a buffer is a valid writeX for recvfile purposes.
4402 ****************************************************************************/
4404 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4405 (2*14) + /* word count (including bcc) */ \
4406 1 /* pad byte */)
4408 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4409 const uint8_t *inbuf)
4411 size_t numtowrite;
4412 connection_struct *conn = NULL;
4413 unsigned int doff = 0;
4414 size_t len = smb_len_large(inbuf);
4416 if (is_encrypted_packet(inbuf)) {
4417 /* Can't do this on encrypted
4418 * connections. */
4419 return false;
4422 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4423 return false;
4426 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4427 CVAL(inbuf,smb_wct) != 14) {
4428 DEBUG(10,("is_valid_writeX_buffer: chained or "
4429 "invalid word length.\n"));
4430 return false;
4433 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4434 if (conn == NULL) {
4435 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4436 return false;
4438 if (IS_IPC(conn)) {
4439 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4440 return false;
4442 if (IS_PRINT(conn)) {
4443 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4444 return false;
4446 doff = SVAL(inbuf,smb_vwv11);
4448 numtowrite = SVAL(inbuf,smb_vwv10);
4450 if (len > doff && len - doff > 0xFFFF) {
4451 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4454 if (numtowrite == 0) {
4455 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4456 return false;
4459 /* Ensure the sizes match up. */
4460 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4461 /* no pad byte...old smbclient :-( */
4462 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4463 (unsigned int)doff,
4464 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4465 return false;
4468 if (len - doff != numtowrite) {
4469 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4470 "len = %u, doff = %u, numtowrite = %u\n",
4471 (unsigned int)len,
4472 (unsigned int)doff,
4473 (unsigned int)numtowrite ));
4474 return false;
4477 DEBUG(10,("is_valid_writeX_buffer: true "
4478 "len = %u, doff = %u, numtowrite = %u\n",
4479 (unsigned int)len,
4480 (unsigned int)doff,
4481 (unsigned int)numtowrite ));
4483 return true;
4486 /****************************************************************************
4487 Reply to a write and X.
4488 ****************************************************************************/
4490 void reply_write_and_X(struct smb_request *req)
4492 connection_struct *conn = req->conn;
4493 files_struct *fsp;
4494 struct lock_struct lock;
4495 SMB_OFF_T startpos;
4496 size_t numtowrite;
4497 bool write_through;
4498 ssize_t nwritten;
4499 unsigned int smb_doff;
4500 unsigned int smblen;
4501 const char *data;
4502 NTSTATUS status;
4503 int saved_errno = 0;
4505 START_PROFILE(SMBwriteX);
4507 if ((req->wct != 12) && (req->wct != 14)) {
4508 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4509 END_PROFILE(SMBwriteX);
4510 return;
4513 numtowrite = SVAL(req->vwv+10, 0);
4514 smb_doff = SVAL(req->vwv+11, 0);
4515 smblen = smb_len(req->inbuf);
4517 if (req->unread_bytes > 0xFFFF ||
4518 (smblen > smb_doff &&
4519 smblen - smb_doff > 0xFFFF)) {
4520 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4523 if (req->unread_bytes) {
4524 /* Can't do a recvfile write on IPC$ */
4525 if (IS_IPC(conn)) {
4526 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4527 END_PROFILE(SMBwriteX);
4528 return;
4530 if (numtowrite != req->unread_bytes) {
4531 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4532 END_PROFILE(SMBwriteX);
4533 return;
4535 } else {
4536 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4537 smb_doff + numtowrite > smblen) {
4538 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4539 END_PROFILE(SMBwriteX);
4540 return;
4544 /* If it's an IPC, pass off the pipe handler. */
4545 if (IS_IPC(conn)) {
4546 if (req->unread_bytes) {
4547 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4548 END_PROFILE(SMBwriteX);
4549 return;
4551 reply_pipe_write_and_X(req);
4552 END_PROFILE(SMBwriteX);
4553 return;
4556 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4557 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4558 write_through = BITSETW(req->vwv+7,0);
4560 if (!check_fsp(conn, req, fsp)) {
4561 END_PROFILE(SMBwriteX);
4562 return;
4565 if (!CHECK_WRITE(fsp)) {
4566 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4567 END_PROFILE(SMBwriteX);
4568 return;
4571 data = smb_base(req->inbuf) + smb_doff;
4573 if(req->wct == 14) {
4574 #ifdef LARGE_SMB_OFF_T
4576 * This is a large offset (64 bit) write.
4578 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4580 #else /* !LARGE_SMB_OFF_T */
4583 * Ensure we haven't been sent a >32 bit offset.
4586 if(IVAL(req->vwv+12, 0) != 0) {
4587 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4588 "used and we don't support 64 bit offsets.\n",
4589 (unsigned int)IVAL(req->vwv+12, 0) ));
4590 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4591 END_PROFILE(SMBwriteX);
4592 return;
4595 #endif /* LARGE_SMB_OFF_T */
4598 /* X/Open SMB protocol says that, unlike SMBwrite
4599 if the length is zero then NO truncation is
4600 done, just a write of zero. To truncate a file,
4601 use SMBwrite. */
4603 if(numtowrite == 0) {
4604 nwritten = 0;
4605 } else {
4606 if (req->unread_bytes == 0) {
4607 status = schedule_aio_write_and_X(conn,
4608 req,
4609 fsp,
4610 data,
4611 startpos,
4612 numtowrite);
4614 if (NT_STATUS_IS_OK(status)) {
4615 /* write scheduled - we're done. */
4616 goto out;
4618 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4619 /* Real error - report to client. */
4620 reply_nterror(req, status);
4621 goto out;
4623 /* NT_STATUS_RETRY - fall through to sync write. */
4626 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4627 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4628 &lock);
4630 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4631 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4632 goto out;
4635 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4636 saved_errno = errno;
4638 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4641 if(nwritten < 0) {
4642 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4643 goto out;
4646 if((nwritten == 0) && (numtowrite != 0)) {
4647 reply_nterror(req, NT_STATUS_DISK_FULL);
4648 goto out;
4651 reply_outbuf(req, 6, 0);
4652 SSVAL(req->outbuf,smb_vwv2,nwritten);
4653 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4655 if (nwritten < (ssize_t)numtowrite) {
4656 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4657 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4660 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4661 fsp->fnum, (int)numtowrite, (int)nwritten));
4663 status = sync_file(conn, fsp, write_through);
4664 if (!NT_STATUS_IS_OK(status)) {
4665 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4666 fsp_str_dbg(fsp), nt_errstr(status)));
4667 reply_nterror(req, status);
4668 goto out;
4671 END_PROFILE(SMBwriteX);
4672 chain_reply(req);
4673 return;
4675 out:
4676 END_PROFILE(SMBwriteX);
4677 return;
4680 /****************************************************************************
4681 Reply to a lseek.
4682 ****************************************************************************/
4684 void reply_lseek(struct smb_request *req)
4686 connection_struct *conn = req->conn;
4687 SMB_OFF_T startpos;
4688 SMB_OFF_T res= -1;
4689 int mode,umode;
4690 files_struct *fsp;
4692 START_PROFILE(SMBlseek);
4694 if (req->wct < 4) {
4695 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4696 END_PROFILE(SMBlseek);
4697 return;
4700 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4702 if (!check_fsp(conn, req, fsp)) {
4703 return;
4706 flush_write_cache(fsp, SEEK_FLUSH);
4708 mode = SVAL(req->vwv+1, 0) & 3;
4709 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4710 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4712 switch (mode) {
4713 case 0:
4714 umode = SEEK_SET;
4715 res = startpos;
4716 break;
4717 case 1:
4718 umode = SEEK_CUR;
4719 res = fsp->fh->pos + startpos;
4720 break;
4721 case 2:
4722 umode = SEEK_END;
4723 break;
4724 default:
4725 umode = SEEK_SET;
4726 res = startpos;
4727 break;
4730 if (umode == SEEK_END) {
4731 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4732 if(errno == EINVAL) {
4733 SMB_OFF_T current_pos = startpos;
4735 if(fsp_stat(fsp) == -1) {
4736 reply_nterror(req,
4737 map_nt_error_from_unix(errno));
4738 END_PROFILE(SMBlseek);
4739 return;
4742 current_pos += fsp->fsp_name->st.st_ex_size;
4743 if(current_pos < 0)
4744 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4748 if(res == -1) {
4749 reply_nterror(req, map_nt_error_from_unix(errno));
4750 END_PROFILE(SMBlseek);
4751 return;
4755 fsp->fh->pos = res;
4757 reply_outbuf(req, 2, 0);
4758 SIVAL(req->outbuf,smb_vwv0,res);
4760 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4761 fsp->fnum, (double)startpos, (double)res, mode));
4763 END_PROFILE(SMBlseek);
4764 return;
4767 /****************************************************************************
4768 Reply to a flush.
4769 ****************************************************************************/
4771 void reply_flush(struct smb_request *req)
4773 connection_struct *conn = req->conn;
4774 uint16 fnum;
4775 files_struct *fsp;
4777 START_PROFILE(SMBflush);
4779 if (req->wct < 1) {
4780 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4781 return;
4784 fnum = SVAL(req->vwv+0, 0);
4785 fsp = file_fsp(req, fnum);
4787 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4788 return;
4791 if (!fsp) {
4792 file_sync_all(conn);
4793 } else {
4794 NTSTATUS status = sync_file(conn, fsp, True);
4795 if (!NT_STATUS_IS_OK(status)) {
4796 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4797 fsp_str_dbg(fsp), nt_errstr(status)));
4798 reply_nterror(req, status);
4799 END_PROFILE(SMBflush);
4800 return;
4804 reply_outbuf(req, 0, 0);
4806 DEBUG(3,("flush\n"));
4807 END_PROFILE(SMBflush);
4808 return;
4811 /****************************************************************************
4812 Reply to a exit.
4813 conn POINTER CAN BE NULL HERE !
4814 ****************************************************************************/
4816 void reply_exit(struct smb_request *req)
4818 START_PROFILE(SMBexit);
4820 file_close_pid(req->sconn, req->smbpid, req->vuid);
4822 reply_outbuf(req, 0, 0);
4824 DEBUG(3,("exit\n"));
4826 END_PROFILE(SMBexit);
4827 return;
4830 /****************************************************************************
4831 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4832 ****************************************************************************/
4834 void reply_close(struct smb_request *req)
4836 connection_struct *conn = req->conn;
4837 NTSTATUS status = NT_STATUS_OK;
4838 files_struct *fsp = NULL;
4839 START_PROFILE(SMBclose);
4841 if (req->wct < 3) {
4842 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4843 END_PROFILE(SMBclose);
4844 return;
4847 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4850 * We can only use check_fsp if we know it's not a directory.
4853 if (!check_fsp_open(conn, req, fsp)) {
4854 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4855 END_PROFILE(SMBclose);
4856 return;
4859 if(fsp->is_directory) {
4861 * Special case - close NT SMB directory handle.
4863 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4864 status = close_file(req, fsp, NORMAL_CLOSE);
4865 } else {
4866 time_t t;
4868 * Close ordinary file.
4871 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4872 fsp->fh->fd, fsp->fnum,
4873 conn->num_files_open));
4876 * Take care of any time sent in the close.
4879 t = srv_make_unix_date3(req->vwv+1);
4880 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4883 * close_file() returns the unix errno if an error
4884 * was detected on close - normally this is due to
4885 * a disk full error. If not then it was probably an I/O error.
4888 status = close_file(req, fsp, NORMAL_CLOSE);
4891 if (!NT_STATUS_IS_OK(status)) {
4892 reply_nterror(req, status);
4893 END_PROFILE(SMBclose);
4894 return;
4897 reply_outbuf(req, 0, 0);
4898 END_PROFILE(SMBclose);
4899 return;
4902 /****************************************************************************
4903 Reply to a writeclose (Core+ protocol).
4904 ****************************************************************************/
4906 void reply_writeclose(struct smb_request *req)
4908 connection_struct *conn = req->conn;
4909 size_t numtowrite;
4910 ssize_t nwritten = -1;
4911 NTSTATUS close_status = NT_STATUS_OK;
4912 SMB_OFF_T startpos;
4913 const char *data;
4914 struct timespec mtime;
4915 files_struct *fsp;
4916 struct lock_struct lock;
4918 START_PROFILE(SMBwriteclose);
4920 if (req->wct < 6) {
4921 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4922 END_PROFILE(SMBwriteclose);
4923 return;
4926 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4928 if (!check_fsp(conn, req, fsp)) {
4929 END_PROFILE(SMBwriteclose);
4930 return;
4932 if (!CHECK_WRITE(fsp)) {
4933 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4934 END_PROFILE(SMBwriteclose);
4935 return;
4938 numtowrite = SVAL(req->vwv+1, 0);
4939 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4940 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4941 data = (const char *)req->buf + 1;
4943 if (!fsp->print_file) {
4944 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4945 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4946 &lock);
4948 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4949 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4950 END_PROFILE(SMBwriteclose);
4951 return;
4955 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4957 set_close_write_time(fsp, mtime);
4960 * More insanity. W2K only closes the file if writelen > 0.
4961 * JRA.
4964 if (numtowrite) {
4965 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4966 "file %s\n", fsp_str_dbg(fsp)));
4967 close_status = close_file(req, fsp, NORMAL_CLOSE);
4970 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4971 fsp->fnum, (int)numtowrite, (int)nwritten,
4972 conn->num_files_open));
4974 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4975 reply_nterror(req, NT_STATUS_DISK_FULL);
4976 goto strict_unlock;
4979 if(!NT_STATUS_IS_OK(close_status)) {
4980 reply_nterror(req, close_status);
4981 goto strict_unlock;
4984 reply_outbuf(req, 1, 0);
4986 SSVAL(req->outbuf,smb_vwv0,nwritten);
4988 strict_unlock:
4989 if (numtowrite && !fsp->print_file) {
4990 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4993 END_PROFILE(SMBwriteclose);
4994 return;
4997 #undef DBGC_CLASS
4998 #define DBGC_CLASS DBGC_LOCKING
5000 /****************************************************************************
5001 Reply to a lock.
5002 ****************************************************************************/
5004 void reply_lock(struct smb_request *req)
5006 connection_struct *conn = req->conn;
5007 uint64_t count,offset;
5008 NTSTATUS status;
5009 files_struct *fsp;
5010 struct byte_range_lock *br_lck = NULL;
5012 START_PROFILE(SMBlock);
5014 if (req->wct < 5) {
5015 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5016 END_PROFILE(SMBlock);
5017 return;
5020 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5022 if (!check_fsp(conn, req, fsp)) {
5023 END_PROFILE(SMBlock);
5024 return;
5027 count = (uint64_t)IVAL(req->vwv+1, 0);
5028 offset = (uint64_t)IVAL(req->vwv+3, 0);
5030 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5031 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5033 br_lck = do_lock(req->sconn->msg_ctx,
5034 fsp,
5035 (uint64_t)req->smbpid,
5036 count,
5037 offset,
5038 WRITE_LOCK,
5039 WINDOWS_LOCK,
5040 False, /* Non-blocking lock. */
5041 &status,
5042 NULL,
5043 NULL);
5045 TALLOC_FREE(br_lck);
5047 if (NT_STATUS_V(status)) {
5048 reply_nterror(req, status);
5049 END_PROFILE(SMBlock);
5050 return;
5053 reply_outbuf(req, 0, 0);
5055 END_PROFILE(SMBlock);
5056 return;
5059 /****************************************************************************
5060 Reply to a unlock.
5061 ****************************************************************************/
5063 void reply_unlock(struct smb_request *req)
5065 connection_struct *conn = req->conn;
5066 uint64_t count,offset;
5067 NTSTATUS status;
5068 files_struct *fsp;
5070 START_PROFILE(SMBunlock);
5072 if (req->wct < 5) {
5073 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5074 END_PROFILE(SMBunlock);
5075 return;
5078 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5080 if (!check_fsp(conn, req, fsp)) {
5081 END_PROFILE(SMBunlock);
5082 return;
5085 count = (uint64_t)IVAL(req->vwv+1, 0);
5086 offset = (uint64_t)IVAL(req->vwv+3, 0);
5088 status = do_unlock(req->sconn->msg_ctx,
5089 fsp,
5090 (uint64_t)req->smbpid,
5091 count,
5092 offset,
5093 WINDOWS_LOCK);
5095 if (NT_STATUS_V(status)) {
5096 reply_nterror(req, status);
5097 END_PROFILE(SMBunlock);
5098 return;
5101 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5102 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5104 reply_outbuf(req, 0, 0);
5106 END_PROFILE(SMBunlock);
5107 return;
5110 #undef DBGC_CLASS
5111 #define DBGC_CLASS DBGC_ALL
5113 /****************************************************************************
5114 Reply to a tdis.
5115 conn POINTER CAN BE NULL HERE !
5116 ****************************************************************************/
5118 void reply_tdis(struct smb_request *req)
5120 connection_struct *conn = req->conn;
5121 START_PROFILE(SMBtdis);
5123 if (!conn) {
5124 DEBUG(4,("Invalid connection in tdis\n"));
5125 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5126 END_PROFILE(SMBtdis);
5127 return;
5130 conn->used = False;
5132 close_cnum(conn,req->vuid);
5133 req->conn = NULL;
5135 reply_outbuf(req, 0, 0);
5136 END_PROFILE(SMBtdis);
5137 return;
5140 /****************************************************************************
5141 Reply to a echo.
5142 conn POINTER CAN BE NULL HERE !
5143 ****************************************************************************/
5145 void reply_echo(struct smb_request *req)
5147 connection_struct *conn = req->conn;
5148 struct smb_perfcount_data local_pcd;
5149 struct smb_perfcount_data *cur_pcd;
5150 int smb_reverb;
5151 int seq_num;
5153 START_PROFILE(SMBecho);
5155 smb_init_perfcount_data(&local_pcd);
5157 if (req->wct < 1) {
5158 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5159 END_PROFILE(SMBecho);
5160 return;
5163 smb_reverb = SVAL(req->vwv+0, 0);
5165 reply_outbuf(req, 1, req->buflen);
5167 /* copy any incoming data back out */
5168 if (req->buflen > 0) {
5169 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5172 if (smb_reverb > 100) {
5173 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5174 smb_reverb = 100;
5177 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5179 /* this makes sure we catch the request pcd */
5180 if (seq_num == smb_reverb) {
5181 cur_pcd = &req->pcd;
5182 } else {
5183 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5184 cur_pcd = &local_pcd;
5187 SSVAL(req->outbuf,smb_vwv0,seq_num);
5189 show_msg((char *)req->outbuf);
5190 if (!srv_send_smb(req->sconn,
5191 (char *)req->outbuf,
5192 true, req->seqnum+1,
5193 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5194 cur_pcd))
5195 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5198 DEBUG(3,("echo %d times\n", smb_reverb));
5200 TALLOC_FREE(req->outbuf);
5202 END_PROFILE(SMBecho);
5203 return;
5206 /****************************************************************************
5207 Reply to a printopen.
5208 ****************************************************************************/
5210 void reply_printopen(struct smb_request *req)
5212 connection_struct *conn = req->conn;
5213 files_struct *fsp;
5214 NTSTATUS status;
5216 START_PROFILE(SMBsplopen);
5218 if (req->wct < 2) {
5219 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5220 END_PROFILE(SMBsplopen);
5221 return;
5224 if (!CAN_PRINT(conn)) {
5225 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5226 END_PROFILE(SMBsplopen);
5227 return;
5230 status = file_new(req, conn, &fsp);
5231 if(!NT_STATUS_IS_OK(status)) {
5232 reply_nterror(req, status);
5233 END_PROFILE(SMBsplopen);
5234 return;
5237 /* Open for exclusive use, write only. */
5238 status = print_spool_open(fsp, NULL, req->vuid);
5240 if (!NT_STATUS_IS_OK(status)) {
5241 file_free(req, fsp);
5242 reply_nterror(req, status);
5243 END_PROFILE(SMBsplopen);
5244 return;
5247 reply_outbuf(req, 1, 0);
5248 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5250 DEBUG(3,("openprint fd=%d fnum=%d\n",
5251 fsp->fh->fd, fsp->fnum));
5253 END_PROFILE(SMBsplopen);
5254 return;
5257 /****************************************************************************
5258 Reply to a printclose.
5259 ****************************************************************************/
5261 void reply_printclose(struct smb_request *req)
5263 connection_struct *conn = req->conn;
5264 files_struct *fsp;
5265 NTSTATUS status;
5267 START_PROFILE(SMBsplclose);
5269 if (req->wct < 1) {
5270 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5271 END_PROFILE(SMBsplclose);
5272 return;
5275 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5277 if (!check_fsp(conn, req, fsp)) {
5278 END_PROFILE(SMBsplclose);
5279 return;
5282 if (!CAN_PRINT(conn)) {
5283 reply_force_doserror(req, ERRSRV, ERRerror);
5284 END_PROFILE(SMBsplclose);
5285 return;
5288 DEBUG(3,("printclose fd=%d fnum=%d\n",
5289 fsp->fh->fd,fsp->fnum));
5291 status = close_file(req, fsp, NORMAL_CLOSE);
5293 if(!NT_STATUS_IS_OK(status)) {
5294 reply_nterror(req, status);
5295 END_PROFILE(SMBsplclose);
5296 return;
5299 reply_outbuf(req, 0, 0);
5301 END_PROFILE(SMBsplclose);
5302 return;
5305 /****************************************************************************
5306 Reply to a printqueue.
5307 ****************************************************************************/
5309 void reply_printqueue(struct smb_request *req)
5311 connection_struct *conn = req->conn;
5312 int max_count;
5313 int start_index;
5315 START_PROFILE(SMBsplretq);
5317 if (req->wct < 2) {
5318 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5319 END_PROFILE(SMBsplretq);
5320 return;
5323 max_count = SVAL(req->vwv+0, 0);
5324 start_index = SVAL(req->vwv+1, 0);
5326 /* we used to allow the client to get the cnum wrong, but that
5327 is really quite gross and only worked when there was only
5328 one printer - I think we should now only accept it if they
5329 get it right (tridge) */
5330 if (!CAN_PRINT(conn)) {
5331 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5332 END_PROFILE(SMBsplretq);
5333 return;
5336 reply_outbuf(req, 2, 3);
5337 SSVAL(req->outbuf,smb_vwv0,0);
5338 SSVAL(req->outbuf,smb_vwv1,0);
5339 SCVAL(smb_buf(req->outbuf),0,1);
5340 SSVAL(smb_buf(req->outbuf),1,0);
5342 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5343 start_index, max_count));
5346 TALLOC_CTX *mem_ctx = talloc_tos();
5347 NTSTATUS status;
5348 WERROR werr;
5349 const char *sharename = lp_servicename(SNUM(conn));
5350 struct rpc_pipe_client *cli = NULL;
5351 struct dcerpc_binding_handle *b = NULL;
5352 struct policy_handle handle;
5353 struct spoolss_DevmodeContainer devmode_ctr;
5354 union spoolss_JobInfo *info;
5355 uint32_t count;
5356 uint32_t num_to_get;
5357 uint32_t first;
5358 uint32_t i;
5360 ZERO_STRUCT(handle);
5362 status = rpc_pipe_open_interface(conn,
5363 &ndr_table_spoolss.syntax_id,
5364 conn->session_info,
5365 conn->sconn->remote_address,
5366 conn->sconn->msg_ctx,
5367 &cli);
5368 if (!NT_STATUS_IS_OK(status)) {
5369 DEBUG(0, ("reply_printqueue: "
5370 "could not connect to spoolss: %s\n",
5371 nt_errstr(status)));
5372 reply_nterror(req, status);
5373 goto out;
5375 b = cli->binding_handle;
5377 ZERO_STRUCT(devmode_ctr);
5379 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5380 sharename,
5381 NULL, devmode_ctr,
5382 SEC_FLAG_MAXIMUM_ALLOWED,
5383 &handle,
5384 &werr);
5385 if (!NT_STATUS_IS_OK(status)) {
5386 reply_nterror(req, status);
5387 goto out;
5389 if (!W_ERROR_IS_OK(werr)) {
5390 reply_nterror(req, werror_to_ntstatus(werr));
5391 goto out;
5394 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5395 &handle,
5396 0, /* firstjob */
5397 0xff, /* numjobs */
5398 2, /* level */
5399 0, /* offered */
5400 &count,
5401 &info);
5402 if (!W_ERROR_IS_OK(werr)) {
5403 reply_nterror(req, werror_to_ntstatus(werr));
5404 goto out;
5407 if (max_count > 0) {
5408 first = start_index;
5409 } else {
5410 first = start_index + max_count + 1;
5413 if (first >= count) {
5414 num_to_get = first;
5415 } else {
5416 num_to_get = first + MIN(ABS(max_count), count - first);
5419 for (i = first; i < num_to_get; i++) {
5420 char blob[28];
5421 char *p = blob;
5422 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5423 int qstatus;
5424 uint16_t qrapjobid = pjobid_to_rap(sharename,
5425 info[i].info2.job_id);
5427 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5428 qstatus = 2;
5429 } else {
5430 qstatus = 3;
5433 srv_put_dos_date2(p, 0, qtime);
5434 SCVAL(p, 4, qstatus);
5435 SSVAL(p, 5, qrapjobid);
5436 SIVAL(p, 7, info[i].info2.size);
5437 SCVAL(p, 11, 0);
5438 srvstr_push(blob, req->flags2, p+12,
5439 info[i].info2.notify_name, 16, STR_ASCII);
5441 if (message_push_blob(
5442 &req->outbuf,
5443 data_blob_const(
5444 blob, sizeof(blob))) == -1) {
5445 reply_nterror(req, NT_STATUS_NO_MEMORY);
5446 goto out;
5450 if (count > 0) {
5451 SSVAL(req->outbuf,smb_vwv0,count);
5452 SSVAL(req->outbuf,smb_vwv1,
5453 (max_count>0?first+count:first-1));
5454 SCVAL(smb_buf(req->outbuf),0,1);
5455 SSVAL(smb_buf(req->outbuf),1,28*count);
5459 DEBUG(3, ("%u entries returned in queue\n",
5460 (unsigned)count));
5462 out:
5463 if (b && is_valid_policy_hnd(&handle)) {
5464 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5469 END_PROFILE(SMBsplretq);
5470 return;
5473 /****************************************************************************
5474 Reply to a printwrite.
5475 ****************************************************************************/
5477 void reply_printwrite(struct smb_request *req)
5479 connection_struct *conn = req->conn;
5480 int numtowrite;
5481 const char *data;
5482 files_struct *fsp;
5484 START_PROFILE(SMBsplwr);
5486 if (req->wct < 1) {
5487 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5488 END_PROFILE(SMBsplwr);
5489 return;
5492 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5494 if (!check_fsp(conn, req, fsp)) {
5495 END_PROFILE(SMBsplwr);
5496 return;
5499 if (!fsp->print_file) {
5500 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5501 END_PROFILE(SMBsplwr);
5502 return;
5505 if (!CHECK_WRITE(fsp)) {
5506 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5507 END_PROFILE(SMBsplwr);
5508 return;
5511 numtowrite = SVAL(req->buf, 1);
5513 if (req->buflen < numtowrite + 3) {
5514 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5515 END_PROFILE(SMBsplwr);
5516 return;
5519 data = (const char *)req->buf + 3;
5521 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5522 reply_nterror(req, map_nt_error_from_unix(errno));
5523 END_PROFILE(SMBsplwr);
5524 return;
5527 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5529 END_PROFILE(SMBsplwr);
5530 return;
5533 /****************************************************************************
5534 Reply to a mkdir.
5535 ****************************************************************************/
5537 void reply_mkdir(struct smb_request *req)
5539 connection_struct *conn = req->conn;
5540 struct smb_filename *smb_dname = NULL;
5541 char *directory = NULL;
5542 NTSTATUS status;
5543 TALLOC_CTX *ctx = talloc_tos();
5545 START_PROFILE(SMBmkdir);
5547 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5548 STR_TERMINATE, &status);
5549 if (!NT_STATUS_IS_OK(status)) {
5550 reply_nterror(req, status);
5551 goto out;
5554 status = filename_convert(ctx, conn,
5555 req->flags2 & FLAGS2_DFS_PATHNAMES,
5556 directory,
5558 NULL,
5559 &smb_dname);
5560 if (!NT_STATUS_IS_OK(status)) {
5561 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5562 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5563 ERRSRV, ERRbadpath);
5564 goto out;
5566 reply_nterror(req, status);
5567 goto out;
5570 status = create_directory(conn, req, smb_dname);
5572 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5574 if (!NT_STATUS_IS_OK(status)) {
5576 if (!use_nt_status()
5577 && NT_STATUS_EQUAL(status,
5578 NT_STATUS_OBJECT_NAME_COLLISION)) {
5580 * Yes, in the DOS error code case we get a
5581 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5582 * samba4 torture test.
5584 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5587 reply_nterror(req, status);
5588 goto out;
5591 reply_outbuf(req, 0, 0);
5593 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5594 out:
5595 TALLOC_FREE(smb_dname);
5596 END_PROFILE(SMBmkdir);
5597 return;
5600 /****************************************************************************
5601 Reply to a rmdir.
5602 ****************************************************************************/
5604 void reply_rmdir(struct smb_request *req)
5606 connection_struct *conn = req->conn;
5607 struct smb_filename *smb_dname = NULL;
5608 char *directory = NULL;
5609 NTSTATUS status;
5610 TALLOC_CTX *ctx = talloc_tos();
5611 files_struct *fsp = NULL;
5612 int info = 0;
5613 struct smbd_server_connection *sconn = req->sconn;
5615 START_PROFILE(SMBrmdir);
5617 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5618 STR_TERMINATE, &status);
5619 if (!NT_STATUS_IS_OK(status)) {
5620 reply_nterror(req, status);
5621 goto out;
5624 status = filename_convert(ctx, conn,
5625 req->flags2 & FLAGS2_DFS_PATHNAMES,
5626 directory,
5628 NULL,
5629 &smb_dname);
5630 if (!NT_STATUS_IS_OK(status)) {
5631 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5632 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5633 ERRSRV, ERRbadpath);
5634 goto out;
5636 reply_nterror(req, status);
5637 goto out;
5640 if (is_ntfs_stream_smb_fname(smb_dname)) {
5641 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5642 goto out;
5645 status = SMB_VFS_CREATE_FILE(
5646 conn, /* conn */
5647 req, /* req */
5648 0, /* root_dir_fid */
5649 smb_dname, /* fname */
5650 DELETE_ACCESS, /* access_mask */
5651 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5652 FILE_SHARE_DELETE),
5653 FILE_OPEN, /* create_disposition*/
5654 FILE_DIRECTORY_FILE, /* create_options */
5655 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5656 0, /* oplock_request */
5657 0, /* allocation_size */
5658 0, /* private_flags */
5659 NULL, /* sd */
5660 NULL, /* ea_list */
5661 &fsp, /* result */
5662 &info); /* pinfo */
5664 if (!NT_STATUS_IS_OK(status)) {
5665 if (open_was_deferred(req->mid)) {
5666 /* We have re-scheduled this call. */
5667 goto out;
5669 reply_nterror(req, status);
5670 goto out;
5673 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5674 if (!NT_STATUS_IS_OK(status)) {
5675 close_file(req, fsp, ERROR_CLOSE);
5676 reply_nterror(req, status);
5677 goto out;
5680 if (!set_delete_on_close(fsp, true, conn->session_info->unix_token)) {
5681 close_file(req, fsp, ERROR_CLOSE);
5682 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5683 goto out;
5686 status = close_file(req, fsp, NORMAL_CLOSE);
5687 if (!NT_STATUS_IS_OK(status)) {
5688 reply_nterror(req, status);
5689 } else {
5690 reply_outbuf(req, 0, 0);
5693 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5695 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5696 out:
5697 TALLOC_FREE(smb_dname);
5698 END_PROFILE(SMBrmdir);
5699 return;
5702 /*******************************************************************
5703 Resolve wildcards in a filename rename.
5704 ********************************************************************/
5706 static bool resolve_wildcards(TALLOC_CTX *ctx,
5707 const char *name1,
5708 const char *name2,
5709 char **pp_newname)
5711 char *name2_copy = NULL;
5712 char *root1 = NULL;
5713 char *root2 = NULL;
5714 char *ext1 = NULL;
5715 char *ext2 = NULL;
5716 char *p,*p2, *pname1, *pname2;
5718 name2_copy = talloc_strdup(ctx, name2);
5719 if (!name2_copy) {
5720 return False;
5723 pname1 = strrchr_m(name1,'/');
5724 pname2 = strrchr_m(name2_copy,'/');
5726 if (!pname1 || !pname2) {
5727 return False;
5730 /* Truncate the copy of name2 at the last '/' */
5731 *pname2 = '\0';
5733 /* Now go past the '/' */
5734 pname1++;
5735 pname2++;
5737 root1 = talloc_strdup(ctx, pname1);
5738 root2 = talloc_strdup(ctx, pname2);
5740 if (!root1 || !root2) {
5741 return False;
5744 p = strrchr_m(root1,'.');
5745 if (p) {
5746 *p = 0;
5747 ext1 = talloc_strdup(ctx, p+1);
5748 } else {
5749 ext1 = talloc_strdup(ctx, "");
5751 p = strrchr_m(root2,'.');
5752 if (p) {
5753 *p = 0;
5754 ext2 = talloc_strdup(ctx, p+1);
5755 } else {
5756 ext2 = talloc_strdup(ctx, "");
5759 if (!ext1 || !ext2) {
5760 return False;
5763 p = root1;
5764 p2 = root2;
5765 while (*p2) {
5766 if (*p2 == '?') {
5767 /* Hmmm. Should this be mb-aware ? */
5768 *p2 = *p;
5769 p2++;
5770 } else if (*p2 == '*') {
5771 *p2 = '\0';
5772 root2 = talloc_asprintf(ctx, "%s%s",
5773 root2,
5775 if (!root2) {
5776 return False;
5778 break;
5779 } else {
5780 p2++;
5782 if (*p) {
5783 p++;
5787 p = ext1;
5788 p2 = ext2;
5789 while (*p2) {
5790 if (*p2 == '?') {
5791 /* Hmmm. Should this be mb-aware ? */
5792 *p2 = *p;
5793 p2++;
5794 } else if (*p2 == '*') {
5795 *p2 = '\0';
5796 ext2 = talloc_asprintf(ctx, "%s%s",
5797 ext2,
5799 if (!ext2) {
5800 return False;
5802 break;
5803 } else {
5804 p2++;
5806 if (*p) {
5807 p++;
5811 if (*ext2) {
5812 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5813 name2_copy,
5814 root2,
5815 ext2);
5816 } else {
5817 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5818 name2_copy,
5819 root2);
5822 if (!*pp_newname) {
5823 return False;
5826 return True;
5829 /****************************************************************************
5830 Ensure open files have their names updated. Updated to notify other smbd's
5831 asynchronously.
5832 ****************************************************************************/
5834 static void rename_open_files(connection_struct *conn,
5835 struct share_mode_lock *lck,
5836 uint32_t orig_name_hash,
5837 const struct smb_filename *smb_fname_dst)
5839 files_struct *fsp;
5840 bool did_rename = False;
5841 NTSTATUS status;
5842 uint32_t new_name_hash = 0;
5844 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5845 fsp = file_find_di_next(fsp)) {
5846 /* fsp_name is a relative path under the fsp. To change this for other
5847 sharepaths we need to manipulate relative paths. */
5848 /* TODO - create the absolute path and manipulate the newname
5849 relative to the sharepath. */
5850 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5851 continue;
5853 if (fsp->name_hash != orig_name_hash) {
5854 continue;
5856 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5857 "(file_id %s) from %s -> %s\n", fsp->fnum,
5858 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5859 smb_fname_str_dbg(smb_fname_dst)));
5861 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5862 if (NT_STATUS_IS_OK(status)) {
5863 did_rename = True;
5864 new_name_hash = fsp->name_hash;
5868 if (!did_rename) {
5869 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5870 "for %s\n", file_id_string_tos(&lck->id),
5871 smb_fname_str_dbg(smb_fname_dst)));
5874 /* Send messages to all smbd's (not ourself) that the name has changed. */
5875 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5876 orig_name_hash, new_name_hash,
5877 smb_fname_dst);
5881 /****************************************************************************
5882 We need to check if the source path is a parent directory of the destination
5883 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5884 refuse the rename with a sharing violation. Under UNIX the above call can
5885 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5886 probably need to check that the client is a Windows one before disallowing
5887 this as a UNIX client (one with UNIX extensions) can know the source is a
5888 symlink and make this decision intelligently. Found by an excellent bug
5889 report from <AndyLiebman@aol.com>.
5890 ****************************************************************************/
5892 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5893 const struct smb_filename *smb_fname_dst)
5895 const char *psrc = smb_fname_src->base_name;
5896 const char *pdst = smb_fname_dst->base_name;
5897 size_t slen;
5899 if (psrc[0] == '.' && psrc[1] == '/') {
5900 psrc += 2;
5902 if (pdst[0] == '.' && pdst[1] == '/') {
5903 pdst += 2;
5905 if ((slen = strlen(psrc)) > strlen(pdst)) {
5906 return False;
5908 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5912 * Do the notify calls from a rename
5915 static void notify_rename(connection_struct *conn, bool is_dir,
5916 const struct smb_filename *smb_fname_src,
5917 const struct smb_filename *smb_fname_dst)
5919 char *parent_dir_src = NULL;
5920 char *parent_dir_dst = NULL;
5921 uint32 mask;
5923 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5924 : FILE_NOTIFY_CHANGE_FILE_NAME;
5926 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5927 &parent_dir_src, NULL) ||
5928 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5929 &parent_dir_dst, NULL)) {
5930 goto out;
5933 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5934 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5935 smb_fname_src->base_name);
5936 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5937 smb_fname_dst->base_name);
5939 else {
5940 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5941 smb_fname_src->base_name);
5942 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5943 smb_fname_dst->base_name);
5946 /* this is a strange one. w2k3 gives an additional event for
5947 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5948 files, but not directories */
5949 if (!is_dir) {
5950 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5951 FILE_NOTIFY_CHANGE_ATTRIBUTES
5952 |FILE_NOTIFY_CHANGE_CREATION,
5953 smb_fname_dst->base_name);
5955 out:
5956 TALLOC_FREE(parent_dir_src);
5957 TALLOC_FREE(parent_dir_dst);
5960 /****************************************************************************
5961 Rename an open file - given an fsp.
5962 ****************************************************************************/
5964 NTSTATUS rename_internals_fsp(connection_struct *conn,
5965 files_struct *fsp,
5966 const struct smb_filename *smb_fname_dst_in,
5967 uint32 attrs,
5968 bool replace_if_exists)
5970 TALLOC_CTX *ctx = talloc_tos();
5971 struct smb_filename *smb_fname_dst = NULL;
5972 NTSTATUS status = NT_STATUS_OK;
5973 struct share_mode_lock *lck = NULL;
5974 bool dst_exists, old_is_stream, new_is_stream;
5976 status = check_name(conn, smb_fname_dst_in->base_name);
5977 if (!NT_STATUS_IS_OK(status)) {
5978 return status;
5981 /* Make a copy of the dst smb_fname structs */
5983 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5984 if (!NT_STATUS_IS_OK(status)) {
5985 goto out;
5989 * Check for special case with case preserving and not
5990 * case sensitive. If the old last component differs from the original
5991 * last component only by case, then we should allow
5992 * the rename (user is trying to change the case of the
5993 * filename).
5995 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5996 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5997 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5998 char *last_slash;
5999 char *fname_dst_lcomp_base_mod = NULL;
6000 struct smb_filename *smb_fname_orig_lcomp = NULL;
6003 * Get the last component of the destination name.
6005 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6006 if (last_slash) {
6007 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6008 } else {
6009 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6011 if (!fname_dst_lcomp_base_mod) {
6012 status = NT_STATUS_NO_MEMORY;
6013 goto out;
6017 * Create an smb_filename struct using the original last
6018 * component of the destination.
6020 status = create_synthetic_smb_fname_split(ctx,
6021 smb_fname_dst->original_lcomp, NULL,
6022 &smb_fname_orig_lcomp);
6023 if (!NT_STATUS_IS_OK(status)) {
6024 TALLOC_FREE(fname_dst_lcomp_base_mod);
6025 goto out;
6028 /* If the base names only differ by case, use original. */
6029 if(!strcsequal(fname_dst_lcomp_base_mod,
6030 smb_fname_orig_lcomp->base_name)) {
6031 char *tmp;
6033 * Replace the modified last component with the
6034 * original.
6036 if (last_slash) {
6037 *last_slash = '\0'; /* Truncate at the '/' */
6038 tmp = talloc_asprintf(smb_fname_dst,
6039 "%s/%s",
6040 smb_fname_dst->base_name,
6041 smb_fname_orig_lcomp->base_name);
6042 } else {
6043 tmp = talloc_asprintf(smb_fname_dst,
6044 "%s",
6045 smb_fname_orig_lcomp->base_name);
6047 if (tmp == NULL) {
6048 status = NT_STATUS_NO_MEMORY;
6049 TALLOC_FREE(fname_dst_lcomp_base_mod);
6050 TALLOC_FREE(smb_fname_orig_lcomp);
6051 goto out;
6053 TALLOC_FREE(smb_fname_dst->base_name);
6054 smb_fname_dst->base_name = tmp;
6057 /* If the stream_names only differ by case, use original. */
6058 if(!strcsequal(smb_fname_dst->stream_name,
6059 smb_fname_orig_lcomp->stream_name)) {
6060 char *tmp = NULL;
6061 /* Use the original stream. */
6062 tmp = talloc_strdup(smb_fname_dst,
6063 smb_fname_orig_lcomp->stream_name);
6064 if (tmp == NULL) {
6065 status = NT_STATUS_NO_MEMORY;
6066 TALLOC_FREE(fname_dst_lcomp_base_mod);
6067 TALLOC_FREE(smb_fname_orig_lcomp);
6068 goto out;
6070 TALLOC_FREE(smb_fname_dst->stream_name);
6071 smb_fname_dst->stream_name = tmp;
6073 TALLOC_FREE(fname_dst_lcomp_base_mod);
6074 TALLOC_FREE(smb_fname_orig_lcomp);
6078 * If the src and dest names are identical - including case,
6079 * don't do the rename, just return success.
6082 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6083 strcsequal(fsp->fsp_name->stream_name,
6084 smb_fname_dst->stream_name)) {
6085 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6086 "- returning success\n",
6087 smb_fname_str_dbg(smb_fname_dst)));
6088 status = NT_STATUS_OK;
6089 goto out;
6092 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6093 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6095 /* Return the correct error code if both names aren't streams. */
6096 if (!old_is_stream && new_is_stream) {
6097 status = NT_STATUS_OBJECT_NAME_INVALID;
6098 goto out;
6101 if (old_is_stream && !new_is_stream) {
6102 status = NT_STATUS_INVALID_PARAMETER;
6103 goto out;
6106 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6108 if(!replace_if_exists && dst_exists) {
6109 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6110 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6111 smb_fname_str_dbg(smb_fname_dst)));
6112 status = NT_STATUS_OBJECT_NAME_COLLISION;
6113 goto out;
6116 if (dst_exists) {
6117 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6118 &smb_fname_dst->st);
6119 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6120 fileid);
6121 /* The file can be open when renaming a stream */
6122 if (dst_fsp && !new_is_stream) {
6123 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6124 status = NT_STATUS_ACCESS_DENIED;
6125 goto out;
6129 /* Ensure we have a valid stat struct for the source. */
6130 status = vfs_stat_fsp(fsp);
6131 if (!NT_STATUS_IS_OK(status)) {
6132 goto out;
6135 status = can_rename(conn, fsp, attrs);
6137 if (!NT_STATUS_IS_OK(status)) {
6138 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6139 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6140 smb_fname_str_dbg(smb_fname_dst)));
6141 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6142 status = NT_STATUS_ACCESS_DENIED;
6143 goto out;
6146 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6147 status = NT_STATUS_ACCESS_DENIED;
6150 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6151 NULL);
6154 * We have the file open ourselves, so not being able to get the
6155 * corresponding share mode lock is a fatal error.
6158 SMB_ASSERT(lck != NULL);
6160 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6161 uint32 create_options = fsp->fh->private_options;
6163 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6164 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6165 smb_fname_str_dbg(smb_fname_dst)));
6167 if (!lp_posix_pathnames() &&
6168 (lp_map_archive(SNUM(conn)) ||
6169 lp_store_dos_attributes(SNUM(conn)))) {
6170 /* We must set the archive bit on the newly
6171 renamed file. */
6172 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6173 uint32_t old_dosmode = dos_mode(conn,
6174 smb_fname_dst);
6175 file_set_dosmode(conn,
6176 smb_fname_dst,
6177 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6178 NULL,
6179 true);
6183 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6184 smb_fname_dst);
6186 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6189 * A rename acts as a new file create w.r.t. allowing an initial delete
6190 * on close, probably because in Windows there is a new handle to the
6191 * new file. If initial delete on close was requested but not
6192 * originally set, we need to set it here. This is probably not 100% correct,
6193 * but will work for the CIFSFS client which in non-posix mode
6194 * depends on these semantics. JRA.
6197 if (create_options & FILE_DELETE_ON_CLOSE) {
6198 status = can_set_delete_on_close(fsp, 0);
6200 if (NT_STATUS_IS_OK(status)) {
6201 /* Note that here we set the *inital* delete on close flag,
6202 * not the regular one. The magic gets handled in close. */
6203 fsp->initial_delete_on_close = True;
6206 TALLOC_FREE(lck);
6207 status = NT_STATUS_OK;
6208 goto out;
6211 TALLOC_FREE(lck);
6213 if (errno == ENOTDIR || errno == EISDIR) {
6214 status = NT_STATUS_OBJECT_NAME_COLLISION;
6215 } else {
6216 status = map_nt_error_from_unix(errno);
6219 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6220 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6221 smb_fname_str_dbg(smb_fname_dst)));
6223 out:
6224 TALLOC_FREE(smb_fname_dst);
6226 return status;
6229 /****************************************************************************
6230 The guts of the rename command, split out so it may be called by the NT SMB
6231 code.
6232 ****************************************************************************/
6234 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6235 connection_struct *conn,
6236 struct smb_request *req,
6237 struct smb_filename *smb_fname_src,
6238 struct smb_filename *smb_fname_dst,
6239 uint32 attrs,
6240 bool replace_if_exists,
6241 bool src_has_wild,
6242 bool dest_has_wild,
6243 uint32_t access_mask)
6245 char *fname_src_dir = NULL;
6246 char *fname_src_mask = NULL;
6247 int count=0;
6248 NTSTATUS status = NT_STATUS_OK;
6249 struct smb_Dir *dir_hnd = NULL;
6250 const char *dname = NULL;
6251 char *talloced = NULL;
6252 long offset = 0;
6253 int create_options = 0;
6254 bool posix_pathnames = lp_posix_pathnames();
6257 * Split the old name into directory and last component
6258 * strings. Note that unix_convert may have stripped off a
6259 * leading ./ from both name and newname if the rename is
6260 * at the root of the share. We need to make sure either both
6261 * name and newname contain a / character or neither of them do
6262 * as this is checked in resolve_wildcards().
6265 /* Split up the directory from the filename/mask. */
6266 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6267 &fname_src_dir, &fname_src_mask);
6268 if (!NT_STATUS_IS_OK(status)) {
6269 status = NT_STATUS_NO_MEMORY;
6270 goto out;
6274 * We should only check the mangled cache
6275 * here if unix_convert failed. This means
6276 * that the path in 'mask' doesn't exist
6277 * on the file system and so we need to look
6278 * for a possible mangle. This patch from
6279 * Tine Smukavec <valentin.smukavec@hermes.si>.
6282 if (!VALID_STAT(smb_fname_src->st) &&
6283 mangle_is_mangled(fname_src_mask, conn->params)) {
6284 char *new_mask = NULL;
6285 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6286 conn->params);
6287 if (new_mask) {
6288 TALLOC_FREE(fname_src_mask);
6289 fname_src_mask = new_mask;
6293 if (!src_has_wild) {
6294 files_struct *fsp;
6297 * Only one file needs to be renamed. Append the mask back
6298 * onto the directory.
6300 TALLOC_FREE(smb_fname_src->base_name);
6301 if (ISDOT(fname_src_dir)) {
6302 /* Ensure we use canonical names on open. */
6303 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6304 "%s",
6305 fname_src_mask);
6306 } else {
6307 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6308 "%s/%s",
6309 fname_src_dir,
6310 fname_src_mask);
6312 if (!smb_fname_src->base_name) {
6313 status = NT_STATUS_NO_MEMORY;
6314 goto out;
6317 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6318 "case_preserve = %d, short case preserve = %d, "
6319 "directory = %s, newname = %s, "
6320 "last_component_dest = %s\n",
6321 conn->case_sensitive, conn->case_preserve,
6322 conn->short_case_preserve,
6323 smb_fname_str_dbg(smb_fname_src),
6324 smb_fname_str_dbg(smb_fname_dst),
6325 smb_fname_dst->original_lcomp));
6327 /* The dest name still may have wildcards. */
6328 if (dest_has_wild) {
6329 char *fname_dst_mod = NULL;
6330 if (!resolve_wildcards(smb_fname_dst,
6331 smb_fname_src->base_name,
6332 smb_fname_dst->base_name,
6333 &fname_dst_mod)) {
6334 DEBUG(6, ("rename_internals: resolve_wildcards "
6335 "%s %s failed\n",
6336 smb_fname_src->base_name,
6337 smb_fname_dst->base_name));
6338 status = NT_STATUS_NO_MEMORY;
6339 goto out;
6341 TALLOC_FREE(smb_fname_dst->base_name);
6342 smb_fname_dst->base_name = fname_dst_mod;
6345 ZERO_STRUCT(smb_fname_src->st);
6346 if (posix_pathnames) {
6347 SMB_VFS_LSTAT(conn, smb_fname_src);
6348 } else {
6349 SMB_VFS_STAT(conn, smb_fname_src);
6352 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6353 create_options |= FILE_DIRECTORY_FILE;
6356 status = SMB_VFS_CREATE_FILE(
6357 conn, /* conn */
6358 req, /* req */
6359 0, /* root_dir_fid */
6360 smb_fname_src, /* fname */
6361 access_mask, /* access_mask */
6362 (FILE_SHARE_READ | /* share_access */
6363 FILE_SHARE_WRITE),
6364 FILE_OPEN, /* create_disposition*/
6365 create_options, /* create_options */
6366 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6367 0, /* oplock_request */
6368 0, /* allocation_size */
6369 0, /* private_flags */
6370 NULL, /* sd */
6371 NULL, /* ea_list */
6372 &fsp, /* result */
6373 NULL); /* pinfo */
6375 if (!NT_STATUS_IS_OK(status)) {
6376 DEBUG(3, ("Could not open rename source %s: %s\n",
6377 smb_fname_str_dbg(smb_fname_src),
6378 nt_errstr(status)));
6379 goto out;
6382 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6383 attrs, replace_if_exists);
6385 close_file(req, fsp, NORMAL_CLOSE);
6387 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6388 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6389 smb_fname_str_dbg(smb_fname_dst)));
6391 goto out;
6395 * Wildcards - process each file that matches.
6397 if (strequal(fname_src_mask, "????????.???")) {
6398 TALLOC_FREE(fname_src_mask);
6399 fname_src_mask = talloc_strdup(ctx, "*");
6400 if (!fname_src_mask) {
6401 status = NT_STATUS_NO_MEMORY;
6402 goto out;
6406 status = check_name(conn, fname_src_dir);
6407 if (!NT_STATUS_IS_OK(status)) {
6408 goto out;
6411 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6412 attrs);
6413 if (dir_hnd == NULL) {
6414 status = map_nt_error_from_unix(errno);
6415 goto out;
6418 status = NT_STATUS_NO_SUCH_FILE;
6420 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6421 * - gentest fix. JRA
6424 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6425 &talloced))) {
6426 files_struct *fsp = NULL;
6427 char *destname = NULL;
6428 bool sysdir_entry = False;
6430 /* Quick check for "." and ".." */
6431 if (ISDOT(dname) || ISDOTDOT(dname)) {
6432 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6433 sysdir_entry = True;
6434 } else {
6435 TALLOC_FREE(talloced);
6436 continue;
6440 if (!is_visible_file(conn, fname_src_dir, dname,
6441 &smb_fname_src->st, false)) {
6442 TALLOC_FREE(talloced);
6443 continue;
6446 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6447 TALLOC_FREE(talloced);
6448 continue;
6451 if (sysdir_entry) {
6452 status = NT_STATUS_OBJECT_NAME_INVALID;
6453 break;
6456 TALLOC_FREE(smb_fname_src->base_name);
6457 if (ISDOT(fname_src_dir)) {
6458 /* Ensure we use canonical names on open. */
6459 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6460 "%s",
6461 dname);
6462 } else {
6463 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6464 "%s/%s",
6465 fname_src_dir,
6466 dname);
6468 if (!smb_fname_src->base_name) {
6469 status = NT_STATUS_NO_MEMORY;
6470 goto out;
6473 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6474 smb_fname_dst->base_name,
6475 &destname)) {
6476 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6477 smb_fname_src->base_name, destname));
6478 TALLOC_FREE(talloced);
6479 continue;
6481 if (!destname) {
6482 status = NT_STATUS_NO_MEMORY;
6483 goto out;
6486 TALLOC_FREE(smb_fname_dst->base_name);
6487 smb_fname_dst->base_name = destname;
6489 ZERO_STRUCT(smb_fname_src->st);
6490 if (posix_pathnames) {
6491 SMB_VFS_LSTAT(conn, smb_fname_src);
6492 } else {
6493 SMB_VFS_STAT(conn, smb_fname_src);
6496 create_options = 0;
6498 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6499 create_options |= FILE_DIRECTORY_FILE;
6502 status = SMB_VFS_CREATE_FILE(
6503 conn, /* conn */
6504 req, /* req */
6505 0, /* root_dir_fid */
6506 smb_fname_src, /* fname */
6507 access_mask, /* access_mask */
6508 (FILE_SHARE_READ | /* share_access */
6509 FILE_SHARE_WRITE),
6510 FILE_OPEN, /* create_disposition*/
6511 create_options, /* create_options */
6512 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6513 0, /* oplock_request */
6514 0, /* allocation_size */
6515 0, /* private_flags */
6516 NULL, /* sd */
6517 NULL, /* ea_list */
6518 &fsp, /* result */
6519 NULL); /* pinfo */
6521 if (!NT_STATUS_IS_OK(status)) {
6522 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6523 "returned %s rename %s -> %s\n",
6524 nt_errstr(status),
6525 smb_fname_str_dbg(smb_fname_src),
6526 smb_fname_str_dbg(smb_fname_dst)));
6527 break;
6530 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6531 dname);
6532 if (!smb_fname_dst->original_lcomp) {
6533 status = NT_STATUS_NO_MEMORY;
6534 goto out;
6537 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6538 attrs, replace_if_exists);
6540 close_file(req, fsp, NORMAL_CLOSE);
6542 if (!NT_STATUS_IS_OK(status)) {
6543 DEBUG(3, ("rename_internals_fsp returned %s for "
6544 "rename %s -> %s\n", nt_errstr(status),
6545 smb_fname_str_dbg(smb_fname_src),
6546 smb_fname_str_dbg(smb_fname_dst)));
6547 break;
6550 count++;
6552 DEBUG(3,("rename_internals: doing rename on %s -> "
6553 "%s\n", smb_fname_str_dbg(smb_fname_src),
6554 smb_fname_str_dbg(smb_fname_src)));
6555 TALLOC_FREE(talloced);
6557 TALLOC_FREE(dir_hnd);
6559 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6560 status = map_nt_error_from_unix(errno);
6563 out:
6564 TALLOC_FREE(talloced);
6565 TALLOC_FREE(fname_src_dir);
6566 TALLOC_FREE(fname_src_mask);
6567 return status;
6570 /****************************************************************************
6571 Reply to a mv.
6572 ****************************************************************************/
6574 void reply_mv(struct smb_request *req)
6576 connection_struct *conn = req->conn;
6577 char *name = NULL;
6578 char *newname = NULL;
6579 const char *p;
6580 uint32 attrs;
6581 NTSTATUS status;
6582 bool src_has_wcard = False;
6583 bool dest_has_wcard = False;
6584 TALLOC_CTX *ctx = talloc_tos();
6585 struct smb_filename *smb_fname_src = NULL;
6586 struct smb_filename *smb_fname_dst = NULL;
6587 bool stream_rename = false;
6589 START_PROFILE(SMBmv);
6591 if (req->wct < 1) {
6592 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6593 goto out;
6596 attrs = SVAL(req->vwv+0, 0);
6598 p = (const char *)req->buf + 1;
6599 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6600 &status, &src_has_wcard);
6601 if (!NT_STATUS_IS_OK(status)) {
6602 reply_nterror(req, status);
6603 goto out;
6605 p++;
6606 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6607 &status, &dest_has_wcard);
6608 if (!NT_STATUS_IS_OK(status)) {
6609 reply_nterror(req, status);
6610 goto out;
6613 if (!lp_posix_pathnames()) {
6614 /* The newname must begin with a ':' if the
6615 name contains a ':'. */
6616 if (strchr_m(name, ':')) {
6617 if (newname[0] != ':') {
6618 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6619 goto out;
6621 stream_rename = true;
6625 status = filename_convert(ctx,
6626 conn,
6627 req->flags2 & FLAGS2_DFS_PATHNAMES,
6628 name,
6629 UCF_COND_ALLOW_WCARD_LCOMP,
6630 &src_has_wcard,
6631 &smb_fname_src);
6633 if (!NT_STATUS_IS_OK(status)) {
6634 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6635 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6636 ERRSRV, ERRbadpath);
6637 goto out;
6639 reply_nterror(req, status);
6640 goto out;
6643 status = filename_convert(ctx,
6644 conn,
6645 req->flags2 & FLAGS2_DFS_PATHNAMES,
6646 newname,
6647 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6648 &dest_has_wcard,
6649 &smb_fname_dst);
6651 if (!NT_STATUS_IS_OK(status)) {
6652 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6653 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6654 ERRSRV, ERRbadpath);
6655 goto out;
6657 reply_nterror(req, status);
6658 goto out;
6661 if (stream_rename) {
6662 /* smb_fname_dst->base_name must be the same as
6663 smb_fname_src->base_name. */
6664 TALLOC_FREE(smb_fname_dst->base_name);
6665 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6666 smb_fname_src->base_name);
6667 if (!smb_fname_dst->base_name) {
6668 reply_nterror(req, NT_STATUS_NO_MEMORY);
6669 goto out;
6673 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6674 smb_fname_str_dbg(smb_fname_dst)));
6676 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6677 attrs, False, src_has_wcard, dest_has_wcard,
6678 DELETE_ACCESS);
6679 if (!NT_STATUS_IS_OK(status)) {
6680 if (open_was_deferred(req->mid)) {
6681 /* We have re-scheduled this call. */
6682 goto out;
6684 reply_nterror(req, status);
6685 goto out;
6688 reply_outbuf(req, 0, 0);
6689 out:
6690 TALLOC_FREE(smb_fname_src);
6691 TALLOC_FREE(smb_fname_dst);
6692 END_PROFILE(SMBmv);
6693 return;
6696 /*******************************************************************
6697 Copy a file as part of a reply_copy.
6698 ******************************************************************/
6701 * TODO: check error codes on all callers
6704 NTSTATUS copy_file(TALLOC_CTX *ctx,
6705 connection_struct *conn,
6706 struct smb_filename *smb_fname_src,
6707 struct smb_filename *smb_fname_dst,
6708 int ofun,
6709 int count,
6710 bool target_is_directory)
6712 struct smb_filename *smb_fname_dst_tmp = NULL;
6713 SMB_OFF_T ret=-1;
6714 files_struct *fsp1,*fsp2;
6715 uint32 dosattrs;
6716 uint32 new_create_disposition;
6717 NTSTATUS status;
6720 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6721 if (!NT_STATUS_IS_OK(status)) {
6722 return status;
6726 * If the target is a directory, extract the last component from the
6727 * src filename and append it to the dst filename
6729 if (target_is_directory) {
6730 const char *p;
6732 /* dest/target can't be a stream if it's a directory. */
6733 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6735 p = strrchr_m(smb_fname_src->base_name,'/');
6736 if (p) {
6737 p++;
6738 } else {
6739 p = smb_fname_src->base_name;
6741 smb_fname_dst_tmp->base_name =
6742 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6744 if (!smb_fname_dst_tmp->base_name) {
6745 status = NT_STATUS_NO_MEMORY;
6746 goto out;
6750 status = vfs_file_exist(conn, smb_fname_src);
6751 if (!NT_STATUS_IS_OK(status)) {
6752 goto out;
6755 if (!target_is_directory && count) {
6756 new_create_disposition = FILE_OPEN;
6757 } else {
6758 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6759 NULL, NULL,
6760 &new_create_disposition,
6761 NULL,
6762 NULL)) {
6763 status = NT_STATUS_INVALID_PARAMETER;
6764 goto out;
6768 /* Open the src file for reading. */
6769 status = SMB_VFS_CREATE_FILE(
6770 conn, /* conn */
6771 NULL, /* req */
6772 0, /* root_dir_fid */
6773 smb_fname_src, /* fname */
6774 FILE_GENERIC_READ, /* access_mask */
6775 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6776 FILE_OPEN, /* create_disposition*/
6777 0, /* create_options */
6778 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6779 INTERNAL_OPEN_ONLY, /* oplock_request */
6780 0, /* allocation_size */
6781 0, /* private_flags */
6782 NULL, /* sd */
6783 NULL, /* ea_list */
6784 &fsp1, /* result */
6785 NULL); /* psbuf */
6787 if (!NT_STATUS_IS_OK(status)) {
6788 goto out;
6791 dosattrs = dos_mode(conn, smb_fname_src);
6793 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6794 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6797 /* Open the dst file for writing. */
6798 status = SMB_VFS_CREATE_FILE(
6799 conn, /* conn */
6800 NULL, /* req */
6801 0, /* root_dir_fid */
6802 smb_fname_dst, /* fname */
6803 FILE_GENERIC_WRITE, /* access_mask */
6804 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6805 new_create_disposition, /* create_disposition*/
6806 0, /* create_options */
6807 dosattrs, /* file_attributes */
6808 INTERNAL_OPEN_ONLY, /* oplock_request */
6809 0, /* allocation_size */
6810 0, /* private_flags */
6811 NULL, /* sd */
6812 NULL, /* ea_list */
6813 &fsp2, /* result */
6814 NULL); /* psbuf */
6816 if (!NT_STATUS_IS_OK(status)) {
6817 close_file(NULL, fsp1, ERROR_CLOSE);
6818 goto out;
6821 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6822 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6823 if (ret == -1) {
6824 DEBUG(0, ("error - vfs lseek returned error %s\n",
6825 strerror(errno)));
6826 status = map_nt_error_from_unix(errno);
6827 close_file(NULL, fsp1, ERROR_CLOSE);
6828 close_file(NULL, fsp2, ERROR_CLOSE);
6829 goto out;
6833 /* Do the actual copy. */
6834 if (smb_fname_src->st.st_ex_size) {
6835 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6836 } else {
6837 ret = 0;
6840 close_file(NULL, fsp1, NORMAL_CLOSE);
6842 /* Ensure the modtime is set correctly on the destination file. */
6843 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6846 * As we are opening fsp1 read-only we only expect
6847 * an error on close on fsp2 if we are out of space.
6848 * Thus we don't look at the error return from the
6849 * close of fsp1.
6851 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6853 if (!NT_STATUS_IS_OK(status)) {
6854 goto out;
6857 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6858 status = NT_STATUS_DISK_FULL;
6859 goto out;
6862 status = NT_STATUS_OK;
6864 out:
6865 TALLOC_FREE(smb_fname_dst_tmp);
6866 return status;
6869 /****************************************************************************
6870 Reply to a file copy.
6871 ****************************************************************************/
6873 void reply_copy(struct smb_request *req)
6875 connection_struct *conn = req->conn;
6876 struct smb_filename *smb_fname_src = NULL;
6877 struct smb_filename *smb_fname_dst = NULL;
6878 char *fname_src = NULL;
6879 char *fname_dst = NULL;
6880 char *fname_src_mask = NULL;
6881 char *fname_src_dir = NULL;
6882 const char *p;
6883 int count=0;
6884 int error = ERRnoaccess;
6885 int tid2;
6886 int ofun;
6887 int flags;
6888 bool target_is_directory=False;
6889 bool source_has_wild = False;
6890 bool dest_has_wild = False;
6891 NTSTATUS status;
6892 TALLOC_CTX *ctx = talloc_tos();
6894 START_PROFILE(SMBcopy);
6896 if (req->wct < 3) {
6897 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6898 goto out;
6901 tid2 = SVAL(req->vwv+0, 0);
6902 ofun = SVAL(req->vwv+1, 0);
6903 flags = SVAL(req->vwv+2, 0);
6905 p = (const char *)req->buf;
6906 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6907 &status, &source_has_wild);
6908 if (!NT_STATUS_IS_OK(status)) {
6909 reply_nterror(req, status);
6910 goto out;
6912 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6913 &status, &dest_has_wild);
6914 if (!NT_STATUS_IS_OK(status)) {
6915 reply_nterror(req, status);
6916 goto out;
6919 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6921 if (tid2 != conn->cnum) {
6922 /* can't currently handle inter share copies XXXX */
6923 DEBUG(3,("Rejecting inter-share copy\n"));
6924 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6925 goto out;
6928 status = filename_convert(ctx, conn,
6929 req->flags2 & FLAGS2_DFS_PATHNAMES,
6930 fname_src,
6931 UCF_COND_ALLOW_WCARD_LCOMP,
6932 &source_has_wild,
6933 &smb_fname_src);
6934 if (!NT_STATUS_IS_OK(status)) {
6935 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6936 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6937 ERRSRV, ERRbadpath);
6938 goto out;
6940 reply_nterror(req, status);
6941 goto out;
6944 status = filename_convert(ctx, conn,
6945 req->flags2 & FLAGS2_DFS_PATHNAMES,
6946 fname_dst,
6947 UCF_COND_ALLOW_WCARD_LCOMP,
6948 &dest_has_wild,
6949 &smb_fname_dst);
6950 if (!NT_STATUS_IS_OK(status)) {
6951 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6952 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6953 ERRSRV, ERRbadpath);
6954 goto out;
6956 reply_nterror(req, status);
6957 goto out;
6960 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6962 if ((flags&1) && target_is_directory) {
6963 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6964 goto out;
6967 if ((flags&2) && !target_is_directory) {
6968 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6969 goto out;
6972 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6973 /* wants a tree copy! XXXX */
6974 DEBUG(3,("Rejecting tree copy\n"));
6975 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6976 goto out;
6979 /* Split up the directory from the filename/mask. */
6980 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6981 &fname_src_dir, &fname_src_mask);
6982 if (!NT_STATUS_IS_OK(status)) {
6983 reply_nterror(req, NT_STATUS_NO_MEMORY);
6984 goto out;
6988 * We should only check the mangled cache
6989 * here if unix_convert failed. This means
6990 * that the path in 'mask' doesn't exist
6991 * on the file system and so we need to look
6992 * for a possible mangle. This patch from
6993 * Tine Smukavec <valentin.smukavec@hermes.si>.
6995 if (!VALID_STAT(smb_fname_src->st) &&
6996 mangle_is_mangled(fname_src_mask, conn->params)) {
6997 char *new_mask = NULL;
6998 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6999 &new_mask, conn->params);
7001 /* Use demangled name if one was successfully found. */
7002 if (new_mask) {
7003 TALLOC_FREE(fname_src_mask);
7004 fname_src_mask = new_mask;
7008 if (!source_has_wild) {
7011 * Only one file needs to be copied. Append the mask back onto
7012 * the directory.
7014 TALLOC_FREE(smb_fname_src->base_name);
7015 if (ISDOT(fname_src_dir)) {
7016 /* Ensure we use canonical names on open. */
7017 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7018 "%s",
7019 fname_src_mask);
7020 } else {
7021 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7022 "%s/%s",
7023 fname_src_dir,
7024 fname_src_mask);
7026 if (!smb_fname_src->base_name) {
7027 reply_nterror(req, NT_STATUS_NO_MEMORY);
7028 goto out;
7031 if (dest_has_wild) {
7032 char *fname_dst_mod = NULL;
7033 if (!resolve_wildcards(smb_fname_dst,
7034 smb_fname_src->base_name,
7035 smb_fname_dst->base_name,
7036 &fname_dst_mod)) {
7037 reply_nterror(req, NT_STATUS_NO_MEMORY);
7038 goto out;
7040 TALLOC_FREE(smb_fname_dst->base_name);
7041 smb_fname_dst->base_name = fname_dst_mod;
7044 status = check_name(conn, smb_fname_src->base_name);
7045 if (!NT_STATUS_IS_OK(status)) {
7046 reply_nterror(req, status);
7047 goto out;
7050 status = check_name(conn, smb_fname_dst->base_name);
7051 if (!NT_STATUS_IS_OK(status)) {
7052 reply_nterror(req, status);
7053 goto out;
7056 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7057 ofun, count, target_is_directory);
7059 if(!NT_STATUS_IS_OK(status)) {
7060 reply_nterror(req, status);
7061 goto out;
7062 } else {
7063 count++;
7065 } else {
7066 struct smb_Dir *dir_hnd = NULL;
7067 const char *dname = NULL;
7068 char *talloced = NULL;
7069 long offset = 0;
7072 * There is a wildcard that requires us to actually read the
7073 * src dir and copy each file matching the mask to the dst.
7074 * Right now streams won't be copied, but this could
7075 * presumably be added with a nested loop for reach dir entry.
7077 SMB_ASSERT(!smb_fname_src->stream_name);
7078 SMB_ASSERT(!smb_fname_dst->stream_name);
7080 smb_fname_src->stream_name = NULL;
7081 smb_fname_dst->stream_name = NULL;
7083 if (strequal(fname_src_mask,"????????.???")) {
7084 TALLOC_FREE(fname_src_mask);
7085 fname_src_mask = talloc_strdup(ctx, "*");
7086 if (!fname_src_mask) {
7087 reply_nterror(req, NT_STATUS_NO_MEMORY);
7088 goto out;
7092 status = check_name(conn, fname_src_dir);
7093 if (!NT_STATUS_IS_OK(status)) {
7094 reply_nterror(req, status);
7095 goto out;
7098 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7099 if (dir_hnd == NULL) {
7100 status = map_nt_error_from_unix(errno);
7101 reply_nterror(req, status);
7102 goto out;
7105 error = ERRbadfile;
7107 /* Iterate over the src dir copying each entry to the dst. */
7108 while ((dname = ReadDirName(dir_hnd, &offset,
7109 &smb_fname_src->st, &talloced))) {
7110 char *destname = NULL;
7112 if (ISDOT(dname) || ISDOTDOT(dname)) {
7113 TALLOC_FREE(talloced);
7114 continue;
7117 if (!is_visible_file(conn, fname_src_dir, dname,
7118 &smb_fname_src->st, false)) {
7119 TALLOC_FREE(talloced);
7120 continue;
7123 if(!mask_match(dname, fname_src_mask,
7124 conn->case_sensitive)) {
7125 TALLOC_FREE(talloced);
7126 continue;
7129 error = ERRnoaccess;
7131 /* Get the src smb_fname struct setup. */
7132 TALLOC_FREE(smb_fname_src->base_name);
7133 if (ISDOT(fname_src_dir)) {
7134 /* Ensure we use canonical names on open. */
7135 smb_fname_src->base_name =
7136 talloc_asprintf(smb_fname_src, "%s",
7137 dname);
7138 } else {
7139 smb_fname_src->base_name =
7140 talloc_asprintf(smb_fname_src, "%s/%s",
7141 fname_src_dir, dname);
7144 if (!smb_fname_src->base_name) {
7145 TALLOC_FREE(dir_hnd);
7146 TALLOC_FREE(talloced);
7147 reply_nterror(req, NT_STATUS_NO_MEMORY);
7148 goto out;
7151 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7152 smb_fname_dst->base_name,
7153 &destname)) {
7154 TALLOC_FREE(talloced);
7155 continue;
7157 if (!destname) {
7158 TALLOC_FREE(dir_hnd);
7159 TALLOC_FREE(talloced);
7160 reply_nterror(req, NT_STATUS_NO_MEMORY);
7161 goto out;
7164 TALLOC_FREE(smb_fname_dst->base_name);
7165 smb_fname_dst->base_name = destname;
7167 status = check_name(conn, smb_fname_src->base_name);
7168 if (!NT_STATUS_IS_OK(status)) {
7169 TALLOC_FREE(dir_hnd);
7170 TALLOC_FREE(talloced);
7171 reply_nterror(req, status);
7172 goto out;
7175 status = check_name(conn, smb_fname_dst->base_name);
7176 if (!NT_STATUS_IS_OK(status)) {
7177 TALLOC_FREE(dir_hnd);
7178 TALLOC_FREE(talloced);
7179 reply_nterror(req, status);
7180 goto out;
7183 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7184 smb_fname_src->base_name,
7185 smb_fname_dst->base_name));
7187 status = copy_file(ctx, conn, smb_fname_src,
7188 smb_fname_dst, ofun, count,
7189 target_is_directory);
7190 if (NT_STATUS_IS_OK(status)) {
7191 count++;
7194 TALLOC_FREE(talloced);
7196 TALLOC_FREE(dir_hnd);
7199 if (count == 0) {
7200 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7201 goto out;
7204 reply_outbuf(req, 1, 0);
7205 SSVAL(req->outbuf,smb_vwv0,count);
7206 out:
7207 TALLOC_FREE(smb_fname_src);
7208 TALLOC_FREE(smb_fname_dst);
7209 TALLOC_FREE(fname_src);
7210 TALLOC_FREE(fname_dst);
7211 TALLOC_FREE(fname_src_mask);
7212 TALLOC_FREE(fname_src_dir);
7214 END_PROFILE(SMBcopy);
7215 return;
7218 #undef DBGC_CLASS
7219 #define DBGC_CLASS DBGC_LOCKING
7221 /****************************************************************************
7222 Get a lock pid, dealing with large count requests.
7223 ****************************************************************************/
7225 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7226 bool large_file_format)
7228 if(!large_file_format)
7229 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7230 else
7231 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7234 /****************************************************************************
7235 Get a lock count, dealing with large count requests.
7236 ****************************************************************************/
7238 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7239 bool large_file_format)
7241 uint64_t count = 0;
7243 if(!large_file_format) {
7244 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7245 } else {
7247 #if defined(HAVE_LONGLONG)
7248 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7249 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7250 #else /* HAVE_LONGLONG */
7253 * NT4.x seems to be broken in that it sends large file (64 bit)
7254 * lockingX calls even if the CAP_LARGE_FILES was *not*
7255 * negotiated. For boxes without large unsigned ints truncate the
7256 * lock count by dropping the top 32 bits.
7259 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7260 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7261 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7262 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7263 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7266 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7267 #endif /* HAVE_LONGLONG */
7270 return count;
7273 #if !defined(HAVE_LONGLONG)
7274 /****************************************************************************
7275 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7276 ****************************************************************************/
7278 static uint32 map_lock_offset(uint32 high, uint32 low)
7280 unsigned int i;
7281 uint32 mask = 0;
7282 uint32 highcopy = high;
7285 * Try and find out how many significant bits there are in high.
7288 for(i = 0; highcopy; i++)
7289 highcopy >>= 1;
7292 * We use 31 bits not 32 here as POSIX
7293 * lock offsets may not be negative.
7296 mask = (~0) << (31 - i);
7298 if(low & mask)
7299 return 0; /* Fail. */
7301 high <<= (31 - i);
7303 return (high|low);
7305 #endif /* !defined(HAVE_LONGLONG) */
7307 /****************************************************************************
7308 Get a lock offset, dealing with large offset requests.
7309 ****************************************************************************/
7311 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7312 bool large_file_format, bool *err)
7314 uint64_t offset = 0;
7316 *err = False;
7318 if(!large_file_format) {
7319 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7320 } else {
7322 #if defined(HAVE_LONGLONG)
7323 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7324 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7325 #else /* HAVE_LONGLONG */
7328 * NT4.x seems to be broken in that it sends large file (64 bit)
7329 * lockingX calls even if the CAP_LARGE_FILES was *not*
7330 * negotiated. For boxes without large unsigned ints mangle the
7331 * lock offset by mapping the top 32 bits onto the lower 32.
7334 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7335 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7336 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7337 uint32 new_low = 0;
7339 if((new_low = map_lock_offset(high, low)) == 0) {
7340 *err = True;
7341 return (uint64_t)-1;
7344 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7345 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7346 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7347 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7350 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7351 #endif /* HAVE_LONGLONG */
7354 return offset;
7357 NTSTATUS smbd_do_locking(struct smb_request *req,
7358 files_struct *fsp,
7359 uint8_t type,
7360 int32_t timeout,
7361 uint16_t num_ulocks,
7362 struct smbd_lock_element *ulocks,
7363 uint16_t num_locks,
7364 struct smbd_lock_element *locks,
7365 bool *async)
7367 connection_struct *conn = req->conn;
7368 int i;
7369 NTSTATUS status = NT_STATUS_OK;
7371 *async = false;
7373 /* Data now points at the beginning of the list
7374 of smb_unlkrng structs */
7375 for(i = 0; i < (int)num_ulocks; i++) {
7376 struct smbd_lock_element *e = &ulocks[i];
7378 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7379 "pid %u, file %s\n",
7380 (double)e->offset,
7381 (double)e->count,
7382 (unsigned int)e->smblctx,
7383 fsp_str_dbg(fsp)));
7385 if (e->brltype != UNLOCK_LOCK) {
7386 /* this can only happen with SMB2 */
7387 return NT_STATUS_INVALID_PARAMETER;
7390 status = do_unlock(req->sconn->msg_ctx,
7391 fsp,
7392 e->smblctx,
7393 e->count,
7394 e->offset,
7395 WINDOWS_LOCK);
7397 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7398 nt_errstr(status)));
7400 if (!NT_STATUS_IS_OK(status)) {
7401 return status;
7405 /* Setup the timeout in seconds. */
7407 if (!lp_blocking_locks(SNUM(conn))) {
7408 timeout = 0;
7411 /* Data now points at the beginning of the list
7412 of smb_lkrng structs */
7414 for(i = 0; i < (int)num_locks; i++) {
7415 struct smbd_lock_element *e = &locks[i];
7417 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7418 "%llu, file %s timeout = %d\n",
7419 (double)e->offset,
7420 (double)e->count,
7421 (unsigned long long)e->smblctx,
7422 fsp_str_dbg(fsp),
7423 (int)timeout));
7425 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7426 struct blocking_lock_record *blr = NULL;
7428 if (num_locks > 1) {
7430 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7431 * if the lock vector contains one entry. When given mutliple cancel
7432 * requests in a single PDU we expect the server to return an
7433 * error. Windows servers seem to accept the request but only
7434 * cancel the first lock.
7435 * JRA - Do what Windows does (tm) :-).
7438 #if 0
7439 /* MS-CIFS (2.2.4.32.1) behavior. */
7440 return NT_STATUS_DOS(ERRDOS,
7441 ERRcancelviolation);
7442 #else
7443 /* Windows behavior. */
7444 if (i != 0) {
7445 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7446 "cancel request\n"));
7447 continue;
7449 #endif
7452 if (lp_blocking_locks(SNUM(conn))) {
7454 /* Schedule a message to ourselves to
7455 remove the blocking lock record and
7456 return the right error. */
7458 blr = blocking_lock_cancel_smb1(fsp,
7459 e->smblctx,
7460 e->offset,
7461 e->count,
7462 WINDOWS_LOCK,
7463 type,
7464 NT_STATUS_FILE_LOCK_CONFLICT);
7465 if (blr == NULL) {
7466 return NT_STATUS_DOS(
7467 ERRDOS,
7468 ERRcancelviolation);
7471 /* Remove a matching pending lock. */
7472 status = do_lock_cancel(fsp,
7473 e->smblctx,
7474 e->count,
7475 e->offset,
7476 WINDOWS_LOCK,
7477 blr);
7478 } else {
7479 bool blocking_lock = timeout ? true : false;
7480 bool defer_lock = false;
7481 struct byte_range_lock *br_lck;
7482 uint64_t block_smblctx;
7484 br_lck = do_lock(req->sconn->msg_ctx,
7485 fsp,
7486 e->smblctx,
7487 e->count,
7488 e->offset,
7489 e->brltype,
7490 WINDOWS_LOCK,
7491 blocking_lock,
7492 &status,
7493 &block_smblctx,
7494 NULL);
7496 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7497 /* Windows internal resolution for blocking locks seems
7498 to be about 200ms... Don't wait for less than that. JRA. */
7499 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7500 timeout = lp_lock_spin_time();
7502 defer_lock = true;
7505 /* If a lock sent with timeout of zero would fail, and
7506 * this lock has been requested multiple times,
7507 * according to brl_lock_failed() we convert this
7508 * request to a blocking lock with a timeout of between
7509 * 150 - 300 milliseconds.
7511 * If lp_lock_spin_time() has been set to 0, we skip
7512 * this blocking retry and fail immediately.
7514 * Replacement for do_lock_spin(). JRA. */
7516 if (!req->sconn->using_smb2 &&
7517 br_lck && lp_blocking_locks(SNUM(conn)) &&
7518 lp_lock_spin_time() && !blocking_lock &&
7519 NT_STATUS_EQUAL((status),
7520 NT_STATUS_FILE_LOCK_CONFLICT))
7522 defer_lock = true;
7523 timeout = lp_lock_spin_time();
7526 if (br_lck && defer_lock) {
7528 * A blocking lock was requested. Package up
7529 * this smb into a queued request and push it
7530 * onto the blocking lock queue.
7532 if(push_blocking_lock_request(br_lck,
7533 req,
7534 fsp,
7535 timeout,
7537 e->smblctx,
7538 e->brltype,
7539 WINDOWS_LOCK,
7540 e->offset,
7541 e->count,
7542 block_smblctx)) {
7543 TALLOC_FREE(br_lck);
7544 *async = true;
7545 return NT_STATUS_OK;
7549 TALLOC_FREE(br_lck);
7552 if (!NT_STATUS_IS_OK(status)) {
7553 break;
7557 /* If any of the above locks failed, then we must unlock
7558 all of the previous locks (X/Open spec). */
7560 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7562 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7563 i = -1; /* we want to skip the for loop */
7567 * Ensure we don't do a remove on the lock that just failed,
7568 * as under POSIX rules, if we have a lock already there, we
7569 * will delete it (and we shouldn't) .....
7571 for(i--; i >= 0; i--) {
7572 struct smbd_lock_element *e = &locks[i];
7574 do_unlock(req->sconn->msg_ctx,
7575 fsp,
7576 e->smblctx,
7577 e->count,
7578 e->offset,
7579 WINDOWS_LOCK);
7581 return status;
7584 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7585 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7587 return NT_STATUS_OK;
7590 /****************************************************************************
7591 Reply to a lockingX request.
7592 ****************************************************************************/
7594 void reply_lockingX(struct smb_request *req)
7596 connection_struct *conn = req->conn;
7597 files_struct *fsp;
7598 unsigned char locktype;
7599 unsigned char oplocklevel;
7600 uint16 num_ulocks;
7601 uint16 num_locks;
7602 int32 lock_timeout;
7603 int i;
7604 const uint8_t *data;
7605 bool large_file_format;
7606 bool err;
7607 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7608 struct smbd_lock_element *ulocks;
7609 struct smbd_lock_element *locks;
7610 bool async = false;
7612 START_PROFILE(SMBlockingX);
7614 if (req->wct < 8) {
7615 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7616 END_PROFILE(SMBlockingX);
7617 return;
7620 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7621 locktype = CVAL(req->vwv+3, 0);
7622 oplocklevel = CVAL(req->vwv+3, 1);
7623 num_ulocks = SVAL(req->vwv+6, 0);
7624 num_locks = SVAL(req->vwv+7, 0);
7625 lock_timeout = IVAL(req->vwv+4, 0);
7626 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7628 if (!check_fsp(conn, req, fsp)) {
7629 END_PROFILE(SMBlockingX);
7630 return;
7633 data = req->buf;
7635 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7636 /* we don't support these - and CANCEL_LOCK makes w2k
7637 and XP reboot so I don't really want to be
7638 compatible! (tridge) */
7639 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7640 END_PROFILE(SMBlockingX);
7641 return;
7644 /* Check if this is an oplock break on a file
7645 we have granted an oplock on.
7647 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7648 /* Client can insist on breaking to none. */
7649 bool break_to_none = (oplocklevel == 0);
7650 bool result;
7652 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7653 "for fnum = %d\n", (unsigned int)oplocklevel,
7654 fsp->fnum ));
7657 * Make sure we have granted an exclusive or batch oplock on
7658 * this file.
7661 if (fsp->oplock_type == 0) {
7663 /* The Samba4 nbench simulator doesn't understand
7664 the difference between break to level2 and break
7665 to none from level2 - it sends oplock break
7666 replies in both cases. Don't keep logging an error
7667 message here - just ignore it. JRA. */
7669 DEBUG(5,("reply_lockingX: Error : oplock break from "
7670 "client for fnum = %d (oplock=%d) and no "
7671 "oplock granted on this file (%s).\n",
7672 fsp->fnum, fsp->oplock_type,
7673 fsp_str_dbg(fsp)));
7675 /* if this is a pure oplock break request then don't
7676 * send a reply */
7677 if (num_locks == 0 && num_ulocks == 0) {
7678 END_PROFILE(SMBlockingX);
7679 return;
7680 } else {
7681 END_PROFILE(SMBlockingX);
7682 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7683 return;
7687 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7688 (break_to_none)) {
7689 result = remove_oplock(fsp);
7690 } else {
7691 result = downgrade_oplock(fsp);
7694 if (!result) {
7695 DEBUG(0, ("reply_lockingX: error in removing "
7696 "oplock on file %s\n", fsp_str_dbg(fsp)));
7697 /* Hmmm. Is this panic justified? */
7698 smb_panic("internal tdb error");
7701 reply_to_oplock_break_requests(fsp);
7703 /* if this is a pure oplock break request then don't send a
7704 * reply */
7705 if (num_locks == 0 && num_ulocks == 0) {
7706 /* Sanity check - ensure a pure oplock break is not a
7707 chained request. */
7708 if(CVAL(req->vwv+0, 0) != 0xff)
7709 DEBUG(0,("reply_lockingX: Error : pure oplock "
7710 "break is a chained %d request !\n",
7711 (unsigned int)CVAL(req->vwv+0, 0)));
7712 END_PROFILE(SMBlockingX);
7713 return;
7717 if (req->buflen <
7718 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7719 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7720 END_PROFILE(SMBlockingX);
7721 return;
7724 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7725 if (ulocks == NULL) {
7726 reply_nterror(req, NT_STATUS_NO_MEMORY);
7727 END_PROFILE(SMBlockingX);
7728 return;
7731 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7732 if (locks == NULL) {
7733 reply_nterror(req, NT_STATUS_NO_MEMORY);
7734 END_PROFILE(SMBlockingX);
7735 return;
7738 /* Data now points at the beginning of the list
7739 of smb_unlkrng structs */
7740 for(i = 0; i < (int)num_ulocks; i++) {
7741 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7742 ulocks[i].count = get_lock_count(data, i, large_file_format);
7743 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7744 ulocks[i].brltype = UNLOCK_LOCK;
7747 * There is no error code marked "stupid client bug".... :-).
7749 if(err) {
7750 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7751 END_PROFILE(SMBlockingX);
7752 return;
7756 /* Now do any requested locks */
7757 data += ((large_file_format ? 20 : 10)*num_ulocks);
7759 /* Data now points at the beginning of the list
7760 of smb_lkrng structs */
7762 for(i = 0; i < (int)num_locks; i++) {
7763 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7764 locks[i].count = get_lock_count(data, i, large_file_format);
7765 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7767 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7768 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7769 locks[i].brltype = PENDING_READ_LOCK;
7770 } else {
7771 locks[i].brltype = READ_LOCK;
7773 } else {
7774 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7775 locks[i].brltype = PENDING_WRITE_LOCK;
7776 } else {
7777 locks[i].brltype = WRITE_LOCK;
7782 * There is no error code marked "stupid client bug".... :-).
7784 if(err) {
7785 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7786 END_PROFILE(SMBlockingX);
7787 return;
7791 status = smbd_do_locking(req, fsp,
7792 locktype, lock_timeout,
7793 num_ulocks, ulocks,
7794 num_locks, locks,
7795 &async);
7796 if (!NT_STATUS_IS_OK(status)) {
7797 END_PROFILE(SMBlockingX);
7798 reply_nterror(req, status);
7799 return;
7801 if (async) {
7802 END_PROFILE(SMBlockingX);
7803 return;
7806 reply_outbuf(req, 2, 0);
7808 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7809 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7811 END_PROFILE(SMBlockingX);
7812 chain_reply(req);
7815 #undef DBGC_CLASS
7816 #define DBGC_CLASS DBGC_ALL
7818 /****************************************************************************
7819 Reply to a SMBreadbmpx (read block multiplex) request.
7820 Always reply with an error, if someone has a platform really needs this,
7821 please contact vl@samba.org
7822 ****************************************************************************/
7824 void reply_readbmpx(struct smb_request *req)
7826 START_PROFILE(SMBreadBmpx);
7827 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7828 END_PROFILE(SMBreadBmpx);
7829 return;
7832 /****************************************************************************
7833 Reply to a SMBreadbs (read block multiplex secondary) request.
7834 Always reply with an error, if someone has a platform really needs this,
7835 please contact vl@samba.org
7836 ****************************************************************************/
7838 void reply_readbs(struct smb_request *req)
7840 START_PROFILE(SMBreadBs);
7841 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7842 END_PROFILE(SMBreadBs);
7843 return;
7846 /****************************************************************************
7847 Reply to a SMBsetattrE.
7848 ****************************************************************************/
7850 void reply_setattrE(struct smb_request *req)
7852 connection_struct *conn = req->conn;
7853 struct smb_file_time ft;
7854 files_struct *fsp;
7855 NTSTATUS status;
7857 START_PROFILE(SMBsetattrE);
7858 ZERO_STRUCT(ft);
7860 if (req->wct < 7) {
7861 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7862 goto out;
7865 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7867 if(!fsp || (fsp->conn != conn)) {
7868 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7869 goto out;
7873 * Convert the DOS times into unix times.
7876 ft.atime = convert_time_t_to_timespec(
7877 srv_make_unix_date2(req->vwv+3));
7878 ft.mtime = convert_time_t_to_timespec(
7879 srv_make_unix_date2(req->vwv+5));
7880 ft.create_time = convert_time_t_to_timespec(
7881 srv_make_unix_date2(req->vwv+1));
7883 reply_outbuf(req, 0, 0);
7886 * Patch from Ray Frush <frush@engr.colostate.edu>
7887 * Sometimes times are sent as zero - ignore them.
7890 /* Ensure we have a valid stat struct for the source. */
7891 status = vfs_stat_fsp(fsp);
7892 if (!NT_STATUS_IS_OK(status)) {
7893 reply_nterror(req, status);
7894 goto out;
7897 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7898 if (!NT_STATUS_IS_OK(status)) {
7899 reply_nterror(req, status);
7900 goto out;
7903 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7904 " createtime=%u\n",
7905 fsp->fnum,
7906 (unsigned int)ft.atime.tv_sec,
7907 (unsigned int)ft.mtime.tv_sec,
7908 (unsigned int)ft.create_time.tv_sec
7910 out:
7911 END_PROFILE(SMBsetattrE);
7912 return;
7916 /* Back from the dead for OS/2..... JRA. */
7918 /****************************************************************************
7919 Reply to a SMBwritebmpx (write block multiplex primary) request.
7920 Always reply with an error, if someone has a platform really needs this,
7921 please contact vl@samba.org
7922 ****************************************************************************/
7924 void reply_writebmpx(struct smb_request *req)
7926 START_PROFILE(SMBwriteBmpx);
7927 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7928 END_PROFILE(SMBwriteBmpx);
7929 return;
7932 /****************************************************************************
7933 Reply to a SMBwritebs (write block multiplex secondary) request.
7934 Always reply with an error, if someone has a platform really needs this,
7935 please contact vl@samba.org
7936 ****************************************************************************/
7938 void reply_writebs(struct smb_request *req)
7940 START_PROFILE(SMBwriteBs);
7941 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7942 END_PROFILE(SMBwriteBs);
7943 return;
7946 /****************************************************************************
7947 Reply to a SMBgetattrE.
7948 ****************************************************************************/
7950 void reply_getattrE(struct smb_request *req)
7952 connection_struct *conn = req->conn;
7953 int mode;
7954 files_struct *fsp;
7955 struct timespec create_ts;
7957 START_PROFILE(SMBgetattrE);
7959 if (req->wct < 1) {
7960 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7961 END_PROFILE(SMBgetattrE);
7962 return;
7965 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7967 if(!fsp || (fsp->conn != conn)) {
7968 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7969 END_PROFILE(SMBgetattrE);
7970 return;
7973 /* Do an fstat on this file */
7974 if(fsp_stat(fsp)) {
7975 reply_nterror(req, map_nt_error_from_unix(errno));
7976 END_PROFILE(SMBgetattrE);
7977 return;
7980 mode = dos_mode(conn, fsp->fsp_name);
7983 * Convert the times into dos times. Set create
7984 * date to be last modify date as UNIX doesn't save
7985 * this.
7988 reply_outbuf(req, 11, 0);
7990 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7991 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7992 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7993 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7994 /* Should we check pending modtime here ? JRA */
7995 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7996 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7998 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
7999 SIVAL(req->outbuf, smb_vwv6, 0);
8000 SIVAL(req->outbuf, smb_vwv8, 0);
8001 } else {
8002 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8003 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8004 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8006 SSVAL(req->outbuf,smb_vwv10, mode);
8008 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8010 END_PROFILE(SMBgetattrE);
8011 return;