First part of fix for bug #8673 - NT ACL issue.
[Samba.git] / source3 / smbd / reply.c
blob4954098de7d513e936949d57dfbe2e5cff96e05a
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
45 /****************************************************************************
46 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
47 path or anything including wildcards.
48 We're assuming here that '/' is not the second byte in any multibyte char
49 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
50 set.
51 ****************************************************************************/
53 /* Custom version for processing POSIX paths. */
54 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
56 static NTSTATUS check_path_syntax_internal(char *path,
57 bool posix_path,
58 bool *p_last_component_contains_wcard)
60 char *d = path;
61 const char *s = path;
62 NTSTATUS ret = NT_STATUS_OK;
63 bool start_of_name_component = True;
64 bool stream_started = false;
66 *p_last_component_contains_wcard = False;
68 while (*s) {
69 if (stream_started) {
70 switch (*s) {
71 case '/':
72 case '\\':
73 return NT_STATUS_OBJECT_NAME_INVALID;
74 case ':':
75 if (s[1] == '\0') {
76 return NT_STATUS_OBJECT_NAME_INVALID;
78 if (strchr_m(&s[1], ':')) {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 break;
85 if ((*s == ':') && !posix_path && !stream_started) {
86 if (*p_last_component_contains_wcard) {
87 return NT_STATUS_OBJECT_NAME_INVALID;
89 /* Stream names allow more characters than file names.
90 We're overloading posix_path here to allow a wider
91 range of characters. If stream_started is true this
92 is still a Windows path even if posix_path is true.
93 JRA.
95 stream_started = true;
96 start_of_name_component = false;
97 posix_path = true;
99 if (s[1] == '\0') {
100 return NT_STATUS_OBJECT_NAME_INVALID;
104 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
106 * Safe to assume is not the second part of a mb char
107 * as this is handled below.
109 /* Eat multiple '/' or '\\' */
110 while (IS_PATH_SEP(*s,posix_path)) {
111 s++;
113 if ((d != path) && (*s != '\0')) {
114 /* We only care about non-leading or trailing '/' or '\\' */
115 *d++ = '/';
118 start_of_name_component = True;
119 /* New component. */
120 *p_last_component_contains_wcard = False;
121 continue;
124 if (start_of_name_component) {
125 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
126 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
129 * No mb char starts with '.' so we're safe checking the directory separator here.
132 /* If we just added a '/' - delete it */
133 if ((d > path) && (*(d-1) == '/')) {
134 *(d-1) = '\0';
135 d--;
138 /* Are we at the start ? Can't go back further if so. */
139 if (d <= path) {
140 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
141 break;
143 /* Go back one level... */
144 /* We know this is safe as '/' cannot be part of a mb sequence. */
145 /* NOTE - if this assumption is invalid we are not in good shape... */
146 /* Decrement d first as d points to the *next* char to write into. */
147 for (d--; d > path; d--) {
148 if (*d == '/')
149 break;
151 s += 2; /* Else go past the .. */
152 /* We're still at the start of a name component, just the previous one. */
153 continue;
155 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
156 if (posix_path) {
157 /* Eat the '.' */
158 s++;
159 continue;
165 if (!(*s & 0x80)) {
166 if (!posix_path) {
167 if (*s <= 0x1f || *s == '|') {
168 return NT_STATUS_OBJECT_NAME_INVALID;
170 switch (*s) {
171 case '*':
172 case '?':
173 case '<':
174 case '>':
175 case '"':
176 *p_last_component_contains_wcard = True;
177 break;
178 default:
179 break;
182 *d++ = *s++;
183 } else {
184 size_t siz;
185 /* Get the size of the next MB character. */
186 next_codepoint(s,&siz);
187 switch(siz) {
188 case 5:
189 *d++ = *s++;
190 /*fall through*/
191 case 4:
192 *d++ = *s++;
193 /*fall through*/
194 case 3:
195 *d++ = *s++;
196 /*fall through*/
197 case 2:
198 *d++ = *s++;
199 /*fall through*/
200 case 1:
201 *d++ = *s++;
202 break;
203 default:
204 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
205 *d = '\0';
206 return NT_STATUS_INVALID_PARAMETER;
209 start_of_name_component = False;
212 *d = '\0';
214 return ret;
217 /****************************************************************************
218 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
219 No wildcards allowed.
220 ****************************************************************************/
222 NTSTATUS check_path_syntax(char *path)
224 bool ignore;
225 return check_path_syntax_internal(path, False, &ignore);
228 /****************************************************************************
229 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
230 Wildcards allowed - p_contains_wcard returns true if the last component contained
231 a wildcard.
232 ****************************************************************************/
234 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
236 return check_path_syntax_internal(path, False, p_contains_wcard);
239 /****************************************************************************
240 Check the path for a POSIX client.
241 We're assuming here that '/' is not the second byte in any multibyte char
242 set (a safe assumption).
243 ****************************************************************************/
245 NTSTATUS check_path_syntax_posix(char *path)
247 bool ignore;
248 return check_path_syntax_internal(path, True, &ignore);
251 /****************************************************************************
252 Pull a string and check the path allowing a wilcard - provide for error return.
253 ****************************************************************************/
255 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
256 const char *base_ptr,
257 uint16 smb_flags2,
258 char **pp_dest,
259 const char *src,
260 size_t src_len,
261 int flags,
262 NTSTATUS *err,
263 bool *contains_wcard)
265 size_t ret;
267 *pp_dest = NULL;
269 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
270 src_len, flags);
272 if (!*pp_dest) {
273 *err = NT_STATUS_INVALID_PARAMETER;
274 return ret;
277 *contains_wcard = False;
279 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
281 * For a DFS path the function parse_dfs_path()
282 * will do the path processing, just make a copy.
284 *err = NT_STATUS_OK;
285 return ret;
288 if (lp_posix_pathnames()) {
289 *err = check_path_syntax_posix(*pp_dest);
290 } else {
291 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
294 return ret;
297 /****************************************************************************
298 Pull a string and check the path - provide for error return.
299 ****************************************************************************/
301 size_t srvstr_get_path(TALLOC_CTX *ctx,
302 const char *base_ptr,
303 uint16 smb_flags2,
304 char **pp_dest,
305 const char *src,
306 size_t src_len,
307 int flags,
308 NTSTATUS *err)
310 bool ignore;
311 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
312 src_len, flags, err, &ignore);
315 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
316 char **pp_dest, const char *src, int flags,
317 NTSTATUS *err, bool *contains_wcard)
319 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
320 pp_dest, src, smbreq_bufrem(req, src),
321 flags, err, contains_wcard);
324 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
325 char **pp_dest, const char *src, int flags,
326 NTSTATUS *err)
328 bool ignore;
329 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
330 flags, err, &ignore);
333 /****************************************************************************
334 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
335 ****************************************************************************/
337 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
338 files_struct *fsp)
340 if ((fsp == NULL) || (conn == NULL)) {
341 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
342 return False;
344 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
345 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
346 return False;
348 return True;
351 /****************************************************************************
352 Check if we have a correct fsp pointing to a file.
353 ****************************************************************************/
355 bool check_fsp(connection_struct *conn, struct smb_request *req,
356 files_struct *fsp)
358 if (!check_fsp_open(conn, req, fsp)) {
359 return False;
361 if (fsp->is_directory) {
362 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
363 return False;
365 if (fsp->fh->fd == -1) {
366 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
367 return False;
369 fsp->num_smb_operations++;
370 return True;
373 /****************************************************************************
374 Check if we have a correct fsp pointing to a quota fake file. Replacement for
375 the CHECK_NTQUOTA_HANDLE_OK macro.
376 ****************************************************************************/
378 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
379 files_struct *fsp)
381 if (!check_fsp_open(conn, req, fsp)) {
382 return false;
385 if (fsp->is_directory) {
386 return false;
389 if (fsp->fake_file_handle == NULL) {
390 return false;
393 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
394 return false;
397 if (fsp->fake_file_handle->private_data == NULL) {
398 return false;
401 return true;
404 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
405 const char *name, int name_type)
407 char *trim_name;
408 char *trim_name_type;
409 const char *retarget_parm;
410 char *retarget;
411 char *p;
412 int retarget_type = 0x20;
413 int retarget_port = 139;
414 struct sockaddr_storage retarget_addr;
415 struct sockaddr_in *in_addr;
416 bool ret = false;
417 uint8_t outbuf[10];
419 if (get_socket_port(sconn->sock) != 139) {
420 return false;
423 trim_name = talloc_strdup(talloc_tos(), name);
424 if (trim_name == NULL) {
425 goto fail;
427 trim_char(trim_name, ' ', ' ');
429 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
430 name_type);
431 if (trim_name_type == NULL) {
432 goto fail;
435 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
436 trim_name_type, NULL);
437 if (retarget_parm == NULL) {
438 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
439 trim_name, NULL);
441 if (retarget_parm == NULL) {
442 goto fail;
445 retarget = talloc_strdup(trim_name, retarget_parm);
446 if (retarget == NULL) {
447 goto fail;
450 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
452 p = strchr(retarget, ':');
453 if (p != NULL) {
454 *p++ = '\0';
455 retarget_port = atoi(p);
458 p = strchr_m(retarget, '#');
459 if (p != NULL) {
460 *p++ = '\0';
461 if (sscanf(p, "%x", &retarget_type) != 1) {
462 goto fail;
466 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
467 if (!ret) {
468 DEBUG(10, ("could not resolve %s\n", retarget));
469 goto fail;
472 if (retarget_addr.ss_family != AF_INET) {
473 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
474 goto fail;
477 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
479 _smb_setlen(outbuf, 6);
480 SCVAL(outbuf, 0, 0x84);
481 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
482 *(uint16_t *)(outbuf+8) = htons(retarget_port);
484 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
485 NULL)) {
486 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
487 "failed.");
490 ret = true;
491 fail:
492 TALLOC_FREE(trim_name);
493 return ret;
496 static void reply_called_name_not_present(char *outbuf)
498 smb_setlen(outbuf, 1);
499 SCVAL(outbuf, 0, 0x83);
500 SCVAL(outbuf, 4, 0x82);
503 /****************************************************************************
504 Reply to a (netbios-level) special message.
505 ****************************************************************************/
507 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
509 int msg_type = CVAL(inbuf,0);
510 int msg_flags = CVAL(inbuf,1);
512 * We only really use 4 bytes of the outbuf, but for the smb_setlen
513 * calculation & friends (srv_send_smb uses that) we need the full smb
514 * header.
516 char outbuf[smb_size];
518 memset(outbuf, '\0', sizeof(outbuf));
520 smb_setlen(outbuf,0);
522 switch (msg_type) {
523 case NBSSrequest: /* session request */
525 /* inbuf_size is guarenteed to be at least 4. */
526 fstring name1,name2;
527 int name_type1, name_type2;
528 int name_len1, name_len2;
530 *name1 = *name2 = 0;
532 if (sconn->nbt.got_session) {
533 exit_server_cleanly("multiple session request not permitted");
536 SCVAL(outbuf,0,NBSSpositive);
537 SCVAL(outbuf,3,0);
539 /* inbuf_size is guaranteed to be at least 4. */
540 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
541 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
542 DEBUG(0,("Invalid name length in session request\n"));
543 reply_called_name_not_present(outbuf);
544 break;
546 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
547 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
548 DEBUG(0,("Invalid name length in session request\n"));
549 reply_called_name_not_present(outbuf);
550 break;
553 name_type1 = name_extract((unsigned char *)inbuf,
554 inbuf_size,(unsigned int)4,name1);
555 name_type2 = name_extract((unsigned char *)inbuf,
556 inbuf_size,(unsigned int)(4 + name_len1),name2);
558 if (name_type1 == -1 || name_type2 == -1) {
559 DEBUG(0,("Invalid name type in session request\n"));
560 reply_called_name_not_present(outbuf);
561 break;
564 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
565 name1, name_type1, name2, name_type2));
567 if (netbios_session_retarget(sconn, name1, name_type1)) {
568 exit_server_cleanly("retargeted client");
572 * Windows NT/2k uses "*SMBSERVER" and XP uses
573 * "*SMBSERV" arrggg!!!
575 if (strequal(name1, "*SMBSERVER ")
576 || strequal(name1, "*SMBSERV ")) {
577 char *raddr;
579 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
580 talloc_tos());
581 if (raddr == NULL) {
582 exit_server_cleanly("could not allocate raddr");
585 fstrcpy(name1, raddr);
588 set_local_machine_name(name1, True);
589 set_remote_machine_name(name2, True);
591 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
592 get_local_machine_name(), get_remote_machine_name(),
593 name_type2));
595 if (name_type2 == 'R') {
596 /* We are being asked for a pathworks session ---
597 no thanks! */
598 reply_called_name_not_present(outbuf);
599 break;
602 /* only add the client's machine name to the list
603 of possibly valid usernames if we are operating
604 in share mode security */
605 if (lp_security() == SEC_SHARE) {
606 add_session_user(sconn, get_remote_machine_name());
609 reload_services(sconn, conn_snum_used, true);
610 reopen_logs();
612 sconn->nbt.got_session = true;
613 break;
616 case 0x89: /* session keepalive request
617 (some old clients produce this?) */
618 SCVAL(outbuf,0,NBSSkeepalive);
619 SCVAL(outbuf,3,0);
620 break;
622 case NBSSpositive: /* positive session response */
623 case NBSSnegative: /* negative session response */
624 case NBSSretarget: /* retarget session response */
625 DEBUG(0,("Unexpected session response\n"));
626 break;
628 case NBSSkeepalive: /* session keepalive */
629 default:
630 return;
633 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
634 msg_type, msg_flags));
636 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
638 if (CVAL(outbuf, 0) != 0x82) {
639 exit_server_cleanly("invalid netbios session");
641 return;
644 /****************************************************************************
645 Reply to a tcon.
646 conn POINTER CAN BE NULL HERE !
647 ****************************************************************************/
649 void reply_tcon(struct smb_request *req)
651 connection_struct *conn = req->conn;
652 const char *service;
653 char *service_buf = NULL;
654 char *password = NULL;
655 char *dev = NULL;
656 int pwlen=0;
657 NTSTATUS nt_status;
658 const char *p;
659 DATA_BLOB password_blob;
660 TALLOC_CTX *ctx = talloc_tos();
661 struct smbd_server_connection *sconn = req->sconn;
663 START_PROFILE(SMBtcon);
665 if (req->buflen < 4) {
666 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
667 END_PROFILE(SMBtcon);
668 return;
671 p = (const char *)req->buf + 1;
672 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
673 p += 1;
674 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
675 p += pwlen+1;
676 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
677 p += 1;
679 if (service_buf == NULL || password == NULL || dev == NULL) {
680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
681 END_PROFILE(SMBtcon);
682 return;
684 p = strrchr_m(service_buf,'\\');
685 if (p) {
686 service = p+1;
687 } else {
688 service = service_buf;
691 password_blob = data_blob(password, pwlen+1);
693 conn = make_connection(sconn,service,password_blob,dev,
694 req->vuid,&nt_status);
695 req->conn = conn;
697 data_blob_clear_free(&password_blob);
699 if (!conn) {
700 reply_nterror(req, nt_status);
701 END_PROFILE(SMBtcon);
702 return;
705 reply_outbuf(req, 2, 0);
706 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
707 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
708 SSVAL(req->outbuf,smb_tid,conn->cnum);
710 DEBUG(3,("tcon service=%s cnum=%d\n",
711 service, conn->cnum));
713 END_PROFILE(SMBtcon);
714 return;
717 /****************************************************************************
718 Reply to a tcon and X.
719 conn POINTER CAN BE NULL HERE !
720 ****************************************************************************/
722 void reply_tcon_and_X(struct smb_request *req)
724 connection_struct *conn = req->conn;
725 const char *service = NULL;
726 DATA_BLOB password;
727 TALLOC_CTX *ctx = talloc_tos();
728 /* what the cleint thinks the device is */
729 char *client_devicetype = NULL;
730 /* what the server tells the client the share represents */
731 const char *server_devicetype;
732 NTSTATUS nt_status;
733 int passlen;
734 char *path = NULL;
735 const char *p, *q;
736 uint16 tcon_flags;
737 struct smbd_server_connection *sconn = req->sconn;
739 START_PROFILE(SMBtconX);
741 if (req->wct < 4) {
742 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
743 END_PROFILE(SMBtconX);
744 return;
747 passlen = SVAL(req->vwv+3, 0);
748 tcon_flags = SVAL(req->vwv+2, 0);
750 /* we might have to close an old one */
751 if ((tcon_flags & 0x1) && conn) {
752 close_cnum(conn,req->vuid);
753 req->conn = NULL;
754 conn = NULL;
757 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
758 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
759 END_PROFILE(SMBtconX);
760 return;
763 if (sconn->smb1.negprot.encrypted_passwords) {
764 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
765 if (lp_security() == SEC_SHARE) {
767 * Security = share always has a pad byte
768 * after the password.
770 p = (const char *)req->buf + passlen + 1;
771 } else {
772 p = (const char *)req->buf + passlen;
774 } else {
775 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
776 /* Ensure correct termination */
777 password.data[passlen]=0;
778 p = (const char *)req->buf + passlen + 1;
781 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
783 if (path == NULL) {
784 data_blob_clear_free(&password);
785 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
786 END_PROFILE(SMBtconX);
787 return;
791 * the service name can be either: \\server\share
792 * or share directly like on the DELL PowerVault 705
794 if (*path=='\\') {
795 q = strchr_m(path+2,'\\');
796 if (!q) {
797 data_blob_clear_free(&password);
798 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
799 END_PROFILE(SMBtconX);
800 return;
802 service = q+1;
803 } else {
804 service = path;
807 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
808 &client_devicetype, p,
809 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
811 if (client_devicetype == NULL) {
812 data_blob_clear_free(&password);
813 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
814 END_PROFILE(SMBtconX);
815 return;
818 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
820 conn = make_connection(sconn, service, password, client_devicetype,
821 req->vuid, &nt_status);
822 req->conn =conn;
824 data_blob_clear_free(&password);
826 if (!conn) {
827 reply_nterror(req, nt_status);
828 END_PROFILE(SMBtconX);
829 return;
832 if ( IS_IPC(conn) )
833 server_devicetype = "IPC";
834 else if ( IS_PRINT(conn) )
835 server_devicetype = "LPT1:";
836 else
837 server_devicetype = "A:";
839 if (get_Protocol() < PROTOCOL_NT1) {
840 reply_outbuf(req, 2, 0);
841 if (message_push_string(&req->outbuf, server_devicetype,
842 STR_TERMINATE|STR_ASCII) == -1) {
843 reply_nterror(req, NT_STATUS_NO_MEMORY);
844 END_PROFILE(SMBtconX);
845 return;
847 } else {
848 /* NT sets the fstype of IPC$ to the null string */
849 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
851 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
852 /* Return permissions. */
853 uint32 perm1 = 0;
854 uint32 perm2 = 0;
856 reply_outbuf(req, 7, 0);
858 if (IS_IPC(conn)) {
859 perm1 = FILE_ALL_ACCESS;
860 perm2 = FILE_ALL_ACCESS;
861 } else {
862 perm1 = conn->share_access;
865 SIVAL(req->outbuf, smb_vwv3, perm1);
866 SIVAL(req->outbuf, smb_vwv5, perm2);
867 } else {
868 reply_outbuf(req, 3, 0);
871 if ((message_push_string(&req->outbuf, server_devicetype,
872 STR_TERMINATE|STR_ASCII) == -1)
873 || (message_push_string(&req->outbuf, fstype,
874 STR_TERMINATE) == -1)) {
875 reply_nterror(req, NT_STATUS_NO_MEMORY);
876 END_PROFILE(SMBtconX);
877 return;
880 /* what does setting this bit do? It is set by NT4 and
881 may affect the ability to autorun mounted cdroms */
882 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
883 (lp_csc_policy(SNUM(conn)) << 2));
885 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
886 DEBUG(2,("Serving %s as a Dfs root\n",
887 lp_servicename(SNUM(conn)) ));
888 SSVAL(req->outbuf, smb_vwv2,
889 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
894 DEBUG(3,("tconX service=%s \n",
895 service));
897 /* set the incoming and outgoing tid to the just created one */
898 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
899 SSVAL(req->outbuf,smb_tid,conn->cnum);
901 END_PROFILE(SMBtconX);
903 req->tid = conn->cnum;
904 chain_reply(req);
905 return;
908 /****************************************************************************
909 Reply to an unknown type.
910 ****************************************************************************/
912 void reply_unknown_new(struct smb_request *req, uint8 type)
914 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
915 smb_fn_name(type), type, type));
916 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
917 return;
920 /****************************************************************************
921 Reply to an ioctl.
922 conn POINTER CAN BE NULL HERE !
923 ****************************************************************************/
925 void reply_ioctl(struct smb_request *req)
927 connection_struct *conn = req->conn;
928 uint16 device;
929 uint16 function;
930 uint32 ioctl_code;
931 int replysize;
932 char *p;
934 START_PROFILE(SMBioctl);
936 if (req->wct < 3) {
937 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
938 END_PROFILE(SMBioctl);
939 return;
942 device = SVAL(req->vwv+1, 0);
943 function = SVAL(req->vwv+2, 0);
944 ioctl_code = (device << 16) + function;
946 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
948 switch (ioctl_code) {
949 case IOCTL_QUERY_JOB_INFO:
950 replysize = 32;
951 break;
952 default:
953 reply_force_doserror(req, ERRSRV, ERRnosupport);
954 END_PROFILE(SMBioctl);
955 return;
958 reply_outbuf(req, 8, replysize+1);
959 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
960 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
961 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
962 p = smb_buf(req->outbuf);
963 memset(p, '\0', replysize+1); /* valgrind-safe. */
964 p += 1; /* Allow for alignment */
966 switch (ioctl_code) {
967 case IOCTL_QUERY_JOB_INFO:
969 files_struct *fsp = file_fsp(
970 req, SVAL(req->vwv+0, 0));
971 if (!fsp) {
972 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
973 END_PROFILE(SMBioctl);
974 return;
976 /* Job number */
977 if (fsp->print_file) {
978 SSVAL(p, 0, fsp->print_file->rap_jobid);
979 } else {
980 SSVAL(p, 0, 0);
982 srvstr_push((char *)req->outbuf, req->flags2, p+2,
983 lp_netbios_name(), 15,
984 STR_TERMINATE|STR_ASCII);
985 if (conn) {
986 srvstr_push((char *)req->outbuf, req->flags2,
987 p+18, lp_servicename(SNUM(conn)),
988 13, STR_TERMINATE|STR_ASCII);
989 } else {
990 memset(p+18, 0, 13);
992 break;
996 END_PROFILE(SMBioctl);
997 return;
1000 /****************************************************************************
1001 Strange checkpath NTSTATUS mapping.
1002 ****************************************************************************/
1004 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1006 /* Strange DOS error code semantics only for checkpath... */
1007 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1008 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1009 /* We need to map to ERRbadpath */
1010 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1013 return status;
1016 /****************************************************************************
1017 Reply to a checkpath.
1018 ****************************************************************************/
1020 void reply_checkpath(struct smb_request *req)
1022 connection_struct *conn = req->conn;
1023 struct smb_filename *smb_fname = NULL;
1024 char *name = NULL;
1025 NTSTATUS status;
1026 TALLOC_CTX *ctx = talloc_tos();
1028 START_PROFILE(SMBcheckpath);
1030 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1031 STR_TERMINATE, &status);
1033 if (!NT_STATUS_IS_OK(status)) {
1034 status = map_checkpath_error(req->flags2, status);
1035 reply_nterror(req, status);
1036 END_PROFILE(SMBcheckpath);
1037 return;
1040 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1042 status = filename_convert(ctx,
1043 conn,
1044 req->flags2 & FLAGS2_DFS_PATHNAMES,
1045 name,
1047 NULL,
1048 &smb_fname);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1052 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1053 ERRSRV, ERRbadpath);
1054 END_PROFILE(SMBcheckpath);
1055 return;
1057 goto path_err;
1060 if (!VALID_STAT(smb_fname->st) &&
1061 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1062 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1063 smb_fname_str_dbg(smb_fname), strerror(errno)));
1064 status = map_nt_error_from_unix(errno);
1065 goto path_err;
1068 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1069 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1070 ERRDOS, ERRbadpath);
1071 goto out;
1074 reply_outbuf(req, 0, 0);
1076 path_err:
1077 /* We special case this - as when a Windows machine
1078 is parsing a path is steps through the components
1079 one at a time - if a component fails it expects
1080 ERRbadpath, not ERRbadfile.
1082 status = map_checkpath_error(req->flags2, status);
1083 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1085 * Windows returns different error codes if
1086 * the parent directory is valid but not the
1087 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1088 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1089 * if the path is invalid.
1091 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1092 ERRDOS, ERRbadpath);
1093 goto out;
1096 reply_nterror(req, status);
1098 out:
1099 TALLOC_FREE(smb_fname);
1100 END_PROFILE(SMBcheckpath);
1101 return;
1104 /****************************************************************************
1105 Reply to a getatr.
1106 ****************************************************************************/
1108 void reply_getatr(struct smb_request *req)
1110 connection_struct *conn = req->conn;
1111 struct smb_filename *smb_fname = NULL;
1112 char *fname = NULL;
1113 int mode=0;
1114 SMB_OFF_T size=0;
1115 time_t mtime=0;
1116 const char *p;
1117 NTSTATUS status;
1118 TALLOC_CTX *ctx = talloc_tos();
1119 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1121 START_PROFILE(SMBgetatr);
1123 p = (const char *)req->buf + 1;
1124 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 reply_nterror(req, status);
1127 goto out;
1130 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1131 under WfWg - weird! */
1132 if (*fname == '\0') {
1133 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1134 if (!CAN_WRITE(conn)) {
1135 mode |= FILE_ATTRIBUTE_READONLY;
1137 size = 0;
1138 mtime = 0;
1139 } else {
1140 status = filename_convert(ctx,
1141 conn,
1142 req->flags2 & FLAGS2_DFS_PATHNAMES,
1143 fname,
1145 NULL,
1146 &smb_fname);
1147 if (!NT_STATUS_IS_OK(status)) {
1148 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1149 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1150 ERRSRV, ERRbadpath);
1151 goto out;
1153 reply_nterror(req, status);
1154 goto out;
1156 if (!VALID_STAT(smb_fname->st) &&
1157 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1158 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1159 smb_fname_str_dbg(smb_fname),
1160 strerror(errno)));
1161 reply_nterror(req, map_nt_error_from_unix(errno));
1162 goto out;
1165 mode = dos_mode(conn, smb_fname);
1166 size = smb_fname->st.st_ex_size;
1168 if (ask_sharemode) {
1169 struct timespec write_time_ts;
1170 struct file_id fileid;
1172 ZERO_STRUCT(write_time_ts);
1173 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1174 get_file_infos(fileid, 0, NULL, &write_time_ts);
1175 if (!null_timespec(write_time_ts)) {
1176 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1180 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1181 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1182 size = 0;
1186 reply_outbuf(req, 10, 0);
1188 SSVAL(req->outbuf,smb_vwv0,mode);
1189 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1190 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1191 } else {
1192 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1194 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1196 if (get_Protocol() >= PROTOCOL_NT1) {
1197 SSVAL(req->outbuf, smb_flg2,
1198 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1201 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1202 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1204 out:
1205 TALLOC_FREE(smb_fname);
1206 TALLOC_FREE(fname);
1207 END_PROFILE(SMBgetatr);
1208 return;
1211 /****************************************************************************
1212 Reply to a setatr.
1213 ****************************************************************************/
1215 void reply_setatr(struct smb_request *req)
1217 struct smb_file_time ft;
1218 connection_struct *conn = req->conn;
1219 struct smb_filename *smb_fname = NULL;
1220 char *fname = NULL;
1221 int mode;
1222 time_t mtime;
1223 const char *p;
1224 NTSTATUS status;
1225 TALLOC_CTX *ctx = talloc_tos();
1227 START_PROFILE(SMBsetatr);
1229 ZERO_STRUCT(ft);
1231 if (req->wct < 2) {
1232 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1233 goto out;
1236 p = (const char *)req->buf + 1;
1237 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1238 if (!NT_STATUS_IS_OK(status)) {
1239 reply_nterror(req, status);
1240 goto out;
1243 status = filename_convert(ctx,
1244 conn,
1245 req->flags2 & FLAGS2_DFS_PATHNAMES,
1246 fname,
1248 NULL,
1249 &smb_fname);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1252 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1253 ERRSRV, ERRbadpath);
1254 goto out;
1256 reply_nterror(req, status);
1257 goto out;
1260 if (smb_fname->base_name[0] == '.' &&
1261 smb_fname->base_name[1] == '\0') {
1263 * Not sure here is the right place to catch this
1264 * condition. Might be moved to somewhere else later -- vl
1266 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1267 goto out;
1270 mode = SVAL(req->vwv+0, 0);
1271 mtime = srv_make_unix_date3(req->vwv+1);
1273 if (mode != FILE_ATTRIBUTE_NORMAL) {
1274 if (VALID_STAT_OF_DIR(smb_fname->st))
1275 mode |= FILE_ATTRIBUTE_DIRECTORY;
1276 else
1277 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1279 status = check_access(conn, NULL, smb_fname,
1280 FILE_WRITE_ATTRIBUTES);
1281 if (!NT_STATUS_IS_OK(status)) {
1282 reply_nterror(req, status);
1283 goto out;
1286 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1287 false) != 0) {
1288 reply_nterror(req, map_nt_error_from_unix(errno));
1289 goto out;
1293 ft.mtime = convert_time_t_to_timespec(mtime);
1294 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1295 if (!NT_STATUS_IS_OK(status)) {
1296 reply_nterror(req, status);
1297 goto out;
1300 reply_outbuf(req, 0, 0);
1302 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1303 mode));
1304 out:
1305 TALLOC_FREE(smb_fname);
1306 END_PROFILE(SMBsetatr);
1307 return;
1310 /****************************************************************************
1311 Reply to a dskattr.
1312 ****************************************************************************/
1314 void reply_dskattr(struct smb_request *req)
1316 connection_struct *conn = req->conn;
1317 uint64_t dfree,dsize,bsize;
1318 START_PROFILE(SMBdskattr);
1320 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1321 reply_nterror(req, map_nt_error_from_unix(errno));
1322 END_PROFILE(SMBdskattr);
1323 return;
1326 reply_outbuf(req, 5, 0);
1328 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1329 double total_space, free_space;
1330 /* we need to scale this to a number that DOS6 can handle. We
1331 use floating point so we can handle large drives on systems
1332 that don't have 64 bit integers
1334 we end up displaying a maximum of 2G to DOS systems
1336 total_space = dsize * (double)bsize;
1337 free_space = dfree * (double)bsize;
1339 dsize = (uint64_t)((total_space+63*512) / (64*512));
1340 dfree = (uint64_t)((free_space+63*512) / (64*512));
1342 if (dsize > 0xFFFF) dsize = 0xFFFF;
1343 if (dfree > 0xFFFF) dfree = 0xFFFF;
1345 SSVAL(req->outbuf,smb_vwv0,dsize);
1346 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1347 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1348 SSVAL(req->outbuf,smb_vwv3,dfree);
1349 } else {
1350 SSVAL(req->outbuf,smb_vwv0,dsize);
1351 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1352 SSVAL(req->outbuf,smb_vwv2,512);
1353 SSVAL(req->outbuf,smb_vwv3,dfree);
1356 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1358 END_PROFILE(SMBdskattr);
1359 return;
1363 * Utility function to split the filename from the directory.
1365 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1366 char **fname_dir_out,
1367 char **fname_mask_out)
1369 const char *p = NULL;
1370 char *fname_dir = NULL;
1371 char *fname_mask = NULL;
1373 p = strrchr_m(fname_in, '/');
1374 if (!p) {
1375 fname_dir = talloc_strdup(ctx, ".");
1376 fname_mask = talloc_strdup(ctx, fname_in);
1377 } else {
1378 fname_dir = talloc_strndup(ctx, fname_in,
1379 PTR_DIFF(p, fname_in));
1380 fname_mask = talloc_strdup(ctx, p+1);
1383 if (!fname_dir || !fname_mask) {
1384 TALLOC_FREE(fname_dir);
1385 TALLOC_FREE(fname_mask);
1386 return NT_STATUS_NO_MEMORY;
1389 *fname_dir_out = fname_dir;
1390 *fname_mask_out = fname_mask;
1391 return NT_STATUS_OK;
1394 /****************************************************************************
1395 Reply to a search.
1396 Can be called from SMBsearch, SMBffirst or SMBfunique.
1397 ****************************************************************************/
1399 void reply_search(struct smb_request *req)
1401 connection_struct *conn = req->conn;
1402 char *path = NULL;
1403 const char *mask = NULL;
1404 char *directory = NULL;
1405 struct smb_filename *smb_fname = NULL;
1406 char *fname = NULL;
1407 SMB_OFF_T size;
1408 uint32 mode;
1409 struct timespec date;
1410 uint32 dirtype;
1411 unsigned int numentries = 0;
1412 unsigned int maxentries = 0;
1413 bool finished = False;
1414 const char *p;
1415 int status_len;
1416 char status[21];
1417 int dptr_num= -1;
1418 bool check_descend = False;
1419 bool expect_close = False;
1420 NTSTATUS nt_status;
1421 bool mask_contains_wcard = False;
1422 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1423 TALLOC_CTX *ctx = talloc_tos();
1424 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1425 struct dptr_struct *dirptr = NULL;
1426 struct smbd_server_connection *sconn = req->sconn;
1428 START_PROFILE(SMBsearch);
1430 if (req->wct < 2) {
1431 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1432 goto out;
1435 if (lp_posix_pathnames()) {
1436 reply_unknown_new(req, req->cmd);
1437 goto out;
1440 /* If we were called as SMBffirst then we must expect close. */
1441 if(req->cmd == SMBffirst) {
1442 expect_close = True;
1445 reply_outbuf(req, 1, 3);
1446 maxentries = SVAL(req->vwv+0, 0);
1447 dirtype = SVAL(req->vwv+1, 0);
1448 p = (const char *)req->buf + 1;
1449 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1450 &nt_status, &mask_contains_wcard);
1451 if (!NT_STATUS_IS_OK(nt_status)) {
1452 reply_nterror(req, nt_status);
1453 goto out;
1456 p++;
1457 status_len = SVAL(p, 0);
1458 p += 2;
1460 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1462 if (status_len == 0) {
1463 nt_status = filename_convert(ctx, conn,
1464 req->flags2 & FLAGS2_DFS_PATHNAMES,
1465 path,
1466 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1467 &mask_contains_wcard,
1468 &smb_fname);
1469 if (!NT_STATUS_IS_OK(nt_status)) {
1470 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1471 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1472 ERRSRV, ERRbadpath);
1473 goto out;
1475 reply_nterror(req, nt_status);
1476 goto out;
1479 directory = smb_fname->base_name;
1481 p = strrchr_m(directory,'/');
1482 if ((p != NULL) && (*directory != '/')) {
1483 mask = p + 1;
1484 directory = talloc_strndup(ctx, directory,
1485 PTR_DIFF(p, directory));
1486 } else {
1487 mask = directory;
1488 directory = talloc_strdup(ctx,".");
1491 if (!directory) {
1492 reply_nterror(req, NT_STATUS_NO_MEMORY);
1493 goto out;
1496 memset((char *)status,'\0',21);
1497 SCVAL(status,0,(dirtype & 0x1F));
1499 nt_status = dptr_create(conn,
1500 NULL, /* fsp */
1501 directory,
1502 True,
1503 expect_close,
1504 req->smbpid,
1505 mask,
1506 mask_contains_wcard,
1507 dirtype,
1508 &dirptr);
1509 if (!NT_STATUS_IS_OK(nt_status)) {
1510 reply_nterror(req, nt_status);
1511 goto out;
1513 dptr_num = dptr_dnum(dirptr);
1514 } else {
1515 int status_dirtype;
1516 const char *dirpath;
1518 memcpy(status,p,21);
1519 status_dirtype = CVAL(status,0) & 0x1F;
1520 if (status_dirtype != (dirtype & 0x1F)) {
1521 dirtype = status_dirtype;
1524 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1525 if (!dirptr) {
1526 goto SearchEmpty;
1528 dirpath = dptr_path(sconn, dptr_num);
1529 directory = talloc_strdup(ctx, dirpath);
1530 if (!directory) {
1531 reply_nterror(req, NT_STATUS_NO_MEMORY);
1532 goto out;
1535 mask = dptr_wcard(sconn, dptr_num);
1536 if (!mask) {
1537 goto SearchEmpty;
1540 * For a 'continue' search we have no string. So
1541 * check from the initial saved string.
1543 mask_contains_wcard = ms_has_wild(mask);
1544 dirtype = dptr_attr(sconn, dptr_num);
1547 DEBUG(4,("dptr_num is %d\n",dptr_num));
1549 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1550 dptr_init_search_op(dirptr);
1552 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1553 char buf[DIR_STRUCT_SIZE];
1554 memcpy(buf,status,21);
1555 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1556 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1557 reply_nterror(req, NT_STATUS_NO_MEMORY);
1558 goto out;
1560 dptr_fill(sconn, buf+12,dptr_num);
1561 if (dptr_zero(buf+12) && (status_len==0)) {
1562 numentries = 1;
1563 } else {
1564 numentries = 0;
1566 if (message_push_blob(&req->outbuf,
1567 data_blob_const(buf, sizeof(buf)))
1568 == -1) {
1569 reply_nterror(req, NT_STATUS_NO_MEMORY);
1570 goto out;
1572 } else {
1573 unsigned int i;
1574 maxentries = MIN(
1575 maxentries,
1576 ((BUFFER_SIZE -
1577 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1578 /DIR_STRUCT_SIZE));
1580 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1581 directory,lp_dontdescend(SNUM(conn))));
1582 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1583 check_descend = True;
1586 for (i=numentries;(i<maxentries) && !finished;i++) {
1587 finished = !get_dir_entry(ctx,
1588 dirptr,
1589 mask,
1590 dirtype,
1591 &fname,
1592 &size,
1593 &mode,
1594 &date,
1595 check_descend,
1596 ask_sharemode);
1597 if (!finished) {
1598 char buf[DIR_STRUCT_SIZE];
1599 memcpy(buf,status,21);
1600 if (!make_dir_struct(ctx,
1601 buf,
1602 mask,
1603 fname,
1604 size,
1605 mode,
1606 convert_timespec_to_time_t(date),
1607 !allow_long_path_components)) {
1608 reply_nterror(req, NT_STATUS_NO_MEMORY);
1609 goto out;
1611 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1612 break;
1614 if (message_push_blob(&req->outbuf,
1615 data_blob_const(buf, sizeof(buf)))
1616 == -1) {
1617 reply_nterror(req, NT_STATUS_NO_MEMORY);
1618 goto out;
1620 numentries++;
1625 SearchEmpty:
1627 /* If we were called as SMBffirst with smb_search_id == NULL
1628 and no entries were found then return error and close dirptr
1629 (X/Open spec) */
1631 if (numentries == 0) {
1632 dptr_close(sconn, &dptr_num);
1633 } else if(expect_close && status_len == 0) {
1634 /* Close the dptr - we know it's gone */
1635 dptr_close(sconn, &dptr_num);
1638 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1639 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1640 dptr_close(sconn, &dptr_num);
1643 if ((numentries == 0) && !mask_contains_wcard) {
1644 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1645 goto out;
1648 SSVAL(req->outbuf,smb_vwv0,numentries);
1649 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1650 SCVAL(smb_buf(req->outbuf),0,5);
1651 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1653 /* The replies here are never long name. */
1654 SSVAL(req->outbuf, smb_flg2,
1655 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1656 if (!allow_long_path_components) {
1657 SSVAL(req->outbuf, smb_flg2,
1658 SVAL(req->outbuf, smb_flg2)
1659 & (~FLAGS2_LONG_PATH_COMPONENTS));
1662 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1663 SSVAL(req->outbuf, smb_flg2,
1664 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1666 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1667 smb_fn_name(req->cmd),
1668 mask,
1669 directory,
1670 dirtype,
1671 numentries,
1672 maxentries ));
1673 out:
1674 TALLOC_FREE(directory);
1675 TALLOC_FREE(smb_fname);
1676 END_PROFILE(SMBsearch);
1677 return;
1680 /****************************************************************************
1681 Reply to a fclose (stop directory search).
1682 ****************************************************************************/
1684 void reply_fclose(struct smb_request *req)
1686 int status_len;
1687 char status[21];
1688 int dptr_num= -2;
1689 const char *p;
1690 char *path = NULL;
1691 NTSTATUS err;
1692 bool path_contains_wcard = False;
1693 TALLOC_CTX *ctx = talloc_tos();
1694 struct smbd_server_connection *sconn = req->sconn;
1696 START_PROFILE(SMBfclose);
1698 if (lp_posix_pathnames()) {
1699 reply_unknown_new(req, req->cmd);
1700 END_PROFILE(SMBfclose);
1701 return;
1704 p = (const char *)req->buf + 1;
1705 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1706 &err, &path_contains_wcard);
1707 if (!NT_STATUS_IS_OK(err)) {
1708 reply_nterror(req, err);
1709 END_PROFILE(SMBfclose);
1710 return;
1712 p++;
1713 status_len = SVAL(p,0);
1714 p += 2;
1716 if (status_len == 0) {
1717 reply_force_doserror(req, ERRSRV, ERRsrverror);
1718 END_PROFILE(SMBfclose);
1719 return;
1722 memcpy(status,p,21);
1724 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1725 /* Close the dptr - we know it's gone */
1726 dptr_close(sconn, &dptr_num);
1729 reply_outbuf(req, 1, 0);
1730 SSVAL(req->outbuf,smb_vwv0,0);
1732 DEBUG(3,("search close\n"));
1734 END_PROFILE(SMBfclose);
1735 return;
1738 /****************************************************************************
1739 Reply to an open.
1740 ****************************************************************************/
1742 void reply_open(struct smb_request *req)
1744 connection_struct *conn = req->conn;
1745 struct smb_filename *smb_fname = NULL;
1746 char *fname = NULL;
1747 uint32 fattr=0;
1748 SMB_OFF_T size = 0;
1749 time_t mtime=0;
1750 int info;
1751 files_struct *fsp;
1752 int oplock_request;
1753 int deny_mode;
1754 uint32 dos_attr;
1755 uint32 access_mask;
1756 uint32 share_mode;
1757 uint32 create_disposition;
1758 uint32 create_options = 0;
1759 uint32_t private_flags = 0;
1760 NTSTATUS status;
1761 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1762 TALLOC_CTX *ctx = talloc_tos();
1764 START_PROFILE(SMBopen);
1766 if (req->wct < 2) {
1767 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1768 goto out;
1771 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1772 deny_mode = SVAL(req->vwv+0, 0);
1773 dos_attr = SVAL(req->vwv+1, 0);
1775 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1776 STR_TERMINATE, &status);
1777 if (!NT_STATUS_IS_OK(status)) {
1778 reply_nterror(req, status);
1779 goto out;
1782 status = filename_convert(ctx,
1783 conn,
1784 req->flags2 & FLAGS2_DFS_PATHNAMES,
1785 fname,
1787 NULL,
1788 &smb_fname);
1789 if (!NT_STATUS_IS_OK(status)) {
1790 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1791 reply_botherror(req,
1792 NT_STATUS_PATH_NOT_COVERED,
1793 ERRSRV, ERRbadpath);
1794 goto out;
1796 reply_nterror(req, status);
1797 goto out;
1800 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1801 OPENX_FILE_EXISTS_OPEN, &access_mask,
1802 &share_mode, &create_disposition,
1803 &create_options, &private_flags)) {
1804 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1805 goto out;
1808 status = SMB_VFS_CREATE_FILE(
1809 conn, /* conn */
1810 req, /* req */
1811 0, /* root_dir_fid */
1812 smb_fname, /* fname */
1813 access_mask, /* access_mask */
1814 share_mode, /* share_access */
1815 create_disposition, /* create_disposition*/
1816 create_options, /* create_options */
1817 dos_attr, /* file_attributes */
1818 oplock_request, /* oplock_request */
1819 0, /* allocation_size */
1820 private_flags,
1821 NULL, /* sd */
1822 NULL, /* ea_list */
1823 &fsp, /* result */
1824 &info); /* pinfo */
1826 if (!NT_STATUS_IS_OK(status)) {
1827 if (open_was_deferred(req->sconn, req->mid)) {
1828 /* We have re-scheduled this call. */
1829 goto out;
1831 reply_openerror(req, status);
1832 goto out;
1835 size = smb_fname->st.st_ex_size;
1836 fattr = dos_mode(conn, smb_fname);
1838 /* Deal with other possible opens having a modified
1839 write time. JRA. */
1840 if (ask_sharemode) {
1841 struct timespec write_time_ts;
1843 ZERO_STRUCT(write_time_ts);
1844 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1845 if (!null_timespec(write_time_ts)) {
1846 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1850 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1852 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1853 DEBUG(3,("attempt to open a directory %s\n",
1854 fsp_str_dbg(fsp)));
1855 close_file(req, fsp, ERROR_CLOSE);
1856 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1857 ERRDOS, ERRnoaccess);
1858 goto out;
1861 reply_outbuf(req, 7, 0);
1862 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1863 SSVAL(req->outbuf,smb_vwv1,fattr);
1864 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1865 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1866 } else {
1867 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1869 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1870 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1872 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1873 SCVAL(req->outbuf,smb_flg,
1874 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1877 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1878 SCVAL(req->outbuf,smb_flg,
1879 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1881 out:
1882 TALLOC_FREE(smb_fname);
1883 END_PROFILE(SMBopen);
1884 return;
1887 /****************************************************************************
1888 Reply to an open and X.
1889 ****************************************************************************/
1891 void reply_open_and_X(struct smb_request *req)
1893 connection_struct *conn = req->conn;
1894 struct smb_filename *smb_fname = NULL;
1895 char *fname = NULL;
1896 uint16 open_flags;
1897 int deny_mode;
1898 uint32 smb_attr;
1899 /* Breakout the oplock request bits so we can set the
1900 reply bits separately. */
1901 int ex_oplock_request;
1902 int core_oplock_request;
1903 int oplock_request;
1904 #if 0
1905 int smb_sattr = SVAL(req->vwv+4, 0);
1906 uint32 smb_time = make_unix_date3(req->vwv+6);
1907 #endif
1908 int smb_ofun;
1909 uint32 fattr=0;
1910 int mtime=0;
1911 int smb_action = 0;
1912 files_struct *fsp;
1913 NTSTATUS status;
1914 uint64_t allocation_size;
1915 ssize_t retval = -1;
1916 uint32 access_mask;
1917 uint32 share_mode;
1918 uint32 create_disposition;
1919 uint32 create_options = 0;
1920 uint32_t private_flags = 0;
1921 TALLOC_CTX *ctx = talloc_tos();
1923 START_PROFILE(SMBopenX);
1925 if (req->wct < 15) {
1926 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1927 goto out;
1930 open_flags = SVAL(req->vwv+2, 0);
1931 deny_mode = SVAL(req->vwv+3, 0);
1932 smb_attr = SVAL(req->vwv+5, 0);
1933 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1934 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1935 oplock_request = ex_oplock_request | core_oplock_request;
1936 smb_ofun = SVAL(req->vwv+8, 0);
1937 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1939 /* If it's an IPC, pass off the pipe handler. */
1940 if (IS_IPC(conn)) {
1941 if (lp_nt_pipe_support()) {
1942 reply_open_pipe_and_X(conn, req);
1943 } else {
1944 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1946 goto out;
1949 /* XXXX we need to handle passed times, sattr and flags */
1950 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1951 STR_TERMINATE, &status);
1952 if (!NT_STATUS_IS_OK(status)) {
1953 reply_nterror(req, status);
1954 goto out;
1957 status = filename_convert(ctx,
1958 conn,
1959 req->flags2 & FLAGS2_DFS_PATHNAMES,
1960 fname,
1962 NULL,
1963 &smb_fname);
1964 if (!NT_STATUS_IS_OK(status)) {
1965 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1966 reply_botherror(req,
1967 NT_STATUS_PATH_NOT_COVERED,
1968 ERRSRV, ERRbadpath);
1969 goto out;
1971 reply_nterror(req, status);
1972 goto out;
1975 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1976 smb_ofun,
1977 &access_mask, &share_mode,
1978 &create_disposition,
1979 &create_options,
1980 &private_flags)) {
1981 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1982 goto out;
1985 status = SMB_VFS_CREATE_FILE(
1986 conn, /* conn */
1987 req, /* req */
1988 0, /* root_dir_fid */
1989 smb_fname, /* fname */
1990 access_mask, /* access_mask */
1991 share_mode, /* share_access */
1992 create_disposition, /* create_disposition*/
1993 create_options, /* create_options */
1994 smb_attr, /* file_attributes */
1995 oplock_request, /* oplock_request */
1996 0, /* allocation_size */
1997 private_flags,
1998 NULL, /* sd */
1999 NULL, /* ea_list */
2000 &fsp, /* result */
2001 &smb_action); /* pinfo */
2003 if (!NT_STATUS_IS_OK(status)) {
2004 if (open_was_deferred(req->sconn, req->mid)) {
2005 /* We have re-scheduled this call. */
2006 goto out;
2008 reply_openerror(req, status);
2009 goto out;
2012 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2013 if the file is truncated or created. */
2014 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2015 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2016 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2017 close_file(req, fsp, ERROR_CLOSE);
2018 reply_nterror(req, NT_STATUS_DISK_FULL);
2019 goto out;
2021 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
2022 if (retval < 0) {
2023 close_file(req, fsp, ERROR_CLOSE);
2024 reply_nterror(req, NT_STATUS_DISK_FULL);
2025 goto out;
2027 status = vfs_stat_fsp(fsp);
2028 if (!NT_STATUS_IS_OK(status)) {
2029 close_file(req, fsp, ERROR_CLOSE);
2030 reply_nterror(req, status);
2031 goto out;
2035 fattr = dos_mode(conn, fsp->fsp_name);
2036 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2037 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2038 close_file(req, fsp, ERROR_CLOSE);
2039 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2040 goto out;
2043 /* If the caller set the extended oplock request bit
2044 and we granted one (by whatever means) - set the
2045 correct bit for extended oplock reply.
2048 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2049 smb_action |= EXTENDED_OPLOCK_GRANTED;
2052 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2053 smb_action |= EXTENDED_OPLOCK_GRANTED;
2056 /* If the caller set the core oplock request bit
2057 and we granted one (by whatever means) - set the
2058 correct bit for core oplock reply.
2061 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2062 reply_outbuf(req, 19, 0);
2063 } else {
2064 reply_outbuf(req, 15, 0);
2067 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2068 SCVAL(req->outbuf, smb_flg,
2069 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2072 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2073 SCVAL(req->outbuf, smb_flg,
2074 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2077 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2078 SSVAL(req->outbuf,smb_vwv3,fattr);
2079 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2080 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2081 } else {
2082 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2084 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2085 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2086 SSVAL(req->outbuf,smb_vwv11,smb_action);
2088 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2089 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2092 chain_reply(req);
2093 out:
2094 TALLOC_FREE(smb_fname);
2095 END_PROFILE(SMBopenX);
2096 return;
2099 /****************************************************************************
2100 Reply to a SMBulogoffX.
2101 ****************************************************************************/
2103 void reply_ulogoffX(struct smb_request *req)
2105 struct smbd_server_connection *sconn = req->sconn;
2106 user_struct *vuser;
2108 START_PROFILE(SMBulogoffX);
2110 vuser = get_valid_user_struct(sconn, req->vuid);
2112 if(vuser == NULL) {
2113 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2114 req->vuid));
2117 /* in user level security we are supposed to close any files
2118 open by this user */
2119 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2120 file_close_user(sconn, req->vuid);
2123 invalidate_vuid(sconn, req->vuid);
2125 reply_outbuf(req, 2, 0);
2127 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2129 END_PROFILE(SMBulogoffX);
2130 req->vuid = UID_FIELD_INVALID;
2131 chain_reply(req);
2134 /****************************************************************************
2135 Reply to a mknew or a create.
2136 ****************************************************************************/
2138 void reply_mknew(struct smb_request *req)
2140 connection_struct *conn = req->conn;
2141 struct smb_filename *smb_fname = NULL;
2142 char *fname = NULL;
2143 uint32 fattr = 0;
2144 struct smb_file_time ft;
2145 files_struct *fsp;
2146 int oplock_request = 0;
2147 NTSTATUS status;
2148 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2149 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2150 uint32 create_disposition;
2151 uint32 create_options = 0;
2152 TALLOC_CTX *ctx = talloc_tos();
2154 START_PROFILE(SMBcreate);
2155 ZERO_STRUCT(ft);
2157 if (req->wct < 3) {
2158 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2159 goto out;
2162 fattr = SVAL(req->vwv+0, 0);
2163 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2165 /* mtime. */
2166 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2168 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2169 STR_TERMINATE, &status);
2170 if (!NT_STATUS_IS_OK(status)) {
2171 reply_nterror(req, status);
2172 goto out;
2175 status = filename_convert(ctx,
2176 conn,
2177 req->flags2 & FLAGS2_DFS_PATHNAMES,
2178 fname,
2180 NULL,
2181 &smb_fname);
2182 if (!NT_STATUS_IS_OK(status)) {
2183 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2184 reply_botherror(req,
2185 NT_STATUS_PATH_NOT_COVERED,
2186 ERRSRV, ERRbadpath);
2187 goto out;
2189 reply_nterror(req, status);
2190 goto out;
2193 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2194 DEBUG(0,("Attempt to create file (%s) with volid set - "
2195 "please report this\n",
2196 smb_fname_str_dbg(smb_fname)));
2199 if(req->cmd == SMBmknew) {
2200 /* We should fail if file exists. */
2201 create_disposition = FILE_CREATE;
2202 } else {
2203 /* Create if file doesn't exist, truncate if it does. */
2204 create_disposition = FILE_OVERWRITE_IF;
2207 status = SMB_VFS_CREATE_FILE(
2208 conn, /* conn */
2209 req, /* req */
2210 0, /* root_dir_fid */
2211 smb_fname, /* fname */
2212 access_mask, /* access_mask */
2213 share_mode, /* share_access */
2214 create_disposition, /* create_disposition*/
2215 create_options, /* create_options */
2216 fattr, /* file_attributes */
2217 oplock_request, /* oplock_request */
2218 0, /* allocation_size */
2219 0, /* private_flags */
2220 NULL, /* sd */
2221 NULL, /* ea_list */
2222 &fsp, /* result */
2223 NULL); /* pinfo */
2225 if (!NT_STATUS_IS_OK(status)) {
2226 if (open_was_deferred(req->sconn, req->mid)) {
2227 /* We have re-scheduled this call. */
2228 goto out;
2230 reply_openerror(req, status);
2231 goto out;
2234 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2235 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2236 if (!NT_STATUS_IS_OK(status)) {
2237 END_PROFILE(SMBcreate);
2238 goto out;
2241 reply_outbuf(req, 1, 0);
2242 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2244 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2245 SCVAL(req->outbuf,smb_flg,
2246 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2249 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2250 SCVAL(req->outbuf,smb_flg,
2251 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2254 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2255 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2256 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2257 (unsigned int)fattr));
2259 out:
2260 TALLOC_FREE(smb_fname);
2261 END_PROFILE(SMBcreate);
2262 return;
2265 /****************************************************************************
2266 Reply to a create temporary file.
2267 ****************************************************************************/
2269 void reply_ctemp(struct smb_request *req)
2271 connection_struct *conn = req->conn;
2272 struct smb_filename *smb_fname = NULL;
2273 char *fname = NULL;
2274 uint32 fattr;
2275 files_struct *fsp;
2276 int oplock_request;
2277 int tmpfd;
2278 char *s;
2279 NTSTATUS status;
2280 TALLOC_CTX *ctx = talloc_tos();
2282 START_PROFILE(SMBctemp);
2284 if (req->wct < 3) {
2285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2286 goto out;
2289 fattr = SVAL(req->vwv+0, 0);
2290 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2292 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2293 STR_TERMINATE, &status);
2294 if (!NT_STATUS_IS_OK(status)) {
2295 reply_nterror(req, status);
2296 goto out;
2298 if (*fname) {
2299 fname = talloc_asprintf(ctx,
2300 "%s/TMXXXXXX",
2301 fname);
2302 } else {
2303 fname = talloc_strdup(ctx, "TMXXXXXX");
2306 if (!fname) {
2307 reply_nterror(req, NT_STATUS_NO_MEMORY);
2308 goto out;
2311 status = filename_convert(ctx, conn,
2312 req->flags2 & FLAGS2_DFS_PATHNAMES,
2313 fname,
2315 NULL,
2316 &smb_fname);
2317 if (!NT_STATUS_IS_OK(status)) {
2318 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2319 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2320 ERRSRV, ERRbadpath);
2321 goto out;
2323 reply_nterror(req, status);
2324 goto out;
2327 tmpfd = mkstemp(smb_fname->base_name);
2328 if (tmpfd == -1) {
2329 reply_nterror(req, map_nt_error_from_unix(errno));
2330 goto out;
2333 SMB_VFS_STAT(conn, smb_fname);
2335 /* We should fail if file does not exist. */
2336 status = SMB_VFS_CREATE_FILE(
2337 conn, /* conn */
2338 req, /* req */
2339 0, /* root_dir_fid */
2340 smb_fname, /* fname */
2341 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2342 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2343 FILE_OPEN, /* create_disposition*/
2344 0, /* create_options */
2345 fattr, /* file_attributes */
2346 oplock_request, /* oplock_request */
2347 0, /* allocation_size */
2348 0, /* private_flags */
2349 NULL, /* sd */
2350 NULL, /* ea_list */
2351 &fsp, /* result */
2352 NULL); /* pinfo */
2354 /* close fd from mkstemp() */
2355 close(tmpfd);
2357 if (!NT_STATUS_IS_OK(status)) {
2358 if (open_was_deferred(req->sconn, req->mid)) {
2359 /* We have re-scheduled this call. */
2360 goto out;
2362 reply_openerror(req, status);
2363 goto out;
2366 reply_outbuf(req, 1, 0);
2367 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2369 /* the returned filename is relative to the directory */
2370 s = strrchr_m(fsp->fsp_name->base_name, '/');
2371 if (!s) {
2372 s = fsp->fsp_name->base_name;
2373 } else {
2374 s++;
2377 #if 0
2378 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2379 thing in the byte section. JRA */
2380 SSVALS(p, 0, -1); /* what is this? not in spec */
2381 #endif
2382 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2383 == -1) {
2384 reply_nterror(req, NT_STATUS_NO_MEMORY);
2385 goto out;
2388 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2389 SCVAL(req->outbuf, smb_flg,
2390 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2393 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2394 SCVAL(req->outbuf, smb_flg,
2395 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2398 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2399 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2400 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2401 out:
2402 TALLOC_FREE(smb_fname);
2403 END_PROFILE(SMBctemp);
2404 return;
2407 /*******************************************************************
2408 Check if a user is allowed to rename a file.
2409 ********************************************************************/
2411 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2412 uint16 dirtype)
2414 if (!CAN_WRITE(conn)) {
2415 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2418 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2419 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2420 /* Only bother to read the DOS attribute if we might deny the
2421 rename on the grounds of attribute missmatch. */
2422 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2423 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2424 return NT_STATUS_NO_SUCH_FILE;
2428 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2429 if (fsp->posix_open) {
2430 return NT_STATUS_OK;
2433 /* If no pathnames are open below this
2434 directory, allow the rename. */
2436 if (file_find_subpath(fsp)) {
2437 return NT_STATUS_ACCESS_DENIED;
2439 return NT_STATUS_OK;
2442 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2443 return NT_STATUS_OK;
2446 return NT_STATUS_ACCESS_DENIED;
2449 /*******************************************************************
2450 * unlink a file with all relevant access checks
2451 *******************************************************************/
2453 static NTSTATUS do_unlink(connection_struct *conn,
2454 struct smb_request *req,
2455 struct smb_filename *smb_fname,
2456 uint32 dirtype)
2458 uint32 fattr;
2459 files_struct *fsp;
2460 uint32 dirtype_orig = dirtype;
2461 NTSTATUS status;
2462 int ret;
2463 bool posix_paths = lp_posix_pathnames();
2465 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2466 smb_fname_str_dbg(smb_fname),
2467 dirtype));
2469 if (!CAN_WRITE(conn)) {
2470 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2473 if (posix_paths) {
2474 ret = SMB_VFS_LSTAT(conn, smb_fname);
2475 } else {
2476 ret = SMB_VFS_STAT(conn, smb_fname);
2478 if (ret != 0) {
2479 return map_nt_error_from_unix(errno);
2482 fattr = dos_mode(conn, smb_fname);
2484 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2485 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2488 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2489 if (!dirtype) {
2490 return NT_STATUS_NO_SUCH_FILE;
2493 if (!dir_check_ftype(conn, fattr, dirtype)) {
2494 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2495 return NT_STATUS_FILE_IS_A_DIRECTORY;
2497 return NT_STATUS_NO_SUCH_FILE;
2500 if (dirtype_orig & 0x8000) {
2501 /* These will never be set for POSIX. */
2502 return NT_STATUS_NO_SUCH_FILE;
2505 #if 0
2506 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2507 return NT_STATUS_FILE_IS_A_DIRECTORY;
2510 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2511 return NT_STATUS_NO_SUCH_FILE;
2514 if (dirtype & 0xFF00) {
2515 /* These will never be set for POSIX. */
2516 return NT_STATUS_NO_SUCH_FILE;
2519 dirtype &= 0xFF;
2520 if (!dirtype) {
2521 return NT_STATUS_NO_SUCH_FILE;
2524 /* Can't delete a directory. */
2525 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2526 return NT_STATUS_FILE_IS_A_DIRECTORY;
2528 #endif
2530 #if 0 /* JRATEST */
2531 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2532 return NT_STATUS_OBJECT_NAME_INVALID;
2533 #endif /* JRATEST */
2535 /* On open checks the open itself will check the share mode, so
2536 don't do it here as we'll get it wrong. */
2538 status = SMB_VFS_CREATE_FILE
2539 (conn, /* conn */
2540 req, /* req */
2541 0, /* root_dir_fid */
2542 smb_fname, /* fname */
2543 DELETE_ACCESS, /* access_mask */
2544 FILE_SHARE_NONE, /* share_access */
2545 FILE_OPEN, /* create_disposition*/
2546 FILE_NON_DIRECTORY_FILE, /* create_options */
2547 /* file_attributes */
2548 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2549 FILE_ATTRIBUTE_NORMAL,
2550 0, /* oplock_request */
2551 0, /* allocation_size */
2552 0, /* private_flags */
2553 NULL, /* sd */
2554 NULL, /* ea_list */
2555 &fsp, /* result */
2556 NULL); /* pinfo */
2558 if (!NT_STATUS_IS_OK(status)) {
2559 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2560 nt_errstr(status)));
2561 return status;
2564 status = can_set_delete_on_close(fsp, fattr);
2565 if (!NT_STATUS_IS_OK(status)) {
2566 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2567 "(%s)\n",
2568 smb_fname_str_dbg(smb_fname),
2569 nt_errstr(status)));
2570 close_file(req, fsp, NORMAL_CLOSE);
2571 return status;
2574 /* The set is across all open files on this dev/inode pair. */
2575 if (!set_delete_on_close(fsp, True, conn->session_info->unix_token)) {
2576 close_file(req, fsp, NORMAL_CLOSE);
2577 return NT_STATUS_ACCESS_DENIED;
2580 return close_file(req, fsp, NORMAL_CLOSE);
2583 /****************************************************************************
2584 The guts of the unlink command, split out so it may be called by the NT SMB
2585 code.
2586 ****************************************************************************/
2588 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2589 uint32 dirtype, struct smb_filename *smb_fname,
2590 bool has_wild)
2592 char *fname_dir = NULL;
2593 char *fname_mask = NULL;
2594 int count=0;
2595 NTSTATUS status = NT_STATUS_OK;
2596 TALLOC_CTX *ctx = talloc_tos();
2598 /* Split up the directory from the filename/mask. */
2599 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2600 &fname_dir, &fname_mask);
2601 if (!NT_STATUS_IS_OK(status)) {
2602 goto out;
2606 * We should only check the mangled cache
2607 * here if unix_convert failed. This means
2608 * that the path in 'mask' doesn't exist
2609 * on the file system and so we need to look
2610 * for a possible mangle. This patch from
2611 * Tine Smukavec <valentin.smukavec@hermes.si>.
2614 if (!VALID_STAT(smb_fname->st) &&
2615 mangle_is_mangled(fname_mask, conn->params)) {
2616 char *new_mask = NULL;
2617 mangle_lookup_name_from_8_3(ctx, fname_mask,
2618 &new_mask, conn->params);
2619 if (new_mask) {
2620 TALLOC_FREE(fname_mask);
2621 fname_mask = new_mask;
2625 if (!has_wild) {
2628 * Only one file needs to be unlinked. Append the mask back
2629 * onto the directory.
2631 TALLOC_FREE(smb_fname->base_name);
2632 if (ISDOT(fname_dir)) {
2633 /* Ensure we use canonical names on open. */
2634 smb_fname->base_name = talloc_asprintf(smb_fname,
2635 "%s",
2636 fname_mask);
2637 } else {
2638 smb_fname->base_name = talloc_asprintf(smb_fname,
2639 "%s/%s",
2640 fname_dir,
2641 fname_mask);
2643 if (!smb_fname->base_name) {
2644 status = NT_STATUS_NO_MEMORY;
2645 goto out;
2647 if (dirtype == 0) {
2648 dirtype = FILE_ATTRIBUTE_NORMAL;
2651 status = check_name(conn, smb_fname->base_name);
2652 if (!NT_STATUS_IS_OK(status)) {
2653 goto out;
2656 status = do_unlink(conn, req, smb_fname, dirtype);
2657 if (!NT_STATUS_IS_OK(status)) {
2658 goto out;
2661 count++;
2662 } else {
2663 struct smb_Dir *dir_hnd = NULL;
2664 long offset = 0;
2665 const char *dname = NULL;
2666 char *talloced = NULL;
2668 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2669 status = NT_STATUS_OBJECT_NAME_INVALID;
2670 goto out;
2673 if (strequal(fname_mask,"????????.???")) {
2674 TALLOC_FREE(fname_mask);
2675 fname_mask = talloc_strdup(ctx, "*");
2676 if (!fname_mask) {
2677 status = NT_STATUS_NO_MEMORY;
2678 goto out;
2682 status = check_name(conn, fname_dir);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 goto out;
2687 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2688 dirtype);
2689 if (dir_hnd == NULL) {
2690 status = map_nt_error_from_unix(errno);
2691 goto out;
2694 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2695 the pattern matches against the long name, otherwise the short name
2696 We don't implement this yet XXXX
2699 status = NT_STATUS_NO_SUCH_FILE;
2701 while ((dname = ReadDirName(dir_hnd, &offset,
2702 &smb_fname->st, &talloced))) {
2703 TALLOC_CTX *frame = talloc_stackframe();
2705 if (!is_visible_file(conn, fname_dir, dname,
2706 &smb_fname->st, true)) {
2707 TALLOC_FREE(frame);
2708 TALLOC_FREE(talloced);
2709 continue;
2712 /* Quick check for "." and ".." */
2713 if (ISDOT(dname) || ISDOTDOT(dname)) {
2714 TALLOC_FREE(frame);
2715 TALLOC_FREE(talloced);
2716 continue;
2719 if(!mask_match(dname, fname_mask,
2720 conn->case_sensitive)) {
2721 TALLOC_FREE(frame);
2722 TALLOC_FREE(talloced);
2723 continue;
2726 TALLOC_FREE(smb_fname->base_name);
2727 if (ISDOT(fname_dir)) {
2728 /* Ensure we use canonical names on open. */
2729 smb_fname->base_name =
2730 talloc_asprintf(smb_fname, "%s",
2731 dname);
2732 } else {
2733 smb_fname->base_name =
2734 talloc_asprintf(smb_fname, "%s/%s",
2735 fname_dir, dname);
2738 if (!smb_fname->base_name) {
2739 TALLOC_FREE(dir_hnd);
2740 status = NT_STATUS_NO_MEMORY;
2741 TALLOC_FREE(frame);
2742 TALLOC_FREE(talloced);
2743 goto out;
2746 status = check_name(conn, smb_fname->base_name);
2747 if (!NT_STATUS_IS_OK(status)) {
2748 TALLOC_FREE(dir_hnd);
2749 TALLOC_FREE(frame);
2750 TALLOC_FREE(talloced);
2751 goto out;
2754 status = do_unlink(conn, req, smb_fname, dirtype);
2755 if (!NT_STATUS_IS_OK(status)) {
2756 TALLOC_FREE(frame);
2757 TALLOC_FREE(talloced);
2758 continue;
2761 count++;
2762 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2763 smb_fname->base_name));
2765 TALLOC_FREE(frame);
2766 TALLOC_FREE(talloced);
2768 TALLOC_FREE(dir_hnd);
2771 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2772 status = map_nt_error_from_unix(errno);
2775 out:
2776 TALLOC_FREE(fname_dir);
2777 TALLOC_FREE(fname_mask);
2778 return status;
2781 /****************************************************************************
2782 Reply to a unlink
2783 ****************************************************************************/
2785 void reply_unlink(struct smb_request *req)
2787 connection_struct *conn = req->conn;
2788 char *name = NULL;
2789 struct smb_filename *smb_fname = NULL;
2790 uint32 dirtype;
2791 NTSTATUS status;
2792 bool path_contains_wcard = False;
2793 TALLOC_CTX *ctx = talloc_tos();
2795 START_PROFILE(SMBunlink);
2797 if (req->wct < 1) {
2798 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2799 goto out;
2802 dirtype = SVAL(req->vwv+0, 0);
2804 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2805 STR_TERMINATE, &status,
2806 &path_contains_wcard);
2807 if (!NT_STATUS_IS_OK(status)) {
2808 reply_nterror(req, status);
2809 goto out;
2812 status = filename_convert(ctx, conn,
2813 req->flags2 & FLAGS2_DFS_PATHNAMES,
2814 name,
2815 UCF_COND_ALLOW_WCARD_LCOMP,
2816 &path_contains_wcard,
2817 &smb_fname);
2818 if (!NT_STATUS_IS_OK(status)) {
2819 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2820 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2821 ERRSRV, ERRbadpath);
2822 goto out;
2824 reply_nterror(req, status);
2825 goto out;
2828 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2830 status = unlink_internals(conn, req, dirtype, smb_fname,
2831 path_contains_wcard);
2832 if (!NT_STATUS_IS_OK(status)) {
2833 if (open_was_deferred(req->sconn, req->mid)) {
2834 /* We have re-scheduled this call. */
2835 goto out;
2837 reply_nterror(req, status);
2838 goto out;
2841 reply_outbuf(req, 0, 0);
2842 out:
2843 TALLOC_FREE(smb_fname);
2844 END_PROFILE(SMBunlink);
2845 return;
2848 /****************************************************************************
2849 Fail for readbraw.
2850 ****************************************************************************/
2852 static void fail_readraw(void)
2854 const char *errstr = talloc_asprintf(talloc_tos(),
2855 "FAIL ! reply_readbraw: socket write fail (%s)",
2856 strerror(errno));
2857 if (!errstr) {
2858 errstr = "";
2860 exit_server_cleanly(errstr);
2863 /****************************************************************************
2864 Fake (read/write) sendfile. Returns -1 on read or write fail.
2865 ****************************************************************************/
2867 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2869 size_t bufsize;
2870 size_t tosend = nread;
2871 char *buf;
2873 if (nread == 0) {
2874 return 0;
2877 bufsize = MIN(nread, 65536);
2879 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2880 return -1;
2883 while (tosend > 0) {
2884 ssize_t ret;
2885 size_t cur_read;
2887 if (tosend > bufsize) {
2888 cur_read = bufsize;
2889 } else {
2890 cur_read = tosend;
2892 ret = read_file(fsp,buf,startpos,cur_read);
2893 if (ret == -1) {
2894 SAFE_FREE(buf);
2895 return -1;
2898 /* If we had a short read, fill with zeros. */
2899 if (ret < cur_read) {
2900 memset(buf + ret, '\0', cur_read - ret);
2903 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2904 != cur_read) {
2905 char addr[INET6_ADDRSTRLEN];
2907 * Try and give an error message saying what
2908 * client failed.
2910 DEBUG(0, ("write_data failed for client %s. "
2911 "Error %s\n",
2912 get_peer_addr(fsp->conn->sconn->sock, addr,
2913 sizeof(addr)),
2914 strerror(errno)));
2915 SAFE_FREE(buf);
2916 return -1;
2918 tosend -= cur_read;
2919 startpos += cur_read;
2922 SAFE_FREE(buf);
2923 return (ssize_t)nread;
2926 /****************************************************************************
2927 Deal with the case of sendfile reading less bytes from the file than
2928 requested. Fill with zeros (all we can do).
2929 ****************************************************************************/
2931 void sendfile_short_send(files_struct *fsp,
2932 ssize_t nread,
2933 size_t headersize,
2934 size_t smb_maxcnt)
2936 #define SHORT_SEND_BUFSIZE 1024
2937 if (nread < headersize) {
2938 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2939 "header for file %s (%s). Terminating\n",
2940 fsp_str_dbg(fsp), strerror(errno)));
2941 exit_server_cleanly("sendfile_short_send failed");
2944 nread -= headersize;
2946 if (nread < smb_maxcnt) {
2947 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2948 if (!buf) {
2949 exit_server_cleanly("sendfile_short_send: "
2950 "malloc failed");
2953 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2954 "with zeros !\n", fsp_str_dbg(fsp)));
2956 while (nread < smb_maxcnt) {
2958 * We asked for the real file size and told sendfile
2959 * to not go beyond the end of the file. But it can
2960 * happen that in between our fstat call and the
2961 * sendfile call the file was truncated. This is very
2962 * bad because we have already announced the larger
2963 * number of bytes to the client.
2965 * The best we can do now is to send 0-bytes, just as
2966 * a read from a hole in a sparse file would do.
2968 * This should happen rarely enough that I don't care
2969 * about efficiency here :-)
2971 size_t to_write;
2973 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2974 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2975 != to_write) {
2976 char addr[INET6_ADDRSTRLEN];
2978 * Try and give an error message saying what
2979 * client failed.
2981 DEBUG(0, ("write_data failed for client %s. "
2982 "Error %s\n",
2983 get_peer_addr(
2984 fsp->conn->sconn->sock, addr,
2985 sizeof(addr)),
2986 strerror(errno)));
2987 exit_server_cleanly("sendfile_short_send: "
2988 "write_data failed");
2990 nread += to_write;
2992 SAFE_FREE(buf);
2996 /****************************************************************************
2997 Return a readbraw error (4 bytes of zero).
2998 ****************************************************************************/
3000 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3002 char header[4];
3004 SIVAL(header,0,0);
3006 smbd_lock_socket(sconn);
3007 if (write_data(sconn->sock,header,4) != 4) {
3008 char addr[INET6_ADDRSTRLEN];
3010 * Try and give an error message saying what
3011 * client failed.
3013 DEBUG(0, ("write_data failed for client %s. "
3014 "Error %s\n",
3015 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3016 strerror(errno)));
3018 fail_readraw();
3020 smbd_unlock_socket(sconn);
3023 /****************************************************************************
3024 Use sendfile in readbraw.
3025 ****************************************************************************/
3027 static void send_file_readbraw(connection_struct *conn,
3028 struct smb_request *req,
3029 files_struct *fsp,
3030 SMB_OFF_T startpos,
3031 size_t nread,
3032 ssize_t mincount)
3034 struct smbd_server_connection *sconn = req->sconn;
3035 char *outbuf = NULL;
3036 ssize_t ret=0;
3039 * We can only use sendfile on a non-chained packet
3040 * but we can use on a non-oplocked file. tridge proved this
3041 * on a train in Germany :-). JRA.
3042 * reply_readbraw has already checked the length.
3045 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3046 (fsp->wcp == NULL) &&
3047 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3048 ssize_t sendfile_read = -1;
3049 char header[4];
3050 DATA_BLOB header_blob;
3052 _smb_setlen(header,nread);
3053 header_blob = data_blob_const(header, 4);
3055 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3056 &header_blob, startpos,
3057 nread);
3058 if (sendfile_read == -1) {
3059 /* Returning ENOSYS means no data at all was sent.
3060 * Do this as a normal read. */
3061 if (errno == ENOSYS) {
3062 goto normal_readbraw;
3066 * Special hack for broken Linux with no working sendfile. If we
3067 * return EINTR we sent the header but not the rest of the data.
3068 * Fake this up by doing read/write calls.
3070 if (errno == EINTR) {
3071 /* Ensure we don't do this again. */
3072 set_use_sendfile(SNUM(conn), False);
3073 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3075 if (fake_sendfile(fsp, startpos, nread) == -1) {
3076 DEBUG(0,("send_file_readbraw: "
3077 "fake_sendfile failed for "
3078 "file %s (%s).\n",
3079 fsp_str_dbg(fsp),
3080 strerror(errno)));
3081 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3083 return;
3086 DEBUG(0,("send_file_readbraw: sendfile failed for "
3087 "file %s (%s). Terminating\n",
3088 fsp_str_dbg(fsp), strerror(errno)));
3089 exit_server_cleanly("send_file_readbraw sendfile failed");
3090 } else if (sendfile_read == 0) {
3092 * Some sendfile implementations return 0 to indicate
3093 * that there was a short read, but nothing was
3094 * actually written to the socket. In this case,
3095 * fallback to the normal read path so the header gets
3096 * the correct byte count.
3098 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3099 "bytes falling back to the normal read: "
3100 "%s\n", fsp_str_dbg(fsp)));
3101 goto normal_readbraw;
3104 /* Deal with possible short send. */
3105 if (sendfile_read != 4+nread) {
3106 sendfile_short_send(fsp, sendfile_read, 4, nread);
3108 return;
3111 normal_readbraw:
3113 outbuf = talloc_array(NULL, char, nread+4);
3114 if (!outbuf) {
3115 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3116 (unsigned)(nread+4)));
3117 reply_readbraw_error(sconn);
3118 return;
3121 if (nread > 0) {
3122 ret = read_file(fsp,outbuf+4,startpos,nread);
3123 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3124 if (ret < mincount)
3125 ret = 0;
3126 #else
3127 if (ret < nread)
3128 ret = 0;
3129 #endif
3132 _smb_setlen(outbuf,ret);
3133 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3134 char addr[INET6_ADDRSTRLEN];
3136 * Try and give an error message saying what
3137 * client failed.
3139 DEBUG(0, ("write_data failed for client %s. "
3140 "Error %s\n",
3141 get_peer_addr(fsp->conn->sconn->sock, addr,
3142 sizeof(addr)),
3143 strerror(errno)));
3145 fail_readraw();
3148 TALLOC_FREE(outbuf);
3151 /****************************************************************************
3152 Reply to a readbraw (core+ protocol).
3153 ****************************************************************************/
3155 void reply_readbraw(struct smb_request *req)
3157 connection_struct *conn = req->conn;
3158 struct smbd_server_connection *sconn = req->sconn;
3159 ssize_t maxcount,mincount;
3160 size_t nread = 0;
3161 SMB_OFF_T startpos;
3162 files_struct *fsp;
3163 struct lock_struct lock;
3164 SMB_OFF_T size = 0;
3166 START_PROFILE(SMBreadbraw);
3168 if (srv_is_signing_active(sconn) ||
3169 is_encrypted_packet(sconn, req->inbuf)) {
3170 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3171 "raw reads/writes are disallowed.");
3174 if (req->wct < 8) {
3175 reply_readbraw_error(sconn);
3176 END_PROFILE(SMBreadbraw);
3177 return;
3180 if (sconn->smb1.echo_handler.trusted_fde) {
3181 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3182 "'async smb echo handler = yes'\n"));
3183 reply_readbraw_error(sconn);
3184 END_PROFILE(SMBreadbraw);
3185 return;
3189 * Special check if an oplock break has been issued
3190 * and the readraw request croses on the wire, we must
3191 * return a zero length response here.
3194 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3197 * We have to do a check_fsp by hand here, as
3198 * we must always return 4 zero bytes on error,
3199 * not a NTSTATUS.
3202 if (!fsp || !conn || conn != fsp->conn ||
3203 req->vuid != fsp->vuid ||
3204 fsp->is_directory || fsp->fh->fd == -1) {
3206 * fsp could be NULL here so use the value from the packet. JRA.
3208 DEBUG(3,("reply_readbraw: fnum %d not valid "
3209 "- cache prime?\n",
3210 (int)SVAL(req->vwv+0, 0)));
3211 reply_readbraw_error(sconn);
3212 END_PROFILE(SMBreadbraw);
3213 return;
3216 /* Do a "by hand" version of CHECK_READ. */
3217 if (!(fsp->can_read ||
3218 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3219 (fsp->access_mask & FILE_EXECUTE)))) {
3220 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3221 (int)SVAL(req->vwv+0, 0)));
3222 reply_readbraw_error(sconn);
3223 END_PROFILE(SMBreadbraw);
3224 return;
3227 flush_write_cache(fsp, READRAW_FLUSH);
3229 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3230 if(req->wct == 10) {
3232 * This is a large offset (64 bit) read.
3234 #ifdef LARGE_SMB_OFF_T
3236 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3238 #else /* !LARGE_SMB_OFF_T */
3241 * Ensure we haven't been sent a >32 bit offset.
3244 if(IVAL(req->vwv+8, 0) != 0) {
3245 DEBUG(0,("reply_readbraw: large offset "
3246 "(%x << 32) used and we don't support "
3247 "64 bit offsets.\n",
3248 (unsigned int)IVAL(req->vwv+8, 0) ));
3249 reply_readbraw_error(sconn);
3250 END_PROFILE(SMBreadbraw);
3251 return;
3254 #endif /* LARGE_SMB_OFF_T */
3256 if(startpos < 0) {
3257 DEBUG(0,("reply_readbraw: negative 64 bit "
3258 "readraw offset (%.0f) !\n",
3259 (double)startpos ));
3260 reply_readbraw_error(sconn);
3261 END_PROFILE(SMBreadbraw);
3262 return;
3266 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3267 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3269 /* ensure we don't overrun the packet size */
3270 maxcount = MIN(65535,maxcount);
3272 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3273 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3274 &lock);
3276 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3277 reply_readbraw_error(sconn);
3278 END_PROFILE(SMBreadbraw);
3279 return;
3282 if (fsp_stat(fsp) == 0) {
3283 size = fsp->fsp_name->st.st_ex_size;
3286 if (startpos >= size) {
3287 nread = 0;
3288 } else {
3289 nread = MIN(maxcount,(size - startpos));
3292 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3293 if (nread < mincount)
3294 nread = 0;
3295 #endif
3297 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3298 "min=%lu nread=%lu\n",
3299 fsp->fnum, (double)startpos,
3300 (unsigned long)maxcount,
3301 (unsigned long)mincount,
3302 (unsigned long)nread ) );
3304 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3306 DEBUG(5,("reply_readbraw finished\n"));
3308 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3310 END_PROFILE(SMBreadbraw);
3311 return;
3314 #undef DBGC_CLASS
3315 #define DBGC_CLASS DBGC_LOCKING
3317 /****************************************************************************
3318 Reply to a lockread (core+ protocol).
3319 ****************************************************************************/
3321 void reply_lockread(struct smb_request *req)
3323 connection_struct *conn = req->conn;
3324 ssize_t nread = -1;
3325 char *data;
3326 SMB_OFF_T startpos;
3327 size_t numtoread;
3328 NTSTATUS status;
3329 files_struct *fsp;
3330 struct byte_range_lock *br_lck = NULL;
3331 char *p = NULL;
3332 struct smbd_server_connection *sconn = req->sconn;
3334 START_PROFILE(SMBlockread);
3336 if (req->wct < 5) {
3337 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3338 END_PROFILE(SMBlockread);
3339 return;
3342 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3344 if (!check_fsp(conn, req, fsp)) {
3345 END_PROFILE(SMBlockread);
3346 return;
3349 if (!CHECK_READ(fsp,req)) {
3350 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3351 END_PROFILE(SMBlockread);
3352 return;
3355 numtoread = SVAL(req->vwv+1, 0);
3356 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3358 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3360 reply_outbuf(req, 5, numtoread + 3);
3362 data = smb_buf(req->outbuf) + 3;
3365 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3366 * protocol request that predates the read/write lock concept.
3367 * Thus instead of asking for a read lock here we need to ask
3368 * for a write lock. JRA.
3369 * Note that the requested lock size is unaffected by max_recv.
3372 br_lck = do_lock(req->sconn->msg_ctx,
3373 fsp,
3374 (uint64_t)req->smbpid,
3375 (uint64_t)numtoread,
3376 (uint64_t)startpos,
3377 WRITE_LOCK,
3378 WINDOWS_LOCK,
3379 False, /* Non-blocking lock. */
3380 &status,
3381 NULL,
3382 NULL);
3383 TALLOC_FREE(br_lck);
3385 if (NT_STATUS_V(status)) {
3386 reply_nterror(req, status);
3387 END_PROFILE(SMBlockread);
3388 return;
3392 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3395 if (numtoread > sconn->smb1.negprot.max_recv) {
3396 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3397 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3398 (unsigned int)numtoread,
3399 (unsigned int)sconn->smb1.negprot.max_recv));
3400 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3402 nread = read_file(fsp,data,startpos,numtoread);
3404 if (nread < 0) {
3405 reply_nterror(req, map_nt_error_from_unix(errno));
3406 END_PROFILE(SMBlockread);
3407 return;
3410 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3412 SSVAL(req->outbuf,smb_vwv0,nread);
3413 SSVAL(req->outbuf,smb_vwv5,nread+3);
3414 p = smb_buf(req->outbuf);
3415 SCVAL(p,0,0); /* pad byte. */
3416 SSVAL(p,1,nread);
3418 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3419 fsp->fnum, (int)numtoread, (int)nread));
3421 END_PROFILE(SMBlockread);
3422 return;
3425 #undef DBGC_CLASS
3426 #define DBGC_CLASS DBGC_ALL
3428 /****************************************************************************
3429 Reply to a read.
3430 ****************************************************************************/
3432 void reply_read(struct smb_request *req)
3434 connection_struct *conn = req->conn;
3435 size_t numtoread;
3436 ssize_t nread = 0;
3437 char *data;
3438 SMB_OFF_T startpos;
3439 int outsize = 0;
3440 files_struct *fsp;
3441 struct lock_struct lock;
3442 struct smbd_server_connection *sconn = req->sconn;
3444 START_PROFILE(SMBread);
3446 if (req->wct < 3) {
3447 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3448 END_PROFILE(SMBread);
3449 return;
3452 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3454 if (!check_fsp(conn, req, fsp)) {
3455 END_PROFILE(SMBread);
3456 return;
3459 if (!CHECK_READ(fsp,req)) {
3460 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3461 END_PROFILE(SMBread);
3462 return;
3465 numtoread = SVAL(req->vwv+1, 0);
3466 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3468 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3471 * The requested read size cannot be greater than max_recv. JRA.
3473 if (numtoread > sconn->smb1.negprot.max_recv) {
3474 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3475 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3476 (unsigned int)numtoread,
3477 (unsigned int)sconn->smb1.negprot.max_recv));
3478 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3481 reply_outbuf(req, 5, numtoread+3);
3483 data = smb_buf(req->outbuf) + 3;
3485 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3486 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3487 &lock);
3489 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3490 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3491 END_PROFILE(SMBread);
3492 return;
3495 if (numtoread > 0)
3496 nread = read_file(fsp,data,startpos,numtoread);
3498 if (nread < 0) {
3499 reply_nterror(req, map_nt_error_from_unix(errno));
3500 goto strict_unlock;
3503 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3505 SSVAL(req->outbuf,smb_vwv0,nread);
3506 SSVAL(req->outbuf,smb_vwv5,nread+3);
3507 SCVAL(smb_buf(req->outbuf),0,1);
3508 SSVAL(smb_buf(req->outbuf),1,nread);
3510 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3511 fsp->fnum, (int)numtoread, (int)nread ) );
3513 strict_unlock:
3514 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3516 END_PROFILE(SMBread);
3517 return;
3520 /****************************************************************************
3521 Setup readX header.
3522 ****************************************************************************/
3524 static int setup_readX_header(struct smb_request *req, char *outbuf,
3525 size_t smb_maxcnt)
3527 int outsize;
3528 char *data;
3530 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3531 data = smb_buf(outbuf);
3533 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3535 SCVAL(outbuf,smb_vwv0,0xFF);
3536 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3537 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3538 SSVAL(outbuf,smb_vwv6,
3539 req_wct_ofs(req)
3540 + 1 /* the wct field */
3541 + 12 * sizeof(uint16_t) /* vwv */
3542 + 2); /* the buflen field */
3543 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3544 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3545 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3546 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3547 return outsize;
3550 /****************************************************************************
3551 Reply to a read and X - possibly using sendfile.
3552 ****************************************************************************/
3554 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3555 files_struct *fsp, SMB_OFF_T startpos,
3556 size_t smb_maxcnt)
3558 ssize_t nread = -1;
3559 struct lock_struct lock;
3560 int saved_errno = 0;
3562 if(fsp_stat(fsp) == -1) {
3563 reply_nterror(req, map_nt_error_from_unix(errno));
3564 return;
3567 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3568 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3569 &lock);
3571 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3572 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3573 return;
3576 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3577 (startpos > fsp->fsp_name->st.st_ex_size)
3578 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3580 * We already know that we would do a short read, so don't
3581 * try the sendfile() path.
3583 goto nosendfile_read;
3587 * We can only use sendfile on a non-chained packet
3588 * but we can use on a non-oplocked file. tridge proved this
3589 * on a train in Germany :-). JRA.
3592 if (!req_is_in_chain(req) &&
3593 !is_encrypted_packet(req->sconn, req->inbuf) &&
3594 (fsp->base_fsp == NULL) &&
3595 (fsp->wcp == NULL) &&
3596 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3597 uint8 headerbuf[smb_size + 12 * 2];
3598 DATA_BLOB header;
3601 * Set up the packet header before send. We
3602 * assume here the sendfile will work (get the
3603 * correct amount of data).
3606 header = data_blob_const(headerbuf, sizeof(headerbuf));
3608 construct_reply_common_req(req, (char *)headerbuf);
3609 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3611 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3612 startpos, smb_maxcnt);
3613 if (nread == -1) {
3614 /* Returning ENOSYS means no data at all was sent.
3615 Do this as a normal read. */
3616 if (errno == ENOSYS) {
3617 goto normal_read;
3621 * Special hack for broken Linux with no working sendfile. If we
3622 * return EINTR we sent the header but not the rest of the data.
3623 * Fake this up by doing read/write calls.
3626 if (errno == EINTR) {
3627 /* Ensure we don't do this again. */
3628 set_use_sendfile(SNUM(conn), False);
3629 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3630 nread = fake_sendfile(fsp, startpos,
3631 smb_maxcnt);
3632 if (nread == -1) {
3633 DEBUG(0,("send_file_readX: "
3634 "fake_sendfile failed for "
3635 "file %s (%s).\n",
3636 fsp_str_dbg(fsp),
3637 strerror(errno)));
3638 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3640 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3641 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3642 /* No outbuf here means successful sendfile. */
3643 goto strict_unlock;
3646 DEBUG(0,("send_file_readX: sendfile failed for file "
3647 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3648 strerror(errno)));
3649 exit_server_cleanly("send_file_readX sendfile failed");
3650 } else if (nread == 0) {
3652 * Some sendfile implementations return 0 to indicate
3653 * that there was a short read, but nothing was
3654 * actually written to the socket. In this case,
3655 * fallback to the normal read path so the header gets
3656 * the correct byte count.
3658 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3659 "falling back to the normal read: %s\n",
3660 fsp_str_dbg(fsp)));
3661 goto normal_read;
3664 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3665 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3667 /* Deal with possible short send. */
3668 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3669 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3671 /* No outbuf here means successful sendfile. */
3672 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3673 SMB_PERFCOUNT_END(&req->pcd);
3674 goto strict_unlock;
3677 normal_read:
3679 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3680 uint8 headerbuf[smb_size + 2*12];
3682 construct_reply_common_req(req, (char *)headerbuf);
3683 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3685 /* Send out the header. */
3686 if (write_data(req->sconn->sock, (char *)headerbuf,
3687 sizeof(headerbuf)) != sizeof(headerbuf)) {
3689 char addr[INET6_ADDRSTRLEN];
3691 * Try and give an error message saying what
3692 * client failed.
3694 DEBUG(0, ("write_data failed for client %s. "
3695 "Error %s\n",
3696 get_peer_addr(req->sconn->sock, addr,
3697 sizeof(addr)),
3698 strerror(errno)));
3700 DEBUG(0,("send_file_readX: write_data failed for file "
3701 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3702 strerror(errno)));
3703 exit_server_cleanly("send_file_readX sendfile failed");
3705 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3706 if (nread == -1) {
3707 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3708 "file %s (%s).\n", fsp_str_dbg(fsp),
3709 strerror(errno)));
3710 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3712 goto strict_unlock;
3715 nosendfile_read:
3717 reply_outbuf(req, 12, smb_maxcnt);
3719 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3720 saved_errno = errno;
3722 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3724 if (nread < 0) {
3725 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3726 return;
3729 setup_readX_header(req, (char *)req->outbuf, nread);
3731 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3732 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3734 chain_reply(req);
3735 return;
3737 strict_unlock:
3738 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3739 TALLOC_FREE(req->outbuf);
3740 return;
3743 /****************************************************************************
3744 Reply to a read and X.
3745 ****************************************************************************/
3747 void reply_read_and_X(struct smb_request *req)
3749 struct smbd_server_connection *sconn = req->sconn;
3750 connection_struct *conn = req->conn;
3751 files_struct *fsp;
3752 SMB_OFF_T startpos;
3753 size_t smb_maxcnt;
3754 bool big_readX = False;
3755 #if 0
3756 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3757 #endif
3759 START_PROFILE(SMBreadX);
3761 if ((req->wct != 10) && (req->wct != 12)) {
3762 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3763 return;
3766 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3767 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3768 smb_maxcnt = SVAL(req->vwv+5, 0);
3770 /* If it's an IPC, pass off the pipe handler. */
3771 if (IS_IPC(conn)) {
3772 reply_pipe_read_and_X(req);
3773 END_PROFILE(SMBreadX);
3774 return;
3777 if (!check_fsp(conn, req, fsp)) {
3778 END_PROFILE(SMBreadX);
3779 return;
3782 if (!CHECK_READ(fsp,req)) {
3783 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3784 END_PROFILE(SMBreadX);
3785 return;
3788 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3789 (get_remote_arch() == RA_SAMBA)) {
3791 * This is Samba only behavior (up to Samba 3.6)!
3793 * Windows 2008 R2 ignores the upper_size,
3794 * so we do unless unix extentions are active
3795 * or "smbclient" is talking to us.
3797 size_t upper_size = SVAL(req->vwv+7, 0);
3798 smb_maxcnt |= (upper_size<<16);
3799 if (upper_size > 1) {
3800 /* Can't do this on a chained packet. */
3801 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3802 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3803 END_PROFILE(SMBreadX);
3804 return;
3806 /* We currently don't do this on signed or sealed data. */
3807 if (srv_is_signing_active(req->sconn) ||
3808 is_encrypted_packet(req->sconn, req->inbuf)) {
3809 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3810 END_PROFILE(SMBreadX);
3811 return;
3813 /* Is there room in the reply for this data ? */
3814 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3815 reply_nterror(req,
3816 NT_STATUS_INVALID_PARAMETER);
3817 END_PROFILE(SMBreadX);
3818 return;
3820 big_readX = True;
3824 if (req->wct == 12) {
3825 #ifdef LARGE_SMB_OFF_T
3827 * This is a large offset (64 bit) read.
3829 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3831 #else /* !LARGE_SMB_OFF_T */
3834 * Ensure we haven't been sent a >32 bit offset.
3837 if(IVAL(req->vwv+10, 0) != 0) {
3838 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3839 "used and we don't support 64 bit offsets.\n",
3840 (unsigned int)IVAL(req->vwv+10, 0) ));
3841 END_PROFILE(SMBreadX);
3842 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3843 return;
3846 #endif /* LARGE_SMB_OFF_T */
3850 if (!big_readX) {
3851 NTSTATUS status = schedule_aio_read_and_X(conn,
3852 req,
3853 fsp,
3854 startpos,
3855 smb_maxcnt);
3856 if (NT_STATUS_IS_OK(status)) {
3857 /* Read scheduled - we're done. */
3858 goto out;
3860 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3861 /* Real error - report to client. */
3862 END_PROFILE(SMBreadX);
3863 reply_nterror(req, status);
3864 return;
3866 /* NT_STATUS_RETRY - fall back to sync read. */
3869 smbd_lock_socket(req->sconn);
3870 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3871 smbd_unlock_socket(req->sconn);
3873 out:
3874 END_PROFILE(SMBreadX);
3875 return;
3878 /****************************************************************************
3879 Error replies to writebraw must have smb_wct == 1. Fix this up.
3880 ****************************************************************************/
3882 void error_to_writebrawerr(struct smb_request *req)
3884 uint8 *old_outbuf = req->outbuf;
3886 reply_outbuf(req, 1, 0);
3888 memcpy(req->outbuf, old_outbuf, smb_size);
3889 TALLOC_FREE(old_outbuf);
3892 /****************************************************************************
3893 Read 4 bytes of a smb packet and return the smb length of the packet.
3894 Store the result in the buffer. This version of the function will
3895 never return a session keepalive (length of zero).
3896 Timeout is in milliseconds.
3897 ****************************************************************************/
3899 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3900 size_t *len)
3902 uint8_t msgtype = NBSSkeepalive;
3904 while (msgtype == NBSSkeepalive) {
3905 NTSTATUS status;
3907 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3908 len);
3909 if (!NT_STATUS_IS_OK(status)) {
3910 char addr[INET6_ADDRSTRLEN];
3911 /* Try and give an error message
3912 * saying what client failed. */
3913 DEBUG(0, ("read_fd_with_timeout failed for "
3914 "client %s read error = %s.\n",
3915 get_peer_addr(fd,addr,sizeof(addr)),
3916 nt_errstr(status)));
3917 return status;
3920 msgtype = CVAL(inbuf, 0);
3923 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3924 (unsigned long)len));
3926 return NT_STATUS_OK;
3929 /****************************************************************************
3930 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3931 ****************************************************************************/
3933 void reply_writebraw(struct smb_request *req)
3935 connection_struct *conn = req->conn;
3936 char *buf = NULL;
3937 ssize_t nwritten=0;
3938 ssize_t total_written=0;
3939 size_t numtowrite=0;
3940 size_t tcount;
3941 SMB_OFF_T startpos;
3942 const char *data=NULL;
3943 bool write_through;
3944 files_struct *fsp;
3945 struct lock_struct lock;
3946 NTSTATUS status;
3948 START_PROFILE(SMBwritebraw);
3951 * If we ever reply with an error, it must have the SMB command
3952 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3953 * we're finished.
3955 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3957 if (srv_is_signing_active(req->sconn)) {
3958 END_PROFILE(SMBwritebraw);
3959 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3960 "raw reads/writes are disallowed.");
3963 if (req->wct < 12) {
3964 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3965 error_to_writebrawerr(req);
3966 END_PROFILE(SMBwritebraw);
3967 return;
3970 if (req->sconn->smb1.echo_handler.trusted_fde) {
3971 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3972 "'async smb echo handler = yes'\n"));
3973 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3974 error_to_writebrawerr(req);
3975 END_PROFILE(SMBwritebraw);
3976 return;
3979 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3980 if (!check_fsp(conn, req, fsp)) {
3981 error_to_writebrawerr(req);
3982 END_PROFILE(SMBwritebraw);
3983 return;
3986 if (!CHECK_WRITE(fsp)) {
3987 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3988 error_to_writebrawerr(req);
3989 END_PROFILE(SMBwritebraw);
3990 return;
3993 tcount = IVAL(req->vwv+1, 0);
3994 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3995 write_through = BITSETW(req->vwv+7,0);
3997 /* We have to deal with slightly different formats depending
3998 on whether we are using the core+ or lanman1.0 protocol */
4000 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4001 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4002 data = smb_buf_const(req->inbuf);
4003 } else {
4004 numtowrite = SVAL(req->vwv+10, 0);
4005 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4008 /* Ensure we don't write bytes past the end of this packet. */
4009 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4010 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4011 error_to_writebrawerr(req);
4012 END_PROFILE(SMBwritebraw);
4013 return;
4016 if (!fsp->print_file) {
4017 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4018 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4019 &lock);
4021 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4022 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4023 error_to_writebrawerr(req);
4024 END_PROFILE(SMBwritebraw);
4025 return;
4029 if (numtowrite>0) {
4030 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4033 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
4034 "wrote=%d sync=%d\n",
4035 fsp->fnum, (double)startpos, (int)numtowrite,
4036 (int)nwritten, (int)write_through));
4038 if (nwritten < (ssize_t)numtowrite) {
4039 reply_nterror(req, NT_STATUS_DISK_FULL);
4040 error_to_writebrawerr(req);
4041 goto strict_unlock;
4044 total_written = nwritten;
4046 /* Allocate a buffer of 64k + length. */
4047 buf = talloc_array(NULL, char, 65540);
4048 if (!buf) {
4049 reply_nterror(req, NT_STATUS_NO_MEMORY);
4050 error_to_writebrawerr(req);
4051 goto strict_unlock;
4054 /* Return a SMBwritebraw message to the redirector to tell
4055 * it to send more bytes */
4057 memcpy(buf, req->inbuf, smb_size);
4058 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4059 SCVAL(buf,smb_com,SMBwritebraw);
4060 SSVALS(buf,smb_vwv0,0xFFFF);
4061 show_msg(buf);
4062 if (!srv_send_smb(req->sconn,
4063 buf,
4064 false, 0, /* no signing */
4065 IS_CONN_ENCRYPTED(conn),
4066 &req->pcd)) {
4067 exit_server_cleanly("reply_writebraw: srv_send_smb "
4068 "failed.");
4071 /* Now read the raw data into the buffer and write it */
4072 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4073 &numtowrite);
4074 if (!NT_STATUS_IS_OK(status)) {
4075 exit_server_cleanly("secondary writebraw failed");
4078 /* Set up outbuf to return the correct size */
4079 reply_outbuf(req, 1, 0);
4081 if (numtowrite != 0) {
4083 if (numtowrite > 0xFFFF) {
4084 DEBUG(0,("reply_writebraw: Oversize secondary write "
4085 "raw requested (%u). Terminating\n",
4086 (unsigned int)numtowrite ));
4087 exit_server_cleanly("secondary writebraw failed");
4090 if (tcount > nwritten+numtowrite) {
4091 DEBUG(3,("reply_writebraw: Client overestimated the "
4092 "write %d %d %d\n",
4093 (int)tcount,(int)nwritten,(int)numtowrite));
4096 status = read_data(req->sconn->sock, buf+4, numtowrite);
4098 if (!NT_STATUS_IS_OK(status)) {
4099 char addr[INET6_ADDRSTRLEN];
4100 /* Try and give an error message
4101 * saying what client failed. */
4102 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4103 "raw read failed (%s) for client %s. "
4104 "Terminating\n", nt_errstr(status),
4105 get_peer_addr(req->sconn->sock, addr,
4106 sizeof(addr))));
4107 exit_server_cleanly("secondary writebraw failed");
4110 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4111 if (nwritten == -1) {
4112 TALLOC_FREE(buf);
4113 reply_nterror(req, map_nt_error_from_unix(errno));
4114 error_to_writebrawerr(req);
4115 goto strict_unlock;
4118 if (nwritten < (ssize_t)numtowrite) {
4119 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4120 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4123 if (nwritten > 0) {
4124 total_written += nwritten;
4128 TALLOC_FREE(buf);
4129 SSVAL(req->outbuf,smb_vwv0,total_written);
4131 status = sync_file(conn, fsp, write_through);
4132 if (!NT_STATUS_IS_OK(status)) {
4133 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4134 fsp_str_dbg(fsp), nt_errstr(status)));
4135 reply_nterror(req, status);
4136 error_to_writebrawerr(req);
4137 goto strict_unlock;
4140 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4141 "wrote=%d\n",
4142 fsp->fnum, (double)startpos, (int)numtowrite,
4143 (int)total_written));
4145 if (!fsp->print_file) {
4146 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4149 /* We won't return a status if write through is not selected - this
4150 * follows what WfWg does */
4151 END_PROFILE(SMBwritebraw);
4153 if (!write_through && total_written==tcount) {
4155 #if RABBIT_PELLET_FIX
4157 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4158 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4159 * JRA.
4161 if (!send_keepalive(req->sconn->sock)) {
4162 exit_server_cleanly("reply_writebraw: send of "
4163 "keepalive failed");
4165 #endif
4166 TALLOC_FREE(req->outbuf);
4168 return;
4170 strict_unlock:
4171 if (!fsp->print_file) {
4172 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4175 END_PROFILE(SMBwritebraw);
4176 return;
4179 #undef DBGC_CLASS
4180 #define DBGC_CLASS DBGC_LOCKING
4182 /****************************************************************************
4183 Reply to a writeunlock (core+).
4184 ****************************************************************************/
4186 void reply_writeunlock(struct smb_request *req)
4188 connection_struct *conn = req->conn;
4189 ssize_t nwritten = -1;
4190 size_t numtowrite;
4191 SMB_OFF_T startpos;
4192 const char *data;
4193 NTSTATUS status = NT_STATUS_OK;
4194 files_struct *fsp;
4195 struct lock_struct lock;
4196 int saved_errno = 0;
4198 START_PROFILE(SMBwriteunlock);
4200 if (req->wct < 5) {
4201 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4202 END_PROFILE(SMBwriteunlock);
4203 return;
4206 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4208 if (!check_fsp(conn, req, fsp)) {
4209 END_PROFILE(SMBwriteunlock);
4210 return;
4213 if (!CHECK_WRITE(fsp)) {
4214 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4215 END_PROFILE(SMBwriteunlock);
4216 return;
4219 numtowrite = SVAL(req->vwv+1, 0);
4220 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4221 data = (const char *)req->buf + 3;
4223 if (!fsp->print_file && numtowrite > 0) {
4224 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4225 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4226 &lock);
4228 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4229 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4230 END_PROFILE(SMBwriteunlock);
4231 return;
4235 /* The special X/Open SMB protocol handling of
4236 zero length writes is *NOT* done for
4237 this call */
4238 if(numtowrite == 0) {
4239 nwritten = 0;
4240 } else {
4241 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4242 saved_errno = errno;
4245 status = sync_file(conn, fsp, False /* write through */);
4246 if (!NT_STATUS_IS_OK(status)) {
4247 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4248 fsp_str_dbg(fsp), nt_errstr(status)));
4249 reply_nterror(req, status);
4250 goto strict_unlock;
4253 if(nwritten < 0) {
4254 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4255 goto strict_unlock;
4258 if((nwritten < numtowrite) && (numtowrite != 0)) {
4259 reply_nterror(req, NT_STATUS_DISK_FULL);
4260 goto strict_unlock;
4263 if (numtowrite && !fsp->print_file) {
4264 status = do_unlock(req->sconn->msg_ctx,
4265 fsp,
4266 (uint64_t)req->smbpid,
4267 (uint64_t)numtowrite,
4268 (uint64_t)startpos,
4269 WINDOWS_LOCK);
4271 if (NT_STATUS_V(status)) {
4272 reply_nterror(req, status);
4273 goto strict_unlock;
4277 reply_outbuf(req, 1, 0);
4279 SSVAL(req->outbuf,smb_vwv0,nwritten);
4281 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4282 fsp->fnum, (int)numtowrite, (int)nwritten));
4284 strict_unlock:
4285 if (numtowrite && !fsp->print_file) {
4286 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4289 END_PROFILE(SMBwriteunlock);
4290 return;
4293 #undef DBGC_CLASS
4294 #define DBGC_CLASS DBGC_ALL
4296 /****************************************************************************
4297 Reply to a write.
4298 ****************************************************************************/
4300 void reply_write(struct smb_request *req)
4302 connection_struct *conn = req->conn;
4303 size_t numtowrite;
4304 ssize_t nwritten = -1;
4305 SMB_OFF_T startpos;
4306 const char *data;
4307 files_struct *fsp;
4308 struct lock_struct lock;
4309 NTSTATUS status;
4310 int saved_errno = 0;
4312 START_PROFILE(SMBwrite);
4314 if (req->wct < 5) {
4315 END_PROFILE(SMBwrite);
4316 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4317 return;
4320 /* If it's an IPC, pass off the pipe handler. */
4321 if (IS_IPC(conn)) {
4322 reply_pipe_write(req);
4323 END_PROFILE(SMBwrite);
4324 return;
4327 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4329 if (!check_fsp(conn, req, fsp)) {
4330 END_PROFILE(SMBwrite);
4331 return;
4334 if (!CHECK_WRITE(fsp)) {
4335 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4336 END_PROFILE(SMBwrite);
4337 return;
4340 numtowrite = SVAL(req->vwv+1, 0);
4341 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4342 data = (const char *)req->buf + 3;
4344 if (!fsp->print_file) {
4345 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4346 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4347 &lock);
4349 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4350 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4351 END_PROFILE(SMBwrite);
4352 return;
4357 * X/Open SMB protocol says that if smb_vwv1 is
4358 * zero then the file size should be extended or
4359 * truncated to the size given in smb_vwv[2-3].
4362 if(numtowrite == 0) {
4364 * This is actually an allocate call, and set EOF. JRA.
4366 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4367 if (nwritten < 0) {
4368 reply_nterror(req, NT_STATUS_DISK_FULL);
4369 goto strict_unlock;
4371 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4372 if (nwritten < 0) {
4373 reply_nterror(req, NT_STATUS_DISK_FULL);
4374 goto strict_unlock;
4376 trigger_write_time_update_immediate(fsp);
4377 } else {
4378 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4381 status = sync_file(conn, fsp, False);
4382 if (!NT_STATUS_IS_OK(status)) {
4383 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4384 fsp_str_dbg(fsp), nt_errstr(status)));
4385 reply_nterror(req, status);
4386 goto strict_unlock;
4389 if(nwritten < 0) {
4390 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4391 goto strict_unlock;
4394 if((nwritten == 0) && (numtowrite != 0)) {
4395 reply_nterror(req, NT_STATUS_DISK_FULL);
4396 goto strict_unlock;
4399 reply_outbuf(req, 1, 0);
4401 SSVAL(req->outbuf,smb_vwv0,nwritten);
4403 if (nwritten < (ssize_t)numtowrite) {
4404 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4405 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4408 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4410 strict_unlock:
4411 if (!fsp->print_file) {
4412 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4415 END_PROFILE(SMBwrite);
4416 return;
4419 /****************************************************************************
4420 Ensure a buffer is a valid writeX for recvfile purposes.
4421 ****************************************************************************/
4423 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4424 (2*14) + /* word count (including bcc) */ \
4425 1 /* pad byte */)
4427 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4428 const uint8_t *inbuf)
4430 size_t numtowrite;
4431 connection_struct *conn = NULL;
4432 unsigned int doff = 0;
4433 size_t len = smb_len_large(inbuf);
4435 if (is_encrypted_packet(sconn, inbuf)) {
4436 /* Can't do this on encrypted
4437 * connections. */
4438 return false;
4441 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4442 return false;
4445 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4446 CVAL(inbuf,smb_wct) != 14) {
4447 DEBUG(10,("is_valid_writeX_buffer: chained or "
4448 "invalid word length.\n"));
4449 return false;
4452 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4453 if (conn == NULL) {
4454 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4455 return false;
4457 if (IS_IPC(conn)) {
4458 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4459 return false;
4461 if (IS_PRINT(conn)) {
4462 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4463 return false;
4465 doff = SVAL(inbuf,smb_vwv11);
4467 numtowrite = SVAL(inbuf,smb_vwv10);
4469 if (len > doff && len - doff > 0xFFFF) {
4470 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4473 if (numtowrite == 0) {
4474 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4475 return false;
4478 /* Ensure the sizes match up. */
4479 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4480 /* no pad byte...old smbclient :-( */
4481 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4482 (unsigned int)doff,
4483 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4484 return false;
4487 if (len - doff != numtowrite) {
4488 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4489 "len = %u, doff = %u, numtowrite = %u\n",
4490 (unsigned int)len,
4491 (unsigned int)doff,
4492 (unsigned int)numtowrite ));
4493 return false;
4496 DEBUG(10,("is_valid_writeX_buffer: true "
4497 "len = %u, doff = %u, numtowrite = %u\n",
4498 (unsigned int)len,
4499 (unsigned int)doff,
4500 (unsigned int)numtowrite ));
4502 return true;
4505 /****************************************************************************
4506 Reply to a write and X.
4507 ****************************************************************************/
4509 void reply_write_and_X(struct smb_request *req)
4511 connection_struct *conn = req->conn;
4512 files_struct *fsp;
4513 struct lock_struct lock;
4514 SMB_OFF_T startpos;
4515 size_t numtowrite;
4516 bool write_through;
4517 ssize_t nwritten;
4518 unsigned int smb_doff;
4519 unsigned int smblen;
4520 const char *data;
4521 NTSTATUS status;
4522 int saved_errno = 0;
4524 START_PROFILE(SMBwriteX);
4526 if ((req->wct != 12) && (req->wct != 14)) {
4527 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4528 END_PROFILE(SMBwriteX);
4529 return;
4532 numtowrite = SVAL(req->vwv+10, 0);
4533 smb_doff = SVAL(req->vwv+11, 0);
4534 smblen = smb_len(req->inbuf);
4536 if (req->unread_bytes > 0xFFFF ||
4537 (smblen > smb_doff &&
4538 smblen - smb_doff > 0xFFFF)) {
4539 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4542 if (req->unread_bytes) {
4543 /* Can't do a recvfile write on IPC$ */
4544 if (IS_IPC(conn)) {
4545 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4546 END_PROFILE(SMBwriteX);
4547 return;
4549 if (numtowrite != req->unread_bytes) {
4550 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4551 END_PROFILE(SMBwriteX);
4552 return;
4554 } else {
4555 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4556 smb_doff + numtowrite > smblen) {
4557 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4558 END_PROFILE(SMBwriteX);
4559 return;
4563 /* If it's an IPC, pass off the pipe handler. */
4564 if (IS_IPC(conn)) {
4565 if (req->unread_bytes) {
4566 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4567 END_PROFILE(SMBwriteX);
4568 return;
4570 reply_pipe_write_and_X(req);
4571 END_PROFILE(SMBwriteX);
4572 return;
4575 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4576 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4577 write_through = BITSETW(req->vwv+7,0);
4579 if (!check_fsp(conn, req, fsp)) {
4580 END_PROFILE(SMBwriteX);
4581 return;
4584 if (!CHECK_WRITE(fsp)) {
4585 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4586 END_PROFILE(SMBwriteX);
4587 return;
4590 data = smb_base(req->inbuf) + smb_doff;
4592 if(req->wct == 14) {
4593 #ifdef LARGE_SMB_OFF_T
4595 * This is a large offset (64 bit) write.
4597 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4599 #else /* !LARGE_SMB_OFF_T */
4602 * Ensure we haven't been sent a >32 bit offset.
4605 if(IVAL(req->vwv+12, 0) != 0) {
4606 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4607 "used and we don't support 64 bit offsets.\n",
4608 (unsigned int)IVAL(req->vwv+12, 0) ));
4609 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4610 END_PROFILE(SMBwriteX);
4611 return;
4614 #endif /* LARGE_SMB_OFF_T */
4617 /* X/Open SMB protocol says that, unlike SMBwrite
4618 if the length is zero then NO truncation is
4619 done, just a write of zero. To truncate a file,
4620 use SMBwrite. */
4622 if(numtowrite == 0) {
4623 nwritten = 0;
4624 } else {
4625 if (req->unread_bytes == 0) {
4626 status = schedule_aio_write_and_X(conn,
4627 req,
4628 fsp,
4629 data,
4630 startpos,
4631 numtowrite);
4633 if (NT_STATUS_IS_OK(status)) {
4634 /* write scheduled - we're done. */
4635 goto out;
4637 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4638 /* Real error - report to client. */
4639 reply_nterror(req, status);
4640 goto out;
4642 /* NT_STATUS_RETRY - fall through to sync write. */
4645 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4646 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4647 &lock);
4649 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4650 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4651 goto out;
4654 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4655 saved_errno = errno;
4657 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4660 if(nwritten < 0) {
4661 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4662 goto out;
4665 if((nwritten == 0) && (numtowrite != 0)) {
4666 reply_nterror(req, NT_STATUS_DISK_FULL);
4667 goto out;
4670 reply_outbuf(req, 6, 0);
4671 SSVAL(req->outbuf,smb_vwv2,nwritten);
4672 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4674 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4675 fsp->fnum, (int)numtowrite, (int)nwritten));
4677 status = sync_file(conn, fsp, write_through);
4678 if (!NT_STATUS_IS_OK(status)) {
4679 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4680 fsp_str_dbg(fsp), nt_errstr(status)));
4681 reply_nterror(req, status);
4682 goto out;
4685 END_PROFILE(SMBwriteX);
4686 chain_reply(req);
4687 return;
4689 out:
4690 END_PROFILE(SMBwriteX);
4691 return;
4694 /****************************************************************************
4695 Reply to a lseek.
4696 ****************************************************************************/
4698 void reply_lseek(struct smb_request *req)
4700 connection_struct *conn = req->conn;
4701 SMB_OFF_T startpos;
4702 SMB_OFF_T res= -1;
4703 int mode,umode;
4704 files_struct *fsp;
4706 START_PROFILE(SMBlseek);
4708 if (req->wct < 4) {
4709 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4710 END_PROFILE(SMBlseek);
4711 return;
4714 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4716 if (!check_fsp(conn, req, fsp)) {
4717 return;
4720 flush_write_cache(fsp, SEEK_FLUSH);
4722 mode = SVAL(req->vwv+1, 0) & 3;
4723 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4724 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4726 switch (mode) {
4727 case 0:
4728 umode = SEEK_SET;
4729 res = startpos;
4730 break;
4731 case 1:
4732 umode = SEEK_CUR;
4733 res = fsp->fh->pos + startpos;
4734 break;
4735 case 2:
4736 umode = SEEK_END;
4737 break;
4738 default:
4739 umode = SEEK_SET;
4740 res = startpos;
4741 break;
4744 if (umode == SEEK_END) {
4745 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4746 if(errno == EINVAL) {
4747 SMB_OFF_T current_pos = startpos;
4749 if(fsp_stat(fsp) == -1) {
4750 reply_nterror(req,
4751 map_nt_error_from_unix(errno));
4752 END_PROFILE(SMBlseek);
4753 return;
4756 current_pos += fsp->fsp_name->st.st_ex_size;
4757 if(current_pos < 0)
4758 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4762 if(res == -1) {
4763 reply_nterror(req, map_nt_error_from_unix(errno));
4764 END_PROFILE(SMBlseek);
4765 return;
4769 fsp->fh->pos = res;
4771 reply_outbuf(req, 2, 0);
4772 SIVAL(req->outbuf,smb_vwv0,res);
4774 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4775 fsp->fnum, (double)startpos, (double)res, mode));
4777 END_PROFILE(SMBlseek);
4778 return;
4781 /****************************************************************************
4782 Reply to a flush.
4783 ****************************************************************************/
4785 void reply_flush(struct smb_request *req)
4787 connection_struct *conn = req->conn;
4788 uint16 fnum;
4789 files_struct *fsp;
4791 START_PROFILE(SMBflush);
4793 if (req->wct < 1) {
4794 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4795 return;
4798 fnum = SVAL(req->vwv+0, 0);
4799 fsp = file_fsp(req, fnum);
4801 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4802 return;
4805 if (!fsp) {
4806 file_sync_all(conn);
4807 } else {
4808 NTSTATUS status = sync_file(conn, fsp, True);
4809 if (!NT_STATUS_IS_OK(status)) {
4810 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4811 fsp_str_dbg(fsp), nt_errstr(status)));
4812 reply_nterror(req, status);
4813 END_PROFILE(SMBflush);
4814 return;
4818 reply_outbuf(req, 0, 0);
4820 DEBUG(3,("flush\n"));
4821 END_PROFILE(SMBflush);
4822 return;
4825 /****************************************************************************
4826 Reply to a exit.
4827 conn POINTER CAN BE NULL HERE !
4828 ****************************************************************************/
4830 void reply_exit(struct smb_request *req)
4832 START_PROFILE(SMBexit);
4834 file_close_pid(req->sconn, req->smbpid, req->vuid);
4836 reply_outbuf(req, 0, 0);
4838 DEBUG(3,("exit\n"));
4840 END_PROFILE(SMBexit);
4841 return;
4844 /****************************************************************************
4845 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4846 ****************************************************************************/
4848 void reply_close(struct smb_request *req)
4850 connection_struct *conn = req->conn;
4851 NTSTATUS status = NT_STATUS_OK;
4852 files_struct *fsp = NULL;
4853 START_PROFILE(SMBclose);
4855 if (req->wct < 3) {
4856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4857 END_PROFILE(SMBclose);
4858 return;
4861 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4864 * We can only use check_fsp if we know it's not a directory.
4867 if (!check_fsp_open(conn, req, fsp)) {
4868 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4869 END_PROFILE(SMBclose);
4870 return;
4873 if(fsp->is_directory) {
4875 * Special case - close NT SMB directory handle.
4877 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4878 status = close_file(req, fsp, NORMAL_CLOSE);
4879 } else {
4880 time_t t;
4882 * Close ordinary file.
4885 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4886 fsp->fh->fd, fsp->fnum,
4887 conn->num_files_open));
4890 * Take care of any time sent in the close.
4893 t = srv_make_unix_date3(req->vwv+1);
4894 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4897 * close_file() returns the unix errno if an error
4898 * was detected on close - normally this is due to
4899 * a disk full error. If not then it was probably an I/O error.
4902 status = close_file(req, fsp, NORMAL_CLOSE);
4905 if (!NT_STATUS_IS_OK(status)) {
4906 reply_nterror(req, status);
4907 END_PROFILE(SMBclose);
4908 return;
4911 reply_outbuf(req, 0, 0);
4912 END_PROFILE(SMBclose);
4913 return;
4916 /****************************************************************************
4917 Reply to a writeclose (Core+ protocol).
4918 ****************************************************************************/
4920 void reply_writeclose(struct smb_request *req)
4922 connection_struct *conn = req->conn;
4923 size_t numtowrite;
4924 ssize_t nwritten = -1;
4925 NTSTATUS close_status = NT_STATUS_OK;
4926 SMB_OFF_T startpos;
4927 const char *data;
4928 struct timespec mtime;
4929 files_struct *fsp;
4930 struct lock_struct lock;
4932 START_PROFILE(SMBwriteclose);
4934 if (req->wct < 6) {
4935 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4936 END_PROFILE(SMBwriteclose);
4937 return;
4940 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4942 if (!check_fsp(conn, req, fsp)) {
4943 END_PROFILE(SMBwriteclose);
4944 return;
4946 if (!CHECK_WRITE(fsp)) {
4947 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4948 END_PROFILE(SMBwriteclose);
4949 return;
4952 numtowrite = SVAL(req->vwv+1, 0);
4953 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4954 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4955 data = (const char *)req->buf + 1;
4957 if (!fsp->print_file) {
4958 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4959 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4960 &lock);
4962 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4963 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4964 END_PROFILE(SMBwriteclose);
4965 return;
4969 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4971 set_close_write_time(fsp, mtime);
4974 * More insanity. W2K only closes the file if writelen > 0.
4975 * JRA.
4978 if (numtowrite) {
4979 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4980 "file %s\n", fsp_str_dbg(fsp)));
4981 close_status = close_file(req, fsp, NORMAL_CLOSE);
4984 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4985 fsp->fnum, (int)numtowrite, (int)nwritten,
4986 conn->num_files_open));
4988 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4989 reply_nterror(req, NT_STATUS_DISK_FULL);
4990 goto strict_unlock;
4993 if(!NT_STATUS_IS_OK(close_status)) {
4994 reply_nterror(req, close_status);
4995 goto strict_unlock;
4998 reply_outbuf(req, 1, 0);
5000 SSVAL(req->outbuf,smb_vwv0,nwritten);
5002 strict_unlock:
5003 if (numtowrite && !fsp->print_file) {
5004 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5007 END_PROFILE(SMBwriteclose);
5008 return;
5011 #undef DBGC_CLASS
5012 #define DBGC_CLASS DBGC_LOCKING
5014 /****************************************************************************
5015 Reply to a lock.
5016 ****************************************************************************/
5018 void reply_lock(struct smb_request *req)
5020 connection_struct *conn = req->conn;
5021 uint64_t count,offset;
5022 NTSTATUS status;
5023 files_struct *fsp;
5024 struct byte_range_lock *br_lck = NULL;
5026 START_PROFILE(SMBlock);
5028 if (req->wct < 5) {
5029 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5030 END_PROFILE(SMBlock);
5031 return;
5034 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5036 if (!check_fsp(conn, req, fsp)) {
5037 END_PROFILE(SMBlock);
5038 return;
5041 count = (uint64_t)IVAL(req->vwv+1, 0);
5042 offset = (uint64_t)IVAL(req->vwv+3, 0);
5044 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5045 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5047 br_lck = do_lock(req->sconn->msg_ctx,
5048 fsp,
5049 (uint64_t)req->smbpid,
5050 count,
5051 offset,
5052 WRITE_LOCK,
5053 WINDOWS_LOCK,
5054 False, /* Non-blocking lock. */
5055 &status,
5056 NULL,
5057 NULL);
5059 TALLOC_FREE(br_lck);
5061 if (NT_STATUS_V(status)) {
5062 reply_nterror(req, status);
5063 END_PROFILE(SMBlock);
5064 return;
5067 reply_outbuf(req, 0, 0);
5069 END_PROFILE(SMBlock);
5070 return;
5073 /****************************************************************************
5074 Reply to a unlock.
5075 ****************************************************************************/
5077 void reply_unlock(struct smb_request *req)
5079 connection_struct *conn = req->conn;
5080 uint64_t count,offset;
5081 NTSTATUS status;
5082 files_struct *fsp;
5084 START_PROFILE(SMBunlock);
5086 if (req->wct < 5) {
5087 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5088 END_PROFILE(SMBunlock);
5089 return;
5092 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5094 if (!check_fsp(conn, req, fsp)) {
5095 END_PROFILE(SMBunlock);
5096 return;
5099 count = (uint64_t)IVAL(req->vwv+1, 0);
5100 offset = (uint64_t)IVAL(req->vwv+3, 0);
5102 status = do_unlock(req->sconn->msg_ctx,
5103 fsp,
5104 (uint64_t)req->smbpid,
5105 count,
5106 offset,
5107 WINDOWS_LOCK);
5109 if (NT_STATUS_V(status)) {
5110 reply_nterror(req, status);
5111 END_PROFILE(SMBunlock);
5112 return;
5115 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5116 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5118 reply_outbuf(req, 0, 0);
5120 END_PROFILE(SMBunlock);
5121 return;
5124 #undef DBGC_CLASS
5125 #define DBGC_CLASS DBGC_ALL
5127 /****************************************************************************
5128 Reply to a tdis.
5129 conn POINTER CAN BE NULL HERE !
5130 ****************************************************************************/
5132 void reply_tdis(struct smb_request *req)
5134 connection_struct *conn = req->conn;
5135 START_PROFILE(SMBtdis);
5137 if (!conn) {
5138 DEBUG(4,("Invalid connection in tdis\n"));
5139 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5140 END_PROFILE(SMBtdis);
5141 return;
5144 conn->used = False;
5146 close_cnum(conn,req->vuid);
5147 req->conn = NULL;
5149 reply_outbuf(req, 0, 0);
5150 END_PROFILE(SMBtdis);
5151 return;
5154 /****************************************************************************
5155 Reply to a echo.
5156 conn POINTER CAN BE NULL HERE !
5157 ****************************************************************************/
5159 void reply_echo(struct smb_request *req)
5161 connection_struct *conn = req->conn;
5162 struct smb_perfcount_data local_pcd;
5163 struct smb_perfcount_data *cur_pcd;
5164 int smb_reverb;
5165 int seq_num;
5167 START_PROFILE(SMBecho);
5169 smb_init_perfcount_data(&local_pcd);
5171 if (req->wct < 1) {
5172 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5173 END_PROFILE(SMBecho);
5174 return;
5177 smb_reverb = SVAL(req->vwv+0, 0);
5179 reply_outbuf(req, 1, req->buflen);
5181 /* copy any incoming data back out */
5182 if (req->buflen > 0) {
5183 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5186 if (smb_reverb > 100) {
5187 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5188 smb_reverb = 100;
5191 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5193 /* this makes sure we catch the request pcd */
5194 if (seq_num == smb_reverb) {
5195 cur_pcd = &req->pcd;
5196 } else {
5197 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5198 cur_pcd = &local_pcd;
5201 SSVAL(req->outbuf,smb_vwv0,seq_num);
5203 show_msg((char *)req->outbuf);
5204 if (!srv_send_smb(req->sconn,
5205 (char *)req->outbuf,
5206 true, req->seqnum+1,
5207 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5208 cur_pcd))
5209 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5212 DEBUG(3,("echo %d times\n", smb_reverb));
5214 TALLOC_FREE(req->outbuf);
5216 END_PROFILE(SMBecho);
5217 return;
5220 /****************************************************************************
5221 Reply to a printopen.
5222 ****************************************************************************/
5224 void reply_printopen(struct smb_request *req)
5226 connection_struct *conn = req->conn;
5227 files_struct *fsp;
5228 NTSTATUS status;
5230 START_PROFILE(SMBsplopen);
5232 if (req->wct < 2) {
5233 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5234 END_PROFILE(SMBsplopen);
5235 return;
5238 if (!CAN_PRINT(conn)) {
5239 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5240 END_PROFILE(SMBsplopen);
5241 return;
5244 status = file_new(req, conn, &fsp);
5245 if(!NT_STATUS_IS_OK(status)) {
5246 reply_nterror(req, status);
5247 END_PROFILE(SMBsplopen);
5248 return;
5251 /* Open for exclusive use, write only. */
5252 status = print_spool_open(fsp, NULL, req->vuid);
5254 if (!NT_STATUS_IS_OK(status)) {
5255 file_free(req, fsp);
5256 reply_nterror(req, status);
5257 END_PROFILE(SMBsplopen);
5258 return;
5261 reply_outbuf(req, 1, 0);
5262 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5264 DEBUG(3,("openprint fd=%d fnum=%d\n",
5265 fsp->fh->fd, fsp->fnum));
5267 END_PROFILE(SMBsplopen);
5268 return;
5271 /****************************************************************************
5272 Reply to a printclose.
5273 ****************************************************************************/
5275 void reply_printclose(struct smb_request *req)
5277 connection_struct *conn = req->conn;
5278 files_struct *fsp;
5279 NTSTATUS status;
5281 START_PROFILE(SMBsplclose);
5283 if (req->wct < 1) {
5284 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5285 END_PROFILE(SMBsplclose);
5286 return;
5289 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5291 if (!check_fsp(conn, req, fsp)) {
5292 END_PROFILE(SMBsplclose);
5293 return;
5296 if (!CAN_PRINT(conn)) {
5297 reply_force_doserror(req, ERRSRV, ERRerror);
5298 END_PROFILE(SMBsplclose);
5299 return;
5302 DEBUG(3,("printclose fd=%d fnum=%d\n",
5303 fsp->fh->fd,fsp->fnum));
5305 status = close_file(req, fsp, NORMAL_CLOSE);
5307 if(!NT_STATUS_IS_OK(status)) {
5308 reply_nterror(req, status);
5309 END_PROFILE(SMBsplclose);
5310 return;
5313 reply_outbuf(req, 0, 0);
5315 END_PROFILE(SMBsplclose);
5316 return;
5319 /****************************************************************************
5320 Reply to a printqueue.
5321 ****************************************************************************/
5323 void reply_printqueue(struct smb_request *req)
5325 connection_struct *conn = req->conn;
5326 int max_count;
5327 int start_index;
5329 START_PROFILE(SMBsplretq);
5331 if (req->wct < 2) {
5332 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5333 END_PROFILE(SMBsplretq);
5334 return;
5337 max_count = SVAL(req->vwv+0, 0);
5338 start_index = SVAL(req->vwv+1, 0);
5340 /* we used to allow the client to get the cnum wrong, but that
5341 is really quite gross and only worked when there was only
5342 one printer - I think we should now only accept it if they
5343 get it right (tridge) */
5344 if (!CAN_PRINT(conn)) {
5345 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5346 END_PROFILE(SMBsplretq);
5347 return;
5350 reply_outbuf(req, 2, 3);
5351 SSVAL(req->outbuf,smb_vwv0,0);
5352 SSVAL(req->outbuf,smb_vwv1,0);
5353 SCVAL(smb_buf(req->outbuf),0,1);
5354 SSVAL(smb_buf(req->outbuf),1,0);
5356 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5357 start_index, max_count));
5360 TALLOC_CTX *mem_ctx = talloc_tos();
5361 NTSTATUS status;
5362 WERROR werr;
5363 const char *sharename = lp_servicename(SNUM(conn));
5364 struct rpc_pipe_client *cli = NULL;
5365 struct dcerpc_binding_handle *b = NULL;
5366 struct policy_handle handle;
5367 struct spoolss_DevmodeContainer devmode_ctr;
5368 union spoolss_JobInfo *info;
5369 uint32_t count;
5370 uint32_t num_to_get;
5371 uint32_t first;
5372 uint32_t i;
5374 ZERO_STRUCT(handle);
5376 status = rpc_pipe_open_interface(conn,
5377 &ndr_table_spoolss.syntax_id,
5378 conn->session_info,
5379 conn->sconn->remote_address,
5380 conn->sconn->msg_ctx,
5381 &cli);
5382 if (!NT_STATUS_IS_OK(status)) {
5383 DEBUG(0, ("reply_printqueue: "
5384 "could not connect to spoolss: %s\n",
5385 nt_errstr(status)));
5386 reply_nterror(req, status);
5387 goto out;
5389 b = cli->binding_handle;
5391 ZERO_STRUCT(devmode_ctr);
5393 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5394 sharename,
5395 NULL, devmode_ctr,
5396 SEC_FLAG_MAXIMUM_ALLOWED,
5397 &handle,
5398 &werr);
5399 if (!NT_STATUS_IS_OK(status)) {
5400 reply_nterror(req, status);
5401 goto out;
5403 if (!W_ERROR_IS_OK(werr)) {
5404 reply_nterror(req, werror_to_ntstatus(werr));
5405 goto out;
5408 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5409 &handle,
5410 0, /* firstjob */
5411 0xff, /* numjobs */
5412 2, /* level */
5413 0, /* offered */
5414 &count,
5415 &info);
5416 if (!W_ERROR_IS_OK(werr)) {
5417 reply_nterror(req, werror_to_ntstatus(werr));
5418 goto out;
5421 if (max_count > 0) {
5422 first = start_index;
5423 } else {
5424 first = start_index + max_count + 1;
5427 if (first >= count) {
5428 num_to_get = first;
5429 } else {
5430 num_to_get = first + MIN(ABS(max_count), count - first);
5433 for (i = first; i < num_to_get; i++) {
5434 char blob[28];
5435 char *p = blob;
5436 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5437 int qstatus;
5438 uint16_t qrapjobid = pjobid_to_rap(sharename,
5439 info[i].info2.job_id);
5441 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5442 qstatus = 2;
5443 } else {
5444 qstatus = 3;
5447 srv_put_dos_date2(p, 0, qtime);
5448 SCVAL(p, 4, qstatus);
5449 SSVAL(p, 5, qrapjobid);
5450 SIVAL(p, 7, info[i].info2.size);
5451 SCVAL(p, 11, 0);
5452 srvstr_push(blob, req->flags2, p+12,
5453 info[i].info2.notify_name, 16, STR_ASCII);
5455 if (message_push_blob(
5456 &req->outbuf,
5457 data_blob_const(
5458 blob, sizeof(blob))) == -1) {
5459 reply_nterror(req, NT_STATUS_NO_MEMORY);
5460 goto out;
5464 if (count > 0) {
5465 SSVAL(req->outbuf,smb_vwv0,count);
5466 SSVAL(req->outbuf,smb_vwv1,
5467 (max_count>0?first+count:first-1));
5468 SCVAL(smb_buf(req->outbuf),0,1);
5469 SSVAL(smb_buf(req->outbuf),1,28*count);
5473 DEBUG(3, ("%u entries returned in queue\n",
5474 (unsigned)count));
5476 out:
5477 if (b && is_valid_policy_hnd(&handle)) {
5478 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5483 END_PROFILE(SMBsplretq);
5484 return;
5487 /****************************************************************************
5488 Reply to a printwrite.
5489 ****************************************************************************/
5491 void reply_printwrite(struct smb_request *req)
5493 connection_struct *conn = req->conn;
5494 int numtowrite;
5495 const char *data;
5496 files_struct *fsp;
5498 START_PROFILE(SMBsplwr);
5500 if (req->wct < 1) {
5501 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5502 END_PROFILE(SMBsplwr);
5503 return;
5506 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5508 if (!check_fsp(conn, req, fsp)) {
5509 END_PROFILE(SMBsplwr);
5510 return;
5513 if (!fsp->print_file) {
5514 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5515 END_PROFILE(SMBsplwr);
5516 return;
5519 if (!CHECK_WRITE(fsp)) {
5520 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5521 END_PROFILE(SMBsplwr);
5522 return;
5525 numtowrite = SVAL(req->buf, 1);
5527 if (req->buflen < numtowrite + 3) {
5528 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5529 END_PROFILE(SMBsplwr);
5530 return;
5533 data = (const char *)req->buf + 3;
5535 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5536 reply_nterror(req, map_nt_error_from_unix(errno));
5537 END_PROFILE(SMBsplwr);
5538 return;
5541 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5543 END_PROFILE(SMBsplwr);
5544 return;
5547 /****************************************************************************
5548 Reply to a mkdir.
5549 ****************************************************************************/
5551 void reply_mkdir(struct smb_request *req)
5553 connection_struct *conn = req->conn;
5554 struct smb_filename *smb_dname = NULL;
5555 char *directory = NULL;
5556 NTSTATUS status;
5557 TALLOC_CTX *ctx = talloc_tos();
5559 START_PROFILE(SMBmkdir);
5561 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5562 STR_TERMINATE, &status);
5563 if (!NT_STATUS_IS_OK(status)) {
5564 reply_nterror(req, status);
5565 goto out;
5568 status = filename_convert(ctx, conn,
5569 req->flags2 & FLAGS2_DFS_PATHNAMES,
5570 directory,
5572 NULL,
5573 &smb_dname);
5574 if (!NT_STATUS_IS_OK(status)) {
5575 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5576 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5577 ERRSRV, ERRbadpath);
5578 goto out;
5580 reply_nterror(req, status);
5581 goto out;
5584 status = create_directory(conn, req, smb_dname);
5586 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5588 if (!NT_STATUS_IS_OK(status)) {
5590 if (!use_nt_status()
5591 && NT_STATUS_EQUAL(status,
5592 NT_STATUS_OBJECT_NAME_COLLISION)) {
5594 * Yes, in the DOS error code case we get a
5595 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5596 * samba4 torture test.
5598 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5601 reply_nterror(req, status);
5602 goto out;
5605 reply_outbuf(req, 0, 0);
5607 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5608 out:
5609 TALLOC_FREE(smb_dname);
5610 END_PROFILE(SMBmkdir);
5611 return;
5614 /****************************************************************************
5615 Reply to a rmdir.
5616 ****************************************************************************/
5618 void reply_rmdir(struct smb_request *req)
5620 connection_struct *conn = req->conn;
5621 struct smb_filename *smb_dname = NULL;
5622 char *directory = NULL;
5623 NTSTATUS status;
5624 TALLOC_CTX *ctx = talloc_tos();
5625 files_struct *fsp = NULL;
5626 int info = 0;
5627 struct smbd_server_connection *sconn = req->sconn;
5629 START_PROFILE(SMBrmdir);
5631 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5632 STR_TERMINATE, &status);
5633 if (!NT_STATUS_IS_OK(status)) {
5634 reply_nterror(req, status);
5635 goto out;
5638 status = filename_convert(ctx, conn,
5639 req->flags2 & FLAGS2_DFS_PATHNAMES,
5640 directory,
5642 NULL,
5643 &smb_dname);
5644 if (!NT_STATUS_IS_OK(status)) {
5645 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5646 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5647 ERRSRV, ERRbadpath);
5648 goto out;
5650 reply_nterror(req, status);
5651 goto out;
5654 if (is_ntfs_stream_smb_fname(smb_dname)) {
5655 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5656 goto out;
5659 status = SMB_VFS_CREATE_FILE(
5660 conn, /* conn */
5661 req, /* req */
5662 0, /* root_dir_fid */
5663 smb_dname, /* fname */
5664 DELETE_ACCESS, /* access_mask */
5665 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5666 FILE_SHARE_DELETE),
5667 FILE_OPEN, /* create_disposition*/
5668 FILE_DIRECTORY_FILE, /* create_options */
5669 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5670 0, /* oplock_request */
5671 0, /* allocation_size */
5672 0, /* private_flags */
5673 NULL, /* sd */
5674 NULL, /* ea_list */
5675 &fsp, /* result */
5676 &info); /* pinfo */
5678 if (!NT_STATUS_IS_OK(status)) {
5679 if (open_was_deferred(req->sconn, req->mid)) {
5680 /* We have re-scheduled this call. */
5681 goto out;
5683 reply_nterror(req, status);
5684 goto out;
5687 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5688 if (!NT_STATUS_IS_OK(status)) {
5689 close_file(req, fsp, ERROR_CLOSE);
5690 reply_nterror(req, status);
5691 goto out;
5694 if (!set_delete_on_close(fsp, true, conn->session_info->unix_token)) {
5695 close_file(req, fsp, ERROR_CLOSE);
5696 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5697 goto out;
5700 status = close_file(req, fsp, NORMAL_CLOSE);
5701 if (!NT_STATUS_IS_OK(status)) {
5702 reply_nterror(req, status);
5703 } else {
5704 reply_outbuf(req, 0, 0);
5707 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5709 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5710 out:
5711 TALLOC_FREE(smb_dname);
5712 END_PROFILE(SMBrmdir);
5713 return;
5716 /*******************************************************************
5717 Resolve wildcards in a filename rename.
5718 ********************************************************************/
5720 static bool resolve_wildcards(TALLOC_CTX *ctx,
5721 const char *name1,
5722 const char *name2,
5723 char **pp_newname)
5725 char *name2_copy = NULL;
5726 char *root1 = NULL;
5727 char *root2 = NULL;
5728 char *ext1 = NULL;
5729 char *ext2 = NULL;
5730 char *p,*p2, *pname1, *pname2;
5732 name2_copy = talloc_strdup(ctx, name2);
5733 if (!name2_copy) {
5734 return False;
5737 pname1 = strrchr_m(name1,'/');
5738 pname2 = strrchr_m(name2_copy,'/');
5740 if (!pname1 || !pname2) {
5741 return False;
5744 /* Truncate the copy of name2 at the last '/' */
5745 *pname2 = '\0';
5747 /* Now go past the '/' */
5748 pname1++;
5749 pname2++;
5751 root1 = talloc_strdup(ctx, pname1);
5752 root2 = talloc_strdup(ctx, pname2);
5754 if (!root1 || !root2) {
5755 return False;
5758 p = strrchr_m(root1,'.');
5759 if (p) {
5760 *p = 0;
5761 ext1 = talloc_strdup(ctx, p+1);
5762 } else {
5763 ext1 = talloc_strdup(ctx, "");
5765 p = strrchr_m(root2,'.');
5766 if (p) {
5767 *p = 0;
5768 ext2 = talloc_strdup(ctx, p+1);
5769 } else {
5770 ext2 = talloc_strdup(ctx, "");
5773 if (!ext1 || !ext2) {
5774 return False;
5777 p = root1;
5778 p2 = root2;
5779 while (*p2) {
5780 if (*p2 == '?') {
5781 /* Hmmm. Should this be mb-aware ? */
5782 *p2 = *p;
5783 p2++;
5784 } else if (*p2 == '*') {
5785 *p2 = '\0';
5786 root2 = talloc_asprintf(ctx, "%s%s",
5787 root2,
5789 if (!root2) {
5790 return False;
5792 break;
5793 } else {
5794 p2++;
5796 if (*p) {
5797 p++;
5801 p = ext1;
5802 p2 = ext2;
5803 while (*p2) {
5804 if (*p2 == '?') {
5805 /* Hmmm. Should this be mb-aware ? */
5806 *p2 = *p;
5807 p2++;
5808 } else if (*p2 == '*') {
5809 *p2 = '\0';
5810 ext2 = talloc_asprintf(ctx, "%s%s",
5811 ext2,
5813 if (!ext2) {
5814 return False;
5816 break;
5817 } else {
5818 p2++;
5820 if (*p) {
5821 p++;
5825 if (*ext2) {
5826 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5827 name2_copy,
5828 root2,
5829 ext2);
5830 } else {
5831 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5832 name2_copy,
5833 root2);
5836 if (!*pp_newname) {
5837 return False;
5840 return True;
5843 /****************************************************************************
5844 Ensure open files have their names updated. Updated to notify other smbd's
5845 asynchronously.
5846 ****************************************************************************/
5848 static void rename_open_files(connection_struct *conn,
5849 struct share_mode_lock *lck,
5850 uint32_t orig_name_hash,
5851 const struct smb_filename *smb_fname_dst)
5853 files_struct *fsp;
5854 bool did_rename = False;
5855 NTSTATUS status;
5856 uint32_t new_name_hash = 0;
5858 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5859 fsp = file_find_di_next(fsp)) {
5860 /* fsp_name is a relative path under the fsp. To change this for other
5861 sharepaths we need to manipulate relative paths. */
5862 /* TODO - create the absolute path and manipulate the newname
5863 relative to the sharepath. */
5864 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5865 continue;
5867 if (fsp->name_hash != orig_name_hash) {
5868 continue;
5870 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5871 "(file_id %s) from %s -> %s\n", fsp->fnum,
5872 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5873 smb_fname_str_dbg(smb_fname_dst)));
5875 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5876 if (NT_STATUS_IS_OK(status)) {
5877 did_rename = True;
5878 new_name_hash = fsp->name_hash;
5882 if (!did_rename) {
5883 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5884 "for %s\n", file_id_string_tos(&lck->id),
5885 smb_fname_str_dbg(smb_fname_dst)));
5888 /* Send messages to all smbd's (not ourself) that the name has changed. */
5889 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5890 orig_name_hash, new_name_hash,
5891 smb_fname_dst);
5895 /****************************************************************************
5896 We need to check if the source path is a parent directory of the destination
5897 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5898 refuse the rename with a sharing violation. Under UNIX the above call can
5899 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5900 probably need to check that the client is a Windows one before disallowing
5901 this as a UNIX client (one with UNIX extensions) can know the source is a
5902 symlink and make this decision intelligently. Found by an excellent bug
5903 report from <AndyLiebman@aol.com>.
5904 ****************************************************************************/
5906 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5907 const struct smb_filename *smb_fname_dst)
5909 const char *psrc = smb_fname_src->base_name;
5910 const char *pdst = smb_fname_dst->base_name;
5911 size_t slen;
5913 if (psrc[0] == '.' && psrc[1] == '/') {
5914 psrc += 2;
5916 if (pdst[0] == '.' && pdst[1] == '/') {
5917 pdst += 2;
5919 if ((slen = strlen(psrc)) > strlen(pdst)) {
5920 return False;
5922 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5926 * Do the notify calls from a rename
5929 static void notify_rename(connection_struct *conn, bool is_dir,
5930 const struct smb_filename *smb_fname_src,
5931 const struct smb_filename *smb_fname_dst)
5933 char *parent_dir_src = NULL;
5934 char *parent_dir_dst = NULL;
5935 uint32 mask;
5937 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5938 : FILE_NOTIFY_CHANGE_FILE_NAME;
5940 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5941 &parent_dir_src, NULL) ||
5942 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5943 &parent_dir_dst, NULL)) {
5944 goto out;
5947 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5948 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5949 smb_fname_src->base_name);
5950 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5951 smb_fname_dst->base_name);
5953 else {
5954 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5955 smb_fname_src->base_name);
5956 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5957 smb_fname_dst->base_name);
5960 /* this is a strange one. w2k3 gives an additional event for
5961 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5962 files, but not directories */
5963 if (!is_dir) {
5964 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5965 FILE_NOTIFY_CHANGE_ATTRIBUTES
5966 |FILE_NOTIFY_CHANGE_CREATION,
5967 smb_fname_dst->base_name);
5969 out:
5970 TALLOC_FREE(parent_dir_src);
5971 TALLOC_FREE(parent_dir_dst);
5974 /****************************************************************************
5975 Returns an error if the parent directory for a filename is open in an
5976 incompatible way.
5977 ****************************************************************************/
5979 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
5980 const struct smb_filename *smb_fname_dst_in)
5982 char *parent_dir = NULL;
5983 struct smb_filename smb_fname_parent;
5984 struct file_id id;
5985 files_struct *fsp = NULL;
5986 int ret;
5988 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
5989 &parent_dir, NULL)) {
5990 return NT_STATUS_NO_MEMORY;
5992 ZERO_STRUCT(smb_fname_parent);
5993 smb_fname_parent.base_name = parent_dir;
5995 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
5996 if (ret == -1) {
5997 return map_nt_error_from_unix(errno);
6001 * We're only checking on this smbd here, mostly good
6002 * enough.. and will pass tests.
6005 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6006 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6007 fsp = file_find_di_next(fsp)) {
6008 if (fsp->access_mask & DELETE_ACCESS) {
6009 return NT_STATUS_SHARING_VIOLATION;
6012 return NT_STATUS_OK;
6015 /****************************************************************************
6016 Rename an open file - given an fsp.
6017 ****************************************************************************/
6019 NTSTATUS rename_internals_fsp(connection_struct *conn,
6020 files_struct *fsp,
6021 const struct smb_filename *smb_fname_dst_in,
6022 uint32 attrs,
6023 bool replace_if_exists)
6025 TALLOC_CTX *ctx = talloc_tos();
6026 struct smb_filename *smb_fname_dst = NULL;
6027 NTSTATUS status = NT_STATUS_OK;
6028 struct share_mode_lock *lck = NULL;
6029 bool dst_exists, old_is_stream, new_is_stream;
6031 status = check_name(conn, smb_fname_dst_in->base_name);
6032 if (!NT_STATUS_IS_OK(status)) {
6033 return status;
6036 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6037 if (!NT_STATUS_IS_OK(status)) {
6038 return status;
6041 /* Make a copy of the dst smb_fname structs */
6043 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6044 if (!NT_STATUS_IS_OK(status)) {
6045 goto out;
6049 * Check for special case with case preserving and not
6050 * case sensitive. If the old last component differs from the original
6051 * last component only by case, then we should allow
6052 * the rename (user is trying to change the case of the
6053 * filename).
6055 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6056 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6057 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6058 char *last_slash;
6059 char *fname_dst_lcomp_base_mod = NULL;
6060 struct smb_filename *smb_fname_orig_lcomp = NULL;
6063 * Get the last component of the destination name.
6065 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6066 if (last_slash) {
6067 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6068 } else {
6069 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6071 if (!fname_dst_lcomp_base_mod) {
6072 status = NT_STATUS_NO_MEMORY;
6073 goto out;
6077 * Create an smb_filename struct using the original last
6078 * component of the destination.
6080 status = create_synthetic_smb_fname_split(ctx,
6081 smb_fname_dst->original_lcomp, NULL,
6082 &smb_fname_orig_lcomp);
6083 if (!NT_STATUS_IS_OK(status)) {
6084 TALLOC_FREE(fname_dst_lcomp_base_mod);
6085 goto out;
6088 /* If the base names only differ by case, use original. */
6089 if(!strcsequal(fname_dst_lcomp_base_mod,
6090 smb_fname_orig_lcomp->base_name)) {
6091 char *tmp;
6093 * Replace the modified last component with the
6094 * original.
6096 if (last_slash) {
6097 *last_slash = '\0'; /* Truncate at the '/' */
6098 tmp = talloc_asprintf(smb_fname_dst,
6099 "%s/%s",
6100 smb_fname_dst->base_name,
6101 smb_fname_orig_lcomp->base_name);
6102 } else {
6103 tmp = talloc_asprintf(smb_fname_dst,
6104 "%s",
6105 smb_fname_orig_lcomp->base_name);
6107 if (tmp == NULL) {
6108 status = NT_STATUS_NO_MEMORY;
6109 TALLOC_FREE(fname_dst_lcomp_base_mod);
6110 TALLOC_FREE(smb_fname_orig_lcomp);
6111 goto out;
6113 TALLOC_FREE(smb_fname_dst->base_name);
6114 smb_fname_dst->base_name = tmp;
6117 /* If the stream_names only differ by case, use original. */
6118 if(!strcsequal(smb_fname_dst->stream_name,
6119 smb_fname_orig_lcomp->stream_name)) {
6120 char *tmp = NULL;
6121 /* Use the original stream. */
6122 tmp = talloc_strdup(smb_fname_dst,
6123 smb_fname_orig_lcomp->stream_name);
6124 if (tmp == NULL) {
6125 status = NT_STATUS_NO_MEMORY;
6126 TALLOC_FREE(fname_dst_lcomp_base_mod);
6127 TALLOC_FREE(smb_fname_orig_lcomp);
6128 goto out;
6130 TALLOC_FREE(smb_fname_dst->stream_name);
6131 smb_fname_dst->stream_name = tmp;
6133 TALLOC_FREE(fname_dst_lcomp_base_mod);
6134 TALLOC_FREE(smb_fname_orig_lcomp);
6138 * If the src and dest names are identical - including case,
6139 * don't do the rename, just return success.
6142 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6143 strcsequal(fsp->fsp_name->stream_name,
6144 smb_fname_dst->stream_name)) {
6145 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6146 "- returning success\n",
6147 smb_fname_str_dbg(smb_fname_dst)));
6148 status = NT_STATUS_OK;
6149 goto out;
6152 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6153 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6155 /* Return the correct error code if both names aren't streams. */
6156 if (!old_is_stream && new_is_stream) {
6157 status = NT_STATUS_OBJECT_NAME_INVALID;
6158 goto out;
6161 if (old_is_stream && !new_is_stream) {
6162 status = NT_STATUS_INVALID_PARAMETER;
6163 goto out;
6166 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6168 if(!replace_if_exists && dst_exists) {
6169 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6170 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6171 smb_fname_str_dbg(smb_fname_dst)));
6172 status = NT_STATUS_OBJECT_NAME_COLLISION;
6173 goto out;
6176 if (dst_exists) {
6177 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6178 &smb_fname_dst->st);
6179 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6180 fileid);
6181 /* The file can be open when renaming a stream */
6182 if (dst_fsp && !new_is_stream) {
6183 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6184 status = NT_STATUS_ACCESS_DENIED;
6185 goto out;
6189 /* Ensure we have a valid stat struct for the source. */
6190 status = vfs_stat_fsp(fsp);
6191 if (!NT_STATUS_IS_OK(status)) {
6192 goto out;
6195 status = can_rename(conn, fsp, attrs);
6197 if (!NT_STATUS_IS_OK(status)) {
6198 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6199 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6200 smb_fname_str_dbg(smb_fname_dst)));
6201 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6202 status = NT_STATUS_ACCESS_DENIED;
6203 goto out;
6206 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6207 status = NT_STATUS_ACCESS_DENIED;
6210 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6211 NULL);
6214 * We have the file open ourselves, so not being able to get the
6215 * corresponding share mode lock is a fatal error.
6218 SMB_ASSERT(lck != NULL);
6220 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6221 uint32 create_options = fsp->fh->private_options;
6223 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6224 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6225 smb_fname_str_dbg(smb_fname_dst)));
6227 if (!lp_posix_pathnames() &&
6228 (lp_map_archive(SNUM(conn)) ||
6229 lp_store_dos_attributes(SNUM(conn)))) {
6230 /* We must set the archive bit on the newly
6231 renamed file. */
6232 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6233 uint32_t old_dosmode = dos_mode(conn,
6234 smb_fname_dst);
6235 file_set_dosmode(conn,
6236 smb_fname_dst,
6237 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6238 NULL,
6239 true);
6243 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6244 smb_fname_dst);
6246 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6249 * A rename acts as a new file create w.r.t. allowing an initial delete
6250 * on close, probably because in Windows there is a new handle to the
6251 * new file. If initial delete on close was requested but not
6252 * originally set, we need to set it here. This is probably not 100% correct,
6253 * but will work for the CIFSFS client which in non-posix mode
6254 * depends on these semantics. JRA.
6257 if (create_options & FILE_DELETE_ON_CLOSE) {
6258 status = can_set_delete_on_close(fsp, 0);
6260 if (NT_STATUS_IS_OK(status)) {
6261 /* Note that here we set the *inital* delete on close flag,
6262 * not the regular one. The magic gets handled in close. */
6263 fsp->initial_delete_on_close = True;
6266 TALLOC_FREE(lck);
6267 status = NT_STATUS_OK;
6268 goto out;
6271 TALLOC_FREE(lck);
6273 if (errno == ENOTDIR || errno == EISDIR) {
6274 status = NT_STATUS_OBJECT_NAME_COLLISION;
6275 } else {
6276 status = map_nt_error_from_unix(errno);
6279 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6280 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6281 smb_fname_str_dbg(smb_fname_dst)));
6283 out:
6284 TALLOC_FREE(smb_fname_dst);
6286 return status;
6289 /****************************************************************************
6290 The guts of the rename command, split out so it may be called by the NT SMB
6291 code.
6292 ****************************************************************************/
6294 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6295 connection_struct *conn,
6296 struct smb_request *req,
6297 struct smb_filename *smb_fname_src,
6298 struct smb_filename *smb_fname_dst,
6299 uint32 attrs,
6300 bool replace_if_exists,
6301 bool src_has_wild,
6302 bool dest_has_wild,
6303 uint32_t access_mask)
6305 char *fname_src_dir = NULL;
6306 char *fname_src_mask = NULL;
6307 int count=0;
6308 NTSTATUS status = NT_STATUS_OK;
6309 struct smb_Dir *dir_hnd = NULL;
6310 const char *dname = NULL;
6311 char *talloced = NULL;
6312 long offset = 0;
6313 int create_options = 0;
6314 bool posix_pathnames = lp_posix_pathnames();
6317 * Split the old name into directory and last component
6318 * strings. Note that unix_convert may have stripped off a
6319 * leading ./ from both name and newname if the rename is
6320 * at the root of the share. We need to make sure either both
6321 * name and newname contain a / character or neither of them do
6322 * as this is checked in resolve_wildcards().
6325 /* Split up the directory from the filename/mask. */
6326 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6327 &fname_src_dir, &fname_src_mask);
6328 if (!NT_STATUS_IS_OK(status)) {
6329 status = NT_STATUS_NO_MEMORY;
6330 goto out;
6334 * We should only check the mangled cache
6335 * here if unix_convert failed. This means
6336 * that the path in 'mask' doesn't exist
6337 * on the file system and so we need to look
6338 * for a possible mangle. This patch from
6339 * Tine Smukavec <valentin.smukavec@hermes.si>.
6342 if (!VALID_STAT(smb_fname_src->st) &&
6343 mangle_is_mangled(fname_src_mask, conn->params)) {
6344 char *new_mask = NULL;
6345 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6346 conn->params);
6347 if (new_mask) {
6348 TALLOC_FREE(fname_src_mask);
6349 fname_src_mask = new_mask;
6353 if (!src_has_wild) {
6354 files_struct *fsp;
6357 * Only one file needs to be renamed. Append the mask back
6358 * onto the directory.
6360 TALLOC_FREE(smb_fname_src->base_name);
6361 if (ISDOT(fname_src_dir)) {
6362 /* Ensure we use canonical names on open. */
6363 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6364 "%s",
6365 fname_src_mask);
6366 } else {
6367 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6368 "%s/%s",
6369 fname_src_dir,
6370 fname_src_mask);
6372 if (!smb_fname_src->base_name) {
6373 status = NT_STATUS_NO_MEMORY;
6374 goto out;
6377 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6378 "case_preserve = %d, short case preserve = %d, "
6379 "directory = %s, newname = %s, "
6380 "last_component_dest = %s\n",
6381 conn->case_sensitive, conn->case_preserve,
6382 conn->short_case_preserve,
6383 smb_fname_str_dbg(smb_fname_src),
6384 smb_fname_str_dbg(smb_fname_dst),
6385 smb_fname_dst->original_lcomp));
6387 /* The dest name still may have wildcards. */
6388 if (dest_has_wild) {
6389 char *fname_dst_mod = NULL;
6390 if (!resolve_wildcards(smb_fname_dst,
6391 smb_fname_src->base_name,
6392 smb_fname_dst->base_name,
6393 &fname_dst_mod)) {
6394 DEBUG(6, ("rename_internals: resolve_wildcards "
6395 "%s %s failed\n",
6396 smb_fname_src->base_name,
6397 smb_fname_dst->base_name));
6398 status = NT_STATUS_NO_MEMORY;
6399 goto out;
6401 TALLOC_FREE(smb_fname_dst->base_name);
6402 smb_fname_dst->base_name = fname_dst_mod;
6405 ZERO_STRUCT(smb_fname_src->st);
6406 if (posix_pathnames) {
6407 SMB_VFS_LSTAT(conn, smb_fname_src);
6408 } else {
6409 SMB_VFS_STAT(conn, smb_fname_src);
6412 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6413 create_options |= FILE_DIRECTORY_FILE;
6416 status = SMB_VFS_CREATE_FILE(
6417 conn, /* conn */
6418 req, /* req */
6419 0, /* root_dir_fid */
6420 smb_fname_src, /* fname */
6421 access_mask, /* access_mask */
6422 (FILE_SHARE_READ | /* share_access */
6423 FILE_SHARE_WRITE),
6424 FILE_OPEN, /* create_disposition*/
6425 create_options, /* create_options */
6426 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6427 0, /* oplock_request */
6428 0, /* allocation_size */
6429 0, /* private_flags */
6430 NULL, /* sd */
6431 NULL, /* ea_list */
6432 &fsp, /* result */
6433 NULL); /* pinfo */
6435 if (!NT_STATUS_IS_OK(status)) {
6436 DEBUG(3, ("Could not open rename source %s: %s\n",
6437 smb_fname_str_dbg(smb_fname_src),
6438 nt_errstr(status)));
6439 goto out;
6442 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6443 attrs, replace_if_exists);
6445 close_file(req, fsp, NORMAL_CLOSE);
6447 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6448 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6449 smb_fname_str_dbg(smb_fname_dst)));
6451 goto out;
6455 * Wildcards - process each file that matches.
6457 if (strequal(fname_src_mask, "????????.???")) {
6458 TALLOC_FREE(fname_src_mask);
6459 fname_src_mask = talloc_strdup(ctx, "*");
6460 if (!fname_src_mask) {
6461 status = NT_STATUS_NO_MEMORY;
6462 goto out;
6466 status = check_name(conn, fname_src_dir);
6467 if (!NT_STATUS_IS_OK(status)) {
6468 goto out;
6471 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6472 attrs);
6473 if (dir_hnd == NULL) {
6474 status = map_nt_error_from_unix(errno);
6475 goto out;
6478 status = NT_STATUS_NO_SUCH_FILE;
6480 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6481 * - gentest fix. JRA
6484 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6485 &talloced))) {
6486 files_struct *fsp = NULL;
6487 char *destname = NULL;
6488 bool sysdir_entry = False;
6490 /* Quick check for "." and ".." */
6491 if (ISDOT(dname) || ISDOTDOT(dname)) {
6492 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6493 sysdir_entry = True;
6494 } else {
6495 TALLOC_FREE(talloced);
6496 continue;
6500 if (!is_visible_file(conn, fname_src_dir, dname,
6501 &smb_fname_src->st, false)) {
6502 TALLOC_FREE(talloced);
6503 continue;
6506 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6507 TALLOC_FREE(talloced);
6508 continue;
6511 if (sysdir_entry) {
6512 status = NT_STATUS_OBJECT_NAME_INVALID;
6513 break;
6516 TALLOC_FREE(smb_fname_src->base_name);
6517 if (ISDOT(fname_src_dir)) {
6518 /* Ensure we use canonical names on open. */
6519 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6520 "%s",
6521 dname);
6522 } else {
6523 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6524 "%s/%s",
6525 fname_src_dir,
6526 dname);
6528 if (!smb_fname_src->base_name) {
6529 status = NT_STATUS_NO_MEMORY;
6530 goto out;
6533 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6534 smb_fname_dst->base_name,
6535 &destname)) {
6536 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6537 smb_fname_src->base_name, destname));
6538 TALLOC_FREE(talloced);
6539 continue;
6541 if (!destname) {
6542 status = NT_STATUS_NO_MEMORY;
6543 goto out;
6546 TALLOC_FREE(smb_fname_dst->base_name);
6547 smb_fname_dst->base_name = destname;
6549 ZERO_STRUCT(smb_fname_src->st);
6550 if (posix_pathnames) {
6551 SMB_VFS_LSTAT(conn, smb_fname_src);
6552 } else {
6553 SMB_VFS_STAT(conn, smb_fname_src);
6556 create_options = 0;
6558 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6559 create_options |= FILE_DIRECTORY_FILE;
6562 status = SMB_VFS_CREATE_FILE(
6563 conn, /* conn */
6564 req, /* req */
6565 0, /* root_dir_fid */
6566 smb_fname_src, /* fname */
6567 access_mask, /* access_mask */
6568 (FILE_SHARE_READ | /* share_access */
6569 FILE_SHARE_WRITE),
6570 FILE_OPEN, /* create_disposition*/
6571 create_options, /* create_options */
6572 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6573 0, /* oplock_request */
6574 0, /* allocation_size */
6575 0, /* private_flags */
6576 NULL, /* sd */
6577 NULL, /* ea_list */
6578 &fsp, /* result */
6579 NULL); /* pinfo */
6581 if (!NT_STATUS_IS_OK(status)) {
6582 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6583 "returned %s rename %s -> %s\n",
6584 nt_errstr(status),
6585 smb_fname_str_dbg(smb_fname_src),
6586 smb_fname_str_dbg(smb_fname_dst)));
6587 break;
6590 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6591 dname);
6592 if (!smb_fname_dst->original_lcomp) {
6593 status = NT_STATUS_NO_MEMORY;
6594 goto out;
6597 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6598 attrs, replace_if_exists);
6600 close_file(req, fsp, NORMAL_CLOSE);
6602 if (!NT_STATUS_IS_OK(status)) {
6603 DEBUG(3, ("rename_internals_fsp returned %s for "
6604 "rename %s -> %s\n", nt_errstr(status),
6605 smb_fname_str_dbg(smb_fname_src),
6606 smb_fname_str_dbg(smb_fname_dst)));
6607 break;
6610 count++;
6612 DEBUG(3,("rename_internals: doing rename on %s -> "
6613 "%s\n", smb_fname_str_dbg(smb_fname_src),
6614 smb_fname_str_dbg(smb_fname_src)));
6615 TALLOC_FREE(talloced);
6617 TALLOC_FREE(dir_hnd);
6619 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6620 status = map_nt_error_from_unix(errno);
6623 out:
6624 TALLOC_FREE(talloced);
6625 TALLOC_FREE(fname_src_dir);
6626 TALLOC_FREE(fname_src_mask);
6627 return status;
6630 /****************************************************************************
6631 Reply to a mv.
6632 ****************************************************************************/
6634 void reply_mv(struct smb_request *req)
6636 connection_struct *conn = req->conn;
6637 char *name = NULL;
6638 char *newname = NULL;
6639 const char *p;
6640 uint32 attrs;
6641 NTSTATUS status;
6642 bool src_has_wcard = False;
6643 bool dest_has_wcard = False;
6644 TALLOC_CTX *ctx = talloc_tos();
6645 struct smb_filename *smb_fname_src = NULL;
6646 struct smb_filename *smb_fname_dst = NULL;
6647 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6648 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6649 bool stream_rename = false;
6651 START_PROFILE(SMBmv);
6653 if (req->wct < 1) {
6654 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6655 goto out;
6658 attrs = SVAL(req->vwv+0, 0);
6660 p = (const char *)req->buf + 1;
6661 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6662 &status, &src_has_wcard);
6663 if (!NT_STATUS_IS_OK(status)) {
6664 reply_nterror(req, status);
6665 goto out;
6667 p++;
6668 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6669 &status, &dest_has_wcard);
6670 if (!NT_STATUS_IS_OK(status)) {
6671 reply_nterror(req, status);
6672 goto out;
6675 if (!lp_posix_pathnames()) {
6676 /* The newname must begin with a ':' if the
6677 name contains a ':'. */
6678 if (strchr_m(name, ':')) {
6679 if (newname[0] != ':') {
6680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6681 goto out;
6683 stream_rename = true;
6687 status = filename_convert(ctx,
6688 conn,
6689 req->flags2 & FLAGS2_DFS_PATHNAMES,
6690 name,
6691 src_ucf_flags,
6692 &src_has_wcard,
6693 &smb_fname_src);
6695 if (!NT_STATUS_IS_OK(status)) {
6696 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6697 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6698 ERRSRV, ERRbadpath);
6699 goto out;
6701 reply_nterror(req, status);
6702 goto out;
6705 status = filename_convert(ctx,
6706 conn,
6707 req->flags2 & FLAGS2_DFS_PATHNAMES,
6708 newname,
6709 dst_ucf_flags,
6710 &dest_has_wcard,
6711 &smb_fname_dst);
6713 if (!NT_STATUS_IS_OK(status)) {
6714 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6715 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6716 ERRSRV, ERRbadpath);
6717 goto out;
6719 reply_nterror(req, status);
6720 goto out;
6723 if (stream_rename) {
6724 /* smb_fname_dst->base_name must be the same as
6725 smb_fname_src->base_name. */
6726 TALLOC_FREE(smb_fname_dst->base_name);
6727 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6728 smb_fname_src->base_name);
6729 if (!smb_fname_dst->base_name) {
6730 reply_nterror(req, NT_STATUS_NO_MEMORY);
6731 goto out;
6735 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6736 smb_fname_str_dbg(smb_fname_dst)));
6738 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6739 attrs, False, src_has_wcard, dest_has_wcard,
6740 DELETE_ACCESS);
6741 if (!NT_STATUS_IS_OK(status)) {
6742 if (open_was_deferred(req->sconn, req->mid)) {
6743 /* We have re-scheduled this call. */
6744 goto out;
6746 reply_nterror(req, status);
6747 goto out;
6750 reply_outbuf(req, 0, 0);
6751 out:
6752 TALLOC_FREE(smb_fname_src);
6753 TALLOC_FREE(smb_fname_dst);
6754 END_PROFILE(SMBmv);
6755 return;
6758 /*******************************************************************
6759 Copy a file as part of a reply_copy.
6760 ******************************************************************/
6763 * TODO: check error codes on all callers
6766 NTSTATUS copy_file(TALLOC_CTX *ctx,
6767 connection_struct *conn,
6768 struct smb_filename *smb_fname_src,
6769 struct smb_filename *smb_fname_dst,
6770 int ofun,
6771 int count,
6772 bool target_is_directory)
6774 struct smb_filename *smb_fname_dst_tmp = NULL;
6775 SMB_OFF_T ret=-1;
6776 files_struct *fsp1,*fsp2;
6777 uint32 dosattrs;
6778 uint32 new_create_disposition;
6779 NTSTATUS status;
6782 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6783 if (!NT_STATUS_IS_OK(status)) {
6784 return status;
6788 * If the target is a directory, extract the last component from the
6789 * src filename and append it to the dst filename
6791 if (target_is_directory) {
6792 const char *p;
6794 /* dest/target can't be a stream if it's a directory. */
6795 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6797 p = strrchr_m(smb_fname_src->base_name,'/');
6798 if (p) {
6799 p++;
6800 } else {
6801 p = smb_fname_src->base_name;
6803 smb_fname_dst_tmp->base_name =
6804 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6806 if (!smb_fname_dst_tmp->base_name) {
6807 status = NT_STATUS_NO_MEMORY;
6808 goto out;
6812 status = vfs_file_exist(conn, smb_fname_src);
6813 if (!NT_STATUS_IS_OK(status)) {
6814 goto out;
6817 if (!target_is_directory && count) {
6818 new_create_disposition = FILE_OPEN;
6819 } else {
6820 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6821 0, ofun,
6822 NULL, NULL,
6823 &new_create_disposition,
6824 NULL,
6825 NULL)) {
6826 status = NT_STATUS_INVALID_PARAMETER;
6827 goto out;
6831 /* Open the src file for reading. */
6832 status = SMB_VFS_CREATE_FILE(
6833 conn, /* conn */
6834 NULL, /* req */
6835 0, /* root_dir_fid */
6836 smb_fname_src, /* fname */
6837 FILE_GENERIC_READ, /* access_mask */
6838 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6839 FILE_OPEN, /* create_disposition*/
6840 0, /* create_options */
6841 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6842 INTERNAL_OPEN_ONLY, /* oplock_request */
6843 0, /* allocation_size */
6844 0, /* private_flags */
6845 NULL, /* sd */
6846 NULL, /* ea_list */
6847 &fsp1, /* result */
6848 NULL); /* psbuf */
6850 if (!NT_STATUS_IS_OK(status)) {
6851 goto out;
6854 dosattrs = dos_mode(conn, smb_fname_src);
6856 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6857 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6860 /* Open the dst file for writing. */
6861 status = SMB_VFS_CREATE_FILE(
6862 conn, /* conn */
6863 NULL, /* req */
6864 0, /* root_dir_fid */
6865 smb_fname_dst, /* fname */
6866 FILE_GENERIC_WRITE, /* access_mask */
6867 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6868 new_create_disposition, /* create_disposition*/
6869 0, /* create_options */
6870 dosattrs, /* file_attributes */
6871 INTERNAL_OPEN_ONLY, /* oplock_request */
6872 0, /* allocation_size */
6873 0, /* private_flags */
6874 NULL, /* sd */
6875 NULL, /* ea_list */
6876 &fsp2, /* result */
6877 NULL); /* psbuf */
6879 if (!NT_STATUS_IS_OK(status)) {
6880 close_file(NULL, fsp1, ERROR_CLOSE);
6881 goto out;
6884 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6885 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6886 if (ret == -1) {
6887 DEBUG(0, ("error - vfs lseek returned error %s\n",
6888 strerror(errno)));
6889 status = map_nt_error_from_unix(errno);
6890 close_file(NULL, fsp1, ERROR_CLOSE);
6891 close_file(NULL, fsp2, ERROR_CLOSE);
6892 goto out;
6896 /* Do the actual copy. */
6897 if (smb_fname_src->st.st_ex_size) {
6898 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6899 } else {
6900 ret = 0;
6903 close_file(NULL, fsp1, NORMAL_CLOSE);
6905 /* Ensure the modtime is set correctly on the destination file. */
6906 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6909 * As we are opening fsp1 read-only we only expect
6910 * an error on close on fsp2 if we are out of space.
6911 * Thus we don't look at the error return from the
6912 * close of fsp1.
6914 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6916 if (!NT_STATUS_IS_OK(status)) {
6917 goto out;
6920 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6921 status = NT_STATUS_DISK_FULL;
6922 goto out;
6925 status = NT_STATUS_OK;
6927 out:
6928 TALLOC_FREE(smb_fname_dst_tmp);
6929 return status;
6932 /****************************************************************************
6933 Reply to a file copy.
6934 ****************************************************************************/
6936 void reply_copy(struct smb_request *req)
6938 connection_struct *conn = req->conn;
6939 struct smb_filename *smb_fname_src = NULL;
6940 struct smb_filename *smb_fname_dst = NULL;
6941 char *fname_src = NULL;
6942 char *fname_dst = NULL;
6943 char *fname_src_mask = NULL;
6944 char *fname_src_dir = NULL;
6945 const char *p;
6946 int count=0;
6947 int error = ERRnoaccess;
6948 int tid2;
6949 int ofun;
6950 int flags;
6951 bool target_is_directory=False;
6952 bool source_has_wild = False;
6953 bool dest_has_wild = False;
6954 NTSTATUS status;
6955 TALLOC_CTX *ctx = talloc_tos();
6957 START_PROFILE(SMBcopy);
6959 if (req->wct < 3) {
6960 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6961 goto out;
6964 tid2 = SVAL(req->vwv+0, 0);
6965 ofun = SVAL(req->vwv+1, 0);
6966 flags = SVAL(req->vwv+2, 0);
6968 p = (const char *)req->buf;
6969 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6970 &status, &source_has_wild);
6971 if (!NT_STATUS_IS_OK(status)) {
6972 reply_nterror(req, status);
6973 goto out;
6975 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6976 &status, &dest_has_wild);
6977 if (!NT_STATUS_IS_OK(status)) {
6978 reply_nterror(req, status);
6979 goto out;
6982 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6984 if (tid2 != conn->cnum) {
6985 /* can't currently handle inter share copies XXXX */
6986 DEBUG(3,("Rejecting inter-share copy\n"));
6987 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6988 goto out;
6991 status = filename_convert(ctx, conn,
6992 req->flags2 & FLAGS2_DFS_PATHNAMES,
6993 fname_src,
6994 UCF_COND_ALLOW_WCARD_LCOMP,
6995 &source_has_wild,
6996 &smb_fname_src);
6997 if (!NT_STATUS_IS_OK(status)) {
6998 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6999 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7000 ERRSRV, ERRbadpath);
7001 goto out;
7003 reply_nterror(req, status);
7004 goto out;
7007 status = filename_convert(ctx, conn,
7008 req->flags2 & FLAGS2_DFS_PATHNAMES,
7009 fname_dst,
7010 UCF_COND_ALLOW_WCARD_LCOMP,
7011 &dest_has_wild,
7012 &smb_fname_dst);
7013 if (!NT_STATUS_IS_OK(status)) {
7014 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7015 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7016 ERRSRV, ERRbadpath);
7017 goto out;
7019 reply_nterror(req, status);
7020 goto out;
7023 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7025 if ((flags&1) && target_is_directory) {
7026 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7027 goto out;
7030 if ((flags&2) && !target_is_directory) {
7031 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7032 goto out;
7035 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7036 /* wants a tree copy! XXXX */
7037 DEBUG(3,("Rejecting tree copy\n"));
7038 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7039 goto out;
7042 /* Split up the directory from the filename/mask. */
7043 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7044 &fname_src_dir, &fname_src_mask);
7045 if (!NT_STATUS_IS_OK(status)) {
7046 reply_nterror(req, NT_STATUS_NO_MEMORY);
7047 goto out;
7051 * We should only check the mangled cache
7052 * here if unix_convert failed. This means
7053 * that the path in 'mask' doesn't exist
7054 * on the file system and so we need to look
7055 * for a possible mangle. This patch from
7056 * Tine Smukavec <valentin.smukavec@hermes.si>.
7058 if (!VALID_STAT(smb_fname_src->st) &&
7059 mangle_is_mangled(fname_src_mask, conn->params)) {
7060 char *new_mask = NULL;
7061 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7062 &new_mask, conn->params);
7064 /* Use demangled name if one was successfully found. */
7065 if (new_mask) {
7066 TALLOC_FREE(fname_src_mask);
7067 fname_src_mask = new_mask;
7071 if (!source_has_wild) {
7074 * Only one file needs to be copied. Append the mask back onto
7075 * the directory.
7077 TALLOC_FREE(smb_fname_src->base_name);
7078 if (ISDOT(fname_src_dir)) {
7079 /* Ensure we use canonical names on open. */
7080 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7081 "%s",
7082 fname_src_mask);
7083 } else {
7084 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7085 "%s/%s",
7086 fname_src_dir,
7087 fname_src_mask);
7089 if (!smb_fname_src->base_name) {
7090 reply_nterror(req, NT_STATUS_NO_MEMORY);
7091 goto out;
7094 if (dest_has_wild) {
7095 char *fname_dst_mod = NULL;
7096 if (!resolve_wildcards(smb_fname_dst,
7097 smb_fname_src->base_name,
7098 smb_fname_dst->base_name,
7099 &fname_dst_mod)) {
7100 reply_nterror(req, NT_STATUS_NO_MEMORY);
7101 goto out;
7103 TALLOC_FREE(smb_fname_dst->base_name);
7104 smb_fname_dst->base_name = fname_dst_mod;
7107 status = check_name(conn, smb_fname_src->base_name);
7108 if (!NT_STATUS_IS_OK(status)) {
7109 reply_nterror(req, status);
7110 goto out;
7113 status = check_name(conn, smb_fname_dst->base_name);
7114 if (!NT_STATUS_IS_OK(status)) {
7115 reply_nterror(req, status);
7116 goto out;
7119 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7120 ofun, count, target_is_directory);
7122 if(!NT_STATUS_IS_OK(status)) {
7123 reply_nterror(req, status);
7124 goto out;
7125 } else {
7126 count++;
7128 } else {
7129 struct smb_Dir *dir_hnd = NULL;
7130 const char *dname = NULL;
7131 char *talloced = NULL;
7132 long offset = 0;
7135 * There is a wildcard that requires us to actually read the
7136 * src dir and copy each file matching the mask to the dst.
7137 * Right now streams won't be copied, but this could
7138 * presumably be added with a nested loop for reach dir entry.
7140 SMB_ASSERT(!smb_fname_src->stream_name);
7141 SMB_ASSERT(!smb_fname_dst->stream_name);
7143 smb_fname_src->stream_name = NULL;
7144 smb_fname_dst->stream_name = NULL;
7146 if (strequal(fname_src_mask,"????????.???")) {
7147 TALLOC_FREE(fname_src_mask);
7148 fname_src_mask = talloc_strdup(ctx, "*");
7149 if (!fname_src_mask) {
7150 reply_nterror(req, NT_STATUS_NO_MEMORY);
7151 goto out;
7155 status = check_name(conn, fname_src_dir);
7156 if (!NT_STATUS_IS_OK(status)) {
7157 reply_nterror(req, status);
7158 goto out;
7161 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7162 if (dir_hnd == NULL) {
7163 status = map_nt_error_from_unix(errno);
7164 reply_nterror(req, status);
7165 goto out;
7168 error = ERRbadfile;
7170 /* Iterate over the src dir copying each entry to the dst. */
7171 while ((dname = ReadDirName(dir_hnd, &offset,
7172 &smb_fname_src->st, &talloced))) {
7173 char *destname = NULL;
7175 if (ISDOT(dname) || ISDOTDOT(dname)) {
7176 TALLOC_FREE(talloced);
7177 continue;
7180 if (!is_visible_file(conn, fname_src_dir, dname,
7181 &smb_fname_src->st, false)) {
7182 TALLOC_FREE(talloced);
7183 continue;
7186 if(!mask_match(dname, fname_src_mask,
7187 conn->case_sensitive)) {
7188 TALLOC_FREE(talloced);
7189 continue;
7192 error = ERRnoaccess;
7194 /* Get the src smb_fname struct setup. */
7195 TALLOC_FREE(smb_fname_src->base_name);
7196 if (ISDOT(fname_src_dir)) {
7197 /* Ensure we use canonical names on open. */
7198 smb_fname_src->base_name =
7199 talloc_asprintf(smb_fname_src, "%s",
7200 dname);
7201 } else {
7202 smb_fname_src->base_name =
7203 talloc_asprintf(smb_fname_src, "%s/%s",
7204 fname_src_dir, dname);
7207 if (!smb_fname_src->base_name) {
7208 TALLOC_FREE(dir_hnd);
7209 TALLOC_FREE(talloced);
7210 reply_nterror(req, NT_STATUS_NO_MEMORY);
7211 goto out;
7214 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7215 smb_fname_dst->base_name,
7216 &destname)) {
7217 TALLOC_FREE(talloced);
7218 continue;
7220 if (!destname) {
7221 TALLOC_FREE(dir_hnd);
7222 TALLOC_FREE(talloced);
7223 reply_nterror(req, NT_STATUS_NO_MEMORY);
7224 goto out;
7227 TALLOC_FREE(smb_fname_dst->base_name);
7228 smb_fname_dst->base_name = destname;
7230 status = check_name(conn, smb_fname_src->base_name);
7231 if (!NT_STATUS_IS_OK(status)) {
7232 TALLOC_FREE(dir_hnd);
7233 TALLOC_FREE(talloced);
7234 reply_nterror(req, status);
7235 goto out;
7238 status = check_name(conn, smb_fname_dst->base_name);
7239 if (!NT_STATUS_IS_OK(status)) {
7240 TALLOC_FREE(dir_hnd);
7241 TALLOC_FREE(talloced);
7242 reply_nterror(req, status);
7243 goto out;
7246 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7247 smb_fname_src->base_name,
7248 smb_fname_dst->base_name));
7250 status = copy_file(ctx, conn, smb_fname_src,
7251 smb_fname_dst, ofun, count,
7252 target_is_directory);
7253 if (NT_STATUS_IS_OK(status)) {
7254 count++;
7257 TALLOC_FREE(talloced);
7259 TALLOC_FREE(dir_hnd);
7262 if (count == 0) {
7263 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7264 goto out;
7267 reply_outbuf(req, 1, 0);
7268 SSVAL(req->outbuf,smb_vwv0,count);
7269 out:
7270 TALLOC_FREE(smb_fname_src);
7271 TALLOC_FREE(smb_fname_dst);
7272 TALLOC_FREE(fname_src);
7273 TALLOC_FREE(fname_dst);
7274 TALLOC_FREE(fname_src_mask);
7275 TALLOC_FREE(fname_src_dir);
7277 END_PROFILE(SMBcopy);
7278 return;
7281 #undef DBGC_CLASS
7282 #define DBGC_CLASS DBGC_LOCKING
7284 /****************************************************************************
7285 Get a lock pid, dealing with large count requests.
7286 ****************************************************************************/
7288 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7289 bool large_file_format)
7291 if(!large_file_format)
7292 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7293 else
7294 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7297 /****************************************************************************
7298 Get a lock count, dealing with large count requests.
7299 ****************************************************************************/
7301 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7302 bool large_file_format)
7304 uint64_t count = 0;
7306 if(!large_file_format) {
7307 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7308 } else {
7310 #if defined(HAVE_LONGLONG)
7311 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7312 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7313 #else /* HAVE_LONGLONG */
7316 * NT4.x seems to be broken in that it sends large file (64 bit)
7317 * lockingX calls even if the CAP_LARGE_FILES was *not*
7318 * negotiated. For boxes without large unsigned ints truncate the
7319 * lock count by dropping the top 32 bits.
7322 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7323 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7324 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7325 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7326 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7329 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7330 #endif /* HAVE_LONGLONG */
7333 return count;
7336 #if !defined(HAVE_LONGLONG)
7337 /****************************************************************************
7338 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7339 ****************************************************************************/
7341 static uint32 map_lock_offset(uint32 high, uint32 low)
7343 unsigned int i;
7344 uint32 mask = 0;
7345 uint32 highcopy = high;
7348 * Try and find out how many significant bits there are in high.
7351 for(i = 0; highcopy; i++)
7352 highcopy >>= 1;
7355 * We use 31 bits not 32 here as POSIX
7356 * lock offsets may not be negative.
7359 mask = (~0) << (31 - i);
7361 if(low & mask)
7362 return 0; /* Fail. */
7364 high <<= (31 - i);
7366 return (high|low);
7368 #endif /* !defined(HAVE_LONGLONG) */
7370 /****************************************************************************
7371 Get a lock offset, dealing with large offset requests.
7372 ****************************************************************************/
7374 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7375 bool large_file_format, bool *err)
7377 uint64_t offset = 0;
7379 *err = False;
7381 if(!large_file_format) {
7382 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7383 } else {
7385 #if defined(HAVE_LONGLONG)
7386 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7387 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7388 #else /* HAVE_LONGLONG */
7391 * NT4.x seems to be broken in that it sends large file (64 bit)
7392 * lockingX calls even if the CAP_LARGE_FILES was *not*
7393 * negotiated. For boxes without large unsigned ints mangle the
7394 * lock offset by mapping the top 32 bits onto the lower 32.
7397 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7398 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7399 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7400 uint32 new_low = 0;
7402 if((new_low = map_lock_offset(high, low)) == 0) {
7403 *err = True;
7404 return (uint64_t)-1;
7407 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7408 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7409 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7410 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7413 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7414 #endif /* HAVE_LONGLONG */
7417 return offset;
7420 NTSTATUS smbd_do_locking(struct smb_request *req,
7421 files_struct *fsp,
7422 uint8_t type,
7423 int32_t timeout,
7424 uint16_t num_ulocks,
7425 struct smbd_lock_element *ulocks,
7426 uint16_t num_locks,
7427 struct smbd_lock_element *locks,
7428 bool *async)
7430 connection_struct *conn = req->conn;
7431 int i;
7432 NTSTATUS status = NT_STATUS_OK;
7434 *async = false;
7436 /* Data now points at the beginning of the list
7437 of smb_unlkrng structs */
7438 for(i = 0; i < (int)num_ulocks; i++) {
7439 struct smbd_lock_element *e = &ulocks[i];
7441 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7442 "pid %u, file %s\n",
7443 (double)e->offset,
7444 (double)e->count,
7445 (unsigned int)e->smblctx,
7446 fsp_str_dbg(fsp)));
7448 if (e->brltype != UNLOCK_LOCK) {
7449 /* this can only happen with SMB2 */
7450 return NT_STATUS_INVALID_PARAMETER;
7453 status = do_unlock(req->sconn->msg_ctx,
7454 fsp,
7455 e->smblctx,
7456 e->count,
7457 e->offset,
7458 WINDOWS_LOCK);
7460 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7461 nt_errstr(status)));
7463 if (!NT_STATUS_IS_OK(status)) {
7464 return status;
7468 /* Setup the timeout in seconds. */
7470 if (!lp_blocking_locks(SNUM(conn))) {
7471 timeout = 0;
7474 /* Data now points at the beginning of the list
7475 of smb_lkrng structs */
7477 for(i = 0; i < (int)num_locks; i++) {
7478 struct smbd_lock_element *e = &locks[i];
7480 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7481 "%llu, file %s timeout = %d\n",
7482 (double)e->offset,
7483 (double)e->count,
7484 (unsigned long long)e->smblctx,
7485 fsp_str_dbg(fsp),
7486 (int)timeout));
7488 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7489 struct blocking_lock_record *blr = NULL;
7491 if (num_locks > 1) {
7493 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7494 * if the lock vector contains one entry. When given mutliple cancel
7495 * requests in a single PDU we expect the server to return an
7496 * error. Windows servers seem to accept the request but only
7497 * cancel the first lock.
7498 * JRA - Do what Windows does (tm) :-).
7501 #if 0
7502 /* MS-CIFS (2.2.4.32.1) behavior. */
7503 return NT_STATUS_DOS(ERRDOS,
7504 ERRcancelviolation);
7505 #else
7506 /* Windows behavior. */
7507 if (i != 0) {
7508 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7509 "cancel request\n"));
7510 continue;
7512 #endif
7515 if (lp_blocking_locks(SNUM(conn))) {
7517 /* Schedule a message to ourselves to
7518 remove the blocking lock record and
7519 return the right error. */
7521 blr = blocking_lock_cancel_smb1(fsp,
7522 e->smblctx,
7523 e->offset,
7524 e->count,
7525 WINDOWS_LOCK,
7526 type,
7527 NT_STATUS_FILE_LOCK_CONFLICT);
7528 if (blr == NULL) {
7529 return NT_STATUS_DOS(
7530 ERRDOS,
7531 ERRcancelviolation);
7534 /* Remove a matching pending lock. */
7535 status = do_lock_cancel(fsp,
7536 e->smblctx,
7537 e->count,
7538 e->offset,
7539 WINDOWS_LOCK,
7540 blr);
7541 } else {
7542 bool blocking_lock = timeout ? true : false;
7543 bool defer_lock = false;
7544 struct byte_range_lock *br_lck;
7545 uint64_t block_smblctx;
7547 br_lck = do_lock(req->sconn->msg_ctx,
7548 fsp,
7549 e->smblctx,
7550 e->count,
7551 e->offset,
7552 e->brltype,
7553 WINDOWS_LOCK,
7554 blocking_lock,
7555 &status,
7556 &block_smblctx,
7557 NULL);
7559 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7560 /* Windows internal resolution for blocking locks seems
7561 to be about 200ms... Don't wait for less than that. JRA. */
7562 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7563 timeout = lp_lock_spin_time();
7565 defer_lock = true;
7568 /* If a lock sent with timeout of zero would fail, and
7569 * this lock has been requested multiple times,
7570 * according to brl_lock_failed() we convert this
7571 * request to a blocking lock with a timeout of between
7572 * 150 - 300 milliseconds.
7574 * If lp_lock_spin_time() has been set to 0, we skip
7575 * this blocking retry and fail immediately.
7577 * Replacement for do_lock_spin(). JRA. */
7579 if (!req->sconn->using_smb2 &&
7580 br_lck && lp_blocking_locks(SNUM(conn)) &&
7581 lp_lock_spin_time() && !blocking_lock &&
7582 NT_STATUS_EQUAL((status),
7583 NT_STATUS_FILE_LOCK_CONFLICT))
7585 defer_lock = true;
7586 timeout = lp_lock_spin_time();
7589 if (br_lck && defer_lock) {
7591 * A blocking lock was requested. Package up
7592 * this smb into a queued request and push it
7593 * onto the blocking lock queue.
7595 if(push_blocking_lock_request(br_lck,
7596 req,
7597 fsp,
7598 timeout,
7600 e->smblctx,
7601 e->brltype,
7602 WINDOWS_LOCK,
7603 e->offset,
7604 e->count,
7605 block_smblctx)) {
7606 TALLOC_FREE(br_lck);
7607 *async = true;
7608 return NT_STATUS_OK;
7612 TALLOC_FREE(br_lck);
7615 if (!NT_STATUS_IS_OK(status)) {
7616 break;
7620 /* If any of the above locks failed, then we must unlock
7621 all of the previous locks (X/Open spec). */
7623 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7625 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7626 i = -1; /* we want to skip the for loop */
7630 * Ensure we don't do a remove on the lock that just failed,
7631 * as under POSIX rules, if we have a lock already there, we
7632 * will delete it (and we shouldn't) .....
7634 for(i--; i >= 0; i--) {
7635 struct smbd_lock_element *e = &locks[i];
7637 do_unlock(req->sconn->msg_ctx,
7638 fsp,
7639 e->smblctx,
7640 e->count,
7641 e->offset,
7642 WINDOWS_LOCK);
7644 return status;
7647 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7648 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7650 return NT_STATUS_OK;
7653 /****************************************************************************
7654 Reply to a lockingX request.
7655 ****************************************************************************/
7657 void reply_lockingX(struct smb_request *req)
7659 connection_struct *conn = req->conn;
7660 files_struct *fsp;
7661 unsigned char locktype;
7662 unsigned char oplocklevel;
7663 uint16 num_ulocks;
7664 uint16 num_locks;
7665 int32 lock_timeout;
7666 int i;
7667 const uint8_t *data;
7668 bool large_file_format;
7669 bool err;
7670 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7671 struct smbd_lock_element *ulocks;
7672 struct smbd_lock_element *locks;
7673 bool async = false;
7675 START_PROFILE(SMBlockingX);
7677 if (req->wct < 8) {
7678 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7679 END_PROFILE(SMBlockingX);
7680 return;
7683 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7684 locktype = CVAL(req->vwv+3, 0);
7685 oplocklevel = CVAL(req->vwv+3, 1);
7686 num_ulocks = SVAL(req->vwv+6, 0);
7687 num_locks = SVAL(req->vwv+7, 0);
7688 lock_timeout = IVAL(req->vwv+4, 0);
7689 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7691 if (!check_fsp(conn, req, fsp)) {
7692 END_PROFILE(SMBlockingX);
7693 return;
7696 data = req->buf;
7698 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7699 /* we don't support these - and CANCEL_LOCK makes w2k
7700 and XP reboot so I don't really want to be
7701 compatible! (tridge) */
7702 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7703 END_PROFILE(SMBlockingX);
7704 return;
7707 /* Check if this is an oplock break on a file
7708 we have granted an oplock on.
7710 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7711 /* Client can insist on breaking to none. */
7712 bool break_to_none = (oplocklevel == 0);
7713 bool result;
7715 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7716 "for fnum = %d\n", (unsigned int)oplocklevel,
7717 fsp->fnum ));
7720 * Make sure we have granted an exclusive or batch oplock on
7721 * this file.
7724 if (fsp->oplock_type == 0) {
7726 /* The Samba4 nbench simulator doesn't understand
7727 the difference between break to level2 and break
7728 to none from level2 - it sends oplock break
7729 replies in both cases. Don't keep logging an error
7730 message here - just ignore it. JRA. */
7732 DEBUG(5,("reply_lockingX: Error : oplock break from "
7733 "client for fnum = %d (oplock=%d) and no "
7734 "oplock granted on this file (%s).\n",
7735 fsp->fnum, fsp->oplock_type,
7736 fsp_str_dbg(fsp)));
7738 /* if this is a pure oplock break request then don't
7739 * send a reply */
7740 if (num_locks == 0 && num_ulocks == 0) {
7741 END_PROFILE(SMBlockingX);
7742 return;
7743 } else {
7744 END_PROFILE(SMBlockingX);
7745 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7746 return;
7750 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7751 (break_to_none)) {
7752 result = remove_oplock(fsp);
7753 } else {
7754 result = downgrade_oplock(fsp);
7757 if (!result) {
7758 DEBUG(0, ("reply_lockingX: error in removing "
7759 "oplock on file %s\n", fsp_str_dbg(fsp)));
7760 /* Hmmm. Is this panic justified? */
7761 smb_panic("internal tdb error");
7764 reply_to_oplock_break_requests(fsp);
7766 /* if this is a pure oplock break request then don't send a
7767 * reply */
7768 if (num_locks == 0 && num_ulocks == 0) {
7769 /* Sanity check - ensure a pure oplock break is not a
7770 chained request. */
7771 if(CVAL(req->vwv+0, 0) != 0xff)
7772 DEBUG(0,("reply_lockingX: Error : pure oplock "
7773 "break is a chained %d request !\n",
7774 (unsigned int)CVAL(req->vwv+0, 0)));
7775 END_PROFILE(SMBlockingX);
7776 return;
7780 if (req->buflen <
7781 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7782 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7783 END_PROFILE(SMBlockingX);
7784 return;
7787 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7788 if (ulocks == NULL) {
7789 reply_nterror(req, NT_STATUS_NO_MEMORY);
7790 END_PROFILE(SMBlockingX);
7791 return;
7794 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7795 if (locks == NULL) {
7796 reply_nterror(req, NT_STATUS_NO_MEMORY);
7797 END_PROFILE(SMBlockingX);
7798 return;
7801 /* Data now points at the beginning of the list
7802 of smb_unlkrng structs */
7803 for(i = 0; i < (int)num_ulocks; i++) {
7804 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7805 ulocks[i].count = get_lock_count(data, i, large_file_format);
7806 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7807 ulocks[i].brltype = UNLOCK_LOCK;
7810 * There is no error code marked "stupid client bug".... :-).
7812 if(err) {
7813 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7814 END_PROFILE(SMBlockingX);
7815 return;
7819 /* Now do any requested locks */
7820 data += ((large_file_format ? 20 : 10)*num_ulocks);
7822 /* Data now points at the beginning of the list
7823 of smb_lkrng structs */
7825 for(i = 0; i < (int)num_locks; i++) {
7826 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7827 locks[i].count = get_lock_count(data, i, large_file_format);
7828 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7830 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7831 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7832 locks[i].brltype = PENDING_READ_LOCK;
7833 } else {
7834 locks[i].brltype = READ_LOCK;
7836 } else {
7837 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7838 locks[i].brltype = PENDING_WRITE_LOCK;
7839 } else {
7840 locks[i].brltype = WRITE_LOCK;
7845 * There is no error code marked "stupid client bug".... :-).
7847 if(err) {
7848 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7849 END_PROFILE(SMBlockingX);
7850 return;
7854 status = smbd_do_locking(req, fsp,
7855 locktype, lock_timeout,
7856 num_ulocks, ulocks,
7857 num_locks, locks,
7858 &async);
7859 if (!NT_STATUS_IS_OK(status)) {
7860 END_PROFILE(SMBlockingX);
7861 reply_nterror(req, status);
7862 return;
7864 if (async) {
7865 END_PROFILE(SMBlockingX);
7866 return;
7869 reply_outbuf(req, 2, 0);
7871 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7872 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7874 END_PROFILE(SMBlockingX);
7875 chain_reply(req);
7878 #undef DBGC_CLASS
7879 #define DBGC_CLASS DBGC_ALL
7881 /****************************************************************************
7882 Reply to a SMBreadbmpx (read block multiplex) request.
7883 Always reply with an error, if someone has a platform really needs this,
7884 please contact vl@samba.org
7885 ****************************************************************************/
7887 void reply_readbmpx(struct smb_request *req)
7889 START_PROFILE(SMBreadBmpx);
7890 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7891 END_PROFILE(SMBreadBmpx);
7892 return;
7895 /****************************************************************************
7896 Reply to a SMBreadbs (read block multiplex secondary) request.
7897 Always reply with an error, if someone has a platform really needs this,
7898 please contact vl@samba.org
7899 ****************************************************************************/
7901 void reply_readbs(struct smb_request *req)
7903 START_PROFILE(SMBreadBs);
7904 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7905 END_PROFILE(SMBreadBs);
7906 return;
7909 /****************************************************************************
7910 Reply to a SMBsetattrE.
7911 ****************************************************************************/
7913 void reply_setattrE(struct smb_request *req)
7915 connection_struct *conn = req->conn;
7916 struct smb_file_time ft;
7917 files_struct *fsp;
7918 NTSTATUS status;
7920 START_PROFILE(SMBsetattrE);
7921 ZERO_STRUCT(ft);
7923 if (req->wct < 7) {
7924 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7925 goto out;
7928 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7930 if(!fsp || (fsp->conn != conn)) {
7931 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7932 goto out;
7936 * Convert the DOS times into unix times.
7939 ft.atime = convert_time_t_to_timespec(
7940 srv_make_unix_date2(req->vwv+3));
7941 ft.mtime = convert_time_t_to_timespec(
7942 srv_make_unix_date2(req->vwv+5));
7943 ft.create_time = convert_time_t_to_timespec(
7944 srv_make_unix_date2(req->vwv+1));
7946 reply_outbuf(req, 0, 0);
7949 * Patch from Ray Frush <frush@engr.colostate.edu>
7950 * Sometimes times are sent as zero - ignore them.
7953 /* Ensure we have a valid stat struct for the source. */
7954 status = vfs_stat_fsp(fsp);
7955 if (!NT_STATUS_IS_OK(status)) {
7956 reply_nterror(req, status);
7957 goto out;
7960 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
7961 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7962 goto out;
7965 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7966 if (!NT_STATUS_IS_OK(status)) {
7967 reply_nterror(req, status);
7968 goto out;
7971 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7972 " createtime=%u\n",
7973 fsp->fnum,
7974 (unsigned int)ft.atime.tv_sec,
7975 (unsigned int)ft.mtime.tv_sec,
7976 (unsigned int)ft.create_time.tv_sec
7978 out:
7979 END_PROFILE(SMBsetattrE);
7980 return;
7984 /* Back from the dead for OS/2..... JRA. */
7986 /****************************************************************************
7987 Reply to a SMBwritebmpx (write block multiplex primary) request.
7988 Always reply with an error, if someone has a platform really needs this,
7989 please contact vl@samba.org
7990 ****************************************************************************/
7992 void reply_writebmpx(struct smb_request *req)
7994 START_PROFILE(SMBwriteBmpx);
7995 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7996 END_PROFILE(SMBwriteBmpx);
7997 return;
8000 /****************************************************************************
8001 Reply to a SMBwritebs (write block multiplex secondary) request.
8002 Always reply with an error, if someone has a platform really needs this,
8003 please contact vl@samba.org
8004 ****************************************************************************/
8006 void reply_writebs(struct smb_request *req)
8008 START_PROFILE(SMBwriteBs);
8009 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8010 END_PROFILE(SMBwriteBs);
8011 return;
8014 /****************************************************************************
8015 Reply to a SMBgetattrE.
8016 ****************************************************************************/
8018 void reply_getattrE(struct smb_request *req)
8020 connection_struct *conn = req->conn;
8021 int mode;
8022 files_struct *fsp;
8023 struct timespec create_ts;
8025 START_PROFILE(SMBgetattrE);
8027 if (req->wct < 1) {
8028 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8029 END_PROFILE(SMBgetattrE);
8030 return;
8033 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8035 if(!fsp || (fsp->conn != conn)) {
8036 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8037 END_PROFILE(SMBgetattrE);
8038 return;
8041 /* Do an fstat on this file */
8042 if(fsp_stat(fsp)) {
8043 reply_nterror(req, map_nt_error_from_unix(errno));
8044 END_PROFILE(SMBgetattrE);
8045 return;
8048 mode = dos_mode(conn, fsp->fsp_name);
8051 * Convert the times into dos times. Set create
8052 * date to be last modify date as UNIX doesn't save
8053 * this.
8056 reply_outbuf(req, 11, 0);
8058 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8059 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8060 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8061 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8062 /* Should we check pending modtime here ? JRA */
8063 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8064 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8066 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8067 SIVAL(req->outbuf, smb_vwv6, 0);
8068 SIVAL(req->outbuf, smb_vwv8, 0);
8069 } else {
8070 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8071 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8072 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8074 SSVAL(req->outbuf,smb_vwv10, mode);
8076 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8078 END_PROFILE(SMBgetattrE);
8079 return;